LCOV - code coverage report
Current view: top level - src/bin/pg_dump - pg_dump.c (source / functions) Hit Total Coverage
Test: PostgreSQL 19devel Lines: 7498 8310 90.2 %
Date: 2025-08-31 01:17:28 Functions: 184 188 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_constraint_d.h"
      51             : #include "catalog/pg_default_acl_d.h"
      52             : #include "catalog/pg_largeobject_d.h"
      53             : #include "catalog/pg_largeobject_metadata_d.h"
      54             : #include "catalog/pg_proc_d.h"
      55             : #include "catalog/pg_publication_d.h"
      56             : #include "catalog/pg_shdepend_d.h"
      57             : #include "catalog/pg_subscription_d.h"
      58             : #include "catalog/pg_type_d.h"
      59             : #include "common/connect.h"
      60             : #include "common/int.h"
      61             : #include "common/relpath.h"
      62             : #include "common/shortest_dec.h"
      63             : #include "compress_io.h"
      64             : #include "dumputils.h"
      65             : #include "fe_utils/option_utils.h"
      66             : #include "fe_utils/string_utils.h"
      67             : #include "filter.h"
      68             : #include "getopt_long.h"
      69             : #include "libpq/libpq-fs.h"
      70             : #include "parallel.h"
      71             : #include "pg_backup_db.h"
      72             : #include "pg_backup_utils.h"
      73             : #include "pg_dump.h"
      74             : #include "storage/block.h"
      75             : 
      76             : typedef struct
      77             : {
      78             :     Oid         roleoid;        /* role's OID */
      79             :     const char *rolename;       /* role's name */
      80             : } RoleNameItem;
      81             : 
      82             : typedef struct
      83             : {
      84             :     const char *descr;          /* comment for an object */
      85             :     Oid         classoid;       /* object class (catalog OID) */
      86             :     Oid         objoid;         /* object OID */
      87             :     int         objsubid;       /* subobject (table column #) */
      88             : } CommentItem;
      89             : 
      90             : typedef struct
      91             : {
      92             :     const char *provider;       /* label provider of this security label */
      93             :     const char *label;          /* security label for an object */
      94             :     Oid         classoid;       /* object class (catalog OID) */
      95             :     Oid         objoid;         /* object OID */
      96             :     int         objsubid;       /* subobject (table column #) */
      97             : } SecLabelItem;
      98             : 
      99             : typedef struct
     100             : {
     101             :     Oid         oid;            /* object OID */
     102             :     char        relkind;        /* object kind */
     103             :     RelFileNumber relfilenumber;    /* object filenode */
     104             :     Oid         toast_oid;      /* toast table OID */
     105             :     RelFileNumber toast_relfilenumber;  /* toast table filenode */
     106             :     Oid         toast_index_oid;    /* toast table index OID */
     107             :     RelFileNumber toast_index_relfilenumber;    /* toast table index filenode */
     108             : } BinaryUpgradeClassOidItem;
     109             : 
     110             : /* sequence types */
     111             : typedef enum SeqType
     112             : {
     113             :     SEQTYPE_SMALLINT,
     114             :     SEQTYPE_INTEGER,
     115             :     SEQTYPE_BIGINT,
     116             : } SeqType;
     117             : 
     118             : static const char *const SeqTypeNames[] =
     119             : {
     120             :     [SEQTYPE_SMALLINT] = "smallint",
     121             :     [SEQTYPE_INTEGER] = "integer",
     122             :     [SEQTYPE_BIGINT] = "bigint",
     123             : };
     124             : 
     125             : StaticAssertDecl(lengthof(SeqTypeNames) == (SEQTYPE_BIGINT + 1),
     126             :                  "array length mismatch");
     127             : 
     128             : typedef struct
     129             : {
     130             :     Oid         oid;            /* sequence OID */
     131             :     SeqType     seqtype;        /* data type of sequence */
     132             :     bool        cycled;         /* whether sequence cycles */
     133             :     int64       minv;           /* minimum value */
     134             :     int64       maxv;           /* maximum value */
     135             :     int64       startv;         /* start value */
     136             :     int64       incby;          /* increment value */
     137             :     int64       cache;          /* cache size */
     138             :     int64       last_value;     /* last value of sequence */
     139             :     bool        is_called;      /* whether nextval advances before returning */
     140             : } SequenceItem;
     141             : 
     142             : typedef enum OidOptions
     143             : {
     144             :     zeroIsError = 1,
     145             :     zeroAsStar = 2,
     146             :     zeroAsNone = 4,
     147             : } OidOptions;
     148             : 
     149             : /* global decls */
     150             : static bool dosync = true;      /* Issue fsync() to make dump durable on disk. */
     151             : 
     152             : static Oid  g_last_builtin_oid; /* value of the last builtin oid */
     153             : 
     154             : /* The specified names/patterns should to match at least one entity */
     155             : static int  strict_names = 0;
     156             : 
     157             : static pg_compress_algorithm compression_algorithm = PG_COMPRESSION_NONE;
     158             : 
     159             : /*
     160             :  * Object inclusion/exclusion lists
     161             :  *
     162             :  * The string lists record the patterns given by command-line switches,
     163             :  * which we then convert to lists of OIDs of matching objects.
     164             :  */
     165             : static SimpleStringList schema_include_patterns = {NULL, NULL};
     166             : static SimpleOidList schema_include_oids = {NULL, NULL};
     167             : static SimpleStringList schema_exclude_patterns = {NULL, NULL};
     168             : static SimpleOidList schema_exclude_oids = {NULL, NULL};
     169             : 
     170             : static SimpleStringList table_include_patterns = {NULL, NULL};
     171             : static SimpleStringList table_include_patterns_and_children = {NULL, NULL};
     172             : static SimpleOidList table_include_oids = {NULL, NULL};
     173             : static SimpleStringList table_exclude_patterns = {NULL, NULL};
     174             : static SimpleStringList table_exclude_patterns_and_children = {NULL, NULL};
     175             : static SimpleOidList table_exclude_oids = {NULL, NULL};
     176             : static SimpleStringList tabledata_exclude_patterns = {NULL, NULL};
     177             : static SimpleStringList tabledata_exclude_patterns_and_children = {NULL, NULL};
     178             : static SimpleOidList tabledata_exclude_oids = {NULL, NULL};
     179             : 
     180             : static SimpleStringList foreign_servers_include_patterns = {NULL, NULL};
     181             : static SimpleOidList foreign_servers_include_oids = {NULL, NULL};
     182             : 
     183             : static SimpleStringList extension_include_patterns = {NULL, NULL};
     184             : static SimpleOidList extension_include_oids = {NULL, NULL};
     185             : 
     186             : static SimpleStringList extension_exclude_patterns = {NULL, NULL};
     187             : static SimpleOidList extension_exclude_oids = {NULL, NULL};
     188             : 
     189             : static const CatalogId nilCatalogId = {0, 0};
     190             : 
     191             : /* override for standard extra_float_digits setting */
     192             : static bool have_extra_float_digits = false;
     193             : static int  extra_float_digits;
     194             : 
     195             : /* sorted table of role names */
     196             : static RoleNameItem *rolenames = NULL;
     197             : static int  nrolenames = 0;
     198             : 
     199             : /* sorted table of comments */
     200             : static CommentItem *comments = NULL;
     201             : static int  ncomments = 0;
     202             : 
     203             : /* sorted table of security labels */
     204             : static SecLabelItem *seclabels = NULL;
     205             : static int  nseclabels = 0;
     206             : 
     207             : /* sorted table of pg_class information for binary upgrade */
     208             : static BinaryUpgradeClassOidItem *binaryUpgradeClassOids = NULL;
     209             : static int  nbinaryUpgradeClassOids = 0;
     210             : 
     211             : /* sorted table of sequences */
     212             : static SequenceItem *sequences = NULL;
     213             : static int  nsequences = 0;
     214             : 
     215             : /*
     216             :  * For binary upgrade, the dump ID of pg_largeobject_metadata is saved for use
     217             :  * as a dependency for pg_shdepend and any large object comments/seclabels.
     218             :  */
     219             : static DumpId lo_metadata_dumpId;
     220             : 
     221             : /* Maximum number of relations to fetch in a fetchAttributeStats() call. */
     222             : #define MAX_ATTR_STATS_RELS 64
     223             : 
     224             : /*
     225             :  * The default number of rows per INSERT when
     226             :  * --inserts is specified without --rows-per-insert
     227             :  */
     228             : #define DUMP_DEFAULT_ROWS_PER_INSERT 1
     229             : 
     230             : /*
     231             :  * Maximum number of large objects to group into a single ArchiveEntry.
     232             :  * At some point we might want to make this user-controllable, but for now
     233             :  * a hard-wired setting will suffice.
     234             :  */
     235             : #define MAX_BLOBS_PER_ARCHIVE_ENTRY 1000
     236             : 
     237             : /*
     238             :  * Macro for producing quoted, schema-qualified name of a dumpable object.
     239             :  */
     240             : #define fmtQualifiedDumpable(obj) \
     241             :     fmtQualifiedId((obj)->dobj.namespace->dobj.name, \
     242             :                    (obj)->dobj.name)
     243             : 
     244             : static void help(const char *progname);
     245             : static void setup_connection(Archive *AH,
     246             :                              const char *dumpencoding, const char *dumpsnapshot,
     247             :                              char *use_role);
     248             : static ArchiveFormat parseArchiveFormat(const char *format, ArchiveMode *mode);
     249             : static void expand_schema_name_patterns(Archive *fout,
     250             :                                         SimpleStringList *patterns,
     251             :                                         SimpleOidList *oids,
     252             :                                         bool strict_names);
     253             : static void expand_extension_name_patterns(Archive *fout,
     254             :                                            SimpleStringList *patterns,
     255             :                                            SimpleOidList *oids,
     256             :                                            bool strict_names);
     257             : static void expand_foreign_server_name_patterns(Archive *fout,
     258             :                                                 SimpleStringList *patterns,
     259             :                                                 SimpleOidList *oids);
     260             : static void expand_table_name_patterns(Archive *fout,
     261             :                                        SimpleStringList *patterns,
     262             :                                        SimpleOidList *oids,
     263             :                                        bool strict_names,
     264             :                                        bool with_child_tables);
     265             : static void prohibit_crossdb_refs(PGconn *conn, const char *dbname,
     266             :                                   const char *pattern);
     267             : 
     268             : static NamespaceInfo *findNamespace(Oid nsoid);
     269             : static void dumpTableData(Archive *fout, const TableDataInfo *tdinfo);
     270             : static void refreshMatViewData(Archive *fout, const TableDataInfo *tdinfo);
     271             : static const char *getRoleName(const char *roleoid_str);
     272             : static void collectRoleNames(Archive *fout);
     273             : static void getAdditionalACLs(Archive *fout);
     274             : static void dumpCommentExtended(Archive *fout, const char *type,
     275             :                                 const char *name, const char *namespace,
     276             :                                 const char *owner, CatalogId catalogId,
     277             :                                 int subid, DumpId dumpId,
     278             :                                 const char *initdb_comment);
     279             : static inline void dumpComment(Archive *fout, const char *type,
     280             :                                const char *name, const char *namespace,
     281             :                                const char *owner, CatalogId catalogId,
     282             :                                int subid, DumpId dumpId);
     283             : static int  findComments(Oid classoid, Oid objoid, CommentItem **items);
     284             : static void collectComments(Archive *fout);
     285             : static void dumpSecLabel(Archive *fout, const char *type, const char *name,
     286             :                          const char *namespace, const char *owner,
     287             :                          CatalogId catalogId, int subid, DumpId dumpId);
     288             : static int  findSecLabels(Oid classoid, Oid objoid, SecLabelItem **items);
     289             : static void collectSecLabels(Archive *fout);
     290             : static void dumpDumpableObject(Archive *fout, DumpableObject *dobj);
     291             : static void dumpNamespace(Archive *fout, const NamespaceInfo *nspinfo);
     292             : static void dumpExtension(Archive *fout, const ExtensionInfo *extinfo);
     293             : static void dumpType(Archive *fout, const TypeInfo *tyinfo);
     294             : static void dumpBaseType(Archive *fout, const TypeInfo *tyinfo);
     295             : static void dumpEnumType(Archive *fout, const TypeInfo *tyinfo);
     296             : static void dumpRangeType(Archive *fout, const TypeInfo *tyinfo);
     297             : static void dumpUndefinedType(Archive *fout, const TypeInfo *tyinfo);
     298             : static void dumpDomain(Archive *fout, const TypeInfo *tyinfo);
     299             : static void dumpCompositeType(Archive *fout, const TypeInfo *tyinfo);
     300             : static void dumpCompositeTypeColComments(Archive *fout, const TypeInfo *tyinfo,
     301             :                                          PGresult *res);
     302             : static void dumpShellType(Archive *fout, const ShellTypeInfo *stinfo);
     303             : static void dumpProcLang(Archive *fout, const ProcLangInfo *plang);
     304             : static void dumpFunc(Archive *fout, const FuncInfo *finfo);
     305             : static void dumpCast(Archive *fout, const CastInfo *cast);
     306             : static void dumpTransform(Archive *fout, const TransformInfo *transform);
     307             : static void dumpOpr(Archive *fout, const OprInfo *oprinfo);
     308             : static void dumpAccessMethod(Archive *fout, const AccessMethodInfo *aminfo);
     309             : static void dumpOpclass(Archive *fout, const OpclassInfo *opcinfo);
     310             : static void dumpOpfamily(Archive *fout, const OpfamilyInfo *opfinfo);
     311             : static void dumpCollation(Archive *fout, const CollInfo *collinfo);
     312             : static void dumpConversion(Archive *fout, const ConvInfo *convinfo);
     313             : static void dumpRule(Archive *fout, const RuleInfo *rinfo);
     314             : static void dumpAgg(Archive *fout, const AggInfo *agginfo);
     315             : static void dumpTrigger(Archive *fout, const TriggerInfo *tginfo);
     316             : static void dumpEventTrigger(Archive *fout, const EventTriggerInfo *evtinfo);
     317             : static void dumpTable(Archive *fout, const TableInfo *tbinfo);
     318             : static void dumpTableSchema(Archive *fout, const TableInfo *tbinfo);
     319             : static void dumpTableAttach(Archive *fout, const TableAttachInfo *attachinfo);
     320             : static void dumpAttrDef(Archive *fout, const AttrDefInfo *adinfo);
     321             : static void collectSequences(Archive *fout);
     322             : static void dumpSequence(Archive *fout, const TableInfo *tbinfo);
     323             : static void dumpSequenceData(Archive *fout, const TableDataInfo *tdinfo);
     324             : static void dumpIndex(Archive *fout, const IndxInfo *indxinfo);
     325             : static void dumpIndexAttach(Archive *fout, const IndexAttachInfo *attachinfo);
     326             : static void dumpStatisticsExt(Archive *fout, const StatsExtInfo *statsextinfo);
     327             : static void dumpConstraint(Archive *fout, const ConstraintInfo *coninfo);
     328             : static void dumpTableConstraintComment(Archive *fout, const ConstraintInfo *coninfo);
     329             : static void dumpTSParser(Archive *fout, const TSParserInfo *prsinfo);
     330             : static void dumpTSDictionary(Archive *fout, const TSDictInfo *dictinfo);
     331             : static void dumpTSTemplate(Archive *fout, const TSTemplateInfo *tmplinfo);
     332             : static void dumpTSConfig(Archive *fout, const TSConfigInfo *cfginfo);
     333             : static void dumpForeignDataWrapper(Archive *fout, const FdwInfo *fdwinfo);
     334             : static void dumpForeignServer(Archive *fout, const ForeignServerInfo *srvinfo);
     335             : static void dumpUserMappings(Archive *fout,
     336             :                              const char *servername, const char *namespace,
     337             :                              const char *owner, CatalogId catalogId, DumpId dumpId);
     338             : static void dumpDefaultACL(Archive *fout, const DefaultACLInfo *daclinfo);
     339             : 
     340             : static DumpId dumpACL(Archive *fout, DumpId objDumpId, DumpId altDumpId,
     341             :                       const char *type, const char *name, const char *subname,
     342             :                       const char *nspname, const char *tag, const char *owner,
     343             :                       const DumpableAcl *dacl);
     344             : 
     345             : static void getDependencies(Archive *fout);
     346             : static void BuildArchiveDependencies(Archive *fout);
     347             : static void findDumpableDependencies(ArchiveHandle *AH, const DumpableObject *dobj,
     348             :                                      DumpId **dependencies, int *nDeps, int *allocDeps);
     349             : 
     350             : static DumpableObject *createBoundaryObjects(void);
     351             : static void addBoundaryDependencies(DumpableObject **dobjs, int numObjs,
     352             :                                     DumpableObject *boundaryObjs);
     353             : 
     354             : static void addConstrChildIdxDeps(DumpableObject *dobj, const IndxInfo *refidx);
     355             : static void getDomainConstraints(Archive *fout, TypeInfo *tyinfo);
     356             : static void getTableData(DumpOptions *dopt, TableInfo *tblinfo, int numTables, char relkind);
     357             : static void makeTableDataInfo(DumpOptions *dopt, TableInfo *tbinfo);
     358             : static void buildMatViewRefreshDependencies(Archive *fout);
     359             : static void getTableDataFKConstraints(void);
     360             : static void determineNotNullFlags(Archive *fout, PGresult *res, int r,
     361             :                                   TableInfo *tbinfo, int j,
     362             :                                   int i_notnull_name,
     363             :                                   int i_notnull_comment,
     364             :                                   int i_notnull_invalidoid,
     365             :                                   int i_notnull_noinherit,
     366             :                                   int i_notnull_islocal,
     367             :                                   PQExpBuffer *invalidnotnulloids);
     368             : static char *format_function_arguments(const FuncInfo *finfo, const char *funcargs,
     369             :                                        bool is_agg);
     370             : static char *format_function_signature(Archive *fout,
     371             :                                        const FuncInfo *finfo, bool honor_quotes);
     372             : static char *convertRegProcReference(const char *proc);
     373             : static char *getFormattedOperatorName(const char *oproid);
     374             : static char *convertTSFunction(Archive *fout, Oid funcOid);
     375             : static const char *getFormattedTypeName(Archive *fout, Oid oid, OidOptions opts);
     376             : static void getLOs(Archive *fout);
     377             : static void dumpLO(Archive *fout, const LoInfo *loinfo);
     378             : static int  dumpLOs(Archive *fout, const void *arg);
     379             : static void dumpPolicy(Archive *fout, const PolicyInfo *polinfo);
     380             : static void dumpPublication(Archive *fout, const PublicationInfo *pubinfo);
     381             : static void dumpPublicationTable(Archive *fout, const PublicationRelInfo *pubrinfo);
     382             : static void dumpSubscription(Archive *fout, const SubscriptionInfo *subinfo);
     383             : static void dumpSubscriptionTable(Archive *fout, const SubRelInfo *subrinfo);
     384             : static void dumpDatabase(Archive *fout);
     385             : static void dumpDatabaseConfig(Archive *AH, PQExpBuffer outbuf,
     386             :                                const char *dbname, Oid dboid);
     387             : static void dumpEncoding(Archive *AH);
     388             : static void dumpStdStrings(Archive *AH);
     389             : static void dumpSearchPath(Archive *AH);
     390             : static void binary_upgrade_set_type_oids_by_type_oid(Archive *fout,
     391             :                                                      PQExpBuffer upgrade_buffer,
     392             :                                                      Oid pg_type_oid,
     393             :                                                      bool force_array_type,
     394             :                                                      bool include_multirange_type);
     395             : static void binary_upgrade_set_type_oids_by_rel(Archive *fout,
     396             :                                                 PQExpBuffer upgrade_buffer,
     397             :                                                 const TableInfo *tbinfo);
     398             : static void collectBinaryUpgradeClassOids(Archive *fout);
     399             : static void binary_upgrade_set_pg_class_oids(Archive *fout,
     400             :                                              PQExpBuffer upgrade_buffer,
     401             :                                              Oid pg_class_oid);
     402             : static void binary_upgrade_extension_member(PQExpBuffer upgrade_buffer,
     403             :                                             const DumpableObject *dobj,
     404             :                                             const char *objtype,
     405             :                                             const char *objname,
     406             :                                             const char *objnamespace);
     407             : static const char *getAttrName(int attrnum, const TableInfo *tblInfo);
     408             : static const char *fmtCopyColumnList(const TableInfo *ti, PQExpBuffer buffer);
     409             : static bool nonemptyReloptions(const char *reloptions);
     410             : static void appendReloptionsArrayAH(PQExpBuffer buffer, const char *reloptions,
     411             :                                     const char *prefix, Archive *fout);
     412             : static char *get_synchronized_snapshot(Archive *fout);
     413             : static void set_restrict_relation_kind(Archive *AH, const char *value);
     414             : static void setupDumpWorker(Archive *AH);
     415             : static TableInfo *getRootTableInfo(const TableInfo *tbinfo);
     416             : static bool forcePartitionRootLoad(const TableInfo *tbinfo);
     417             : static void read_dump_filters(const char *filename, DumpOptions *dopt);
     418             : 
     419             : 
     420             : int
     421         580 : main(int argc, char **argv)
     422             : {
     423             :     int         c;
     424         580 :     const char *filename = NULL;
     425         580 :     const char *format = "p";
     426             :     TableInfo  *tblinfo;
     427             :     int         numTables;
     428             :     DumpableObject **dobjs;
     429             :     int         numObjs;
     430             :     DumpableObject *boundaryObjs;
     431             :     int         i;
     432             :     int         optindex;
     433             :     RestoreOptions *ropt;
     434             :     Archive    *fout;           /* the script file */
     435         580 :     bool        g_verbose = false;
     436         580 :     const char *dumpencoding = NULL;
     437         580 :     const char *dumpsnapshot = NULL;
     438         580 :     char       *use_role = NULL;
     439         580 :     int         numWorkers = 1;
     440         580 :     int         plainText = 0;
     441         580 :     ArchiveFormat archiveFormat = archUnknown;
     442             :     ArchiveMode archiveMode;
     443         580 :     pg_compress_specification compression_spec = {0};
     444         580 :     char       *compression_detail = NULL;
     445         580 :     char       *compression_algorithm_str = "none";
     446         580 :     char       *error_detail = NULL;
     447         580 :     bool        user_compression_defined = false;
     448         580 :     DataDirSyncMethod sync_method = DATA_DIR_SYNC_METHOD_FSYNC;
     449         580 :     bool        data_only = false;
     450         580 :     bool        schema_only = false;
     451         580 :     bool        statistics_only = false;
     452         580 :     bool        with_statistics = false;
     453         580 :     bool        no_data = false;
     454         580 :     bool        no_schema = false;
     455         580 :     bool        no_statistics = false;
     456             : 
     457             :     static DumpOptions dopt;
     458             : 
     459             :     static struct option long_options[] = {
     460             :         {"data-only", no_argument, NULL, 'a'},
     461             :         {"blobs", no_argument, NULL, 'b'},
     462             :         {"large-objects", no_argument, NULL, 'b'},
     463             :         {"no-blobs", no_argument, NULL, 'B'},
     464             :         {"no-large-objects", no_argument, NULL, 'B'},
     465             :         {"clean", no_argument, NULL, 'c'},
     466             :         {"create", no_argument, NULL, 'C'},
     467             :         {"dbname", required_argument, NULL, 'd'},
     468             :         {"extension", required_argument, NULL, 'e'},
     469             :         {"file", required_argument, NULL, 'f'},
     470             :         {"format", required_argument, NULL, 'F'},
     471             :         {"host", required_argument, NULL, 'h'},
     472             :         {"jobs", 1, NULL, 'j'},
     473             :         {"no-reconnect", no_argument, NULL, 'R'},
     474             :         {"no-owner", no_argument, NULL, 'O'},
     475             :         {"port", required_argument, NULL, 'p'},
     476             :         {"schema", required_argument, NULL, 'n'},
     477             :         {"exclude-schema", required_argument, NULL, 'N'},
     478             :         {"schema-only", no_argument, NULL, 's'},
     479             :         {"superuser", required_argument, NULL, 'S'},
     480             :         {"table", required_argument, NULL, 't'},
     481             :         {"exclude-table", required_argument, NULL, 'T'},
     482             :         {"no-password", no_argument, NULL, 'w'},
     483             :         {"password", no_argument, NULL, 'W'},
     484             :         {"username", required_argument, NULL, 'U'},
     485             :         {"verbose", no_argument, NULL, 'v'},
     486             :         {"no-privileges", no_argument, NULL, 'x'},
     487             :         {"no-acl", no_argument, NULL, 'x'},
     488             :         {"compress", required_argument, NULL, 'Z'},
     489             :         {"encoding", required_argument, NULL, 'E'},
     490             :         {"help", no_argument, NULL, '?'},
     491             :         {"version", no_argument, NULL, 'V'},
     492             : 
     493             :         /*
     494             :          * the following options don't have an equivalent short option letter
     495             :          */
     496             :         {"attribute-inserts", no_argument, &dopt.column_inserts, 1},
     497             :         {"binary-upgrade", no_argument, &dopt.binary_upgrade, 1},
     498             :         {"column-inserts", no_argument, &dopt.column_inserts, 1},
     499             :         {"disable-dollar-quoting", no_argument, &dopt.disable_dollar_quoting, 1},
     500             :         {"disable-triggers", no_argument, &dopt.disable_triggers, 1},
     501             :         {"enable-row-security", no_argument, &dopt.enable_row_security, 1},
     502             :         {"exclude-table-data", required_argument, NULL, 4},
     503             :         {"extra-float-digits", required_argument, NULL, 8},
     504             :         {"if-exists", no_argument, &dopt.if_exists, 1},
     505             :         {"inserts", no_argument, NULL, 9},
     506             :         {"lock-wait-timeout", required_argument, NULL, 2},
     507             :         {"no-table-access-method", no_argument, &dopt.outputNoTableAm, 1},
     508             :         {"no-tablespaces", no_argument, &dopt.outputNoTablespaces, 1},
     509             :         {"quote-all-identifiers", no_argument, &quote_all_identifiers, 1},
     510             :         {"load-via-partition-root", no_argument, &dopt.load_via_partition_root, 1},
     511             :         {"role", required_argument, NULL, 3},
     512             :         {"section", required_argument, NULL, 5},
     513             :         {"serializable-deferrable", no_argument, &dopt.serializable_deferrable, 1},
     514             :         {"snapshot", required_argument, NULL, 6},
     515             :         {"statistics", no_argument, NULL, 22},
     516             :         {"statistics-only", no_argument, NULL, 18},
     517             :         {"strict-names", no_argument, &strict_names, 1},
     518             :         {"use-set-session-authorization", no_argument, &dopt.use_setsessauth, 1},
     519             :         {"no-comments", no_argument, &dopt.no_comments, 1},
     520             :         {"no-data", no_argument, NULL, 19},
     521             :         {"no-policies", no_argument, &dopt.no_policies, 1},
     522             :         {"no-publications", no_argument, &dopt.no_publications, 1},
     523             :         {"no-schema", no_argument, NULL, 20},
     524             :         {"no-security-labels", no_argument, &dopt.no_security_labels, 1},
     525             :         {"no-statistics", no_argument, NULL, 21},
     526             :         {"no-subscriptions", no_argument, &dopt.no_subscriptions, 1},
     527             :         {"no-toast-compression", no_argument, &dopt.no_toast_compression, 1},
     528             :         {"no-unlogged-table-data", no_argument, &dopt.no_unlogged_table_data, 1},
     529             :         {"no-sync", no_argument, NULL, 7},
     530             :         {"on-conflict-do-nothing", no_argument, &dopt.do_nothing, 1},
     531             :         {"rows-per-insert", required_argument, NULL, 10},
     532             :         {"include-foreign-data", required_argument, NULL, 11},
     533             :         {"table-and-children", required_argument, NULL, 12},
     534             :         {"exclude-table-and-children", required_argument, NULL, 13},
     535             :         {"exclude-table-data-and-children", required_argument, NULL, 14},
     536             :         {"sync-method", required_argument, NULL, 15},
     537             :         {"filter", required_argument, NULL, 16},
     538             :         {"exclude-extension", required_argument, NULL, 17},
     539             :         {"sequence-data", no_argument, &dopt.sequence_data, 1},
     540             :         {"restrict-key", required_argument, NULL, 25},
     541             : 
     542             :         {NULL, 0, NULL, 0}
     543             :     };
     544             : 
     545         580 :     pg_logging_init(argv[0]);
     546         580 :     pg_logging_set_level(PG_LOG_WARNING);
     547         580 :     set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_dump"));
     548             : 
     549             :     /*
     550             :      * Initialize what we need for parallel execution, especially for thread
     551             :      * support on Windows.
     552             :      */
     553         580 :     init_parallel_dump_utils();
     554             : 
     555         580 :     progname = get_progname(argv[0]);
     556             : 
     557         580 :     if (argc > 1)
     558             :     {
     559         580 :         if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
     560             :         {
     561           2 :             help(progname);
     562           2 :             exit_nicely(0);
     563             :         }
     564         578 :         if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
     565             :         {
     566         124 :             puts("pg_dump (PostgreSQL) " PG_VERSION);
     567         124 :             exit_nicely(0);
     568             :         }
     569             :     }
     570             : 
     571         454 :     InitDumpOptions(&dopt);
     572             : 
     573        2520 :     while ((c = getopt_long(argc, argv, "abBcCd:e:E:f:F:h:j:n:N:Op:RsS:t:T:U:vwWxXZ:",
     574        2520 :                             long_options, &optindex)) != -1)
     575             :     {
     576        2082 :         switch (c)
     577             :         {
     578          18 :             case 'a':           /* Dump data only */
     579          18 :                 data_only = true;
     580          18 :                 break;
     581             : 
     582           2 :             case 'b':           /* Dump LOs */
     583           2 :                 dopt.outputLOs = true;
     584           2 :                 break;
     585             : 
     586           4 :             case 'B':           /* Don't dump LOs */
     587           4 :                 dopt.dontOutputLOs = true;
     588           4 :                 break;
     589             : 
     590          12 :             case 'c':           /* clean (i.e., drop) schema prior to create */
     591          12 :                 dopt.outputClean = 1;
     592          12 :                 break;
     593             : 
     594          58 :             case 'C':           /* Create DB */
     595          58 :                 dopt.outputCreateDB = 1;
     596          58 :                 break;
     597             : 
     598          10 :             case 'd':           /* database name */
     599          10 :                 dopt.cparams.dbname = pg_strdup(optarg);
     600          10 :                 break;
     601             : 
     602           8 :             case 'e':           /* include extension(s) */
     603           8 :                 simple_string_list_append(&extension_include_patterns, optarg);
     604           8 :                 dopt.include_everything = false;
     605           8 :                 break;
     606             : 
     607           4 :             case 'E':           /* Dump encoding */
     608           4 :                 dumpencoding = pg_strdup(optarg);
     609           4 :                 break;
     610             : 
     611         360 :             case 'f':
     612         360 :                 filename = pg_strdup(optarg);
     613         360 :                 break;
     614             : 
     615         216 :             case 'F':
     616         216 :                 format = pg_strdup(optarg);
     617         216 :                 break;
     618             : 
     619          68 :             case 'h':           /* server host */
     620          68 :                 dopt.cparams.pghost = pg_strdup(optarg);
     621          68 :                 break;
     622             : 
     623          22 :             case 'j':           /* number of dump jobs */
     624          22 :                 if (!option_parse_int(optarg, "-j/--jobs", 1,
     625             :                                       PG_MAX_JOBS,
     626             :                                       &numWorkers))
     627           2 :                     exit_nicely(1);
     628          20 :                 break;
     629             : 
     630          34 :             case 'n':           /* include schema(s) */
     631          34 :                 simple_string_list_append(&schema_include_patterns, optarg);
     632          34 :                 dopt.include_everything = false;
     633          34 :                 break;
     634             : 
     635           2 :             case 'N':           /* exclude schema(s) */
     636           2 :                 simple_string_list_append(&schema_exclude_patterns, optarg);
     637           2 :                 break;
     638             : 
     639           4 :             case 'O':           /* Don't reconnect to match owner */
     640           4 :                 dopt.outputNoOwner = 1;
     641           4 :                 break;
     642             : 
     643         146 :             case 'p':           /* server port */
     644         146 :                 dopt.cparams.pgport = pg_strdup(optarg);
     645         146 :                 break;
     646             : 
     647           4 :             case 'R':
     648             :                 /* no-op, still accepted for backwards compatibility */
     649           4 :                 break;
     650             : 
     651          14 :             case 's':           /* dump schema only */
     652          14 :                 schema_only = true;
     653          14 :                 break;
     654             : 
     655           2 :             case 'S':           /* Username for superuser in plain text output */
     656           2 :                 dopt.outputSuperuser = pg_strdup(optarg);
     657           2 :                 break;
     658             : 
     659          16 :             case 't':           /* include table(s) */
     660          16 :                 simple_string_list_append(&table_include_patterns, optarg);
     661          16 :                 dopt.include_everything = false;
     662          16 :                 break;
     663             : 
     664           8 :             case 'T':           /* exclude table(s) */
     665           8 :                 simple_string_list_append(&table_exclude_patterns, optarg);
     666           8 :                 break;
     667             : 
     668          72 :             case 'U':
     669          72 :                 dopt.cparams.username = pg_strdup(optarg);
     670          72 :                 break;
     671             : 
     672          12 :             case 'v':           /* verbose */
     673          12 :                 g_verbose = true;
     674          12 :                 pg_logging_increase_verbosity();
     675          12 :                 break;
     676             : 
     677           2 :             case 'w':
     678           2 :                 dopt.cparams.promptPassword = TRI_NO;
     679           2 :                 break;
     680             : 
     681           0 :             case 'W':
     682           0 :                 dopt.cparams.promptPassword = TRI_YES;
     683           0 :                 break;
     684             : 
     685           4 :             case 'x':           /* skip ACL dump */
     686           4 :                 dopt.aclsSkip = true;
     687           4 :                 break;
     688             : 
     689          24 :             case 'Z':           /* Compression */
     690          24 :                 parse_compress_options(optarg, &compression_algorithm_str,
     691             :                                        &compression_detail);
     692          24 :                 user_compression_defined = true;
     693          24 :                 break;
     694             : 
     695         256 :             case 0:
     696             :                 /* This covers the long options. */
     697         256 :                 break;
     698             : 
     699           4 :             case 2:             /* lock-wait-timeout */
     700           4 :                 dopt.lockWaitTimeout = pg_strdup(optarg);
     701           4 :                 break;
     702             : 
     703           6 :             case 3:             /* SET ROLE */
     704           6 :                 use_role = pg_strdup(optarg);
     705           6 :                 break;
     706             : 
     707           2 :             case 4:             /* exclude table(s) data */
     708           2 :                 simple_string_list_append(&tabledata_exclude_patterns, optarg);
     709           2 :                 break;
     710             : 
     711          12 :             case 5:             /* section */
     712          12 :                 set_dump_section(optarg, &dopt.dumpSections);
     713          12 :                 break;
     714             : 
     715           0 :             case 6:             /* snapshot */
     716           0 :                 dumpsnapshot = pg_strdup(optarg);
     717           0 :                 break;
     718             : 
     719         276 :             case 7:             /* no-sync */
     720         276 :                 dosync = false;
     721         276 :                 break;
     722             : 
     723           2 :             case 8:
     724           2 :                 have_extra_float_digits = true;
     725           2 :                 if (!option_parse_int(optarg, "--extra-float-digits", -15, 3,
     726             :                                       &extra_float_digits))
     727           2 :                     exit_nicely(1);
     728           0 :                 break;
     729             : 
     730           4 :             case 9:             /* inserts */
     731             : 
     732             :                 /*
     733             :                  * dump_inserts also stores --rows-per-insert, careful not to
     734             :                  * overwrite that.
     735             :                  */
     736           4 :                 if (dopt.dump_inserts == 0)
     737           4 :                     dopt.dump_inserts = DUMP_DEFAULT_ROWS_PER_INSERT;
     738           4 :                 break;
     739             : 
     740           4 :             case 10:            /* rows per insert */
     741           4 :                 if (!option_parse_int(optarg, "--rows-per-insert", 1, INT_MAX,
     742             :                                       &dopt.dump_inserts))
     743           2 :                     exit_nicely(1);
     744           2 :                 break;
     745             : 
     746           8 :             case 11:            /* include foreign data */
     747           8 :                 simple_string_list_append(&foreign_servers_include_patterns,
     748             :                                           optarg);
     749           8 :                 break;
     750             : 
     751           2 :             case 12:            /* include table(s) and their children */
     752           2 :                 simple_string_list_append(&table_include_patterns_and_children,
     753             :                                           optarg);
     754           2 :                 dopt.include_everything = false;
     755           2 :                 break;
     756             : 
     757           2 :             case 13:            /* exclude table(s) and their children */
     758           2 :                 simple_string_list_append(&table_exclude_patterns_and_children,
     759             :                                           optarg);
     760           2 :                 break;
     761             : 
     762           2 :             case 14:            /* exclude data of table(s) and children */
     763           2 :                 simple_string_list_append(&tabledata_exclude_patterns_and_children,
     764             :                                           optarg);
     765           2 :                 break;
     766             : 
     767           0 :             case 15:
     768           0 :                 if (!parse_sync_method(optarg, &sync_method))
     769           0 :                     exit_nicely(1);
     770           0 :                 break;
     771             : 
     772          52 :             case 16:            /* read object filters from file */
     773          52 :                 read_dump_filters(optarg, &dopt);
     774          44 :                 break;
     775             : 
     776           2 :             case 17:            /* exclude extension(s) */
     777           2 :                 simple_string_list_append(&extension_exclude_patterns,
     778             :                                           optarg);
     779           2 :                 break;
     780             : 
     781           8 :             case 18:
     782           8 :                 statistics_only = true;
     783           8 :                 break;
     784             : 
     785          72 :             case 19:
     786          72 :                 no_data = true;
     787          72 :                 break;
     788             : 
     789           4 :             case 20:
     790           4 :                 no_schema = true;
     791           4 :                 break;
     792             : 
     793          16 :             case 21:
     794          16 :                 no_statistics = true;
     795          16 :                 break;
     796             : 
     797         168 :             case 22:
     798         168 :                 with_statistics = true;
     799         168 :                 break;
     800             : 
     801          52 :             case 25:
     802          52 :                 dopt.restrict_key = pg_strdup(optarg);
     803          52 :                 break;
     804             : 
     805           2 :             default:
     806             :                 /* getopt_long already emitted a complaint */
     807           2 :                 pg_log_error_hint("Try \"%s --help\" for more information.", progname);
     808           2 :                 exit_nicely(1);
     809             :         }
     810             :     }
     811             : 
     812             :     /*
     813             :      * Non-option argument specifies database name as long as it wasn't
     814             :      * already specified with -d / --dbname
     815             :      */
     816         438 :     if (optind < argc && dopt.cparams.dbname == NULL)
     817         366 :         dopt.cparams.dbname = argv[optind++];
     818             : 
     819             :     /* Complain if any arguments remain */
     820         438 :     if (optind < argc)
     821             :     {
     822           2 :         pg_log_error("too many command-line arguments (first is \"%s\")",
     823             :                      argv[optind]);
     824           2 :         pg_log_error_hint("Try \"%s --help\" for more information.", progname);
     825           2 :         exit_nicely(1);
     826             :     }
     827             : 
     828             :     /* --column-inserts implies --inserts */
     829         436 :     if (dopt.column_inserts && dopt.dump_inserts == 0)
     830           2 :         dopt.dump_inserts = DUMP_DEFAULT_ROWS_PER_INSERT;
     831             : 
     832             :     /* reject conflicting "-only" options */
     833         436 :     if (data_only && schema_only)
     834           2 :         pg_fatal("options -s/--schema-only and -a/--data-only cannot be used together");
     835         434 :     if (schema_only && statistics_only)
     836           2 :         pg_fatal("options -s/--schema-only and --statistics-only cannot be used together");
     837         432 :     if (data_only && statistics_only)
     838           2 :         pg_fatal("options -a/--data-only and --statistics-only cannot be used together");
     839             : 
     840             :     /* reject conflicting "-only" and "no-" options */
     841         430 :     if (data_only && no_data)
     842           0 :         pg_fatal("options -a/--data-only and --no-data cannot be used together");
     843         430 :     if (schema_only && no_schema)
     844           0 :         pg_fatal("options -s/--schema-only and --no-schema cannot be used together");
     845         430 :     if (statistics_only && no_statistics)
     846           2 :         pg_fatal("options --statistics-only and --no-statistics cannot be used together");
     847             : 
     848             :     /* reject conflicting "no-" options */
     849         428 :     if (with_statistics && no_statistics)
     850           0 :         pg_fatal("options --statistics and --no-statistics cannot be used together");
     851             : 
     852             :     /* reject conflicting "-only" options */
     853         428 :     if (data_only && with_statistics)
     854           0 :         pg_fatal("options %s and %s cannot be used together",
     855             :                  "-a/--data-only", "--statistics");
     856         428 :     if (schema_only && with_statistics)
     857           2 :         pg_fatal("options %s and %s cannot be used together",
     858             :                  "-s/--schema-only", "--statistics");
     859             : 
     860         426 :     if (schema_only && foreign_servers_include_patterns.head != NULL)
     861           2 :         pg_fatal("options -s/--schema-only and --include-foreign-data cannot be used together");
     862             : 
     863         424 :     if (numWorkers > 1 && foreign_servers_include_patterns.head != NULL)
     864           2 :         pg_fatal("option --include-foreign-data is not supported with parallel backup");
     865             : 
     866         422 :     if (data_only && dopt.outputClean)
     867           2 :         pg_fatal("options -c/--clean and -a/--data-only cannot be used together");
     868             : 
     869         420 :     if (dopt.if_exists && !dopt.outputClean)
     870           2 :         pg_fatal("option --if-exists requires option -c/--clean");
     871             : 
     872             :     /*
     873             :      * Set derivative flags. Ambiguous or nonsensical combinations, e.g.
     874             :      * "--schema-only --no-schema", will have already caused an error in one
     875             :      * of the checks above.
     876             :      */
     877         418 :     dopt.dumpData = ((dopt.dumpData && !schema_only && !statistics_only) ||
     878         836 :                      data_only) && !no_data;
     879         418 :     dopt.dumpSchema = ((dopt.dumpSchema && !data_only && !statistics_only) ||
     880         836 :                        schema_only) && !no_schema;
     881         418 :     dopt.dumpStatistics = ((dopt.dumpStatistics && !schema_only && !data_only) ||
     882         836 :                            (statistics_only || with_statistics)) && !no_statistics;
     883             : 
     884             : 
     885             :     /*
     886             :      * --inserts are already implied above if --column-inserts or
     887             :      * --rows-per-insert were specified.
     888             :      */
     889         418 :     if (dopt.do_nothing && dopt.dump_inserts == 0)
     890           2 :         pg_fatal("option --on-conflict-do-nothing requires option --inserts, --rows-per-insert, or --column-inserts");
     891             : 
     892             :     /* Identify archive format to emit */
     893         416 :     archiveFormat = parseArchiveFormat(format, &archiveMode);
     894             : 
     895             :     /* archiveFormat specific setup */
     896         414 :     if (archiveFormat == archNull)
     897             :     {
     898         306 :         plainText = 1;
     899             : 
     900             :         /*
     901             :          * If you don't provide a restrict key, one will be appointed for you.
     902             :          */
     903         306 :         if (!dopt.restrict_key)
     904         254 :             dopt.restrict_key = generate_restrict_key();
     905         306 :         if (!dopt.restrict_key)
     906           0 :             pg_fatal("could not generate restrict key");
     907         306 :         if (!valid_restrict_key(dopt.restrict_key))
     908           0 :             pg_fatal("invalid restrict key");
     909             :     }
     910         108 :     else if (dopt.restrict_key)
     911           0 :         pg_fatal("option --restrict-key can only be used with --format=plain");
     912             : 
     913             :     /*
     914             :      * Custom and directory formats are compressed by default with gzip when
     915             :      * available, not the others.  If gzip is not available, no compression is
     916             :      * done by default.
     917             :      */
     918         414 :     if ((archiveFormat == archCustom || archiveFormat == archDirectory) &&
     919         102 :         !user_compression_defined)
     920             :     {
     921             : #ifdef HAVE_LIBZ
     922          92 :         compression_algorithm_str = "gzip";
     923             : #else
     924             :         compression_algorithm_str = "none";
     925             : #endif
     926             :     }
     927             : 
     928             :     /*
     929             :      * Compression options
     930             :      */
     931         414 :     if (!parse_compress_algorithm(compression_algorithm_str,
     932             :                                   &compression_algorithm))
     933           2 :         pg_fatal("unrecognized compression algorithm: \"%s\"",
     934             :                  compression_algorithm_str);
     935             : 
     936         412 :     parse_compress_specification(compression_algorithm, compression_detail,
     937             :                                  &compression_spec);
     938         412 :     error_detail = validate_compress_specification(&compression_spec);
     939         412 :     if (error_detail != NULL)
     940           6 :         pg_fatal("invalid compression specification: %s",
     941             :                  error_detail);
     942             : 
     943         406 :     error_detail = supports_compression(compression_spec);
     944         406 :     if (error_detail != NULL)
     945           0 :         pg_fatal("%s", error_detail);
     946             : 
     947             :     /*
     948             :      * Disable support for zstd workers for now - these are based on
     949             :      * threading, and it's unclear how it interacts with parallel dumps on
     950             :      * platforms where that relies on threads too (e.g. Windows).
     951             :      */
     952         406 :     if (compression_spec.options & PG_COMPRESSION_OPTION_WORKERS)
     953           0 :         pg_log_warning("compression option \"%s\" is not currently supported by pg_dump",
     954             :                        "workers");
     955             : 
     956             :     /*
     957             :      * If emitting an archive format, we always want to emit a DATABASE item,
     958             :      * in case --create is specified at pg_restore time.
     959             :      */
     960         406 :     if (!plainText)
     961         108 :         dopt.outputCreateDB = 1;
     962             : 
     963             :     /* Parallel backup only in the directory archive format so far */
     964         406 :     if (archiveFormat != archDirectory && numWorkers > 1)
     965           2 :         pg_fatal("parallel backup only supported by the directory format");
     966             : 
     967             :     /* Open the output file */
     968         404 :     fout = CreateArchive(filename, archiveFormat, compression_spec,
     969             :                          dosync, archiveMode, setupDumpWorker, sync_method);
     970             : 
     971             :     /* Make dump options accessible right away */
     972         402 :     SetArchiveOptions(fout, &dopt, NULL);
     973             : 
     974             :     /* Register the cleanup hook */
     975         402 :     on_exit_close_archive(fout);
     976             : 
     977             :     /* Let the archiver know how noisy to be */
     978         402 :     fout->verbose = g_verbose;
     979             : 
     980             : 
     981             :     /*
     982             :      * We allow the server to be back to 9.2, and up to any minor release of
     983             :      * our own major version.  (See also version check in pg_dumpall.c.)
     984             :      */
     985         402 :     fout->minRemoteVersion = 90200;
     986         402 :     fout->maxRemoteVersion = (PG_VERSION_NUM / 100) * 100 + 99;
     987             : 
     988         402 :     fout->numWorkers = numWorkers;
     989             : 
     990             :     /*
     991             :      * Open the database using the Archiver, so it knows about it. Errors mean
     992             :      * death.
     993             :      */
     994         402 :     ConnectDatabaseAhx(fout, &dopt.cparams, false);
     995         398 :     setup_connection(fout, dumpencoding, dumpsnapshot, use_role);
     996             : 
     997             :     /*
     998             :      * On hot standbys, never try to dump unlogged table data, since it will
     999             :      * just throw an error.
    1000             :      */
    1001         398 :     if (fout->isStandby)
    1002           8 :         dopt.no_unlogged_table_data = true;
    1003             : 
    1004             :     /*
    1005             :      * Find the last built-in OID, if needed (prior to 8.1)
    1006             :      *
    1007             :      * With 8.1 and above, we can just use FirstNormalObjectId - 1.
    1008             :      */
    1009         398 :     g_last_builtin_oid = FirstNormalObjectId - 1;
    1010             : 
    1011         398 :     pg_log_info("last built-in OID is %u", g_last_builtin_oid);
    1012             : 
    1013             :     /* Expand schema selection patterns into OID lists */
    1014         398 :     if (schema_include_patterns.head != NULL)
    1015             :     {
    1016          36 :         expand_schema_name_patterns(fout, &schema_include_patterns,
    1017             :                                     &schema_include_oids,
    1018             :                                     strict_names);
    1019          24 :         if (schema_include_oids.head == NULL)
    1020           2 :             pg_fatal("no matching schemas were found");
    1021             :     }
    1022         384 :     expand_schema_name_patterns(fout, &schema_exclude_patterns,
    1023             :                                 &schema_exclude_oids,
    1024             :                                 false);
    1025             :     /* non-matching exclusion patterns aren't an error */
    1026             : 
    1027             :     /* Expand table selection patterns into OID lists */
    1028         384 :     expand_table_name_patterns(fout, &table_include_patterns,
    1029             :                                &table_include_oids,
    1030             :                                strict_names, false);
    1031         374 :     expand_table_name_patterns(fout, &table_include_patterns_and_children,
    1032             :                                &table_include_oids,
    1033             :                                strict_names, true);
    1034         374 :     if ((table_include_patterns.head != NULL ||
    1035         352 :          table_include_patterns_and_children.head != NULL) &&
    1036          26 :         table_include_oids.head == NULL)
    1037           4 :         pg_fatal("no matching tables were found");
    1038             : 
    1039         370 :     expand_table_name_patterns(fout, &table_exclude_patterns,
    1040             :                                &table_exclude_oids,
    1041             :                                false, false);
    1042         370 :     expand_table_name_patterns(fout, &table_exclude_patterns_and_children,
    1043             :                                &table_exclude_oids,
    1044             :                                false, true);
    1045             : 
    1046         370 :     expand_table_name_patterns(fout, &tabledata_exclude_patterns,
    1047             :                                &tabledata_exclude_oids,
    1048             :                                false, false);
    1049         370 :     expand_table_name_patterns(fout, &tabledata_exclude_patterns_and_children,
    1050             :                                &tabledata_exclude_oids,
    1051             :                                false, true);
    1052             : 
    1053         370 :     expand_foreign_server_name_patterns(fout, &foreign_servers_include_patterns,
    1054             :                                         &foreign_servers_include_oids);
    1055             : 
    1056             :     /* non-matching exclusion patterns aren't an error */
    1057             : 
    1058             :     /* Expand extension selection patterns into OID lists */
    1059         368 :     if (extension_include_patterns.head != NULL)
    1060             :     {
    1061          10 :         expand_extension_name_patterns(fout, &extension_include_patterns,
    1062             :                                        &extension_include_oids,
    1063             :                                        strict_names);
    1064          10 :         if (extension_include_oids.head == NULL)
    1065           2 :             pg_fatal("no matching extensions were found");
    1066             :     }
    1067         366 :     expand_extension_name_patterns(fout, &extension_exclude_patterns,
    1068             :                                    &extension_exclude_oids,
    1069             :                                    false);
    1070             :     /* non-matching exclusion patterns aren't an error */
    1071             : 
    1072             :     /*
    1073             :      * Dumping LOs is the default for dumps where an inclusion switch is not
    1074             :      * used (an "include everything" dump).  -B can be used to exclude LOs
    1075             :      * from those dumps.  -b can be used to include LOs even when an inclusion
    1076             :      * switch is used.
    1077             :      *
    1078             :      * -s means "schema only" and LOs are data, not schema, so we never
    1079             :      * include LOs when -s is used.
    1080             :      */
    1081         366 :     if (dopt.include_everything && dopt.dumpData && !dopt.dontOutputLOs)
    1082         236 :         dopt.outputLOs = true;
    1083             : 
    1084             :     /*
    1085             :      * Collect role names so we can map object owner OIDs to names.
    1086             :      */
    1087         366 :     collectRoleNames(fout);
    1088             : 
    1089             :     /*
    1090             :      * Now scan the database and create DumpableObject structs for all the
    1091             :      * objects we intend to dump.
    1092             :      */
    1093         366 :     tblinfo = getSchemaData(fout, &numTables);
    1094             : 
    1095         364 :     if (dopt.dumpData)
    1096             :     {
    1097         284 :         getTableData(&dopt, tblinfo, numTables, 0);
    1098         284 :         buildMatViewRefreshDependencies(fout);
    1099         284 :         if (!dopt.dumpSchema)
    1100          14 :             getTableDataFKConstraints();
    1101             :     }
    1102             : 
    1103         364 :     if (!dopt.dumpData && dopt.sequence_data)
    1104          64 :         getTableData(&dopt, tblinfo, numTables, RELKIND_SEQUENCE);
    1105             : 
    1106             :     /*
    1107             :      * For binary upgrade mode, dump pg_largeobject_metadata and the
    1108             :      * associated pg_shdepend rows. This is faster to restore than the
    1109             :      * equivalent set of large object commands.  We can only do this for
    1110             :      * upgrades from v12 and newer; in older versions, pg_largeobject_metadata
    1111             :      * was created WITH OIDS, so the OID column is hidden and won't be dumped.
    1112             :      */
    1113         364 :     if (dopt.binary_upgrade && fout->remoteVersion >= 120000)
    1114             :     {
    1115          72 :         TableInfo  *lo_metadata = findTableByOid(LargeObjectMetadataRelationId);
    1116          72 :         TableInfo  *shdepend = findTableByOid(SharedDependRelationId);
    1117             : 
    1118          72 :         makeTableDataInfo(&dopt, lo_metadata);
    1119          72 :         makeTableDataInfo(&dopt, shdepend);
    1120             : 
    1121             :         /*
    1122             :          * Save pg_largeobject_metadata's dump ID for use as a dependency for
    1123             :          * pg_shdepend and any large object comments/seclabels.
    1124             :          */
    1125          72 :         lo_metadata_dumpId = lo_metadata->dataObj->dobj.dumpId;
    1126          72 :         addObjectDependency(&shdepend->dataObj->dobj, lo_metadata_dumpId);
    1127             : 
    1128             :         /*
    1129             :          * Only dump large object shdepend rows for this database.
    1130             :          */
    1131          72 :         shdepend->dataObj->filtercond = "WHERE classid = 'pg_largeobject'::regclass "
    1132             :             "AND dbid = (SELECT oid FROM pg_database "
    1133             :             "            WHERE datname = current_database())";
    1134             :     }
    1135             : 
    1136             :     /*
    1137             :      * In binary-upgrade mode, we do not have to worry about the actual LO
    1138             :      * data or the associated metadata that resides in the pg_largeobject and
    1139             :      * pg_largeobject_metadata tables, respectively.
    1140             :      *
    1141             :      * However, we do need to collect LO information as there may be comments
    1142             :      * or other information on LOs that we do need to dump out.
    1143             :      */
    1144         364 :     if (dopt.outputLOs || dopt.binary_upgrade)
    1145         308 :         getLOs(fout);
    1146             : 
    1147             :     /*
    1148             :      * Collect dependency data to assist in ordering the objects.
    1149             :      */
    1150         364 :     getDependencies(fout);
    1151             : 
    1152             :     /*
    1153             :      * Collect ACLs, comments, and security labels, if wanted.
    1154             :      */
    1155         364 :     if (!dopt.aclsSkip)
    1156         360 :         getAdditionalACLs(fout);
    1157         364 :     if (!dopt.no_comments)
    1158         364 :         collectComments(fout);
    1159         364 :     if (!dopt.no_security_labels)
    1160         364 :         collectSecLabels(fout);
    1161             : 
    1162             :     /* For binary upgrade mode, collect required pg_class information. */
    1163         364 :     if (dopt.binary_upgrade)
    1164          72 :         collectBinaryUpgradeClassOids(fout);
    1165             : 
    1166             :     /* Collect sequence information. */
    1167         364 :     collectSequences(fout);
    1168             : 
    1169             :     /* Lastly, create dummy objects to represent the section boundaries */
    1170         364 :     boundaryObjs = createBoundaryObjects();
    1171             : 
    1172             :     /* Get pointers to all the known DumpableObjects */
    1173         364 :     getDumpableObjects(&dobjs, &numObjs);
    1174             : 
    1175             :     /*
    1176             :      * Add dummy dependencies to enforce the dump section ordering.
    1177             :      */
    1178         364 :     addBoundaryDependencies(dobjs, numObjs, boundaryObjs);
    1179             : 
    1180             :     /*
    1181             :      * Sort the objects into a safe dump order (no forward references).
    1182             :      *
    1183             :      * We rely on dependency information to help us determine a safe order, so
    1184             :      * the initial sort is mostly for cosmetic purposes: we sort by name to
    1185             :      * ensure that logically identical schemas will dump identically.
    1186             :      */
    1187         364 :     sortDumpableObjectsByTypeName(dobjs, numObjs);
    1188             : 
    1189         364 :     sortDumpableObjects(dobjs, numObjs,
    1190         364 :                         boundaryObjs[0].dumpId, boundaryObjs[1].dumpId);
    1191             : 
    1192             :     /*
    1193             :      * Create archive TOC entries for all the objects to be dumped, in a safe
    1194             :      * order.
    1195             :      */
    1196             : 
    1197             :     /*
    1198             :      * First the special entries for ENCODING, STDSTRINGS, and SEARCHPATH.
    1199             :      */
    1200         364 :     dumpEncoding(fout);
    1201         364 :     dumpStdStrings(fout);
    1202         364 :     dumpSearchPath(fout);
    1203             : 
    1204             :     /* The database items are always next, unless we don't want them at all */
    1205         364 :     if (dopt.outputCreateDB)
    1206         164 :         dumpDatabase(fout);
    1207             : 
    1208             :     /* Now the rearrangeable objects. */
    1209     1355506 :     for (i = 0; i < numObjs; i++)
    1210     1355142 :         dumpDumpableObject(fout, dobjs[i]);
    1211             : 
    1212             :     /*
    1213             :      * Set up options info to ensure we dump what we want.
    1214             :      */
    1215         364 :     ropt = NewRestoreOptions();
    1216         364 :     ropt->filename = filename;
    1217             : 
    1218             :     /* if you change this list, see dumpOptionsFromRestoreOptions */
    1219         364 :     ropt->cparams.dbname = dopt.cparams.dbname ? pg_strdup(dopt.cparams.dbname) : NULL;
    1220         364 :     ropt->cparams.pgport = dopt.cparams.pgport ? pg_strdup(dopt.cparams.pgport) : NULL;
    1221         364 :     ropt->cparams.pghost = dopt.cparams.pghost ? pg_strdup(dopt.cparams.pghost) : NULL;
    1222         364 :     ropt->cparams.username = dopt.cparams.username ? pg_strdup(dopt.cparams.username) : NULL;
    1223         364 :     ropt->cparams.promptPassword = dopt.cparams.promptPassword;
    1224         364 :     ropt->dropSchema = dopt.outputClean;
    1225         364 :     ropt->dumpData = dopt.dumpData;
    1226         364 :     ropt->dumpSchema = dopt.dumpSchema;
    1227         364 :     ropt->dumpStatistics = dopt.dumpStatistics;
    1228         364 :     ropt->if_exists = dopt.if_exists;
    1229         364 :     ropt->column_inserts = dopt.column_inserts;
    1230         364 :     ropt->dumpSections = dopt.dumpSections;
    1231         364 :     ropt->aclsSkip = dopt.aclsSkip;
    1232         364 :     ropt->superuser = dopt.outputSuperuser;
    1233         364 :     ropt->createDB = dopt.outputCreateDB;
    1234         364 :     ropt->noOwner = dopt.outputNoOwner;
    1235         364 :     ropt->noTableAm = dopt.outputNoTableAm;
    1236         364 :     ropt->noTablespace = dopt.outputNoTablespaces;
    1237         364 :     ropt->disable_triggers = dopt.disable_triggers;
    1238         364 :     ropt->use_setsessauth = dopt.use_setsessauth;
    1239         364 :     ropt->disable_dollar_quoting = dopt.disable_dollar_quoting;
    1240         364 :     ropt->dump_inserts = dopt.dump_inserts;
    1241         364 :     ropt->no_comments = dopt.no_comments;
    1242         364 :     ropt->no_policies = dopt.no_policies;
    1243         364 :     ropt->no_publications = dopt.no_publications;
    1244         364 :     ropt->no_security_labels = dopt.no_security_labels;
    1245         364 :     ropt->no_subscriptions = dopt.no_subscriptions;
    1246         364 :     ropt->lockWaitTimeout = dopt.lockWaitTimeout;
    1247         364 :     ropt->include_everything = dopt.include_everything;
    1248         364 :     ropt->enable_row_security = dopt.enable_row_security;
    1249         364 :     ropt->sequence_data = dopt.sequence_data;
    1250         364 :     ropt->binary_upgrade = dopt.binary_upgrade;
    1251         364 :     ropt->restrict_key = dopt.restrict_key ? pg_strdup(dopt.restrict_key) : NULL;
    1252             : 
    1253         364 :     ropt->compression_spec = compression_spec;
    1254             : 
    1255         364 :     ropt->suppressDumpWarnings = true;   /* We've already shown them */
    1256             : 
    1257         364 :     SetArchiveOptions(fout, &dopt, ropt);
    1258             : 
    1259             :     /* Mark which entries should be output */
    1260         364 :     ProcessArchiveRestoreOptions(fout);
    1261             : 
    1262             :     /*
    1263             :      * The archive's TOC entries are now marked as to which ones will actually
    1264             :      * be output, so we can set up their dependency lists properly. This isn't
    1265             :      * necessary for plain-text output, though.
    1266             :      */
    1267         364 :     if (!plainText)
    1268         106 :         BuildArchiveDependencies(fout);
    1269             : 
    1270             :     /*
    1271             :      * And finally we can do the actual output.
    1272             :      *
    1273             :      * Note: for non-plain-text output formats, the output file is written
    1274             :      * inside CloseArchive().  This is, um, bizarre; but not worth changing
    1275             :      * right now.
    1276             :      */
    1277         364 :     if (plainText)
    1278         258 :         RestoreArchive(fout);
    1279             : 
    1280         362 :     CloseArchive(fout);
    1281             : 
    1282         362 :     exit_nicely(0);
    1283             : }
    1284             : 
    1285             : 
    1286             : static void
    1287           2 : help(const char *progname)
    1288             : {
    1289           2 :     printf(_("%s exports a PostgreSQL database as an SQL script or to other formats.\n\n"), progname);
    1290           2 :     printf(_("Usage:\n"));
    1291           2 :     printf(_("  %s [OPTION]... [DBNAME]\n"), progname);
    1292             : 
    1293           2 :     printf(_("\nGeneral options:\n"));
    1294           2 :     printf(_("  -f, --file=FILENAME          output file or directory name\n"));
    1295           2 :     printf(_("  -F, --format=c|d|t|p         output file format (custom, directory, tar,\n"
    1296             :              "                               plain text (default))\n"));
    1297           2 :     printf(_("  -j, --jobs=NUM               use this many parallel jobs to dump\n"));
    1298           2 :     printf(_("  -v, --verbose                verbose mode\n"));
    1299           2 :     printf(_("  -V, --version                output version information, then exit\n"));
    1300           2 :     printf(_("  -Z, --compress=METHOD[:DETAIL]\n"
    1301             :              "                               compress as specified\n"));
    1302           2 :     printf(_("  --lock-wait-timeout=TIMEOUT  fail after waiting TIMEOUT for a table lock\n"));
    1303           2 :     printf(_("  --no-sync                    do not wait for changes to be written safely to disk\n"));
    1304           2 :     printf(_("  --sync-method=METHOD         set method for syncing files to disk\n"));
    1305           2 :     printf(_("  -?, --help                   show this help, then exit\n"));
    1306             : 
    1307           2 :     printf(_("\nOptions controlling the output content:\n"));
    1308           2 :     printf(_("  -a, --data-only              dump only the data, not the schema or statistics\n"));
    1309           2 :     printf(_("  -b, --large-objects          include large objects in dump\n"));
    1310           2 :     printf(_("  --blobs                      (same as --large-objects, deprecated)\n"));
    1311           2 :     printf(_("  -B, --no-large-objects       exclude large objects in dump\n"));
    1312           2 :     printf(_("  --no-blobs                   (same as --no-large-objects, deprecated)\n"));
    1313           2 :     printf(_("  -c, --clean                  clean (drop) database objects before recreating\n"));
    1314           2 :     printf(_("  -C, --create                 include commands to create database in dump\n"));
    1315           2 :     printf(_("  -e, --extension=PATTERN      dump the specified extension(s) only\n"));
    1316           2 :     printf(_("  -E, --encoding=ENCODING      dump the data in encoding ENCODING\n"));
    1317           2 :     printf(_("  -n, --schema=PATTERN         dump the specified schema(s) only\n"));
    1318           2 :     printf(_("  -N, --exclude-schema=PATTERN do NOT dump the specified schema(s)\n"));
    1319           2 :     printf(_("  -O, --no-owner               skip restoration of object ownership in\n"
    1320             :              "                               plain-text format\n"));
    1321           2 :     printf(_("  -s, --schema-only            dump only the schema, no data or statistics\n"));
    1322           2 :     printf(_("  -S, --superuser=NAME         superuser user name to use in plain-text format\n"));
    1323           2 :     printf(_("  -t, --table=PATTERN          dump only the specified table(s)\n"));
    1324           2 :     printf(_("  -T, --exclude-table=PATTERN  do NOT dump the specified table(s)\n"));
    1325           2 :     printf(_("  -x, --no-privileges          do not dump privileges (grant/revoke)\n"));
    1326           2 :     printf(_("  --binary-upgrade             for use by upgrade utilities only\n"));
    1327           2 :     printf(_("  --column-inserts             dump data as INSERT commands with column names\n"));
    1328           2 :     printf(_("  --disable-dollar-quoting     disable dollar quoting, use SQL standard quoting\n"));
    1329           2 :     printf(_("  --disable-triggers           disable triggers during data-only restore\n"));
    1330           2 :     printf(_("  --enable-row-security        enable row security (dump only content user has\n"
    1331             :              "                               access to)\n"));
    1332           2 :     printf(_("  --exclude-extension=PATTERN  do NOT dump the specified extension(s)\n"));
    1333           2 :     printf(_("  --exclude-table-and-children=PATTERN\n"
    1334             :              "                               do NOT dump the specified table(s), including\n"
    1335             :              "                               child and partition tables\n"));
    1336           2 :     printf(_("  --exclude-table-data=PATTERN do NOT dump data for the specified table(s)\n"));
    1337           2 :     printf(_("  --exclude-table-data-and-children=PATTERN\n"
    1338             :              "                               do NOT dump data for the specified table(s),\n"
    1339             :              "                               including child and partition tables\n"));
    1340           2 :     printf(_("  --extra-float-digits=NUM     override default setting for extra_float_digits\n"));
    1341           2 :     printf(_("  --filter=FILENAME            include or exclude objects and data from dump\n"
    1342             :              "                               based on expressions in FILENAME\n"));
    1343           2 :     printf(_("  --if-exists                  use IF EXISTS when dropping objects\n"));
    1344           2 :     printf(_("  --include-foreign-data=PATTERN\n"
    1345             :              "                               include data of foreign tables on foreign\n"
    1346             :              "                               servers matching PATTERN\n"));
    1347           2 :     printf(_("  --inserts                    dump data as INSERT commands, rather than COPY\n"));
    1348           2 :     printf(_("  --load-via-partition-root    load partitions via the root table\n"));
    1349           2 :     printf(_("  --no-comments                do not dump comment commands\n"));
    1350           2 :     printf(_("  --no-data                    do not dump data\n"));
    1351           2 :     printf(_("  --no-policies                do not dump row security policies\n"));
    1352           2 :     printf(_("  --no-publications            do not dump publications\n"));
    1353           2 :     printf(_("  --no-schema                  do not dump schema\n"));
    1354           2 :     printf(_("  --no-security-labels         do not dump security label assignments\n"));
    1355           2 :     printf(_("  --no-statistics              do not dump statistics\n"));
    1356           2 :     printf(_("  --no-subscriptions           do not dump subscriptions\n"));
    1357           2 :     printf(_("  --no-table-access-method     do not dump table access methods\n"));
    1358           2 :     printf(_("  --no-tablespaces             do not dump tablespace assignments\n"));
    1359           2 :     printf(_("  --no-toast-compression       do not dump TOAST compression methods\n"));
    1360           2 :     printf(_("  --no-unlogged-table-data     do not dump unlogged table data\n"));
    1361           2 :     printf(_("  --on-conflict-do-nothing     add ON CONFLICT DO NOTHING to INSERT commands\n"));
    1362           2 :     printf(_("  --quote-all-identifiers      quote all identifiers, even if not key words\n"));
    1363           2 :     printf(_("  --restrict-key=RESTRICT_KEY  use provided string as psql \\restrict key\n"));
    1364           2 :     printf(_("  --rows-per-insert=NROWS      number of rows per INSERT; implies --inserts\n"));
    1365           2 :     printf(_("  --section=SECTION            dump named section (pre-data, data, or post-data)\n"));
    1366           2 :     printf(_("  --sequence-data              include sequence data in dump\n"));
    1367           2 :     printf(_("  --serializable-deferrable    wait until the dump can run without anomalies\n"));
    1368           2 :     printf(_("  --snapshot=SNAPSHOT          use given snapshot for the dump\n"));
    1369           2 :     printf(_("  --statistics                 dump the statistics\n"));
    1370           2 :     printf(_("  --statistics-only            dump only the statistics, not schema or data\n"));
    1371           2 :     printf(_("  --strict-names               require table and/or schema include patterns to\n"
    1372             :              "                               match at least one entity each\n"));
    1373           2 :     printf(_("  --table-and-children=PATTERN dump only the specified table(s), including\n"
    1374             :              "                               child and partition tables\n"));
    1375           2 :     printf(_("  --use-set-session-authorization\n"
    1376             :              "                               use SET SESSION AUTHORIZATION commands instead of\n"
    1377             :              "                               ALTER OWNER commands to set ownership\n"));
    1378             : 
    1379           2 :     printf(_("\nConnection options:\n"));
    1380           2 :     printf(_("  -d, --dbname=DBNAME      database to dump\n"));
    1381           2 :     printf(_("  -h, --host=HOSTNAME      database server host or socket directory\n"));
    1382           2 :     printf(_("  -p, --port=PORT          database server port number\n"));
    1383           2 :     printf(_("  -U, --username=NAME      connect as specified database user\n"));
    1384           2 :     printf(_("  -w, --no-password        never prompt for password\n"));
    1385           2 :     printf(_("  -W, --password           force password prompt (should happen automatically)\n"));
    1386           2 :     printf(_("  --role=ROLENAME          do SET ROLE before dump\n"));
    1387             : 
    1388           2 :     printf(_("\nIf no database name is supplied, then the PGDATABASE environment\n"
    1389             :              "variable value is used.\n\n"));
    1390           2 :     printf(_("Report bugs to <%s>.\n"), PACKAGE_BUGREPORT);
    1391           2 :     printf(_("%s home page: <%s>\n"), PACKAGE_NAME, PACKAGE_URL);
    1392           2 : }
    1393             : 
    1394             : static void
    1395         430 : setup_connection(Archive *AH, const char *dumpencoding,
    1396             :                  const char *dumpsnapshot, char *use_role)
    1397             : {
    1398         430 :     DumpOptions *dopt = AH->dopt;
    1399         430 :     PGconn     *conn = GetConnection(AH);
    1400             :     const char *std_strings;
    1401             : 
    1402         430 :     PQclear(ExecuteSqlQueryForSingleRow(AH, ALWAYS_SECURE_SEARCH_PATH_SQL));
    1403             : 
    1404             :     /*
    1405             :      * Set the client encoding if requested.
    1406             :      */
    1407         430 :     if (dumpencoding)
    1408             :     {
    1409          36 :         if (PQsetClientEncoding(conn, dumpencoding) < 0)
    1410           0 :             pg_fatal("invalid client encoding \"%s\" specified",
    1411             :                      dumpencoding);
    1412             :     }
    1413             : 
    1414             :     /*
    1415             :      * Get the active encoding and the standard_conforming_strings setting, so
    1416             :      * we know how to escape strings.
    1417             :      */
    1418         430 :     AH->encoding = PQclientEncoding(conn);
    1419         430 :     setFmtEncoding(AH->encoding);
    1420             : 
    1421         430 :     std_strings = PQparameterStatus(conn, "standard_conforming_strings");
    1422         430 :     AH->std_strings = (std_strings && strcmp(std_strings, "on") == 0);
    1423             : 
    1424             :     /*
    1425             :      * Set the role if requested.  In a parallel dump worker, we'll be passed
    1426             :      * use_role == NULL, but AH->use_role is already set (if user specified it
    1427             :      * originally) and we should use that.
    1428             :      */
    1429         430 :     if (!use_role && AH->use_role)
    1430           4 :         use_role = AH->use_role;
    1431             : 
    1432             :     /* Set the role if requested */
    1433         430 :     if (use_role)
    1434             :     {
    1435          10 :         PQExpBuffer query = createPQExpBuffer();
    1436             : 
    1437          10 :         appendPQExpBuffer(query, "SET ROLE %s", fmtId(use_role));
    1438          10 :         ExecuteSqlStatement(AH, query->data);
    1439          10 :         destroyPQExpBuffer(query);
    1440             : 
    1441             :         /* save it for possible later use by parallel workers */
    1442          10 :         if (!AH->use_role)
    1443           6 :             AH->use_role = pg_strdup(use_role);
    1444             :     }
    1445             : 
    1446             :     /* Set the datestyle to ISO to ensure the dump's portability */
    1447         430 :     ExecuteSqlStatement(AH, "SET DATESTYLE = ISO");
    1448             : 
    1449             :     /* Likewise, avoid using sql_standard intervalstyle */
    1450         430 :     ExecuteSqlStatement(AH, "SET INTERVALSTYLE = POSTGRES");
    1451             : 
    1452             :     /*
    1453             :      * Use an explicitly specified extra_float_digits if it has been provided.
    1454             :      * Otherwise, set extra_float_digits so that we can dump float data
    1455             :      * exactly (given correctly implemented float I/O code, anyway).
    1456             :      */
    1457         430 :     if (have_extra_float_digits)
    1458             :     {
    1459           0 :         PQExpBuffer q = createPQExpBuffer();
    1460             : 
    1461           0 :         appendPQExpBuffer(q, "SET extra_float_digits TO %d",
    1462             :                           extra_float_digits);
    1463           0 :         ExecuteSqlStatement(AH, q->data);
    1464           0 :         destroyPQExpBuffer(q);
    1465             :     }
    1466             :     else
    1467         430 :         ExecuteSqlStatement(AH, "SET extra_float_digits TO 3");
    1468             : 
    1469             :     /*
    1470             :      * Disable synchronized scanning, to prevent unpredictable changes in row
    1471             :      * ordering across a dump and reload.
    1472             :      */
    1473         430 :     ExecuteSqlStatement(AH, "SET synchronize_seqscans TO off");
    1474             : 
    1475             :     /*
    1476             :      * Disable timeouts if supported.
    1477             :      */
    1478         430 :     ExecuteSqlStatement(AH, "SET statement_timeout = 0");
    1479         430 :     if (AH->remoteVersion >= 90300)
    1480         430 :         ExecuteSqlStatement(AH, "SET lock_timeout = 0");
    1481         430 :     if (AH->remoteVersion >= 90600)
    1482         430 :         ExecuteSqlStatement(AH, "SET idle_in_transaction_session_timeout = 0");
    1483         430 :     if (AH->remoteVersion >= 170000)
    1484         430 :         ExecuteSqlStatement(AH, "SET transaction_timeout = 0");
    1485             : 
    1486             :     /*
    1487             :      * Quote all identifiers, if requested.
    1488             :      */
    1489         430 :     if (quote_all_identifiers)
    1490          68 :         ExecuteSqlStatement(AH, "SET quote_all_identifiers = true");
    1491             : 
    1492             :     /*
    1493             :      * Adjust row-security mode, if supported.
    1494             :      */
    1495         430 :     if (AH->remoteVersion >= 90500)
    1496             :     {
    1497         430 :         if (dopt->enable_row_security)
    1498           0 :             ExecuteSqlStatement(AH, "SET row_security = on");
    1499             :         else
    1500         430 :             ExecuteSqlStatement(AH, "SET row_security = off");
    1501             :     }
    1502             : 
    1503             :     /*
    1504             :      * For security reasons, we restrict the expansion of non-system views and
    1505             :      * access to foreign tables during the pg_dump process. This restriction
    1506             :      * is adjusted when dumping foreign table data.
    1507             :      */
    1508         430 :     set_restrict_relation_kind(AH, "view, foreign-table");
    1509             : 
    1510             :     /*
    1511             :      * Initialize prepared-query state to "nothing prepared".  We do this here
    1512             :      * so that a parallel dump worker will have its own state.
    1513             :      */
    1514         430 :     AH->is_prepared = (bool *) pg_malloc0(NUM_PREP_QUERIES * sizeof(bool));
    1515             : 
    1516             :     /*
    1517             :      * Start transaction-snapshot mode transaction to dump consistent data.
    1518             :      */
    1519         430 :     ExecuteSqlStatement(AH, "BEGIN");
    1520             : 
    1521             :     /*
    1522             :      * To support the combination of serializable_deferrable with the jobs
    1523             :      * option we use REPEATABLE READ for the worker connections that are
    1524             :      * passed a snapshot.  As long as the snapshot is acquired in a
    1525             :      * SERIALIZABLE, READ ONLY, DEFERRABLE transaction, its use within a
    1526             :      * REPEATABLE READ transaction provides the appropriate integrity
    1527             :      * guarantees.  This is a kluge, but safe for back-patching.
    1528             :      */
    1529         430 :     if (dopt->serializable_deferrable && AH->sync_snapshot_id == NULL)
    1530           0 :         ExecuteSqlStatement(AH,
    1531             :                             "SET TRANSACTION ISOLATION LEVEL "
    1532             :                             "SERIALIZABLE, READ ONLY, DEFERRABLE");
    1533             :     else
    1534         430 :         ExecuteSqlStatement(AH,
    1535             :                             "SET TRANSACTION ISOLATION LEVEL "
    1536             :                             "REPEATABLE READ, READ ONLY");
    1537             : 
    1538             :     /*
    1539             :      * If user specified a snapshot to use, select that.  In a parallel dump
    1540             :      * worker, we'll be passed dumpsnapshot == NULL, but AH->sync_snapshot_id
    1541             :      * is already set (if the server can handle it) and we should use that.
    1542             :      */
    1543         430 :     if (dumpsnapshot)
    1544           0 :         AH->sync_snapshot_id = pg_strdup(dumpsnapshot);
    1545             : 
    1546         430 :     if (AH->sync_snapshot_id)
    1547             :     {
    1548          32 :         PQExpBuffer query = createPQExpBuffer();
    1549             : 
    1550          32 :         appendPQExpBufferStr(query, "SET TRANSACTION SNAPSHOT ");
    1551          32 :         appendStringLiteralConn(query, AH->sync_snapshot_id, conn);
    1552          32 :         ExecuteSqlStatement(AH, query->data);
    1553          32 :         destroyPQExpBuffer(query);
    1554             :     }
    1555         398 :     else if (AH->numWorkers > 1)
    1556             :     {
    1557          16 :         if (AH->isStandby && AH->remoteVersion < 100000)
    1558           0 :             pg_fatal("parallel dumps from standby servers are not supported by this server version");
    1559          16 :         AH->sync_snapshot_id = get_synchronized_snapshot(AH);
    1560             :     }
    1561         430 : }
    1562             : 
    1563             : /* Set up connection for a parallel worker process */
    1564             : static void
    1565          32 : setupDumpWorker(Archive *AH)
    1566             : {
    1567             :     /*
    1568             :      * We want to re-select all the same values the leader connection is
    1569             :      * using.  We'll have inherited directly-usable values in
    1570             :      * AH->sync_snapshot_id and AH->use_role, but we need to translate the
    1571             :      * inherited encoding value back to a string to pass to setup_connection.
    1572             :      */
    1573          32 :     setup_connection(AH,
    1574             :                      pg_encoding_to_char(AH->encoding),
    1575             :                      NULL,
    1576             :                      NULL);
    1577          32 : }
    1578             : 
    1579             : static char *
    1580          16 : get_synchronized_snapshot(Archive *fout)
    1581             : {
    1582          16 :     char       *query = "SELECT pg_catalog.pg_export_snapshot()";
    1583             :     char       *result;
    1584             :     PGresult   *res;
    1585             : 
    1586          16 :     res = ExecuteSqlQueryForSingleRow(fout, query);
    1587          16 :     result = pg_strdup(PQgetvalue(res, 0, 0));
    1588          16 :     PQclear(res);
    1589             : 
    1590          16 :     return result;
    1591             : }
    1592             : 
    1593             : static ArchiveFormat
    1594         416 : parseArchiveFormat(const char *format, ArchiveMode *mode)
    1595             : {
    1596             :     ArchiveFormat archiveFormat;
    1597             : 
    1598         416 :     *mode = archModeWrite;
    1599             : 
    1600         416 :     if (pg_strcasecmp(format, "a") == 0 || pg_strcasecmp(format, "append") == 0)
    1601             :     {
    1602             :         /* This is used by pg_dumpall, and is not documented */
    1603          86 :         archiveFormat = archNull;
    1604          86 :         *mode = archModeAppend;
    1605             :     }
    1606         330 :     else if (pg_strcasecmp(format, "c") == 0)
    1607           0 :         archiveFormat = archCustom;
    1608         330 :     else if (pg_strcasecmp(format, "custom") == 0)
    1609          82 :         archiveFormat = archCustom;
    1610         248 :     else if (pg_strcasecmp(format, "d") == 0)
    1611           0 :         archiveFormat = archDirectory;
    1612         248 :     else if (pg_strcasecmp(format, "directory") == 0)
    1613          20 :         archiveFormat = archDirectory;
    1614         228 :     else if (pg_strcasecmp(format, "p") == 0)
    1615         214 :         archiveFormat = archNull;
    1616          14 :     else if (pg_strcasecmp(format, "plain") == 0)
    1617           6 :         archiveFormat = archNull;
    1618           8 :     else if (pg_strcasecmp(format, "t") == 0)
    1619           0 :         archiveFormat = archTar;
    1620           8 :     else if (pg_strcasecmp(format, "tar") == 0)
    1621           6 :         archiveFormat = archTar;
    1622             :     else
    1623           2 :         pg_fatal("invalid output format \"%s\" specified", format);
    1624         414 :     return archiveFormat;
    1625             : }
    1626             : 
    1627             : /*
    1628             :  * Find the OIDs of all schemas matching the given list of patterns,
    1629             :  * and append them to the given OID list.
    1630             :  */
    1631             : static void
    1632         420 : expand_schema_name_patterns(Archive *fout,
    1633             :                             SimpleStringList *patterns,
    1634             :                             SimpleOidList *oids,
    1635             :                             bool strict_names)
    1636             : {
    1637             :     PQExpBuffer query;
    1638             :     PGresult   *res;
    1639             :     SimpleStringListCell *cell;
    1640             :     int         i;
    1641             : 
    1642         420 :     if (patterns->head == NULL)
    1643         378 :         return;                 /* nothing to do */
    1644             : 
    1645          42 :     query = createPQExpBuffer();
    1646             : 
    1647             :     /*
    1648             :      * The loop below runs multiple SELECTs might sometimes result in
    1649             :      * duplicate entries in the OID list, but we don't care.
    1650             :      */
    1651             : 
    1652          72 :     for (cell = patterns->head; cell; cell = cell->next)
    1653             :     {
    1654             :         PQExpBufferData dbbuf;
    1655             :         int         dotcnt;
    1656             : 
    1657          42 :         appendPQExpBufferStr(query,
    1658             :                              "SELECT oid FROM pg_catalog.pg_namespace n\n");
    1659          42 :         initPQExpBuffer(&dbbuf);
    1660          42 :         processSQLNamePattern(GetConnection(fout), query, cell->val, false,
    1661             :                               false, NULL, "n.nspname", NULL, NULL, &dbbuf,
    1662             :                               &dotcnt);
    1663          42 :         if (dotcnt > 1)
    1664           4 :             pg_fatal("improper qualified name (too many dotted names): %s",
    1665             :                      cell->val);
    1666          38 :         else if (dotcnt == 1)
    1667           6 :             prohibit_crossdb_refs(GetConnection(fout), dbbuf.data, cell->val);
    1668          32 :         termPQExpBuffer(&dbbuf);
    1669             : 
    1670          32 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    1671          32 :         if (strict_names && PQntuples(res) == 0)
    1672           2 :             pg_fatal("no matching schemas were found for pattern \"%s\"", cell->val);
    1673             : 
    1674          58 :         for (i = 0; i < PQntuples(res); i++)
    1675             :         {
    1676          28 :             simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
    1677             :         }
    1678             : 
    1679          30 :         PQclear(res);
    1680          30 :         resetPQExpBuffer(query);
    1681             :     }
    1682             : 
    1683          30 :     destroyPQExpBuffer(query);
    1684             : }
    1685             : 
    1686             : /*
    1687             :  * Find the OIDs of all extensions matching the given list of patterns,
    1688             :  * and append them to the given OID list.
    1689             :  */
    1690             : static void
    1691         376 : expand_extension_name_patterns(Archive *fout,
    1692             :                                SimpleStringList *patterns,
    1693             :                                SimpleOidList *oids,
    1694             :                                bool strict_names)
    1695             : {
    1696             :     PQExpBuffer query;
    1697             :     PGresult   *res;
    1698             :     SimpleStringListCell *cell;
    1699             :     int         i;
    1700             : 
    1701         376 :     if (patterns->head == NULL)
    1702         362 :         return;                 /* nothing to do */
    1703             : 
    1704          14 :     query = createPQExpBuffer();
    1705             : 
    1706             :     /*
    1707             :      * The loop below runs multiple SELECTs might sometimes result in
    1708             :      * duplicate entries in the OID list, but we don't care.
    1709             :      */
    1710          28 :     for (cell = patterns->head; cell; cell = cell->next)
    1711             :     {
    1712             :         int         dotcnt;
    1713             : 
    1714          14 :         appendPQExpBufferStr(query,
    1715             :                              "SELECT oid FROM pg_catalog.pg_extension e\n");
    1716          14 :         processSQLNamePattern(GetConnection(fout), query, cell->val, false,
    1717             :                               false, NULL, "e.extname", NULL, NULL, NULL,
    1718             :                               &dotcnt);
    1719          14 :         if (dotcnt > 0)
    1720           0 :             pg_fatal("improper qualified name (too many dotted names): %s",
    1721             :                      cell->val);
    1722             : 
    1723          14 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    1724          14 :         if (strict_names && PQntuples(res) == 0)
    1725           0 :             pg_fatal("no matching extensions were found for pattern \"%s\"", cell->val);
    1726             : 
    1727          26 :         for (i = 0; i < PQntuples(res); i++)
    1728             :         {
    1729          12 :             simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
    1730             :         }
    1731             : 
    1732          14 :         PQclear(res);
    1733          14 :         resetPQExpBuffer(query);
    1734             :     }
    1735             : 
    1736          14 :     destroyPQExpBuffer(query);
    1737             : }
    1738             : 
    1739             : /*
    1740             :  * Find the OIDs of all foreign servers matching the given list of patterns,
    1741             :  * and append them to the given OID list.
    1742             :  */
    1743             : static void
    1744         370 : expand_foreign_server_name_patterns(Archive *fout,
    1745             :                                     SimpleStringList *patterns,
    1746             :                                     SimpleOidList *oids)
    1747             : {
    1748             :     PQExpBuffer query;
    1749             :     PGresult   *res;
    1750             :     SimpleStringListCell *cell;
    1751             :     int         i;
    1752             : 
    1753         370 :     if (patterns->head == NULL)
    1754         364 :         return;                 /* nothing to do */
    1755             : 
    1756           6 :     query = createPQExpBuffer();
    1757             : 
    1758             :     /*
    1759             :      * The loop below runs multiple SELECTs might sometimes result in
    1760             :      * duplicate entries in the OID list, but we don't care.
    1761             :      */
    1762             : 
    1763          10 :     for (cell = patterns->head; cell; cell = cell->next)
    1764             :     {
    1765             :         int         dotcnt;
    1766             : 
    1767           6 :         appendPQExpBufferStr(query,
    1768             :                              "SELECT oid FROM pg_catalog.pg_foreign_server s\n");
    1769           6 :         processSQLNamePattern(GetConnection(fout), query, cell->val, false,
    1770             :                               false, NULL, "s.srvname", NULL, NULL, NULL,
    1771             :                               &dotcnt);
    1772           6 :         if (dotcnt > 0)
    1773           0 :             pg_fatal("improper qualified name (too many dotted names): %s",
    1774             :                      cell->val);
    1775             : 
    1776           6 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    1777           6 :         if (PQntuples(res) == 0)
    1778           2 :             pg_fatal("no matching foreign servers were found for pattern \"%s\"", cell->val);
    1779             : 
    1780           8 :         for (i = 0; i < PQntuples(res); i++)
    1781           4 :             simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
    1782             : 
    1783           4 :         PQclear(res);
    1784           4 :         resetPQExpBuffer(query);
    1785             :     }
    1786             : 
    1787           4 :     destroyPQExpBuffer(query);
    1788             : }
    1789             : 
    1790             : /*
    1791             :  * Find the OIDs of all tables matching the given list of patterns,
    1792             :  * and append them to the given OID list. See also expand_dbname_patterns()
    1793             :  * in pg_dumpall.c
    1794             :  */
    1795             : static void
    1796        2238 : expand_table_name_patterns(Archive *fout,
    1797             :                            SimpleStringList *patterns, SimpleOidList *oids,
    1798             :                            bool strict_names, bool with_child_tables)
    1799             : {
    1800             :     PQExpBuffer query;
    1801             :     PGresult   *res;
    1802             :     SimpleStringListCell *cell;
    1803             :     int         i;
    1804             : 
    1805        2238 :     if (patterns->head == NULL)
    1806        2180 :         return;                 /* nothing to do */
    1807             : 
    1808          58 :     query = createPQExpBuffer();
    1809             : 
    1810             :     /*
    1811             :      * this might sometimes result in duplicate entries in the OID list, but
    1812             :      * we don't care.
    1813             :      */
    1814             : 
    1815         118 :     for (cell = patterns->head; cell; cell = cell->next)
    1816             :     {
    1817             :         PQExpBufferData dbbuf;
    1818             :         int         dotcnt;
    1819             : 
    1820             :         /*
    1821             :          * Query must remain ABSOLUTELY devoid of unqualified names.  This
    1822             :          * would be unnecessary given a pg_table_is_visible() variant taking a
    1823             :          * search_path argument.
    1824             :          *
    1825             :          * For with_child_tables, we start with the basic query's results and
    1826             :          * recursively search the inheritance tree to add child tables.
    1827             :          */
    1828          70 :         if (with_child_tables)
    1829             :         {
    1830          12 :             appendPQExpBufferStr(query, "WITH RECURSIVE partition_tree (relid) AS (\n");
    1831             :         }
    1832             : 
    1833          70 :         appendPQExpBuffer(query,
    1834             :                           "SELECT c.oid"
    1835             :                           "\nFROM pg_catalog.pg_class c"
    1836             :                           "\n     LEFT JOIN pg_catalog.pg_namespace n"
    1837             :                           "\n     ON n.oid OPERATOR(pg_catalog.=) c.relnamespace"
    1838             :                           "\nWHERE c.relkind OPERATOR(pg_catalog.=) ANY"
    1839             :                           "\n    (array['%c', '%c', '%c', '%c', '%c', '%c'])\n",
    1840             :                           RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_VIEW,
    1841             :                           RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE,
    1842             :                           RELKIND_PARTITIONED_TABLE);
    1843          70 :         initPQExpBuffer(&dbbuf);
    1844          70 :         processSQLNamePattern(GetConnection(fout), query, cell->val, true,
    1845             :                               false, "n.nspname", "c.relname", NULL,
    1846             :                               "pg_catalog.pg_table_is_visible(c.oid)", &dbbuf,
    1847             :                               &dotcnt);
    1848          70 :         if (dotcnt > 2)
    1849           2 :             pg_fatal("improper relation name (too many dotted names): %s",
    1850             :                      cell->val);
    1851          68 :         else if (dotcnt == 2)
    1852           4 :             prohibit_crossdb_refs(GetConnection(fout), dbbuf.data, cell->val);
    1853          64 :         termPQExpBuffer(&dbbuf);
    1854             : 
    1855          64 :         if (with_child_tables)
    1856             :         {
    1857          12 :             appendPQExpBufferStr(query, "UNION"
    1858             :                                  "\nSELECT i.inhrelid"
    1859             :                                  "\nFROM partition_tree p"
    1860             :                                  "\n     JOIN pg_catalog.pg_inherits i"
    1861             :                                  "\n     ON p.relid OPERATOR(pg_catalog.=) i.inhparent"
    1862             :                                  "\n)"
    1863             :                                  "\nSELECT relid FROM partition_tree");
    1864             :         }
    1865             : 
    1866          64 :         ExecuteSqlStatement(fout, "RESET search_path");
    1867          64 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    1868          64 :         PQclear(ExecuteSqlQueryForSingleRow(fout,
    1869             :                                             ALWAYS_SECURE_SEARCH_PATH_SQL));
    1870          64 :         if (strict_names && PQntuples(res) == 0)
    1871           4 :             pg_fatal("no matching tables were found for pattern \"%s\"", cell->val);
    1872             : 
    1873         148 :         for (i = 0; i < PQntuples(res); i++)
    1874             :         {
    1875          88 :             simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
    1876             :         }
    1877             : 
    1878          60 :         PQclear(res);
    1879          60 :         resetPQExpBuffer(query);
    1880             :     }
    1881             : 
    1882          48 :     destroyPQExpBuffer(query);
    1883             : }
    1884             : 
    1885             : /*
    1886             :  * Verifies that the connected database name matches the given database name,
    1887             :  * and if not, dies with an error about the given pattern.
    1888             :  *
    1889             :  * The 'dbname' argument should be a literal name parsed from 'pattern'.
    1890             :  */
    1891             : static void
    1892          10 : prohibit_crossdb_refs(PGconn *conn, const char *dbname, const char *pattern)
    1893             : {
    1894             :     const char *db;
    1895             : 
    1896          10 :     db = PQdb(conn);
    1897          10 :     if (db == NULL)
    1898           0 :         pg_fatal("You are currently not connected to a database.");
    1899             : 
    1900          10 :     if (strcmp(db, dbname) != 0)
    1901          10 :         pg_fatal("cross-database references are not implemented: %s",
    1902             :                  pattern);
    1903           0 : }
    1904             : 
    1905             : /*
    1906             :  * checkExtensionMembership
    1907             :  *      Determine whether object is an extension member, and if so,
    1908             :  *      record an appropriate dependency and set the object's dump flag.
    1909             :  *
    1910             :  * It's important to call this for each object that could be an extension
    1911             :  * member.  Generally, we integrate this with determining the object's
    1912             :  * to-be-dumped-ness, since extension membership overrides other rules for that.
    1913             :  *
    1914             :  * Returns true if object is an extension member, else false.
    1915             :  */
    1916             : static bool
    1917     1149880 : checkExtensionMembership(DumpableObject *dobj, Archive *fout)
    1918             : {
    1919     1149880 :     ExtensionInfo *ext = findOwningExtension(dobj->catId);
    1920             : 
    1921     1149880 :     if (ext == NULL)
    1922     1148300 :         return false;
    1923             : 
    1924        1580 :     dobj->ext_member = true;
    1925             : 
    1926             :     /* Record dependency so that getDependencies needn't deal with that */
    1927        1580 :     addObjectDependency(dobj, ext->dobj.dumpId);
    1928             : 
    1929             :     /*
    1930             :      * In 9.6 and above, mark the member object to have any non-initial ACLs
    1931             :      * dumped.  (Any initial ACLs will be removed later, using data from
    1932             :      * pg_init_privs, so that we'll dump only the delta from the extension's
    1933             :      * initial setup.)
    1934             :      *
    1935             :      * Prior to 9.6, we do not include any extension member components.
    1936             :      *
    1937             :      * In binary upgrades, we still dump all components of the members
    1938             :      * individually, since the idea is to exactly reproduce the database
    1939             :      * contents rather than replace the extension contents with something
    1940             :      * different.
    1941             :      *
    1942             :      * Note: it might be interesting someday to implement storage and delta
    1943             :      * dumping of extension members' RLS policies and/or security labels.
    1944             :      * However there is a pitfall for RLS policies: trying to dump them
    1945             :      * requires getting a lock on their tables, and the calling user might not
    1946             :      * have privileges for that.  We need no lock to examine a table's ACLs,
    1947             :      * so the current feature doesn't have a problem of that sort.
    1948             :      */
    1949        1580 :     if (fout->dopt->binary_upgrade)
    1950         328 :         dobj->dump = ext->dobj.dump;
    1951             :     else
    1952             :     {
    1953        1252 :         if (fout->remoteVersion < 90600)
    1954           0 :             dobj->dump = DUMP_COMPONENT_NONE;
    1955             :         else
    1956        1252 :             dobj->dump = ext->dobj.dump_contains & (DUMP_COMPONENT_ACL);
    1957             :     }
    1958             : 
    1959        1580 :     return true;
    1960             : }
    1961             : 
    1962             : /*
    1963             :  * selectDumpableNamespace: policy-setting subroutine
    1964             :  *      Mark a namespace as to be dumped or not
    1965             :  */
    1966             : static void
    1967        2856 : selectDumpableNamespace(NamespaceInfo *nsinfo, Archive *fout)
    1968             : {
    1969             :     /*
    1970             :      * DUMP_COMPONENT_DEFINITION typically implies a CREATE SCHEMA statement
    1971             :      * and (for --clean) a DROP SCHEMA statement.  (In the absence of
    1972             :      * DUMP_COMPONENT_DEFINITION, this value is irrelevant.)
    1973             :      */
    1974        2856 :     nsinfo->create = true;
    1975             : 
    1976             :     /*
    1977             :      * If specific tables are being dumped, do not dump any complete
    1978             :      * namespaces. If specific namespaces are being dumped, dump just those
    1979             :      * namespaces. Otherwise, dump all non-system namespaces.
    1980             :      */
    1981        2856 :     if (table_include_oids.head != NULL)
    1982         100 :         nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
    1983        2756 :     else if (schema_include_oids.head != NULL)
    1984         374 :         nsinfo->dobj.dump_contains = nsinfo->dobj.dump =
    1985         374 :             simple_oid_list_member(&schema_include_oids,
    1986             :                                    nsinfo->dobj.catId.oid) ?
    1987         374 :             DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
    1988        2382 :     else if (fout->remoteVersion >= 90600 &&
    1989        2382 :              strcmp(nsinfo->dobj.name, "pg_catalog") == 0)
    1990             :     {
    1991             :         /*
    1992             :          * In 9.6 and above, we dump out any ACLs defined in pg_catalog, if
    1993             :          * they are interesting (and not the original ACLs which were set at
    1994             :          * initdb time, see pg_init_privs).
    1995             :          */
    1996         322 :         nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_ACL;
    1997             :     }
    1998        2060 :     else if (strncmp(nsinfo->dobj.name, "pg_", 3) == 0 ||
    1999        1002 :              strcmp(nsinfo->dobj.name, "information_schema") == 0)
    2000             :     {
    2001             :         /* Other system schemas don't get dumped */
    2002        1380 :         nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
    2003             :     }
    2004         680 :     else if (strcmp(nsinfo->dobj.name, "public") == 0)
    2005             :     {
    2006             :         /*
    2007             :          * The public schema is a strange beast that sits in a sort of
    2008             :          * no-mans-land between being a system object and a user object.
    2009             :          * CREATE SCHEMA would fail, so its DUMP_COMPONENT_DEFINITION is just
    2010             :          * a comment and an indication of ownership.  If the owner is the
    2011             :          * default, omit that superfluous DUMP_COMPONENT_DEFINITION.  Before
    2012             :          * v15, the default owner was BOOTSTRAP_SUPERUSERID.
    2013             :          */
    2014         314 :         nsinfo->create = false;
    2015         314 :         nsinfo->dobj.dump = DUMP_COMPONENT_ALL;
    2016         314 :         if (nsinfo->nspowner == ROLE_PG_DATABASE_OWNER)
    2017         224 :             nsinfo->dobj.dump &= ~DUMP_COMPONENT_DEFINITION;
    2018         314 :         nsinfo->dobj.dump_contains = DUMP_COMPONENT_ALL;
    2019             : 
    2020             :         /*
    2021             :          * Also, make like it has a comment even if it doesn't; this is so
    2022             :          * that we'll emit a command to drop the comment, if appropriate.
    2023             :          * (Without this, we'd not call dumpCommentExtended for it.)
    2024             :          */
    2025         314 :         nsinfo->dobj.components |= DUMP_COMPONENT_COMMENT;
    2026             :     }
    2027             :     else
    2028         366 :         nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_ALL;
    2029             : 
    2030             :     /*
    2031             :      * In any case, a namespace can be excluded by an exclusion switch
    2032             :      */
    2033        3880 :     if (nsinfo->dobj.dump_contains &&
    2034        1024 :         simple_oid_list_member(&schema_exclude_oids,
    2035             :                                nsinfo->dobj.catId.oid))
    2036           6 :         nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
    2037             : 
    2038             :     /*
    2039             :      * If the schema belongs to an extension, allow extension membership to
    2040             :      * override the dump decision for the schema itself.  However, this does
    2041             :      * not change dump_contains, so this won't change what we do with objects
    2042             :      * within the schema.  (If they belong to the extension, they'll get
    2043             :      * suppressed by it, otherwise not.)
    2044             :      */
    2045        2856 :     (void) checkExtensionMembership(&nsinfo->dobj, fout);
    2046        2856 : }
    2047             : 
    2048             : /*
    2049             :  * selectDumpableTable: policy-setting subroutine
    2050             :  *      Mark a table as to be dumped or not
    2051             :  */
    2052             : static void
    2053       96626 : selectDumpableTable(TableInfo *tbinfo, Archive *fout)
    2054             : {
    2055       96626 :     if (checkExtensionMembership(&tbinfo->dobj, fout))
    2056         450 :         return;                 /* extension membership overrides all else */
    2057             : 
    2058             :     /*
    2059             :      * If specific tables are being dumped, dump just those tables; else, dump
    2060             :      * according to the parent namespace's dump flag.
    2061             :      */
    2062       96176 :     if (table_include_oids.head != NULL)
    2063       10356 :         tbinfo->dobj.dump = simple_oid_list_member(&table_include_oids,
    2064             :                                                    tbinfo->dobj.catId.oid) ?
    2065        5178 :             DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
    2066             :     else
    2067       90998 :         tbinfo->dobj.dump = tbinfo->dobj.namespace->dobj.dump_contains;
    2068             : 
    2069             :     /*
    2070             :      * In any case, a table can be excluded by an exclusion switch
    2071             :      */
    2072      157314 :     if (tbinfo->dobj.dump &&
    2073       61138 :         simple_oid_list_member(&table_exclude_oids,
    2074             :                                tbinfo->dobj.catId.oid))
    2075          24 :         tbinfo->dobj.dump = DUMP_COMPONENT_NONE;
    2076             : }
    2077             : 
    2078             : /*
    2079             :  * selectDumpableType: policy-setting subroutine
    2080             :  *      Mark a type as to be dumped or not
    2081             :  *
    2082             :  * If it's a table's rowtype or an autogenerated array type, we also apply a
    2083             :  * special type code to facilitate sorting into the desired order.  (We don't
    2084             :  * want to consider those to be ordinary types because that would bring tables
    2085             :  * up into the datatype part of the dump order.)  We still set the object's
    2086             :  * dump flag; that's not going to cause the dummy type to be dumped, but we
    2087             :  * need it so that casts involving such types will be dumped correctly -- see
    2088             :  * dumpCast.  This means the flag should be set the same as for the underlying
    2089             :  * object (the table or base type).
    2090             :  */
    2091             : static void
    2092      264998 : selectDumpableType(TypeInfo *tyinfo, Archive *fout)
    2093             : {
    2094             :     /* skip complex types, except for standalone composite types */
    2095      264998 :     if (OidIsValid(tyinfo->typrelid) &&
    2096       95160 :         tyinfo->typrelkind != RELKIND_COMPOSITE_TYPE)
    2097             :     {
    2098       94790 :         TableInfo  *tytable = findTableByOid(tyinfo->typrelid);
    2099             : 
    2100       94790 :         tyinfo->dobj.objType = DO_DUMMY_TYPE;
    2101       94790 :         if (tytable != NULL)
    2102       94790 :             tyinfo->dobj.dump = tytable->dobj.dump;
    2103             :         else
    2104           0 :             tyinfo->dobj.dump = DUMP_COMPONENT_NONE;
    2105       94790 :         return;
    2106             :     }
    2107             : 
    2108             :     /* skip auto-generated array and multirange types */
    2109      170208 :     if (tyinfo->isArray || tyinfo->isMultirange)
    2110             :     {
    2111      129626 :         tyinfo->dobj.objType = DO_DUMMY_TYPE;
    2112             : 
    2113             :         /*
    2114             :          * Fall through to set the dump flag; we assume that the subsequent
    2115             :          * rules will do the same thing as they would for the array's base
    2116             :          * type or multirange's range type.  (We cannot reliably look up the
    2117             :          * base type here, since getTypes may not have processed it yet.)
    2118             :          */
    2119             :     }
    2120             : 
    2121      170208 :     if (checkExtensionMembership(&tyinfo->dobj, fout))
    2122         300 :         return;                 /* extension membership overrides all else */
    2123             : 
    2124             :     /* Dump based on if the contents of the namespace are being dumped */
    2125      169908 :     tyinfo->dobj.dump = tyinfo->dobj.namespace->dobj.dump_contains;
    2126             : }
    2127             : 
    2128             : /*
    2129             :  * selectDumpableDefaultACL: policy-setting subroutine
    2130             :  *      Mark a default ACL as to be dumped or not
    2131             :  *
    2132             :  * For per-schema default ACLs, dump if the schema is to be dumped.
    2133             :  * Otherwise dump if we are dumping "everything".  Note that dumpSchema
    2134             :  * and aclsSkip are checked separately.
    2135             :  */
    2136             : static void
    2137         412 : selectDumpableDefaultACL(DefaultACLInfo *dinfo, DumpOptions *dopt)
    2138             : {
    2139             :     /* Default ACLs can't be extension members */
    2140             : 
    2141         412 :     if (dinfo->dobj.namespace)
    2142             :         /* default ACLs are considered part of the namespace */
    2143         192 :         dinfo->dobj.dump = dinfo->dobj.namespace->dobj.dump_contains;
    2144             :     else
    2145         220 :         dinfo->dobj.dump = dopt->include_everything ?
    2146         220 :             DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
    2147         412 : }
    2148             : 
    2149             : /*
    2150             :  * selectDumpableCast: policy-setting subroutine
    2151             :  *      Mark a cast as to be dumped or not
    2152             :  *
    2153             :  * Casts do not belong to any particular namespace (since they haven't got
    2154             :  * names), nor do they have identifiable owners.  To distinguish user-defined
    2155             :  * casts from built-in ones, we must resort to checking whether the cast's
    2156             :  * OID is in the range reserved for initdb.
    2157             :  */
    2158             : static void
    2159       86084 : selectDumpableCast(CastInfo *cast, Archive *fout)
    2160             : {
    2161       86084 :     if (checkExtensionMembership(&cast->dobj, fout))
    2162           0 :         return;                 /* extension membership overrides all else */
    2163             : 
    2164             :     /*
    2165             :      * This would be DUMP_COMPONENT_ACL for from-initdb casts, but they do not
    2166             :      * support ACLs currently.
    2167             :      */
    2168       86084 :     if (cast->dobj.catId.oid <= (Oid) g_last_builtin_oid)
    2169       85904 :         cast->dobj.dump = DUMP_COMPONENT_NONE;
    2170             :     else
    2171         180 :         cast->dobj.dump = fout->dopt->include_everything ?
    2172         180 :             DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
    2173             : }
    2174             : 
    2175             : /*
    2176             :  * selectDumpableProcLang: policy-setting subroutine
    2177             :  *      Mark a procedural language as to be dumped or not
    2178             :  *
    2179             :  * Procedural languages do not belong to any particular namespace.  To
    2180             :  * identify built-in languages, we must resort to checking whether the
    2181             :  * language's OID is in the range reserved for initdb.
    2182             :  */
    2183             : static void
    2184         460 : selectDumpableProcLang(ProcLangInfo *plang, Archive *fout)
    2185             : {
    2186         460 :     if (checkExtensionMembership(&plang->dobj, fout))
    2187         364 :         return;                 /* extension membership overrides all else */
    2188             : 
    2189             :     /*
    2190             :      * Only include procedural languages when we are dumping everything.
    2191             :      *
    2192             :      * For from-initdb procedural languages, only include ACLs, as we do for
    2193             :      * the pg_catalog namespace.  We need this because procedural languages do
    2194             :      * not live in any namespace.
    2195             :      */
    2196          96 :     if (!fout->dopt->include_everything)
    2197          16 :         plang->dobj.dump = DUMP_COMPONENT_NONE;
    2198             :     else
    2199             :     {
    2200          80 :         if (plang->dobj.catId.oid <= (Oid) g_last_builtin_oid)
    2201           0 :             plang->dobj.dump = fout->remoteVersion < 90600 ?
    2202           0 :                 DUMP_COMPONENT_NONE : DUMP_COMPONENT_ACL;
    2203             :         else
    2204          80 :             plang->dobj.dump = DUMP_COMPONENT_ALL;
    2205             :     }
    2206             : }
    2207             : 
    2208             : /*
    2209             :  * selectDumpableAccessMethod: policy-setting subroutine
    2210             :  *      Mark an access method as to be dumped or not
    2211             :  *
    2212             :  * Access methods do not belong to any particular namespace.  To identify
    2213             :  * built-in access methods, we must resort to checking whether the
    2214             :  * method's OID is in the range reserved for initdb.
    2215             :  */
    2216             : static void
    2217        2804 : selectDumpableAccessMethod(AccessMethodInfo *method, Archive *fout)
    2218             : {
    2219             :     /* see getAccessMethods() comment about v9.6. */
    2220        2804 :     if (fout->remoteVersion < 90600)
    2221             :     {
    2222           0 :         method->dobj.dump = DUMP_COMPONENT_NONE;
    2223           0 :         return;
    2224             :     }
    2225             : 
    2226        2804 :     if (checkExtensionMembership(&method->dobj, fout))
    2227          50 :         return;                 /* extension membership overrides all else */
    2228             : 
    2229             :     /*
    2230             :      * This would be DUMP_COMPONENT_ACL for from-initdb access methods, but
    2231             :      * they do not support ACLs currently.
    2232             :      */
    2233        2754 :     if (method->dobj.catId.oid <= (Oid) g_last_builtin_oid)
    2234        2548 :         method->dobj.dump = DUMP_COMPONENT_NONE;
    2235             :     else
    2236         206 :         method->dobj.dump = fout->dopt->include_everything ?
    2237         206 :             DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
    2238             : }
    2239             : 
    2240             : /*
    2241             :  * selectDumpableExtension: policy-setting subroutine
    2242             :  *      Mark an extension as to be dumped or not
    2243             :  *
    2244             :  * Built-in extensions should be skipped except for checking ACLs, since we
    2245             :  * assume those will already be installed in the target database.  We identify
    2246             :  * such extensions by their having OIDs in the range reserved for initdb.
    2247             :  * We dump all user-added extensions by default.  No extensions are dumped
    2248             :  * if include_everything is false (i.e., a --schema or --table switch was
    2249             :  * given), except if --extension specifies a list of extensions to dump.
    2250             :  */
    2251             : static void
    2252         416 : selectDumpableExtension(ExtensionInfo *extinfo, DumpOptions *dopt)
    2253             : {
    2254             :     /*
    2255             :      * Use DUMP_COMPONENT_ACL for built-in extensions, to allow users to
    2256             :      * change permissions on their member objects, if they wish to, and have
    2257             :      * those changes preserved.
    2258             :      */
    2259         416 :     if (extinfo->dobj.catId.oid <= (Oid) g_last_builtin_oid)
    2260         366 :         extinfo->dobj.dump = extinfo->dobj.dump_contains = DUMP_COMPONENT_ACL;
    2261             :     else
    2262             :     {
    2263             :         /* check if there is a list of extensions to dump */
    2264          50 :         if (extension_include_oids.head != NULL)
    2265           8 :             extinfo->dobj.dump = extinfo->dobj.dump_contains =
    2266           8 :                 simple_oid_list_member(&extension_include_oids,
    2267             :                                        extinfo->dobj.catId.oid) ?
    2268           8 :                 DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
    2269             :         else
    2270          42 :             extinfo->dobj.dump = extinfo->dobj.dump_contains =
    2271          42 :                 dopt->include_everything ?
    2272          42 :                 DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
    2273             : 
    2274             :         /* check that the extension is not explicitly excluded */
    2275          92 :         if (extinfo->dobj.dump &&
    2276          42 :             simple_oid_list_member(&extension_exclude_oids,
    2277             :                                    extinfo->dobj.catId.oid))
    2278           4 :             extinfo->dobj.dump = extinfo->dobj.dump_contains = DUMP_COMPONENT_NONE;
    2279             :     }
    2280         416 : }
    2281             : 
    2282             : /*
    2283             :  * selectDumpablePublicationObject: policy-setting subroutine
    2284             :  *      Mark a publication object as to be dumped or not
    2285             :  *
    2286             :  * A publication can have schemas and tables which have schemas, but those are
    2287             :  * ignored in decision making, because publications are only dumped when we are
    2288             :  * dumping everything.
    2289             :  */
    2290             : static void
    2291        1004 : selectDumpablePublicationObject(DumpableObject *dobj, Archive *fout)
    2292             : {
    2293        1004 :     if (checkExtensionMembership(dobj, fout))
    2294           0 :         return;                 /* extension membership overrides all else */
    2295             : 
    2296        1004 :     dobj->dump = fout->dopt->include_everything ?
    2297        1004 :         DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
    2298             : }
    2299             : 
    2300             : /*
    2301             :  * selectDumpableStatisticsObject: policy-setting subroutine
    2302             :  *      Mark an extended statistics object as to be dumped or not
    2303             :  *
    2304             :  * We dump an extended statistics object if the schema it's in and the table
    2305             :  * it's for are being dumped.  (This'll need more thought if statistics
    2306             :  * objects ever support cross-table stats.)
    2307             :  */
    2308             : static void
    2309         344 : selectDumpableStatisticsObject(StatsExtInfo *sobj, Archive *fout)
    2310             : {
    2311         344 :     if (checkExtensionMembership(&sobj->dobj, fout))
    2312           0 :         return;                 /* extension membership overrides all else */
    2313             : 
    2314         344 :     sobj->dobj.dump = sobj->dobj.namespace->dobj.dump_contains;
    2315         344 :     if (sobj->stattable == NULL ||
    2316         344 :         !(sobj->stattable->dobj.dump & DUMP_COMPONENT_DEFINITION))
    2317          56 :         sobj->dobj.dump = DUMP_COMPONENT_NONE;
    2318             : }
    2319             : 
    2320             : /*
    2321             :  * selectDumpableObject: policy-setting subroutine
    2322             :  *      Mark a generic dumpable object as to be dumped or not
    2323             :  *
    2324             :  * Use this only for object types without a special-case routine above.
    2325             :  */
    2326             : static void
    2327      789494 : selectDumpableObject(DumpableObject *dobj, Archive *fout)
    2328             : {
    2329      789494 :     if (checkExtensionMembership(dobj, fout))
    2330         366 :         return;                 /* extension membership overrides all else */
    2331             : 
    2332             :     /*
    2333             :      * Default policy is to dump if parent namespace is dumpable, or for
    2334             :      * non-namespace-associated items, dump if we're dumping "everything".
    2335             :      */
    2336      789128 :     if (dobj->namespace)
    2337      787768 :         dobj->dump = dobj->namespace->dobj.dump_contains;
    2338             :     else
    2339        1360 :         dobj->dump = fout->dopt->include_everything ?
    2340        1360 :             DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
    2341             : }
    2342             : 
    2343             : /*
    2344             :  *  Dump a table's contents for loading using the COPY command
    2345             :  *  - this routine is called by the Archiver when it wants the table
    2346             :  *    to be dumped.
    2347             :  */
    2348             : static int
    2349        8426 : dumpTableData_copy(Archive *fout, const void *dcontext)
    2350             : {
    2351        8426 :     TableDataInfo *tdinfo = (TableDataInfo *) dcontext;
    2352        8426 :     TableInfo  *tbinfo = tdinfo->tdtable;
    2353        8426 :     const char *classname = tbinfo->dobj.name;
    2354        8426 :     PQExpBuffer q = createPQExpBuffer();
    2355             : 
    2356             :     /*
    2357             :      * Note: can't use getThreadLocalPQExpBuffer() here, we're calling fmtId
    2358             :      * which uses it already.
    2359             :      */
    2360        8426 :     PQExpBuffer clistBuf = createPQExpBuffer();
    2361        8426 :     PGconn     *conn = GetConnection(fout);
    2362             :     PGresult   *res;
    2363             :     int         ret;
    2364             :     char       *copybuf;
    2365             :     const char *column_list;
    2366             : 
    2367        8426 :     pg_log_info("dumping contents of table \"%s.%s\"",
    2368             :                 tbinfo->dobj.namespace->dobj.name, classname);
    2369             : 
    2370             :     /*
    2371             :      * Specify the column list explicitly so that we have no possibility of
    2372             :      * retrieving data in the wrong column order.  (The default column
    2373             :      * ordering of COPY will not be what we want in certain corner cases
    2374             :      * involving ADD COLUMN and inheritance.)
    2375             :      */
    2376        8426 :     column_list = fmtCopyColumnList(tbinfo, clistBuf);
    2377             : 
    2378             :     /*
    2379             :      * Use COPY (SELECT ...) TO when dumping a foreign table's data, and when
    2380             :      * a filter condition was specified.  For other cases a simple COPY
    2381             :      * suffices.
    2382             :      */
    2383        8426 :     if (tdinfo->filtercond || tbinfo->relkind == RELKIND_FOREIGN_TABLE)
    2384             :     {
    2385             :         /* Temporary allows to access to foreign tables to dump data */
    2386          74 :         if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
    2387           2 :             set_restrict_relation_kind(fout, "view");
    2388             : 
    2389          74 :         appendPQExpBufferStr(q, "COPY (SELECT ");
    2390             :         /* klugery to get rid of parens in column list */
    2391          74 :         if (strlen(column_list) > 2)
    2392             :         {
    2393          74 :             appendPQExpBufferStr(q, column_list + 1);
    2394          74 :             q->data[q->len - 1] = ' ';
    2395             :         }
    2396             :         else
    2397           0 :             appendPQExpBufferStr(q, "* ");
    2398             : 
    2399         148 :         appendPQExpBuffer(q, "FROM %s %s) TO stdout;",
    2400          74 :                           fmtQualifiedDumpable(tbinfo),
    2401          74 :                           tdinfo->filtercond ? tdinfo->filtercond : "");
    2402             :     }
    2403             :     else
    2404             :     {
    2405        8352 :         appendPQExpBuffer(q, "COPY %s %s TO stdout;",
    2406        8352 :                           fmtQualifiedDumpable(tbinfo),
    2407             :                           column_list);
    2408             :     }
    2409        8426 :     res = ExecuteSqlQuery(fout, q->data, PGRES_COPY_OUT);
    2410        8424 :     PQclear(res);
    2411        8424 :     destroyPQExpBuffer(clistBuf);
    2412             : 
    2413             :     for (;;)
    2414             :     {
    2415     3620934 :         ret = PQgetCopyData(conn, &copybuf, 0);
    2416             : 
    2417     3620934 :         if (ret < 0)
    2418        8424 :             break;              /* done or error */
    2419             : 
    2420     3612510 :         if (copybuf)
    2421             :         {
    2422     3612510 :             WriteData(fout, copybuf, ret);
    2423     3612510 :             PQfreemem(copybuf);
    2424             :         }
    2425             : 
    2426             :         /* ----------
    2427             :          * THROTTLE:
    2428             :          *
    2429             :          * There was considerable discussion in late July, 2000 regarding
    2430             :          * slowing down pg_dump when backing up large tables. Users with both
    2431             :          * slow & fast (multi-processor) machines experienced performance
    2432             :          * degradation when doing a backup.
    2433             :          *
    2434             :          * Initial attempts based on sleeping for a number of ms for each ms
    2435             :          * of work were deemed too complex, then a simple 'sleep in each loop'
    2436             :          * implementation was suggested. The latter failed because the loop
    2437             :          * was too tight. Finally, the following was implemented:
    2438             :          *
    2439             :          * If throttle is non-zero, then
    2440             :          *      See how long since the last sleep.
    2441             :          *      Work out how long to sleep (based on ratio).
    2442             :          *      If sleep is more than 100ms, then
    2443             :          *          sleep
    2444             :          *          reset timer
    2445             :          *      EndIf
    2446             :          * EndIf
    2447             :          *
    2448             :          * where the throttle value was the number of ms to sleep per ms of
    2449             :          * work. The calculation was done in each loop.
    2450             :          *
    2451             :          * Most of the hard work is done in the backend, and this solution
    2452             :          * still did not work particularly well: on slow machines, the ratio
    2453             :          * was 50:1, and on medium paced machines, 1:1, and on fast
    2454             :          * multi-processor machines, it had little or no effect, for reasons
    2455             :          * that were unclear.
    2456             :          *
    2457             :          * Further discussion ensued, and the proposal was dropped.
    2458             :          *
    2459             :          * For those people who want this feature, it can be implemented using
    2460             :          * gettimeofday in each loop, calculating the time since last sleep,
    2461             :          * multiplying that by the sleep ratio, then if the result is more
    2462             :          * than a preset 'minimum sleep time' (say 100ms), call the 'select'
    2463             :          * function to sleep for a subsecond period ie.
    2464             :          *
    2465             :          * select(0, NULL, NULL, NULL, &tvi);
    2466             :          *
    2467             :          * This will return after the interval specified in the structure tvi.
    2468             :          * Finally, call gettimeofday again to save the 'last sleep time'.
    2469             :          * ----------
    2470             :          */
    2471             :     }
    2472        8424 :     archprintf(fout, "\\.\n\n\n");
    2473             : 
    2474        8424 :     if (ret == -2)
    2475             :     {
    2476             :         /* copy data transfer failed */
    2477           0 :         pg_log_error("Dumping the contents of table \"%s\" failed: PQgetCopyData() failed.", classname);
    2478           0 :         pg_log_error_detail("Error message from server: %s", PQerrorMessage(conn));
    2479           0 :         pg_log_error_detail("Command was: %s", q->data);
    2480           0 :         exit_nicely(1);
    2481             :     }
    2482             : 
    2483             :     /* Check command status and return to normal libpq state */
    2484        8424 :     res = PQgetResult(conn);
    2485        8424 :     if (PQresultStatus(res) != PGRES_COMMAND_OK)
    2486             :     {
    2487           0 :         pg_log_error("Dumping the contents of table \"%s\" failed: PQgetResult() failed.", classname);
    2488           0 :         pg_log_error_detail("Error message from server: %s", PQerrorMessage(conn));
    2489           0 :         pg_log_error_detail("Command was: %s", q->data);
    2490           0 :         exit_nicely(1);
    2491             :     }
    2492        8424 :     PQclear(res);
    2493             : 
    2494             :     /* Do this to ensure we've pumped libpq back to idle state */
    2495        8424 :     if (PQgetResult(conn) != NULL)
    2496           0 :         pg_log_warning("unexpected extra results during COPY of table \"%s\"",
    2497             :                        classname);
    2498             : 
    2499        8424 :     destroyPQExpBuffer(q);
    2500             : 
    2501             :     /* Revert back the setting */
    2502        8424 :     if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
    2503           0 :         set_restrict_relation_kind(fout, "view, foreign-table");
    2504             : 
    2505        8424 :     return 1;
    2506             : }
    2507             : 
    2508             : /*
    2509             :  * Dump table data using INSERT commands.
    2510             :  *
    2511             :  * Caution: when we restore from an archive file direct to database, the
    2512             :  * INSERT commands emitted by this function have to be parsed by
    2513             :  * pg_backup_db.c's ExecuteSimpleCommands(), which will not handle comments,
    2514             :  * E'' strings, or dollar-quoted strings.  So don't emit anything like that.
    2515             :  */
    2516             : static int
    2517         170 : dumpTableData_insert(Archive *fout, const void *dcontext)
    2518             : {
    2519         170 :     TableDataInfo *tdinfo = (TableDataInfo *) dcontext;
    2520         170 :     TableInfo  *tbinfo = tdinfo->tdtable;
    2521         170 :     DumpOptions *dopt = fout->dopt;
    2522         170 :     PQExpBuffer q = createPQExpBuffer();
    2523         170 :     PQExpBuffer insertStmt = NULL;
    2524             :     char       *attgenerated;
    2525             :     PGresult   *res;
    2526             :     int         nfields,
    2527             :                 i;
    2528         170 :     int         rows_per_statement = dopt->dump_inserts;
    2529         170 :     int         rows_this_statement = 0;
    2530             : 
    2531             :     /* Temporary allows to access to foreign tables to dump data */
    2532         170 :     if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
    2533           0 :         set_restrict_relation_kind(fout, "view");
    2534             : 
    2535             :     /*
    2536             :      * If we're going to emit INSERTs with column names, the most efficient
    2537             :      * way to deal with generated columns is to exclude them entirely.  For
    2538             :      * INSERTs without column names, we have to emit DEFAULT rather than the
    2539             :      * actual column value --- but we can save a few cycles by fetching nulls
    2540             :      * rather than the uninteresting-to-us value.
    2541             :      */
    2542         170 :     attgenerated = (char *) pg_malloc(tbinfo->numatts * sizeof(char));
    2543         170 :     appendPQExpBufferStr(q, "DECLARE _pg_dump_cursor CURSOR FOR SELECT ");
    2544         170 :     nfields = 0;
    2545         522 :     for (i = 0; i < tbinfo->numatts; i++)
    2546             :     {
    2547         352 :         if (tbinfo->attisdropped[i])
    2548           4 :             continue;
    2549         348 :         if (tbinfo->attgenerated[i] && dopt->column_inserts)
    2550          16 :             continue;
    2551         332 :         if (nfields > 0)
    2552         176 :             appendPQExpBufferStr(q, ", ");
    2553         332 :         if (tbinfo->attgenerated[i])
    2554          16 :             appendPQExpBufferStr(q, "NULL");
    2555             :         else
    2556         316 :             appendPQExpBufferStr(q, fmtId(tbinfo->attnames[i]));
    2557         332 :         attgenerated[nfields] = tbinfo->attgenerated[i];
    2558         332 :         nfields++;
    2559             :     }
    2560             :     /* Servers before 9.4 will complain about zero-column SELECT */
    2561         170 :     if (nfields == 0)
    2562          14 :         appendPQExpBufferStr(q, "NULL");
    2563         170 :     appendPQExpBuffer(q, " FROM ONLY %s",
    2564         170 :                       fmtQualifiedDumpable(tbinfo));
    2565         170 :     if (tdinfo->filtercond)
    2566           0 :         appendPQExpBuffer(q, " %s", tdinfo->filtercond);
    2567             : 
    2568         170 :     ExecuteSqlStatement(fout, q->data);
    2569             : 
    2570             :     while (1)
    2571             :     {
    2572         274 :         res = ExecuteSqlQuery(fout, "FETCH 100 FROM _pg_dump_cursor",
    2573             :                               PGRES_TUPLES_OK);
    2574             : 
    2575             :         /* cross-check field count, allowing for dummy NULL if any */
    2576         274 :         if (nfields != PQnfields(res) &&
    2577          20 :             !(nfields == 0 && PQnfields(res) == 1))
    2578           0 :             pg_fatal("wrong number of fields retrieved from table \"%s\"",
    2579             :                      tbinfo->dobj.name);
    2580             : 
    2581             :         /*
    2582             :          * First time through, we build as much of the INSERT statement as
    2583             :          * possible in "insertStmt", which we can then just print for each
    2584             :          * statement. If the table happens to have zero dumpable columns then
    2585             :          * this will be a complete statement, otherwise it will end in
    2586             :          * "VALUES" and be ready to have the row's column values printed.
    2587             :          */
    2588         274 :         if (insertStmt == NULL)
    2589             :         {
    2590             :             TableInfo  *targettab;
    2591             : 
    2592         170 :             insertStmt = createPQExpBuffer();
    2593             : 
    2594             :             /*
    2595             :              * When load-via-partition-root is set or forced, get the root
    2596             :              * table name for the partition table, so that we can reload data
    2597             :              * through the root table.
    2598             :              */
    2599         170 :             if (tbinfo->ispartition &&
    2600          96 :                 (dopt->load_via_partition_root ||
    2601          48 :                  forcePartitionRootLoad(tbinfo)))
    2602          14 :                 targettab = getRootTableInfo(tbinfo);
    2603             :             else
    2604         156 :                 targettab = tbinfo;
    2605             : 
    2606         170 :             appendPQExpBuffer(insertStmt, "INSERT INTO %s ",
    2607         170 :                               fmtQualifiedDumpable(targettab));
    2608             : 
    2609             :             /* corner case for zero-column table */
    2610         170 :             if (nfields == 0)
    2611             :             {
    2612          14 :                 appendPQExpBufferStr(insertStmt, "DEFAULT VALUES;\n");
    2613             :             }
    2614             :             else
    2615             :             {
    2616             :                 /* append the list of column names if required */
    2617         156 :                 if (dopt->column_inserts)
    2618             :                 {
    2619          70 :                     appendPQExpBufferChar(insertStmt, '(');
    2620         210 :                     for (int field = 0; field < nfields; field++)
    2621             :                     {
    2622         140 :                         if (field > 0)
    2623          70 :                             appendPQExpBufferStr(insertStmt, ", ");
    2624         140 :                         appendPQExpBufferStr(insertStmt,
    2625         140 :                                              fmtId(PQfname(res, field)));
    2626             :                     }
    2627          70 :                     appendPQExpBufferStr(insertStmt, ") ");
    2628             :                 }
    2629             : 
    2630         156 :                 if (tbinfo->needs_override)
    2631           4 :                     appendPQExpBufferStr(insertStmt, "OVERRIDING SYSTEM VALUE ");
    2632             : 
    2633         156 :                 appendPQExpBufferStr(insertStmt, "VALUES");
    2634             :             }
    2635             :         }
    2636             : 
    2637        6816 :         for (int tuple = 0; tuple < PQntuples(res); tuple++)
    2638             :         {
    2639             :             /* Write the INSERT if not in the middle of a multi-row INSERT. */
    2640        6542 :             if (rows_this_statement == 0)
    2641        6530 :                 archputs(insertStmt->data, fout);
    2642             : 
    2643             :             /*
    2644             :              * If it is zero-column table then we've already written the
    2645             :              * complete statement, which will mean we've disobeyed
    2646             :              * --rows-per-insert when it's set greater than 1.  We do support
    2647             :              * a way to make this multi-row with: SELECT UNION ALL SELECT
    2648             :              * UNION ALL ... but that's non-standard so we should avoid it
    2649             :              * given that using INSERTs is mostly only ever needed for
    2650             :              * cross-database exports.
    2651             :              */
    2652        6542 :             if (nfields == 0)
    2653          12 :                 continue;
    2654             : 
    2655             :             /* Emit a row heading */
    2656        6530 :             if (rows_per_statement == 1)
    2657        6512 :                 archputs(" (", fout);
    2658          18 :             else if (rows_this_statement > 0)
    2659          12 :                 archputs(",\n\t(", fout);
    2660             :             else
    2661           6 :                 archputs("\n\t(", fout);
    2662             : 
    2663       19698 :             for (int field = 0; field < nfields; field++)
    2664             :             {
    2665       13168 :                 if (field > 0)
    2666        6638 :                     archputs(", ", fout);
    2667       13168 :                 if (attgenerated[field])
    2668             :                 {
    2669           4 :                     archputs("DEFAULT", fout);
    2670           4 :                     continue;
    2671             :                 }
    2672       13164 :                 if (PQgetisnull(res, tuple, field))
    2673             :                 {
    2674         166 :                     archputs("NULL", fout);
    2675         166 :                     continue;
    2676             :                 }
    2677             : 
    2678             :                 /* XXX This code is partially duplicated in ruleutils.c */
    2679       12998 :                 switch (PQftype(res, field))
    2680             :                 {
    2681        8938 :                     case INT2OID:
    2682             :                     case INT4OID:
    2683             :                     case INT8OID:
    2684             :                     case OIDOID:
    2685             :                     case FLOAT4OID:
    2686             :                     case FLOAT8OID:
    2687             :                     case NUMERICOID:
    2688             :                         {
    2689             :                             /*
    2690             :                              * These types are printed without quotes unless
    2691             :                              * they contain values that aren't accepted by the
    2692             :                              * scanner unquoted (e.g., 'NaN').  Note that
    2693             :                              * strtod() and friends might accept NaN, so we
    2694             :                              * can't use that to test.
    2695             :                              *
    2696             :                              * In reality we only need to defend against
    2697             :                              * infinity and NaN, so we need not get too crazy
    2698             :                              * about pattern matching here.
    2699             :                              */
    2700        8938 :                             const char *s = PQgetvalue(res, tuple, field);
    2701             : 
    2702        8938 :                             if (strspn(s, "0123456789 +-eE.") == strlen(s))
    2703        8934 :                                 archputs(s, fout);
    2704             :                             else
    2705           4 :                                 archprintf(fout, "'%s'", s);
    2706             :                         }
    2707        8938 :                         break;
    2708             : 
    2709           4 :                     case BITOID:
    2710             :                     case VARBITOID:
    2711           4 :                         archprintf(fout, "B'%s'",
    2712             :                                    PQgetvalue(res, tuple, field));
    2713           4 :                         break;
    2714             : 
    2715           8 :                     case BOOLOID:
    2716           8 :                         if (strcmp(PQgetvalue(res, tuple, field), "t") == 0)
    2717           4 :                             archputs("true", fout);
    2718             :                         else
    2719           4 :                             archputs("false", fout);
    2720           8 :                         break;
    2721             : 
    2722        4048 :                     default:
    2723             :                         /* All other types are printed as string literals. */
    2724        4048 :                         resetPQExpBuffer(q);
    2725        4048 :                         appendStringLiteralAH(q,
    2726             :                                               PQgetvalue(res, tuple, field),
    2727             :                                               fout);
    2728        4048 :                         archputs(q->data, fout);
    2729        4048 :                         break;
    2730             :                 }
    2731             :             }
    2732             : 
    2733             :             /* Terminate the row ... */
    2734        6530 :             archputs(")", fout);
    2735             : 
    2736             :             /* ... and the statement, if the target no. of rows is reached */
    2737        6530 :             if (++rows_this_statement >= rows_per_statement)
    2738             :             {
    2739        6516 :                 if (dopt->do_nothing)
    2740           0 :                     archputs(" ON CONFLICT DO NOTHING;\n", fout);
    2741             :                 else
    2742        6516 :                     archputs(";\n", fout);
    2743             :                 /* Reset the row counter */
    2744        6516 :                 rows_this_statement = 0;
    2745             :             }
    2746             :         }
    2747             : 
    2748         274 :         if (PQntuples(res) <= 0)
    2749             :         {
    2750         170 :             PQclear(res);
    2751         170 :             break;
    2752             :         }
    2753         104 :         PQclear(res);
    2754             :     }
    2755             : 
    2756             :     /* Terminate any statements that didn't make the row count. */
    2757         170 :     if (rows_this_statement > 0)
    2758             :     {
    2759           2 :         if (dopt->do_nothing)
    2760           0 :             archputs(" ON CONFLICT DO NOTHING;\n", fout);
    2761             :         else
    2762           2 :             archputs(";\n", fout);
    2763             :     }
    2764             : 
    2765         170 :     archputs("\n\n", fout);
    2766             : 
    2767         170 :     ExecuteSqlStatement(fout, "CLOSE _pg_dump_cursor");
    2768             : 
    2769         170 :     destroyPQExpBuffer(q);
    2770         170 :     if (insertStmt != NULL)
    2771         170 :         destroyPQExpBuffer(insertStmt);
    2772         170 :     free(attgenerated);
    2773             : 
    2774             :     /* Revert back the setting */
    2775         170 :     if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
    2776           0 :         set_restrict_relation_kind(fout, "view, foreign-table");
    2777             : 
    2778         170 :     return 1;
    2779             : }
    2780             : 
    2781             : /*
    2782             :  * getRootTableInfo:
    2783             :  *     get the root TableInfo for the given partition table.
    2784             :  */
    2785             : static TableInfo *
    2786         170 : getRootTableInfo(const TableInfo *tbinfo)
    2787             : {
    2788             :     TableInfo  *parentTbinfo;
    2789             : 
    2790             :     Assert(tbinfo->ispartition);
    2791             :     Assert(tbinfo->numParents == 1);
    2792             : 
    2793         170 :     parentTbinfo = tbinfo->parents[0];
    2794         170 :     while (parentTbinfo->ispartition)
    2795             :     {
    2796             :         Assert(parentTbinfo->numParents == 1);
    2797           0 :         parentTbinfo = parentTbinfo->parents[0];
    2798             :     }
    2799             : 
    2800         170 :     return parentTbinfo;
    2801             : }
    2802             : 
    2803             : /*
    2804             :  * forcePartitionRootLoad
    2805             :  *     Check if we must force load_via_partition_root for this partition.
    2806             :  *
    2807             :  * This is required if any level of ancestral partitioned table has an
    2808             :  * unsafe partitioning scheme.
    2809             :  */
    2810             : static bool
    2811        2150 : forcePartitionRootLoad(const TableInfo *tbinfo)
    2812             : {
    2813             :     TableInfo  *parentTbinfo;
    2814             : 
    2815             :     Assert(tbinfo->ispartition);
    2816             :     Assert(tbinfo->numParents == 1);
    2817             : 
    2818        2150 :     parentTbinfo = tbinfo->parents[0];
    2819        2150 :     if (parentTbinfo->unsafe_partitions)
    2820         170 :         return true;
    2821        2412 :     while (parentTbinfo->ispartition)
    2822             :     {
    2823             :         Assert(parentTbinfo->numParents == 1);
    2824         432 :         parentTbinfo = parentTbinfo->parents[0];
    2825         432 :         if (parentTbinfo->unsafe_partitions)
    2826           0 :             return true;
    2827             :     }
    2828             : 
    2829        1980 :     return false;
    2830             : }
    2831             : 
    2832             : /*
    2833             :  * dumpTableData -
    2834             :  *    dump the contents of a single table
    2835             :  *
    2836             :  * Actually, this just makes an ArchiveEntry for the table contents.
    2837             :  */
    2838             : static void
    2839        8764 : dumpTableData(Archive *fout, const TableDataInfo *tdinfo)
    2840             : {
    2841        8764 :     DumpOptions *dopt = fout->dopt;
    2842        8764 :     TableInfo  *tbinfo = tdinfo->tdtable;
    2843        8764 :     PQExpBuffer copyBuf = createPQExpBuffer();
    2844        8764 :     PQExpBuffer clistBuf = createPQExpBuffer();
    2845             :     DataDumperPtr dumpFn;
    2846        8764 :     char       *tdDefn = NULL;
    2847             :     char       *copyStmt;
    2848             :     const char *copyFrom;
    2849             : 
    2850             :     /* We had better have loaded per-column details about this table */
    2851             :     Assert(tbinfo->interesting);
    2852             : 
    2853             :     /*
    2854             :      * When load-via-partition-root is set or forced, get the root table name
    2855             :      * for the partition table, so that we can reload data through the root
    2856             :      * table.  Then construct a comment to be inserted into the TOC entry's
    2857             :      * defn field, so that such cases can be identified reliably.
    2858             :      */
    2859        8764 :     if (tbinfo->ispartition &&
    2860        4204 :         (dopt->load_via_partition_root ||
    2861        2102 :          forcePartitionRootLoad(tbinfo)))
    2862         156 :     {
    2863             :         TableInfo  *parentTbinfo;
    2864             :         char       *sanitized;
    2865             : 
    2866         156 :         parentTbinfo = getRootTableInfo(tbinfo);
    2867         156 :         copyFrom = fmtQualifiedDumpable(parentTbinfo);
    2868         156 :         sanitized = sanitize_line(copyFrom, true);
    2869         156 :         printfPQExpBuffer(copyBuf, "-- load via partition root %s",
    2870             :                           sanitized);
    2871         156 :         free(sanitized);
    2872         156 :         tdDefn = pg_strdup(copyBuf->data);
    2873             :     }
    2874             :     else
    2875        8608 :         copyFrom = fmtQualifiedDumpable(tbinfo);
    2876             : 
    2877        8764 :     if (dopt->dump_inserts == 0)
    2878             :     {
    2879             :         /* Dump/restore using COPY */
    2880        8594 :         dumpFn = dumpTableData_copy;
    2881             :         /* must use 2 steps here 'cause fmtId is nonreentrant */
    2882        8594 :         printfPQExpBuffer(copyBuf, "COPY %s ",
    2883             :                           copyFrom);
    2884        8594 :         appendPQExpBuffer(copyBuf, "%s FROM stdin;\n",
    2885             :                           fmtCopyColumnList(tbinfo, clistBuf));
    2886        8594 :         copyStmt = copyBuf->data;
    2887             :     }
    2888             :     else
    2889             :     {
    2890             :         /* Restore using INSERT */
    2891         170 :         dumpFn = dumpTableData_insert;
    2892         170 :         copyStmt = NULL;
    2893             :     }
    2894             : 
    2895             :     /*
    2896             :      * Note: although the TableDataInfo is a full DumpableObject, we treat its
    2897             :      * dependency on its table as "special" and pass it to ArchiveEntry now.
    2898             :      * See comments for BuildArchiveDependencies.
    2899             :      */
    2900        8764 :     if (tdinfo->dobj.dump & DUMP_COMPONENT_DATA)
    2901             :     {
    2902             :         TocEntry   *te;
    2903             : 
    2904        8764 :         te = ArchiveEntry(fout, tdinfo->dobj.catId, tdinfo->dobj.dumpId,
    2905        8764 :                           ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
    2906             :                                        .namespace = tbinfo->dobj.namespace->dobj.name,
    2907             :                                        .owner = tbinfo->rolname,
    2908             :                                        .description = "TABLE DATA",
    2909             :                                        .section = SECTION_DATA,
    2910             :                                        .createStmt = tdDefn,
    2911             :                                        .copyStmt = copyStmt,
    2912             :                                        .deps = &(tbinfo->dobj.dumpId),
    2913             :                                        .nDeps = 1,
    2914             :                                        .dumpFn = dumpFn,
    2915             :                                        .dumpArg = tdinfo));
    2916             : 
    2917             :         /*
    2918             :          * Set the TocEntry's dataLength in case we are doing a parallel dump
    2919             :          * and want to order dump jobs by table size.  We choose to measure
    2920             :          * dataLength in table pages (including TOAST pages) during dump, so
    2921             :          * no scaling is needed.
    2922             :          *
    2923             :          * However, relpages is declared as "integer" in pg_class, and hence
    2924             :          * also in TableInfo, but it's really BlockNumber a/k/a unsigned int.
    2925             :          * Cast so that we get the right interpretation of table sizes
    2926             :          * exceeding INT_MAX pages.
    2927             :          */
    2928        8764 :         te->dataLength = (BlockNumber) tbinfo->relpages;
    2929        8764 :         te->dataLength += (BlockNumber) tbinfo->toastpages;
    2930             : 
    2931             :         /*
    2932             :          * If pgoff_t is only 32 bits wide, the above refinement is useless,
    2933             :          * and instead we'd better worry about integer overflow.  Clamp to
    2934             :          * INT_MAX if the correct result exceeds that.
    2935             :          */
    2936             :         if (sizeof(te->dataLength) == 4 &&
    2937             :             (tbinfo->relpages < 0 || tbinfo->toastpages < 0 ||
    2938             :              te->dataLength < 0))
    2939             :             te->dataLength = INT_MAX;
    2940             :     }
    2941             : 
    2942        8764 :     destroyPQExpBuffer(copyBuf);
    2943        8764 :     destroyPQExpBuffer(clistBuf);
    2944        8764 : }
    2945             : 
    2946             : /*
    2947             :  * refreshMatViewData -
    2948             :  *    load or refresh the contents of a single materialized view
    2949             :  *
    2950             :  * Actually, this just makes an ArchiveEntry for the REFRESH MATERIALIZED VIEW
    2951             :  * statement.
    2952             :  */
    2953             : static void
    2954         804 : refreshMatViewData(Archive *fout, const TableDataInfo *tdinfo)
    2955             : {
    2956         804 :     TableInfo  *tbinfo = tdinfo->tdtable;
    2957             :     PQExpBuffer q;
    2958             : 
    2959             :     /* If the materialized view is not flagged as populated, skip this. */
    2960         804 :     if (!tbinfo->relispopulated)
    2961         148 :         return;
    2962             : 
    2963         656 :     q = createPQExpBuffer();
    2964             : 
    2965         656 :     appendPQExpBuffer(q, "REFRESH MATERIALIZED VIEW %s;\n",
    2966         656 :                       fmtQualifiedDumpable(tbinfo));
    2967             : 
    2968         656 :     if (tdinfo->dobj.dump & DUMP_COMPONENT_DATA)
    2969         656 :         ArchiveEntry(fout,
    2970             :                      tdinfo->dobj.catId, /* catalog ID */
    2971         656 :                      tdinfo->dobj.dumpId,    /* dump ID */
    2972         656 :                      ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
    2973             :                                   .namespace = tbinfo->dobj.namespace->dobj.name,
    2974             :                                   .owner = tbinfo->rolname,
    2975             :                                   .description = "MATERIALIZED VIEW DATA",
    2976             :                                   .section = SECTION_POST_DATA,
    2977             :                                   .createStmt = q->data,
    2978             :                                   .deps = tdinfo->dobj.dependencies,
    2979             :                                   .nDeps = tdinfo->dobj.nDeps));
    2980             : 
    2981         656 :     destroyPQExpBuffer(q);
    2982             : }
    2983             : 
    2984             : /*
    2985             :  * getTableData -
    2986             :  *    set up dumpable objects representing the contents of tables
    2987             :  */
    2988             : static void
    2989         348 : getTableData(DumpOptions *dopt, TableInfo *tblinfo, int numTables, char relkind)
    2990             : {
    2991             :     int         i;
    2992             : 
    2993       92996 :     for (i = 0; i < numTables; i++)
    2994             :     {
    2995       92648 :         if (tblinfo[i].dobj.dump & DUMP_COMPONENT_DATA &&
    2996        1858 :             (!relkind || tblinfo[i].relkind == relkind))
    2997       12250 :             makeTableDataInfo(dopt, &(tblinfo[i]));
    2998             :     }
    2999         348 : }
    3000             : 
    3001             : /*
    3002             :  * Make a dumpable object for the data of this specific table
    3003             :  *
    3004             :  * Note: we make a TableDataInfo if and only if we are going to dump the
    3005             :  * table data; the "dump" field in such objects isn't very interesting.
    3006             :  */
    3007             : static void
    3008       12472 : makeTableDataInfo(DumpOptions *dopt, TableInfo *tbinfo)
    3009             : {
    3010             :     TableDataInfo *tdinfo;
    3011             : 
    3012             :     /*
    3013             :      * Nothing to do if we already decided to dump the table.  This will
    3014             :      * happen for "config" tables.
    3015             :      */
    3016       12472 :     if (tbinfo->dataObj != NULL)
    3017           2 :         return;
    3018             : 
    3019             :     /* Skip VIEWs (no data to dump) */
    3020       12470 :     if (tbinfo->relkind == RELKIND_VIEW)
    3021         968 :         return;
    3022             :     /* Skip FOREIGN TABLEs (no data to dump) unless requested explicitly */
    3023       11502 :     if (tbinfo->relkind == RELKIND_FOREIGN_TABLE &&
    3024          82 :         (foreign_servers_include_oids.head == NULL ||
    3025           8 :          !simple_oid_list_member(&foreign_servers_include_oids,
    3026             :                                  tbinfo->foreign_server)))
    3027          80 :         return;
    3028             :     /* Skip partitioned tables (data in partitions) */
    3029       11422 :     if (tbinfo->relkind == RELKIND_PARTITIONED_TABLE)
    3030         998 :         return;
    3031             : 
    3032             :     /* Don't dump data in unlogged tables, if so requested */
    3033       10424 :     if (tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED &&
    3034          82 :         dopt->no_unlogged_table_data)
    3035          36 :         return;
    3036             : 
    3037             :     /* Check that the data is not explicitly excluded */
    3038       10388 :     if (simple_oid_list_member(&tabledata_exclude_oids,
    3039             :                                tbinfo->dobj.catId.oid))
    3040          16 :         return;
    3041             : 
    3042             :     /* OK, let's dump it */
    3043       10372 :     tdinfo = (TableDataInfo *) pg_malloc(sizeof(TableDataInfo));
    3044             : 
    3045       10372 :     if (tbinfo->relkind == RELKIND_MATVIEW)
    3046         804 :         tdinfo->dobj.objType = DO_REFRESH_MATVIEW;
    3047        9568 :     else if (tbinfo->relkind == RELKIND_SEQUENCE)
    3048         804 :         tdinfo->dobj.objType = DO_SEQUENCE_SET;
    3049             :     else
    3050        8764 :         tdinfo->dobj.objType = DO_TABLE_DATA;
    3051             : 
    3052             :     /*
    3053             :      * Note: use tableoid 0 so that this object won't be mistaken for
    3054             :      * something that pg_depend entries apply to.
    3055             :      */
    3056       10372 :     tdinfo->dobj.catId.tableoid = 0;
    3057       10372 :     tdinfo->dobj.catId.oid = tbinfo->dobj.catId.oid;
    3058       10372 :     AssignDumpId(&tdinfo->dobj);
    3059       10372 :     tdinfo->dobj.name = tbinfo->dobj.name;
    3060       10372 :     tdinfo->dobj.namespace = tbinfo->dobj.namespace;
    3061       10372 :     tdinfo->tdtable = tbinfo;
    3062       10372 :     tdinfo->filtercond = NULL;   /* might get set later */
    3063       10372 :     addObjectDependency(&tdinfo->dobj, tbinfo->dobj.dumpId);
    3064             : 
    3065             :     /* A TableDataInfo contains data, of course */
    3066       10372 :     tdinfo->dobj.components |= DUMP_COMPONENT_DATA;
    3067             : 
    3068       10372 :     tbinfo->dataObj = tdinfo;
    3069             : 
    3070             :     /*
    3071             :      * Materialized view statistics must be restored after the data, because
    3072             :      * REFRESH MATERIALIZED VIEW replaces the storage and resets the stats.
    3073             :      *
    3074             :      * The dependency is added here because the statistics objects are created
    3075             :      * first.
    3076             :      */
    3077       10372 :     if (tbinfo->relkind == RELKIND_MATVIEW && tbinfo->stats != NULL)
    3078             :     {
    3079         640 :         tbinfo->stats->section = SECTION_POST_DATA;
    3080         640 :         addObjectDependency(&tbinfo->stats->dobj, tdinfo->dobj.dumpId);
    3081             :     }
    3082             : 
    3083             :     /* Make sure that we'll collect per-column info for this table. */
    3084       10372 :     tbinfo->interesting = true;
    3085             : }
    3086             : 
    3087             : /*
    3088             :  * The refresh for a materialized view must be dependent on the refresh for
    3089             :  * any materialized view that this one is dependent on.
    3090             :  *
    3091             :  * This must be called after all the objects are created, but before they are
    3092             :  * sorted.
    3093             :  */
    3094             : static void
    3095         284 : buildMatViewRefreshDependencies(Archive *fout)
    3096             : {
    3097             :     PQExpBuffer query;
    3098             :     PGresult   *res;
    3099             :     int         ntups,
    3100             :                 i;
    3101             :     int         i_classid,
    3102             :                 i_objid,
    3103             :                 i_refobjid;
    3104             : 
    3105             :     /* No Mat Views before 9.3. */
    3106         284 :     if (fout->remoteVersion < 90300)
    3107           0 :         return;
    3108             : 
    3109         284 :     query = createPQExpBuffer();
    3110             : 
    3111         284 :     appendPQExpBufferStr(query, "WITH RECURSIVE w AS "
    3112             :                          "( "
    3113             :                          "SELECT d1.objid, d2.refobjid, c2.relkind AS refrelkind "
    3114             :                          "FROM pg_depend d1 "
    3115             :                          "JOIN pg_class c1 ON c1.oid = d1.objid "
    3116             :                          "AND c1.relkind = " CppAsString2(RELKIND_MATVIEW)
    3117             :                          " JOIN pg_rewrite r1 ON r1.ev_class = d1.objid "
    3118             :                          "JOIN pg_depend d2 ON d2.classid = 'pg_rewrite'::regclass "
    3119             :                          "AND d2.objid = r1.oid "
    3120             :                          "AND d2.refobjid <> d1.objid "
    3121             :                          "JOIN pg_class c2 ON c2.oid = d2.refobjid "
    3122             :                          "AND c2.relkind IN (" CppAsString2(RELKIND_MATVIEW) ","
    3123             :                          CppAsString2(RELKIND_VIEW) ") "
    3124             :                          "WHERE d1.classid = 'pg_class'::regclass "
    3125             :                          "UNION "
    3126             :                          "SELECT w.objid, d3.refobjid, c3.relkind "
    3127             :                          "FROM w "
    3128             :                          "JOIN pg_rewrite r3 ON r3.ev_class = w.refobjid "
    3129             :                          "JOIN pg_depend d3 ON d3.classid = 'pg_rewrite'::regclass "
    3130             :                          "AND d3.objid = r3.oid "
    3131             :                          "AND d3.refobjid <> w.refobjid "
    3132             :                          "JOIN pg_class c3 ON c3.oid = d3.refobjid "
    3133             :                          "AND c3.relkind IN (" CppAsString2(RELKIND_MATVIEW) ","
    3134             :                          CppAsString2(RELKIND_VIEW) ") "
    3135             :                          ") "
    3136             :                          "SELECT 'pg_class'::regclass::oid AS classid, objid, refobjid "
    3137             :                          "FROM w "
    3138             :                          "WHERE refrelkind = " CppAsString2(RELKIND_MATVIEW));
    3139             : 
    3140         284 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    3141             : 
    3142         284 :     ntups = PQntuples(res);
    3143             : 
    3144         284 :     i_classid = PQfnumber(res, "classid");
    3145         284 :     i_objid = PQfnumber(res, "objid");
    3146         284 :     i_refobjid = PQfnumber(res, "refobjid");
    3147             : 
    3148         848 :     for (i = 0; i < ntups; i++)
    3149             :     {
    3150             :         CatalogId   objId;
    3151             :         CatalogId   refobjId;
    3152             :         DumpableObject *dobj;
    3153             :         DumpableObject *refdobj;
    3154             :         TableInfo  *tbinfo;
    3155             :         TableInfo  *reftbinfo;
    3156             : 
    3157         564 :         objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
    3158         564 :         objId.oid = atooid(PQgetvalue(res, i, i_objid));
    3159         564 :         refobjId.tableoid = objId.tableoid;
    3160         564 :         refobjId.oid = atooid(PQgetvalue(res, i, i_refobjid));
    3161             : 
    3162         564 :         dobj = findObjectByCatalogId(objId);
    3163         564 :         if (dobj == NULL)
    3164          96 :             continue;
    3165             : 
    3166             :         Assert(dobj->objType == DO_TABLE);
    3167         564 :         tbinfo = (TableInfo *) dobj;
    3168             :         Assert(tbinfo->relkind == RELKIND_MATVIEW);
    3169         564 :         dobj = (DumpableObject *) tbinfo->dataObj;
    3170         564 :         if (dobj == NULL)
    3171          96 :             continue;
    3172             :         Assert(dobj->objType == DO_REFRESH_MATVIEW);
    3173             : 
    3174         468 :         refdobj = findObjectByCatalogId(refobjId);
    3175         468 :         if (refdobj == NULL)
    3176           0 :             continue;
    3177             : 
    3178             :         Assert(refdobj->objType == DO_TABLE);
    3179         468 :         reftbinfo = (TableInfo *) refdobj;
    3180             :         Assert(reftbinfo->relkind == RELKIND_MATVIEW);
    3181         468 :         refdobj = (DumpableObject *) reftbinfo->dataObj;
    3182         468 :         if (refdobj == NULL)
    3183           0 :             continue;
    3184             :         Assert(refdobj->objType == DO_REFRESH_MATVIEW);
    3185             : 
    3186         468 :         addObjectDependency(dobj, refdobj->dumpId);
    3187             : 
    3188         468 :         if (!reftbinfo->relispopulated)
    3189          74 :             tbinfo->relispopulated = false;
    3190             :     }
    3191             : 
    3192         284 :     PQclear(res);
    3193             : 
    3194         284 :     destroyPQExpBuffer(query);
    3195             : }
    3196             : 
    3197             : /*
    3198             :  * getTableDataFKConstraints -
    3199             :  *    add dump-order dependencies reflecting foreign key constraints
    3200             :  *
    3201             :  * This code is executed only in a data-only dump --- in schema+data dumps
    3202             :  * we handle foreign key issues by not creating the FK constraints until
    3203             :  * after the data is loaded.  In a data-only dump, however, we want to
    3204             :  * order the table data objects in such a way that a table's referenced
    3205             :  * tables are restored first.  (In the presence of circular references or
    3206             :  * self-references this may be impossible; we'll detect and complain about
    3207             :  * that during the dependency sorting step.)
    3208             :  */
    3209             : static void
    3210          14 : getTableDataFKConstraints(void)
    3211             : {
    3212             :     DumpableObject **dobjs;
    3213             :     int         numObjs;
    3214             :     int         i;
    3215             : 
    3216             :     /* Search through all the dumpable objects for FK constraints */
    3217          14 :     getDumpableObjects(&dobjs, &numObjs);
    3218       51614 :     for (i = 0; i < numObjs; i++)
    3219             :     {
    3220       51600 :         if (dobjs[i]->objType == DO_FK_CONSTRAINT)
    3221             :         {
    3222          16 :             ConstraintInfo *cinfo = (ConstraintInfo *) dobjs[i];
    3223             :             TableInfo  *ftable;
    3224             : 
    3225             :             /* Not interesting unless both tables are to be dumped */
    3226          16 :             if (cinfo->contable == NULL ||
    3227          16 :                 cinfo->contable->dataObj == NULL)
    3228           8 :                 continue;
    3229           8 :             ftable = findTableByOid(cinfo->confrelid);
    3230           8 :             if (ftable == NULL ||
    3231           8 :                 ftable->dataObj == NULL)
    3232           0 :                 continue;
    3233             : 
    3234             :             /*
    3235             :              * Okay, make referencing table's TABLE_DATA object depend on the
    3236             :              * referenced table's TABLE_DATA object.
    3237             :              */
    3238           8 :             addObjectDependency(&cinfo->contable->dataObj->dobj,
    3239           8 :                                 ftable->dataObj->dobj.dumpId);
    3240             :         }
    3241             :     }
    3242          14 :     free(dobjs);
    3243          14 : }
    3244             : 
    3245             : 
    3246             : /*
    3247             :  * dumpDatabase:
    3248             :  *  dump the database definition
    3249             :  */
    3250             : static void
    3251         164 : dumpDatabase(Archive *fout)
    3252             : {
    3253         164 :     DumpOptions *dopt = fout->dopt;
    3254         164 :     PQExpBuffer dbQry = createPQExpBuffer();
    3255         164 :     PQExpBuffer delQry = createPQExpBuffer();
    3256         164 :     PQExpBuffer creaQry = createPQExpBuffer();
    3257         164 :     PQExpBuffer labelq = createPQExpBuffer();
    3258         164 :     PGconn     *conn = GetConnection(fout);
    3259             :     PGresult   *res;
    3260             :     int         i_tableoid,
    3261             :                 i_oid,
    3262             :                 i_datname,
    3263             :                 i_datdba,
    3264             :                 i_encoding,
    3265             :                 i_datlocprovider,
    3266             :                 i_collate,
    3267             :                 i_ctype,
    3268             :                 i_datlocale,
    3269             :                 i_daticurules,
    3270             :                 i_frozenxid,
    3271             :                 i_minmxid,
    3272             :                 i_datacl,
    3273             :                 i_acldefault,
    3274             :                 i_datistemplate,
    3275             :                 i_datconnlimit,
    3276             :                 i_datcollversion,
    3277             :                 i_tablespace;
    3278             :     CatalogId   dbCatId;
    3279             :     DumpId      dbDumpId;
    3280             :     DumpableAcl dbdacl;
    3281             :     const char *datname,
    3282             :                *dba,
    3283             :                *encoding,
    3284             :                *datlocprovider,
    3285             :                *collate,
    3286             :                *ctype,
    3287             :                *locale,
    3288             :                *icurules,
    3289             :                *datistemplate,
    3290             :                *datconnlimit,
    3291             :                *tablespace;
    3292             :     uint32      frozenxid,
    3293             :                 minmxid;
    3294             :     char       *qdatname;
    3295             : 
    3296         164 :     pg_log_info("saving database definition");
    3297             : 
    3298             :     /*
    3299             :      * Fetch the database-level properties for this database.
    3300             :      */
    3301         164 :     appendPQExpBufferStr(dbQry, "SELECT tableoid, oid, datname, "
    3302             :                          "datdba, "
    3303             :                          "pg_encoding_to_char(encoding) AS encoding, "
    3304             :                          "datcollate, datctype, datfrozenxid, "
    3305             :                          "datacl, acldefault('d', datdba) AS acldefault, "
    3306             :                          "datistemplate, datconnlimit, ");
    3307         164 :     if (fout->remoteVersion >= 90300)
    3308         164 :         appendPQExpBufferStr(dbQry, "datminmxid, ");
    3309             :     else
    3310           0 :         appendPQExpBufferStr(dbQry, "0 AS datminmxid, ");
    3311         164 :     if (fout->remoteVersion >= 170000)
    3312         164 :         appendPQExpBufferStr(dbQry, "datlocprovider, datlocale, datcollversion, ");
    3313           0 :     else if (fout->remoteVersion >= 150000)
    3314           0 :         appendPQExpBufferStr(dbQry, "datlocprovider, daticulocale AS datlocale, datcollversion, ");
    3315             :     else
    3316           0 :         appendPQExpBufferStr(dbQry, "'c' AS datlocprovider, NULL AS datlocale, NULL AS datcollversion, ");
    3317         164 :     if (fout->remoteVersion >= 160000)
    3318         164 :         appendPQExpBufferStr(dbQry, "daticurules, ");
    3319             :     else
    3320           0 :         appendPQExpBufferStr(dbQry, "NULL AS daticurules, ");
    3321         164 :     appendPQExpBufferStr(dbQry,
    3322             :                          "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace, "
    3323             :                          "shobj_description(oid, 'pg_database') AS description "
    3324             :                          "FROM pg_database "
    3325             :                          "WHERE datname = current_database()");
    3326             : 
    3327         164 :     res = ExecuteSqlQueryForSingleRow(fout, dbQry->data);
    3328             : 
    3329         164 :     i_tableoid = PQfnumber(res, "tableoid");
    3330         164 :     i_oid = PQfnumber(res, "oid");
    3331         164 :     i_datname = PQfnumber(res, "datname");
    3332         164 :     i_datdba = PQfnumber(res, "datdba");
    3333         164 :     i_encoding = PQfnumber(res, "encoding");
    3334         164 :     i_datlocprovider = PQfnumber(res, "datlocprovider");
    3335         164 :     i_collate = PQfnumber(res, "datcollate");
    3336         164 :     i_ctype = PQfnumber(res, "datctype");
    3337         164 :     i_datlocale = PQfnumber(res, "datlocale");
    3338         164 :     i_daticurules = PQfnumber(res, "daticurules");
    3339         164 :     i_frozenxid = PQfnumber(res, "datfrozenxid");
    3340         164 :     i_minmxid = PQfnumber(res, "datminmxid");
    3341         164 :     i_datacl = PQfnumber(res, "datacl");
    3342         164 :     i_acldefault = PQfnumber(res, "acldefault");
    3343         164 :     i_datistemplate = PQfnumber(res, "datistemplate");
    3344         164 :     i_datconnlimit = PQfnumber(res, "datconnlimit");
    3345         164 :     i_datcollversion = PQfnumber(res, "datcollversion");
    3346         164 :     i_tablespace = PQfnumber(res, "tablespace");
    3347             : 
    3348         164 :     dbCatId.tableoid = atooid(PQgetvalue(res, 0, i_tableoid));
    3349         164 :     dbCatId.oid = atooid(PQgetvalue(res, 0, i_oid));
    3350         164 :     datname = PQgetvalue(res, 0, i_datname);
    3351         164 :     dba = getRoleName(PQgetvalue(res, 0, i_datdba));
    3352         164 :     encoding = PQgetvalue(res, 0, i_encoding);
    3353         164 :     datlocprovider = PQgetvalue(res, 0, i_datlocprovider);
    3354         164 :     collate = PQgetvalue(res, 0, i_collate);
    3355         164 :     ctype = PQgetvalue(res, 0, i_ctype);
    3356         164 :     if (!PQgetisnull(res, 0, i_datlocale))
    3357          28 :         locale = PQgetvalue(res, 0, i_datlocale);
    3358             :     else
    3359         136 :         locale = NULL;
    3360         164 :     if (!PQgetisnull(res, 0, i_daticurules))
    3361           0 :         icurules = PQgetvalue(res, 0, i_daticurules);
    3362             :     else
    3363         164 :         icurules = NULL;
    3364         164 :     frozenxid = atooid(PQgetvalue(res, 0, i_frozenxid));
    3365         164 :     minmxid = atooid(PQgetvalue(res, 0, i_minmxid));
    3366         164 :     dbdacl.acl = PQgetvalue(res, 0, i_datacl);
    3367         164 :     dbdacl.acldefault = PQgetvalue(res, 0, i_acldefault);
    3368         164 :     datistemplate = PQgetvalue(res, 0, i_datistemplate);
    3369         164 :     datconnlimit = PQgetvalue(res, 0, i_datconnlimit);
    3370         164 :     tablespace = PQgetvalue(res, 0, i_tablespace);
    3371             : 
    3372         164 :     qdatname = pg_strdup(fmtId(datname));
    3373             : 
    3374             :     /*
    3375             :      * Prepare the CREATE DATABASE command.  We must specify OID (if we want
    3376             :      * to preserve that), as well as the encoding, locale, and tablespace
    3377             :      * since those can't be altered later.  Other DB properties are left to
    3378             :      * the DATABASE PROPERTIES entry, so that they can be applied after
    3379             :      * reconnecting to the target DB.
    3380             :      *
    3381             :      * For binary upgrade, we use the FILE_COPY strategy because testing has
    3382             :      * shown it to be faster.  When the server is in binary upgrade mode, it
    3383             :      * will also skip the checkpoints this strategy ordinarily performs.
    3384             :      */
    3385         164 :     if (dopt->binary_upgrade)
    3386             :     {
    3387          70 :         appendPQExpBuffer(creaQry,
    3388             :                           "CREATE DATABASE %s WITH TEMPLATE = template0 "
    3389             :                           "OID = %u STRATEGY = FILE_COPY",
    3390             :                           qdatname, dbCatId.oid);
    3391             :     }
    3392             :     else
    3393             :     {
    3394          94 :         appendPQExpBuffer(creaQry, "CREATE DATABASE %s WITH TEMPLATE = template0",
    3395             :                           qdatname);
    3396             :     }
    3397         164 :     if (strlen(encoding) > 0)
    3398             :     {
    3399         164 :         appendPQExpBufferStr(creaQry, " ENCODING = ");
    3400         164 :         appendStringLiteralAH(creaQry, encoding, fout);
    3401             :     }
    3402             : 
    3403         164 :     appendPQExpBufferStr(creaQry, " LOCALE_PROVIDER = ");
    3404         164 :     if (datlocprovider[0] == 'b')
    3405          28 :         appendPQExpBufferStr(creaQry, "builtin");
    3406         136 :     else if (datlocprovider[0] == 'c')
    3407         136 :         appendPQExpBufferStr(creaQry, "libc");
    3408           0 :     else if (datlocprovider[0] == 'i')
    3409           0 :         appendPQExpBufferStr(creaQry, "icu");
    3410             :     else
    3411           0 :         pg_fatal("unrecognized locale provider: %s",
    3412             :                  datlocprovider);
    3413             : 
    3414         164 :     if (strlen(collate) > 0 && strcmp(collate, ctype) == 0)
    3415             :     {
    3416         164 :         appendPQExpBufferStr(creaQry, " LOCALE = ");
    3417         164 :         appendStringLiteralAH(creaQry, collate, fout);
    3418             :     }
    3419             :     else
    3420             :     {
    3421           0 :         if (strlen(collate) > 0)
    3422             :         {
    3423           0 :             appendPQExpBufferStr(creaQry, " LC_COLLATE = ");
    3424           0 :             appendStringLiteralAH(creaQry, collate, fout);
    3425             :         }
    3426           0 :         if (strlen(ctype) > 0)
    3427             :         {
    3428           0 :             appendPQExpBufferStr(creaQry, " LC_CTYPE = ");
    3429           0 :             appendStringLiteralAH(creaQry, ctype, fout);
    3430             :         }
    3431             :     }
    3432         164 :     if (locale)
    3433             :     {
    3434          28 :         if (datlocprovider[0] == 'b')
    3435          28 :             appendPQExpBufferStr(creaQry, " BUILTIN_LOCALE = ");
    3436             :         else
    3437           0 :             appendPQExpBufferStr(creaQry, " ICU_LOCALE = ");
    3438             : 
    3439          28 :         appendStringLiteralAH(creaQry, locale, fout);
    3440             :     }
    3441             : 
    3442         164 :     if (icurules)
    3443             :     {
    3444           0 :         appendPQExpBufferStr(creaQry, " ICU_RULES = ");
    3445           0 :         appendStringLiteralAH(creaQry, icurules, fout);
    3446             :     }
    3447             : 
    3448             :     /*
    3449             :      * For binary upgrade, carry over the collation version.  For normal
    3450             :      * dump/restore, omit the version, so that it is computed upon restore.
    3451             :      */
    3452         164 :     if (dopt->binary_upgrade)
    3453             :     {
    3454          70 :         if (!PQgetisnull(res, 0, i_datcollversion))
    3455             :         {
    3456          70 :             appendPQExpBufferStr(creaQry, " COLLATION_VERSION = ");
    3457          70 :             appendStringLiteralAH(creaQry,
    3458             :                                   PQgetvalue(res, 0, i_datcollversion),
    3459             :                                   fout);
    3460             :         }
    3461             :     }
    3462             : 
    3463             :     /*
    3464             :      * Note: looking at dopt->outputNoTablespaces here is completely the wrong
    3465             :      * thing; the decision whether to specify a tablespace should be left till
    3466             :      * pg_restore, so that pg_restore --no-tablespaces applies.  Ideally we'd
    3467             :      * label the DATABASE entry with the tablespace and let the normal
    3468             :      * tablespace selection logic work ... but CREATE DATABASE doesn't pay
    3469             :      * attention to default_tablespace, so that won't work.
    3470             :      */
    3471         164 :     if (strlen(tablespace) > 0 && strcmp(tablespace, "pg_default") != 0 &&
    3472          10 :         !dopt->outputNoTablespaces)
    3473          10 :         appendPQExpBuffer(creaQry, " TABLESPACE = %s",
    3474             :                           fmtId(tablespace));
    3475         164 :     appendPQExpBufferStr(creaQry, ";\n");
    3476             : 
    3477         164 :     appendPQExpBuffer(delQry, "DROP DATABASE %s;\n",
    3478             :                       qdatname);
    3479             : 
    3480         164 :     dbDumpId = createDumpId();
    3481             : 
    3482         164 :     ArchiveEntry(fout,
    3483             :                  dbCatId,       /* catalog ID */
    3484             :                  dbDumpId,      /* dump ID */
    3485         164 :                  ARCHIVE_OPTS(.tag = datname,
    3486             :                               .owner = dba,
    3487             :                               .description = "DATABASE",
    3488             :                               .section = SECTION_PRE_DATA,
    3489             :                               .createStmt = creaQry->data,
    3490             :                               .dropStmt = delQry->data));
    3491             : 
    3492             :     /* Compute correct tag for archive entry */
    3493         164 :     appendPQExpBuffer(labelq, "DATABASE %s", qdatname);
    3494             : 
    3495             :     /* Dump DB comment if any */
    3496             :     {
    3497             :         /*
    3498             :          * 8.2 and up keep comments on shared objects in a shared table, so we
    3499             :          * cannot use the dumpComment() code used for other database objects.
    3500             :          * Be careful that the ArchiveEntry parameters match that function.
    3501             :          */
    3502         164 :         char       *comment = PQgetvalue(res, 0, PQfnumber(res, "description"));
    3503             : 
    3504         164 :         if (comment && *comment && !dopt->no_comments)
    3505             :         {
    3506          74 :             resetPQExpBuffer(dbQry);
    3507             : 
    3508             :             /*
    3509             :              * Generates warning when loaded into a differently-named
    3510             :              * database.
    3511             :              */
    3512          74 :             appendPQExpBuffer(dbQry, "COMMENT ON DATABASE %s IS ", qdatname);
    3513          74 :             appendStringLiteralAH(dbQry, comment, fout);
    3514          74 :             appendPQExpBufferStr(dbQry, ";\n");
    3515             : 
    3516          74 :             ArchiveEntry(fout, nilCatalogId, createDumpId(),
    3517          74 :                          ARCHIVE_OPTS(.tag = labelq->data,
    3518             :                                       .owner = dba,
    3519             :                                       .description = "COMMENT",
    3520             :                                       .section = SECTION_NONE,
    3521             :                                       .createStmt = dbQry->data,
    3522             :                                       .deps = &dbDumpId,
    3523             :                                       .nDeps = 1));
    3524             :         }
    3525             :     }
    3526             : 
    3527             :     /* Dump DB security label, if enabled */
    3528         164 :     if (!dopt->no_security_labels)
    3529             :     {
    3530             :         PGresult   *shres;
    3531             :         PQExpBuffer seclabelQry;
    3532             : 
    3533         164 :         seclabelQry = createPQExpBuffer();
    3534             : 
    3535         164 :         buildShSecLabelQuery("pg_database", dbCatId.oid, seclabelQry);
    3536         164 :         shres = ExecuteSqlQuery(fout, seclabelQry->data, PGRES_TUPLES_OK);
    3537         164 :         resetPQExpBuffer(seclabelQry);
    3538         164 :         emitShSecLabels(conn, shres, seclabelQry, "DATABASE", datname);
    3539         164 :         if (seclabelQry->len > 0)
    3540           0 :             ArchiveEntry(fout, nilCatalogId, createDumpId(),
    3541           0 :                          ARCHIVE_OPTS(.tag = labelq->data,
    3542             :                                       .owner = dba,
    3543             :                                       .description = "SECURITY LABEL",
    3544             :                                       .section = SECTION_NONE,
    3545             :                                       .createStmt = seclabelQry->data,
    3546             :                                       .deps = &dbDumpId,
    3547             :                                       .nDeps = 1));
    3548         164 :         destroyPQExpBuffer(seclabelQry);
    3549         164 :         PQclear(shres);
    3550             :     }
    3551             : 
    3552             :     /*
    3553             :      * Dump ACL if any.  Note that we do not support initial privileges
    3554             :      * (pg_init_privs) on databases.
    3555             :      */
    3556         164 :     dbdacl.privtype = 0;
    3557         164 :     dbdacl.initprivs = NULL;
    3558             : 
    3559         164 :     dumpACL(fout, dbDumpId, InvalidDumpId, "DATABASE",
    3560             :             qdatname, NULL, NULL,
    3561             :             NULL, dba, &dbdacl);
    3562             : 
    3563             :     /*
    3564             :      * Now construct a DATABASE PROPERTIES archive entry to restore any
    3565             :      * non-default database-level properties.  (The reason this must be
    3566             :      * separate is that we cannot put any additional commands into the TOC
    3567             :      * entry that has CREATE DATABASE.  pg_restore would execute such a group
    3568             :      * in an implicit transaction block, and the backend won't allow CREATE
    3569             :      * DATABASE in that context.)
    3570             :      */
    3571         164 :     resetPQExpBuffer(creaQry);
    3572         164 :     resetPQExpBuffer(delQry);
    3573             : 
    3574         164 :     if (strlen(datconnlimit) > 0 && strcmp(datconnlimit, "-1") != 0)
    3575           0 :         appendPQExpBuffer(creaQry, "ALTER DATABASE %s CONNECTION LIMIT = %s;\n",
    3576             :                           qdatname, datconnlimit);
    3577             : 
    3578         164 :     if (strcmp(datistemplate, "t") == 0)
    3579             :     {
    3580          20 :         appendPQExpBuffer(creaQry, "ALTER DATABASE %s IS_TEMPLATE = true;\n",
    3581             :                           qdatname);
    3582             : 
    3583             :         /*
    3584             :          * The backend won't accept DROP DATABASE on a template database.  We
    3585             :          * can deal with that by removing the template marking before the DROP
    3586             :          * gets issued.  We'd prefer to use ALTER DATABASE IF EXISTS here, but
    3587             :          * since no such command is currently supported, fake it with a direct
    3588             :          * UPDATE on pg_database.
    3589             :          */
    3590          20 :         appendPQExpBufferStr(delQry, "UPDATE pg_catalog.pg_database "
    3591             :                              "SET datistemplate = false WHERE datname = ");
    3592          20 :         appendStringLiteralAH(delQry, datname, fout);
    3593          20 :         appendPQExpBufferStr(delQry, ";\n");
    3594             :     }
    3595             : 
    3596             :     /*
    3597             :      * We do not restore pg_database.dathasloginevt because it is set
    3598             :      * automatically on login event trigger creation.
    3599             :      */
    3600             : 
    3601             :     /* Add database-specific SET options */
    3602         164 :     dumpDatabaseConfig(fout, creaQry, datname, dbCatId.oid);
    3603             : 
    3604             :     /*
    3605             :      * We stick this binary-upgrade query into the DATABASE PROPERTIES archive
    3606             :      * entry, too, for lack of a better place.
    3607             :      */
    3608         164 :     if (dopt->binary_upgrade)
    3609             :     {
    3610          70 :         appendPQExpBufferStr(creaQry, "\n-- For binary upgrade, set datfrozenxid and datminmxid.\n");
    3611          70 :         appendPQExpBuffer(creaQry, "UPDATE pg_catalog.pg_database\n"
    3612             :                           "SET datfrozenxid = '%u', datminmxid = '%u'\n"
    3613             :                           "WHERE datname = ",
    3614             :                           frozenxid, minmxid);
    3615          70 :         appendStringLiteralAH(creaQry, datname, fout);
    3616          70 :         appendPQExpBufferStr(creaQry, ";\n");
    3617             :     }
    3618             : 
    3619         164 :     if (creaQry->len > 0)
    3620          78 :         ArchiveEntry(fout, nilCatalogId, createDumpId(),
    3621          78 :                      ARCHIVE_OPTS(.tag = datname,
    3622             :                                   .owner = dba,
    3623             :                                   .description = "DATABASE PROPERTIES",
    3624             :                                   .section = SECTION_PRE_DATA,
    3625             :                                   .createStmt = creaQry->data,
    3626             :                                   .dropStmt = delQry->data,
    3627             :                                   .deps = &dbDumpId));
    3628             : 
    3629             :     /*
    3630             :      * pg_largeobject comes from the old system intact, so set its
    3631             :      * relfrozenxids, relminmxids and relfilenode.
    3632             :      */
    3633         164 :     if (dopt->binary_upgrade)
    3634             :     {
    3635             :         PGresult   *lo_res;
    3636          70 :         PQExpBuffer loFrozenQry = createPQExpBuffer();
    3637          70 :         PQExpBuffer loOutQry = createPQExpBuffer();
    3638          70 :         PQExpBuffer loHorizonQry = createPQExpBuffer();
    3639             :         int         ii_relfrozenxid,
    3640             :                     ii_relfilenode,
    3641             :                     ii_oid,
    3642             :                     ii_relminmxid;
    3643             : 
    3644             :         /*
    3645             :          * pg_largeobject
    3646             :          */
    3647          70 :         if (fout->remoteVersion >= 90300)
    3648          70 :             appendPQExpBuffer(loFrozenQry, "SELECT relfrozenxid, relminmxid, relfilenode, oid\n"
    3649             :                               "FROM pg_catalog.pg_class\n"
    3650             :                               "WHERE oid IN (%u, %u);\n",
    3651             :                               LargeObjectRelationId, LargeObjectLOidPNIndexId);
    3652             :         else
    3653           0 :             appendPQExpBuffer(loFrozenQry, "SELECT relfrozenxid, 0 AS relminmxid, relfilenode, oid\n"
    3654             :                               "FROM pg_catalog.pg_class\n"
    3655             :                               "WHERE oid IN (%u, %u);\n",
    3656             :                               LargeObjectRelationId, LargeObjectLOidPNIndexId);
    3657             : 
    3658          70 :         lo_res = ExecuteSqlQuery(fout, loFrozenQry->data, PGRES_TUPLES_OK);
    3659             : 
    3660          70 :         ii_relfrozenxid = PQfnumber(lo_res, "relfrozenxid");
    3661          70 :         ii_relminmxid = PQfnumber(lo_res, "relminmxid");
    3662          70 :         ii_relfilenode = PQfnumber(lo_res, "relfilenode");
    3663          70 :         ii_oid = PQfnumber(lo_res, "oid");
    3664             : 
    3665          70 :         appendPQExpBufferStr(loHorizonQry, "\n-- For binary upgrade, set pg_largeobject relfrozenxid and relminmxid\n");
    3666          70 :         appendPQExpBufferStr(loOutQry, "\n-- For binary upgrade, preserve pg_largeobject and index relfilenodes\n");
    3667         210 :         for (int i = 0; i < PQntuples(lo_res); ++i)
    3668             :         {
    3669             :             Oid         oid;
    3670             :             RelFileNumber relfilenumber;
    3671             : 
    3672         140 :             appendPQExpBuffer(loHorizonQry, "UPDATE pg_catalog.pg_class\n"
    3673             :                               "SET relfrozenxid = '%u', relminmxid = '%u'\n"
    3674             :                               "WHERE oid = %u;\n",
    3675         140 :                               atooid(PQgetvalue(lo_res, i, ii_relfrozenxid)),
    3676         140 :                               atooid(PQgetvalue(lo_res, i, ii_relminmxid)),
    3677         140 :                               atooid(PQgetvalue(lo_res, i, ii_oid)));
    3678             : 
    3679         140 :             oid = atooid(PQgetvalue(lo_res, i, ii_oid));
    3680         140 :             relfilenumber = atooid(PQgetvalue(lo_res, i, ii_relfilenode));
    3681             : 
    3682         140 :             if (oid == LargeObjectRelationId)
    3683          70 :                 appendPQExpBuffer(loOutQry,
    3684             :                                   "SELECT pg_catalog.binary_upgrade_set_next_heap_relfilenode('%u'::pg_catalog.oid);\n",
    3685             :                                   relfilenumber);
    3686          70 :             else if (oid == LargeObjectLOidPNIndexId)
    3687          70 :                 appendPQExpBuffer(loOutQry,
    3688             :                                   "SELECT pg_catalog.binary_upgrade_set_next_index_relfilenode('%u'::pg_catalog.oid);\n",
    3689             :                                   relfilenumber);
    3690             :         }
    3691             : 
    3692          70 :         appendPQExpBufferStr(loOutQry,
    3693             :                              "TRUNCATE pg_catalog.pg_largeobject;\n");
    3694          70 :         appendPQExpBufferStr(loOutQry, loHorizonQry->data);
    3695             : 
    3696          70 :         ArchiveEntry(fout, nilCatalogId, createDumpId(),
    3697          70 :                      ARCHIVE_OPTS(.tag = "pg_largeobject",
    3698             :                                   .description = "pg_largeobject",
    3699             :                                   .section = SECTION_PRE_DATA,
    3700             :                                   .createStmt = loOutQry->data));
    3701             : 
    3702          70 :         PQclear(lo_res);
    3703             : 
    3704          70 :         destroyPQExpBuffer(loFrozenQry);
    3705          70 :         destroyPQExpBuffer(loHorizonQry);
    3706          70 :         destroyPQExpBuffer(loOutQry);
    3707             :     }
    3708             : 
    3709         164 :     PQclear(res);
    3710             : 
    3711         164 :     free(qdatname);
    3712         164 :     destroyPQExpBuffer(dbQry);
    3713         164 :     destroyPQExpBuffer(delQry);
    3714         164 :     destroyPQExpBuffer(creaQry);
    3715         164 :     destroyPQExpBuffer(labelq);
    3716         164 : }
    3717             : 
    3718             : /*
    3719             :  * Collect any database-specific or role-and-database-specific SET options
    3720             :  * for this database, and append them to outbuf.
    3721             :  */
    3722             : static void
    3723         164 : dumpDatabaseConfig(Archive *AH, PQExpBuffer outbuf,
    3724             :                    const char *dbname, Oid dboid)
    3725             : {
    3726         164 :     PGconn     *conn = GetConnection(AH);
    3727         164 :     PQExpBuffer buf = createPQExpBuffer();
    3728             :     PGresult   *res;
    3729             : 
    3730             :     /* First collect database-specific options */
    3731         164 :     printfPQExpBuffer(buf, "SELECT unnest(setconfig) FROM pg_db_role_setting "
    3732             :                       "WHERE setrole = 0 AND setdatabase = '%u'::oid",
    3733             :                       dboid);
    3734             : 
    3735         164 :     res = ExecuteSqlQuery(AH, buf->data, PGRES_TUPLES_OK);
    3736             : 
    3737         224 :     for (int i = 0; i < PQntuples(res); i++)
    3738          60 :         makeAlterConfigCommand(conn, PQgetvalue(res, i, 0),
    3739             :                                "DATABASE", dbname, NULL, NULL,
    3740             :                                outbuf);
    3741             : 
    3742         164 :     PQclear(res);
    3743             : 
    3744             :     /* Now look for role-and-database-specific options */
    3745         164 :     printfPQExpBuffer(buf, "SELECT rolname, unnest(setconfig) "
    3746             :                       "FROM pg_db_role_setting s, pg_roles r "
    3747             :                       "WHERE setrole = r.oid AND setdatabase = '%u'::oid",
    3748             :                       dboid);
    3749             : 
    3750         164 :     res = ExecuteSqlQuery(AH, buf->data, PGRES_TUPLES_OK);
    3751             : 
    3752         164 :     for (int i = 0; i < PQntuples(res); i++)
    3753           0 :         makeAlterConfigCommand(conn, PQgetvalue(res, i, 1),
    3754           0 :                                "ROLE", PQgetvalue(res, i, 0),
    3755             :                                "DATABASE", dbname,
    3756             :                                outbuf);
    3757             : 
    3758         164 :     PQclear(res);
    3759             : 
    3760         164 :     destroyPQExpBuffer(buf);
    3761         164 : }
    3762             : 
    3763             : /*
    3764             :  * dumpEncoding: put the correct encoding into the archive
    3765             :  */
    3766             : static void
    3767         364 : dumpEncoding(Archive *AH)
    3768             : {
    3769         364 :     const char *encname = pg_encoding_to_char(AH->encoding);
    3770         364 :     PQExpBuffer qry = createPQExpBuffer();
    3771             : 
    3772         364 :     pg_log_info("saving encoding = %s", encname);
    3773             : 
    3774         364 :     appendPQExpBufferStr(qry, "SET client_encoding = ");
    3775         364 :     appendStringLiteralAH(qry, encname, AH);
    3776         364 :     appendPQExpBufferStr(qry, ";\n");
    3777             : 
    3778         364 :     ArchiveEntry(AH, nilCatalogId, createDumpId(),
    3779         364 :                  ARCHIVE_OPTS(.tag = "ENCODING",
    3780             :                               .description = "ENCODING",
    3781             :                               .section = SECTION_PRE_DATA,
    3782             :                               .createStmt = qry->data));
    3783             : 
    3784         364 :     destroyPQExpBuffer(qry);
    3785         364 : }
    3786             : 
    3787             : 
    3788             : /*
    3789             :  * dumpStdStrings: put the correct escape string behavior into the archive
    3790             :  */
    3791             : static void
    3792         364 : dumpStdStrings(Archive *AH)
    3793             : {
    3794         364 :     const char *stdstrings = AH->std_strings ? "on" : "off";
    3795         364 :     PQExpBuffer qry = createPQExpBuffer();
    3796             : 
    3797         364 :     pg_log_info("saving \"standard_conforming_strings = %s\"",
    3798             :                 stdstrings);
    3799             : 
    3800         364 :     appendPQExpBuffer(qry, "SET standard_conforming_strings = '%s';\n",
    3801             :                       stdstrings);
    3802             : 
    3803         364 :     ArchiveEntry(AH, nilCatalogId, createDumpId(),
    3804         364 :                  ARCHIVE_OPTS(.tag = "STDSTRINGS",
    3805             :                               .description = "STDSTRINGS",
    3806             :                               .section = SECTION_PRE_DATA,
    3807             :                               .createStmt = qry->data));
    3808             : 
    3809         364 :     destroyPQExpBuffer(qry);
    3810         364 : }
    3811             : 
    3812             : /*
    3813             :  * dumpSearchPath: record the active search_path in the archive
    3814             :  */
    3815             : static void
    3816         364 : dumpSearchPath(Archive *AH)
    3817             : {
    3818         364 :     PQExpBuffer qry = createPQExpBuffer();
    3819         364 :     PQExpBuffer path = createPQExpBuffer();
    3820             :     PGresult   *res;
    3821         364 :     char      **schemanames = NULL;
    3822         364 :     int         nschemanames = 0;
    3823             :     int         i;
    3824             : 
    3825             :     /*
    3826             :      * We use the result of current_schemas(), not the search_path GUC,
    3827             :      * because that might contain wildcards such as "$user", which won't
    3828             :      * necessarily have the same value during restore.  Also, this way avoids
    3829             :      * listing schemas that may appear in search_path but not actually exist,
    3830             :      * which seems like a prudent exclusion.
    3831             :      */
    3832         364 :     res = ExecuteSqlQueryForSingleRow(AH,
    3833             :                                       "SELECT pg_catalog.current_schemas(false)");
    3834             : 
    3835         364 :     if (!parsePGArray(PQgetvalue(res, 0, 0), &schemanames, &nschemanames))
    3836           0 :         pg_fatal("could not parse result of current_schemas()");
    3837             : 
    3838             :     /*
    3839             :      * We use set_config(), not a simple "SET search_path" command, because
    3840             :      * the latter has less-clean behavior if the search path is empty.  While
    3841             :      * that's likely to get fixed at some point, it seems like a good idea to
    3842             :      * be as backwards-compatible as possible in what we put into archives.
    3843             :      */
    3844         364 :     for (i = 0; i < nschemanames; i++)
    3845             :     {
    3846           0 :         if (i > 0)
    3847           0 :             appendPQExpBufferStr(path, ", ");
    3848           0 :         appendPQExpBufferStr(path, fmtId(schemanames[i]));
    3849             :     }
    3850             : 
    3851         364 :     appendPQExpBufferStr(qry, "SELECT pg_catalog.set_config('search_path', ");
    3852         364 :     appendStringLiteralAH(qry, path->data, AH);
    3853         364 :     appendPQExpBufferStr(qry, ", false);\n");
    3854             : 
    3855         364 :     pg_log_info("saving \"search_path = %s\"", path->data);
    3856             : 
    3857         364 :     ArchiveEntry(AH, nilCatalogId, createDumpId(),
    3858         364 :                  ARCHIVE_OPTS(.tag = "SEARCHPATH",
    3859             :                               .description = "SEARCHPATH",
    3860             :                               .section = SECTION_PRE_DATA,
    3861             :                               .createStmt = qry->data));
    3862             : 
    3863             :     /* Also save it in AH->searchpath, in case we're doing plain text dump */
    3864         364 :     AH->searchpath = pg_strdup(qry->data);
    3865             : 
    3866         364 :     free(schemanames);
    3867         364 :     PQclear(res);
    3868         364 :     destroyPQExpBuffer(qry);
    3869         364 :     destroyPQExpBuffer(path);
    3870         364 : }
    3871             : 
    3872             : 
    3873             : /*
    3874             :  * getLOs:
    3875             :  *  Collect schema-level data about large objects
    3876             :  */
    3877             : static void
    3878         308 : getLOs(Archive *fout)
    3879             : {
    3880         308 :     DumpOptions *dopt = fout->dopt;
    3881         308 :     PQExpBuffer loQry = createPQExpBuffer();
    3882             :     PGresult   *res;
    3883             :     int         ntups;
    3884             :     int         i;
    3885             :     int         n;
    3886             :     int         i_oid;
    3887             :     int         i_lomowner;
    3888             :     int         i_lomacl;
    3889             :     int         i_acldefault;
    3890             : 
    3891         308 :     pg_log_info("reading large objects");
    3892             : 
    3893             :     /*
    3894             :      * Fetch LO OIDs and owner/ACL data.  Order the data so that all the blobs
    3895             :      * with the same owner/ACL appear together.
    3896             :      */
    3897         308 :     appendPQExpBufferStr(loQry,
    3898             :                          "SELECT oid, lomowner, lomacl, "
    3899             :                          "acldefault('L', lomowner) AS acldefault "
    3900             :                          "FROM pg_largeobject_metadata "
    3901             :                          "ORDER BY lomowner, lomacl::pg_catalog.text, oid");
    3902             : 
    3903         308 :     res = ExecuteSqlQuery(fout, loQry->data, PGRES_TUPLES_OK);
    3904             : 
    3905         308 :     i_oid = PQfnumber(res, "oid");
    3906         308 :     i_lomowner = PQfnumber(res, "lomowner");
    3907         308 :     i_lomacl = PQfnumber(res, "lomacl");
    3908         308 :     i_acldefault = PQfnumber(res, "acldefault");
    3909             : 
    3910         308 :     ntups = PQntuples(res);
    3911             : 
    3912             :     /*
    3913             :      * Group the blobs into suitably-sized groups that have the same owner and
    3914             :      * ACL setting, and build a metadata and a data DumpableObject for each
    3915             :      * group.  (If we supported initprivs for blobs, we'd have to insist that
    3916             :      * groups also share initprivs settings, since the DumpableObject only has
    3917             :      * room for one.)  i is the index of the first tuple in the current group,
    3918             :      * and n is the number of tuples we include in the group.
    3919             :      */
    3920         466 :     for (i = 0; i < ntups; i += n)
    3921             :     {
    3922         158 :         Oid         thisoid = atooid(PQgetvalue(res, i, i_oid));
    3923         158 :         char       *thisowner = PQgetvalue(res, i, i_lomowner);
    3924         158 :         char       *thisacl = PQgetvalue(res, i, i_lomacl);
    3925             :         LoInfo     *loinfo;
    3926             :         DumpableObject *lodata;
    3927             :         char        namebuf[64];
    3928             : 
    3929             :         /* Scan to find first tuple not to be included in group */
    3930         158 :         n = 1;
    3931         178 :         while (n < MAX_BLOBS_PER_ARCHIVE_ENTRY && i + n < ntups)
    3932             :         {
    3933          94 :             if (strcmp(thisowner, PQgetvalue(res, i + n, i_lomowner)) != 0 ||
    3934          94 :                 strcmp(thisacl, PQgetvalue(res, i + n, i_lomacl)) != 0)
    3935             :                 break;
    3936          20 :             n++;
    3937             :         }
    3938             : 
    3939             :         /* Build the metadata DumpableObject */
    3940         158 :         loinfo = (LoInfo *) pg_malloc(offsetof(LoInfo, looids) + n * sizeof(Oid));
    3941             : 
    3942         158 :         loinfo->dobj.objType = DO_LARGE_OBJECT;
    3943         158 :         loinfo->dobj.catId.tableoid = LargeObjectRelationId;
    3944         158 :         loinfo->dobj.catId.oid = thisoid;
    3945         158 :         AssignDumpId(&loinfo->dobj);
    3946             : 
    3947         158 :         if (n > 1)
    3948          10 :             snprintf(namebuf, sizeof(namebuf), "%u..%u", thisoid,
    3949          10 :                      atooid(PQgetvalue(res, i + n - 1, i_oid)));
    3950             :         else
    3951         148 :             snprintf(namebuf, sizeof(namebuf), "%u", thisoid);
    3952         158 :         loinfo->dobj.name = pg_strdup(namebuf);
    3953         158 :         loinfo->dacl.acl = pg_strdup(thisacl);
    3954         158 :         loinfo->dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
    3955         158 :         loinfo->dacl.privtype = 0;
    3956         158 :         loinfo->dacl.initprivs = NULL;
    3957         158 :         loinfo->rolname = getRoleName(thisowner);
    3958         158 :         loinfo->numlos = n;
    3959         158 :         loinfo->looids[0] = thisoid;
    3960             :         /* Collect OIDs of the remaining blobs in this group */
    3961         178 :         for (int k = 1; k < n; k++)
    3962             :         {
    3963             :             CatalogId   extraID;
    3964             : 
    3965          20 :             loinfo->looids[k] = atooid(PQgetvalue(res, i + k, i_oid));
    3966             : 
    3967             :             /* Make sure we can look up loinfo by any of the blobs' OIDs */
    3968          20 :             extraID.tableoid = LargeObjectRelationId;
    3969          20 :             extraID.oid = loinfo->looids[k];
    3970          20 :             recordAdditionalCatalogID(extraID, &loinfo->dobj);
    3971             :         }
    3972             : 
    3973             :         /* LOs have data */
    3974         158 :         loinfo->dobj.components |= DUMP_COMPONENT_DATA;
    3975             : 
    3976             :         /* Mark whether LO group has a non-empty ACL */
    3977         158 :         if (!PQgetisnull(res, i, i_lomacl))
    3978          74 :             loinfo->dobj.components |= DUMP_COMPONENT_ACL;
    3979             : 
    3980             :         /*
    3981             :          * In binary-upgrade mode for LOs, we do *not* dump out the LO data,
    3982             :          * as it will be copied by pg_upgrade, which simply copies the
    3983             :          * pg_largeobject table. We *do* however dump out anything but the
    3984             :          * data, as pg_upgrade copies just pg_largeobject, but not
    3985             :          * pg_largeobject_metadata, after the dump is restored.  In versions
    3986             :          * before v12, this is done via proper large object commands.  In
    3987             :          * newer versions, we dump the content of pg_largeobject_metadata and
    3988             :          * any associated pg_shdepend rows, which is faster to restore.  (On
    3989             :          * <v12, pg_largeobject_metadata was created WITH OIDS, so the OID
    3990             :          * column is hidden and won't be dumped.)
    3991             :          */
    3992         158 :         if (dopt->binary_upgrade)
    3993             :         {
    3994           6 :             if (fout->remoteVersion >= 120000)
    3995             :             {
    3996             :                 /*
    3997             :                  * We should've saved pg_largeobject_metadata's dump ID before
    3998             :                  * this point.
    3999             :                  */
    4000             :                 Assert(lo_metadata_dumpId);
    4001             : 
    4002           6 :                 loinfo->dobj.dump &= ~(DUMP_COMPONENT_DATA | DUMP_COMPONENT_ACL | DUMP_COMPONENT_DEFINITION);
    4003             : 
    4004             :                 /*
    4005             :                  * Mark the large object as dependent on
    4006             :                  * pg_largeobject_metadata so that any large object
    4007             :                  * comments/seclables are dumped after it.
    4008             :                  */
    4009           6 :                 loinfo->dobj.dependencies = (DumpId *) pg_malloc(sizeof(DumpId));
    4010           6 :                 loinfo->dobj.dependencies[0] = lo_metadata_dumpId;
    4011           6 :                 loinfo->dobj.nDeps = loinfo->dobj.allocDeps = 1;
    4012             :             }
    4013             :             else
    4014           0 :                 loinfo->dobj.dump &= ~DUMP_COMPONENT_DATA;
    4015             :         }
    4016             : 
    4017             :         /*
    4018             :          * Create a "BLOBS" data item for the group, too. This is just a
    4019             :          * placeholder for sorting; it carries no data now.
    4020             :          */
    4021         158 :         lodata = (DumpableObject *) pg_malloc(sizeof(DumpableObject));
    4022         158 :         lodata->objType = DO_LARGE_OBJECT_DATA;
    4023         158 :         lodata->catId = nilCatalogId;
    4024         158 :         AssignDumpId(lodata);
    4025         158 :         lodata->name = pg_strdup(namebuf);
    4026         158 :         lodata->components |= DUMP_COMPONENT_DATA;
    4027             :         /* Set up explicit dependency from data to metadata */
    4028         158 :         lodata->dependencies = (DumpId *) pg_malloc(sizeof(DumpId));
    4029         158 :         lodata->dependencies[0] = loinfo->dobj.dumpId;
    4030         158 :         lodata->nDeps = lodata->allocDeps = 1;
    4031             :     }
    4032             : 
    4033         308 :     PQclear(res);
    4034         308 :     destroyPQExpBuffer(loQry);
    4035         308 : }
    4036             : 
    4037             : /*
    4038             :  * dumpLO
    4039             :  *
    4040             :  * dump the definition (metadata) of the given large object group
    4041             :  */
    4042             : static void
    4043         156 : dumpLO(Archive *fout, const LoInfo *loinfo)
    4044             : {
    4045         156 :     PQExpBuffer cquery = createPQExpBuffer();
    4046             : 
    4047             :     /*
    4048             :      * The "definition" is just a newline-separated list of OIDs.  We need to
    4049             :      * put something into the dropStmt too, but it can just be a comment.
    4050             :      */
    4051         332 :     for (int i = 0; i < loinfo->numlos; i++)
    4052         176 :         appendPQExpBuffer(cquery, "%u\n", loinfo->looids[i]);
    4053             : 
    4054         156 :     if (loinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
    4055         152 :         ArchiveEntry(fout, loinfo->dobj.catId, loinfo->dobj.dumpId,
    4056         152 :                      ARCHIVE_OPTS(.tag = loinfo->dobj.name,
    4057             :                                   .owner = loinfo->rolname,
    4058             :                                   .description = "BLOB METADATA",
    4059             :                                   .section = SECTION_DATA,
    4060             :                                   .createStmt = cquery->data,
    4061             :                                   .dropStmt = "-- dummy"));
    4062             : 
    4063             :     /*
    4064             :      * Dump per-blob comments and seclabels if any.  We assume these are rare
    4065             :      * enough that it's okay to generate retail TOC entries for them.
    4066             :      */
    4067         156 :     if (loinfo->dobj.dump & (DUMP_COMPONENT_COMMENT |
    4068             :                              DUMP_COMPONENT_SECLABEL))
    4069             :     {
    4070         188 :         for (int i = 0; i < loinfo->numlos; i++)
    4071             :         {
    4072             :             CatalogId   catId;
    4073             :             char        namebuf[32];
    4074             : 
    4075             :             /* Build identifying info for this blob */
    4076         104 :             catId.tableoid = loinfo->dobj.catId.tableoid;
    4077         104 :             catId.oid = loinfo->looids[i];
    4078         104 :             snprintf(namebuf, sizeof(namebuf), "%u", loinfo->looids[i]);
    4079             : 
    4080         104 :             if (loinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
    4081         104 :                 dumpComment(fout, "LARGE OBJECT", namebuf,
    4082         104 :                             NULL, loinfo->rolname,
    4083         104 :                             catId, 0, loinfo->dobj.dumpId);
    4084             : 
    4085         104 :             if (loinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
    4086           0 :                 dumpSecLabel(fout, "LARGE OBJECT", namebuf,
    4087           0 :                              NULL, loinfo->rolname,
    4088           0 :                              catId, 0, loinfo->dobj.dumpId);
    4089             :         }
    4090             :     }
    4091             : 
    4092             :     /*
    4093             :      * Dump the ACLs if any (remember that all blobs in the group will have
    4094             :      * the same ACL).  If there's just one blob, dump a simple ACL entry; if
    4095             :      * there's more, make a "LARGE OBJECTS" entry that really contains only
    4096             :      * the ACL for the first blob.  _printTocEntry() will be cued by the tag
    4097             :      * string to emit a mutated version for each blob.
    4098             :      */
    4099         156 :     if (loinfo->dobj.dump & DUMP_COMPONENT_ACL)
    4100             :     {
    4101             :         char        namebuf[32];
    4102             : 
    4103             :         /* Build identifying info for the first blob */
    4104          72 :         snprintf(namebuf, sizeof(namebuf), "%u", loinfo->looids[0]);
    4105             : 
    4106          72 :         if (loinfo->numlos > 1)
    4107             :         {
    4108             :             char        tagbuf[64];
    4109             : 
    4110           0 :             snprintf(tagbuf, sizeof(tagbuf), "LARGE OBJECTS %u..%u",
    4111           0 :                      loinfo->looids[0], loinfo->looids[loinfo->numlos - 1]);
    4112             : 
    4113           0 :             dumpACL(fout, loinfo->dobj.dumpId, InvalidDumpId,
    4114             :                     "LARGE OBJECT", namebuf, NULL, NULL,
    4115           0 :                     tagbuf, loinfo->rolname, &loinfo->dacl);
    4116             :         }
    4117             :         else
    4118             :         {
    4119          72 :             dumpACL(fout, loinfo->dobj.dumpId, InvalidDumpId,
    4120             :                     "LARGE OBJECT", namebuf, NULL, NULL,
    4121          72 :                     NULL, loinfo->rolname, &loinfo->dacl);
    4122             :         }
    4123             :     }
    4124             : 
    4125         156 :     destroyPQExpBuffer(cquery);
    4126         156 : }
    4127             : 
    4128             : /*
    4129             :  * dumpLOs:
    4130             :  *  dump the data contents of the large objects in the given group
    4131             :  */
    4132             : static int
    4133         144 : dumpLOs(Archive *fout, const void *arg)
    4134             : {
    4135         144 :     const LoInfo *loinfo = (const LoInfo *) arg;
    4136         144 :     PGconn     *conn = GetConnection(fout);
    4137             :     char        buf[LOBBUFSIZE];
    4138             : 
    4139         144 :     pg_log_info("saving large objects \"%s\"", loinfo->dobj.name);
    4140             : 
    4141         304 :     for (int i = 0; i < loinfo->numlos; i++)
    4142             :     {
    4143         160 :         Oid         loOid = loinfo->looids[i];
    4144             :         int         loFd;
    4145             :         int         cnt;
    4146             : 
    4147             :         /* Open the LO */
    4148         160 :         loFd = lo_open(conn, loOid, INV_READ);
    4149         160 :         if (loFd == -1)
    4150           0 :             pg_fatal("could not open large object %u: %s",
    4151             :                      loOid, PQerrorMessage(conn));
    4152             : 
    4153         160 :         StartLO(fout, loOid);
    4154             : 
    4155             :         /* Now read it in chunks, sending data to archive */
    4156             :         do
    4157             :         {
    4158         244 :             cnt = lo_read(conn, loFd, buf, LOBBUFSIZE);
    4159         244 :             if (cnt < 0)
    4160           0 :                 pg_fatal("error reading large object %u: %s",
    4161             :                          loOid, PQerrorMessage(conn));
    4162             : 
    4163         244 :             WriteData(fout, buf, cnt);
    4164         244 :         } while (cnt > 0);
    4165             : 
    4166         160 :         lo_close(conn, loFd);
    4167             : 
    4168         160 :         EndLO(fout, loOid);
    4169             :     }
    4170             : 
    4171         144 :     return 1;
    4172             : }
    4173             : 
    4174             : /*
    4175             :  * getPolicies
    4176             :  *    get information about all RLS policies on dumpable tables.
    4177             :  */
    4178             : void
    4179         364 : getPolicies(Archive *fout, TableInfo tblinfo[], int numTables)
    4180             : {
    4181         364 :     DumpOptions *dopt = fout->dopt;
    4182             :     PQExpBuffer query;
    4183             :     PQExpBuffer tbloids;
    4184             :     PGresult   *res;
    4185             :     PolicyInfo *polinfo;
    4186             :     int         i_oid;
    4187             :     int         i_tableoid;
    4188             :     int         i_polrelid;
    4189             :     int         i_polname;
    4190             :     int         i_polcmd;
    4191             :     int         i_polpermissive;
    4192             :     int         i_polroles;
    4193             :     int         i_polqual;
    4194             :     int         i_polwithcheck;
    4195             :     int         i,
    4196             :                 j,
    4197             :                 ntups;
    4198             : 
    4199             :     /* No policies before 9.5 */
    4200         364 :     if (fout->remoteVersion < 90500)
    4201           0 :         return;
    4202             : 
    4203             :     /* Skip if --no-policies was specified */
    4204         364 :     if (dopt->no_policies)
    4205           2 :         return;
    4206             : 
    4207         362 :     query = createPQExpBuffer();
    4208         362 :     tbloids = createPQExpBuffer();
    4209             : 
    4210             :     /*
    4211             :      * Identify tables of interest, and check which ones have RLS enabled.
    4212             :      */
    4213         362 :     appendPQExpBufferChar(tbloids, '{');
    4214       96272 :     for (i = 0; i < numTables; i++)
    4215             :     {
    4216       95910 :         TableInfo  *tbinfo = &tblinfo[i];
    4217             : 
    4218             :         /* Ignore row security on tables not to be dumped */
    4219       95910 :         if (!(tbinfo->dobj.dump & DUMP_COMPONENT_POLICY))
    4220       81690 :             continue;
    4221             : 
    4222             :         /* It can't have RLS or policies if it's not a table */
    4223       14220 :         if (tbinfo->relkind != RELKIND_RELATION &&
    4224        4040 :             tbinfo->relkind != RELKIND_PARTITIONED_TABLE)
    4225        2844 :             continue;
    4226             : 
    4227             :         /* Add it to the list of table OIDs to be probed below */
    4228       11376 :         if (tbloids->len > 1) /* do we have more than the '{'? */
    4229       11142 :             appendPQExpBufferChar(tbloids, ',');
    4230       11376 :         appendPQExpBuffer(tbloids, "%u", tbinfo->dobj.catId.oid);
    4231             : 
    4232             :         /* Is RLS enabled?  (That's separate from whether it has policies) */
    4233       11376 :         if (tbinfo->rowsec)
    4234             :         {
    4235         112 :             tbinfo->dobj.components |= DUMP_COMPONENT_POLICY;
    4236             : 
    4237             :             /*
    4238             :              * We represent RLS being enabled on a table by creating a
    4239             :              * PolicyInfo object with null polname.
    4240             :              *
    4241             :              * Note: use tableoid 0 so that this object won't be mistaken for
    4242             :              * something that pg_depend entries apply to.
    4243             :              */
    4244         112 :             polinfo = pg_malloc(sizeof(PolicyInfo));
    4245         112 :             polinfo->dobj.objType = DO_POLICY;
    4246         112 :             polinfo->dobj.catId.tableoid = 0;
    4247         112 :             polinfo->dobj.catId.oid = tbinfo->dobj.catId.oid;
    4248         112 :             AssignDumpId(&polinfo->dobj);
    4249         112 :             polinfo->dobj.namespace = tbinfo->dobj.namespace;
    4250         112 :             polinfo->dobj.name = pg_strdup(tbinfo->dobj.name);
    4251         112 :             polinfo->poltable = tbinfo;
    4252         112 :             polinfo->polname = NULL;
    4253         112 :             polinfo->polcmd = '\0';
    4254         112 :             polinfo->polpermissive = 0;
    4255         112 :             polinfo->polroles = NULL;
    4256         112 :             polinfo->polqual = NULL;
    4257         112 :             polinfo->polwithcheck = NULL;
    4258             :         }
    4259             :     }
    4260         362 :     appendPQExpBufferChar(tbloids, '}');
    4261             : 
    4262             :     /*
    4263             :      * Now, read all RLS policies belonging to the tables of interest, and
    4264             :      * create PolicyInfo objects for them.  (Note that we must filter the
    4265             :      * results server-side not locally, because we dare not apply pg_get_expr
    4266             :      * to tables we don't have lock on.)
    4267             :      */
    4268         362 :     pg_log_info("reading row-level security policies");
    4269             : 
    4270         362 :     printfPQExpBuffer(query,
    4271             :                       "SELECT pol.oid, pol.tableoid, pol.polrelid, pol.polname, pol.polcmd, ");
    4272         362 :     if (fout->remoteVersion >= 100000)
    4273         362 :         appendPQExpBufferStr(query, "pol.polpermissive, ");
    4274             :     else
    4275           0 :         appendPQExpBufferStr(query, "'t' as polpermissive, ");
    4276         362 :     appendPQExpBuffer(query,
    4277             :                       "CASE WHEN pol.polroles = '{0}' THEN NULL ELSE "
    4278             :                       "   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, "
    4279             :                       "pg_catalog.pg_get_expr(pol.polqual, pol.polrelid) AS polqual, "
    4280             :                       "pg_catalog.pg_get_expr(pol.polwithcheck, pol.polrelid) AS polwithcheck "
    4281             :                       "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
    4282             :                       "JOIN pg_catalog.pg_policy pol ON (src.tbloid = pol.polrelid)",
    4283             :                       tbloids->data);
    4284             : 
    4285         362 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    4286             : 
    4287         362 :     ntups = PQntuples(res);
    4288         362 :     if (ntups > 0)
    4289             :     {
    4290          92 :         i_oid = PQfnumber(res, "oid");
    4291          92 :         i_tableoid = PQfnumber(res, "tableoid");
    4292          92 :         i_polrelid = PQfnumber(res, "polrelid");
    4293          92 :         i_polname = PQfnumber(res, "polname");
    4294          92 :         i_polcmd = PQfnumber(res, "polcmd");
    4295          92 :         i_polpermissive = PQfnumber(res, "polpermissive");
    4296          92 :         i_polroles = PQfnumber(res, "polroles");
    4297          92 :         i_polqual = PQfnumber(res, "polqual");
    4298          92 :         i_polwithcheck = PQfnumber(res, "polwithcheck");
    4299             : 
    4300          92 :         polinfo = pg_malloc(ntups * sizeof(PolicyInfo));
    4301             : 
    4302         674 :         for (j = 0; j < ntups; j++)
    4303             :         {
    4304         582 :             Oid         polrelid = atooid(PQgetvalue(res, j, i_polrelid));
    4305         582 :             TableInfo  *tbinfo = findTableByOid(polrelid);
    4306             : 
    4307         582 :             tbinfo->dobj.components |= DUMP_COMPONENT_POLICY;
    4308             : 
    4309         582 :             polinfo[j].dobj.objType = DO_POLICY;
    4310         582 :             polinfo[j].dobj.catId.tableoid =
    4311         582 :                 atooid(PQgetvalue(res, j, i_tableoid));
    4312         582 :             polinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
    4313         582 :             AssignDumpId(&polinfo[j].dobj);
    4314         582 :             polinfo[j].dobj.namespace = tbinfo->dobj.namespace;
    4315         582 :             polinfo[j].poltable = tbinfo;
    4316         582 :             polinfo[j].polname = pg_strdup(PQgetvalue(res, j, i_polname));
    4317         582 :             polinfo[j].dobj.name = pg_strdup(polinfo[j].polname);
    4318             : 
    4319         582 :             polinfo[j].polcmd = *(PQgetvalue(res, j, i_polcmd));
    4320         582 :             polinfo[j].polpermissive = *(PQgetvalue(res, j, i_polpermissive)) == 't';
    4321             : 
    4322         582 :             if (PQgetisnull(res, j, i_polroles))
    4323         254 :                 polinfo[j].polroles = NULL;
    4324             :             else
    4325         328 :                 polinfo[j].polroles = pg_strdup(PQgetvalue(res, j, i_polroles));
    4326             : 
    4327         582 :             if (PQgetisnull(res, j, i_polqual))
    4328          82 :                 polinfo[j].polqual = NULL;
    4329             :             else
    4330         500 :                 polinfo[j].polqual = pg_strdup(PQgetvalue(res, j, i_polqual));
    4331             : 
    4332         582 :             if (PQgetisnull(res, j, i_polwithcheck))
    4333         306 :                 polinfo[j].polwithcheck = NULL;
    4334             :             else
    4335         276 :                 polinfo[j].polwithcheck
    4336         276 :                     = pg_strdup(PQgetvalue(res, j, i_polwithcheck));
    4337             :         }
    4338             :     }
    4339             : 
    4340         362 :     PQclear(res);
    4341             : 
    4342         362 :     destroyPQExpBuffer(query);
    4343         362 :     destroyPQExpBuffer(tbloids);
    4344             : }
    4345             : 
    4346             : /*
    4347             :  * dumpPolicy
    4348             :  *    dump the definition of the given policy
    4349             :  */
    4350             : static void
    4351         694 : dumpPolicy(Archive *fout, const PolicyInfo *polinfo)
    4352             : {
    4353         694 :     DumpOptions *dopt = fout->dopt;
    4354         694 :     TableInfo  *tbinfo = polinfo->poltable;
    4355             :     PQExpBuffer query;
    4356             :     PQExpBuffer delqry;
    4357             :     PQExpBuffer polprefix;
    4358             :     char       *qtabname;
    4359             :     const char *cmd;
    4360             :     char       *tag;
    4361             : 
    4362             :     /* Do nothing if not dumping schema */
    4363         694 :     if (!dopt->dumpSchema)
    4364          98 :         return;
    4365             : 
    4366             :     /*
    4367             :      * If polname is NULL, then this record is just indicating that ROW LEVEL
    4368             :      * SECURITY is enabled for the table. Dump as ALTER TABLE <table> ENABLE
    4369             :      * ROW LEVEL SECURITY.
    4370             :      */
    4371         596 :     if (polinfo->polname == NULL)
    4372             :     {
    4373          98 :         query = createPQExpBuffer();
    4374             : 
    4375          98 :         appendPQExpBuffer(query, "ALTER TABLE %s ENABLE ROW LEVEL SECURITY;",
    4376          98 :                           fmtQualifiedDumpable(tbinfo));
    4377             : 
    4378             :         /*
    4379             :          * We must emit the ROW SECURITY object's dependency on its table
    4380             :          * explicitly, because it will not match anything in pg_depend (unlike
    4381             :          * the case for other PolicyInfo objects).
    4382             :          */
    4383          98 :         if (polinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
    4384          98 :             ArchiveEntry(fout, polinfo->dobj.catId, polinfo->dobj.dumpId,
    4385          98 :                          ARCHIVE_OPTS(.tag = polinfo->dobj.name,
    4386             :                                       .namespace = polinfo->dobj.namespace->dobj.name,
    4387             :                                       .owner = tbinfo->rolname,
    4388             :                                       .description = "ROW SECURITY",
    4389             :                                       .section = SECTION_POST_DATA,
    4390             :                                       .createStmt = query->data,
    4391             :                                       .deps = &(tbinfo->dobj.dumpId),
    4392             :                                       .nDeps = 1));
    4393             : 
    4394          98 :         destroyPQExpBuffer(query);
    4395          98 :         return;
    4396             :     }
    4397             : 
    4398         498 :     if (polinfo->polcmd == '*')
    4399         166 :         cmd = "";
    4400         332 :     else if (polinfo->polcmd == 'r')
    4401          88 :         cmd = " FOR SELECT";
    4402         244 :     else if (polinfo->polcmd == 'a')
    4403          68 :         cmd = " FOR INSERT";
    4404         176 :     else if (polinfo->polcmd == 'w')
    4405          88 :         cmd = " FOR UPDATE";
    4406          88 :     else if (polinfo->polcmd == 'd')
    4407          88 :         cmd = " FOR DELETE";
    4408             :     else
    4409           0 :         pg_fatal("unexpected policy command type: %c",
    4410             :                  polinfo->polcmd);
    4411             : 
    4412         498 :     query = createPQExpBuffer();
    4413         498 :     delqry = createPQExpBuffer();
    4414         498 :     polprefix = createPQExpBuffer();
    4415             : 
    4416         498 :     qtabname = pg_strdup(fmtId(tbinfo->dobj.name));
    4417             : 
    4418         498 :     appendPQExpBuffer(query, "CREATE POLICY %s", fmtId(polinfo->polname));
    4419             : 
    4420         498 :     appendPQExpBuffer(query, " ON %s%s%s", fmtQualifiedDumpable(tbinfo),
    4421         498 :                       !polinfo->polpermissive ? " AS RESTRICTIVE" : "", cmd);
    4422             : 
    4423         498 :     if (polinfo->polroles != NULL)
    4424         272 :         appendPQExpBuffer(query, " TO %s", polinfo->polroles);
    4425             : 
    4426         498 :     if (polinfo->polqual != NULL)
    4427         430 :         appendPQExpBuffer(query, " USING (%s)", polinfo->polqual);
    4428             : 
    4429         498 :     if (polinfo->polwithcheck != NULL)
    4430         234 :         appendPQExpBuffer(query, " WITH CHECK (%s)", polinfo->polwithcheck);
    4431             : 
    4432         498 :     appendPQExpBufferStr(query, ";\n");
    4433             : 
    4434         498 :     appendPQExpBuffer(delqry, "DROP POLICY %s", fmtId(polinfo->polname));
    4435         498 :     appendPQExpBuffer(delqry, " ON %s;\n", fmtQualifiedDumpable(tbinfo));
    4436             : 
    4437         498 :     appendPQExpBuffer(polprefix, "POLICY %s ON",
    4438         498 :                       fmtId(polinfo->polname));
    4439             : 
    4440         498 :     tag = psprintf("%s %s", tbinfo->dobj.name, polinfo->dobj.name);
    4441             : 
    4442         498 :     if (polinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
    4443         498 :         ArchiveEntry(fout, polinfo->dobj.catId, polinfo->dobj.dumpId,
    4444         498 :                      ARCHIVE_OPTS(.tag = tag,
    4445             :                                   .namespace = polinfo->dobj.namespace->dobj.name,
    4446             :                                   .owner = tbinfo->rolname,
    4447             :                                   .description = "POLICY",
    4448             :                                   .section = SECTION_POST_DATA,
    4449             :                                   .createStmt = query->data,
    4450             :                                   .dropStmt = delqry->data));
    4451             : 
    4452         498 :     if (polinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
    4453           0 :         dumpComment(fout, polprefix->data, qtabname,
    4454           0 :                     tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
    4455           0 :                     polinfo->dobj.catId, 0, polinfo->dobj.dumpId);
    4456             : 
    4457         498 :     free(tag);
    4458         498 :     destroyPQExpBuffer(query);
    4459         498 :     destroyPQExpBuffer(delqry);
    4460         498 :     destroyPQExpBuffer(polprefix);
    4461         498 :     free(qtabname);
    4462             : }
    4463             : 
    4464             : /*
    4465             :  * getPublications
    4466             :  *    get information about publications
    4467             :  */
    4468             : void
    4469         364 : getPublications(Archive *fout)
    4470             : {
    4471         364 :     DumpOptions *dopt = fout->dopt;
    4472             :     PQExpBuffer query;
    4473             :     PGresult   *res;
    4474             :     PublicationInfo *pubinfo;
    4475             :     int         i_tableoid;
    4476             :     int         i_oid;
    4477             :     int         i_pubname;
    4478             :     int         i_pubowner;
    4479             :     int         i_puballtables;
    4480             :     int         i_pubinsert;
    4481             :     int         i_pubupdate;
    4482             :     int         i_pubdelete;
    4483             :     int         i_pubtruncate;
    4484             :     int         i_pubviaroot;
    4485             :     int         i_pubgencols;
    4486             :     int         i,
    4487             :                 ntups;
    4488             : 
    4489         364 :     if (dopt->no_publications || fout->remoteVersion < 100000)
    4490           0 :         return;
    4491             : 
    4492         364 :     query = createPQExpBuffer();
    4493             : 
    4494             :     /* Get the publications. */
    4495         364 :     appendPQExpBufferStr(query, "SELECT p.tableoid, p.oid, p.pubname, "
    4496             :                          "p.pubowner, p.puballtables, p.pubinsert, "
    4497             :                          "p.pubupdate, p.pubdelete, ");
    4498             : 
    4499         364 :     if (fout->remoteVersion >= 110000)
    4500         364 :         appendPQExpBufferStr(query, "p.pubtruncate, ");
    4501             :     else
    4502           0 :         appendPQExpBufferStr(query, "false AS pubtruncate, ");
    4503             : 
    4504         364 :     if (fout->remoteVersion >= 130000)
    4505         364 :         appendPQExpBufferStr(query, "p.pubviaroot, ");
    4506             :     else
    4507           0 :         appendPQExpBufferStr(query, "false AS pubviaroot, ");
    4508             : 
    4509         364 :     if (fout->remoteVersion >= 180000)
    4510         364 :         appendPQExpBufferStr(query, "p.pubgencols ");
    4511             :     else
    4512           0 :         appendPQExpBuffer(query, "'%c' AS pubgencols ", PUBLISH_GENCOLS_NONE);
    4513             : 
    4514         364 :     appendPQExpBufferStr(query, "FROM pg_publication p");
    4515             : 
    4516         364 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    4517             : 
    4518         364 :     ntups = PQntuples(res);
    4519             : 
    4520         364 :     if (ntups == 0)
    4521         252 :         goto cleanup;
    4522             : 
    4523         112 :     i_tableoid = PQfnumber(res, "tableoid");
    4524         112 :     i_oid = PQfnumber(res, "oid");
    4525         112 :     i_pubname = PQfnumber(res, "pubname");
    4526         112 :     i_pubowner = PQfnumber(res, "pubowner");
    4527         112 :     i_puballtables = PQfnumber(res, "puballtables");
    4528         112 :     i_pubinsert = PQfnumber(res, "pubinsert");
    4529         112 :     i_pubupdate = PQfnumber(res, "pubupdate");
    4530         112 :     i_pubdelete = PQfnumber(res, "pubdelete");
    4531         112 :     i_pubtruncate = PQfnumber(res, "pubtruncate");
    4532         112 :     i_pubviaroot = PQfnumber(res, "pubviaroot");
    4533         112 :     i_pubgencols = PQfnumber(res, "pubgencols");
    4534             : 
    4535         112 :     pubinfo = pg_malloc(ntups * sizeof(PublicationInfo));
    4536             : 
    4537         664 :     for (i = 0; i < ntups; i++)
    4538             :     {
    4539         552 :         pubinfo[i].dobj.objType = DO_PUBLICATION;
    4540         552 :         pubinfo[i].dobj.catId.tableoid =
    4541         552 :             atooid(PQgetvalue(res, i, i_tableoid));
    4542         552 :         pubinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    4543         552 :         AssignDumpId(&pubinfo[i].dobj);
    4544         552 :         pubinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_pubname));
    4545         552 :         pubinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_pubowner));
    4546         552 :         pubinfo[i].puballtables =
    4547         552 :             (strcmp(PQgetvalue(res, i, i_puballtables), "t") == 0);
    4548         552 :         pubinfo[i].pubinsert =
    4549         552 :             (strcmp(PQgetvalue(res, i, i_pubinsert), "t") == 0);
    4550         552 :         pubinfo[i].pubupdate =
    4551         552 :             (strcmp(PQgetvalue(res, i, i_pubupdate), "t") == 0);
    4552         552 :         pubinfo[i].pubdelete =
    4553         552 :             (strcmp(PQgetvalue(res, i, i_pubdelete), "t") == 0);
    4554         552 :         pubinfo[i].pubtruncate =
    4555         552 :             (strcmp(PQgetvalue(res, i, i_pubtruncate), "t") == 0);
    4556         552 :         pubinfo[i].pubviaroot =
    4557         552 :             (strcmp(PQgetvalue(res, i, i_pubviaroot), "t") == 0);
    4558         552 :         pubinfo[i].pubgencols_type =
    4559         552 :             *(PQgetvalue(res, i, i_pubgencols));
    4560             : 
    4561             :         /* Decide whether we want to dump it */
    4562         552 :         selectDumpableObject(&(pubinfo[i].dobj), fout);
    4563             :     }
    4564             : 
    4565         112 : cleanup:
    4566         364 :     PQclear(res);
    4567             : 
    4568         364 :     destroyPQExpBuffer(query);
    4569             : }
    4570             : 
    4571             : /*
    4572             :  * dumpPublication
    4573             :  *    dump the definition of the given publication
    4574             :  */
    4575             : static void
    4576         452 : dumpPublication(Archive *fout, const PublicationInfo *pubinfo)
    4577             : {
    4578         452 :     DumpOptions *dopt = fout->dopt;
    4579             :     PQExpBuffer delq;
    4580             :     PQExpBuffer query;
    4581             :     char       *qpubname;
    4582         452 :     bool        first = true;
    4583             : 
    4584             :     /* Do nothing if not dumping schema */
    4585         452 :     if (!dopt->dumpSchema)
    4586          60 :         return;
    4587             : 
    4588         392 :     delq = createPQExpBuffer();
    4589         392 :     query = createPQExpBuffer();
    4590             : 
    4591         392 :     qpubname = pg_strdup(fmtId(pubinfo->dobj.name));
    4592             : 
    4593         392 :     appendPQExpBuffer(delq, "DROP PUBLICATION %s;\n",
    4594             :                       qpubname);
    4595             : 
    4596         392 :     appendPQExpBuffer(query, "CREATE PUBLICATION %s",
    4597             :                       qpubname);
    4598             : 
    4599         392 :     if (pubinfo->puballtables)
    4600          70 :         appendPQExpBufferStr(query, " FOR ALL TABLES");
    4601             : 
    4602         392 :     appendPQExpBufferStr(query, " WITH (publish = '");
    4603         392 :     if (pubinfo->pubinsert)
    4604             :     {
    4605         324 :         appendPQExpBufferStr(query, "insert");
    4606         324 :         first = false;
    4607             :     }
    4608             : 
    4609         392 :     if (pubinfo->pubupdate)
    4610             :     {
    4611         324 :         if (!first)
    4612         324 :             appendPQExpBufferStr(query, ", ");
    4613             : 
    4614         324 :         appendPQExpBufferStr(query, "update");
    4615         324 :         first = false;
    4616             :     }
    4617             : 
    4618         392 :     if (pubinfo->pubdelete)
    4619             :     {
    4620         324 :         if (!first)
    4621         324 :             appendPQExpBufferStr(query, ", ");
    4622             : 
    4623         324 :         appendPQExpBufferStr(query, "delete");
    4624         324 :         first = false;
    4625             :     }
    4626             : 
    4627         392 :     if (pubinfo->pubtruncate)
    4628             :     {
    4629         324 :         if (!first)
    4630         324 :             appendPQExpBufferStr(query, ", ");
    4631             : 
    4632         324 :         appendPQExpBufferStr(query, "truncate");
    4633         324 :         first = false;
    4634             :     }
    4635             : 
    4636         392 :     appendPQExpBufferChar(query, '\'');
    4637             : 
    4638         392 :     if (pubinfo->pubviaroot)
    4639          10 :         appendPQExpBufferStr(query, ", publish_via_partition_root = true");
    4640             : 
    4641         392 :     if (pubinfo->pubgencols_type == PUBLISH_GENCOLS_STORED)
    4642          68 :         appendPQExpBufferStr(query, ", publish_generated_columns = stored");
    4643             : 
    4644         392 :     appendPQExpBufferStr(query, ");\n");
    4645             : 
    4646         392 :     if (pubinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
    4647         392 :         ArchiveEntry(fout, pubinfo->dobj.catId, pubinfo->dobj.dumpId,
    4648         392 :                      ARCHIVE_OPTS(.tag = pubinfo->dobj.name,
    4649             :                                   .owner = pubinfo->rolname,
    4650             :                                   .description = "PUBLICATION",
    4651             :                                   .section = SECTION_POST_DATA,
    4652             :                                   .createStmt = query->data,
    4653             :                                   .dropStmt = delq->data));
    4654             : 
    4655         392 :     if (pubinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
    4656          68 :         dumpComment(fout, "PUBLICATION", qpubname,
    4657          68 :                     NULL, pubinfo->rolname,
    4658          68 :                     pubinfo->dobj.catId, 0, pubinfo->dobj.dumpId);
    4659             : 
    4660         392 :     if (pubinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
    4661           0 :         dumpSecLabel(fout, "PUBLICATION", qpubname,
    4662           0 :                      NULL, pubinfo->rolname,
    4663           0 :                      pubinfo->dobj.catId, 0, pubinfo->dobj.dumpId);
    4664             : 
    4665         392 :     destroyPQExpBuffer(delq);
    4666         392 :     destroyPQExpBuffer(query);
    4667         392 :     free(qpubname);
    4668             : }
    4669             : 
    4670             : /*
    4671             :  * getPublicationNamespaces
    4672             :  *    get information about publication membership for dumpable schemas.
    4673             :  */
    4674             : void
    4675         364 : getPublicationNamespaces(Archive *fout)
    4676             : {
    4677             :     PQExpBuffer query;
    4678             :     PGresult   *res;
    4679             :     PublicationSchemaInfo *pubsinfo;
    4680         364 :     DumpOptions *dopt = fout->dopt;
    4681             :     int         i_tableoid;
    4682             :     int         i_oid;
    4683             :     int         i_pnpubid;
    4684             :     int         i_pnnspid;
    4685             :     int         i,
    4686             :                 j,
    4687             :                 ntups;
    4688             : 
    4689         364 :     if (dopt->no_publications || fout->remoteVersion < 150000)
    4690           0 :         return;
    4691             : 
    4692         364 :     query = createPQExpBuffer();
    4693             : 
    4694             :     /* Collect all publication membership info. */
    4695         364 :     appendPQExpBufferStr(query,
    4696             :                          "SELECT tableoid, oid, pnpubid, pnnspid "
    4697             :                          "FROM pg_catalog.pg_publication_namespace");
    4698         364 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    4699             : 
    4700         364 :     ntups = PQntuples(res);
    4701             : 
    4702         364 :     i_tableoid = PQfnumber(res, "tableoid");
    4703         364 :     i_oid = PQfnumber(res, "oid");
    4704         364 :     i_pnpubid = PQfnumber(res, "pnpubid");
    4705         364 :     i_pnnspid = PQfnumber(res, "pnnspid");
    4706             : 
    4707             :     /* this allocation may be more than we need */
    4708         364 :     pubsinfo = pg_malloc(ntups * sizeof(PublicationSchemaInfo));
    4709         364 :     j = 0;
    4710             : 
    4711         626 :     for (i = 0; i < ntups; i++)
    4712             :     {
    4713         262 :         Oid         pnpubid = atooid(PQgetvalue(res, i, i_pnpubid));
    4714         262 :         Oid         pnnspid = atooid(PQgetvalue(res, i, i_pnnspid));
    4715             :         PublicationInfo *pubinfo;
    4716             :         NamespaceInfo *nspinfo;
    4717             : 
    4718             :         /*
    4719             :          * Ignore any entries for which we aren't interested in either the
    4720             :          * publication or the rel.
    4721             :          */
    4722         262 :         pubinfo = findPublicationByOid(pnpubid);
    4723         262 :         if (pubinfo == NULL)
    4724           0 :             continue;
    4725         262 :         nspinfo = findNamespaceByOid(pnnspid);
    4726         262 :         if (nspinfo == NULL)
    4727           0 :             continue;
    4728             : 
    4729             :         /* OK, make a DumpableObject for this relationship */
    4730         262 :         pubsinfo[j].dobj.objType = DO_PUBLICATION_TABLE_IN_SCHEMA;
    4731         262 :         pubsinfo[j].dobj.catId.tableoid =
    4732         262 :             atooid(PQgetvalue(res, i, i_tableoid));
    4733         262 :         pubsinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    4734         262 :         AssignDumpId(&pubsinfo[j].dobj);
    4735         262 :         pubsinfo[j].dobj.namespace = nspinfo->dobj.namespace;
    4736         262 :         pubsinfo[j].dobj.name = nspinfo->dobj.name;
    4737         262 :         pubsinfo[j].publication = pubinfo;
    4738         262 :         pubsinfo[j].pubschema = nspinfo;
    4739             : 
    4740             :         /* Decide whether we want to dump it */
    4741         262 :         selectDumpablePublicationObject(&(pubsinfo[j].dobj), fout);
    4742             : 
    4743         262 :         j++;
    4744             :     }
    4745             : 
    4746         364 :     PQclear(res);
    4747         364 :     destroyPQExpBuffer(query);
    4748             : }
    4749             : 
    4750             : /*
    4751             :  * getPublicationTables
    4752             :  *    get information about publication membership for dumpable tables.
    4753             :  */
    4754             : void
    4755         364 : getPublicationTables(Archive *fout, TableInfo tblinfo[], int numTables)
    4756             : {
    4757             :     PQExpBuffer query;
    4758             :     PGresult   *res;
    4759             :     PublicationRelInfo *pubrinfo;
    4760         364 :     DumpOptions *dopt = fout->dopt;
    4761             :     int         i_tableoid;
    4762             :     int         i_oid;
    4763             :     int         i_prpubid;
    4764             :     int         i_prrelid;
    4765             :     int         i_prrelqual;
    4766             :     int         i_prattrs;
    4767             :     int         i,
    4768             :                 j,
    4769             :                 ntups;
    4770             : 
    4771         364 :     if (dopt->no_publications || fout->remoteVersion < 100000)
    4772           0 :         return;
    4773             : 
    4774         364 :     query = createPQExpBuffer();
    4775             : 
    4776             :     /* Collect all publication membership info. */
    4777         364 :     if (fout->remoteVersion >= 150000)
    4778         364 :         appendPQExpBufferStr(query,
    4779             :                              "SELECT tableoid, oid, prpubid, prrelid, "
    4780             :                              "pg_catalog.pg_get_expr(prqual, prrelid) AS prrelqual, "
    4781             :                              "(CASE\n"
    4782             :                              "  WHEN pr.prattrs IS NOT NULL THEN\n"
    4783             :                              "    (SELECT array_agg(attname)\n"
    4784             :                              "       FROM\n"
    4785             :                              "         pg_catalog.generate_series(0, pg_catalog.array_upper(pr.prattrs::pg_catalog.int2[], 1)) s,\n"
    4786             :                              "         pg_catalog.pg_attribute\n"
    4787             :                              "      WHERE attrelid = pr.prrelid AND attnum = prattrs[s])\n"
    4788             :                              "  ELSE NULL END) prattrs "
    4789             :                              "FROM pg_catalog.pg_publication_rel pr");
    4790             :     else
    4791           0 :         appendPQExpBufferStr(query,
    4792             :                              "SELECT tableoid, oid, prpubid, prrelid, "
    4793             :                              "NULL AS prrelqual, NULL AS prattrs "
    4794             :                              "FROM pg_catalog.pg_publication_rel");
    4795         364 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    4796             : 
    4797         364 :     ntups = PQntuples(res);
    4798             : 
    4799         364 :     i_tableoid = PQfnumber(res, "tableoid");
    4800         364 :     i_oid = PQfnumber(res, "oid");
    4801         364 :     i_prpubid = PQfnumber(res, "prpubid");
    4802         364 :     i_prrelid = PQfnumber(res, "prrelid");
    4803         364 :     i_prrelqual = PQfnumber(res, "prrelqual");
    4804         364 :     i_prattrs = PQfnumber(res, "prattrs");
    4805             : 
    4806             :     /* this allocation may be more than we need */
    4807         364 :     pubrinfo = pg_malloc(ntups * sizeof(PublicationRelInfo));
    4808         364 :     j = 0;
    4809             : 
    4810        1106 :     for (i = 0; i < ntups; i++)
    4811             :     {
    4812         742 :         Oid         prpubid = atooid(PQgetvalue(res, i, i_prpubid));
    4813         742 :         Oid         prrelid = atooid(PQgetvalue(res, i, i_prrelid));
    4814             :         PublicationInfo *pubinfo;
    4815             :         TableInfo  *tbinfo;
    4816             : 
    4817             :         /*
    4818             :          * Ignore any entries for which we aren't interested in either the
    4819             :          * publication or the rel.
    4820             :          */
    4821         742 :         pubinfo = findPublicationByOid(prpubid);
    4822         742 :         if (pubinfo == NULL)
    4823           0 :             continue;
    4824         742 :         tbinfo = findTableByOid(prrelid);
    4825         742 :         if (tbinfo == NULL)
    4826           0 :             continue;
    4827             : 
    4828             :         /* OK, make a DumpableObject for this relationship */
    4829         742 :         pubrinfo[j].dobj.objType = DO_PUBLICATION_REL;
    4830         742 :         pubrinfo[j].dobj.catId.tableoid =
    4831         742 :             atooid(PQgetvalue(res, i, i_tableoid));
    4832         742 :         pubrinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    4833         742 :         AssignDumpId(&pubrinfo[j].dobj);
    4834         742 :         pubrinfo[j].dobj.namespace = tbinfo->dobj.namespace;
    4835         742 :         pubrinfo[j].dobj.name = tbinfo->dobj.name;
    4836         742 :         pubrinfo[j].publication = pubinfo;
    4837         742 :         pubrinfo[j].pubtable = tbinfo;
    4838         742 :         if (PQgetisnull(res, i, i_prrelqual))
    4839         412 :             pubrinfo[j].pubrelqual = NULL;
    4840             :         else
    4841         330 :             pubrinfo[j].pubrelqual = pg_strdup(PQgetvalue(res, i, i_prrelqual));
    4842             : 
    4843         742 :         if (!PQgetisnull(res, i, i_prattrs))
    4844             :         {
    4845             :             char      **attnames;
    4846             :             int         nattnames;
    4847             :             PQExpBuffer attribs;
    4848             : 
    4849         234 :             if (!parsePGArray(PQgetvalue(res, i, i_prattrs),
    4850             :                               &attnames, &nattnames))
    4851           0 :                 pg_fatal("could not parse %s array", "prattrs");
    4852         234 :             attribs = createPQExpBuffer();
    4853         674 :             for (int k = 0; k < nattnames; k++)
    4854             :             {
    4855         440 :                 if (k > 0)
    4856         206 :                     appendPQExpBufferStr(attribs, ", ");
    4857             : 
    4858         440 :                 appendPQExpBufferStr(attribs, fmtId(attnames[k]));
    4859             :             }
    4860         234 :             pubrinfo[j].pubrattrs = attribs->data;
    4861         234 :             free(attribs);      /* but not attribs->data */
    4862         234 :             free(attnames);
    4863             :         }
    4864             :         else
    4865         508 :             pubrinfo[j].pubrattrs = NULL;
    4866             : 
    4867             :         /* Decide whether we want to dump it */
    4868         742 :         selectDumpablePublicationObject(&(pubrinfo[j].dobj), fout);
    4869             : 
    4870         742 :         j++;
    4871             :     }
    4872             : 
    4873         364 :     PQclear(res);
    4874         364 :     destroyPQExpBuffer(query);
    4875             : }
    4876             : 
    4877             : /*
    4878             :  * dumpPublicationNamespace
    4879             :  *    dump the definition of the given publication schema mapping.
    4880             :  */
    4881             : static void
    4882         210 : dumpPublicationNamespace(Archive *fout, const PublicationSchemaInfo *pubsinfo)
    4883             : {
    4884         210 :     DumpOptions *dopt = fout->dopt;
    4885         210 :     NamespaceInfo *schemainfo = pubsinfo->pubschema;
    4886         210 :     PublicationInfo *pubinfo = pubsinfo->publication;
    4887             :     PQExpBuffer query;
    4888             :     char       *tag;
    4889             : 
    4890             :     /* Do nothing if not dumping schema */
    4891         210 :     if (!dopt->dumpSchema)
    4892          24 :         return;
    4893             : 
    4894         186 :     tag = psprintf("%s %s", pubinfo->dobj.name, schemainfo->dobj.name);
    4895             : 
    4896         186 :     query = createPQExpBuffer();
    4897             : 
    4898         186 :     appendPQExpBuffer(query, "ALTER PUBLICATION %s ", fmtId(pubinfo->dobj.name));
    4899         186 :     appendPQExpBuffer(query, "ADD TABLES IN SCHEMA %s;\n", fmtId(schemainfo->dobj.name));
    4900             : 
    4901             :     /*
    4902             :      * There is no point in creating drop query as the drop is done by schema
    4903             :      * drop.
    4904             :      */
    4905         186 :     if (pubsinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
    4906         186 :         ArchiveEntry(fout, pubsinfo->dobj.catId, pubsinfo->dobj.dumpId,
    4907         186 :                      ARCHIVE_OPTS(.tag = tag,
    4908             :                                   .namespace = schemainfo->dobj.name,
    4909             :                                   .owner = pubinfo->rolname,
    4910             :                                   .description = "PUBLICATION TABLES IN SCHEMA",
    4911             :                                   .section = SECTION_POST_DATA,
    4912             :                                   .createStmt = query->data));
    4913             : 
    4914             :     /* These objects can't currently have comments or seclabels */
    4915             : 
    4916         186 :     free(tag);
    4917         186 :     destroyPQExpBuffer(query);
    4918             : }
    4919             : 
    4920             : /*
    4921             :  * dumpPublicationTable
    4922             :  *    dump the definition of the given publication table mapping
    4923             :  */
    4924             : static void
    4925         610 : dumpPublicationTable(Archive *fout, const PublicationRelInfo *pubrinfo)
    4926             : {
    4927         610 :     DumpOptions *dopt = fout->dopt;
    4928         610 :     PublicationInfo *pubinfo = pubrinfo->publication;
    4929         610 :     TableInfo  *tbinfo = pubrinfo->pubtable;
    4930             :     PQExpBuffer query;
    4931             :     char       *tag;
    4932             : 
    4933             :     /* Do nothing if not dumping schema */
    4934         610 :     if (!dopt->dumpSchema)
    4935          84 :         return;
    4936             : 
    4937         526 :     tag = psprintf("%s %s", pubinfo->dobj.name, tbinfo->dobj.name);
    4938             : 
    4939         526 :     query = createPQExpBuffer();
    4940             : 
    4941         526 :     appendPQExpBuffer(query, "ALTER PUBLICATION %s ADD TABLE ONLY",
    4942         526 :                       fmtId(pubinfo->dobj.name));
    4943         526 :     appendPQExpBuffer(query, " %s",
    4944         526 :                       fmtQualifiedDumpable(tbinfo));
    4945             : 
    4946         526 :     if (pubrinfo->pubrattrs)
    4947         166 :         appendPQExpBuffer(query, " (%s)", pubrinfo->pubrattrs);
    4948             : 
    4949         526 :     if (pubrinfo->pubrelqual)
    4950             :     {
    4951             :         /*
    4952             :          * It's necessary to add parentheses around the expression because
    4953             :          * pg_get_expr won't supply the parentheses for things like WHERE
    4954             :          * TRUE.
    4955             :          */
    4956         234 :         appendPQExpBuffer(query, " WHERE (%s)", pubrinfo->pubrelqual);
    4957             :     }
    4958         526 :     appendPQExpBufferStr(query, ";\n");
    4959             : 
    4960             :     /*
    4961             :      * There is no point in creating a drop query as the drop is done by table
    4962             :      * drop.  (If you think to change this, see also _printTocEntry().)
    4963             :      * Although this object doesn't really have ownership as such, set the
    4964             :      * owner field anyway to ensure that the command is run by the correct
    4965             :      * role at restore time.
    4966             :      */
    4967         526 :     if (pubrinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
    4968         526 :         ArchiveEntry(fout, pubrinfo->dobj.catId, pubrinfo->dobj.dumpId,
    4969         526 :                      ARCHIVE_OPTS(.tag = tag,
    4970             :                                   .namespace = tbinfo->dobj.namespace->dobj.name,
    4971             :                                   .owner = pubinfo->rolname,
    4972             :                                   .description = "PUBLICATION TABLE",
    4973             :                                   .section = SECTION_POST_DATA,
    4974             :                                   .createStmt = query->data));
    4975             : 
    4976             :     /* These objects can't currently have comments or seclabels */
    4977             : 
    4978         526 :     free(tag);
    4979         526 :     destroyPQExpBuffer(query);
    4980             : }
    4981             : 
    4982             : /*
    4983             :  * Is the currently connected user a superuser?
    4984             :  */
    4985             : static bool
    4986         364 : is_superuser(Archive *fout)
    4987             : {
    4988         364 :     ArchiveHandle *AH = (ArchiveHandle *) fout;
    4989             :     const char *val;
    4990             : 
    4991         364 :     val = PQparameterStatus(AH->connection, "is_superuser");
    4992             : 
    4993         364 :     if (val && strcmp(val, "on") == 0)
    4994         358 :         return true;
    4995             : 
    4996           6 :     return false;
    4997             : }
    4998             : 
    4999             : /*
    5000             :  * Set the given value to restrict_nonsystem_relation_kind value. Since
    5001             :  * restrict_nonsystem_relation_kind is introduced in minor version releases,
    5002             :  * the setting query is effective only where available.
    5003             :  */
    5004             : static void
    5005         432 : set_restrict_relation_kind(Archive *AH, const char *value)
    5006             : {
    5007         432 :     PQExpBuffer query = createPQExpBuffer();
    5008             :     PGresult   *res;
    5009             : 
    5010         432 :     appendPQExpBuffer(query,
    5011             :                       "SELECT set_config(name, '%s', false) "
    5012             :                       "FROM pg_settings "
    5013             :                       "WHERE name = 'restrict_nonsystem_relation_kind'",
    5014             :                       value);
    5015         432 :     res = ExecuteSqlQuery(AH, query->data, PGRES_TUPLES_OK);
    5016             : 
    5017         432 :     PQclear(res);
    5018         432 :     destroyPQExpBuffer(query);
    5019         432 : }
    5020             : 
    5021             : /*
    5022             :  * getSubscriptions
    5023             :  *    get information about subscriptions
    5024             :  */
    5025             : void
    5026         364 : getSubscriptions(Archive *fout)
    5027             : {
    5028         364 :     DumpOptions *dopt = fout->dopt;
    5029             :     PQExpBuffer query;
    5030             :     PGresult   *res;
    5031             :     SubscriptionInfo *subinfo;
    5032             :     int         i_tableoid;
    5033             :     int         i_oid;
    5034             :     int         i_subname;
    5035             :     int         i_subowner;
    5036             :     int         i_subbinary;
    5037             :     int         i_substream;
    5038             :     int         i_subtwophasestate;
    5039             :     int         i_subdisableonerr;
    5040             :     int         i_subpasswordrequired;
    5041             :     int         i_subrunasowner;
    5042             :     int         i_subconninfo;
    5043             :     int         i_subslotname;
    5044             :     int         i_subsynccommit;
    5045             :     int         i_subpublications;
    5046             :     int         i_suborigin;
    5047             :     int         i_suboriginremotelsn;
    5048             :     int         i_subenabled;
    5049             :     int         i_subfailover;
    5050             :     int         i_subretaindeadtuples;
    5051             :     int         i,
    5052             :                 ntups;
    5053             : 
    5054         364 :     if (dopt->no_subscriptions || fout->remoteVersion < 100000)
    5055           0 :         return;
    5056             : 
    5057         364 :     if (!is_superuser(fout))
    5058             :     {
    5059             :         int         n;
    5060             : 
    5061           6 :         res = ExecuteSqlQuery(fout,
    5062             :                               "SELECT count(*) FROM pg_subscription "
    5063             :                               "WHERE subdbid = (SELECT oid FROM pg_database"
    5064             :                               "                 WHERE datname = current_database())",
    5065             :                               PGRES_TUPLES_OK);
    5066           6 :         n = atoi(PQgetvalue(res, 0, 0));
    5067           6 :         if (n > 0)
    5068           4 :             pg_log_warning("subscriptions not dumped because current user is not a superuser");
    5069           6 :         PQclear(res);
    5070           6 :         return;
    5071             :     }
    5072             : 
    5073         358 :     query = createPQExpBuffer();
    5074             : 
    5075             :     /* Get the subscriptions in current database. */
    5076         358 :     appendPQExpBufferStr(query,
    5077             :                          "SELECT s.tableoid, s.oid, s.subname,\n"
    5078             :                          " s.subowner,\n"
    5079             :                          " s.subconninfo, s.subslotname, s.subsynccommit,\n"
    5080             :                          " s.subpublications,\n");
    5081             : 
    5082         358 :     if (fout->remoteVersion >= 140000)
    5083         358 :         appendPQExpBufferStr(query, " s.subbinary,\n");
    5084             :     else
    5085           0 :         appendPQExpBufferStr(query, " false AS subbinary,\n");
    5086             : 
    5087         358 :     if (fout->remoteVersion >= 140000)
    5088         358 :         appendPQExpBufferStr(query, " s.substream,\n");
    5089             :     else
    5090           0 :         appendPQExpBufferStr(query, " 'f' AS substream,\n");
    5091             : 
    5092         358 :     if (fout->remoteVersion >= 150000)
    5093         358 :         appendPQExpBufferStr(query,
    5094             :                              " s.subtwophasestate,\n"
    5095             :                              " s.subdisableonerr,\n");
    5096             :     else
    5097           0 :         appendPQExpBuffer(query,
    5098             :                           " '%c' AS subtwophasestate,\n"
    5099             :                           " false AS subdisableonerr,\n",
    5100             :                           LOGICALREP_TWOPHASE_STATE_DISABLED);
    5101             : 
    5102         358 :     if (fout->remoteVersion >= 160000)
    5103         358 :         appendPQExpBufferStr(query,
    5104             :                              " s.subpasswordrequired,\n"
    5105             :                              " s.subrunasowner,\n"
    5106             :                              " s.suborigin,\n");
    5107             :     else
    5108           0 :         appendPQExpBuffer(query,
    5109             :                           " 't' AS subpasswordrequired,\n"
    5110             :                           " 't' AS subrunasowner,\n"
    5111             :                           " '%s' AS suborigin,\n",
    5112             :                           LOGICALREP_ORIGIN_ANY);
    5113             : 
    5114         358 :     if (dopt->binary_upgrade && fout->remoteVersion >= 170000)
    5115          72 :         appendPQExpBufferStr(query, " o.remote_lsn AS suboriginremotelsn,\n"
    5116             :                              " s.subenabled,\n");
    5117             :     else
    5118         286 :         appendPQExpBufferStr(query, " NULL AS suboriginremotelsn,\n"
    5119             :                              " false AS subenabled,\n");
    5120             : 
    5121         358 :     if (fout->remoteVersion >= 170000)
    5122         358 :         appendPQExpBufferStr(query,
    5123             :                              " s.subfailover,\n");
    5124             :     else
    5125           0 :         appendPQExpBufferStr(query,
    5126             :                              " false AS subfailover,\n");
    5127             : 
    5128         358 :     if (fout->remoteVersion >= 190000)
    5129         358 :         appendPQExpBufferStr(query,
    5130             :                              " s.subretaindeadtuples\n");
    5131             :     else
    5132           0 :         appendPQExpBufferStr(query,
    5133             :                              " false AS subretaindeadtuples\n");
    5134             : 
    5135         358 :     appendPQExpBufferStr(query,
    5136             :                          "FROM pg_subscription s\n");
    5137             : 
    5138         358 :     if (dopt->binary_upgrade && fout->remoteVersion >= 170000)
    5139          72 :         appendPQExpBufferStr(query,
    5140             :                              "LEFT JOIN pg_catalog.pg_replication_origin_status o \n"
    5141             :                              "    ON o.external_id = 'pg_' || s.oid::text \n");
    5142             : 
    5143         358 :     appendPQExpBufferStr(query,
    5144             :                          "WHERE s.subdbid = (SELECT oid FROM pg_database\n"
    5145             :                          "                   WHERE datname = current_database())");
    5146             : 
    5147         358 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    5148             : 
    5149         358 :     ntups = PQntuples(res);
    5150             : 
    5151             :     /*
    5152             :      * Get subscription fields. We don't include subskiplsn in the dump as
    5153             :      * after restoring the dump this value may no longer be relevant.
    5154             :      */
    5155         358 :     i_tableoid = PQfnumber(res, "tableoid");
    5156         358 :     i_oid = PQfnumber(res, "oid");
    5157         358 :     i_subname = PQfnumber(res, "subname");
    5158         358 :     i_subowner = PQfnumber(res, "subowner");
    5159         358 :     i_subenabled = PQfnumber(res, "subenabled");
    5160         358 :     i_subbinary = PQfnumber(res, "subbinary");
    5161         358 :     i_substream = PQfnumber(res, "substream");
    5162         358 :     i_subtwophasestate = PQfnumber(res, "subtwophasestate");
    5163         358 :     i_subdisableonerr = PQfnumber(res, "subdisableonerr");
    5164         358 :     i_subpasswordrequired = PQfnumber(res, "subpasswordrequired");
    5165         358 :     i_subrunasowner = PQfnumber(res, "subrunasowner");
    5166         358 :     i_subfailover = PQfnumber(res, "subfailover");
    5167         358 :     i_subretaindeadtuples = PQfnumber(res, "subretaindeadtuples");
    5168         358 :     i_subconninfo = PQfnumber(res, "subconninfo");
    5169         358 :     i_subslotname = PQfnumber(res, "subslotname");
    5170         358 :     i_subsynccommit = PQfnumber(res, "subsynccommit");
    5171         358 :     i_subpublications = PQfnumber(res, "subpublications");
    5172         358 :     i_suborigin = PQfnumber(res, "suborigin");
    5173         358 :     i_suboriginremotelsn = PQfnumber(res, "suboriginremotelsn");
    5174             : 
    5175         358 :     subinfo = pg_malloc(ntups * sizeof(SubscriptionInfo));
    5176             : 
    5177         638 :     for (i = 0; i < ntups; i++)
    5178             :     {
    5179         280 :         subinfo[i].dobj.objType = DO_SUBSCRIPTION;
    5180         280 :         subinfo[i].dobj.catId.tableoid =
    5181         280 :             atooid(PQgetvalue(res, i, i_tableoid));
    5182         280 :         subinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    5183         280 :         AssignDumpId(&subinfo[i].dobj);
    5184         280 :         subinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_subname));
    5185         280 :         subinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_subowner));
    5186             : 
    5187         280 :         subinfo[i].subenabled =
    5188         280 :             (strcmp(PQgetvalue(res, i, i_subenabled), "t") == 0);
    5189         280 :         subinfo[i].subbinary =
    5190         280 :             (strcmp(PQgetvalue(res, i, i_subbinary), "t") == 0);
    5191         280 :         subinfo[i].substream = *(PQgetvalue(res, i, i_substream));
    5192         280 :         subinfo[i].subtwophasestate = *(PQgetvalue(res, i, i_subtwophasestate));
    5193         280 :         subinfo[i].subdisableonerr =
    5194         280 :             (strcmp(PQgetvalue(res, i, i_subdisableonerr), "t") == 0);
    5195         280 :         subinfo[i].subpasswordrequired =
    5196         280 :             (strcmp(PQgetvalue(res, i, i_subpasswordrequired), "t") == 0);
    5197         280 :         subinfo[i].subrunasowner =
    5198         280 :             (strcmp(PQgetvalue(res, i, i_subrunasowner), "t") == 0);
    5199         280 :         subinfo[i].subfailover =
    5200         280 :             (strcmp(PQgetvalue(res, i, i_subfailover), "t") == 0);
    5201         280 :         subinfo[i].subretaindeadtuples =
    5202         280 :             (strcmp(PQgetvalue(res, i, i_subretaindeadtuples), "t") == 0);
    5203         560 :         subinfo[i].subconninfo =
    5204         280 :             pg_strdup(PQgetvalue(res, i, i_subconninfo));
    5205         280 :         if (PQgetisnull(res, i, i_subslotname))
    5206           0 :             subinfo[i].subslotname = NULL;
    5207             :         else
    5208         280 :             subinfo[i].subslotname =
    5209         280 :                 pg_strdup(PQgetvalue(res, i, i_subslotname));
    5210         560 :         subinfo[i].subsynccommit =
    5211         280 :             pg_strdup(PQgetvalue(res, i, i_subsynccommit));
    5212         560 :         subinfo[i].subpublications =
    5213         280 :             pg_strdup(PQgetvalue(res, i, i_subpublications));
    5214         280 :         subinfo[i].suborigin = pg_strdup(PQgetvalue(res, i, i_suborigin));
    5215         280 :         if (PQgetisnull(res, i, i_suboriginremotelsn))
    5216         278 :             subinfo[i].suboriginremotelsn = NULL;
    5217             :         else
    5218           2 :             subinfo[i].suboriginremotelsn =
    5219           2 :                 pg_strdup(PQgetvalue(res, i, i_suboriginremotelsn));
    5220             : 
    5221             :         /* Decide whether we want to dump it */
    5222         280 :         selectDumpableObject(&(subinfo[i].dobj), fout);
    5223             :     }
    5224         358 :     PQclear(res);
    5225             : 
    5226         358 :     destroyPQExpBuffer(query);
    5227             : }
    5228             : 
    5229             : /*
    5230             :  * getSubscriptionTables
    5231             :  *    Get information about subscription membership for dumpable tables. This
    5232             :  *    will be used only in binary-upgrade mode for PG17 or later versions.
    5233             :  */
    5234             : void
    5235         364 : getSubscriptionTables(Archive *fout)
    5236             : {
    5237         364 :     DumpOptions *dopt = fout->dopt;
    5238         364 :     SubscriptionInfo *subinfo = NULL;
    5239             :     SubRelInfo *subrinfo;
    5240             :     PGresult   *res;
    5241             :     int         i_srsubid;
    5242             :     int         i_srrelid;
    5243             :     int         i_srsubstate;
    5244             :     int         i_srsublsn;
    5245             :     int         ntups;
    5246         364 :     Oid         last_srsubid = InvalidOid;
    5247             : 
    5248         364 :     if (dopt->no_subscriptions || !dopt->binary_upgrade ||
    5249          72 :         fout->remoteVersion < 170000)
    5250         292 :         return;
    5251             : 
    5252          72 :     res = ExecuteSqlQuery(fout,
    5253             :                           "SELECT srsubid, srrelid, srsubstate, srsublsn "
    5254             :                           "FROM pg_catalog.pg_subscription_rel "
    5255             :                           "ORDER BY srsubid",
    5256             :                           PGRES_TUPLES_OK);
    5257          72 :     ntups = PQntuples(res);
    5258          72 :     if (ntups == 0)
    5259          70 :         goto cleanup;
    5260             : 
    5261             :     /* Get pg_subscription_rel attributes */
    5262           2 :     i_srsubid = PQfnumber(res, "srsubid");
    5263           2 :     i_srrelid = PQfnumber(res, "srrelid");
    5264           2 :     i_srsubstate = PQfnumber(res, "srsubstate");
    5265           2 :     i_srsublsn = PQfnumber(res, "srsublsn");
    5266             : 
    5267           2 :     subrinfo = pg_malloc(ntups * sizeof(SubRelInfo));
    5268           6 :     for (int i = 0; i < ntups; i++)
    5269             :     {
    5270           4 :         Oid         cur_srsubid = atooid(PQgetvalue(res, i, i_srsubid));
    5271           4 :         Oid         relid = atooid(PQgetvalue(res, i, i_srrelid));
    5272             :         TableInfo  *tblinfo;
    5273             : 
    5274             :         /*
    5275             :          * If we switched to a new subscription, check if the subscription
    5276             :          * exists.
    5277             :          */
    5278           4 :         if (cur_srsubid != last_srsubid)
    5279             :         {
    5280           4 :             subinfo = findSubscriptionByOid(cur_srsubid);
    5281           4 :             if (subinfo == NULL)
    5282           0 :                 pg_fatal("subscription with OID %u does not exist", cur_srsubid);
    5283             : 
    5284           4 :             last_srsubid = cur_srsubid;
    5285             :         }
    5286             : 
    5287           4 :         tblinfo = findTableByOid(relid);
    5288           4 :         if (tblinfo == NULL)
    5289           0 :             pg_fatal("failed sanity check, table with OID %u not found",
    5290             :                      relid);
    5291             : 
    5292             :         /* OK, make a DumpableObject for this relationship */
    5293           4 :         subrinfo[i].dobj.objType = DO_SUBSCRIPTION_REL;
    5294           4 :         subrinfo[i].dobj.catId.tableoid = relid;
    5295           4 :         subrinfo[i].dobj.catId.oid = cur_srsubid;
    5296           4 :         AssignDumpId(&subrinfo[i].dobj);
    5297           4 :         subrinfo[i].dobj.name = pg_strdup(subinfo->dobj.name);
    5298           4 :         subrinfo[i].tblinfo = tblinfo;
    5299           4 :         subrinfo[i].srsubstate = PQgetvalue(res, i, i_srsubstate)[0];
    5300           4 :         if (PQgetisnull(res, i, i_srsublsn))
    5301           2 :             subrinfo[i].srsublsn = NULL;
    5302             :         else
    5303           2 :             subrinfo[i].srsublsn = pg_strdup(PQgetvalue(res, i, i_srsublsn));
    5304             : 
    5305           4 :         subrinfo[i].subinfo = subinfo;
    5306             : 
    5307             :         /* Decide whether we want to dump it */
    5308           4 :         selectDumpableObject(&(subrinfo[i].dobj), fout);
    5309             :     }
    5310             : 
    5311           2 : cleanup:
    5312          72 :     PQclear(res);
    5313             : }
    5314             : 
    5315             : /*
    5316             :  * dumpSubscriptionTable
    5317             :  *    Dump the definition of the given subscription table mapping. This will be
    5318             :  *    used only in binary-upgrade mode for PG17 or later versions.
    5319             :  */
    5320             : static void
    5321           4 : dumpSubscriptionTable(Archive *fout, const SubRelInfo *subrinfo)
    5322             : {
    5323           4 :     DumpOptions *dopt = fout->dopt;
    5324           4 :     SubscriptionInfo *subinfo = subrinfo->subinfo;
    5325             :     PQExpBuffer query;
    5326             :     char       *tag;
    5327             : 
    5328             :     /* Do nothing if not dumping schema */
    5329           4 :     if (!dopt->dumpSchema)
    5330           0 :         return;
    5331             : 
    5332             :     Assert(fout->dopt->binary_upgrade && fout->remoteVersion >= 170000);
    5333             : 
    5334           4 :     tag = psprintf("%s %s", subinfo->dobj.name, subrinfo->dobj.name);
    5335             : 
    5336           4 :     query = createPQExpBuffer();
    5337             : 
    5338           4 :     if (subinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
    5339             :     {
    5340             :         /*
    5341             :          * binary_upgrade_add_sub_rel_state will add the subscription relation
    5342             :          * to pg_subscription_rel table. This will be used only in
    5343             :          * binary-upgrade mode.
    5344             :          */
    5345           4 :         appendPQExpBufferStr(query,
    5346             :                              "\n-- For binary upgrade, must preserve the subscriber table.\n");
    5347           4 :         appendPQExpBufferStr(query,
    5348             :                              "SELECT pg_catalog.binary_upgrade_add_sub_rel_state(");
    5349           4 :         appendStringLiteralAH(query, subrinfo->dobj.name, fout);
    5350           4 :         appendPQExpBuffer(query,
    5351             :                           ", %u, '%c'",
    5352           4 :                           subrinfo->tblinfo->dobj.catId.oid,
    5353           4 :                           subrinfo->srsubstate);
    5354             : 
    5355           4 :         if (subrinfo->srsublsn && subrinfo->srsublsn[0] != '\0')
    5356           2 :             appendPQExpBuffer(query, ", '%s'", subrinfo->srsublsn);
    5357             :         else
    5358           2 :             appendPQExpBufferStr(query, ", NULL");
    5359             : 
    5360           4 :         appendPQExpBufferStr(query, ");\n");
    5361             :     }
    5362             : 
    5363             :     /*
    5364             :      * There is no point in creating a drop query as the drop is done by table
    5365             :      * drop.  (If you think to change this, see also _printTocEntry().)
    5366             :      * Although this object doesn't really have ownership as such, set the
    5367             :      * owner field anyway to ensure that the command is run by the correct
    5368             :      * role at restore time.
    5369             :      */
    5370           4 :     if (subrinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
    5371           4 :         ArchiveEntry(fout, subrinfo->dobj.catId, subrinfo->dobj.dumpId,
    5372           4 :                      ARCHIVE_OPTS(.tag = tag,
    5373             :                                   .namespace = subrinfo->tblinfo->dobj.namespace->dobj.name,
    5374             :                                   .owner = subinfo->rolname,
    5375             :                                   .description = "SUBSCRIPTION TABLE",
    5376             :                                   .section = SECTION_POST_DATA,
    5377             :                                   .createStmt = query->data));
    5378             : 
    5379             :     /* These objects can't currently have comments or seclabels */
    5380             : 
    5381           4 :     free(tag);
    5382           4 :     destroyPQExpBuffer(query);
    5383             : }
    5384             : 
    5385             : /*
    5386             :  * dumpSubscription
    5387             :  *    dump the definition of the given subscription
    5388             :  */
    5389             : static void
    5390         244 : dumpSubscription(Archive *fout, const SubscriptionInfo *subinfo)
    5391             : {
    5392         244 :     DumpOptions *dopt = fout->dopt;
    5393             :     PQExpBuffer delq;
    5394             :     PQExpBuffer query;
    5395             :     PQExpBuffer publications;
    5396             :     char       *qsubname;
    5397         244 :     char      **pubnames = NULL;
    5398         244 :     int         npubnames = 0;
    5399             :     int         i;
    5400             : 
    5401             :     /* Do nothing if not dumping schema */
    5402         244 :     if (!dopt->dumpSchema)
    5403          36 :         return;
    5404             : 
    5405         208 :     delq = createPQExpBuffer();
    5406         208 :     query = createPQExpBuffer();
    5407             : 
    5408         208 :     qsubname = pg_strdup(fmtId(subinfo->dobj.name));
    5409             : 
    5410         208 :     appendPQExpBuffer(delq, "DROP SUBSCRIPTION %s;\n",
    5411             :                       qsubname);
    5412             : 
    5413         208 :     appendPQExpBuffer(query, "CREATE SUBSCRIPTION %s CONNECTION ",
    5414             :                       qsubname);
    5415         208 :     appendStringLiteralAH(query, subinfo->subconninfo, fout);
    5416             : 
    5417             :     /* Build list of quoted publications and append them to query. */
    5418         208 :     if (!parsePGArray(subinfo->subpublications, &pubnames, &npubnames))
    5419           0 :         pg_fatal("could not parse %s array", "subpublications");
    5420             : 
    5421         208 :     publications = createPQExpBuffer();
    5422         416 :     for (i = 0; i < npubnames; i++)
    5423             :     {
    5424         208 :         if (i > 0)
    5425           0 :             appendPQExpBufferStr(publications, ", ");
    5426             : 
    5427         208 :         appendPQExpBufferStr(publications, fmtId(pubnames[i]));
    5428             :     }
    5429             : 
    5430         208 :     appendPQExpBuffer(query, " PUBLICATION %s WITH (connect = false, slot_name = ", publications->data);
    5431         208 :     if (subinfo->subslotname)
    5432         208 :         appendStringLiteralAH(query, subinfo->subslotname, fout);
    5433             :     else
    5434           0 :         appendPQExpBufferStr(query, "NONE");
    5435             : 
    5436         208 :     if (subinfo->subbinary)
    5437           0 :         appendPQExpBufferStr(query, ", binary = true");
    5438             : 
    5439         208 :     if (subinfo->substream == LOGICALREP_STREAM_ON)
    5440          68 :         appendPQExpBufferStr(query, ", streaming = on");
    5441         140 :     else if (subinfo->substream == LOGICALREP_STREAM_PARALLEL)
    5442          72 :         appendPQExpBufferStr(query, ", streaming = parallel");
    5443             :     else
    5444          68 :         appendPQExpBufferStr(query, ", streaming = off");
    5445             : 
    5446         208 :     if (subinfo->subtwophasestate != LOGICALREP_TWOPHASE_STATE_DISABLED)
    5447           0 :         appendPQExpBufferStr(query, ", two_phase = on");
    5448             : 
    5449         208 :     if (subinfo->subdisableonerr)
    5450           0 :         appendPQExpBufferStr(query, ", disable_on_error = true");
    5451             : 
    5452         208 :     if (!subinfo->subpasswordrequired)
    5453           0 :         appendPQExpBufferStr(query, ", password_required = false");
    5454             : 
    5455         208 :     if (subinfo->subrunasowner)
    5456           0 :         appendPQExpBufferStr(query, ", run_as_owner = true");
    5457             : 
    5458         208 :     if (subinfo->subfailover)
    5459           2 :         appendPQExpBufferStr(query, ", failover = true");
    5460             : 
    5461         208 :     if (subinfo->subretaindeadtuples)
    5462           2 :         appendPQExpBufferStr(query, ", retain_dead_tuples = true");
    5463             : 
    5464         208 :     if (strcmp(subinfo->subsynccommit, "off") != 0)
    5465           0 :         appendPQExpBuffer(query, ", synchronous_commit = %s", fmtId(subinfo->subsynccommit));
    5466             : 
    5467         208 :     if (pg_strcasecmp(subinfo->suborigin, LOGICALREP_ORIGIN_ANY) != 0)
    5468          68 :         appendPQExpBuffer(query, ", origin = %s", subinfo->suborigin);
    5469             : 
    5470         208 :     appendPQExpBufferStr(query, ");\n");
    5471             : 
    5472             :     /*
    5473             :      * In binary-upgrade mode, we allow the replication to continue after the
    5474             :      * upgrade.
    5475             :      */
    5476         208 :     if (dopt->binary_upgrade && fout->remoteVersion >= 170000)
    5477             :     {
    5478          10 :         if (subinfo->suboriginremotelsn)
    5479             :         {
    5480             :             /*
    5481             :              * Preserve the remote_lsn for the subscriber's replication
    5482             :              * origin. This value is required to start the replication from
    5483             :              * the position before the upgrade. This value will be stale if
    5484             :              * the publisher gets upgraded before the subscriber node.
    5485             :              * However, this shouldn't be a problem as the upgrade of the
    5486             :              * publisher ensures that all the transactions were replicated
    5487             :              * before upgrading it.
    5488             :              */
    5489           2 :             appendPQExpBufferStr(query,
    5490             :                                  "\n-- For binary upgrade, must preserve the remote_lsn for the subscriber's replication origin.\n");
    5491           2 :             appendPQExpBufferStr(query,
    5492             :                                  "SELECT pg_catalog.binary_upgrade_replorigin_advance(");
    5493           2 :             appendStringLiteralAH(query, subinfo->dobj.name, fout);
    5494           2 :             appendPQExpBuffer(query, ", '%s');\n", subinfo->suboriginremotelsn);
    5495             :         }
    5496             : 
    5497          10 :         if (subinfo->subenabled)
    5498             :         {
    5499             :             /*
    5500             :              * Enable the subscription to allow the replication to continue
    5501             :              * after the upgrade.
    5502             :              */
    5503           2 :             appendPQExpBufferStr(query,
    5504             :                                  "\n-- For binary upgrade, must preserve the subscriber's running state.\n");
    5505           2 :             appendPQExpBuffer(query, "ALTER SUBSCRIPTION %s ENABLE;\n", qsubname);
    5506             :         }
    5507             :     }
    5508             : 
    5509         208 :     if (subinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
    5510         208 :         ArchiveEntry(fout, subinfo->dobj.catId, subinfo->dobj.dumpId,
    5511         208 :                      ARCHIVE_OPTS(.tag = subinfo->dobj.name,
    5512             :                                   .owner = subinfo->rolname,
    5513             :                                   .description = "SUBSCRIPTION",
    5514             :                                   .section = SECTION_POST_DATA,
    5515             :                                   .createStmt = query->data,
    5516             :                                   .dropStmt = delq->data));
    5517             : 
    5518         208 :     if (subinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
    5519          68 :         dumpComment(fout, "SUBSCRIPTION", qsubname,
    5520          68 :                     NULL, subinfo->rolname,
    5521          68 :                     subinfo->dobj.catId, 0, subinfo->dobj.dumpId);
    5522             : 
    5523         208 :     if (subinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
    5524           0 :         dumpSecLabel(fout, "SUBSCRIPTION", qsubname,
    5525           0 :                      NULL, subinfo->rolname,
    5526           0 :                      subinfo->dobj.catId, 0, subinfo->dobj.dumpId);
    5527             : 
    5528         208 :     destroyPQExpBuffer(publications);
    5529         208 :     free(pubnames);
    5530             : 
    5531         208 :     destroyPQExpBuffer(delq);
    5532         208 :     destroyPQExpBuffer(query);
    5533         208 :     free(qsubname);
    5534             : }
    5535             : 
    5536             : /*
    5537             :  * Given a "create query", append as many ALTER ... DEPENDS ON EXTENSION as
    5538             :  * the object needs.
    5539             :  */
    5540             : static void
    5541       10384 : append_depends_on_extension(Archive *fout,
    5542             :                             PQExpBuffer create,
    5543             :                             const DumpableObject *dobj,
    5544             :                             const char *catalog,
    5545             :                             const char *keyword,
    5546             :                             const char *objname)
    5547             : {
    5548       10384 :     if (dobj->depends_on_ext)
    5549             :     {
    5550             :         char       *nm;
    5551             :         PGresult   *res;
    5552             :         PQExpBuffer query;
    5553             :         int         ntups;
    5554             :         int         i_extname;
    5555             :         int         i;
    5556             : 
    5557             :         /* dodge fmtId() non-reentrancy */
    5558          84 :         nm = pg_strdup(objname);
    5559             : 
    5560          84 :         query = createPQExpBuffer();
    5561          84 :         appendPQExpBuffer(query,
    5562             :                           "SELECT e.extname "
    5563             :                           "FROM pg_catalog.pg_depend d, pg_catalog.pg_extension e "
    5564             :                           "WHERE d.refobjid = e.oid AND classid = '%s'::pg_catalog.regclass "
    5565             :                           "AND objid = '%u'::pg_catalog.oid AND deptype = 'x' "
    5566             :                           "AND refclassid = 'pg_catalog.pg_extension'::pg_catalog.regclass",
    5567             :                           catalog,
    5568          84 :                           dobj->catId.oid);
    5569          84 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    5570          84 :         ntups = PQntuples(res);
    5571          84 :         i_extname = PQfnumber(res, "extname");
    5572         168 :         for (i = 0; i < ntups; i++)
    5573             :         {
    5574          84 :             appendPQExpBuffer(create, "\nALTER %s %s DEPENDS ON EXTENSION %s;",
    5575             :                               keyword, nm,
    5576          84 :                               fmtId(PQgetvalue(res, i, i_extname)));
    5577             :         }
    5578             : 
    5579          84 :         PQclear(res);
    5580          84 :         destroyPQExpBuffer(query);
    5581          84 :         pg_free(nm);
    5582             :     }
    5583       10384 : }
    5584             : 
    5585             : static Oid
    5586           0 : get_next_possible_free_pg_type_oid(Archive *fout, PQExpBuffer upgrade_query)
    5587             : {
    5588             :     /*
    5589             :      * If the old version didn't assign an array type, but the new version
    5590             :      * does, we must select an unused type OID to assign.  This currently only
    5591             :      * happens for domains, when upgrading pre-v11 to v11 and up.
    5592             :      *
    5593             :      * Note: local state here is kind of ugly, but we must have some, since we
    5594             :      * mustn't choose the same unused OID more than once.
    5595             :      */
    5596             :     static Oid  next_possible_free_oid = FirstNormalObjectId;
    5597             :     PGresult   *res;
    5598             :     bool        is_dup;
    5599             : 
    5600             :     do
    5601             :     {
    5602           0 :         ++next_possible_free_oid;
    5603           0 :         printfPQExpBuffer(upgrade_query,
    5604             :                           "SELECT EXISTS(SELECT 1 "
    5605             :                           "FROM pg_catalog.pg_type "
    5606             :                           "WHERE oid = '%u'::pg_catalog.oid);",
    5607             :                           next_possible_free_oid);
    5608           0 :         res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data);
    5609           0 :         is_dup = (PQgetvalue(res, 0, 0)[0] == 't');
    5610           0 :         PQclear(res);
    5611           0 :     } while (is_dup);
    5612             : 
    5613           0 :     return next_possible_free_oid;
    5614             : }
    5615             : 
    5616             : static void
    5617        1886 : binary_upgrade_set_type_oids_by_type_oid(Archive *fout,
    5618             :                                          PQExpBuffer upgrade_buffer,
    5619             :                                          Oid pg_type_oid,
    5620             :                                          bool force_array_type,
    5621             :                                          bool include_multirange_type)
    5622             : {
    5623        1886 :     PQExpBuffer upgrade_query = createPQExpBuffer();
    5624             :     PGresult   *res;
    5625             :     Oid         pg_type_array_oid;
    5626             :     Oid         pg_type_multirange_oid;
    5627             :     Oid         pg_type_multirange_array_oid;
    5628             :     TypeInfo   *tinfo;
    5629             : 
    5630        1886 :     appendPQExpBufferStr(upgrade_buffer, "\n-- For binary upgrade, must preserve pg_type oid\n");
    5631        1886 :     appendPQExpBuffer(upgrade_buffer,
    5632             :                       "SELECT pg_catalog.binary_upgrade_set_next_pg_type_oid('%u'::pg_catalog.oid);\n\n",
    5633             :                       pg_type_oid);
    5634             : 
    5635        1886 :     tinfo = findTypeByOid(pg_type_oid);
    5636        1886 :     if (tinfo)
    5637        1886 :         pg_type_array_oid = tinfo->typarray;
    5638             :     else
    5639           0 :         pg_type_array_oid = InvalidOid;
    5640             : 
    5641        1886 :     if (!OidIsValid(pg_type_array_oid) && force_array_type)
    5642           0 :         pg_type_array_oid = get_next_possible_free_pg_type_oid(fout, upgrade_query);
    5643             : 
    5644        1886 :     if (OidIsValid(pg_type_array_oid))
    5645             :     {
    5646        1882 :         appendPQExpBufferStr(upgrade_buffer,
    5647             :                              "\n-- For binary upgrade, must preserve pg_type array oid\n");
    5648        1882 :         appendPQExpBuffer(upgrade_buffer,
    5649             :                           "SELECT pg_catalog.binary_upgrade_set_next_array_pg_type_oid('%u'::pg_catalog.oid);\n\n",
    5650             :                           pg_type_array_oid);
    5651             :     }
    5652             : 
    5653             :     /*
    5654             :      * Pre-set the multirange type oid and its own array type oid.
    5655             :      */
    5656        1886 :     if (include_multirange_type)
    5657             :     {
    5658          16 :         if (fout->remoteVersion >= 140000)
    5659             :         {
    5660          16 :             printfPQExpBuffer(upgrade_query,
    5661             :                               "SELECT t.oid, t.typarray "
    5662             :                               "FROM pg_catalog.pg_type t "
    5663             :                               "JOIN pg_catalog.pg_range r "
    5664             :                               "ON t.oid = r.rngmultitypid "
    5665             :                               "WHERE r.rngtypid = '%u'::pg_catalog.oid;",
    5666             :                               pg_type_oid);
    5667             : 
    5668          16 :             res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data);
    5669             : 
    5670          16 :             pg_type_multirange_oid = atooid(PQgetvalue(res, 0, PQfnumber(res, "oid")));
    5671          16 :             pg_type_multirange_array_oid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typarray")));
    5672             : 
    5673          16 :             PQclear(res);
    5674             :         }
    5675             :         else
    5676             :         {
    5677           0 :             pg_type_multirange_oid = get_next_possible_free_pg_type_oid(fout, upgrade_query);
    5678           0 :             pg_type_multirange_array_oid = get_next_possible_free_pg_type_oid(fout, upgrade_query);
    5679             :         }
    5680             : 
    5681          16 :         appendPQExpBufferStr(upgrade_buffer,
    5682             :                              "\n-- For binary upgrade, must preserve multirange pg_type oid\n");
    5683          16 :         appendPQExpBuffer(upgrade_buffer,
    5684             :                           "SELECT pg_catalog.binary_upgrade_set_next_multirange_pg_type_oid('%u'::pg_catalog.oid);\n\n",
    5685             :                           pg_type_multirange_oid);
    5686          16 :         appendPQExpBufferStr(upgrade_buffer,
    5687             :                              "\n-- For binary upgrade, must preserve multirange pg_type array oid\n");
    5688          16 :         appendPQExpBuffer(upgrade_buffer,
    5689             :                           "SELECT pg_catalog.binary_upgrade_set_next_multirange_array_pg_type_oid('%u'::pg_catalog.oid);\n\n",
    5690             :                           pg_type_multirange_array_oid);
    5691             :     }
    5692             : 
    5693        1886 :     destroyPQExpBuffer(upgrade_query);
    5694        1886 : }
    5695             : 
    5696             : static void
    5697        1736 : binary_upgrade_set_type_oids_by_rel(Archive *fout,
    5698             :                                     PQExpBuffer upgrade_buffer,
    5699             :                                     const TableInfo *tbinfo)
    5700             : {
    5701        1736 :     Oid         pg_type_oid = tbinfo->reltype;
    5702             : 
    5703        1736 :     if (OidIsValid(pg_type_oid))
    5704        1736 :         binary_upgrade_set_type_oids_by_type_oid(fout, upgrade_buffer,
    5705             :                                                  pg_type_oid, false, false);
    5706        1736 : }
    5707             : 
    5708             : /*
    5709             :  * bsearch() comparator for BinaryUpgradeClassOidItem
    5710             :  */
    5711             : static int
    5712       24720 : BinaryUpgradeClassOidItemCmp(const void *p1, const void *p2)
    5713             : {
    5714       24720 :     BinaryUpgradeClassOidItem v1 = *((const BinaryUpgradeClassOidItem *) p1);
    5715       24720 :     BinaryUpgradeClassOidItem v2 = *((const BinaryUpgradeClassOidItem *) p2);
    5716             : 
    5717       24720 :     return pg_cmp_u32(v1.oid, v2.oid);
    5718             : }
    5719             : 
    5720             : /*
    5721             :  * collectBinaryUpgradeClassOids
    5722             :  *
    5723             :  * Construct a table of pg_class information required for
    5724             :  * binary_upgrade_set_pg_class_oids().  The table is sorted by OID for speed in
    5725             :  * lookup.
    5726             :  */
    5727             : static void
    5728          72 : collectBinaryUpgradeClassOids(Archive *fout)
    5729             : {
    5730             :     PGresult   *res;
    5731             :     const char *query;
    5732             : 
    5733          72 :     query = "SELECT c.oid, c.relkind, c.relfilenode, c.reltoastrelid, "
    5734             :         "ct.relfilenode, i.indexrelid, cti.relfilenode "
    5735             :         "FROM pg_catalog.pg_class c LEFT JOIN pg_catalog.pg_index i "
    5736             :         "ON (c.reltoastrelid = i.indrelid AND i.indisvalid) "
    5737             :         "LEFT JOIN pg_catalog.pg_class ct ON (c.reltoastrelid = ct.oid) "
    5738             :         "LEFT JOIN pg_catalog.pg_class AS cti ON (i.indexrelid = cti.oid) "
    5739             :         "ORDER BY c.oid;";
    5740             : 
    5741          72 :     res = ExecuteSqlQuery(fout, query, PGRES_TUPLES_OK);
    5742             : 
    5743          72 :     nbinaryUpgradeClassOids = PQntuples(res);
    5744          72 :     binaryUpgradeClassOids = (BinaryUpgradeClassOidItem *)
    5745          72 :         pg_malloc(nbinaryUpgradeClassOids * sizeof(BinaryUpgradeClassOidItem));
    5746             : 
    5747       33652 :     for (int i = 0; i < nbinaryUpgradeClassOids; i++)
    5748             :     {
    5749       33580 :         binaryUpgradeClassOids[i].oid = atooid(PQgetvalue(res, i, 0));
    5750       33580 :         binaryUpgradeClassOids[i].relkind = *PQgetvalue(res, i, 1);
    5751       33580 :         binaryUpgradeClassOids[i].relfilenumber = atooid(PQgetvalue(res, i, 2));
    5752       33580 :         binaryUpgradeClassOids[i].toast_oid = atooid(PQgetvalue(res, i, 3));
    5753       33580 :         binaryUpgradeClassOids[i].toast_relfilenumber = atooid(PQgetvalue(res, i, 4));
    5754       33580 :         binaryUpgradeClassOids[i].toast_index_oid = atooid(PQgetvalue(res, i, 5));
    5755       33580 :         binaryUpgradeClassOids[i].toast_index_relfilenumber = atooid(PQgetvalue(res, i, 6));
    5756             :     }
    5757             : 
    5758          72 :     PQclear(res);
    5759          72 : }
    5760             : 
    5761             : static void
    5762        2508 : binary_upgrade_set_pg_class_oids(Archive *fout,
    5763             :                                  PQExpBuffer upgrade_buffer, Oid pg_class_oid)
    5764             : {
    5765        2508 :     BinaryUpgradeClassOidItem key = {0};
    5766             :     BinaryUpgradeClassOidItem *entry;
    5767             : 
    5768             :     Assert(binaryUpgradeClassOids);
    5769             : 
    5770             :     /*
    5771             :      * Preserve the OID and relfilenumber of the table, table's index, table's
    5772             :      * toast table and toast table's index if any.
    5773             :      *
    5774             :      * One complexity is that the current table definition might not require
    5775             :      * the creation of a TOAST table, but the old database might have a TOAST
    5776             :      * table that was created earlier, before some wide columns were dropped.
    5777             :      * By setting the TOAST oid we force creation of the TOAST heap and index
    5778             :      * by the new backend, so we can copy the files during binary upgrade
    5779             :      * without worrying about this case.
    5780             :      */
    5781        2508 :     key.oid = pg_class_oid;
    5782        2508 :     entry = bsearch(&key, binaryUpgradeClassOids, nbinaryUpgradeClassOids,
    5783             :                     sizeof(BinaryUpgradeClassOidItem),
    5784             :                     BinaryUpgradeClassOidItemCmp);
    5785             : 
    5786        2508 :     appendPQExpBufferStr(upgrade_buffer,
    5787             :                          "\n-- For binary upgrade, must preserve pg_class oids and relfilenodes\n");
    5788             : 
    5789        2508 :     if (entry->relkind != RELKIND_INDEX &&
    5790        1954 :         entry->relkind != RELKIND_PARTITIONED_INDEX)
    5791             :     {
    5792        1904 :         appendPQExpBuffer(upgrade_buffer,
    5793             :                           "SELECT pg_catalog.binary_upgrade_set_next_heap_pg_class_oid('%u'::pg_catalog.oid);\n",
    5794             :                           pg_class_oid);
    5795             : 
    5796             :         /*
    5797             :          * Not every relation has storage. Also, in a pre-v12 database,
    5798             :          * partitioned tables have a relfilenumber, which should not be
    5799             :          * preserved when upgrading.
    5800             :          */
    5801        1904 :         if (RelFileNumberIsValid(entry->relfilenumber) &&
    5802        1580 :             entry->relkind != RELKIND_PARTITIONED_TABLE)
    5803        1580 :             appendPQExpBuffer(upgrade_buffer,
    5804             :                               "SELECT pg_catalog.binary_upgrade_set_next_heap_relfilenode('%u'::pg_catalog.oid);\n",
    5805             :                               entry->relfilenumber);
    5806             : 
    5807             :         /*
    5808             :          * In a pre-v12 database, partitioned tables might be marked as having
    5809             :          * toast tables, but we should ignore them if so.
    5810             :          */
    5811        1904 :         if (OidIsValid(entry->toast_oid) &&
    5812         560 :             entry->relkind != RELKIND_PARTITIONED_TABLE)
    5813             :         {
    5814         560 :             appendPQExpBuffer(upgrade_buffer,
    5815             :                               "SELECT pg_catalog.binary_upgrade_set_next_toast_pg_class_oid('%u'::pg_catalog.oid);\n",
    5816             :                               entry->toast_oid);
    5817         560 :             appendPQExpBuffer(upgrade_buffer,
    5818             :                               "SELECT pg_catalog.binary_upgrade_set_next_toast_relfilenode('%u'::pg_catalog.oid);\n",
    5819             :                               entry->toast_relfilenumber);
    5820             : 
    5821             :             /* every toast table has an index */
    5822         560 :             appendPQExpBuffer(upgrade_buffer,
    5823             :                               "SELECT pg_catalog.binary_upgrade_set_next_index_pg_class_oid('%u'::pg_catalog.oid);\n",
    5824             :                               entry->toast_index_oid);
    5825         560 :             appendPQExpBuffer(upgrade_buffer,
    5826             :                               "SELECT pg_catalog.binary_upgrade_set_next_index_relfilenode('%u'::pg_catalog.oid);\n",
    5827             :                               entry->toast_index_relfilenumber);
    5828             :         }
    5829             :     }
    5830             :     else
    5831             :     {
    5832             :         /* Preserve the OID and relfilenumber of the index */
    5833         604 :         appendPQExpBuffer(upgrade_buffer,
    5834             :                           "SELECT pg_catalog.binary_upgrade_set_next_index_pg_class_oid('%u'::pg_catalog.oid);\n",
    5835             :                           pg_class_oid);
    5836         604 :         appendPQExpBuffer(upgrade_buffer,
    5837             :                           "SELECT pg_catalog.binary_upgrade_set_next_index_relfilenode('%u'::pg_catalog.oid);\n",
    5838             :                           entry->relfilenumber);
    5839             :     }
    5840             : 
    5841        2508 :     appendPQExpBufferChar(upgrade_buffer, '\n');
    5842        2508 : }
    5843             : 
    5844             : /*
    5845             :  * If the DumpableObject is a member of an extension, add a suitable
    5846             :  * ALTER EXTENSION ADD command to the creation commands in upgrade_buffer.
    5847             :  *
    5848             :  * For somewhat historical reasons, objname should already be quoted,
    5849             :  * but not objnamespace (if any).
    5850             :  */
    5851             : static void
    5852        2998 : binary_upgrade_extension_member(PQExpBuffer upgrade_buffer,
    5853             :                                 const DumpableObject *dobj,
    5854             :                                 const char *objtype,
    5855             :                                 const char *objname,
    5856             :                                 const char *objnamespace)
    5857             : {
    5858        2998 :     DumpableObject *extobj = NULL;
    5859             :     int         i;
    5860             : 
    5861        2998 :     if (!dobj->ext_member)
    5862        2966 :         return;
    5863             : 
    5864             :     /*
    5865             :      * Find the parent extension.  We could avoid this search if we wanted to
    5866             :      * add a link field to DumpableObject, but the space costs of that would
    5867             :      * be considerable.  We assume that member objects could only have a
    5868             :      * direct dependency on their own extension, not any others.
    5869             :      */
    5870          32 :     for (i = 0; i < dobj->nDeps; i++)
    5871             :     {
    5872          32 :         extobj = findObjectByDumpId(dobj->dependencies[i]);
    5873          32 :         if (extobj && extobj->objType == DO_EXTENSION)
    5874          32 :             break;
    5875           0 :         extobj = NULL;
    5876             :     }
    5877          32 :     if (extobj == NULL)
    5878           0 :         pg_fatal("could not find parent extension for %s %s",
    5879             :                  objtype, objname);
    5880             : 
    5881          32 :     appendPQExpBufferStr(upgrade_buffer,
    5882             :                          "\n-- For binary upgrade, handle extension membership the hard way\n");
    5883          32 :     appendPQExpBuffer(upgrade_buffer, "ALTER EXTENSION %s ADD %s ",
    5884          32 :                       fmtId(extobj->name),
    5885             :                       objtype);
    5886          32 :     if (objnamespace && *objnamespace)
    5887          26 :         appendPQExpBuffer(upgrade_buffer, "%s.", fmtId(objnamespace));
    5888          32 :     appendPQExpBuffer(upgrade_buffer, "%s;\n", objname);
    5889             : }
    5890             : 
    5891             : /*
    5892             :  * getNamespaces:
    5893             :  *    get information about all namespaces in the system catalogs
    5894             :  */
    5895             : void
    5896         366 : getNamespaces(Archive *fout)
    5897             : {
    5898             :     PGresult   *res;
    5899             :     int         ntups;
    5900             :     int         i;
    5901             :     PQExpBuffer query;
    5902             :     NamespaceInfo *nsinfo;
    5903             :     int         i_tableoid;
    5904             :     int         i_oid;
    5905             :     int         i_nspname;
    5906             :     int         i_nspowner;
    5907             :     int         i_nspacl;
    5908             :     int         i_acldefault;
    5909             : 
    5910         366 :     query = createPQExpBuffer();
    5911             : 
    5912             :     /*
    5913             :      * we fetch all namespaces including system ones, so that every object we
    5914             :      * read in can be linked to a containing namespace.
    5915             :      */
    5916         366 :     appendPQExpBufferStr(query, "SELECT n.tableoid, n.oid, n.nspname, "
    5917             :                          "n.nspowner, "
    5918             :                          "n.nspacl, "
    5919             :                          "acldefault('n', n.nspowner) AS acldefault "
    5920             :                          "FROM pg_namespace n");
    5921             : 
    5922         366 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    5923             : 
    5924         366 :     ntups = PQntuples(res);
    5925             : 
    5926         366 :     nsinfo = (NamespaceInfo *) pg_malloc(ntups * sizeof(NamespaceInfo));
    5927             : 
    5928         366 :     i_tableoid = PQfnumber(res, "tableoid");
    5929         366 :     i_oid = PQfnumber(res, "oid");
    5930         366 :     i_nspname = PQfnumber(res, "nspname");
    5931         366 :     i_nspowner = PQfnumber(res, "nspowner");
    5932         366 :     i_nspacl = PQfnumber(res, "nspacl");
    5933         366 :     i_acldefault = PQfnumber(res, "acldefault");
    5934             : 
    5935        3222 :     for (i = 0; i < ntups; i++)
    5936             :     {
    5937             :         const char *nspowner;
    5938             : 
    5939        2856 :         nsinfo[i].dobj.objType = DO_NAMESPACE;
    5940        2856 :         nsinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    5941        2856 :         nsinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    5942        2856 :         AssignDumpId(&nsinfo[i].dobj);
    5943        2856 :         nsinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_nspname));
    5944        2856 :         nsinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_nspacl));
    5945        2856 :         nsinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
    5946        2856 :         nsinfo[i].dacl.privtype = 0;
    5947        2856 :         nsinfo[i].dacl.initprivs = NULL;
    5948        2856 :         nspowner = PQgetvalue(res, i, i_nspowner);
    5949        2856 :         nsinfo[i].nspowner = atooid(nspowner);
    5950        2856 :         nsinfo[i].rolname = getRoleName(nspowner);
    5951             : 
    5952             :         /* Decide whether to dump this namespace */
    5953        2856 :         selectDumpableNamespace(&nsinfo[i], fout);
    5954             : 
    5955             :         /* Mark whether namespace has an ACL */
    5956        2856 :         if (!PQgetisnull(res, i, i_nspacl))
    5957        1228 :             nsinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
    5958             : 
    5959             :         /*
    5960             :          * We ignore any pg_init_privs.initprivs entry for the public schema
    5961             :          * and assume a predetermined default, for several reasons.  First,
    5962             :          * dropping and recreating the schema removes its pg_init_privs entry,
    5963             :          * but an empty destination database starts with this ACL nonetheless.
    5964             :          * Second, we support dump/reload of public schema ownership changes.
    5965             :          * ALTER SCHEMA OWNER filters nspacl through aclnewowner(), but
    5966             :          * initprivs continues to reflect the initial owner.  Hence,
    5967             :          * synthesize the value that nspacl will have after the restore's
    5968             :          * ALTER SCHEMA OWNER.  Third, this makes the destination database
    5969             :          * match the source's ACL, even if the latter was an initdb-default
    5970             :          * ACL, which changed in v15.  An upgrade pulls in changes to most
    5971             :          * system object ACLs that the DBA had not customized.  We've made the
    5972             :          * public schema depart from that, because changing its ACL so easily
    5973             :          * breaks applications.
    5974             :          */
    5975        2856 :         if (strcmp(nsinfo[i].dobj.name, "public") == 0)
    5976             :         {
    5977         358 :             PQExpBuffer aclarray = createPQExpBuffer();
    5978         358 :             PQExpBuffer aclitem = createPQExpBuffer();
    5979             : 
    5980             :             /* Standard ACL as of v15 is {owner=UC/owner,=U/owner} */
    5981         358 :             appendPQExpBufferChar(aclarray, '{');
    5982         358 :             quoteAclUserName(aclitem, nsinfo[i].rolname);
    5983         358 :             appendPQExpBufferStr(aclitem, "=UC/");
    5984         358 :             quoteAclUserName(aclitem, nsinfo[i].rolname);
    5985         358 :             appendPGArray(aclarray, aclitem->data);
    5986         358 :             resetPQExpBuffer(aclitem);
    5987         358 :             appendPQExpBufferStr(aclitem, "=U/");
    5988         358 :             quoteAclUserName(aclitem, nsinfo[i].rolname);
    5989         358 :             appendPGArray(aclarray, aclitem->data);
    5990         358 :             appendPQExpBufferChar(aclarray, '}');
    5991             : 
    5992         358 :             nsinfo[i].dacl.privtype = 'i';
    5993         358 :             nsinfo[i].dacl.initprivs = pstrdup(aclarray->data);
    5994         358 :             nsinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
    5995             : 
    5996         358 :             destroyPQExpBuffer(aclarray);
    5997         358 :             destroyPQExpBuffer(aclitem);
    5998             :         }
    5999             :     }
    6000             : 
    6001         366 :     PQclear(res);
    6002         366 :     destroyPQExpBuffer(query);
    6003         366 : }
    6004             : 
    6005             : /*
    6006             :  * findNamespace:
    6007             :  *      given a namespace OID, look up the info read by getNamespaces
    6008             :  */
    6009             : static NamespaceInfo *
    6010     1150666 : findNamespace(Oid nsoid)
    6011             : {
    6012             :     NamespaceInfo *nsinfo;
    6013             : 
    6014     1150666 :     nsinfo = findNamespaceByOid(nsoid);
    6015     1150666 :     if (nsinfo == NULL)
    6016           0 :         pg_fatal("schema with OID %u does not exist", nsoid);
    6017     1150666 :     return nsinfo;
    6018             : }
    6019             : 
    6020             : /*
    6021             :  * getExtensions:
    6022             :  *    read all extensions in the system catalogs and return them in the
    6023             :  * ExtensionInfo* structure
    6024             :  *
    6025             :  *  numExtensions is set to the number of extensions read in
    6026             :  */
    6027             : ExtensionInfo *
    6028         366 : getExtensions(Archive *fout, int *numExtensions)
    6029             : {
    6030         366 :     DumpOptions *dopt = fout->dopt;
    6031             :     PGresult   *res;
    6032             :     int         ntups;
    6033             :     int         i;
    6034             :     PQExpBuffer query;
    6035         366 :     ExtensionInfo *extinfo = NULL;
    6036             :     int         i_tableoid;
    6037             :     int         i_oid;
    6038             :     int         i_extname;
    6039             :     int         i_nspname;
    6040             :     int         i_extrelocatable;
    6041             :     int         i_extversion;
    6042             :     int         i_extconfig;
    6043             :     int         i_extcondition;
    6044             : 
    6045         366 :     query = createPQExpBuffer();
    6046             : 
    6047         366 :     appendPQExpBufferStr(query, "SELECT x.tableoid, x.oid, "
    6048             :                          "x.extname, n.nspname, x.extrelocatable, x.extversion, x.extconfig, x.extcondition "
    6049             :                          "FROM pg_extension x "
    6050             :                          "JOIN pg_namespace n ON n.oid = x.extnamespace");
    6051             : 
    6052         366 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    6053             : 
    6054         366 :     ntups = PQntuples(res);
    6055         366 :     if (ntups == 0)
    6056           0 :         goto cleanup;
    6057             : 
    6058         366 :     extinfo = (ExtensionInfo *) pg_malloc(ntups * sizeof(ExtensionInfo));
    6059             : 
    6060         366 :     i_tableoid = PQfnumber(res, "tableoid");
    6061         366 :     i_oid = PQfnumber(res, "oid");
    6062         366 :     i_extname = PQfnumber(res, "extname");
    6063         366 :     i_nspname = PQfnumber(res, "nspname");
    6064         366 :     i_extrelocatable = PQfnumber(res, "extrelocatable");
    6065         366 :     i_extversion = PQfnumber(res, "extversion");
    6066         366 :     i_extconfig = PQfnumber(res, "extconfig");
    6067         366 :     i_extcondition = PQfnumber(res, "extcondition");
    6068             : 
    6069         782 :     for (i = 0; i < ntups; i++)
    6070             :     {
    6071         416 :         extinfo[i].dobj.objType = DO_EXTENSION;
    6072         416 :         extinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    6073         416 :         extinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    6074         416 :         AssignDumpId(&extinfo[i].dobj);
    6075         416 :         extinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_extname));
    6076         416 :         extinfo[i].namespace = pg_strdup(PQgetvalue(res, i, i_nspname));
    6077         416 :         extinfo[i].relocatable = *(PQgetvalue(res, i, i_extrelocatable)) == 't';
    6078         416 :         extinfo[i].extversion = pg_strdup(PQgetvalue(res, i, i_extversion));
    6079         416 :         extinfo[i].extconfig = pg_strdup(PQgetvalue(res, i, i_extconfig));
    6080         416 :         extinfo[i].extcondition = pg_strdup(PQgetvalue(res, i, i_extcondition));
    6081             : 
    6082             :         /* Decide whether we want to dump it */
    6083         416 :         selectDumpableExtension(&(extinfo[i]), dopt);
    6084             :     }
    6085             : 
    6086         366 : cleanup:
    6087         366 :     PQclear(res);
    6088         366 :     destroyPQExpBuffer(query);
    6089             : 
    6090         366 :     *numExtensions = ntups;
    6091             : 
    6092         366 :     return extinfo;
    6093             : }
    6094             : 
    6095             : /*
    6096             :  * getTypes:
    6097             :  *    get information about all types in the system catalogs
    6098             :  *
    6099             :  * NB: this must run after getFuncs() because we assume we can do
    6100             :  * findFuncByOid().
    6101             :  */
    6102             : void
    6103         364 : getTypes(Archive *fout)
    6104             : {
    6105             :     PGresult   *res;
    6106             :     int         ntups;
    6107             :     int         i;
    6108         364 :     PQExpBuffer query = createPQExpBuffer();
    6109             :     TypeInfo   *tyinfo;
    6110             :     ShellTypeInfo *stinfo;
    6111             :     int         i_tableoid;
    6112             :     int         i_oid;
    6113             :     int         i_typname;
    6114             :     int         i_typnamespace;
    6115             :     int         i_typacl;
    6116             :     int         i_acldefault;
    6117             :     int         i_typowner;
    6118             :     int         i_typelem;
    6119             :     int         i_typrelid;
    6120             :     int         i_typrelkind;
    6121             :     int         i_typtype;
    6122             :     int         i_typisdefined;
    6123             :     int         i_isarray;
    6124             :     int         i_typarray;
    6125             : 
    6126             :     /*
    6127             :      * we include even the built-in types because those may be used as array
    6128             :      * elements by user-defined types
    6129             :      *
    6130             :      * we filter out the built-in types when we dump out the types
    6131             :      *
    6132             :      * same approach for undefined (shell) types and array types
    6133             :      *
    6134             :      * Note: as of 8.3 we can reliably detect whether a type is an
    6135             :      * auto-generated array type by checking the element type's typarray.
    6136             :      * (Before that the test is capable of generating false positives.) We
    6137             :      * still check for name beginning with '_', though, so as to avoid the
    6138             :      * cost of the subselect probe for all standard types.  This would have to
    6139             :      * be revisited if the backend ever allows renaming of array types.
    6140             :      */
    6141         364 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, typname, "
    6142             :                          "typnamespace, typacl, "
    6143             :                          "acldefault('T', typowner) AS acldefault, "
    6144             :                          "typowner, "
    6145             :                          "typelem, typrelid, typarray, "
    6146             :                          "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
    6147             :                          "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
    6148             :                          "typtype, typisdefined, "
    6149             :                          "typname[0] = '_' AND typelem != 0 AND "
    6150             :                          "(SELECT typarray FROM pg_type te WHERE oid = pg_type.typelem) = oid AS isarray "
    6151             :                          "FROM pg_type");
    6152             : 
    6153         364 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    6154             : 
    6155         364 :     ntups = PQntuples(res);
    6156             : 
    6157         364 :     tyinfo = (TypeInfo *) pg_malloc(ntups * sizeof(TypeInfo));
    6158             : 
    6159         364 :     i_tableoid = PQfnumber(res, "tableoid");
    6160         364 :     i_oid = PQfnumber(res, "oid");
    6161         364 :     i_typname = PQfnumber(res, "typname");
    6162         364 :     i_typnamespace = PQfnumber(res, "typnamespace");
    6163         364 :     i_typacl = PQfnumber(res, "typacl");
    6164         364 :     i_acldefault = PQfnumber(res, "acldefault");
    6165         364 :     i_typowner = PQfnumber(res, "typowner");
    6166         364 :     i_typelem = PQfnumber(res, "typelem");
    6167         364 :     i_typrelid = PQfnumber(res, "typrelid");
    6168         364 :     i_typrelkind = PQfnumber(res, "typrelkind");
    6169         364 :     i_typtype = PQfnumber(res, "typtype");
    6170         364 :     i_typisdefined = PQfnumber(res, "typisdefined");
    6171         364 :     i_isarray = PQfnumber(res, "isarray");
    6172         364 :     i_typarray = PQfnumber(res, "typarray");
    6173             : 
    6174      265362 :     for (i = 0; i < ntups; i++)
    6175             :     {
    6176      264998 :         tyinfo[i].dobj.objType = DO_TYPE;
    6177      264998 :         tyinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    6178      264998 :         tyinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    6179      264998 :         AssignDumpId(&tyinfo[i].dobj);
    6180      264998 :         tyinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_typname));
    6181      529996 :         tyinfo[i].dobj.namespace =
    6182      264998 :             findNamespace(atooid(PQgetvalue(res, i, i_typnamespace)));
    6183      264998 :         tyinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_typacl));
    6184      264998 :         tyinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
    6185      264998 :         tyinfo[i].dacl.privtype = 0;
    6186      264998 :         tyinfo[i].dacl.initprivs = NULL;
    6187      264998 :         tyinfo[i].ftypname = NULL;  /* may get filled later */
    6188      264998 :         tyinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_typowner));
    6189      264998 :         tyinfo[i].typelem = atooid(PQgetvalue(res, i, i_typelem));
    6190      264998 :         tyinfo[i].typrelid = atooid(PQgetvalue(res, i, i_typrelid));
    6191      264998 :         tyinfo[i].typrelkind = *PQgetvalue(res, i, i_typrelkind);
    6192      264998 :         tyinfo[i].typtype = *PQgetvalue(res, i, i_typtype);
    6193      264998 :         tyinfo[i].shellType = NULL;
    6194             : 
    6195      264998 :         if (strcmp(PQgetvalue(res, i, i_typisdefined), "t") == 0)
    6196      264888 :             tyinfo[i].isDefined = true;
    6197             :         else
    6198         110 :             tyinfo[i].isDefined = false;
    6199             : 
    6200      264998 :         if (strcmp(PQgetvalue(res, i, i_isarray), "t") == 0)
    6201      127166 :             tyinfo[i].isArray = true;
    6202             :         else
    6203      137832 :             tyinfo[i].isArray = false;
    6204             : 
    6205      264998 :         tyinfo[i].typarray = atooid(PQgetvalue(res, i, i_typarray));
    6206             : 
    6207      264998 :         if (tyinfo[i].typtype == TYPTYPE_MULTIRANGE)
    6208        2460 :             tyinfo[i].isMultirange = true;
    6209             :         else
    6210      262538 :             tyinfo[i].isMultirange = false;
    6211             : 
    6212             :         /* Decide whether we want to dump it */
    6213      264998 :         selectDumpableType(&tyinfo[i], fout);
    6214             : 
    6215             :         /* Mark whether type has an ACL */
    6216      264998 :         if (!PQgetisnull(res, i, i_typacl))
    6217         434 :             tyinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
    6218             : 
    6219             :         /*
    6220             :          * If it's a domain, fetch info about its constraints, if any
    6221             :          */
    6222      264998 :         tyinfo[i].nDomChecks = 0;
    6223      264998 :         tyinfo[i].domChecks = NULL;
    6224      264998 :         tyinfo[i].notnull = NULL;
    6225      264998 :         if ((tyinfo[i].dobj.dump & DUMP_COMPONENT_DEFINITION) &&
    6226       30996 :             tyinfo[i].typtype == TYPTYPE_DOMAIN)
    6227         322 :             getDomainConstraints(fout, &(tyinfo[i]));
    6228             : 
    6229             :         /*
    6230             :          * If it's a base type, make a DumpableObject representing a shell
    6231             :          * definition of the type.  We will need to dump that ahead of the I/O
    6232             :          * functions for the type.  Similarly, range types need a shell
    6233             :          * definition in case they have a canonicalize function.
    6234             :          *
    6235             :          * Note: the shell type doesn't have a catId.  You might think it
    6236             :          * should copy the base type's catId, but then it might capture the
    6237             :          * pg_depend entries for the type, which we don't want.
    6238             :          */
    6239      264998 :         if ((tyinfo[i].dobj.dump & DUMP_COMPONENT_DEFINITION) &&
    6240       30996 :             (tyinfo[i].typtype == TYPTYPE_BASE ||
    6241       15068 :              tyinfo[i].typtype == TYPTYPE_RANGE))
    6242             :         {
    6243       16188 :             stinfo = (ShellTypeInfo *) pg_malloc(sizeof(ShellTypeInfo));
    6244       16188 :             stinfo->dobj.objType = DO_SHELL_TYPE;
    6245       16188 :             stinfo->dobj.catId = nilCatalogId;
    6246       16188 :             AssignDumpId(&stinfo->dobj);
    6247       16188 :             stinfo->dobj.name = pg_strdup(tyinfo[i].dobj.name);
    6248       16188 :             stinfo->dobj.namespace = tyinfo[i].dobj.namespace;
    6249       16188 :             stinfo->baseType = &(tyinfo[i]);
    6250       16188 :             tyinfo[i].shellType = stinfo;
    6251             : 
    6252             :             /*
    6253             :              * Initially mark the shell type as not to be dumped.  We'll only
    6254             :              * dump it if the I/O or canonicalize functions need to be dumped;
    6255             :              * this is taken care of while sorting dependencies.
    6256             :              */
    6257       16188 :             stinfo->dobj.dump = DUMP_COMPONENT_NONE;
    6258             :         }
    6259             :     }
    6260             : 
    6261         364 :     PQclear(res);
    6262             : 
    6263         364 :     destroyPQExpBuffer(query);
    6264         364 : }
    6265             : 
    6266             : /*
    6267             :  * getOperators:
    6268             :  *    get information about all operators in the system catalogs
    6269             :  */
    6270             : void
    6271         364 : getOperators(Archive *fout)
    6272             : {
    6273             :     PGresult   *res;
    6274             :     int         ntups;
    6275             :     int         i;
    6276         364 :     PQExpBuffer query = createPQExpBuffer();
    6277             :     OprInfo    *oprinfo;
    6278             :     int         i_tableoid;
    6279             :     int         i_oid;
    6280             :     int         i_oprname;
    6281             :     int         i_oprnamespace;
    6282             :     int         i_oprowner;
    6283             :     int         i_oprkind;
    6284             :     int         i_oprleft;
    6285             :     int         i_oprright;
    6286             :     int         i_oprcode;
    6287             : 
    6288             :     /*
    6289             :      * find all operators, including builtin operators; we filter out
    6290             :      * system-defined operators at dump-out time.
    6291             :      */
    6292             : 
    6293         364 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, oprname, "
    6294             :                          "oprnamespace, "
    6295             :                          "oprowner, "
    6296             :                          "oprkind, "
    6297             :                          "oprleft, "
    6298             :                          "oprright, "
    6299             :                          "oprcode::oid AS oprcode "
    6300             :                          "FROM pg_operator");
    6301             : 
    6302         364 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    6303             : 
    6304         364 :     ntups = PQntuples(res);
    6305             : 
    6306         364 :     oprinfo = (OprInfo *) pg_malloc(ntups * sizeof(OprInfo));
    6307             : 
    6308         364 :     i_tableoid = PQfnumber(res, "tableoid");
    6309         364 :     i_oid = PQfnumber(res, "oid");
    6310         364 :     i_oprname = PQfnumber(res, "oprname");
    6311         364 :     i_oprnamespace = PQfnumber(res, "oprnamespace");
    6312         364 :     i_oprowner = PQfnumber(res, "oprowner");
    6313         364 :     i_oprkind = PQfnumber(res, "oprkind");
    6314         364 :     i_oprleft = PQfnumber(res, "oprleft");
    6315         364 :     i_oprright = PQfnumber(res, "oprright");
    6316         364 :     i_oprcode = PQfnumber(res, "oprcode");
    6317             : 
    6318      291490 :     for (i = 0; i < ntups; i++)
    6319             :     {
    6320      291126 :         oprinfo[i].dobj.objType = DO_OPERATOR;
    6321      291126 :         oprinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    6322      291126 :         oprinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    6323      291126 :         AssignDumpId(&oprinfo[i].dobj);
    6324      291126 :         oprinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_oprname));
    6325      582252 :         oprinfo[i].dobj.namespace =
    6326      291126 :             findNamespace(atooid(PQgetvalue(res, i, i_oprnamespace)));
    6327      291126 :         oprinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_oprowner));
    6328      291126 :         oprinfo[i].oprkind = (PQgetvalue(res, i, i_oprkind))[0];
    6329      291126 :         oprinfo[i].oprleft = atooid(PQgetvalue(res, i, i_oprleft));
    6330      291126 :         oprinfo[i].oprright = atooid(PQgetvalue(res, i, i_oprright));
    6331      291126 :         oprinfo[i].oprcode = atooid(PQgetvalue(res, i, i_oprcode));
    6332             : 
    6333             :         /* Decide whether we want to dump it */
    6334      291126 :         selectDumpableObject(&(oprinfo[i].dobj), fout);
    6335             :     }
    6336             : 
    6337         364 :     PQclear(res);
    6338             : 
    6339         364 :     destroyPQExpBuffer(query);
    6340         364 : }
    6341             : 
    6342             : /*
    6343             :  * getCollations:
    6344             :  *    get information about all collations in the system catalogs
    6345             :  */
    6346             : void
    6347         364 : getCollations(Archive *fout)
    6348             : {
    6349             :     PGresult   *res;
    6350             :     int         ntups;
    6351             :     int         i;
    6352             :     PQExpBuffer query;
    6353             :     CollInfo   *collinfo;
    6354             :     int         i_tableoid;
    6355             :     int         i_oid;
    6356             :     int         i_collname;
    6357             :     int         i_collnamespace;
    6358             :     int         i_collowner;
    6359             :     int         i_collencoding;
    6360             : 
    6361         364 :     query = createPQExpBuffer();
    6362             : 
    6363             :     /*
    6364             :      * find all collations, including builtin collations; we filter out
    6365             :      * system-defined collations at dump-out time.
    6366             :      */
    6367             : 
    6368         364 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, collname, "
    6369             :                          "collnamespace, "
    6370             :                          "collowner, "
    6371             :                          "collencoding "
    6372             :                          "FROM pg_collation");
    6373             : 
    6374         364 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    6375             : 
    6376         364 :     ntups = PQntuples(res);
    6377             : 
    6378         364 :     collinfo = (CollInfo *) pg_malloc(ntups * sizeof(CollInfo));
    6379             : 
    6380         364 :     i_tableoid = PQfnumber(res, "tableoid");
    6381         364 :     i_oid = PQfnumber(res, "oid");
    6382         364 :     i_collname = PQfnumber(res, "collname");
    6383         364 :     i_collnamespace = PQfnumber(res, "collnamespace");
    6384         364 :     i_collowner = PQfnumber(res, "collowner");
    6385         364 :     i_collencoding = PQfnumber(res, "collencoding");
    6386             : 
    6387      297622 :     for (i = 0; i < ntups; i++)
    6388             :     {
    6389      297258 :         collinfo[i].dobj.objType = DO_COLLATION;
    6390      297258 :         collinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    6391      297258 :         collinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    6392      297258 :         AssignDumpId(&collinfo[i].dobj);
    6393      297258 :         collinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_collname));
    6394      594516 :         collinfo[i].dobj.namespace =
    6395      297258 :             findNamespace(atooid(PQgetvalue(res, i, i_collnamespace)));
    6396      297258 :         collinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_collowner));
    6397      297258 :         collinfo[i].collencoding = atoi(PQgetvalue(res, i, i_collencoding));
    6398             : 
    6399             :         /* Decide whether we want to dump it */
    6400      297258 :         selectDumpableObject(&(collinfo[i].dobj), fout);
    6401             :     }
    6402             : 
    6403         364 :     PQclear(res);
    6404             : 
    6405         364 :     destroyPQExpBuffer(query);
    6406         364 : }
    6407             : 
    6408             : /*
    6409             :  * getConversions:
    6410             :  *    get information about all conversions in the system catalogs
    6411             :  */
    6412             : void
    6413         364 : getConversions(Archive *fout)
    6414             : {
    6415             :     PGresult   *res;
    6416             :     int         ntups;
    6417             :     int         i;
    6418             :     PQExpBuffer query;
    6419             :     ConvInfo   *convinfo;
    6420             :     int         i_tableoid;
    6421             :     int         i_oid;
    6422             :     int         i_conname;
    6423             :     int         i_connamespace;
    6424             :     int         i_conowner;
    6425             : 
    6426         364 :     query = createPQExpBuffer();
    6427             : 
    6428             :     /*
    6429             :      * find all conversions, including builtin conversions; we filter out
    6430             :      * system-defined conversions at dump-out time.
    6431             :      */
    6432             : 
    6433         364 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, conname, "
    6434             :                          "connamespace, "
    6435             :                          "conowner "
    6436             :                          "FROM pg_conversion");
    6437             : 
    6438         364 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    6439             : 
    6440         364 :     ntups = PQntuples(res);
    6441             : 
    6442         364 :     convinfo = (ConvInfo *) pg_malloc(ntups * sizeof(ConvInfo));
    6443             : 
    6444         364 :     i_tableoid = PQfnumber(res, "tableoid");
    6445         364 :     i_oid = PQfnumber(res, "oid");
    6446         364 :     i_conname = PQfnumber(res, "conname");
    6447         364 :     i_connamespace = PQfnumber(res, "connamespace");
    6448         364 :     i_conowner = PQfnumber(res, "conowner");
    6449             : 
    6450       47052 :     for (i = 0; i < ntups; i++)
    6451             :     {
    6452       46688 :         convinfo[i].dobj.objType = DO_CONVERSION;
    6453       46688 :         convinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    6454       46688 :         convinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    6455       46688 :         AssignDumpId(&convinfo[i].dobj);
    6456       46688 :         convinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_conname));
    6457       93376 :         convinfo[i].dobj.namespace =
    6458       46688 :             findNamespace(atooid(PQgetvalue(res, i, i_connamespace)));
    6459       46688 :         convinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_conowner));
    6460             : 
    6461             :         /* Decide whether we want to dump it */
    6462       46688 :         selectDumpableObject(&(convinfo[i].dobj), fout);
    6463             :     }
    6464             : 
    6465         364 :     PQclear(res);
    6466             : 
    6467         364 :     destroyPQExpBuffer(query);
    6468         364 : }
    6469             : 
    6470             : /*
    6471             :  * getAccessMethods:
    6472             :  *    get information about all user-defined access methods
    6473             :  */
    6474             : void
    6475         364 : getAccessMethods(Archive *fout)
    6476             : {
    6477             :     PGresult   *res;
    6478             :     int         ntups;
    6479             :     int         i;
    6480             :     PQExpBuffer query;
    6481             :     AccessMethodInfo *aminfo;
    6482             :     int         i_tableoid;
    6483             :     int         i_oid;
    6484             :     int         i_amname;
    6485             :     int         i_amhandler;
    6486             :     int         i_amtype;
    6487             : 
    6488         364 :     query = createPQExpBuffer();
    6489             : 
    6490             :     /*
    6491             :      * Select all access methods from pg_am table.  v9.6 introduced CREATE
    6492             :      * ACCESS METHOD, so earlier versions usually have only built-in access
    6493             :      * methods.  v9.6 also changed the access method API, replacing dozens of
    6494             :      * pg_am columns with amhandler.  Even if a user created an access method
    6495             :      * by "INSERT INTO pg_am", we have no way to translate pre-v9.6 pg_am
    6496             :      * columns to a v9.6+ CREATE ACCESS METHOD.  Hence, before v9.6, read
    6497             :      * pg_am just to facilitate findAccessMethodByOid() providing the
    6498             :      * OID-to-name mapping.
    6499             :      */
    6500         364 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, amname, ");
    6501         364 :     if (fout->remoteVersion >= 90600)
    6502         364 :         appendPQExpBufferStr(query,
    6503             :                              "amtype, "
    6504             :                              "amhandler::pg_catalog.regproc AS amhandler ");
    6505             :     else
    6506           0 :         appendPQExpBufferStr(query,
    6507             :                              "'i'::pg_catalog.\"char\" AS amtype, "
    6508             :                              "'-'::pg_catalog.regproc AS amhandler ");
    6509         364 :     appendPQExpBufferStr(query, "FROM pg_am");
    6510             : 
    6511         364 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    6512             : 
    6513         364 :     ntups = PQntuples(res);
    6514             : 
    6515         364 :     aminfo = (AccessMethodInfo *) pg_malloc(ntups * sizeof(AccessMethodInfo));
    6516             : 
    6517         364 :     i_tableoid = PQfnumber(res, "tableoid");
    6518         364 :     i_oid = PQfnumber(res, "oid");
    6519         364 :     i_amname = PQfnumber(res, "amname");
    6520         364 :     i_amhandler = PQfnumber(res, "amhandler");
    6521         364 :     i_amtype = PQfnumber(res, "amtype");
    6522             : 
    6523        3168 :     for (i = 0; i < ntups; i++)
    6524             :     {
    6525        2804 :         aminfo[i].dobj.objType = DO_ACCESS_METHOD;
    6526        2804 :         aminfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    6527        2804 :         aminfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    6528        2804 :         AssignDumpId(&aminfo[i].dobj);
    6529        2804 :         aminfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_amname));
    6530        2804 :         aminfo[i].dobj.namespace = NULL;
    6531        2804 :         aminfo[i].amhandler = pg_strdup(PQgetvalue(res, i, i_amhandler));
    6532        2804 :         aminfo[i].amtype = *(PQgetvalue(res, i, i_amtype));
    6533             : 
    6534             :         /* Decide whether we want to dump it */
    6535        2804 :         selectDumpableAccessMethod(&(aminfo[i]), fout);
    6536             :     }
    6537             : 
    6538         364 :     PQclear(res);
    6539             : 
    6540         364 :     destroyPQExpBuffer(query);
    6541         364 : }
    6542             : 
    6543             : 
    6544             : /*
    6545             :  * getOpclasses:
    6546             :  *    get information about all opclasses in the system catalogs
    6547             :  */
    6548             : void
    6549         364 : getOpclasses(Archive *fout)
    6550             : {
    6551             :     PGresult   *res;
    6552             :     int         ntups;
    6553             :     int         i;
    6554         364 :     PQExpBuffer query = createPQExpBuffer();
    6555             :     OpclassInfo *opcinfo;
    6556             :     int         i_tableoid;
    6557             :     int         i_oid;
    6558             :     int         i_opcmethod;
    6559             :     int         i_opcname;
    6560             :     int         i_opcnamespace;
    6561             :     int         i_opcowner;
    6562             : 
    6563             :     /*
    6564             :      * find all opclasses, including builtin opclasses; we filter out
    6565             :      * system-defined opclasses at dump-out time.
    6566             :      */
    6567             : 
    6568         364 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, opcmethod, opcname, "
    6569             :                          "opcnamespace, "
    6570             :                          "opcowner "
    6571             :                          "FROM pg_opclass");
    6572             : 
    6573         364 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    6574             : 
    6575         364 :     ntups = PQntuples(res);
    6576             : 
    6577         364 :     opcinfo = (OpclassInfo *) pg_malloc(ntups * sizeof(OpclassInfo));
    6578             : 
    6579         364 :     i_tableoid = PQfnumber(res, "tableoid");
    6580         364 :     i_oid = PQfnumber(res, "oid");
    6581         364 :     i_opcmethod = PQfnumber(res, "opcmethod");
    6582         364 :     i_opcname = PQfnumber(res, "opcname");
    6583         364 :     i_opcnamespace = PQfnumber(res, "opcnamespace");
    6584         364 :     i_opcowner = PQfnumber(res, "opcowner");
    6585             : 
    6586       65122 :     for (i = 0; i < ntups; i++)
    6587             :     {
    6588       64758 :         opcinfo[i].dobj.objType = DO_OPCLASS;
    6589       64758 :         opcinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    6590       64758 :         opcinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    6591       64758 :         AssignDumpId(&opcinfo[i].dobj);
    6592       64758 :         opcinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_opcname));
    6593      129516 :         opcinfo[i].dobj.namespace =
    6594       64758 :             findNamespace(atooid(PQgetvalue(res, i, i_opcnamespace)));
    6595       64758 :         opcinfo[i].opcmethod = atooid(PQgetvalue(res, i, i_opcmethod));
    6596       64758 :         opcinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_opcowner));
    6597             : 
    6598             :         /* Decide whether we want to dump it */
    6599       64758 :         selectDumpableObject(&(opcinfo[i].dobj), fout);
    6600             :     }
    6601             : 
    6602         364 :     PQclear(res);
    6603             : 
    6604         364 :     destroyPQExpBuffer(query);
    6605         364 : }
    6606             : 
    6607             : /*
    6608             :  * getOpfamilies:
    6609             :  *    get information about all opfamilies in the system catalogs
    6610             :  */
    6611             : void
    6612         364 : getOpfamilies(Archive *fout)
    6613             : {
    6614             :     PGresult   *res;
    6615             :     int         ntups;
    6616             :     int         i;
    6617             :     PQExpBuffer query;
    6618             :     OpfamilyInfo *opfinfo;
    6619             :     int         i_tableoid;
    6620             :     int         i_oid;
    6621             :     int         i_opfmethod;
    6622             :     int         i_opfname;
    6623             :     int         i_opfnamespace;
    6624             :     int         i_opfowner;
    6625             : 
    6626         364 :     query = createPQExpBuffer();
    6627             : 
    6628             :     /*
    6629             :      * find all opfamilies, including builtin opfamilies; we filter out
    6630             :      * system-defined opfamilies at dump-out time.
    6631             :      */
    6632             : 
    6633         364 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, opfmethod, opfname, "
    6634             :                          "opfnamespace, "
    6635             :                          "opfowner "
    6636             :                          "FROM pg_opfamily");
    6637             : 
    6638         364 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    6639             : 
    6640         364 :     ntups = PQntuples(res);
    6641             : 
    6642         364 :     opfinfo = (OpfamilyInfo *) pg_malloc(ntups * sizeof(OpfamilyInfo));
    6643             : 
    6644         364 :     i_tableoid = PQfnumber(res, "tableoid");
    6645         364 :     i_oid = PQfnumber(res, "oid");
    6646         364 :     i_opfname = PQfnumber(res, "opfname");
    6647         364 :     i_opfmethod = PQfnumber(res, "opfmethod");
    6648         364 :     i_opfnamespace = PQfnumber(res, "opfnamespace");
    6649         364 :     i_opfowner = PQfnumber(res, "opfowner");
    6650             : 
    6651       53798 :     for (i = 0; i < ntups; i++)
    6652             :     {
    6653       53434 :         opfinfo[i].dobj.objType = DO_OPFAMILY;
    6654       53434 :         opfinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    6655       53434 :         opfinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    6656       53434 :         AssignDumpId(&opfinfo[i].dobj);
    6657       53434 :         opfinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_opfname));
    6658      106868 :         opfinfo[i].dobj.namespace =
    6659       53434 :             findNamespace(atooid(PQgetvalue(res, i, i_opfnamespace)));
    6660       53434 :         opfinfo[i].opfmethod = atooid(PQgetvalue(res, i, i_opfmethod));
    6661       53434 :         opfinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_opfowner));
    6662             : 
    6663             :         /* Decide whether we want to dump it */
    6664       53434 :         selectDumpableObject(&(opfinfo[i].dobj), fout);
    6665             :     }
    6666             : 
    6667         364 :     PQclear(res);
    6668             : 
    6669         364 :     destroyPQExpBuffer(query);
    6670         364 : }
    6671             : 
    6672             : /*
    6673             :  * getAggregates:
    6674             :  *    get information about all user-defined aggregates in the system catalogs
    6675             :  */
    6676             : void
    6677         364 : getAggregates(Archive *fout)
    6678             : {
    6679         364 :     DumpOptions *dopt = fout->dopt;
    6680             :     PGresult   *res;
    6681             :     int         ntups;
    6682             :     int         i;
    6683         364 :     PQExpBuffer query = createPQExpBuffer();
    6684             :     AggInfo    *agginfo;
    6685             :     int         i_tableoid;
    6686             :     int         i_oid;
    6687             :     int         i_aggname;
    6688             :     int         i_aggnamespace;
    6689             :     int         i_pronargs;
    6690             :     int         i_proargtypes;
    6691             :     int         i_proowner;
    6692             :     int         i_aggacl;
    6693             :     int         i_acldefault;
    6694             : 
    6695             :     /*
    6696             :      * Find all interesting aggregates.  See comment in getFuncs() for the
    6697             :      * rationale behind the filtering logic.
    6698             :      */
    6699         364 :     if (fout->remoteVersion >= 90600)
    6700             :     {
    6701             :         const char *agg_check;
    6702             : 
    6703         728 :         agg_check = (fout->remoteVersion >= 110000 ? "p.prokind = 'a'"
    6704         364 :                      : "p.proisagg");
    6705             : 
    6706         364 :         appendPQExpBuffer(query, "SELECT p.tableoid, p.oid, "
    6707             :                           "p.proname AS aggname, "
    6708             :                           "p.pronamespace AS aggnamespace, "
    6709             :                           "p.pronargs, p.proargtypes, "
    6710             :                           "p.proowner, "
    6711             :                           "p.proacl AS aggacl, "
    6712             :                           "acldefault('f', p.proowner) AS acldefault "
    6713             :                           "FROM pg_proc p "
    6714             :                           "LEFT JOIN pg_init_privs pip ON "
    6715             :                           "(p.oid = pip.objoid "
    6716             :                           "AND pip.classoid = 'pg_proc'::regclass "
    6717             :                           "AND pip.objsubid = 0) "
    6718             :                           "WHERE %s AND ("
    6719             :                           "p.pronamespace != "
    6720             :                           "(SELECT oid FROM pg_namespace "
    6721             :                           "WHERE nspname = 'pg_catalog') OR "
    6722             :                           "p.proacl IS DISTINCT FROM pip.initprivs",
    6723             :                           agg_check);
    6724         364 :         if (dopt->binary_upgrade)
    6725          72 :             appendPQExpBufferStr(query,
    6726             :                                  " OR EXISTS(SELECT 1 FROM pg_depend WHERE "
    6727             :                                  "classid = 'pg_proc'::regclass AND "
    6728             :                                  "objid = p.oid AND "
    6729             :                                  "refclassid = 'pg_extension'::regclass AND "
    6730             :                                  "deptype = 'e')");
    6731         364 :         appendPQExpBufferChar(query, ')');
    6732             :     }
    6733             :     else
    6734             :     {
    6735           0 :         appendPQExpBufferStr(query, "SELECT tableoid, oid, proname AS aggname, "
    6736             :                              "pronamespace AS aggnamespace, "
    6737             :                              "pronargs, proargtypes, "
    6738             :                              "proowner, "
    6739             :                              "proacl AS aggacl, "
    6740             :                              "acldefault('f', proowner) AS acldefault "
    6741             :                              "FROM pg_proc p "
    6742             :                              "WHERE proisagg AND ("
    6743             :                              "pronamespace != "
    6744             :                              "(SELECT oid FROM pg_namespace "
    6745             :                              "WHERE nspname = 'pg_catalog')");
    6746           0 :         if (dopt->binary_upgrade)
    6747           0 :             appendPQExpBufferStr(query,
    6748             :                                  " OR EXISTS(SELECT 1 FROM pg_depend WHERE "
    6749             :                                  "classid = 'pg_proc'::regclass AND "
    6750             :                                  "objid = p.oid AND "
    6751             :                                  "refclassid = 'pg_extension'::regclass AND "
    6752             :                                  "deptype = 'e')");
    6753           0 :         appendPQExpBufferChar(query, ')');
    6754             :     }
    6755             : 
    6756         364 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    6757             : 
    6758         364 :     ntups = PQntuples(res);
    6759             : 
    6760         364 :     agginfo = (AggInfo *) pg_malloc(ntups * sizeof(AggInfo));
    6761             : 
    6762         364 :     i_tableoid = PQfnumber(res, "tableoid");
    6763         364 :     i_oid = PQfnumber(res, "oid");
    6764         364 :     i_aggname = PQfnumber(res, "aggname");
    6765         364 :     i_aggnamespace = PQfnumber(res, "aggnamespace");
    6766         364 :     i_pronargs = PQfnumber(res, "pronargs");
    6767         364 :     i_proargtypes = PQfnumber(res, "proargtypes");
    6768         364 :     i_proowner = PQfnumber(res, "proowner");
    6769         364 :     i_aggacl = PQfnumber(res, "aggacl");
    6770         364 :     i_acldefault = PQfnumber(res, "acldefault");
    6771             : 
    6772        1168 :     for (i = 0; i < ntups; i++)
    6773             :     {
    6774         804 :         agginfo[i].aggfn.dobj.objType = DO_AGG;
    6775         804 :         agginfo[i].aggfn.dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    6776         804 :         agginfo[i].aggfn.dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    6777         804 :         AssignDumpId(&agginfo[i].aggfn.dobj);
    6778         804 :         agginfo[i].aggfn.dobj.name = pg_strdup(PQgetvalue(res, i, i_aggname));
    6779        1608 :         agginfo[i].aggfn.dobj.namespace =
    6780         804 :             findNamespace(atooid(PQgetvalue(res, i, i_aggnamespace)));
    6781         804 :         agginfo[i].aggfn.dacl.acl = pg_strdup(PQgetvalue(res, i, i_aggacl));
    6782         804 :         agginfo[i].aggfn.dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
    6783         804 :         agginfo[i].aggfn.dacl.privtype = 0;
    6784         804 :         agginfo[i].aggfn.dacl.initprivs = NULL;
    6785         804 :         agginfo[i].aggfn.rolname = getRoleName(PQgetvalue(res, i, i_proowner));
    6786         804 :         agginfo[i].aggfn.lang = InvalidOid; /* not currently interesting */
    6787         804 :         agginfo[i].aggfn.prorettype = InvalidOid;   /* not saved */
    6788         804 :         agginfo[i].aggfn.nargs = atoi(PQgetvalue(res, i, i_pronargs));
    6789         804 :         if (agginfo[i].aggfn.nargs == 0)
    6790         112 :             agginfo[i].aggfn.argtypes = NULL;
    6791             :         else
    6792             :         {
    6793         692 :             agginfo[i].aggfn.argtypes = (Oid *) pg_malloc(agginfo[i].aggfn.nargs * sizeof(Oid));
    6794         692 :             parseOidArray(PQgetvalue(res, i, i_proargtypes),
    6795         692 :                           agginfo[i].aggfn.argtypes,
    6796         692 :                           agginfo[i].aggfn.nargs);
    6797             :         }
    6798         804 :         agginfo[i].aggfn.postponed_def = false; /* might get set during sort */
    6799             : 
    6800             :         /* Decide whether we want to dump it */
    6801         804 :         selectDumpableObject(&(agginfo[i].aggfn.dobj), fout);
    6802             : 
    6803             :         /* Mark whether aggregate has an ACL */
    6804         804 :         if (!PQgetisnull(res, i, i_aggacl))
    6805          50 :             agginfo[i].aggfn.dobj.components |= DUMP_COMPONENT_ACL;
    6806             :     }
    6807             : 
    6808         364 :     PQclear(res);
    6809             : 
    6810         364 :     destroyPQExpBuffer(query);
    6811         364 : }
    6812             : 
    6813             : /*
    6814             :  * getFuncs:
    6815             :  *    get information about all user-defined functions in the system catalogs
    6816             :  */
    6817             : void
    6818         364 : getFuncs(Archive *fout)
    6819             : {
    6820         364 :     DumpOptions *dopt = fout->dopt;
    6821             :     PGresult   *res;
    6822             :     int         ntups;
    6823             :     int         i;
    6824         364 :     PQExpBuffer query = createPQExpBuffer();
    6825             :     FuncInfo   *finfo;
    6826             :     int         i_tableoid;
    6827             :     int         i_oid;
    6828             :     int         i_proname;
    6829             :     int         i_pronamespace;
    6830             :     int         i_proowner;
    6831             :     int         i_prolang;
    6832             :     int         i_pronargs;
    6833             :     int         i_proargtypes;
    6834             :     int         i_prorettype;
    6835             :     int         i_proacl;
    6836             :     int         i_acldefault;
    6837             : 
    6838             :     /*
    6839             :      * Find all interesting functions.  This is a bit complicated:
    6840             :      *
    6841             :      * 1. Always exclude aggregates; those are handled elsewhere.
    6842             :      *
    6843             :      * 2. Always exclude functions that are internally dependent on something
    6844             :      * else, since presumably those will be created as a result of creating
    6845             :      * the something else.  This currently acts only to suppress constructor
    6846             :      * functions for range types.  Note this is OK only because the
    6847             :      * constructors don't have any dependencies the range type doesn't have;
    6848             :      * otherwise we might not get creation ordering correct.
    6849             :      *
    6850             :      * 3. Otherwise, we normally exclude functions in pg_catalog.  However, if
    6851             :      * they're members of extensions and we are in binary-upgrade mode then
    6852             :      * include them, since we want to dump extension members individually in
    6853             :      * that mode.  Also, if they are used by casts or transforms then we need
    6854             :      * to gather the information about them, though they won't be dumped if
    6855             :      * they are built-in.  Also, in 9.6 and up, include functions in
    6856             :      * pg_catalog if they have an ACL different from what's shown in
    6857             :      * pg_init_privs (so we have to join to pg_init_privs; annoying).
    6858             :      */
    6859         364 :     if (fout->remoteVersion >= 90600)
    6860             :     {
    6861             :         const char *not_agg_check;
    6862             : 
    6863         728 :         not_agg_check = (fout->remoteVersion >= 110000 ? "p.prokind <> 'a'"
    6864         364 :                          : "NOT p.proisagg");
    6865             : 
    6866         364 :         appendPQExpBuffer(query,
    6867             :                           "SELECT p.tableoid, p.oid, p.proname, p.prolang, "
    6868             :                           "p.pronargs, p.proargtypes, p.prorettype, "
    6869             :                           "p.proacl, "
    6870             :                           "acldefault('f', p.proowner) AS acldefault, "
    6871             :                           "p.pronamespace, "
    6872             :                           "p.proowner "
    6873             :                           "FROM pg_proc p "
    6874             :                           "LEFT JOIN pg_init_privs pip ON "
    6875             :                           "(p.oid = pip.objoid "
    6876             :                           "AND pip.classoid = 'pg_proc'::regclass "
    6877             :                           "AND pip.objsubid = 0) "
    6878             :                           "WHERE %s"
    6879             :                           "\n  AND NOT EXISTS (SELECT 1 FROM pg_depend "
    6880             :                           "WHERE classid = 'pg_proc'::regclass AND "
    6881             :                           "objid = p.oid AND deptype = 'i')"
    6882             :                           "\n  AND ("
    6883             :                           "\n  pronamespace != "
    6884             :                           "(SELECT oid FROM pg_namespace "
    6885             :                           "WHERE nspname = 'pg_catalog')"
    6886             :                           "\n  OR EXISTS (SELECT 1 FROM pg_cast"
    6887             :                           "\n  WHERE pg_cast.oid > %u "
    6888             :                           "\n  AND p.oid = pg_cast.castfunc)"
    6889             :                           "\n  OR EXISTS (SELECT 1 FROM pg_transform"
    6890             :                           "\n  WHERE pg_transform.oid > %u AND "
    6891             :                           "\n  (p.oid = pg_transform.trffromsql"
    6892             :                           "\n  OR p.oid = pg_transform.trftosql))",
    6893             :                           not_agg_check,
    6894             :                           g_last_builtin_oid,
    6895             :                           g_last_builtin_oid);
    6896         364 :         if (dopt->binary_upgrade)
    6897          72 :             appendPQExpBufferStr(query,
    6898             :                                  "\n  OR EXISTS(SELECT 1 FROM pg_depend WHERE "
    6899             :                                  "classid = 'pg_proc'::regclass AND "
    6900             :                                  "objid = p.oid AND "
    6901             :                                  "refclassid = 'pg_extension'::regclass AND "
    6902             :                                  "deptype = 'e')");
    6903         364 :         appendPQExpBufferStr(query,
    6904             :                              "\n  OR p.proacl IS DISTINCT FROM pip.initprivs");
    6905         364 :         appendPQExpBufferChar(query, ')');
    6906             :     }
    6907             :     else
    6908             :     {
    6909           0 :         appendPQExpBuffer(query,
    6910             :                           "SELECT tableoid, oid, proname, prolang, "
    6911             :                           "pronargs, proargtypes, prorettype, proacl, "
    6912             :                           "acldefault('f', proowner) AS acldefault, "
    6913             :                           "pronamespace, "
    6914             :                           "proowner "
    6915             :                           "FROM pg_proc p "
    6916             :                           "WHERE NOT proisagg"
    6917             :                           "\n  AND NOT EXISTS (SELECT 1 FROM pg_depend "
    6918             :                           "WHERE classid = 'pg_proc'::regclass AND "
    6919             :                           "objid = p.oid AND deptype = 'i')"
    6920             :                           "\n  AND ("
    6921             :                           "\n  pronamespace != "
    6922             :                           "(SELECT oid FROM pg_namespace "
    6923             :                           "WHERE nspname = 'pg_catalog')"
    6924             :                           "\n  OR EXISTS (SELECT 1 FROM pg_cast"
    6925             :                           "\n  WHERE pg_cast.oid > '%u'::oid"
    6926             :                           "\n  AND p.oid = pg_cast.castfunc)",
    6927             :                           g_last_builtin_oid);
    6928             : 
    6929           0 :         if (fout->remoteVersion >= 90500)
    6930           0 :             appendPQExpBuffer(query,
    6931             :                               "\n  OR EXISTS (SELECT 1 FROM pg_transform"
    6932             :                               "\n  WHERE pg_transform.oid > '%u'::oid"
    6933             :                               "\n  AND (p.oid = pg_transform.trffromsql"
    6934             :                               "\n  OR p.oid = pg_transform.trftosql))",
    6935             :                               g_last_builtin_oid);
    6936             : 
    6937           0 :         if (dopt->binary_upgrade)
    6938           0 :             appendPQExpBufferStr(query,
    6939             :                                  "\n  OR EXISTS(SELECT 1 FROM pg_depend WHERE "
    6940             :                                  "classid = 'pg_proc'::regclass AND "
    6941             :                                  "objid = p.oid AND "
    6942             :                                  "refclassid = 'pg_extension'::regclass AND "
    6943             :                                  "deptype = 'e')");
    6944           0 :         appendPQExpBufferChar(query, ')');
    6945             :     }
    6946             : 
    6947         364 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    6948             : 
    6949         364 :     ntups = PQntuples(res);
    6950             : 
    6951         364 :     finfo = (FuncInfo *) pg_malloc0(ntups * sizeof(FuncInfo));
    6952             : 
    6953         364 :     i_tableoid = PQfnumber(res, "tableoid");
    6954         364 :     i_oid = PQfnumber(res, "oid");
    6955         364 :     i_proname = PQfnumber(res, "proname");
    6956         364 :     i_pronamespace = PQfnumber(res, "pronamespace");
    6957         364 :     i_proowner = PQfnumber(res, "proowner");
    6958         364 :     i_prolang = PQfnumber(res, "prolang");
    6959         364 :     i_pronargs = PQfnumber(res, "pronargs");
    6960         364 :     i_proargtypes = PQfnumber(res, "proargtypes");
    6961         364 :     i_prorettype = PQfnumber(res, "prorettype");
    6962         364 :     i_proacl = PQfnumber(res, "proacl");
    6963         364 :     i_acldefault = PQfnumber(res, "acldefault");
    6964             : 
    6965        9840 :     for (i = 0; i < ntups; i++)
    6966             :     {
    6967        9476 :         finfo[i].dobj.objType = DO_FUNC;
    6968        9476 :         finfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    6969        9476 :         finfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    6970        9476 :         AssignDumpId(&finfo[i].dobj);
    6971        9476 :         finfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_proname));
    6972       18952 :         finfo[i].dobj.namespace =
    6973        9476 :             findNamespace(atooid(PQgetvalue(res, i, i_pronamespace)));
    6974        9476 :         finfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_proacl));
    6975        9476 :         finfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
    6976        9476 :         finfo[i].dacl.privtype = 0;
    6977        9476 :         finfo[i].dacl.initprivs = NULL;
    6978        9476 :         finfo[i].rolname = getRoleName(PQgetvalue(res, i, i_proowner));
    6979        9476 :         finfo[i].lang = atooid(PQgetvalue(res, i, i_prolang));
    6980        9476 :         finfo[i].prorettype = atooid(PQgetvalue(res, i, i_prorettype));
    6981        9476 :         finfo[i].nargs = atoi(PQgetvalue(res, i, i_pronargs));
    6982        9476 :         if (finfo[i].nargs == 0)
    6983        2152 :             finfo[i].argtypes = NULL;
    6984             :         else
    6985             :         {
    6986        7324 :             finfo[i].argtypes = (Oid *) pg_malloc(finfo[i].nargs * sizeof(Oid));
    6987        7324 :             parseOidArray(PQgetvalue(res, i, i_proargtypes),
    6988        7324 :                           finfo[i].argtypes, finfo[i].nargs);
    6989             :         }
    6990        9476 :         finfo[i].postponed_def = false; /* might get set during sort */
    6991             : 
    6992             :         /* Decide whether we want to dump it */
    6993        9476 :         selectDumpableObject(&(finfo[i].dobj), fout);
    6994             : 
    6995             :         /* Mark whether function has an ACL */
    6996        9476 :         if (!PQgetisnull(res, i, i_proacl))
    6997         292 :             finfo[i].dobj.components |= DUMP_COMPONENT_ACL;
    6998             :     }
    6999             : 
    7000         364 :     PQclear(res);
    7001             : 
    7002         364 :     destroyPQExpBuffer(query);
    7003         364 : }
    7004             : 
    7005             : /*
    7006             :  * getRelationStatistics
    7007             :  *    register the statistics object as a dependent of the relation.
    7008             :  *
    7009             :  * reltuples is passed as a string to avoid complexities in converting from/to
    7010             :  * floating point.
    7011             :  */
    7012             : static RelStatsInfo *
    7013       19722 : getRelationStatistics(Archive *fout, DumpableObject *rel, int32 relpages,
    7014             :                       char *reltuples, int32 relallvisible,
    7015             :                       int32 relallfrozen, char relkind,
    7016             :                       char **indAttNames, int nindAttNames)
    7017             : {
    7018       19722 :     if (!fout->dopt->dumpStatistics)
    7019       12072 :         return NULL;
    7020             : 
    7021        7650 :     if ((relkind == RELKIND_RELATION) ||
    7022        3210 :         (relkind == RELKIND_PARTITIONED_TABLE) ||
    7023        1956 :         (relkind == RELKIND_INDEX) ||
    7024        1284 :         (relkind == RELKIND_PARTITIONED_INDEX) ||
    7025         568 :         (relkind == RELKIND_MATVIEW ||
    7026             :          relkind == RELKIND_FOREIGN_TABLE))
    7027             :     {
    7028        7152 :         RelStatsInfo *info = pg_malloc0(sizeof(RelStatsInfo));
    7029        7152 :         DumpableObject *dobj = &info->dobj;
    7030             : 
    7031        7152 :         dobj->objType = DO_REL_STATS;
    7032        7152 :         dobj->catId.tableoid = 0;
    7033        7152 :         dobj->catId.oid = 0;
    7034        7152 :         AssignDumpId(dobj);
    7035        7152 :         dobj->dependencies = (DumpId *) pg_malloc(sizeof(DumpId));
    7036        7152 :         dobj->dependencies[0] = rel->dumpId;
    7037        7152 :         dobj->nDeps = 1;
    7038        7152 :         dobj->allocDeps = 1;
    7039        7152 :         dobj->components |= DUMP_COMPONENT_STATISTICS;
    7040        7152 :         dobj->name = pg_strdup(rel->name);
    7041        7152 :         dobj->namespace = rel->namespace;
    7042        7152 :         info->relpages = relpages;
    7043        7152 :         info->reltuples = pstrdup(reltuples);
    7044        7152 :         info->relallvisible = relallvisible;
    7045        7152 :         info->relallfrozen = relallfrozen;
    7046        7152 :         info->relkind = relkind;
    7047        7152 :         info->indAttNames = indAttNames;
    7048        7152 :         info->nindAttNames = nindAttNames;
    7049             : 
    7050             :         /*
    7051             :          * Ordinarily, stats go in SECTION_DATA for tables and
    7052             :          * SECTION_POST_DATA for indexes.
    7053             :          *
    7054             :          * However, the section may be updated later for materialized view
    7055             :          * stats. REFRESH MATERIALIZED VIEW replaces the storage and resets
    7056             :          * the stats, so the stats must be restored after the data. Also, the
    7057             :          * materialized view definition may be postponed to SECTION_POST_DATA
    7058             :          * (see repairMatViewBoundaryMultiLoop()).
    7059             :          */
    7060        7152 :         switch (info->relkind)
    7061             :         {
    7062        5226 :             case RELKIND_RELATION:
    7063             :             case RELKIND_PARTITIONED_TABLE:
    7064             :             case RELKIND_MATVIEW:
    7065             :             case RELKIND_FOREIGN_TABLE:
    7066        5226 :                 info->section = SECTION_DATA;
    7067        5226 :                 break;
    7068        1926 :             case RELKIND_INDEX:
    7069             :             case RELKIND_PARTITIONED_INDEX:
    7070        1926 :                 info->section = SECTION_POST_DATA;
    7071        1926 :                 break;
    7072           0 :             default:
    7073           0 :                 pg_fatal("cannot dump statistics for relation kind \"%c\"",
    7074             :                          info->relkind);
    7075             :         }
    7076             : 
    7077        7152 :         return info;
    7078             :     }
    7079         498 :     return NULL;
    7080             : }
    7081             : 
    7082             : /*
    7083             :  * getTables
    7084             :  *    read all the tables (no indexes) in the system catalogs,
    7085             :  *    and return them as an array of TableInfo structures
    7086             :  *
    7087             :  * *numTables is set to the number of tables read in
    7088             :  */
    7089             : TableInfo *
    7090         366 : getTables(Archive *fout, int *numTables)
    7091             : {
    7092         366 :     DumpOptions *dopt = fout->dopt;
    7093             :     PGresult   *res;
    7094             :     int         ntups;
    7095             :     int         i;
    7096         366 :     PQExpBuffer query = createPQExpBuffer();
    7097             :     TableInfo  *tblinfo;
    7098             :     int         i_reltableoid;
    7099             :     int         i_reloid;
    7100             :     int         i_relname;
    7101             :     int         i_relnamespace;
    7102             :     int         i_relkind;
    7103             :     int         i_reltype;
    7104             :     int         i_relowner;
    7105             :     int         i_relchecks;
    7106             :     int         i_relhasindex;
    7107             :     int         i_relhasrules;
    7108             :     int         i_relpages;
    7109             :     int         i_reltuples;
    7110             :     int         i_relallvisible;
    7111             :     int         i_relallfrozen;
    7112             :     int         i_toastpages;
    7113             :     int         i_owning_tab;
    7114             :     int         i_owning_col;
    7115             :     int         i_reltablespace;
    7116             :     int         i_relhasoids;
    7117             :     int         i_relhastriggers;
    7118             :     int         i_relpersistence;
    7119             :     int         i_relispopulated;
    7120             :     int         i_relreplident;
    7121             :     int         i_relrowsec;
    7122             :     int         i_relforcerowsec;
    7123             :     int         i_relfrozenxid;
    7124             :     int         i_toastfrozenxid;
    7125             :     int         i_toastoid;
    7126             :     int         i_relminmxid;
    7127             :     int         i_toastminmxid;
    7128             :     int         i_reloptions;
    7129             :     int         i_checkoption;
    7130             :     int         i_toastreloptions;
    7131             :     int         i_reloftype;
    7132             :     int         i_foreignserver;
    7133             :     int         i_amname;
    7134             :     int         i_is_identity_sequence;
    7135             :     int         i_relacl;
    7136             :     int         i_acldefault;
    7137             :     int         i_ispartition;
    7138             : 
    7139             :     /*
    7140             :      * Find all the tables and table-like objects.
    7141             :      *
    7142             :      * We must fetch all tables in this phase because otherwise we cannot
    7143             :      * correctly identify inherited columns, owned sequences, etc.
    7144             :      *
    7145             :      * We include system catalogs, so that we can work if a user table is
    7146             :      * defined to inherit from a system catalog (pretty weird, but...)
    7147             :      *
    7148             :      * Note: in this phase we should collect only a minimal amount of
    7149             :      * information about each table, basically just enough to decide if it is
    7150             :      * interesting.  In particular, since we do not yet have lock on any user
    7151             :      * table, we MUST NOT invoke any server-side data collection functions
    7152             :      * (for instance, pg_get_partkeydef()).  Those are likely to fail or give
    7153             :      * wrong answers if any concurrent DDL is happening.
    7154             :      */
    7155             : 
    7156         366 :     appendPQExpBufferStr(query,
    7157             :                          "SELECT c.tableoid, c.oid, c.relname, "
    7158             :                          "c.relnamespace, c.relkind, c.reltype, "
    7159             :                          "c.relowner, "
    7160             :                          "c.relchecks, "
    7161             :                          "c.relhasindex, c.relhasrules, c.relpages, "
    7162             :                          "c.reltuples, c.relallvisible, ");
    7163             : 
    7164         366 :     if (fout->remoteVersion >= 180000)
    7165         366 :         appendPQExpBufferStr(query, "c.relallfrozen, ");
    7166             :     else
    7167           0 :         appendPQExpBufferStr(query, "0 AS relallfrozen, ");
    7168             : 
    7169         366 :     appendPQExpBufferStr(query,
    7170             :                          "c.relhastriggers, c.relpersistence, "
    7171             :                          "c.reloftype, "
    7172             :                          "c.relacl, "
    7173             :                          "acldefault(CASE WHEN c.relkind = " CppAsString2(RELKIND_SEQUENCE)
    7174             :                          " THEN 's'::\"char\" ELSE 'r'::\"char\" END, c.relowner) AS acldefault, "
    7175             :                          "CASE WHEN c.relkind = " CppAsString2(RELKIND_FOREIGN_TABLE) " THEN "
    7176             :                          "(SELECT ftserver FROM pg_catalog.pg_foreign_table WHERE ftrelid = c.oid) "
    7177             :                          "ELSE 0 END AS foreignserver, "
    7178             :                          "c.relfrozenxid, tc.relfrozenxid AS tfrozenxid, "
    7179             :                          "tc.oid AS toid, "
    7180             :                          "tc.relpages AS toastpages, "
    7181             :                          "tc.reloptions AS toast_reloptions, "
    7182             :                          "d.refobjid AS owning_tab, "
    7183             :                          "d.refobjsubid AS owning_col, "
    7184             :                          "tsp.spcname AS reltablespace, ");
    7185             : 
    7186         366 :     if (fout->remoteVersion >= 120000)
    7187         366 :         appendPQExpBufferStr(query,
    7188             :                              "false AS relhasoids, ");
    7189             :     else
    7190           0 :         appendPQExpBufferStr(query,
    7191             :                              "c.relhasoids, ");
    7192             : 
    7193         366 :     if (fout->remoteVersion >= 90300)
    7194         366 :         appendPQExpBufferStr(query,
    7195             :                              "c.relispopulated, ");
    7196             :     else
    7197           0 :         appendPQExpBufferStr(query,
    7198             :                              "'t' as relispopulated, ");
    7199             : 
    7200         366 :     if (fout->remoteVersion >= 90400)
    7201         366 :         appendPQExpBufferStr(query,
    7202             :                              "c.relreplident, ");
    7203             :     else
    7204           0 :         appendPQExpBufferStr(query,
    7205             :                              "'d' AS relreplident, ");
    7206             : 
    7207         366 :     if (fout->remoteVersion >= 90500)
    7208         366 :         appendPQExpBufferStr(query,
    7209             :                              "c.relrowsecurity, c.relforcerowsecurity, ");
    7210             :     else
    7211           0 :         appendPQExpBufferStr(query,
    7212             :                              "false AS relrowsecurity, "
    7213             :                              "false AS relforcerowsecurity, ");
    7214             : 
    7215         366 :     if (fout->remoteVersion >= 90300)
    7216         366 :         appendPQExpBufferStr(query,
    7217             :                              "c.relminmxid, tc.relminmxid AS tminmxid, ");
    7218             :     else
    7219           0 :         appendPQExpBufferStr(query,
    7220             :                              "0 AS relminmxid, 0 AS tminmxid, ");
    7221             : 
    7222         366 :     if (fout->remoteVersion >= 90300)
    7223         366 :         appendPQExpBufferStr(query,
    7224             :                              "array_remove(array_remove(c.reloptions,'check_option=local'),'check_option=cascaded') AS reloptions, "
    7225             :                              "CASE WHEN 'check_option=local' = ANY (c.reloptions) THEN 'LOCAL'::text "
    7226             :                              "WHEN 'check_option=cascaded' = ANY (c.reloptions) THEN 'CASCADED'::text ELSE NULL END AS checkoption, ");
    7227             :     else
    7228           0 :         appendPQExpBufferStr(query,
    7229             :                              "c.reloptions, NULL AS checkoption, ");
    7230             : 
    7231         366 :     if (fout->remoteVersion >= 90600)
    7232         366 :         appendPQExpBufferStr(query,
    7233             :                              "am.amname, ");
    7234             :     else
    7235           0 :         appendPQExpBufferStr(query,
    7236             :                              "NULL AS amname, ");
    7237             : 
    7238         366 :     if (fout->remoteVersion >= 90600)
    7239         366 :         appendPQExpBufferStr(query,
    7240             :                              "(d.deptype = 'i') IS TRUE AS is_identity_sequence, ");
    7241             :     else
    7242           0 :         appendPQExpBufferStr(query,
    7243             :                              "false AS is_identity_sequence, ");
    7244             : 
    7245         366 :     if (fout->remoteVersion >= 100000)
    7246         366 :         appendPQExpBufferStr(query,
    7247             :                              "c.relispartition AS ispartition ");
    7248             :     else
    7249           0 :         appendPQExpBufferStr(query,
    7250             :                              "false AS ispartition ");
    7251             : 
    7252             :     /*
    7253             :      * Left join to pg_depend to pick up dependency info linking sequences to
    7254             :      * their owning column, if any (note this dependency is AUTO except for
    7255             :      * identity sequences, where it's INTERNAL). Also join to pg_tablespace to
    7256             :      * collect the spcname.
    7257             :      */
    7258         366 :     appendPQExpBufferStr(query,
    7259             :                          "\nFROM pg_class c\n"
    7260             :                          "LEFT JOIN pg_depend d ON "
    7261             :                          "(c.relkind = " CppAsString2(RELKIND_SEQUENCE) " AND "
    7262             :                          "d.classid = 'pg_class'::regclass AND d.objid = c.oid AND "
    7263             :                          "d.objsubid = 0 AND "
    7264             :                          "d.refclassid = 'pg_class'::regclass AND d.deptype IN ('a', 'i'))\n"
    7265             :                          "LEFT JOIN pg_tablespace tsp ON (tsp.oid = c.reltablespace)\n");
    7266             : 
    7267             :     /*
    7268             :      * In 9.6 and up, left join to pg_am to pick up the amname.
    7269             :      */
    7270         366 :     if (fout->remoteVersion >= 90600)
    7271         366 :         appendPQExpBufferStr(query,
    7272             :                              "LEFT JOIN pg_am am ON (c.relam = am.oid)\n");
    7273             : 
    7274             :     /*
    7275             :      * We purposefully ignore toast OIDs for partitioned tables; the reason is
    7276             :      * that versions 10 and 11 have them, but later versions do not, so
    7277             :      * emitting them causes the upgrade to fail.
    7278             :      */
    7279         366 :     appendPQExpBufferStr(query,
    7280             :                          "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid"
    7281             :                          " AND tc.relkind = " CppAsString2(RELKIND_TOASTVALUE)
    7282             :                          " AND c.relkind <> " CppAsString2(RELKIND_PARTITIONED_TABLE) ")\n");
    7283             : 
    7284             :     /*
    7285             :      * Restrict to interesting relkinds (in particular, not indexes).  Not all
    7286             :      * relkinds are possible in older servers, but it's not worth the trouble
    7287             :      * to emit a version-dependent list.
    7288             :      *
    7289             :      * Composite-type table entries won't be dumped as such, but we have to
    7290             :      * make a DumpableObject for them so that we can track dependencies of the
    7291             :      * composite type (pg_depend entries for columns of the composite type
    7292             :      * link to the pg_class entry not the pg_type entry).
    7293             :      */
    7294         366 :     appendPQExpBufferStr(query,
    7295             :                          "WHERE c.relkind IN ("
    7296             :                          CppAsString2(RELKIND_RELATION) ", "
    7297             :                          CppAsString2(RELKIND_SEQUENCE) ", "
    7298             :                          CppAsString2(RELKIND_VIEW) ", "
    7299             :                          CppAsString2(RELKIND_COMPOSITE_TYPE) ", "
    7300             :                          CppAsString2(RELKIND_MATVIEW) ", "
    7301             :                          CppAsString2(RELKIND_FOREIGN_TABLE) ", "
    7302             :                          CppAsString2(RELKIND_PARTITIONED_TABLE) ")\n"
    7303             :                          "ORDER BY c.oid");
    7304             : 
    7305         366 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    7306             : 
    7307         366 :     ntups = PQntuples(res);
    7308             : 
    7309         366 :     *numTables = ntups;
    7310             : 
    7311             :     /*
    7312             :      * Extract data from result and lock dumpable tables.  We do the locking
    7313             :      * before anything else, to minimize the window wherein a table could
    7314             :      * disappear under us.
    7315             :      *
    7316             :      * Note that we have to save info about all tables here, even when dumping
    7317             :      * only one, because we don't yet know which tables might be inheritance
    7318             :      * ancestors of the target table.
    7319             :      */
    7320         366 :     tblinfo = (TableInfo *) pg_malloc0(ntups * sizeof(TableInfo));
    7321             : 
    7322         366 :     i_reltableoid = PQfnumber(res, "tableoid");
    7323         366 :     i_reloid = PQfnumber(res, "oid");
    7324         366 :     i_relname = PQfnumber(res, "relname");
    7325         366 :     i_relnamespace = PQfnumber(res, "relnamespace");
    7326         366 :     i_relkind = PQfnumber(res, "relkind");
    7327         366 :     i_reltype = PQfnumber(res, "reltype");
    7328         366 :     i_relowner = PQfnumber(res, "relowner");
    7329         366 :     i_relchecks = PQfnumber(res, "relchecks");
    7330         366 :     i_relhasindex = PQfnumber(res, "relhasindex");
    7331         366 :     i_relhasrules = PQfnumber(res, "relhasrules");
    7332         366 :     i_relpages = PQfnumber(res, "relpages");
    7333         366 :     i_reltuples = PQfnumber(res, "reltuples");
    7334         366 :     i_relallvisible = PQfnumber(res, "relallvisible");
    7335         366 :     i_relallfrozen = PQfnumber(res, "relallfrozen");
    7336         366 :     i_toastpages = PQfnumber(res, "toastpages");
    7337         366 :     i_owning_tab = PQfnumber(res, "owning_tab");
    7338         366 :     i_owning_col = PQfnumber(res, "owning_col");
    7339         366 :     i_reltablespace = PQfnumber(res, "reltablespace");
    7340         366 :     i_relhasoids = PQfnumber(res, "relhasoids");
    7341         366 :     i_relhastriggers = PQfnumber(res, "relhastriggers");
    7342         366 :     i_relpersistence = PQfnumber(res, "relpersistence");
    7343         366 :     i_relispopulated = PQfnumber(res, "relispopulated");
    7344         366 :     i_relreplident = PQfnumber(res, "relreplident");
    7345         366 :     i_relrowsec = PQfnumber(res, "relrowsecurity");
    7346         366 :     i_relforcerowsec = PQfnumber(res, "relforcerowsecurity");
    7347         366 :     i_relfrozenxid = PQfnumber(res, "relfrozenxid");
    7348         366 :     i_toastfrozenxid = PQfnumber(res, "tfrozenxid");
    7349         366 :     i_toastoid = PQfnumber(res, "toid");
    7350         366 :     i_relminmxid = PQfnumber(res, "relminmxid");
    7351         366 :     i_toastminmxid = PQfnumber(res, "tminmxid");
    7352         366 :     i_reloptions = PQfnumber(res, "reloptions");
    7353         366 :     i_checkoption = PQfnumber(res, "checkoption");
    7354         366 :     i_toastreloptions = PQfnumber(res, "toast_reloptions");
    7355         366 :     i_reloftype = PQfnumber(res, "reloftype");
    7356         366 :     i_foreignserver = PQfnumber(res, "foreignserver");
    7357         366 :     i_amname = PQfnumber(res, "amname");
    7358         366 :     i_is_identity_sequence = PQfnumber(res, "is_identity_sequence");
    7359         366 :     i_relacl = PQfnumber(res, "relacl");
    7360         366 :     i_acldefault = PQfnumber(res, "acldefault");
    7361         366 :     i_ispartition = PQfnumber(res, "ispartition");
    7362             : 
    7363         366 :     if (dopt->lockWaitTimeout)
    7364             :     {
    7365             :         /*
    7366             :          * Arrange to fail instead of waiting forever for a table lock.
    7367             :          *
    7368             :          * NB: this coding assumes that the only queries issued within the
    7369             :          * following loop are LOCK TABLEs; else the timeout may be undesirably
    7370             :          * applied to other things too.
    7371             :          */
    7372           4 :         resetPQExpBuffer(query);
    7373           4 :         appendPQExpBufferStr(query, "SET statement_timeout = ");
    7374           4 :         appendStringLiteralConn(query, dopt->lockWaitTimeout, GetConnection(fout));
    7375           4 :         ExecuteSqlStatement(fout, query->data);
    7376             :     }
    7377             : 
    7378         366 :     resetPQExpBuffer(query);
    7379             : 
    7380       97364 :     for (i = 0; i < ntups; i++)
    7381             :     {
    7382       96998 :         int32       relallvisible = atoi(PQgetvalue(res, i, i_relallvisible));
    7383       96998 :         int32       relallfrozen = atoi(PQgetvalue(res, i, i_relallfrozen));
    7384             : 
    7385       96998 :         tblinfo[i].dobj.objType = DO_TABLE;
    7386       96998 :         tblinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_reltableoid));
    7387       96998 :         tblinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_reloid));
    7388       96998 :         AssignDumpId(&tblinfo[i].dobj);
    7389       96998 :         tblinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_relname));
    7390      193996 :         tblinfo[i].dobj.namespace =
    7391       96998 :             findNamespace(atooid(PQgetvalue(res, i, i_relnamespace)));
    7392       96998 :         tblinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_relacl));
    7393       96998 :         tblinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
    7394       96998 :         tblinfo[i].dacl.privtype = 0;
    7395       96998 :         tblinfo[i].dacl.initprivs = NULL;
    7396       96998 :         tblinfo[i].relkind = *(PQgetvalue(res, i, i_relkind));
    7397       96998 :         tblinfo[i].reltype = atooid(PQgetvalue(res, i, i_reltype));
    7398       96998 :         tblinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_relowner));
    7399       96998 :         tblinfo[i].ncheck = atoi(PQgetvalue(res, i, i_relchecks));
    7400       96998 :         tblinfo[i].hasindex = (strcmp(PQgetvalue(res, i, i_relhasindex), "t") == 0);
    7401       96998 :         tblinfo[i].hasrules = (strcmp(PQgetvalue(res, i, i_relhasrules), "t") == 0);
    7402       96998 :         tblinfo[i].relpages = atoi(PQgetvalue(res, i, i_relpages));
    7403       96998 :         if (PQgetisnull(res, i, i_toastpages))
    7404       77690 :             tblinfo[i].toastpages = 0;
    7405             :         else
    7406       19308 :             tblinfo[i].toastpages = atoi(PQgetvalue(res, i, i_toastpages));
    7407       96998 :         if (PQgetisnull(res, i, i_owning_tab))
    7408             :         {
    7409       96150 :             tblinfo[i].owning_tab = InvalidOid;
    7410       96150 :             tblinfo[i].owning_col = 0;
    7411             :         }
    7412             :         else
    7413             :         {
    7414         848 :             tblinfo[i].owning_tab = atooid(PQgetvalue(res, i, i_owning_tab));
    7415         848 :             tblinfo[i].owning_col = atoi(PQgetvalue(res, i, i_owning_col));
    7416             :         }
    7417       96998 :         tblinfo[i].reltablespace = pg_strdup(PQgetvalue(res, i, i_reltablespace));
    7418       96998 :         tblinfo[i].hasoids = (strcmp(PQgetvalue(res, i, i_relhasoids), "t") == 0);
    7419       96998 :         tblinfo[i].hastriggers = (strcmp(PQgetvalue(res, i, i_relhastriggers), "t") == 0);
    7420       96998 :         tblinfo[i].relpersistence = *(PQgetvalue(res, i, i_relpersistence));
    7421       96998 :         tblinfo[i].relispopulated = (strcmp(PQgetvalue(res, i, i_relispopulated), "t") == 0);
    7422       96998 :         tblinfo[i].relreplident = *(PQgetvalue(res, i, i_relreplident));
    7423       96998 :         tblinfo[i].rowsec = (strcmp(PQgetvalue(res, i, i_relrowsec), "t") == 0);
    7424       96998 :         tblinfo[i].forcerowsec = (strcmp(PQgetvalue(res, i, i_relforcerowsec), "t") == 0);
    7425       96998 :         tblinfo[i].frozenxid = atooid(PQgetvalue(res, i, i_relfrozenxid));
    7426       96998 :         tblinfo[i].toast_frozenxid = atooid(PQgetvalue(res, i, i_toastfrozenxid));
    7427       96998 :         tblinfo[i].toast_oid = atooid(PQgetvalue(res, i, i_toastoid));
    7428       96998 :         tblinfo[i].minmxid = atooid(PQgetvalue(res, i, i_relminmxid));
    7429       96998 :         tblinfo[i].toast_minmxid = atooid(PQgetvalue(res, i, i_toastminmxid));
    7430       96998 :         tblinfo[i].reloptions = pg_strdup(PQgetvalue(res, i, i_reloptions));
    7431       96998 :         if (PQgetisnull(res, i, i_checkoption))
    7432       96900 :             tblinfo[i].checkoption = NULL;
    7433             :         else
    7434          98 :             tblinfo[i].checkoption = pg_strdup(PQgetvalue(res, i, i_checkoption));
    7435       96998 :         tblinfo[i].toast_reloptions = pg_strdup(PQgetvalue(res, i, i_toastreloptions));
    7436       96998 :         tblinfo[i].reloftype = atooid(PQgetvalue(res, i, i_reloftype));
    7437       96998 :         tblinfo[i].foreign_server = atooid(PQgetvalue(res, i, i_foreignserver));
    7438       96998 :         if (PQgetisnull(res, i, i_amname))
    7439       57546 :             tblinfo[i].amname = NULL;
    7440             :         else
    7441       39452 :             tblinfo[i].amname = pg_strdup(PQgetvalue(res, i, i_amname));
    7442       96998 :         tblinfo[i].is_identity_sequence = (strcmp(PQgetvalue(res, i, i_is_identity_sequence), "t") == 0);
    7443       96998 :         tblinfo[i].ispartition = (strcmp(PQgetvalue(res, i, i_ispartition), "t") == 0);
    7444             : 
    7445             :         /* other fields were zeroed above */
    7446             : 
    7447             :         /*
    7448             :          * Decide whether we want to dump this table.
    7449             :          */
    7450       96998 :         if (tblinfo[i].relkind == RELKIND_COMPOSITE_TYPE)
    7451         372 :             tblinfo[i].dobj.dump = DUMP_COMPONENT_NONE;
    7452             :         else
    7453       96626 :             selectDumpableTable(&tblinfo[i], fout);
    7454             : 
    7455             :         /*
    7456             :          * Now, consider the table "interesting" if we need to dump its
    7457             :          * definition, data or its statistics.  Later on, we'll skip a lot of
    7458             :          * data collection for uninteresting tables.
    7459             :          *
    7460             :          * Note: the "interesting" flag will also be set by flagInhTables for
    7461             :          * parents of interesting tables, so that we collect necessary
    7462             :          * inheritance info even when the parents are not themselves being
    7463             :          * dumped.  This is the main reason why we need an "interesting" flag
    7464             :          * that's separate from the components-to-dump bitmask.
    7465             :          */
    7466       96998 :         tblinfo[i].interesting = (tblinfo[i].dobj.dump &
    7467             :                                   (DUMP_COMPONENT_DEFINITION |
    7468             :                                    DUMP_COMPONENT_DATA |
    7469       96998 :                                    DUMP_COMPONENT_STATISTICS)) != 0;
    7470             : 
    7471       96998 :         tblinfo[i].dummy_view = false;  /* might get set during sort */
    7472       96998 :         tblinfo[i].postponed_def = false;   /* might get set during sort */
    7473             : 
    7474             :         /* Tables have data */
    7475       96998 :         tblinfo[i].dobj.components |= DUMP_COMPONENT_DATA;
    7476             : 
    7477             :         /* Mark whether table has an ACL */
    7478       96998 :         if (!PQgetisnull(res, i, i_relacl))
    7479       76934 :             tblinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
    7480       96998 :         tblinfo[i].hascolumnACLs = false;   /* may get set later */
    7481             : 
    7482             :         /* Add statistics */
    7483       96998 :         if (tblinfo[i].interesting)
    7484             :         {
    7485             :             RelStatsInfo *stats;
    7486             : 
    7487       28884 :             stats = getRelationStatistics(fout, &tblinfo[i].dobj,
    7488       14442 :                                           tblinfo[i].relpages,
    7489             :                                           PQgetvalue(res, i, i_reltuples),
    7490             :                                           relallvisible, relallfrozen,
    7491       14442 :                                           tblinfo[i].relkind, NULL, 0);
    7492       14442 :             if (tblinfo[i].relkind == RELKIND_MATVIEW)
    7493         920 :                 tblinfo[i].stats = stats;
    7494             :         }
    7495             : 
    7496             :         /*
    7497             :          * Read-lock target tables to make sure they aren't DROPPED or altered
    7498             :          * in schema before we get around to dumping them.
    7499             :          *
    7500             :          * Note that we don't explicitly lock parents of the target tables; we
    7501             :          * assume our lock on the child is enough to prevent schema
    7502             :          * alterations to parent tables.
    7503             :          *
    7504             :          * NOTE: it'd be kinda nice to lock other relations too, not only
    7505             :          * plain or partitioned tables, but the backend doesn't presently
    7506             :          * allow that.
    7507             :          *
    7508             :          * We only need to lock the table for certain components; see
    7509             :          * pg_dump.h
    7510             :          */
    7511       96998 :         if ((tblinfo[i].dobj.dump & DUMP_COMPONENTS_REQUIRING_LOCK) &&
    7512       14442 :             (tblinfo[i].relkind == RELKIND_RELATION ||
    7513        4110 :              tblinfo[i].relkind == RELKIND_PARTITIONED_TABLE))
    7514             :         {
    7515             :             /*
    7516             :              * Tables are locked in batches.  When dumping from a remote
    7517             :              * server this can save a significant amount of time by reducing
    7518             :              * the number of round trips.
    7519             :              */
    7520       11544 :             if (query->len == 0)
    7521         238 :                 appendPQExpBuffer(query, "LOCK TABLE %s",
    7522         238 :                                   fmtQualifiedDumpable(&tblinfo[i]));
    7523             :             else
    7524             :             {
    7525       11306 :                 appendPQExpBuffer(query, ", %s",
    7526       11306 :                                   fmtQualifiedDumpable(&tblinfo[i]));
    7527             : 
    7528             :                 /* Arbitrarily end a batch when query length reaches 100K. */
    7529       11306 :                 if (query->len >= 100000)
    7530             :                 {
    7531             :                     /* Lock another batch of tables. */
    7532           0 :                     appendPQExpBufferStr(query, " IN ACCESS SHARE MODE");
    7533           0 :                     ExecuteSqlStatement(fout, query->data);
    7534           0 :                     resetPQExpBuffer(query);
    7535             :                 }
    7536             :             }
    7537             :         }
    7538             :     }
    7539             : 
    7540         366 :     if (query->len != 0)
    7541             :     {
    7542             :         /* Lock the tables in the last batch. */
    7543         238 :         appendPQExpBufferStr(query, " IN ACCESS SHARE MODE");
    7544         238 :         ExecuteSqlStatement(fout, query->data);
    7545             :     }
    7546             : 
    7547         364 :     if (dopt->lockWaitTimeout)
    7548             :     {
    7549           4 :         ExecuteSqlStatement(fout, "SET statement_timeout = 0");
    7550             :     }
    7551             : 
    7552         364 :     PQclear(res);
    7553             : 
    7554         364 :     destroyPQExpBuffer(query);
    7555             : 
    7556         364 :     return tblinfo;
    7557             : }
    7558             : 
    7559             : /*
    7560             :  * getOwnedSeqs
    7561             :  *    identify owned sequences and mark them as dumpable if owning table is
    7562             :  *
    7563             :  * We used to do this in getTables(), but it's better to do it after the
    7564             :  * index used by findTableByOid() has been set up.
    7565             :  */
    7566             : void
    7567         364 : getOwnedSeqs(Archive *fout, TableInfo tblinfo[], int numTables)
    7568             : {
    7569             :     int         i;
    7570             : 
    7571             :     /*
    7572             :      * Force sequences that are "owned" by table columns to be dumped whenever
    7573             :      * their owning table is being dumped.
    7574             :      */
    7575       96818 :     for (i = 0; i < numTables; i++)
    7576             :     {
    7577       96454 :         TableInfo  *seqinfo = &tblinfo[i];
    7578             :         TableInfo  *owning_tab;
    7579             : 
    7580       96454 :         if (!OidIsValid(seqinfo->owning_tab))
    7581       95612 :             continue;           /* not an owned sequence */
    7582             : 
    7583         842 :         owning_tab = findTableByOid(seqinfo->owning_tab);
    7584         842 :         if (owning_tab == NULL)
    7585           0 :             pg_fatal("failed sanity check, parent table with OID %u of sequence with OID %u not found",
    7586             :                      seqinfo->owning_tab, seqinfo->dobj.catId.oid);
    7587             : 
    7588             :         /*
    7589             :          * For an identity sequence, dump exactly the same components for the
    7590             :          * sequence as for the owning table.  This is important because we
    7591             :          * treat the identity sequence as an integral part of the table.  For
    7592             :          * example, there is not any DDL command that allows creation of such
    7593             :          * a sequence independently of the table.
    7594             :          *
    7595             :          * For other owned sequences such as serial sequences, we need to dump
    7596             :          * the components that are being dumped for the table and any
    7597             :          * components that the sequence is explicitly marked with.
    7598             :          *
    7599             :          * We can't simply use the set of components which are being dumped
    7600             :          * for the table as the table might be in an extension (and only the
    7601             :          * non-extension components, eg: ACLs if changed, security labels, and
    7602             :          * policies, are being dumped) while the sequence is not (and
    7603             :          * therefore the definition and other components should also be
    7604             :          * dumped).
    7605             :          *
    7606             :          * If the sequence is part of the extension then it should be properly
    7607             :          * marked by checkExtensionMembership() and this will be a no-op as
    7608             :          * the table will be equivalently marked.
    7609             :          */
    7610         842 :         if (seqinfo->is_identity_sequence)
    7611         404 :             seqinfo->dobj.dump = owning_tab->dobj.dump;
    7612             :         else
    7613         438 :             seqinfo->dobj.dump |= owning_tab->dobj.dump;
    7614             : 
    7615             :         /* Make sure that necessary data is available if we're dumping it */
    7616         842 :         if (seqinfo->dobj.dump != DUMP_COMPONENT_NONE)
    7617             :         {
    7618         650 :             seqinfo->interesting = true;
    7619         650 :             owning_tab->interesting = true;
    7620             :         }
    7621             :     }
    7622         364 : }
    7623             : 
    7624             : /*
    7625             :  * getInherits
    7626             :  *    read all the inheritance information
    7627             :  * from the system catalogs return them in the InhInfo* structure
    7628             :  *
    7629             :  * numInherits is set to the number of pairs read in
    7630             :  */
    7631             : InhInfo *
    7632         364 : getInherits(Archive *fout, int *numInherits)
    7633             : {
    7634             :     PGresult   *res;
    7635             :     int         ntups;
    7636             :     int         i;
    7637         364 :     PQExpBuffer query = createPQExpBuffer();
    7638             :     InhInfo    *inhinfo;
    7639             : 
    7640             :     int         i_inhrelid;
    7641             :     int         i_inhparent;
    7642             : 
    7643             :     /* find all the inheritance information */
    7644         364 :     appendPQExpBufferStr(query, "SELECT inhrelid, inhparent FROM pg_inherits");
    7645             : 
    7646         364 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    7647             : 
    7648         364 :     ntups = PQntuples(res);
    7649             : 
    7650         364 :     *numInherits = ntups;
    7651             : 
    7652         364 :     inhinfo = (InhInfo *) pg_malloc(ntups * sizeof(InhInfo));
    7653             : 
    7654         364 :     i_inhrelid = PQfnumber(res, "inhrelid");
    7655         364 :     i_inhparent = PQfnumber(res, "inhparent");
    7656             : 
    7657        7230 :     for (i = 0; i < ntups; i++)
    7658             :     {
    7659        6866 :         inhinfo[i].inhrelid = atooid(PQgetvalue(res, i, i_inhrelid));
    7660        6866 :         inhinfo[i].inhparent = atooid(PQgetvalue(res, i, i_inhparent));
    7661             :     }
    7662             : 
    7663         364 :     PQclear(res);
    7664             : 
    7665         364 :     destroyPQExpBuffer(query);
    7666             : 
    7667         364 :     return inhinfo;
    7668             : }
    7669             : 
    7670             : /*
    7671             :  * getPartitioningInfo
    7672             :  *    get information about partitioning
    7673             :  *
    7674             :  * For the most part, we only collect partitioning info about tables we
    7675             :  * intend to dump.  However, this function has to consider all partitioned
    7676             :  * tables in the database, because we need to know about parents of partitions
    7677             :  * we are going to dump even if the parents themselves won't be dumped.
    7678             :  *
    7679             :  * Specifically, what we need to know is whether each partitioned table
    7680             :  * has an "unsafe" partitioning scheme that requires us to force
    7681             :  * load-via-partition-root mode for its children.  Currently the only case
    7682             :  * for which we force that is hash partitioning on enum columns, since the
    7683             :  * hash codes depend on enum value OIDs which won't be replicated across
    7684             :  * dump-and-reload.  There are other cases in which load-via-partition-root
    7685             :  * might be necessary, but we expect users to cope with them.
    7686             :  */
    7687             : void
    7688         364 : getPartitioningInfo(Archive *fout)
    7689             : {
    7690             :     PQExpBuffer query;
    7691             :     PGresult   *res;
    7692             :     int         ntups;
    7693             : 
    7694             :     /* hash partitioning didn't exist before v11 */
    7695         364 :     if (fout->remoteVersion < 110000)
    7696           0 :         return;
    7697             :     /* needn't bother if not dumping data */
    7698         364 :     if (!fout->dopt->dumpData)
    7699          80 :         return;
    7700             : 
    7701         284 :     query = createPQExpBuffer();
    7702             : 
    7703             :     /*
    7704             :      * Unsafe partitioning schemes are exactly those for which hash enum_ops
    7705             :      * appears among the partition opclasses.  We needn't check partstrat.
    7706             :      *
    7707             :      * Note that this query may well retrieve info about tables we aren't
    7708             :      * going to dump and hence have no lock on.  That's okay since we need not
    7709             :      * invoke any unsafe server-side functions.
    7710             :      */
    7711         284 :     appendPQExpBufferStr(query,
    7712             :                          "SELECT partrelid FROM pg_partitioned_table WHERE\n"
    7713             :                          "(SELECT c.oid FROM pg_opclass c JOIN pg_am a "
    7714             :                          "ON c.opcmethod = a.oid\n"
    7715             :                          "WHERE opcname = 'enum_ops' "
    7716             :                          "AND opcnamespace = 'pg_catalog'::regnamespace "
    7717             :                          "AND amname = 'hash') = ANY(partclass)");
    7718             : 
    7719         284 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    7720             : 
    7721         284 :     ntups = PQntuples(res);
    7722             : 
    7723         376 :     for (int i = 0; i < ntups; i++)
    7724             :     {
    7725          92 :         Oid         tabrelid = atooid(PQgetvalue(res, i, 0));
    7726             :         TableInfo  *tbinfo;
    7727             : 
    7728          92 :         tbinfo = findTableByOid(tabrelid);
    7729          92 :         if (tbinfo == NULL)
    7730           0 :             pg_fatal("failed sanity check, table OID %u appearing in pg_partitioned_table not found",
    7731             :                      tabrelid);
    7732          92 :         tbinfo->unsafe_partitions = true;
    7733             :     }
    7734             : 
    7735         284 :     PQclear(res);
    7736             : 
    7737         284 :     destroyPQExpBuffer(query);
    7738             : }
    7739             : 
    7740             : /*
    7741             :  * getIndexes
    7742             :  *    get information about every index on a dumpable table
    7743             :  *
    7744             :  * Note: index data is not returned directly to the caller, but it
    7745             :  * does get entered into the DumpableObject tables.
    7746             :  */
    7747             : void
    7748         364 : getIndexes(Archive *fout, TableInfo tblinfo[], int numTables)
    7749             : {
    7750         364 :     PQExpBuffer query = createPQExpBuffer();
    7751         364 :     PQExpBuffer tbloids = createPQExpBuffer();
    7752             :     PGresult   *res;
    7753             :     int         ntups;
    7754             :     int         curtblindx;
    7755             :     IndxInfo   *indxinfo;
    7756             :     int         i_tableoid,
    7757             :                 i_oid,
    7758             :                 i_indrelid,
    7759             :                 i_indexname,
    7760             :                 i_relpages,
    7761             :                 i_reltuples,
    7762             :                 i_relallvisible,
    7763             :                 i_relallfrozen,
    7764             :                 i_parentidx,
    7765             :                 i_indexdef,
    7766             :                 i_indnkeyatts,
    7767             :                 i_indnatts,
    7768             :                 i_indkey,
    7769             :                 i_indisclustered,
    7770             :                 i_indisreplident,
    7771             :                 i_indnullsnotdistinct,
    7772             :                 i_contype,
    7773             :                 i_conname,
    7774             :                 i_condeferrable,
    7775             :                 i_condeferred,
    7776             :                 i_conperiod,
    7777             :                 i_contableoid,
    7778             :                 i_conoid,
    7779             :                 i_condef,
    7780             :                 i_indattnames,
    7781             :                 i_tablespace,
    7782             :                 i_indreloptions,
    7783             :                 i_indstatcols,
    7784             :                 i_indstatvals;
    7785             : 
    7786             :     /*
    7787             :      * We want to perform just one query against pg_index.  However, we
    7788             :      * mustn't try to select every row of the catalog and then sort it out on
    7789             :      * the client side, because some of the server-side functions we need
    7790             :      * would be unsafe to apply to tables we don't have lock on.  Hence, we
    7791             :      * build an array of the OIDs of tables we care about (and now have lock
    7792             :      * on!), and use a WHERE clause to constrain which rows are selected.
    7793             :      */
    7794         364 :     appendPQExpBufferChar(tbloids, '{');
    7795       96818 :     for (int i = 0; i < numTables; i++)
    7796             :     {
    7797       96454 :         TableInfo  *tbinfo = &tblinfo[i];
    7798             : 
    7799       96454 :         if (!tbinfo->hasindex)
    7800       68326 :             continue;
    7801             : 
    7802             :         /*
    7803             :          * We can ignore indexes of uninteresting tables.
    7804             :          */
    7805       28128 :         if (!tbinfo->interesting)
    7806       24070 :             continue;
    7807             : 
    7808             :         /* OK, we need info for this table */
    7809        4058 :         if (tbloids->len > 1) /* do we have more than the '{'? */
    7810        3896 :             appendPQExpBufferChar(tbloids, ',');
    7811        4058 :         appendPQExpBuffer(tbloids, "%u", tbinfo->dobj.catId.oid);
    7812             :     }
    7813         364 :     appendPQExpBufferChar(tbloids, '}');
    7814             : 
    7815         364 :     appendPQExpBufferStr(query,
    7816             :                          "SELECT t.tableoid, t.oid, i.indrelid, "
    7817             :                          "t.relname AS indexname, "
    7818             :                          "t.relpages, t.reltuples, t.relallvisible, ");
    7819             : 
    7820         364 :     if (fout->remoteVersion >= 180000)
    7821         364 :         appendPQExpBufferStr(query, "t.relallfrozen, ");
    7822             :     else
    7823           0 :         appendPQExpBufferStr(query, "0 AS relallfrozen, ");
    7824             : 
    7825         364 :     appendPQExpBufferStr(query,
    7826             :                          "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
    7827             :                          "i.indkey, i.indisclustered, "
    7828             :                          "c.contype, c.conname, "
    7829             :                          "c.condeferrable, c.condeferred, "
    7830             :                          "c.tableoid AS contableoid, "
    7831             :                          "c.oid AS conoid, "
    7832             :                          "pg_catalog.pg_get_constraintdef(c.oid, false) AS condef, "
    7833             :                          "CASE WHEN i.indexprs IS NOT NULL THEN "
    7834             :                          "(SELECT pg_catalog.array_agg(attname ORDER BY attnum)"
    7835             :                          "  FROM pg_catalog.pg_attribute "
    7836             :                          "  WHERE attrelid = i.indexrelid) "
    7837             :                          "ELSE NULL END AS indattnames, "
    7838             :                          "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
    7839             :                          "t.reloptions AS indreloptions, ");
    7840             : 
    7841             : 
    7842         364 :     if (fout->remoteVersion >= 90400)
    7843         364 :         appendPQExpBufferStr(query,
    7844             :                              "i.indisreplident, ");
    7845             :     else
    7846           0 :         appendPQExpBufferStr(query,
    7847             :                              "false AS indisreplident, ");
    7848             : 
    7849         364 :     if (fout->remoteVersion >= 110000)
    7850         364 :         appendPQExpBufferStr(query,
    7851             :                              "inh.inhparent AS parentidx, "
    7852             :                              "i.indnkeyatts AS indnkeyatts, "
    7853             :                              "i.indnatts AS indnatts, "
    7854             :                              "(SELECT pg_catalog.array_agg(attnum ORDER BY attnum) "
    7855             :                              "  FROM pg_catalog.pg_attribute "
    7856             :                              "  WHERE attrelid = i.indexrelid AND "
    7857             :                              "    attstattarget >= 0) AS indstatcols, "
    7858             :                              "(SELECT pg_catalog.array_agg(attstattarget ORDER BY attnum) "
    7859             :                              "  FROM pg_catalog.pg_attribute "
    7860             :                              "  WHERE attrelid = i.indexrelid AND "
    7861             :                              "    attstattarget >= 0) AS indstatvals, ");
    7862             :     else
    7863           0 :         appendPQExpBufferStr(query,
    7864             :                              "0 AS parentidx, "
    7865             :                              "i.indnatts AS indnkeyatts, "
    7866             :                              "i.indnatts AS indnatts, "
    7867             :                              "'' AS indstatcols, "
    7868             :                              "'' AS indstatvals, ");
    7869             : 
    7870         364 :     if (fout->remoteVersion >= 150000)
    7871         364 :         appendPQExpBufferStr(query,
    7872             :                              "i.indnullsnotdistinct, ");
    7873             :     else
    7874           0 :         appendPQExpBufferStr(query,
    7875             :                              "false AS indnullsnotdistinct, ");
    7876             : 
    7877         364 :     if (fout->remoteVersion >= 180000)
    7878         364 :         appendPQExpBufferStr(query,
    7879             :                              "c.conperiod ");
    7880             :     else
    7881           0 :         appendPQExpBufferStr(query,
    7882             :                              "NULL AS conperiod ");
    7883             : 
    7884             :     /*
    7885             :      * The point of the messy-looking outer join is to find a constraint that
    7886             :      * is related by an internal dependency link to the index. If we find one,
    7887             :      * create a CONSTRAINT entry linked to the INDEX entry.  We assume an
    7888             :      * index won't have more than one internal dependency.
    7889             :      *
    7890             :      * Note: the check on conrelid is redundant, but useful because that
    7891             :      * column is indexed while conindid is not.
    7892             :      */
    7893         364 :     if (fout->remoteVersion >= 110000)
    7894             :     {
    7895         364 :         appendPQExpBuffer(query,
    7896             :                           "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
    7897             :                           "JOIN pg_catalog.pg_index i ON (src.tbloid = i.indrelid) "
    7898             :                           "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
    7899             :                           "JOIN pg_catalog.pg_class t2 ON (t2.oid = i.indrelid) "
    7900             :                           "LEFT JOIN pg_catalog.pg_constraint c "
    7901             :                           "ON (i.indrelid = c.conrelid AND "
    7902             :                           "i.indexrelid = c.conindid AND "
    7903             :                           "c.contype IN ('p','u','x')) "
    7904             :                           "LEFT JOIN pg_catalog.pg_inherits inh "
    7905             :                           "ON (inh.inhrelid = indexrelid) "
    7906             :                           "WHERE (i.indisvalid OR t2.relkind = 'p') "
    7907             :                           "AND i.indisready "
    7908             :                           "ORDER BY i.indrelid, indexname",
    7909             :                           tbloids->data);
    7910             :     }
    7911             :     else
    7912             :     {
    7913             :         /*
    7914             :          * the test on indisready is necessary in 9.2, and harmless in
    7915             :          * earlier/later versions
    7916             :          */
    7917           0 :         appendPQExpBuffer(query,
    7918             :                           "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
    7919             :                           "JOIN pg_catalog.pg_index i ON (src.tbloid = i.indrelid) "
    7920             :                           "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
    7921             :                           "LEFT JOIN pg_catalog.pg_constraint c "
    7922             :                           "ON (i.indrelid = c.conrelid AND "
    7923             :                           "i.indexrelid = c.conindid AND "
    7924             :                           "c.contype IN ('p','u','x')) "
    7925             :                           "WHERE i.indisvalid AND i.indisready "
    7926             :                           "ORDER BY i.indrelid, indexname",
    7927             :                           tbloids->data);
    7928             :     }
    7929             : 
    7930         364 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    7931             : 
    7932         364 :     ntups = PQntuples(res);
    7933             : 
    7934         364 :     i_tableoid = PQfnumber(res, "tableoid");
    7935         364 :     i_oid = PQfnumber(res, "oid");
    7936         364 :     i_indrelid = PQfnumber(res, "indrelid");
    7937         364 :     i_indexname = PQfnumber(res, "indexname");
    7938         364 :     i_relpages = PQfnumber(res, "relpages");
    7939         364 :     i_reltuples = PQfnumber(res, "reltuples");
    7940         364 :     i_relallvisible = PQfnumber(res, "relallvisible");
    7941         364 :     i_relallfrozen = PQfnumber(res, "relallfrozen");
    7942         364 :     i_parentidx = PQfnumber(res, "parentidx");
    7943         364 :     i_indexdef = PQfnumber(res, "indexdef");
    7944         364 :     i_indnkeyatts = PQfnumber(res, "indnkeyatts");
    7945         364 :     i_indnatts = PQfnumber(res, "indnatts");
    7946         364 :     i_indkey = PQfnumber(res, "indkey");
    7947         364 :     i_indisclustered = PQfnumber(res, "indisclustered");
    7948         364 :     i_indisreplident = PQfnumber(res, "indisreplident");
    7949         364 :     i_indnullsnotdistinct = PQfnumber(res, "indnullsnotdistinct");
    7950         364 :     i_contype = PQfnumber(res, "contype");
    7951         364 :     i_conname = PQfnumber(res, "conname");
    7952         364 :     i_condeferrable = PQfnumber(res, "condeferrable");
    7953         364 :     i_condeferred = PQfnumber(res, "condeferred");
    7954         364 :     i_conperiod = PQfnumber(res, "conperiod");
    7955         364 :     i_contableoid = PQfnumber(res, "contableoid");
    7956         364 :     i_conoid = PQfnumber(res, "conoid");
    7957         364 :     i_condef = PQfnumber(res, "condef");
    7958         364 :     i_indattnames = PQfnumber(res, "indattnames");
    7959         364 :     i_tablespace = PQfnumber(res, "tablespace");
    7960         364 :     i_indreloptions = PQfnumber(res, "indreloptions");
    7961         364 :     i_indstatcols = PQfnumber(res, "indstatcols");
    7962         364 :     i_indstatvals = PQfnumber(res, "indstatvals");
    7963             : 
    7964         364 :     indxinfo = (IndxInfo *) pg_malloc(ntups * sizeof(IndxInfo));
    7965             : 
    7966             :     /*
    7967             :      * Outer loop iterates once per table, not once per row.  Incrementing of
    7968             :      * j is handled by the inner loop.
    7969             :      */
    7970         364 :     curtblindx = -1;
    7971        4390 :     for (int j = 0; j < ntups;)
    7972             :     {
    7973        4026 :         Oid         indrelid = atooid(PQgetvalue(res, j, i_indrelid));
    7974        4026 :         TableInfo  *tbinfo = NULL;
    7975        4026 :         char      **indAttNames = NULL;
    7976        4026 :         int         nindAttNames = 0;
    7977             :         int         numinds;
    7978             : 
    7979             :         /* Count rows for this table */
    7980        5280 :         for (numinds = 1; numinds < ntups - j; numinds++)
    7981        5118 :             if (atooid(PQgetvalue(res, j + numinds, i_indrelid)) != indrelid)
    7982        3864 :                 break;
    7983             : 
    7984             :         /*
    7985             :          * Locate the associated TableInfo; we rely on tblinfo[] being in OID
    7986             :          * order.
    7987             :          */
    7988       47834 :         while (++curtblindx < numTables)
    7989             :         {
    7990       47834 :             tbinfo = &tblinfo[curtblindx];
    7991       47834 :             if (tbinfo->dobj.catId.oid == indrelid)
    7992        4026 :                 break;
    7993             :         }
    7994        4026 :         if (curtblindx >= numTables)
    7995           0 :             pg_fatal("unrecognized table OID %u", indrelid);
    7996             :         /* cross-check that we only got requested tables */
    7997        4026 :         if (!tbinfo->hasindex ||
    7998        4026 :             !tbinfo->interesting)
    7999           0 :             pg_fatal("unexpected index data for table \"%s\"",
    8000             :                      tbinfo->dobj.name);
    8001             : 
    8002             :         /* Save data for this table */
    8003        4026 :         tbinfo->indexes = indxinfo + j;
    8004        4026 :         tbinfo->numIndexes = numinds;
    8005             : 
    8006        9306 :         for (int c = 0; c < numinds; c++, j++)
    8007             :         {
    8008             :             char        contype;
    8009             :             char        indexkind;
    8010             :             RelStatsInfo *relstats;
    8011        5280 :             int32       relpages = atoi(PQgetvalue(res, j, i_relpages));
    8012        5280 :             int32       relallvisible = atoi(PQgetvalue(res, j, i_relallvisible));
    8013        5280 :             int32       relallfrozen = atoi(PQgetvalue(res, j, i_relallfrozen));
    8014             : 
    8015        5280 :             indxinfo[j].dobj.objType = DO_INDEX;
    8016        5280 :             indxinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
    8017        5280 :             indxinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
    8018        5280 :             AssignDumpId(&indxinfo[j].dobj);
    8019        5280 :             indxinfo[j].dobj.dump = tbinfo->dobj.dump;
    8020        5280 :             indxinfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_indexname));
    8021        5280 :             indxinfo[j].dobj.namespace = tbinfo->dobj.namespace;
    8022        5280 :             indxinfo[j].indextable = tbinfo;
    8023        5280 :             indxinfo[j].indexdef = pg_strdup(PQgetvalue(res, j, i_indexdef));
    8024        5280 :             indxinfo[j].indnkeyattrs = atoi(PQgetvalue(res, j, i_indnkeyatts));
    8025        5280 :             indxinfo[j].indnattrs = atoi(PQgetvalue(res, j, i_indnatts));
    8026        5280 :             indxinfo[j].tablespace = pg_strdup(PQgetvalue(res, j, i_tablespace));
    8027        5280 :             indxinfo[j].indreloptions = pg_strdup(PQgetvalue(res, j, i_indreloptions));
    8028        5280 :             indxinfo[j].indstatcols = pg_strdup(PQgetvalue(res, j, i_indstatcols));
    8029        5280 :             indxinfo[j].indstatvals = pg_strdup(PQgetvalue(res, j, i_indstatvals));
    8030        5280 :             indxinfo[j].indkeys = (Oid *) pg_malloc(indxinfo[j].indnattrs * sizeof(Oid));
    8031        5280 :             parseOidArray(PQgetvalue(res, j, i_indkey),
    8032        5280 :                           indxinfo[j].indkeys, indxinfo[j].indnattrs);
    8033        5280 :             indxinfo[j].indisclustered = (PQgetvalue(res, j, i_indisclustered)[0] == 't');
    8034        5280 :             indxinfo[j].indisreplident = (PQgetvalue(res, j, i_indisreplident)[0] == 't');
    8035        5280 :             indxinfo[j].indnullsnotdistinct = (PQgetvalue(res, j, i_indnullsnotdistinct)[0] == 't');
    8036        5280 :             indxinfo[j].parentidx = atooid(PQgetvalue(res, j, i_parentidx));
    8037        5280 :             indxinfo[j].partattaches = (SimplePtrList)
    8038             :             {
    8039             :                 NULL, NULL
    8040             :             };
    8041             : 
    8042        5280 :             if (indxinfo[j].parentidx == 0)
    8043        4104 :                 indexkind = RELKIND_INDEX;
    8044             :             else
    8045        1176 :                 indexkind = RELKIND_PARTITIONED_INDEX;
    8046             : 
    8047        5280 :             if (!PQgetisnull(res, j, i_indattnames))
    8048             :             {
    8049         304 :                 if (!parsePGArray(PQgetvalue(res, j, i_indattnames),
    8050             :                                   &indAttNames, &nindAttNames))
    8051           0 :                     pg_fatal("could not parse %s array", "indattnames");
    8052             :             }
    8053             : 
    8054        5280 :             relstats = getRelationStatistics(fout, &indxinfo[j].dobj, relpages,
    8055             :                                              PQgetvalue(res, j, i_reltuples),
    8056             :                                              relallvisible, relallfrozen, indexkind,
    8057             :                                              indAttNames, nindAttNames);
    8058             : 
    8059        5280 :             contype = *(PQgetvalue(res, j, i_contype));
    8060        5280 :             if (contype == 'p' || contype == 'u' || contype == 'x')
    8061        3074 :             {
    8062             :                 /*
    8063             :                  * If we found a constraint matching the index, create an
    8064             :                  * entry for it.
    8065             :                  */
    8066             :                 ConstraintInfo *constrinfo;
    8067             : 
    8068        3074 :                 constrinfo = (ConstraintInfo *) pg_malloc(sizeof(ConstraintInfo));
    8069        3074 :                 constrinfo->dobj.objType = DO_CONSTRAINT;
    8070        3074 :                 constrinfo->dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_contableoid));
    8071        3074 :                 constrinfo->dobj.catId.oid = atooid(PQgetvalue(res, j, i_conoid));
    8072        3074 :                 AssignDumpId(&constrinfo->dobj);
    8073        3074 :                 constrinfo->dobj.dump = tbinfo->dobj.dump;
    8074        3074 :                 constrinfo->dobj.name = pg_strdup(PQgetvalue(res, j, i_conname));
    8075        3074 :                 constrinfo->dobj.namespace = tbinfo->dobj.namespace;
    8076        3074 :                 constrinfo->contable = tbinfo;
    8077        3074 :                 constrinfo->condomain = NULL;
    8078        3074 :                 constrinfo->contype = contype;
    8079        3074 :                 if (contype == 'x')
    8080          20 :                     constrinfo->condef = pg_strdup(PQgetvalue(res, j, i_condef));
    8081             :                 else
    8082        3054 :                     constrinfo->condef = NULL;
    8083        3074 :                 constrinfo->confrelid = InvalidOid;
    8084        3074 :                 constrinfo->conindex = indxinfo[j].dobj.dumpId;
    8085        3074 :                 constrinfo->condeferrable = *(PQgetvalue(res, j, i_condeferrable)) == 't';
    8086        3074 :                 constrinfo->condeferred = *(PQgetvalue(res, j, i_condeferred)) == 't';
    8087        3074 :                 constrinfo->conperiod = *(PQgetvalue(res, j, i_conperiod)) == 't';
    8088        3074 :                 constrinfo->conislocal = true;
    8089        3074 :                 constrinfo->separate = true;
    8090             : 
    8091        3074 :                 indxinfo[j].indexconstraint = constrinfo->dobj.dumpId;
    8092        3074 :                 if (relstats != NULL)
    8093        1124 :                     addObjectDependency(&relstats->dobj, constrinfo->dobj.dumpId);
    8094             :             }
    8095             :             else
    8096             :             {
    8097             :                 /* Plain secondary index */
    8098        2206 :                 indxinfo[j].indexconstraint = 0;
    8099             :             }
    8100             :         }
    8101             :     }
    8102             : 
    8103         364 :     PQclear(res);
    8104             : 
    8105         364 :     destroyPQExpBuffer(query);
    8106         364 :     destroyPQExpBuffer(tbloids);
    8107         364 : }
    8108             : 
    8109             : /*
    8110             :  * getExtendedStatistics
    8111             :  *    get information about extended-statistics objects.
    8112             :  *
    8113             :  * Note: extended statistics data is not returned directly to the caller, but
    8114             :  * it does get entered into the DumpableObject tables.
    8115             :  */
    8116             : void
    8117         364 : getExtendedStatistics(Archive *fout)
    8118             : {
    8119             :     PQExpBuffer query;
    8120             :     PGresult   *res;
    8121             :     StatsExtInfo *statsextinfo;
    8122             :     int         ntups;
    8123             :     int         i_tableoid;
    8124             :     int         i_oid;
    8125             :     int         i_stxname;
    8126             :     int         i_stxnamespace;
    8127             :     int         i_stxowner;
    8128             :     int         i_stxrelid;
    8129             :     int         i_stattarget;
    8130             :     int         i;
    8131             : 
    8132             :     /* Extended statistics were new in v10 */
    8133         364 :     if (fout->remoteVersion < 100000)
    8134           0 :         return;
    8135             : 
    8136         364 :     query = createPQExpBuffer();
    8137             : 
    8138         364 :     if (fout->remoteVersion < 130000)
    8139           0 :         appendPQExpBufferStr(query, "SELECT tableoid, oid, stxname, "
    8140             :                              "stxnamespace, stxowner, stxrelid, NULL AS stxstattarget "
    8141             :                              "FROM pg_catalog.pg_statistic_ext");
    8142             :     else
    8143         364 :         appendPQExpBufferStr(query, "SELECT tableoid, oid, stxname, "
    8144             :                              "stxnamespace, stxowner, stxrelid, stxstattarget "
    8145             :                              "FROM pg_catalog.pg_statistic_ext");
    8146             : 
    8147         364 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    8148             : 
    8149         364 :     ntups = PQntuples(res);
    8150             : 
    8151         364 :     i_tableoid = PQfnumber(res, "tableoid");
    8152         364 :     i_oid = PQfnumber(res, "oid");
    8153         364 :     i_stxname = PQfnumber(res, "stxname");
    8154         364 :     i_stxnamespace = PQfnumber(res, "stxnamespace");
    8155         364 :     i_stxowner = PQfnumber(res, "stxowner");
    8156         364 :     i_stxrelid = PQfnumber(res, "stxrelid");
    8157         364 :     i_stattarget = PQfnumber(res, "stxstattarget");
    8158             : 
    8159         364 :     statsextinfo = (StatsExtInfo *) pg_malloc(ntups * sizeof(StatsExtInfo));
    8160             : 
    8161         708 :     for (i = 0; i < ntups; i++)
    8162             :     {
    8163         344 :         statsextinfo[i].dobj.objType = DO_STATSEXT;
    8164         344 :         statsextinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    8165         344 :         statsextinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    8166         344 :         AssignDumpId(&statsextinfo[i].dobj);
    8167         344 :         statsextinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_stxname));
    8168         688 :         statsextinfo[i].dobj.namespace =
    8169         344 :             findNamespace(atooid(PQgetvalue(res, i, i_stxnamespace)));
    8170         344 :         statsextinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_stxowner));
    8171         688 :         statsextinfo[i].stattable =
    8172         344 :             findTableByOid(atooid(PQgetvalue(res, i, i_stxrelid)));
    8173         344 :         if (PQgetisnull(res, i, i_stattarget))
    8174         248 :             statsextinfo[i].stattarget = -1;
    8175             :         else
    8176          96 :             statsextinfo[i].stattarget = atoi(PQgetvalue(res, i, i_stattarget));
    8177             : 
    8178             :         /* Decide whether we want to dump it */
    8179         344 :         selectDumpableStatisticsObject(&(statsextinfo[i]), fout);
    8180             :     }
    8181             : 
    8182         364 :     PQclear(res);
    8183         364 :     destroyPQExpBuffer(query);
    8184             : }
    8185             : 
    8186             : /*
    8187             :  * getConstraints
    8188             :  *
    8189             :  * Get info about constraints on dumpable tables.
    8190             :  *
    8191             :  * Currently handles foreign keys only.
    8192             :  * Unique and primary key constraints are handled with indexes,
    8193             :  * while check constraints are processed in getTableAttrs().
    8194             :  */
    8195             : void
    8196         364 : getConstraints(Archive *fout, TableInfo tblinfo[], int numTables)
    8197             : {
    8198         364 :     PQExpBuffer query = createPQExpBuffer();
    8199         364 :     PQExpBuffer tbloids = createPQExpBuffer();
    8200             :     PGresult   *res;
    8201             :     int         ntups;
    8202             :     int         curtblindx;
    8203         364 :     TableInfo  *tbinfo = NULL;
    8204             :     ConstraintInfo *constrinfo;
    8205             :     int         i_contableoid,
    8206             :                 i_conoid,
    8207             :                 i_conrelid,
    8208             :                 i_conname,
    8209             :                 i_confrelid,
    8210             :                 i_conindid,
    8211             :                 i_condef;
    8212             : 
    8213             :     /*
    8214             :      * We want to perform just one query against pg_constraint.  However, we
    8215             :      * mustn't try to select every row of the catalog and then sort it out on
    8216             :      * the client side, because some of the server-side functions we need
    8217             :      * would be unsafe to apply to tables we don't have lock on.  Hence, we
    8218             :      * build an array of the OIDs of tables we care about (and now have lock
    8219             :      * on!), and use a WHERE clause to constrain which rows are selected.
    8220             :      */
    8221         364 :     appendPQExpBufferChar(tbloids, '{');
    8222       96818 :     for (int i = 0; i < numTables; i++)
    8223             :     {
    8224       96454 :         TableInfo  *tinfo = &tblinfo[i];
    8225             : 
    8226       96454 :         if (!(tinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
    8227       82120 :             continue;
    8228             : 
    8229             :         /* OK, we need info for this table */
    8230       14334 :         if (tbloids->len > 1) /* do we have more than the '{'? */
    8231       14094 :             appendPQExpBufferChar(tbloids, ',');
    8232       14334 :         appendPQExpBuffer(tbloids, "%u", tinfo->dobj.catId.oid);
    8233             :     }
    8234         364 :     appendPQExpBufferChar(tbloids, '}');
    8235             : 
    8236         364 :     appendPQExpBufferStr(query,
    8237             :                          "SELECT c.tableoid, c.oid, "
    8238             :                          "conrelid, conname, confrelid, ");
    8239         364 :     if (fout->remoteVersion >= 110000)
    8240         364 :         appendPQExpBufferStr(query, "conindid, ");
    8241             :     else
    8242           0 :         appendPQExpBufferStr(query, "0 AS conindid, ");
    8243         364 :     appendPQExpBuffer(query,
    8244             :                       "pg_catalog.pg_get_constraintdef(c.oid) AS condef\n"
    8245             :                       "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
    8246             :                       "JOIN pg_catalog.pg_constraint c ON (src.tbloid = c.conrelid)\n"
    8247             :                       "WHERE contype = 'f' ",
    8248             :                       tbloids->data);
    8249         364 :     if (fout->remoteVersion >= 110000)
    8250         364 :         appendPQExpBufferStr(query,
    8251             :                              "AND conparentid = 0 ");
    8252         364 :     appendPQExpBufferStr(query,
    8253             :                          "ORDER BY conrelid, conname");
    8254             : 
    8255         364 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    8256             : 
    8257         364 :     ntups = PQntuples(res);
    8258             : 
    8259         364 :     i_contableoid = PQfnumber(res, "tableoid");
    8260         364 :     i_conoid = PQfnumber(res, "oid");
    8261         364 :     i_conrelid = PQfnumber(res, "conrelid");
    8262         364 :     i_conname = PQfnumber(res, "conname");
    8263         364 :     i_confrelid = PQfnumber(res, "confrelid");
    8264         364 :     i_conindid = PQfnumber(res, "conindid");
    8265         364 :     i_condef = PQfnumber(res, "condef");
    8266             : 
    8267         364 :     constrinfo = (ConstraintInfo *) pg_malloc(ntups * sizeof(ConstraintInfo));
    8268             : 
    8269         364 :     curtblindx = -1;
    8270         718 :     for (int j = 0; j < ntups; j++)
    8271             :     {
    8272         354 :         Oid         conrelid = atooid(PQgetvalue(res, j, i_conrelid));
    8273             :         TableInfo  *reftable;
    8274             : 
    8275             :         /*
    8276             :          * Locate the associated TableInfo; we rely on tblinfo[] being in OID
    8277             :          * order.
    8278             :          */
    8279         354 :         if (tbinfo == NULL || tbinfo->dobj.catId.oid != conrelid)
    8280             :         {
    8281       28482 :             while (++curtblindx < numTables)
    8282             :             {
    8283       28482 :                 tbinfo = &tblinfo[curtblindx];
    8284       28482 :                 if (tbinfo->dobj.catId.oid == conrelid)
    8285         334 :                     break;
    8286             :             }
    8287         334 :             if (curtblindx >= numTables)
    8288           0 :                 pg_fatal("unrecognized table OID %u", conrelid);
    8289             :         }
    8290             : 
    8291         354 :         constrinfo[j].dobj.objType = DO_FK_CONSTRAINT;
    8292         354 :         constrinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_contableoid));
    8293         354 :         constrinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_conoid));
    8294         354 :         AssignDumpId(&constrinfo[j].dobj);
    8295         354 :         constrinfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_conname));
    8296         354 :         constrinfo[j].dobj.namespace = tbinfo->dobj.namespace;
    8297         354 :         constrinfo[j].contable = tbinfo;
    8298         354 :         constrinfo[j].condomain = NULL;
    8299         354 :         constrinfo[j].contype = 'f';
    8300         354 :         constrinfo[j].condef = pg_strdup(PQgetvalue(res, j, i_condef));
    8301         354 :         constrinfo[j].confrelid = atooid(PQgetvalue(res, j, i_confrelid));
    8302         354 :         constrinfo[j].conindex = 0;
    8303         354 :         constrinfo[j].condeferrable = false;
    8304         354 :         constrinfo[j].condeferred = false;
    8305         354 :         constrinfo[j].conislocal = true;
    8306         354 :         constrinfo[j].separate = true;
    8307             : 
    8308             :         /*
    8309             :          * Restoring an FK that points to a partitioned table requires that
    8310             :          * all partition indexes have been attached beforehand. Ensure that
    8311             :          * happens by making the constraint depend on each index partition
    8312             :          * attach object.
    8313             :          */
    8314         354 :         reftable = findTableByOid(constrinfo[j].confrelid);
    8315         354 :         if (reftable && reftable->relkind == RELKIND_PARTITIONED_TABLE)
    8316             :         {
    8317          40 :             Oid         indexOid = atooid(PQgetvalue(res, j, i_conindid));
    8318             : 
    8319          40 :             if (indexOid != InvalidOid)
    8320             :             {
    8321          40 :                 for (int k = 0; k < reftable->numIndexes; k++)
    8322             :                 {
    8323             :                     IndxInfo   *refidx;
    8324             : 
    8325             :                     /* not our index? */
    8326          40 :                     if (reftable->indexes[k].dobj.catId.oid != indexOid)
    8327           0 :                         continue;
    8328             : 
    8329          40 :                     refidx = &reftable->indexes[k];
    8330          40 :                     addConstrChildIdxDeps(&constrinfo[j].dobj, refidx);
    8331          40 :                     break;
    8332             :                 }
    8333             :             }
    8334             :         }
    8335             :     }
    8336             : 
    8337         364 :     PQclear(res);
    8338             : 
    8339         364 :     destroyPQExpBuffer(query);
    8340         364 :     destroyPQExpBuffer(tbloids);
    8341         364 : }
    8342             : 
    8343             : /*
    8344             :  * addConstrChildIdxDeps
    8345             :  *
    8346             :  * Recursive subroutine for getConstraints
    8347             :  *
    8348             :  * Given an object representing a foreign key constraint and an index on the
    8349             :  * partitioned table it references, mark the constraint object as dependent
    8350             :  * on the DO_INDEX_ATTACH object of each index partition, recursively
    8351             :  * drilling down to their partitions if any.  This ensures that the FK is not
    8352             :  * restored until the index is fully marked valid.
    8353             :  */
    8354             : static void
    8355          90 : addConstrChildIdxDeps(DumpableObject *dobj, const IndxInfo *refidx)
    8356             : {
    8357             :     SimplePtrListCell *cell;
    8358             : 
    8359             :     Assert(dobj->objType == DO_FK_CONSTRAINT);
    8360             : 
    8361         310 :     for (cell = refidx->partattaches.head; cell; cell = cell->next)
    8362             :     {
    8363         220 :         IndexAttachInfo *attach = (IndexAttachInfo *) cell->ptr;
    8364             : 
    8365         220 :         addObjectDependency(dobj, attach->dobj.dumpId);
    8366             : 
    8367         220 :         if (attach->partitionIdx->partattaches.head != NULL)
    8368          50 :             addConstrChildIdxDeps(dobj, attach->partitionIdx);
    8369             :     }
    8370          90 : }
    8371             : 
    8372             : /*
    8373             :  * getDomainConstraints
    8374             :  *
    8375             :  * Get info about constraints on a domain.
    8376             :  */
    8377             : static void
    8378         322 : getDomainConstraints(Archive *fout, TypeInfo *tyinfo)
    8379             : {
    8380             :     ConstraintInfo *constrinfo;
    8381         322 :     PQExpBuffer query = createPQExpBuffer();
    8382             :     PGresult   *res;
    8383             :     int         i_tableoid,
    8384             :                 i_oid,
    8385             :                 i_conname,
    8386             :                 i_consrc,
    8387             :                 i_convalidated,
    8388             :                 i_contype;
    8389             :     int         ntups;
    8390             : 
    8391         322 :     if (!fout->is_prepared[PREPQUERY_GETDOMAINCONSTRAINTS])
    8392             :     {
    8393             :         /*
    8394             :          * Set up query for constraint-specific details.  For servers 17 and
    8395             :          * up, domains have constraints of type 'n' as well as 'c', otherwise
    8396             :          * just the latter.
    8397             :          */
    8398          92 :         appendPQExpBuffer(query,
    8399             :                           "PREPARE getDomainConstraints(pg_catalog.oid) AS\n"
    8400             :                           "SELECT tableoid, oid, conname, "
    8401             :                           "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
    8402             :                           "convalidated, contype "
    8403             :                           "FROM pg_catalog.pg_constraint "
    8404             :                           "WHERE contypid = $1 AND contype IN (%s) "
    8405             :                           "ORDER BY conname",
    8406          92 :                           fout->remoteVersion < 170000 ? "'c'" : "'c', 'n'");
    8407             : 
    8408          92 :         ExecuteSqlStatement(fout, query->data);
    8409             : 
    8410          92 :         fout->is_prepared[PREPQUERY_GETDOMAINCONSTRAINTS] = true;
    8411             :     }
    8412             : 
    8413         322 :     printfPQExpBuffer(query,
    8414             :                       "EXECUTE getDomainConstraints('%u')",
    8415             :                       tyinfo->dobj.catId.oid);
    8416             : 
    8417         322 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    8418             : 
    8419         322 :     ntups = PQntuples(res);
    8420             : 
    8421         322 :     i_tableoid = PQfnumber(res, "tableoid");
    8422         322 :     i_oid = PQfnumber(res, "oid");
    8423         322 :     i_conname = PQfnumber(res, "conname");
    8424         322 :     i_consrc = PQfnumber(res, "consrc");
    8425         322 :     i_convalidated = PQfnumber(res, "convalidated");
    8426         322 :     i_contype = PQfnumber(res, "contype");
    8427             : 
    8428         322 :     constrinfo = (ConstraintInfo *) pg_malloc(ntups * sizeof(ConstraintInfo));
    8429         322 :     tyinfo->domChecks = constrinfo;
    8430             : 
    8431             :     /* 'i' tracks result rows; 'j' counts CHECK constraints */
    8432         666 :     for (int i = 0, j = 0; i < ntups; i++)
    8433             :     {
    8434         344 :         bool        validated = PQgetvalue(res, i, i_convalidated)[0] == 't';
    8435         344 :         char        contype = (PQgetvalue(res, i, i_contype))[0];
    8436             :         ConstraintInfo *constraint;
    8437             : 
    8438         344 :         if (contype == CONSTRAINT_CHECK)
    8439             :         {
    8440         232 :             constraint = &constrinfo[j++];
    8441         232 :             tyinfo->nDomChecks++;
    8442             :         }
    8443             :         else
    8444             :         {
    8445             :             Assert(contype == CONSTRAINT_NOTNULL);
    8446             :             Assert(tyinfo->notnull == NULL);
    8447             :             /* use last item in array for the not-null constraint */
    8448         112 :             tyinfo->notnull = &(constrinfo[ntups - 1]);
    8449         112 :             constraint = tyinfo->notnull;
    8450             :         }
    8451             : 
    8452         344 :         constraint->dobj.objType = DO_CONSTRAINT;
    8453         344 :         constraint->dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    8454         344 :         constraint->dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    8455         344 :         AssignDumpId(&(constraint->dobj));
    8456         344 :         constraint->dobj.name = pg_strdup(PQgetvalue(res, i, i_conname));
    8457         344 :         constraint->dobj.namespace = tyinfo->dobj.namespace;
    8458         344 :         constraint->contable = NULL;
    8459         344 :         constraint->condomain = tyinfo;
    8460         344 :         constraint->contype = contype;
    8461         344 :         constraint->condef = pg_strdup(PQgetvalue(res, i, i_consrc));
    8462         344 :         constraint->confrelid = InvalidOid;
    8463         344 :         constraint->conindex = 0;
    8464         344 :         constraint->condeferrable = false;
    8465         344 :         constraint->condeferred = false;
    8466         344 :         constraint->conislocal = true;
    8467             : 
    8468         344 :         constraint->separate = !validated;
    8469             : 
    8470             :         /*
    8471             :          * Make the domain depend on the constraint, ensuring it won't be
    8472             :          * output till any constraint dependencies are OK.  If the constraint
    8473             :          * has not been validated, it's going to be dumped after the domain
    8474             :          * anyway, so this doesn't matter.
    8475             :          */
    8476         344 :         if (validated)
    8477         334 :             addObjectDependency(&tyinfo->dobj, constraint->dobj.dumpId);
    8478             :     }
    8479             : 
    8480         322 :     PQclear(res);
    8481             : 
    8482         322 :     destroyPQExpBuffer(query);
    8483         322 : }
    8484             : 
    8485             : /*
    8486             :  * getRules
    8487             :  *    get basic information about every rule in the system
    8488             :  */
    8489             : void
    8490         364 : getRules(Archive *fout)
    8491             : {
    8492             :     PGresult   *res;
    8493             :     int         ntups;
    8494             :     int         i;
    8495         364 :     PQExpBuffer query = createPQExpBuffer();
    8496             :     RuleInfo   *ruleinfo;
    8497             :     int         i_tableoid;
    8498             :     int         i_oid;
    8499             :     int         i_rulename;
    8500             :     int         i_ruletable;
    8501             :     int         i_ev_type;
    8502             :     int         i_is_instead;
    8503             :     int         i_ev_enabled;
    8504             : 
    8505         364 :     appendPQExpBufferStr(query, "SELECT "
    8506             :                          "tableoid, oid, rulename, "
    8507             :                          "ev_class AS ruletable, ev_type, is_instead, "
    8508             :                          "ev_enabled "
    8509             :                          "FROM pg_rewrite "
    8510             :                          "ORDER BY oid");
    8511             : 
    8512         364 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    8513             : 
    8514         364 :     ntups = PQntuples(res);
    8515             : 
    8516         364 :     ruleinfo = (RuleInfo *) pg_malloc(ntups * sizeof(RuleInfo));
    8517             : 
    8518         364 :     i_tableoid = PQfnumber(res, "tableoid");
    8519         364 :     i_oid = PQfnumber(res, "oid");
    8520         364 :     i_rulename = PQfnumber(res, "rulename");
    8521         364 :     i_ruletable = PQfnumber(res, "ruletable");
    8522         364 :     i_ev_type = PQfnumber(res, "ev_type");
    8523         364 :     i_is_instead = PQfnumber(res, "is_instead");
    8524         364 :     i_ev_enabled = PQfnumber(res, "ev_enabled");
    8525             : 
    8526       56664 :     for (i = 0; i < ntups; i++)
    8527             :     {
    8528             :         Oid         ruletableoid;
    8529             : 
    8530       56300 :         ruleinfo[i].dobj.objType = DO_RULE;
    8531       56300 :         ruleinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    8532       56300 :         ruleinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    8533       56300 :         AssignDumpId(&ruleinfo[i].dobj);
    8534       56300 :         ruleinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_rulename));
    8535       56300 :         ruletableoid = atooid(PQgetvalue(res, i, i_ruletable));
    8536       56300 :         ruleinfo[i].ruletable = findTableByOid(ruletableoid);
    8537       56300 :         if (ruleinfo[i].ruletable == NULL)
    8538           0 :             pg_fatal("failed sanity check, parent table with OID %u of pg_rewrite entry with OID %u not found",
    8539             :                      ruletableoid, ruleinfo[i].dobj.catId.oid);
    8540       56300 :         ruleinfo[i].dobj.namespace = ruleinfo[i].ruletable->dobj.namespace;
    8541       56300 :         ruleinfo[i].dobj.dump = ruleinfo[i].ruletable->dobj.dump;
    8542       56300 :         ruleinfo[i].ev_type = *(PQgetvalue(res, i, i_ev_type));
    8543       56300 :         ruleinfo[i].is_instead = *(PQgetvalue(res, i, i_is_instead)) == 't';
    8544       56300 :         ruleinfo[i].ev_enabled = *(PQgetvalue(res, i, i_ev_enabled));
    8545       56300 :         if (ruleinfo[i].ruletable)
    8546             :         {
    8547             :             /*
    8548             :              * If the table is a view or materialized view, force its ON
    8549             :              * SELECT rule to be sorted before the view itself --- this
    8550             :              * ensures that any dependencies for the rule affect the table's
    8551             :              * positioning. Other rules are forced to appear after their
    8552             :              * table.
    8553             :              */
    8554       56300 :             if ((ruleinfo[i].ruletable->relkind == RELKIND_VIEW ||
    8555        1534 :                  ruleinfo[i].ruletable->relkind == RELKIND_MATVIEW) &&
    8556       55838 :                 ruleinfo[i].ev_type == '1' && ruleinfo[i].is_instead)
    8557             :             {
    8558       55026 :                 addObjectDependency(&ruleinfo[i].ruletable->dobj,
    8559       55026 :                                     ruleinfo[i].dobj.dumpId);
    8560             :                 /* We'll merge the rule into CREATE VIEW, if possible */
    8561       55026 :                 ruleinfo[i].separate = false;
    8562             :             }
    8563             :             else
    8564             :             {
    8565        1274 :                 addObjectDependency(&ruleinfo[i].dobj,
    8566        1274 :                                     ruleinfo[i].ruletable->dobj.dumpId);
    8567        1274 :                 ruleinfo[i].separate = true;
    8568             :             }
    8569             :         }
    8570             :         else
    8571           0 :             ruleinfo[i].separate = true;
    8572             :     }
    8573             : 
    8574         364 :     PQclear(res);
    8575             : 
    8576         364 :     destroyPQExpBuffer(query);
    8577         364 : }
    8578             : 
    8579             : /*
    8580             :  * getTriggers
    8581             :  *    get information about every trigger on a dumpable table
    8582             :  *
    8583             :  * Note: trigger data is not returned directly to the caller, but it
    8584             :  * does get entered into the DumpableObject tables.
    8585             :  */
    8586             : void
    8587         364 : getTriggers(Archive *fout, TableInfo tblinfo[], int numTables)
    8588             : {
    8589         364 :     PQExpBuffer query = createPQExpBuffer();
    8590         364 :     PQExpBuffer tbloids = createPQExpBuffer();
    8591             :     PGresult   *res;
    8592             :     int         ntups;
    8593             :     int         curtblindx;
    8594             :     TriggerInfo *tginfo;
    8595             :     int         i_tableoid,
    8596             :                 i_oid,
    8597             :                 i_tgrelid,
    8598             :                 i_tgname,
    8599             :                 i_tgenabled,
    8600             :                 i_tgispartition,
    8601             :                 i_tgdef;
    8602             : 
    8603             :     /*
    8604             :      * We want to perform just one query against pg_trigger.  However, we
    8605             :      * mustn't try to select every row of the catalog and then sort it out on
    8606             :      * the client side, because some of the server-side functions we need
    8607             :      * would be unsafe to apply to tables we don't have lock on.  Hence, we
    8608             :      * build an array of the OIDs of tables we care about (and now have lock
    8609             :      * on!), and use a WHERE clause to constrain which rows are selected.
    8610             :      */
    8611         364 :     appendPQExpBufferChar(tbloids, '{');
    8612       96818 :     for (int i = 0; i < numTables; i++)
    8613             :     {
    8614       96454 :         TableInfo  *tbinfo = &tblinfo[i];
    8615             : 
    8616       96454 :         if (!tbinfo->hastriggers ||
    8617        2282 :             !(tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
    8618       94696 :             continue;
    8619             : 
    8620             :         /* OK, we need info for this table */
    8621        1758 :         if (tbloids->len > 1) /* do we have more than the '{'? */
    8622        1650 :             appendPQExpBufferChar(tbloids, ',');
    8623        1758 :         appendPQExpBuffer(tbloids, "%u", tbinfo->dobj.catId.oid);
    8624             :     }
    8625         364 :     appendPQExpBufferChar(tbloids, '}');
    8626             : 
    8627         364 :     if (fout->remoteVersion >= 150000)
    8628             :     {
    8629             :         /*
    8630             :          * NB: think not to use pretty=true in pg_get_triggerdef.  It could
    8631             :          * result in non-forward-compatible dumps of WHEN clauses due to
    8632             :          * under-parenthesization.
    8633             :          *
    8634             :          * NB: We need to see partition triggers in case the tgenabled flag
    8635             :          * has been changed from the parent.
    8636             :          */
    8637         364 :         appendPQExpBuffer(query,
    8638             :                           "SELECT t.tgrelid, t.tgname, "
    8639             :                           "pg_catalog.pg_get_triggerdef(t.oid, false) AS tgdef, "
    8640             :                           "t.tgenabled, t.tableoid, t.oid, "
    8641             :                           "t.tgparentid <> 0 AS tgispartition\n"
    8642             :                           "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
    8643             :                           "JOIN pg_catalog.pg_trigger t ON (src.tbloid = t.tgrelid) "
    8644             :                           "LEFT JOIN pg_catalog.pg_trigger u ON (u.oid = t.tgparentid) "
    8645             :                           "WHERE ((NOT t.tgisinternal AND t.tgparentid = 0) "
    8646             :                           "OR t.tgenabled != u.tgenabled) "
    8647             :                           "ORDER BY t.tgrelid, t.tgname",
    8648             :                           tbloids->data);
    8649             :     }
    8650           0 :     else if (fout->remoteVersion >= 130000)
    8651             :     {
    8652             :         /*
    8653             :          * NB: think not to use pretty=true in pg_get_triggerdef.  It could
    8654             :          * result in non-forward-compatible dumps of WHEN clauses due to
    8655             :          * under-parenthesization.
    8656             :          *
    8657             :          * NB: We need to see tgisinternal triggers in partitions, in case the
    8658             :          * tgenabled flag has been changed from the parent.
    8659             :          */
    8660           0 :         appendPQExpBuffer(query,
    8661             :                           "SELECT t.tgrelid, t.tgname, "
    8662             :                           "pg_catalog.pg_get_triggerdef(t.oid, false) AS tgdef, "
    8663             :                           "t.tgenabled, t.tableoid, t.oid, t.tgisinternal as tgispartition\n"
    8664             :                           "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
    8665             :                           "JOIN pg_catalog.pg_trigger t ON (src.tbloid = t.tgrelid) "
    8666             :                           "LEFT JOIN pg_catalog.pg_trigger u ON (u.oid = t.tgparentid) "
    8667             :                           "WHERE (NOT t.tgisinternal OR t.tgenabled != u.tgenabled) "
    8668             :                           "ORDER BY t.tgrelid, t.tgname",
    8669             :                           tbloids->data);
    8670             :     }
    8671           0 :     else if (fout->remoteVersion >= 110000)
    8672             :     {
    8673             :         /*
    8674             :          * NB: We need to see tgisinternal triggers in partitions, in case the
    8675             :          * tgenabled flag has been changed from the parent. No tgparentid in
    8676             :          * version 11-12, so we have to match them via pg_depend.
    8677             :          *
    8678             :          * See above about pretty=true in pg_get_triggerdef.
    8679             :          */
    8680           0 :         appendPQExpBuffer(query,
    8681             :                           "SELECT t.tgrelid, t.tgname, "
    8682             :                           "pg_catalog.pg_get_triggerdef(t.oid, false) AS tgdef, "
    8683             :                           "t.tgenabled, t.tableoid, t.oid, t.tgisinternal as tgispartition "
    8684             :                           "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
    8685             :                           "JOIN pg_catalog.pg_trigger t ON (src.tbloid = t.tgrelid) "
    8686             :                           "LEFT JOIN pg_catalog.pg_depend AS d ON "
    8687             :                           " d.classid = 'pg_catalog.pg_trigger'::pg_catalog.regclass AND "
    8688             :                           " d.refclassid = 'pg_catalog.pg_trigger'::pg_catalog.regclass AND "
    8689             :                           " d.objid = t.oid "
    8690             :                           "LEFT JOIN pg_catalog.pg_trigger AS pt ON pt.oid = refobjid "
    8691             :                           "WHERE (NOT t.tgisinternal OR t.tgenabled != pt.tgenabled) "
    8692             :                           "ORDER BY t.tgrelid, t.tgname",
    8693             :                           tbloids->data);
    8694             :     }
    8695             :     else
    8696             :     {
    8697             :         /* See above about pretty=true in pg_get_triggerdef */
    8698           0 :         appendPQExpBuffer(query,
    8699             :                           "SELECT t.tgrelid, t.tgname, "
    8700             :                           "pg_catalog.pg_get_triggerdef(t.oid, false) AS tgdef, "
    8701             :                           "t.tgenabled, false as tgispartition, "
    8702             :                           "t.tableoid, t.oid "
    8703             :                           "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
    8704             :                           "JOIN pg_catalog.pg_trigger t ON (src.tbloid = t.tgrelid) "
    8705             :                           "WHERE NOT tgisinternal "
    8706             :                           "ORDER BY t.tgrelid, t.tgname",
    8707             :                           tbloids->data);
    8708             :     }
    8709             : 
    8710         364 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    8711             : 
    8712         364 :     ntups = PQntuples(res);
    8713             : 
    8714         364 :     i_tableoid = PQfnumber(res, "tableoid");
    8715         364 :     i_oid = PQfnumber(res, "oid");
    8716         364 :     i_tgrelid = PQfnumber(res, "tgrelid");
    8717         364 :     i_tgname = PQfnumber(res, "tgname");
    8718         364 :     i_tgenabled = PQfnumber(res, "tgenabled");
    8719         364 :     i_tgispartition = PQfnumber(res, "tgispartition");
    8720         364 :     i_tgdef = PQfnumber(res, "tgdef");
    8721             : 
    8722         364 :     tginfo = (TriggerInfo *) pg_malloc(ntups * sizeof(TriggerInfo));
    8723             : 
    8724             :     /*
    8725             :      * Outer loop iterates once per table, not once per row.  Incrementing of
    8726             :      * j is handled by the inner loop.
    8727             :      */
    8728         364 :     curtblindx = -1;
    8729        1006 :     for (int j = 0; j < ntups;)
    8730             :     {
    8731         642 :         Oid         tgrelid = atooid(PQgetvalue(res, j, i_tgrelid));
    8732         642 :         TableInfo  *tbinfo = NULL;
    8733             :         int         numtrigs;
    8734             : 
    8735             :         /* Count rows for this table */
    8736        1076 :         for (numtrigs = 1; numtrigs < ntups - j; numtrigs++)
    8737         968 :             if (atooid(PQgetvalue(res, j + numtrigs, i_tgrelid)) != tgrelid)
    8738         534 :                 break;
    8739             : 
    8740             :         /*
    8741             :          * Locate the associated TableInfo; we rely on tblinfo[] being in OID
    8742             :          * order.
    8743             :          */
    8744       33686 :         while (++curtblindx < numTables)
    8745             :         {
    8746       33686 :             tbinfo = &tblinfo[curtblindx];
    8747       33686 :             if (tbinfo->dobj.catId.oid == tgrelid)
    8748         642 :                 break;
    8749             :         }
    8750         642 :         if (curtblindx >= numTables)
    8751           0 :             pg_fatal("unrecognized table OID %u", tgrelid);
    8752             : 
    8753             :         /* Save data for this table */
    8754         642 :         tbinfo->triggers = tginfo + j;
    8755         642 :         tbinfo->numTriggers = numtrigs;
    8756             : 
    8757        1718 :         for (int c = 0; c < numtrigs; c++, j++)
    8758             :         {
    8759        1076 :             tginfo[j].dobj.objType = DO_TRIGGER;
    8760        1076 :             tginfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
    8761        1076 :             tginfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
    8762        1076 :             AssignDumpId(&tginfo[j].dobj);
    8763        1076 :             tginfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_tgname));
    8764        1076 :             tginfo[j].dobj.namespace = tbinfo->dobj.namespace;
    8765        1076 :             tginfo[j].tgtable = tbinfo;
    8766        1076 :             tginfo[j].tgenabled = *(PQgetvalue(res, j, i_tgenabled));
    8767        1076 :             tginfo[j].tgispartition = *(PQgetvalue(res, j, i_tgispartition)) == 't';
    8768        1076 :             tginfo[j].tgdef = pg_strdup(PQgetvalue(res, j, i_tgdef));
    8769             :         }
    8770             :     }
    8771             : 
    8772         364 :     PQclear(res);
    8773             : 
    8774         364 :     destroyPQExpBuffer(query);
    8775         364 :     destroyPQExpBuffer(tbloids);
    8776         364 : }
    8777             : 
    8778             : /*
    8779             :  * getEventTriggers
    8780             :  *    get information about event triggers
    8781             :  */
    8782             : void
    8783         364 : getEventTriggers(Archive *fout)
    8784             : {
    8785             :     int         i;
    8786             :     PQExpBuffer query;
    8787             :     PGresult   *res;
    8788             :     EventTriggerInfo *evtinfo;
    8789             :     int         i_tableoid,
    8790             :                 i_oid,
    8791             :                 i_evtname,
    8792             :                 i_evtevent,
    8793             :                 i_evtowner,
    8794             :                 i_evttags,
    8795             :                 i_evtfname,
    8796             :                 i_evtenabled;
    8797             :     int         ntups;
    8798             : 
    8799             :     /* Before 9.3, there are no event triggers */
    8800         364 :     if (fout->remoteVersion < 90300)
    8801           0 :         return;
    8802             : 
    8803         364 :     query = createPQExpBuffer();
    8804             : 
    8805         364 :     appendPQExpBufferStr(query,
    8806             :                          "SELECT e.tableoid, e.oid, evtname, evtenabled, "
    8807             :                          "evtevent, evtowner, "
    8808             :                          "array_to_string(array("
    8809             :                          "select quote_literal(x) "
    8810             :                          " from unnest(evttags) as t(x)), ', ') as evttags, "
    8811             :                          "e.evtfoid::regproc as evtfname "
    8812             :                          "FROM pg_event_trigger e "
    8813             :                          "ORDER BY e.oid");
    8814             : 
    8815         364 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    8816             : 
    8817         364 :     ntups = PQntuples(res);
    8818             : 
    8819         364 :     evtinfo = (EventTriggerInfo *) pg_malloc(ntups * sizeof(EventTriggerInfo));
    8820             : 
    8821         364 :     i_tableoid = PQfnumber(res, "tableoid");
    8822         364 :     i_oid = PQfnumber(res, "oid");
    8823         364 :     i_evtname = PQfnumber(res, "evtname");
    8824         364 :     i_evtevent = PQfnumber(res, "evtevent");
    8825         364 :     i_evtowner = PQfnumber(res, "evtowner");
    8826         364 :     i_evttags = PQfnumber(res, "evttags");
    8827         364 :     i_evtfname = PQfnumber(res, "evtfname");
    8828         364 :     i_evtenabled = PQfnumber(res, "evtenabled");
    8829             : 
    8830         474 :     for (i = 0; i < ntups; i++)
    8831             :     {
    8832         110 :         evtinfo[i].dobj.objType = DO_EVENT_TRIGGER;
    8833         110 :         evtinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    8834         110 :         evtinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    8835         110 :         AssignDumpId(&evtinfo[i].dobj);
    8836         110 :         evtinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_evtname));
    8837         110 :         evtinfo[i].evtname = pg_strdup(PQgetvalue(res, i, i_evtname));
    8838         110 :         evtinfo[i].evtevent = pg_strdup(PQgetvalue(res, i, i_evtevent));
    8839         110 :         evtinfo[i].evtowner = getRoleName(PQgetvalue(res, i, i_evtowner));
    8840         110 :         evtinfo[i].evttags = pg_strdup(PQgetvalue(res, i, i_evttags));
    8841         110 :         evtinfo[i].evtfname = pg_strdup(PQgetvalue(res, i, i_evtfname));
    8842         110 :         evtinfo[i].evtenabled = *(PQgetvalue(res, i, i_evtenabled));
    8843             : 
    8844             :         /* Decide whether we want to dump it */
    8845         110 :         selectDumpableObject(&(evtinfo[i].dobj), fout);
    8846             :     }
    8847             : 
    8848         364 :     PQclear(res);
    8849             : 
    8850         364 :     destroyPQExpBuffer(query);
    8851             : }
    8852             : 
    8853             : /*
    8854             :  * getProcLangs
    8855             :  *    get basic information about every procedural language in the system
    8856             :  *
    8857             :  * NB: this must run after getFuncs() because we assume we can do
    8858             :  * findFuncByOid().
    8859             :  */
    8860             : void
    8861         364 : getProcLangs(Archive *fout)
    8862             : {
    8863             :     PGresult   *res;
    8864             :     int         ntups;
    8865             :     int         i;
    8866         364 :     PQExpBuffer query = createPQExpBuffer();
    8867             :     ProcLangInfo *planginfo;
    8868             :     int         i_tableoid;
    8869             :     int         i_oid;
    8870             :     int         i_lanname;
    8871             :     int         i_lanpltrusted;
    8872             :     int         i_lanplcallfoid;
    8873             :     int         i_laninline;
    8874             :     int         i_lanvalidator;
    8875             :     int         i_lanacl;
    8876             :     int         i_acldefault;
    8877             :     int         i_lanowner;
    8878             : 
    8879         364 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, "
    8880             :                          "lanname, lanpltrusted, lanplcallfoid, "
    8881             :                          "laninline, lanvalidator, "
    8882             :                          "lanacl, "
    8883             :                          "acldefault('l', lanowner) AS acldefault, "
    8884             :                          "lanowner "
    8885             :                          "FROM pg_language "
    8886             :                          "WHERE lanispl "
    8887             :                          "ORDER BY oid");
    8888             : 
    8889         364 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    8890             : 
    8891         364 :     ntups = PQntuples(res);
    8892             : 
    8893         364 :     planginfo = (ProcLangInfo *) pg_malloc(ntups * sizeof(ProcLangInfo));
    8894             : 
    8895         364 :     i_tableoid = PQfnumber(res, "tableoid");
    8896         364 :     i_oid = PQfnumber(res, "oid");
    8897         364 :     i_lanname = PQfnumber(res, "lanname");
    8898         364 :     i_lanpltrusted = PQfnumber(res, "lanpltrusted");
    8899         364 :     i_lanplcallfoid = PQfnumber(res, "lanplcallfoid");
    8900         364 :     i_laninline = PQfnumber(res, "laninline");
    8901         364 :     i_lanvalidator = PQfnumber(res, "lanvalidator");
    8902         364 :     i_lanacl = PQfnumber(res, "lanacl");
    8903         364 :     i_acldefault = PQfnumber(res, "acldefault");
    8904         364 :     i_lanowner = PQfnumber(res, "lanowner");
    8905             : 
    8906         824 :     for (i = 0; i < ntups; i++)
    8907             :     {
    8908         460 :         planginfo[i].dobj.objType = DO_PROCLANG;
    8909         460 :         planginfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    8910         460 :         planginfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    8911         460 :         AssignDumpId(&planginfo[i].dobj);
    8912             : 
    8913         460 :         planginfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_lanname));
    8914         460 :         planginfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_lanacl));
    8915         460 :         planginfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
    8916         460 :         planginfo[i].dacl.privtype = 0;
    8917         460 :         planginfo[i].dacl.initprivs = NULL;
    8918         460 :         planginfo[i].lanpltrusted = *(PQgetvalue(res, i, i_lanpltrusted)) == 't';
    8919         460 :         planginfo[i].lanplcallfoid = atooid(PQgetvalue(res, i, i_lanplcallfoid));
    8920         460 :         planginfo[i].laninline = atooid(PQgetvalue(res, i, i_laninline));
    8921         460 :         planginfo[i].lanvalidator = atooid(PQgetvalue(res, i, i_lanvalidator));
    8922         460 :         planginfo[i].lanowner = getRoleName(PQgetvalue(res, i, i_lanowner));
    8923             : 
    8924             :         /* Decide whether we want to dump it */
    8925         460 :         selectDumpableProcLang(&(planginfo[i]), fout);
    8926             : 
    8927             :         /* Mark whether language has an ACL */
    8928         460 :         if (!PQgetisnull(res, i, i_lanacl))
    8929          96 :             planginfo[i].dobj.components |= DUMP_COMPONENT_ACL;
    8930             :     }
    8931             : 
    8932         364 :     PQclear(res);
    8933             : 
    8934         364 :     destroyPQExpBuffer(query);
    8935         364 : }
    8936             : 
    8937             : /*
    8938             :  * getCasts
    8939             :  *    get basic information about most casts in the system
    8940             :  *
    8941             :  * Skip casts from a range to its multirange, since we'll create those
    8942             :  * automatically.
    8943             :  */
    8944             : void
    8945         364 : getCasts(Archive *fout)
    8946             : {
    8947             :     PGresult   *res;
    8948             :     int         ntups;
    8949             :     int         i;
    8950         364 :     PQExpBuffer query = createPQExpBuffer();
    8951             :     CastInfo   *castinfo;
    8952             :     int         i_tableoid;
    8953             :     int         i_oid;
    8954             :     int         i_castsource;
    8955             :     int         i_casttarget;
    8956             :     int         i_castfunc;
    8957             :     int         i_castcontext;
    8958             :     int         i_castmethod;
    8959             : 
    8960         364 :     if (fout->remoteVersion >= 140000)
    8961             :     {
    8962         364 :         appendPQExpBufferStr(query, "SELECT tableoid, oid, "
    8963             :                              "castsource, casttarget, castfunc, castcontext, "
    8964             :                              "castmethod "
    8965             :                              "FROM pg_cast c "
    8966             :                              "WHERE NOT EXISTS ( "
    8967             :                              "SELECT 1 FROM pg_range r "
    8968             :                              "WHERE c.castsource = r.rngtypid "
    8969             :                              "AND c.casttarget = r.rngmultitypid "
    8970             :                              ") "
    8971             :                              "ORDER BY 3,4");
    8972             :     }
    8973             :     else
    8974             :     {
    8975           0 :         appendPQExpBufferStr(query, "SELECT tableoid, oid, "
    8976             :                              "castsource, casttarget, castfunc, castcontext, "
    8977             :                              "castmethod "
    8978             :                              "FROM pg_cast ORDER BY 3,4");
    8979             :     }
    8980             : 
    8981         364 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    8982             : 
    8983         364 :     ntups = PQntuples(res);
    8984             : 
    8985         364 :     castinfo = (CastInfo *) pg_malloc(ntups * sizeof(CastInfo));
    8986             : 
    8987         364 :     i_tableoid = PQfnumber(res, "tableoid");
    8988         364 :     i_oid = PQfnumber(res, "oid");
    8989         364 :     i_castsource = PQfnumber(res, "castsource");
    8990         364 :     i_casttarget = PQfnumber(res, "casttarget");
    8991         364 :     i_castfunc = PQfnumber(res, "castfunc");
    8992         364 :     i_castcontext = PQfnumber(res, "castcontext");
    8993         364 :     i_castmethod = PQfnumber(res, "castmethod");
    8994             : 
    8995       86448 :     for (i = 0; i < ntups; i++)
    8996             :     {
    8997             :         PQExpBufferData namebuf;
    8998             :         TypeInfo   *sTypeInfo;
    8999             :         TypeInfo   *tTypeInfo;
    9000             : 
    9001       86084 :         castinfo[i].dobj.objType = DO_CAST;
    9002       86084 :         castinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    9003       86084 :         castinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    9004       86084 :         AssignDumpId(&castinfo[i].dobj);
    9005       86084 :         castinfo[i].castsource = atooid(PQgetvalue(res, i, i_castsource));
    9006       86084 :         castinfo[i].casttarget = atooid(PQgetvalue(res, i, i_casttarget));
    9007       86084 :         castinfo[i].castfunc = atooid(PQgetvalue(res, i, i_castfunc));
    9008       86084 :         castinfo[i].castcontext = *(PQgetvalue(res, i, i_castcontext));
    9009       86084 :         castinfo[i].castmethod = *(PQgetvalue(res, i, i_castmethod));
    9010             : 
    9011             :         /*
    9012             :          * Try to name cast as concatenation of typnames.  This is only used
    9013             :          * for purposes of sorting.  If we fail to find either type, the name
    9014             :          * will be an empty string.
    9015             :          */
    9016       86084 :         initPQExpBuffer(&namebuf);
    9017       86084 :         sTypeInfo = findTypeByOid(castinfo[i].castsource);
    9018       86084 :         tTypeInfo = findTypeByOid(castinfo[i].casttarget);
    9019       86084 :         if (sTypeInfo && tTypeInfo)
    9020       86084 :             appendPQExpBuffer(&namebuf, "%s %s",
    9021             :                               sTypeInfo->dobj.name, tTypeInfo->dobj.name);
    9022       86084 :         castinfo[i].dobj.name = namebuf.data;
    9023             : 
    9024             :         /* Decide whether we want to dump it */
    9025       86084 :         selectDumpableCast(&(castinfo[i]), fout);
    9026             :     }
    9027             : 
    9028         364 :     PQclear(res);
    9029             : 
    9030         364 :     destroyPQExpBuffer(query);
    9031         364 : }
    9032             : 
    9033             : static char *
    9034         188 : get_language_name(Archive *fout, Oid langid)
    9035             : {
    9036             :     PQExpBuffer query;
    9037             :     PGresult   *res;
    9038             :     char       *lanname;
    9039             : 
    9040         188 :     query = createPQExpBuffer();
    9041         188 :     appendPQExpBuffer(query, "SELECT lanname FROM pg_language WHERE oid = %u", langid);
    9042         188 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
    9043         188 :     lanname = pg_strdup(fmtId(PQgetvalue(res, 0, 0)));
    9044         188 :     destroyPQExpBuffer(query);
    9045         188 :     PQclear(res);
    9046             : 
    9047         188 :     return lanname;
    9048             : }
    9049             : 
    9050             : /*
    9051             :  * getTransforms
    9052             :  *    get basic information about every transform in the system
    9053             :  */
    9054             : void
    9055         364 : getTransforms(Archive *fout)
    9056             : {
    9057             :     PGresult   *res;
    9058             :     int         ntups;
    9059             :     int         i;
    9060             :     PQExpBuffer query;
    9061             :     TransformInfo *transforminfo;
    9062             :     int         i_tableoid;
    9063             :     int         i_oid;
    9064             :     int         i_trftype;
    9065             :     int         i_trflang;
    9066             :     int         i_trffromsql;
    9067             :     int         i_trftosql;
    9068             : 
    9069             :     /* Transforms didn't exist pre-9.5 */
    9070         364 :     if (fout->remoteVersion < 90500)
    9071           0 :         return;
    9072             : 
    9073         364 :     query = createPQExpBuffer();
    9074             : 
    9075         364 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, "
    9076             :                          "trftype, trflang, trffromsql::oid, trftosql::oid "
    9077             :                          "FROM pg_transform "
    9078             :                          "ORDER BY 3,4");
    9079             : 
    9080         364 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    9081             : 
    9082         364 :     ntups = PQntuples(res);
    9083             : 
    9084         364 :     transforminfo = (TransformInfo *) pg_malloc(ntups * sizeof(TransformInfo));
    9085             : 
    9086         364 :     i_tableoid = PQfnumber(res, "tableoid");
    9087         364 :     i_oid = PQfnumber(res, "oid");
    9088         364 :     i_trftype = PQfnumber(res, "trftype");
    9089         364 :     i_trflang = PQfnumber(res, "trflang");
    9090         364 :     i_trffromsql = PQfnumber(res, "trffromsql");
    9091         364 :     i_trftosql = PQfnumber(res, "trftosql");
    9092             : 
    9093         474 :     for (i = 0; i < ntups; i++)
    9094             :     {
    9095             :         PQExpBufferData namebuf;
    9096             :         TypeInfo   *typeInfo;
    9097             :         char       *lanname;
    9098             : 
    9099         110 :         transforminfo[i].dobj.objType = DO_TRANSFORM;
    9100         110 :         transforminfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    9101         110 :         transforminfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    9102         110 :         AssignDumpId(&transforminfo[i].dobj);
    9103         110 :         transforminfo[i].trftype = atooid(PQgetvalue(res, i, i_trftype));
    9104         110 :         transforminfo[i].trflang = atooid(PQgetvalue(res, i, i_trflang));
    9105         110 :         transforminfo[i].trffromsql = atooid(PQgetvalue(res, i, i_trffromsql));
    9106         110 :         transforminfo[i].trftosql = atooid(PQgetvalue(res, i, i_trftosql));
    9107             : 
    9108             :         /*
    9109             :          * Try to name transform as concatenation of type and language name.
    9110             :          * This is only used for purposes of sorting.  If we fail to find
    9111             :          * either, the name will be an empty string.
    9112             :          */
    9113         110 :         initPQExpBuffer(&namebuf);
    9114         110 :         typeInfo = findTypeByOid(transforminfo[i].trftype);
    9115         110 :         lanname = get_language_name(fout, transforminfo[i].trflang);
    9116         110 :         if (typeInfo && lanname)
    9117         110 :             appendPQExpBuffer(&namebuf, "%s %s",
    9118             :                               typeInfo->dobj.name, lanname);
    9119         110 :         transforminfo[i].dobj.name = namebuf.data;
    9120         110 :         free(lanname);
    9121             : 
    9122             :         /* Decide whether we want to dump it */
    9123         110 :         selectDumpableObject(&(transforminfo[i].dobj), fout);
    9124             :     }
    9125             : 
    9126         364 :     PQclear(res);
    9127             : 
    9128         364 :     destroyPQExpBuffer(query);
    9129             : }
    9130             : 
    9131             : /*
    9132             :  * getTableAttrs -
    9133             :  *    for each interesting table, read info about its attributes
    9134             :  *    (names, types, default values, CHECK constraints, etc)
    9135             :  *
    9136             :  *  modifies tblinfo
    9137             :  */
    9138             : void
    9139         364 : getTableAttrs(Archive *fout, TableInfo *tblinfo, int numTables)
    9140             : {
    9141         364 :     DumpOptions *dopt = fout->dopt;
    9142         364 :     PQExpBuffer q = createPQExpBuffer();
    9143         364 :     PQExpBuffer tbloids = createPQExpBuffer();
    9144         364 :     PQExpBuffer checkoids = createPQExpBuffer();
    9145         364 :     PQExpBuffer invalidnotnulloids = NULL;
    9146             :     PGresult   *res;
    9147             :     int         ntups;
    9148             :     int         curtblindx;
    9149             :     int         i_attrelid;
    9150             :     int         i_attnum;
    9151             :     int         i_attname;
    9152             :     int         i_atttypname;
    9153             :     int         i_attstattarget;
    9154             :     int         i_attstorage;
    9155             :     int         i_typstorage;
    9156             :     int         i_attidentity;
    9157             :     int         i_attgenerated;
    9158             :     int         i_attisdropped;
    9159             :     int         i_attlen;
    9160             :     int         i_attalign;
    9161             :     int         i_attislocal;
    9162             :     int         i_notnull_name;
    9163             :     int         i_notnull_comment;
    9164             :     int         i_notnull_noinherit;
    9165             :     int         i_notnull_islocal;
    9166             :     int         i_notnull_invalidoid;
    9167             :     int         i_attoptions;
    9168             :     int         i_attcollation;
    9169             :     int         i_attcompression;
    9170             :     int         i_attfdwoptions;
    9171             :     int         i_attmissingval;
    9172             :     int         i_atthasdef;
    9173             : 
    9174             :     /*
    9175             :      * We want to perform just one query against pg_attribute, and then just
    9176             :      * one against pg_attrdef (for DEFAULTs) and two against pg_constraint
    9177             :      * (for CHECK constraints and for NOT NULL constraints).  However, we
    9178             :      * mustn't try to select every row of those catalogs and then sort it out
    9179             :      * on the client side, because some of the server-side functions we need
    9180             :      * would be unsafe to apply to tables we don't have lock on.  Hence, we
    9181             :      * build an array of the OIDs of tables we care about (and now have lock
    9182             :      * on!), and use a WHERE clause to constrain which rows are selected.
    9183             :      */
    9184         364 :     appendPQExpBufferChar(tbloids, '{');
    9185         364 :     appendPQExpBufferChar(checkoids, '{');
    9186       96818 :     for (int i = 0; i < numTables; i++)
    9187             :     {
    9188       96454 :         TableInfo  *tbinfo = &tblinfo[i];
    9189             : 
    9190             :         /* Don't bother to collect info for sequences */
    9191       96454 :         if (tbinfo->relkind == RELKIND_SEQUENCE)
    9192        1294 :             continue;
    9193             : 
    9194             :         /*
    9195             :          * Don't bother with uninteresting tables, either.  For binary
    9196             :          * upgrades, this is bypassed for pg_largeobject_metadata and
    9197             :          * pg_shdepend so that the columns names are collected for the
    9198             :          * corresponding COPY commands.  Restoring the data for those catalogs
    9199             :          * is faster than restoring the equivalent set of large object
    9200             :          * commands.  We can only do this for upgrades from v12 and newer; in
    9201             :          * older versions, pg_largeobject_metadata was created WITH OIDS, so
    9202             :          * the OID column is hidden and won't be dumped.
    9203             :          */
    9204       95160 :         if (!tbinfo->interesting &&
    9205       81550 :             !(fout->dopt->binary_upgrade && fout->remoteVersion >= 120000 &&
    9206       15444 :               (tbinfo->dobj.catId.oid == LargeObjectMetadataRelationId ||
    9207       15372 :                tbinfo->dobj.catId.oid == SharedDependRelationId)))
    9208       81406 :             continue;
    9209             : 
    9210             :         /* OK, we need info for this table */
    9211       13754 :         if (tbloids->len > 1) /* do we have more than the '{'? */
    9212       13478 :             appendPQExpBufferChar(tbloids, ',');
    9213       13754 :         appendPQExpBuffer(tbloids, "%u", tbinfo->dobj.catId.oid);
    9214             : 
    9215       13754 :         if (tbinfo->ncheck > 0)
    9216             :         {
    9217             :             /* Also make a list of the ones with check constraints */
    9218        1124 :             if (checkoids->len > 1) /* do we have more than the '{'? */
    9219         980 :                 appendPQExpBufferChar(checkoids, ',');
    9220        1124 :             appendPQExpBuffer(checkoids, "%u", tbinfo->dobj.catId.oid);
    9221             :         }
    9222             :     }
    9223         364 :     appendPQExpBufferChar(tbloids, '}');
    9224         364 :     appendPQExpBufferChar(checkoids, '}');
    9225             : 
    9226             :     /*
    9227             :      * Find all the user attributes and their types.
    9228             :      *
    9229             :      * Since we only want to dump COLLATE clauses for attributes whose
    9230             :      * collation is different from their type's default, we use a CASE here to
    9231             :      * suppress uninteresting attcollations cheaply.
    9232             :      */
    9233         364 :     appendPQExpBufferStr(q,
    9234             :                          "SELECT\n"
    9235             :                          "a.attrelid,\n"
    9236             :                          "a.attnum,\n"
    9237             :                          "a.attname,\n"
    9238             :                          "a.attstattarget,\n"
    9239             :                          "a.attstorage,\n"
    9240             :                          "t.typstorage,\n"
    9241             :                          "a.atthasdef,\n"
    9242             :                          "a.attisdropped,\n"
    9243             :                          "a.attlen,\n"
    9244             :                          "a.attalign,\n"
    9245             :                          "a.attislocal,\n"
    9246             :                          "pg_catalog.format_type(t.oid, a.atttypmod) AS atttypname,\n"
    9247             :                          "array_to_string(a.attoptions, ', ') AS attoptions,\n"
    9248             :                          "CASE WHEN a.attcollation <> t.typcollation "
    9249             :                          "THEN a.attcollation ELSE 0 END AS attcollation,\n"
    9250             :                          "pg_catalog.array_to_string(ARRAY("
    9251             :                          "SELECT pg_catalog.quote_ident(option_name) || "
    9252             :                          "' ' || pg_catalog.quote_literal(option_value) "
    9253             :                          "FROM pg_catalog.pg_options_to_table(attfdwoptions) "
    9254             :                          "ORDER BY option_name"
    9255             :                          "), E',\n    ') AS attfdwoptions,\n");
    9256             : 
    9257             :     /*
    9258             :      * Find out any NOT NULL markings for each column.  In 18 and up we read
    9259             :      * pg_constraint to obtain the constraint name, and for valid constraints
    9260             :      * also pg_description to obtain its comment.  notnull_noinherit is set
    9261             :      * according to the NO INHERIT property.  For versions prior to 18, we
    9262             :      * store an empty string as the name when a constraint is marked as
    9263             :      * attnotnull (this cues dumpTableSchema to print the NOT NULL clause
    9264             :      * without a name); also, such cases are never NO INHERIT.
    9265             :      *
    9266             :      * For invalid constraints, we need to store their OIDs for processing
    9267             :      * elsewhere, so we bring the pg_constraint.oid value when the constraint
    9268             :      * is invalid, and NULL otherwise.  Their comments are handled not here
    9269             :      * but by collectComments, because they're their own dumpable object.
    9270             :      *
    9271             :      * We track in notnull_islocal whether the constraint was defined directly
    9272             :      * in this table or via an ancestor, for binary upgrade.  flagInhAttrs
    9273             :      * might modify this later; that routine is also in charge of determining
    9274             :      * the correct inhcount.
    9275             :      */
    9276         364 :     if (fout->remoteVersion >= 180000)
    9277         364 :         appendPQExpBufferStr(q,
    9278             :                              "co.conname AS notnull_name,\n"
    9279             :                              "CASE WHEN co.convalidated THEN pt.description"
    9280             :                              " ELSE NULL END AS notnull_comment,\n"
    9281             :                              "CASE WHEN NOT co.convalidated THEN co.oid "
    9282             :                              "ELSE NULL END AS notnull_invalidoid,\n"
    9283             :                              "co.connoinherit AS notnull_noinherit,\n"
    9284             :                              "co.conislocal AS notnull_islocal,\n");
    9285             :     else
    9286           0 :         appendPQExpBufferStr(q,
    9287             :                              "CASE WHEN a.attnotnull THEN '' ELSE NULL END AS notnull_name,\n"
    9288             :                              "NULL AS notnull_comment,\n"
    9289             :                              "NULL AS notnull_invalidoid,\n"
    9290             :                              "false AS notnull_noinherit,\n"
    9291             :                              "a.attislocal AS notnull_islocal,\n");
    9292             : 
    9293         364 :     if (fout->remoteVersion >= 140000)
    9294         364 :         appendPQExpBufferStr(q,
    9295             :                              "a.attcompression AS attcompression,\n");
    9296             :     else
    9297           0 :         appendPQExpBufferStr(q,
    9298             :                              "'' AS attcompression,\n");
    9299             : 
    9300         364 :     if (fout->remoteVersion >= 100000)
    9301         364 :         appendPQExpBufferStr(q,
    9302             :                              "a.attidentity,\n");
    9303             :     else
    9304           0 :         appendPQExpBufferStr(q,
    9305             :                              "'' AS attidentity,\n");
    9306             : 
    9307         364 :     if (fout->remoteVersion >= 110000)
    9308         364 :         appendPQExpBufferStr(q,
    9309             :                              "CASE WHEN a.atthasmissing AND NOT a.attisdropped "
    9310             :                              "THEN a.attmissingval ELSE null END AS attmissingval,\n");
    9311             :     else
    9312           0 :         appendPQExpBufferStr(q,
    9313             :                              "NULL AS attmissingval,\n");
    9314             : 
    9315         364 :     if (fout->remoteVersion >= 120000)
    9316         364 :         appendPQExpBufferStr(q,
    9317             :                              "a.attgenerated\n");
    9318             :     else
    9319           0 :         appendPQExpBufferStr(q,
    9320             :                              "'' AS attgenerated\n");
    9321             : 
    9322             :     /* need left join to pg_type to not fail on dropped columns ... */
    9323         364 :     appendPQExpBuffer(q,
    9324             :                       "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
    9325             :                       "JOIN pg_catalog.pg_attribute a ON (src.tbloid = a.attrelid) "
    9326             :                       "LEFT JOIN pg_catalog.pg_type t "
    9327             :                       "ON (a.atttypid = t.oid)\n",
    9328             :                       tbloids->data);
    9329             : 
    9330             :     /*
    9331             :      * In versions 18 and up, we need pg_constraint for explicit NOT NULL
    9332             :      * entries and pg_description to get their comments.
    9333             :      */
    9334         364 :     if (fout->remoteVersion >= 180000)
    9335         364 :         appendPQExpBufferStr(q,
    9336             :                              " LEFT JOIN pg_catalog.pg_constraint co ON "
    9337             :                              "(a.attrelid = co.conrelid\n"
    9338             :                              "   AND co.contype = 'n' AND "
    9339             :                              "co.conkey = array[a.attnum])\n"
    9340             :                              " LEFT JOIN pg_catalog.pg_description pt ON "
    9341             :                              "(pt.classoid = co.tableoid AND pt.objoid = co.oid)\n");
    9342             : 
    9343         364 :     appendPQExpBufferStr(q,
    9344             :                          "WHERE a.attnum > 0::pg_catalog.int2\n"
    9345             :                          "ORDER BY a.attrelid, a.attnum");
    9346             : 
    9347         364 :     res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
    9348             : 
    9349         364 :     ntups = PQntuples(res);
    9350             : 
    9351         364 :     i_attrelid = PQfnumber(res, "attrelid");
    9352         364 :     i_attnum = PQfnumber(res, "attnum");
    9353         364 :     i_attname = PQfnumber(res, "attname");
    9354         364 :     i_atttypname = PQfnumber(res, "atttypname");
    9355         364 :     i_attstattarget = PQfnumber(res, "attstattarget");
    9356         364 :     i_attstorage = PQfnumber(res, "attstorage");
    9357         364 :     i_typstorage = PQfnumber(res, "typstorage");
    9358         364 :     i_attidentity = PQfnumber(res, "attidentity");
    9359         364 :     i_attgenerated = PQfnumber(res, "attgenerated");
    9360         364 :     i_attisdropped = PQfnumber(res, "attisdropped");
    9361         364 :     i_attlen = PQfnumber(res, "attlen");
    9362         364 :     i_attalign = PQfnumber(res, "attalign");
    9363         364 :     i_attislocal = PQfnumber(res, "attislocal");
    9364         364 :     i_notnull_name = PQfnumber(res, "notnull_name");
    9365         364 :     i_notnull_comment = PQfnumber(res, "notnull_comment");
    9366         364 :     i_notnull_invalidoid = PQfnumber(res, "notnull_invalidoid");
    9367         364 :     i_notnull_noinherit = PQfnumber(res, "notnull_noinherit");
    9368         364 :     i_notnull_islocal = PQfnumber(res, "notnull_islocal");
    9369         364 :     i_attoptions = PQfnumber(res, "attoptions");
    9370         364 :     i_attcollation = PQfnumber(res, "attcollation");
    9371         364 :     i_attcompression = PQfnumber(res, "attcompression");
    9372         364 :     i_attfdwoptions = PQfnumber(res, "attfdwoptions");
    9373         364 :     i_attmissingval = PQfnumber(res, "attmissingval");
    9374         364 :     i_atthasdef = PQfnumber(res, "atthasdef");
    9375             : 
    9376             :     /* Within the next loop, we'll accumulate OIDs of tables with defaults */
    9377         364 :     resetPQExpBuffer(tbloids);
    9378         364 :     appendPQExpBufferChar(tbloids, '{');
    9379             : 
    9380             :     /*
    9381             :      * Outer loop iterates once per table, not once per row.  Incrementing of
    9382             :      * r is handled by the inner loop.
    9383             :      */
    9384         364 :     curtblindx = -1;
    9385       13824 :     for (int r = 0; r < ntups;)
    9386             :     {
    9387       13460 :         Oid         attrelid = atooid(PQgetvalue(res, r, i_attrelid));
    9388       13460 :         TableInfo  *tbinfo = NULL;
    9389             :         int         numatts;
    9390             :         bool        hasdefaults;
    9391             : 
    9392             :         /* Count rows for this table */
    9393       49884 :         for (numatts = 1; numatts < ntups - r; numatts++)
    9394       49614 :             if (atooid(PQgetvalue(res, r + numatts, i_attrelid)) != attrelid)
    9395       13190 :                 break;
    9396             : 
    9397             :         /*
    9398             :          * Locate the associated TableInfo; we rely on tblinfo[] being in OID
    9399             :          * order.
    9400             :          */
    9401       66300 :         while (++curtblindx < numTables)
    9402             :         {
    9403       66300 :             tbinfo = &tblinfo[curtblindx];
    9404       66300 :             if (tbinfo->dobj.catId.oid == attrelid)
    9405       13460 :                 break;
    9406             :         }
    9407       13460 :         if (curtblindx >= numTables)
    9408           0 :             pg_fatal("unrecognized table OID %u", attrelid);
    9409             :         /* cross-check that we only got requested tables */
    9410       13460 :         if (tbinfo->relkind == RELKIND_SEQUENCE ||
    9411       13460 :             (!tbinfo->interesting &&
    9412         144 :              !(fout->dopt->binary_upgrade && fout->remoteVersion >= 120000 &&
    9413         144 :                (tbinfo->dobj.catId.oid == LargeObjectMetadataRelationId ||
    9414          72 :                 tbinfo->dobj.catId.oid == SharedDependRelationId))))
    9415           0 :             pg_fatal("unexpected column data for table \"%s\"",
    9416             :                      tbinfo->dobj.name);
    9417             : 
    9418             :         /* Save data for this table */
    9419       13460 :         tbinfo->numatts = numatts;
    9420       13460 :         tbinfo->attnames = (char **) pg_malloc(numatts * sizeof(char *));
    9421       13460 :         tbinfo->atttypnames = (char **) pg_malloc(numatts * sizeof(char *));
    9422       13460 :         tbinfo->attstattarget = (int *) pg_malloc(numatts * sizeof(int));
    9423       13460 :         tbinfo->attstorage = (char *) pg_malloc(numatts * sizeof(char));
    9424       13460 :         tbinfo->typstorage = (char *) pg_malloc(numatts * sizeof(char));
    9425       13460 :         tbinfo->attidentity = (char *) pg_malloc(numatts * sizeof(char));
    9426       13460 :         tbinfo->attgenerated = (char *) pg_malloc(numatts * sizeof(char));
    9427       13460 :         tbinfo->attisdropped = (bool *) pg_malloc(numatts * sizeof(bool));
    9428       13460 :         tbinfo->attlen = (int *) pg_malloc(numatts * sizeof(int));
    9429       13460 :         tbinfo->attalign = (char *) pg_malloc(numatts * sizeof(char));
    9430       13460 :         tbinfo->attislocal = (bool *) pg_malloc(numatts * sizeof(bool));
    9431       13460 :         tbinfo->attoptions = (char **) pg_malloc(numatts * sizeof(char *));
    9432       13460 :         tbinfo->attcollation = (Oid *) pg_malloc(numatts * sizeof(Oid));
    9433       13460 :         tbinfo->attcompression = (char *) pg_malloc(numatts * sizeof(char));
    9434       13460 :         tbinfo->attfdwoptions = (char **) pg_malloc(numatts * sizeof(char *));
    9435       13460 :         tbinfo->attmissingval = (char **) pg_malloc(numatts * sizeof(char *));
    9436       13460 :         tbinfo->notnull_constrs = (char **) pg_malloc(numatts * sizeof(char *));
    9437       13460 :         tbinfo->notnull_comment = (char **) pg_malloc(numatts * sizeof(char *));
    9438       13460 :         tbinfo->notnull_invalid = (bool *) pg_malloc(numatts * sizeof(bool));
    9439       13460 :         tbinfo->notnull_noinh = (bool *) pg_malloc(numatts * sizeof(bool));
    9440       13460 :         tbinfo->notnull_islocal = (bool *) pg_malloc(numatts * sizeof(bool));
    9441       13460 :         tbinfo->attrdefs = (AttrDefInfo **) pg_malloc(numatts * sizeof(AttrDefInfo *));
    9442       13460 :         hasdefaults = false;
    9443             : 
    9444       63344 :         for (int j = 0; j < numatts; j++, r++)
    9445             :         {
    9446       49884 :             if (j + 1 != atoi(PQgetvalue(res, r, i_attnum)))
    9447           0 :                 pg_fatal("invalid column numbering in table \"%s\"",
    9448             :                          tbinfo->dobj.name);
    9449       49884 :             tbinfo->attnames[j] = pg_strdup(PQgetvalue(res, r, i_attname));
    9450       49884 :             tbinfo->atttypnames[j] = pg_strdup(PQgetvalue(res, r, i_atttypname));
    9451       49884 :             if (PQgetisnull(res, r, i_attstattarget))
    9452       49798 :                 tbinfo->attstattarget[j] = -1;
    9453             :             else
    9454          86 :                 tbinfo->attstattarget[j] = atoi(PQgetvalue(res, r, i_attstattarget));
    9455       49884 :             tbinfo->attstorage[j] = *(PQgetvalue(res, r, i_attstorage));
    9456       49884 :             tbinfo->typstorage[j] = *(PQgetvalue(res, r, i_typstorage));
    9457       49884 :             tbinfo->attidentity[j] = *(PQgetvalue(res, r, i_attidentity));
    9458       49884 :             tbinfo->attgenerated[j] = *(PQgetvalue(res, r, i_attgenerated));
    9459       49884 :             tbinfo->needs_override = tbinfo->needs_override || (tbinfo->attidentity[j] == ATTRIBUTE_IDENTITY_ALWAYS);
    9460       49884 :             tbinfo->attisdropped[j] = (PQgetvalue(res, r, i_attisdropped)[0] == 't');
    9461       49884 :             tbinfo->attlen[j] = atoi(PQgetvalue(res, r, i_attlen));
    9462       49884 :             tbinfo->attalign[j] = *(PQgetvalue(res, r, i_attalign));
    9463       49884 :             tbinfo->attislocal[j] = (PQgetvalue(res, r, i_attislocal)[0] == 't');
    9464             : 
    9465             :             /* Handle not-null constraint name and flags */
    9466       49884 :             determineNotNullFlags(fout, res, r,
    9467             :                                   tbinfo, j,
    9468             :                                   i_notnull_name,
    9469             :                                   i_notnull_comment,
    9470             :                                   i_notnull_invalidoid,
    9471             :                                   i_notnull_noinherit,
    9472             :                                   i_notnull_islocal,
    9473             :                                   &invalidnotnulloids);
    9474             : 
    9475       49884 :             tbinfo->notnull_comment[j] = PQgetisnull(res, r, i_notnull_comment) ?
    9476       49884 :                 NULL : pg_strdup(PQgetvalue(res, r, i_notnull_comment));
    9477       49884 :             tbinfo->attoptions[j] = pg_strdup(PQgetvalue(res, r, i_attoptions));
    9478       49884 :             tbinfo->attcollation[j] = atooid(PQgetvalue(res, r, i_attcollation));
    9479       49884 :             tbinfo->attcompression[j] = *(PQgetvalue(res, r, i_attcompression));
    9480       49884 :             tbinfo->attfdwoptions[j] = pg_strdup(PQgetvalue(res, r, i_attfdwoptions));
    9481       49884 :             tbinfo->attmissingval[j] = pg_strdup(PQgetvalue(res, r, i_attmissingval));
    9482       49884 :             tbinfo->attrdefs[j] = NULL; /* fix below */
    9483       49884 :             if (PQgetvalue(res, r, i_atthasdef)[0] == 't')
    9484        2632 :                 hasdefaults = true;
    9485             :         }
    9486             : 
    9487       13460 :         if (hasdefaults)
    9488             :         {
    9489             :             /* Collect OIDs of interesting tables that have defaults */
    9490        1970 :             if (tbloids->len > 1) /* do we have more than the '{'? */
    9491        1828 :                 appendPQExpBufferChar(tbloids, ',');
    9492        1970 :             appendPQExpBuffer(tbloids, "%u", tbinfo->dobj.catId.oid);
    9493             :         }
    9494             :     }
    9495             : 
    9496             :     /* If invalidnotnulloids has any data, finalize it */
    9497         364 :     if (invalidnotnulloids != NULL)
    9498          92 :         appendPQExpBufferChar(invalidnotnulloids, '}');
    9499             : 
    9500         364 :     PQclear(res);
    9501             : 
    9502             :     /*
    9503             :      * Now get info about column defaults.  This is skipped for a data-only
    9504             :      * dump, as it is only needed for table schemas.
    9505             :      */
    9506         364 :     if (dopt->dumpSchema && tbloids->len > 1)
    9507             :     {
    9508             :         AttrDefInfo *attrdefs;
    9509             :         int         numDefaults;
    9510         126 :         TableInfo  *tbinfo = NULL;
    9511             : 
    9512         126 :         pg_log_info("finding table default expressions");
    9513             : 
    9514         126 :         appendPQExpBufferChar(tbloids, '}');
    9515             : 
    9516         126 :         printfPQExpBuffer(q, "SELECT a.tableoid, a.oid, adrelid, adnum, "
    9517             :                           "pg_catalog.pg_get_expr(adbin, adrelid) AS adsrc\n"
    9518             :                           "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
    9519             :                           "JOIN pg_catalog.pg_attrdef a ON (src.tbloid = a.adrelid)\n"
    9520             :                           "ORDER BY a.adrelid, a.adnum",
    9521             :                           tbloids->data);
    9522             : 
    9523         126 :         res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
    9524             : 
    9525         126 :         numDefaults = PQntuples(res);
    9526         126 :         attrdefs = (AttrDefInfo *) pg_malloc(numDefaults * sizeof(AttrDefInfo));
    9527             : 
    9528         126 :         curtblindx = -1;
    9529        2562 :         for (int j = 0; j < numDefaults; j++)
    9530             :         {
    9531        2436 :             Oid         adtableoid = atooid(PQgetvalue(res, j, 0));
    9532        2436 :             Oid         adoid = atooid(PQgetvalue(res, j, 1));
    9533        2436 :             Oid         adrelid = atooid(PQgetvalue(res, j, 2));
    9534        2436 :             int         adnum = atoi(PQgetvalue(res, j, 3));
    9535        2436 :             char       *adsrc = PQgetvalue(res, j, 4);
    9536             : 
    9537             :             /*
    9538             :              * Locate the associated TableInfo; we rely on tblinfo[] being in
    9539             :              * OID order.
    9540             :              */
    9541        2436 :             if (tbinfo == NULL || tbinfo->dobj.catId.oid != adrelid)
    9542             :             {
    9543       38982 :                 while (++curtblindx < numTables)
    9544             :                 {
    9545       38982 :                     tbinfo = &tblinfo[curtblindx];
    9546       38982 :                     if (tbinfo->dobj.catId.oid == adrelid)
    9547        1834 :                         break;
    9548             :                 }
    9549        1834 :                 if (curtblindx >= numTables)
    9550           0 :                     pg_fatal("unrecognized table OID %u", adrelid);
    9551             :             }
    9552             : 
    9553        2436 :             if (adnum <= 0 || adnum > tbinfo->numatts)
    9554           0 :                 pg_fatal("invalid adnum value %d for table \"%s\"",
    9555             :                          adnum, tbinfo->dobj.name);
    9556             : 
    9557             :             /*
    9558             :              * dropped columns shouldn't have defaults, but just in case,
    9559             :              * ignore 'em
    9560             :              */
    9561        2436 :             if (tbinfo->attisdropped[adnum - 1])
    9562           0 :                 continue;
    9563             : 
    9564        2436 :             attrdefs[j].dobj.objType = DO_ATTRDEF;
    9565        2436 :             attrdefs[j].dobj.catId.tableoid = adtableoid;
    9566        2436 :             attrdefs[j].dobj.catId.oid = adoid;
    9567        2436 :             AssignDumpId(&attrdefs[j].dobj);
    9568        2436 :             attrdefs[j].adtable = tbinfo;
    9569        2436 :             attrdefs[j].adnum = adnum;
    9570        2436 :             attrdefs[j].adef_expr = pg_strdup(adsrc);
    9571             : 
    9572        2436 :             attrdefs[j].dobj.name = pg_strdup(tbinfo->dobj.name);
    9573        2436 :             attrdefs[j].dobj.namespace = tbinfo->dobj.namespace;
    9574             : 
    9575        2436 :             attrdefs[j].dobj.dump = tbinfo->dobj.dump;
    9576             : 
    9577             :             /*
    9578             :              * Figure out whether the default/generation expression should be
    9579             :              * dumped as part of the main CREATE TABLE (or similar) command or
    9580             :              * as a separate ALTER TABLE (or similar) command. The preference
    9581             :              * is to put it into the CREATE command, but in some cases that's
    9582             :              * not possible.
    9583             :              */
    9584        2436 :             if (tbinfo->attgenerated[adnum - 1])
    9585             :             {
    9586             :                 /*
    9587             :                  * Column generation expressions cannot be dumped separately,
    9588             :                  * because there is no syntax for it.  By setting separate to
    9589             :                  * false here we prevent the "default" from being processed as
    9590             :                  * its own dumpable object.  Later, flagInhAttrs() will mark
    9591             :                  * it as not to be dumped at all, if possible (that is, if it
    9592             :                  * can be inherited from a parent).
    9593             :                  */
    9594        1360 :                 attrdefs[j].separate = false;
    9595             :             }
    9596        1076 :             else if (tbinfo->relkind == RELKIND_VIEW)
    9597             :             {
    9598             :                 /*
    9599             :                  * Defaults on a VIEW must always be dumped as separate ALTER
    9600             :                  * TABLE commands.
    9601             :                  */
    9602          70 :                 attrdefs[j].separate = true;
    9603             :             }
    9604        1006 :             else if (!shouldPrintColumn(dopt, tbinfo, adnum - 1))
    9605             :             {
    9606             :                 /* column will be suppressed, print default separately */
    9607           8 :                 attrdefs[j].separate = true;
    9608             :             }
    9609             :             else
    9610             :             {
    9611         998 :                 attrdefs[j].separate = false;
    9612             :             }
    9613             : 
    9614        2436 :             if (!attrdefs[j].separate)
    9615             :             {
    9616             :                 /*
    9617             :                  * Mark the default as needing to appear before the table, so
    9618             :                  * that any dependencies it has must be emitted before the
    9619             :                  * CREATE TABLE.  If this is not possible, we'll change to
    9620             :                  * "separate" mode while sorting dependencies.
    9621             :                  */
    9622        2358 :                 addObjectDependency(&tbinfo->dobj,
    9623        2358 :                                     attrdefs[j].dobj.dumpId);
    9624             :             }
    9625             : 
    9626        2436 :             tbinfo->attrdefs[adnum - 1] = &attrdefs[j];
    9627             :         }
    9628             : 
    9629         126 :         PQclear(res);
    9630             :     }
    9631             : 
    9632             :     /*
    9633             :      * Get info about NOT NULL NOT VALID constraints.  This is skipped for a
    9634             :      * data-only dump, as it is only needed for table schemas.
    9635             :      */
    9636         364 :     if (dopt->dumpSchema && invalidnotnulloids)
    9637             :     {
    9638             :         ConstraintInfo *constrs;
    9639             :         int         numConstrs;
    9640             :         int         i_tableoid;
    9641             :         int         i_oid;
    9642             :         int         i_conrelid;
    9643             :         int         i_conname;
    9644             :         int         i_consrc;
    9645             :         int         i_conislocal;
    9646             : 
    9647          80 :         pg_log_info("finding invalid not-null constraints");
    9648             : 
    9649          80 :         resetPQExpBuffer(q);
    9650          80 :         appendPQExpBuffer(q,
    9651             :                           "SELECT c.tableoid, c.oid, conrelid, conname, "
    9652             :                           "pg_catalog.pg_get_constraintdef(c.oid) AS consrc, "
    9653             :                           "conislocal, convalidated "
    9654             :                           "FROM unnest('%s'::pg_catalog.oid[]) AS src(conoid)\n"
    9655             :                           "JOIN pg_catalog.pg_constraint c ON (src.conoid = c.oid)\n"
    9656             :                           "ORDER BY c.conrelid, c.conname",
    9657          80 :                           invalidnotnulloids->data);
    9658             : 
    9659          80 :         res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
    9660             : 
    9661          80 :         numConstrs = PQntuples(res);
    9662          80 :         constrs = (ConstraintInfo *) pg_malloc(numConstrs * sizeof(ConstraintInfo));
    9663             : 
    9664          80 :         i_tableoid = PQfnumber(res, "tableoid");
    9665          80 :         i_oid = PQfnumber(res, "oid");
    9666          80 :         i_conrelid = PQfnumber(res, "conrelid");
    9667          80 :         i_conname = PQfnumber(res, "conname");
    9668          80 :         i_consrc = PQfnumber(res, "consrc");
    9669          80 :         i_conislocal = PQfnumber(res, "conislocal");
    9670             : 
    9671             :         /* As above, this loop iterates once per table, not once per row */
    9672          80 :         curtblindx = -1;
    9673         220 :         for (int j = 0; j < numConstrs;)
    9674             :         {
    9675         140 :             Oid         conrelid = atooid(PQgetvalue(res, j, i_conrelid));
    9676         140 :             TableInfo  *tbinfo = NULL;
    9677             :             int         numcons;
    9678             : 
    9679             :             /* Count rows for this table */
    9680         140 :             for (numcons = 1; numcons < numConstrs - j; numcons++)
    9681          60 :                 if (atooid(PQgetvalue(res, j + numcons, i_conrelid)) != conrelid)
    9682          60 :                     break;
    9683             : 
    9684             :             /*
    9685             :              * Locate the associated TableInfo; we rely on tblinfo[] being in
    9686             :              * OID order.
    9687             :              */
    9688       26890 :             while (++curtblindx < numTables)
    9689             :             {
    9690       26890 :                 tbinfo = &tblinfo[curtblindx];
    9691       26890 :                 if (tbinfo->dobj.catId.oid == conrelid)
    9692         140 :                     break;
    9693             :             }
    9694         140 :             if (curtblindx >= numTables)
    9695           0 :                 pg_fatal("unrecognized table OID %u", conrelid);
    9696             : 
    9697         280 :             for (int c = 0; c < numcons; c++, j++)
    9698             :             {
    9699         140 :                 constrs[j].dobj.objType = DO_CONSTRAINT;
    9700         140 :                 constrs[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
    9701         140 :                 constrs[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
    9702         140 :                 AssignDumpId(&constrs[j].dobj);
    9703         140 :                 constrs[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_conname));
    9704         140 :                 constrs[j].dobj.namespace = tbinfo->dobj.namespace;
    9705         140 :                 constrs[j].contable = tbinfo;
    9706         140 :                 constrs[j].condomain = NULL;
    9707         140 :                 constrs[j].contype = 'n';
    9708         140 :                 constrs[j].condef = pg_strdup(PQgetvalue(res, j, i_consrc));
    9709         140 :                 constrs[j].confrelid = InvalidOid;
    9710         140 :                 constrs[j].conindex = 0;
    9711         140 :                 constrs[j].condeferrable = false;
    9712         140 :                 constrs[j].condeferred = false;
    9713         140 :                 constrs[j].conislocal = (PQgetvalue(res, j, i_conislocal)[0] == 't');
    9714             : 
    9715             :                 /*
    9716             :                  * All invalid not-null constraints must be dumped separately,
    9717             :                  * because CREATE TABLE would not create them as invalid, and
    9718             :                  * also because they must be created after potentially
    9719             :                  * violating data has been loaded.
    9720             :                  */
    9721         140 :                 constrs[j].separate = true;
    9722             : 
    9723         140 :                 constrs[j].dobj.dump = tbinfo->dobj.dump;
    9724             :             }
    9725             :         }
    9726          80 :         PQclear(res);
    9727             :     }
    9728             : 
    9729             :     /*
    9730             :      * Get info about table CHECK constraints.  This is skipped for a
    9731             :      * data-only dump, as it is only needed for table schemas.
    9732             :      */
    9733         364 :     if (dopt->dumpSchema && checkoids->len > 2)
    9734             :     {
    9735             :         ConstraintInfo *constrs;
    9736             :         int         numConstrs;
    9737             :         int         i_tableoid;
    9738             :         int         i_oid;
    9739             :         int         i_conrelid;
    9740             :         int         i_conname;
    9741             :         int         i_consrc;
    9742             :         int         i_conislocal;
    9743             :         int         i_convalidated;
    9744             : 
    9745         128 :         pg_log_info("finding table check constraints");
    9746             : 
    9747         128 :         resetPQExpBuffer(q);
    9748         128 :         appendPQExpBuffer(q,
    9749             :                           "SELECT c.tableoid, c.oid, conrelid, conname, "
    9750             :                           "pg_catalog.pg_get_constraintdef(c.oid) AS consrc, "
    9751             :                           "conislocal, convalidated "
    9752             :                           "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
    9753             :                           "JOIN pg_catalog.pg_constraint c ON (src.tbloid = c.conrelid)\n"
    9754             :                           "WHERE contype = 'c' "
    9755             :                           "ORDER BY c.conrelid, c.conname",
    9756             :                           checkoids->data);
    9757             : 
    9758         128 :         res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
    9759             : 
    9760         128 :         numConstrs = PQntuples(res);
    9761         128 :         constrs = (ConstraintInfo *) pg_malloc(numConstrs * sizeof(ConstraintInfo));
    9762             : 
    9763         128 :         i_tableoid = PQfnumber(res, "tableoid");
    9764         128 :         i_oid = PQfnumber(res, "oid");
    9765         128 :         i_conrelid = PQfnumber(res, "conrelid");
    9766         128 :         i_conname = PQfnumber(res, "conname");
    9767         128 :         i_consrc = PQfnumber(res, "consrc");
    9768         128 :         i_conislocal = PQfnumber(res, "conislocal");
    9769         128 :         i_convalidated = PQfnumber(res, "convalidated");
    9770             : 
    9771             :         /* As above, this loop iterates once per table, not once per row */
    9772         128 :         curtblindx = -1;
    9773        1150 :         for (int j = 0; j < numConstrs;)
    9774             :         {
    9775        1022 :             Oid         conrelid = atooid(PQgetvalue(res, j, i_conrelid));
    9776        1022 :             TableInfo  *tbinfo = NULL;
    9777             :             int         numcons;
    9778             : 
    9779             :             /* Count rows for this table */
    9780        1304 :             for (numcons = 1; numcons < numConstrs - j; numcons++)
    9781        1176 :                 if (atooid(PQgetvalue(res, j + numcons, i_conrelid)) != conrelid)
    9782         894 :                     break;
    9783             : 
    9784             :             /*
    9785             :              * Locate the associated TableInfo; we rely on tblinfo[] being in
    9786             :              * OID order.
    9787             :              */
    9788       37638 :             while (++curtblindx < numTables)
    9789             :             {
    9790       37638 :                 tbinfo = &tblinfo[curtblindx];
    9791       37638 :                 if (tbinfo->dobj.catId.oid == conrelid)
    9792        1022 :                     break;
    9793             :             }
    9794        1022 :             if (curtblindx >= numTables)
    9795           0 :                 pg_fatal("unrecognized table OID %u", conrelid);
    9796             : 
    9797        1022 :             if (numcons != tbinfo->ncheck)
    9798             :             {
    9799           0 :                 pg_log_error(ngettext("expected %d check constraint on table \"%s\" but found %d",
    9800             :                                       "expected %d check constraints on table \"%s\" but found %d",
    9801             :                                       tbinfo->ncheck),
    9802             :                              tbinfo->ncheck, tbinfo->dobj.name, numcons);
    9803           0 :                 pg_log_error_hint("The system catalogs might be corrupted.");
    9804           0 :                 exit_nicely(1);
    9805             :             }
    9806             : 
    9807        1022 :             tbinfo->checkexprs = constrs + j;
    9808             : 
    9809        2326 :             for (int c = 0; c < numcons; c++, j++)
    9810             :             {
    9811        1304 :                 bool        validated = PQgetvalue(res, j, i_convalidated)[0] == 't';
    9812             : 
    9813        1304 :                 constrs[j].dobj.objType = DO_CONSTRAINT;
    9814        1304 :                 constrs[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
    9815        1304 :                 constrs[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
    9816        1304 :                 AssignDumpId(&constrs[j].dobj);
    9817        1304 :                 constrs[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_conname));
    9818        1304 :                 constrs[j].dobj.namespace = tbinfo->dobj.namespace;
    9819        1304 :                 constrs[j].contable = tbinfo;
    9820        1304 :                 constrs[j].condomain = NULL;
    9821        1304 :                 constrs[j].contype = 'c';
    9822        1304 :                 constrs[j].condef = pg_strdup(PQgetvalue(res, j, i_consrc));
    9823        1304 :                 constrs[j].confrelid = InvalidOid;
    9824        1304 :                 constrs[j].conindex = 0;
    9825        1304 :                 constrs[j].condeferrable = false;
    9826        1304 :                 constrs[j].condeferred = false;
    9827        1304 :                 constrs[j].conislocal = (PQgetvalue(res, j, i_conislocal)[0] == 't');
    9828             : 
    9829             :                 /*
    9830             :                  * An unvalidated constraint needs to be dumped separately, so
    9831             :                  * that potentially-violating existing data is loaded before
    9832             :                  * the constraint.
    9833             :                  */
    9834        1304 :                 constrs[j].separate = !validated;
    9835             : 
    9836        1304 :                 constrs[j].dobj.dump = tbinfo->dobj.dump;
    9837             : 
    9838             :                 /*
    9839             :                  * Mark the constraint as needing to appear before the table
    9840             :                  * --- this is so that any other dependencies of the
    9841             :                  * constraint will be emitted before we try to create the
    9842             :                  * table.  If the constraint is to be dumped separately, it
    9843             :                  * will be dumped after data is loaded anyway, so don't do it.
    9844             :                  * (There's an automatic dependency in the opposite direction
    9845             :                  * anyway, so don't need to add one manually here.)
    9846             :                  */
    9847        1304 :                 if (!constrs[j].separate)
    9848        1174 :                     addObjectDependency(&tbinfo->dobj,
    9849        1174 :                                         constrs[j].dobj.dumpId);
    9850             : 
    9851             :                 /*
    9852             :                  * We will detect later whether the constraint must be split
    9853             :                  * out from the table definition.
    9854             :                  */
    9855             :             }
    9856             :         }
    9857             : 
    9858         128 :         PQclear(res);
    9859             :     }
    9860             : 
    9861         364 :     destroyPQExpBuffer(q);
    9862         364 :     destroyPQExpBuffer(tbloids);
    9863         364 :     destroyPQExpBuffer(checkoids);
    9864         364 : }
    9865             : 
    9866             : /*
    9867             :  * Based on the getTableAttrs query's row corresponding to one column, set
    9868             :  * the name and flags to handle a not-null constraint for that column in
    9869             :  * the tbinfo struct.
    9870             :  *
    9871             :  * Result row 'r' is for tbinfo's attribute 'j'.
    9872             :  *
    9873             :  * There are four possibilities:
    9874             :  * 1) the column has no not-null constraints. In that case, ->notnull_constrs
    9875             :  *    (the constraint name) remains NULL.
    9876             :  * 2) The column has a constraint with no name (this is the case when
    9877             :  *    constraints come from pre-18 servers).  In this case, ->notnull_constrs
    9878             :  *    is set to the empty string; dumpTableSchema will print just "NOT NULL".
    9879             :  * 3) The column has an invalid not-null constraint.  This must be treated
    9880             :  *    as a separate object (because it must be created after the table data
    9881             :  *    is loaded).  So we add its OID to invalidnotnulloids for processing
    9882             :  *    elsewhere and do nothing further with it here.  We distinguish this
    9883             :  *    case because the "notnull_invalidoid" column has been set to a non-NULL
    9884             :  *    value, which is the constraint OID.  Valid constraints have a null OID.
    9885             :  * 4) The column has a constraint with a known name; in that case
    9886             :  *    notnull_constrs carries that name and dumpTableSchema will print
    9887             :  *    "CONSTRAINT the_name NOT NULL".  However, if the name is the default
    9888             :  *    (table_column_not_null) and there's no comment on the constraint,
    9889             :  *    there's no need to print that name in the dump, so notnull_constrs
    9890             :  *    is set to the empty string and it behaves as case 2.
    9891             :  *
    9892             :  * In a child table that inherits from a parent already containing NOT NULL
    9893             :  * constraints and the columns in the child don't have their own NOT NULL
    9894             :  * declarations, we suppress printing constraints in the child: the
    9895             :  * constraints are acquired at the point where the child is attached to the
    9896             :  * parent.  This is tracked in ->notnull_islocal; for servers pre-18 this is
    9897             :  * set not here but in flagInhAttrs.  That flag is also used when the
    9898             :  * constraint was validated in a child but all its parent have it as NOT
    9899             :  * VALID.
    9900             :  *
    9901             :  * Any of these constraints might have the NO INHERIT bit.  If so we set
    9902             :  * ->notnull_noinh and NO INHERIT will be printed by dumpTableSchema.
    9903             :  *
    9904             :  * In case 4 above, the name comparison is a bit of a hack; it actually fails
    9905             :  * to do the right thing in all but the trivial case.  However, the downside
    9906             :  * of getting it wrong is simply that the name is printed rather than
    9907             :  * suppressed, so it's not a big deal.
    9908             :  *
    9909             :  * invalidnotnulloids is expected to be given as NULL; if any invalid not-null
    9910             :  * constraints are found, it is initialized and filled with the array of
    9911             :  * OIDs of such constraints, for later processing.
    9912             :  */
    9913             : static void
    9914       49884 : determineNotNullFlags(Archive *fout, PGresult *res, int r,
    9915             :                       TableInfo *tbinfo, int j,
    9916             :                       int i_notnull_name,
    9917             :                       int i_notnull_comment,
    9918             :                       int i_notnull_invalidoid,
    9919             :                       int i_notnull_noinherit,
    9920             :                       int i_notnull_islocal,
    9921             :                       PQExpBuffer *invalidnotnulloids)
    9922             : {
    9923       49884 :     DumpOptions *dopt = fout->dopt;
    9924             : 
    9925             :     /*
    9926             :      * If this not-null constraint is not valid, list its OID in
    9927             :      * invalidnotnulloids and do nothing further.  It'll be processed
    9928             :      * elsewhere later.
    9929             :      *
    9930             :      * Because invalid not-null constraints are rare, we don't want to malloc
    9931             :      * invalidnotnulloids until we're sure we're going it need it, which
    9932             :      * happens here.
    9933             :      */
    9934       49884 :     if (!PQgetisnull(res, r, i_notnull_invalidoid))
    9935             :     {
    9936         152 :         char       *constroid = PQgetvalue(res, r, i_notnull_invalidoid);
    9937             : 
    9938         152 :         if (*invalidnotnulloids == NULL)
    9939             :         {
    9940          92 :             *invalidnotnulloids = createPQExpBuffer();
    9941          92 :             appendPQExpBufferChar(*invalidnotnulloids, '{');
    9942          92 :             appendPQExpBufferStr(*invalidnotnulloids, constroid);
    9943             :         }
    9944             :         else
    9945          60 :             appendPQExpBuffer(*invalidnotnulloids, ",%s", constroid);
    9946             : 
    9947             :         /*
    9948             :          * Track when a parent constraint is invalid for the cases where a
    9949             :          * child constraint has been validated independenly.
    9950             :          */
    9951         152 :         tbinfo->notnull_invalid[j] = true;
    9952             : 
    9953             :         /* nothing else to do */
    9954         152 :         tbinfo->notnull_constrs[j] = NULL;
    9955         152 :         return;
    9956             :     }
    9957             : 
    9958             :     /*
    9959             :      * notnull_noinh is straight from the query result. notnull_islocal also,
    9960             :      * though flagInhAttrs may change that one later.
    9961             :      */
    9962       49732 :     tbinfo->notnull_noinh[j] = PQgetvalue(res, r, i_notnull_noinherit)[0] == 't';
    9963       49732 :     tbinfo->notnull_islocal[j] = PQgetvalue(res, r, i_notnull_islocal)[0] == 't';
    9964       49732 :     tbinfo->notnull_invalid[j] = false;
    9965             : 
    9966             :     /*
    9967             :      * Determine a constraint name to use.  If the column is not marked not-
    9968             :      * null, we set NULL which cues ... to do nothing.  An empty string says
    9969             :      * to print an unnamed NOT NULL, and anything else is a constraint name to
    9970             :      * use.
    9971             :      */
    9972       49732 :     if (fout->remoteVersion < 180000)
    9973             :     {
    9974             :         /*
    9975             :          * < 18 doesn't have not-null names, so an unnamed constraint is
    9976             :          * sufficient.
    9977             :          */
    9978           0 :         if (PQgetisnull(res, r, i_notnull_name))
    9979           0 :             tbinfo->notnull_constrs[j] = NULL;
    9980             :         else
    9981           0 :             tbinfo->notnull_constrs[j] = "";
    9982             :     }
    9983             :     else
    9984             :     {
    9985       49732 :         if (PQgetisnull(res, r, i_notnull_name))
    9986       44378 :             tbinfo->notnull_constrs[j] = NULL;
    9987             :         else
    9988             :         {
    9989             :             /*
    9990             :              * In binary upgrade of inheritance child tables, must have a
    9991             :              * constraint name that we can UPDATE later; same if there's a
    9992             :              * comment on the constraint.
    9993             :              */
    9994        5354 :             if ((dopt->binary_upgrade &&
    9995         652 :                  !tbinfo->ispartition &&
    9996        5850 :                  !tbinfo->notnull_islocal) ||
    9997        5354 :                 !PQgetisnull(res, r, i_notnull_comment))
    9998             :             {
    9999         102 :                 tbinfo->notnull_constrs[j] =
   10000         102 :                     pstrdup(PQgetvalue(res, r, i_notnull_name));
   10001             :             }
   10002             :             else
   10003             :             {
   10004             :                 char       *default_name;
   10005             : 
   10006             :                 /* XXX should match ChooseConstraintName better */
   10007        5252 :                 default_name = psprintf("%s_%s_not_null", tbinfo->dobj.name,
   10008        5252 :                                         tbinfo->attnames[j]);
   10009        5252 :                 if (strcmp(default_name,
   10010        5252 :                            PQgetvalue(res, r, i_notnull_name)) == 0)
   10011        3452 :                     tbinfo->notnull_constrs[j] = "";
   10012             :                 else
   10013             :                 {
   10014        1800 :                     tbinfo->notnull_constrs[j] =
   10015        1800 :                         pstrdup(PQgetvalue(res, r, i_notnull_name));
   10016             :                 }
   10017        5252 :                 free(default_name);
   10018             :             }
   10019             :         }
   10020             :     }
   10021             : }
   10022             : 
   10023             : /*
   10024             :  * Test whether a column should be printed as part of table's CREATE TABLE.
   10025             :  * Column number is zero-based.
   10026             :  *
   10027             :  * Normally this is always true, but it's false for dropped columns, as well
   10028             :  * as those that were inherited without any local definition.  (If we print
   10029             :  * such a column it will mistakenly get pg_attribute.attislocal set to true.)
   10030             :  * For partitions, it's always true, because we want the partitions to be
   10031             :  * created independently and ATTACH PARTITION used afterwards.
   10032             :  *
   10033             :  * In binary_upgrade mode, we must print all columns and fix the attislocal/
   10034             :  * attisdropped state later, so as to keep control of the physical column
   10035             :  * order.
   10036             :  *
   10037             :  * This function exists because there are scattered nonobvious places that
   10038             :  * must be kept in sync with this decision.
   10039             :  */
   10040             : bool
   10041       81182 : shouldPrintColumn(const DumpOptions *dopt, const TableInfo *tbinfo, int colno)
   10042             : {
   10043       81182 :     if (dopt->binary_upgrade)
   10044       12412 :         return true;
   10045       68770 :     if (tbinfo->attisdropped[colno])
   10046        1464 :         return false;
   10047       67306 :     return (tbinfo->attislocal[colno] || tbinfo->ispartition);
   10048             : }
   10049             : 
   10050             : 
   10051             : /*
   10052             :  * getTSParsers:
   10053             :  *    get information about all text search parsers in the system catalogs
   10054             :  */
   10055             : void
   10056         364 : getTSParsers(Archive *fout)
   10057             : {
   10058             :     PGresult   *res;
   10059             :     int         ntups;
   10060             :     int         i;
   10061             :     PQExpBuffer query;
   10062             :     TSParserInfo *prsinfo;
   10063             :     int         i_tableoid;
   10064             :     int         i_oid;
   10065             :     int         i_prsname;
   10066             :     int         i_prsnamespace;
   10067             :     int         i_prsstart;
   10068             :     int         i_prstoken;
   10069             :     int         i_prsend;
   10070             :     int         i_prsheadline;
   10071             :     int         i_prslextype;
   10072             : 
   10073         364 :     query = createPQExpBuffer();
   10074             : 
   10075             :     /*
   10076             :      * find all text search objects, including builtin ones; we filter out
   10077             :      * system-defined objects at dump-out time.
   10078             :      */
   10079             : 
   10080         364 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, prsname, prsnamespace, "
   10081             :                          "prsstart::oid, prstoken::oid, "
   10082             :                          "prsend::oid, prsheadline::oid, prslextype::oid "
   10083             :                          "FROM pg_ts_parser");
   10084             : 
   10085         364 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   10086             : 
   10087         364 :     ntups = PQntuples(res);
   10088             : 
   10089         364 :     prsinfo = (TSParserInfo *) pg_malloc(ntups * sizeof(TSParserInfo));
   10090             : 
   10091         364 :     i_tableoid = PQfnumber(res, "tableoid");
   10092         364 :     i_oid = PQfnumber(res, "oid");
   10093         364 :     i_prsname = PQfnumber(res, "prsname");
   10094         364 :     i_prsnamespace = PQfnumber(res, "prsnamespace");
   10095         364 :     i_prsstart = PQfnumber(res, "prsstart");
   10096         364 :     i_prstoken = PQfnumber(res, "prstoken");
   10097         364 :     i_prsend = PQfnumber(res, "prsend");
   10098         364 :     i_prsheadline = PQfnumber(res, "prsheadline");
   10099         364 :     i_prslextype = PQfnumber(res, "prslextype");
   10100             : 
   10101         824 :     for (i = 0; i < ntups; i++)
   10102             :     {
   10103         460 :         prsinfo[i].dobj.objType = DO_TSPARSER;
   10104         460 :         prsinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
   10105         460 :         prsinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
   10106         460 :         AssignDumpId(&prsinfo[i].dobj);
   10107         460 :         prsinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_prsname));
   10108         920 :         prsinfo[i].dobj.namespace =
   10109         460 :             findNamespace(atooid(PQgetvalue(res, i, i_prsnamespace)));
   10110         460 :         prsinfo[i].prsstart = atooid(PQgetvalue(res, i, i_prsstart));
   10111         460 :         prsinfo[i].prstoken = atooid(PQgetvalue(res, i, i_prstoken));
   10112         460 :         prsinfo[i].prsend = atooid(PQgetvalue(res, i, i_prsend));
   10113         460 :         prsinfo[i].prsheadline = atooid(PQgetvalue(res, i, i_prsheadline));
   10114         460 :         prsinfo[i].prslextype = atooid(PQgetvalue(res, i, i_prslextype));
   10115             : 
   10116             :         /* Decide whether we want to dump it */
   10117         460 :         selectDumpableObject(&(prsinfo[i].dobj), fout);
   10118             :     }
   10119             : 
   10120         364 :     PQclear(res);
   10121             : 
   10122         364 :     destroyPQExpBuffer(query);
   10123         364 : }
   10124             : 
   10125             : /*
   10126             :  * getTSDictionaries:
   10127             :  *    get information about all text search dictionaries in the system catalogs
   10128             :  */
   10129             : void
   10130         364 : getTSDictionaries(Archive *fout)
   10131             : {
   10132             :     PGresult   *res;
   10133             :     int         ntups;
   10134             :     int         i;
   10135             :     PQExpBuffer query;
   10136             :     TSDictInfo *dictinfo;
   10137             :     int         i_tableoid;
   10138             :     int         i_oid;
   10139             :     int         i_dictname;
   10140             :     int         i_dictnamespace;
   10141             :     int         i_dictowner;
   10142             :     int         i_dicttemplate;
   10143             :     int         i_dictinitoption;
   10144             : 
   10145         364 :     query = createPQExpBuffer();
   10146             : 
   10147         364 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, dictname, "
   10148             :                          "dictnamespace, dictowner, "
   10149             :                          "dicttemplate, dictinitoption "
   10150             :                          "FROM pg_ts_dict");
   10151             : 
   10152         364 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   10153             : 
   10154         364 :     ntups = PQntuples(res);
   10155             : 
   10156         364 :     dictinfo = (TSDictInfo *) pg_malloc(ntups * sizeof(TSDictInfo));
   10157             : 
   10158         364 :     i_tableoid = PQfnumber(res, "tableoid");
   10159         364 :     i_oid = PQfnumber(res, "oid");
   10160         364 :     i_dictname = PQfnumber(res, "dictname");
   10161         364 :     i_dictnamespace = PQfnumber(res, "dictnamespace");
   10162         364 :     i_dictowner = PQfnumber(res, "dictowner");
   10163         364 :     i_dictinitoption = PQfnumber(res, "dictinitoption");
   10164         364 :     i_dicttemplate = PQfnumber(res, "dicttemplate");
   10165             : 
   10166       11506 :     for (i = 0; i < ntups; i++)
   10167             :     {
   10168       11142 :         dictinfo[i].dobj.objType = DO_TSDICT;
   10169       11142 :         dictinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
   10170       11142 :         dictinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
   10171       11142 :         AssignDumpId(&dictinfo[i].dobj);
   10172       11142 :         dictinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_dictname));
   10173       22284 :         dictinfo[i].dobj.namespace =
   10174       11142 :             findNamespace(atooid(PQgetvalue(res, i, i_dictnamespace)));
   10175       11142 :         dictinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_dictowner));
   10176       11142 :         dictinfo[i].dicttemplate = atooid(PQgetvalue(res, i, i_dicttemplate));
   10177       11142 :         if (PQgetisnull(res, i, i_dictinitoption))
   10178         460 :             dictinfo[i].dictinitoption = NULL;
   10179             :         else
   10180       10682 :             dictinfo[i].dictinitoption = pg_strdup(PQgetvalue(res, i, i_dictinitoption));
   10181             : 
   10182             :         /* Decide whether we want to dump it */
   10183       11142 :         selectDumpableObject(&(dictinfo[i].dobj), fout);
   10184             :     }
   10185             : 
   10186         364 :     PQclear(res);
   10187             : 
   10188         364 :     destroyPQExpBuffer(query);
   10189         364 : }
   10190             : 
   10191             : /*
   10192             :  * getTSTemplates:
   10193             :  *    get information about all text search templates in the system catalogs
   10194             :  */
   10195             : void
   10196         364 : getTSTemplates(Archive *fout)
   10197             : {
   10198             :     PGresult   *res;
   10199             :     int         ntups;
   10200             :     int         i;
   10201             :     PQExpBuffer query;
   10202             :     TSTemplateInfo *tmplinfo;
   10203             :     int         i_tableoid;
   10204             :     int         i_oid;
   10205             :     int         i_tmplname;
   10206             :     int         i_tmplnamespace;
   10207             :     int         i_tmplinit;
   10208             :     int         i_tmpllexize;
   10209             : 
   10210         364 :     query = createPQExpBuffer();
   10211             : 
   10212         364 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, tmplname, "
   10213             :                          "tmplnamespace, tmplinit::oid, tmpllexize::oid "
   10214             :                          "FROM pg_ts_template");
   10215             : 
   10216         364 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   10217             : 
   10218         364 :     ntups = PQntuples(res);
   10219             : 
   10220         364 :     tmplinfo = (TSTemplateInfo *) pg_malloc(ntups * sizeof(TSTemplateInfo));
   10221             : 
   10222         364 :     i_tableoid = PQfnumber(res, "tableoid");
   10223         364 :     i_oid = PQfnumber(res, "oid");
   10224         364 :     i_tmplname = PQfnumber(res, "tmplname");
   10225         364 :     i_tmplnamespace = PQfnumber(res, "tmplnamespace");
   10226         364 :     i_tmplinit = PQfnumber(res, "tmplinit");
   10227         364 :     i_tmpllexize = PQfnumber(res, "tmpllexize");
   10228             : 
   10229        2280 :     for (i = 0; i < ntups; i++)
   10230             :     {
   10231        1916 :         tmplinfo[i].dobj.objType = DO_TSTEMPLATE;
   10232        1916 :         tmplinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
   10233        1916 :         tmplinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
   10234        1916 :         AssignDumpId(&tmplinfo[i].dobj);
   10235        1916 :         tmplinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_tmplname));
   10236        3832 :         tmplinfo[i].dobj.namespace =
   10237        1916 :             findNamespace(atooid(PQgetvalue(res, i, i_tmplnamespace)));
   10238        1916 :         tmplinfo[i].tmplinit = atooid(PQgetvalue(res, i, i_tmplinit));
   10239        1916 :         tmplinfo[i].tmpllexize = atooid(PQgetvalue(res, i, i_tmpllexize));
   10240             : 
   10241             :         /* Decide whether we want to dump it */
   10242        1916 :         selectDumpableObject(&(tmplinfo[i].dobj), fout);
   10243             :     }
   10244             : 
   10245         364 :     PQclear(res);
   10246             : 
   10247         364 :     destroyPQExpBuffer(query);
   10248         364 : }
   10249             : 
   10250             : /*
   10251             :  * getTSConfigurations:
   10252             :  *    get information about all text search configurations
   10253             :  */
   10254             : void
   10255         364 : getTSConfigurations(Archive *fout)
   10256             : {
   10257             :     PGresult   *res;
   10258             :     int         ntups;
   10259             :     int         i;
   10260             :     PQExpBuffer query;
   10261             :     TSConfigInfo *cfginfo;
   10262             :     int         i_tableoid;
   10263             :     int         i_oid;
   10264             :     int         i_cfgname;
   10265             :     int         i_cfgnamespace;
   10266             :     int         i_cfgowner;
   10267             :     int         i_cfgparser;
   10268             : 
   10269         364 :     query = createPQExpBuffer();
   10270             : 
   10271         364 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, cfgname, "
   10272             :                          "cfgnamespace, cfgowner, cfgparser "
   10273             :                          "FROM pg_ts_config");
   10274             : 
   10275         364 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   10276             : 
   10277         364 :     ntups = PQntuples(res);
   10278             : 
   10279         364 :     cfginfo = (TSConfigInfo *) pg_malloc(ntups * sizeof(TSConfigInfo));
   10280             : 
   10281         364 :     i_tableoid = PQfnumber(res, "tableoid");
   10282         364 :     i_oid = PQfnumber(res, "oid");
   10283         364 :     i_cfgname = PQfnumber(res, "cfgname");
   10284         364 :     i_cfgnamespace = PQfnumber(res, "cfgnamespace");
   10285         364 :     i_cfgowner = PQfnumber(res, "cfgowner");
   10286         364 :     i_cfgparser = PQfnumber(res, "cfgparser");
   10287             : 
   10288       11436 :     for (i = 0; i < ntups; i++)
   10289             :     {
   10290       11072 :         cfginfo[i].dobj.objType = DO_TSCONFIG;
   10291       11072 :         cfginfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
   10292       11072 :         cfginfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
   10293       11072 :         AssignDumpId(&cfginfo[i].dobj);
   10294       11072 :         cfginfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_cfgname));
   10295       22144 :         cfginfo[i].dobj.namespace =
   10296       11072 :             findNamespace(atooid(PQgetvalue(res, i, i_cfgnamespace)));
   10297       11072 :         cfginfo[i].rolname = getRoleName(PQgetvalue(res, i, i_cfgowner));
   10298       11072 :         cfginfo[i].cfgparser = atooid(PQgetvalue(res, i, i_cfgparser));
   10299             : 
   10300             :         /* Decide whether we want to dump it */
   10301       11072 :         selectDumpableObject(&(cfginfo[i].dobj), fout);
   10302             :     }
   10303             : 
   10304         364 :     PQclear(res);
   10305             : 
   10306         364 :     destroyPQExpBuffer(query);
   10307         364 : }
   10308             : 
   10309             : /*
   10310             :  * getForeignDataWrappers:
   10311             :  *    get information about all foreign-data wrappers in the system catalogs
   10312             :  */
   10313             : void
   10314         364 : getForeignDataWrappers(Archive *fout)
   10315             : {
   10316             :     PGresult   *res;
   10317             :     int         ntups;
   10318             :     int         i;
   10319             :     PQExpBuffer query;
   10320             :     FdwInfo    *fdwinfo;
   10321             :     int         i_tableoid;
   10322             :     int         i_oid;
   10323             :     int         i_fdwname;
   10324             :     int         i_fdwowner;
   10325             :     int         i_fdwhandler;
   10326             :     int         i_fdwvalidator;
   10327             :     int         i_fdwacl;
   10328             :     int         i_acldefault;
   10329             :     int         i_fdwoptions;
   10330             : 
   10331         364 :     query = createPQExpBuffer();
   10332             : 
   10333         364 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, fdwname, "
   10334             :                          "fdwowner, "
   10335             :                          "fdwhandler::pg_catalog.regproc, "
   10336             :                          "fdwvalidator::pg_catalog.regproc, "
   10337             :                          "fdwacl, "
   10338             :                          "acldefault('F', fdwowner) AS acldefault, "
   10339             :                          "array_to_string(ARRAY("
   10340             :                          "SELECT quote_ident(option_name) || ' ' || "
   10341             :                          "quote_literal(option_value) "
   10342             :                          "FROM pg_options_to_table(fdwoptions) "
   10343             :                          "ORDER BY option_name"
   10344             :                          "), E',\n    ') AS fdwoptions "
   10345             :                          "FROM pg_foreign_data_wrapper");
   10346             : 
   10347         364 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   10348             : 
   10349         364 :     ntups = PQntuples(res);
   10350             : 
   10351         364 :     fdwinfo = (FdwInfo *) pg_malloc(ntups * sizeof(FdwInfo));
   10352             : 
   10353         364 :     i_tableoid = PQfnumber(res, "tableoid");
   10354         364 :     i_oid = PQfnumber(res, "oid");
   10355         364 :     i_fdwname = PQfnumber(res, "fdwname");
   10356         364 :     i_fdwowner = PQfnumber(res, "fdwowner");
   10357         364 :     i_fdwhandler = PQfnumber(res, "fdwhandler");
   10358         364 :     i_fdwvalidator = PQfnumber(res, "fdwvalidator");
   10359         364 :     i_fdwacl = PQfnumber(res, "fdwacl");
   10360         364 :     i_acldefault = PQfnumber(res, "acldefault");
   10361         364 :     i_fdwoptions = PQfnumber(res, "fdwoptions");
   10362             : 
   10363         512 :     for (i = 0; i < ntups; i++)
   10364             :     {
   10365         148 :         fdwinfo[i].dobj.objType = DO_FDW;
   10366         148 :         fdwinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
   10367         148 :         fdwinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
   10368         148 :         AssignDumpId(&fdwinfo[i].dobj);
   10369         148 :         fdwinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_fdwname));
   10370         148 :         fdwinfo[i].dobj.namespace = NULL;
   10371         148 :         fdwinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_fdwacl));
   10372         148 :         fdwinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
   10373         148 :         fdwinfo[i].dacl.privtype = 0;
   10374         148 :         fdwinfo[i].dacl.initprivs = NULL;
   10375         148 :         fdwinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_fdwowner));
   10376         148 :         fdwinfo[i].fdwhandler = pg_strdup(PQgetvalue(res, i, i_fdwhandler));
   10377         148 :         fdwinfo[i].fdwvalidator = pg_strdup(PQgetvalue(res, i, i_fdwvalidator));
   10378         148 :         fdwinfo[i].fdwoptions = pg_strdup(PQgetvalue(res, i, i_fdwoptions));
   10379             : 
   10380             :         /* Decide whether we want to dump it */
   10381         148 :         selectDumpableObject(&(fdwinfo[i].dobj), fout);
   10382             : 
   10383             :         /* Mark whether FDW has an ACL */
   10384         148 :         if (!PQgetisnull(res, i, i_fdwacl))
   10385          96 :             fdwinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
   10386             :     }
   10387             : 
   10388         364 :     PQclear(res);
   10389             : 
   10390         364 :     destroyPQExpBuffer(query);
   10391         364 : }
   10392             : 
   10393             : /*
   10394             :  * getForeignServers:
   10395             :  *    get information about all foreign servers in the system catalogs
   10396             :  */
   10397             : void
   10398         364 : getForeignServers(Archive *fout)
   10399             : {
   10400             :     PGresult   *res;
   10401             :     int         ntups;
   10402             :     int         i;
   10403             :     PQExpBuffer query;
   10404             :     ForeignServerInfo *srvinfo;
   10405             :     int         i_tableoid;
   10406             :     int         i_oid;
   10407             :     int         i_srvname;
   10408             :     int         i_srvowner;
   10409             :     int         i_srvfdw;
   10410             :     int         i_srvtype;
   10411             :     int         i_srvversion;
   10412             :     int         i_srvacl;
   10413             :     int         i_acldefault;
   10414             :     int         i_srvoptions;
   10415             : 
   10416         364 :     query = createPQExpBuffer();
   10417             : 
   10418         364 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, srvname, "
   10419             :                          "srvowner, "
   10420             :                          "srvfdw, srvtype, srvversion, srvacl, "
   10421             :                          "acldefault('S', srvowner) AS acldefault, "
   10422             :                          "array_to_string(ARRAY("
   10423             :                          "SELECT quote_ident(option_name) || ' ' || "
   10424             :                          "quote_literal(option_value) "
   10425             :                          "FROM pg_options_to_table(srvoptions) "
   10426             :                          "ORDER BY option_name"
   10427             :                          "), E',\n    ') AS srvoptions "
   10428             :                          "FROM pg_foreign_server");
   10429             : 
   10430         364 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   10431             : 
   10432         364 :     ntups = PQntuples(res);
   10433             : 
   10434         364 :     srvinfo = (ForeignServerInfo *) pg_malloc(ntups * sizeof(ForeignServerInfo));
   10435             : 
   10436         364 :     i_tableoid = PQfnumber(res, "tableoid");
   10437         364 :     i_oid = PQfnumber(res, "oid");
   10438         364 :     i_srvname = PQfnumber(res, "srvname");
   10439         364 :     i_srvowner = PQfnumber(res, "srvowner");
   10440         364 :     i_srvfdw = PQfnumber(res, "srvfdw");
   10441         364 :     i_srvtype = PQfnumber(res, "srvtype");
   10442         364 :     i_srvversion = PQfnumber(res, "srvversion");
   10443         364 :     i_srvacl = PQfnumber(res, "srvacl");
   10444         364 :     i_acldefault = PQfnumber(res, "acldefault");
   10445         364 :     i_srvoptions = PQfnumber(res, "srvoptions");
   10446             : 
   10447         520 :     for (i = 0; i < ntups; i++)
   10448             :     {
   10449         156 :         srvinfo[i].dobj.objType = DO_FOREIGN_SERVER;
   10450         156 :         srvinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
   10451         156 :         srvinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
   10452         156 :         AssignDumpId(&srvinfo[i].dobj);
   10453         156 :         srvinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_srvname));
   10454         156 :         srvinfo[i].dobj.namespace = NULL;
   10455         156 :         srvinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_srvacl));
   10456         156 :         srvinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
   10457         156 :         srvinfo[i].dacl.privtype = 0;
   10458         156 :         srvinfo[i].dacl.initprivs = NULL;
   10459         156 :         srvinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_srvowner));
   10460         156 :         srvinfo[i].srvfdw = atooid(PQgetvalue(res, i, i_srvfdw));
   10461         156 :         srvinfo[i].srvtype = pg_strdup(PQgetvalue(res, i, i_srvtype));
   10462         156 :         srvinfo[i].srvversion = pg_strdup(PQgetvalue(res, i, i_srvversion));
   10463         156 :         srvinfo[i].srvoptions = pg_strdup(PQgetvalue(res, i, i_srvoptions));
   10464             : 
   10465             :         /* Decide whether we want to dump it */
   10466         156 :         selectDumpableObject(&(srvinfo[i].dobj), fout);
   10467             : 
   10468             :         /* Servers have user mappings */
   10469         156 :         srvinfo[i].dobj.components |= DUMP_COMPONENT_USERMAP;
   10470             : 
   10471             :         /* Mark whether server has an ACL */
   10472         156 :         if (!PQgetisnull(res, i, i_srvacl))
   10473          96 :             srvinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
   10474             :     }
   10475             : 
   10476         364 :     PQclear(res);
   10477             : 
   10478         364 :     destroyPQExpBuffer(query);
   10479         364 : }
   10480             : 
   10481             : /*
   10482             :  * getDefaultACLs:
   10483             :  *    get information about all default ACL information in the system catalogs
   10484             :  */
   10485             : void
   10486         364 : getDefaultACLs(Archive *fout)
   10487             : {
   10488         364 :     DumpOptions *dopt = fout->dopt;
   10489             :     DefaultACLInfo *daclinfo;
   10490             :     PQExpBuffer query;
   10491             :     PGresult   *res;
   10492             :     int         i_oid;
   10493             :     int         i_tableoid;
   10494             :     int         i_defaclrole;
   10495             :     int         i_defaclnamespace;
   10496             :     int         i_defaclobjtype;
   10497             :     int         i_defaclacl;
   10498             :     int         i_acldefault;
   10499             :     int         i,
   10500             :                 ntups;
   10501             : 
   10502         364 :     query = createPQExpBuffer();
   10503             : 
   10504             :     /*
   10505             :      * Global entries (with defaclnamespace=0) replace the hard-wired default
   10506             :      * ACL for their object type.  We should dump them as deltas from the
   10507             :      * default ACL, since that will be used as a starting point for
   10508             :      * interpreting the ALTER DEFAULT PRIVILEGES commands.  On the other hand,
   10509             :      * non-global entries can only add privileges not revoke them.  We must
   10510             :      * dump those as-is (i.e., as deltas from an empty ACL).
   10511             :      *
   10512             :      * We can use defaclobjtype as the object type for acldefault(), except
   10513             :      * for the case of 'S' (DEFACLOBJ_SEQUENCE) which must be converted to
   10514             :      * 's'.
   10515             :      */
   10516         364 :     appendPQExpBufferStr(query,
   10517             :                          "SELECT oid, tableoid, "
   10518             :                          "defaclrole, "
   10519             :                          "defaclnamespace, "
   10520             :                          "defaclobjtype, "
   10521             :                          "defaclacl, "
   10522             :                          "CASE WHEN defaclnamespace = 0 THEN "
   10523             :                          "acldefault(CASE WHEN defaclobjtype = 'S' "
   10524             :                          "THEN 's'::\"char\" ELSE defaclobjtype END, "
   10525             :                          "defaclrole) ELSE '{}' END AS acldefault "
   10526             :                          "FROM pg_default_acl");
   10527             : 
   10528         364 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   10529             : 
   10530         364 :     ntups = PQntuples(res);
   10531             : 
   10532         364 :     daclinfo = (DefaultACLInfo *) pg_malloc(ntups * sizeof(DefaultACLInfo));
   10533             : 
   10534         364 :     i_oid = PQfnumber(res, "oid");
   10535         364 :     i_tableoid = PQfnumber(res, "tableoid");
   10536         364 :     i_defaclrole = PQfnumber(res, "defaclrole");
   10537         364 :     i_defaclnamespace = PQfnumber(res, "defaclnamespace");
   10538         364 :     i_defaclobjtype = PQfnumber(res, "defaclobjtype");
   10539         364 :     i_defaclacl = PQfnumber(res, "defaclacl");
   10540         364 :     i_acldefault = PQfnumber(res, "acldefault");
   10541             : 
   10542         776 :     for (i = 0; i < ntups; i++)
   10543             :     {
   10544         412 :         Oid         nspid = atooid(PQgetvalue(res, i, i_defaclnamespace));
   10545             : 
   10546         412 :         daclinfo[i].dobj.objType = DO_DEFAULT_ACL;
   10547         412 :         daclinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
   10548         412 :         daclinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
   10549         412 :         AssignDumpId(&daclinfo[i].dobj);
   10550             :         /* cheesy ... is it worth coming up with a better object name? */
   10551         412 :         daclinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_defaclobjtype));
   10552             : 
   10553         412 :         if (nspid != InvalidOid)
   10554         192 :             daclinfo[i].dobj.namespace = findNamespace(nspid);
   10555             :         else
   10556         220 :             daclinfo[i].dobj.namespace = NULL;
   10557             : 
   10558         412 :         daclinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_defaclacl));
   10559         412 :         daclinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
   10560         412 :         daclinfo[i].dacl.privtype = 0;
   10561         412 :         daclinfo[i].dacl.initprivs = NULL;
   10562         412 :         daclinfo[i].defaclrole = getRoleName(PQgetvalue(res, i, i_defaclrole));
   10563         412 :         daclinfo[i].defaclobjtype = *(PQgetvalue(res, i, i_defaclobjtype));
   10564             : 
   10565             :         /* Default ACLs are ACLs, of course */
   10566         412 :         daclinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
   10567             : 
   10568             :         /* Decide whether we want to dump it */
   10569         412 :         selectDumpableDefaultACL(&(daclinfo[i]), dopt);
   10570             :     }
   10571             : 
   10572         364 :     PQclear(res);
   10573             : 
   10574         364 :     destroyPQExpBuffer(query);
   10575         364 : }
   10576             : 
   10577             : /*
   10578             :  * getRoleName -- look up the name of a role, given its OID
   10579             :  *
   10580             :  * In current usage, we don't expect failures, so error out for a bad OID.
   10581             :  */
   10582             : static const char *
   10583     1153394 : getRoleName(const char *roleoid_str)
   10584             : {
   10585     1153394 :     Oid         roleoid = atooid(roleoid_str);
   10586             : 
   10587             :     /*
   10588             :      * Do binary search to find the appropriate item.
   10589             :      */
   10590     1153394 :     if (nrolenames > 0)
   10591             :     {
   10592     1153394 :         RoleNameItem *low = &rolenames[0];
   10593     1153394 :         RoleNameItem *high = &rolenames[nrolenames - 1];
   10594             : 
   10595     4613392 :         while (low <= high)
   10596             :         {
   10597     4613392 :             RoleNameItem *middle = low + (high - low) / 2;
   10598             : 
   10599     4613392 :             if (roleoid < middle->roleoid)
   10600     3457810 :                 high = middle - 1;
   10601     1155582 :             else if (roleoid > middle->roleoid)
   10602        2188 :                 low = middle + 1;
   10603             :             else
   10604     1153394 :                 return middle->rolename; /* found a match */
   10605             :         }
   10606             :     }
   10607             : 
   10608           0 :     pg_fatal("role with OID %u does not exist", roleoid);
   10609             :     return NULL;                /* keep compiler quiet */
   10610             : }
   10611             : 
   10612             : /*
   10613             :  * collectRoleNames --
   10614             :  *
   10615             :  * Construct a table of all known roles.
   10616             :  * The table is sorted by OID for speed in lookup.
   10617             :  */
   10618             : static void
   10619         366 : collectRoleNames(Archive *fout)
   10620             : {
   10621             :     PGresult   *res;
   10622             :     const char *query;
   10623             :     int         i;
   10624             : 
   10625         366 :     query = "SELECT oid, rolname FROM pg_catalog.pg_roles ORDER BY 1";
   10626             : 
   10627         366 :     res = ExecuteSqlQuery(fout, query, PGRES_TUPLES_OK);
   10628             : 
   10629         366 :     nrolenames = PQntuples(res);
   10630             : 
   10631         366 :     rolenames = (RoleNameItem *) pg_malloc(nrolenames * sizeof(RoleNameItem));
   10632             : 
   10633        7136 :     for (i = 0; i < nrolenames; i++)
   10634             :     {
   10635        6770 :         rolenames[i].roleoid = atooid(PQgetvalue(res, i, 0));
   10636        6770 :         rolenames[i].rolename = pg_strdup(PQgetvalue(res, i, 1));
   10637             :     }
   10638             : 
   10639         366 :     PQclear(res);
   10640         366 : }
   10641             : 
   10642             : /*
   10643             :  * getAdditionalACLs
   10644             :  *
   10645             :  * We have now created all the DumpableObjects, and collected the ACL data
   10646             :  * that appears in the directly-associated catalog entries.  However, there's
   10647             :  * more ACL-related info to collect.  If any of a table's columns have ACLs,
   10648             :  * we must set the TableInfo's DUMP_COMPONENT_ACL components flag, as well as
   10649             :  * its hascolumnACLs flag (we won't store the ACLs themselves here, though).
   10650             :  * Also, in versions having the pg_init_privs catalog, read that and load the
   10651             :  * information into the relevant DumpableObjects.
   10652             :  */
   10653             : static void
   10654         360 : getAdditionalACLs(Archive *fout)
   10655             : {
   10656         360 :     PQExpBuffer query = createPQExpBuffer();
   10657             :     PGresult   *res;
   10658             :     int         ntups,
   10659             :                 i;
   10660             : 
   10661             :     /* Check for per-column ACLs */
   10662         360 :     appendPQExpBufferStr(query,
   10663             :                          "SELECT DISTINCT attrelid FROM pg_attribute "
   10664             :                          "WHERE attacl IS NOT NULL");
   10665             : 
   10666         360 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   10667             : 
   10668         360 :     ntups = PQntuples(res);
   10669        1078 :     for (i = 0; i < ntups; i++)
   10670             :     {
   10671         718 :         Oid         relid = atooid(PQgetvalue(res, i, 0));
   10672             :         TableInfo  *tblinfo;
   10673             : 
   10674         718 :         tblinfo = findTableByOid(relid);
   10675             :         /* OK to ignore tables we haven't got a DumpableObject for */
   10676         718 :         if (tblinfo)
   10677             :         {
   10678         718 :             tblinfo->dobj.components |= DUMP_COMPONENT_ACL;
   10679         718 :             tblinfo->hascolumnACLs = true;
   10680             :         }
   10681             :     }
   10682         360 :     PQclear(res);
   10683             : 
   10684             :     /* Fetch initial-privileges data */
   10685         360 :     if (fout->remoteVersion >= 90600)
   10686             :     {
   10687         360 :         printfPQExpBuffer(query,
   10688             :                           "SELECT objoid, classoid, objsubid, privtype, initprivs "
   10689             :                           "FROM pg_init_privs");
   10690             : 
   10691         360 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   10692             : 
   10693         360 :         ntups = PQntuples(res);
   10694       84496 :         for (i = 0; i < ntups; i++)
   10695             :         {
   10696       84136 :             Oid         objoid = atooid(PQgetvalue(res, i, 0));
   10697       84136 :             Oid         classoid = atooid(PQgetvalue(res, i, 1));
   10698       84136 :             int         objsubid = atoi(PQgetvalue(res, i, 2));
   10699       84136 :             char        privtype = *(PQgetvalue(res, i, 3));
   10700       84136 :             char       *initprivs = PQgetvalue(res, i, 4);
   10701             :             CatalogId   objId;
   10702             :             DumpableObject *dobj;
   10703             : 
   10704       84136 :             objId.tableoid = classoid;
   10705       84136 :             objId.oid = objoid;
   10706       84136 :             dobj = findObjectByCatalogId(objId);
   10707             :             /* OK to ignore entries we haven't got a DumpableObject for */
   10708       84136 :             if (dobj)
   10709             :             {
   10710             :                 /* Cope with sub-object initprivs */
   10711       60110 :                 if (objsubid != 0)
   10712             :                 {
   10713        6528 :                     if (dobj->objType == DO_TABLE)
   10714             :                     {
   10715             :                         /* For a column initprivs, set the table's ACL flags */
   10716        6528 :                         dobj->components |= DUMP_COMPONENT_ACL;
   10717        6528 :                         ((TableInfo *) dobj)->hascolumnACLs = true;
   10718             :                     }
   10719             :                     else
   10720           0 :                         pg_log_warning("unsupported pg_init_privs entry: %u %u %d",
   10721             :                                        classoid, objoid, objsubid);
   10722        6880 :                     continue;
   10723             :                 }
   10724             : 
   10725             :                 /*
   10726             :                  * We ignore any pg_init_privs.initprivs entry for the public
   10727             :                  * schema, as explained in getNamespaces().
   10728             :                  */
   10729       53582 :                 if (dobj->objType == DO_NAMESPACE &&
   10730         712 :                     strcmp(dobj->name, "public") == 0)
   10731         352 :                     continue;
   10732             : 
   10733             :                 /* Else it had better be of a type we think has ACLs */
   10734       53230 :                 if (dobj->objType == DO_NAMESPACE ||
   10735       52870 :                     dobj->objType == DO_TYPE ||
   10736       52822 :                     dobj->objType == DO_FUNC ||
   10737       52632 :                     dobj->objType == DO_AGG ||
   10738       52584 :                     dobj->objType == DO_TABLE ||
   10739           0 :                     dobj->objType == DO_PROCLANG ||
   10740           0 :                     dobj->objType == DO_FDW ||
   10741           0 :                     dobj->objType == DO_FOREIGN_SERVER)
   10742       53230 :                 {
   10743       53230 :                     DumpableObjectWithAcl *daobj = (DumpableObjectWithAcl *) dobj;
   10744             : 
   10745       53230 :                     daobj->dacl.privtype = privtype;
   10746       53230 :                     daobj->dacl.initprivs = pstrdup(initprivs);
   10747             :                 }
   10748             :                 else
   10749           0 :                     pg_log_warning("unsupported pg_init_privs entry: %u %u %d",
   10750             :                                    classoid, objoid, objsubid);
   10751             :             }
   10752             :         }
   10753         360 :         PQclear(res);
   10754             :     }
   10755             : 
   10756         360 :     destroyPQExpBuffer(query);
   10757         360 : }
   10758             : 
   10759             : /*
   10760             :  * dumpCommentExtended --
   10761             :  *
   10762             :  * This routine is used to dump any comments associated with the
   10763             :  * object handed to this routine. The routine takes the object type
   10764             :  * and object name (ready to print, except for schema decoration), plus
   10765             :  * the namespace and owner of the object (for labeling the ArchiveEntry),
   10766             :  * plus catalog ID and subid which are the lookup key for pg_description,
   10767             :  * plus the dump ID for the object (for setting a dependency).
   10768             :  * If a matching pg_description entry is found, it is dumped.
   10769             :  *
   10770             :  * Note: in some cases, such as comments for triggers and rules, the "type"
   10771             :  * string really looks like, e.g., "TRIGGER name ON".  This is a bit of a hack
   10772             :  * but it doesn't seem worth complicating the API for all callers to make
   10773             :  * it cleaner.
   10774             :  *
   10775             :  * Note: although this routine takes a dumpId for dependency purposes,
   10776             :  * that purpose is just to mark the dependency in the emitted dump file
   10777             :  * for possible future use by pg_restore.  We do NOT use it for determining
   10778             :  * ordering of the comment in the dump file, because this routine is called
   10779             :  * after dependency sorting occurs.  This routine should be called just after
   10780             :  * calling ArchiveEntry() for the specified object.
   10781             :  */
   10782             : static void
   10783       12966 : dumpCommentExtended(Archive *fout, const char *type,
   10784             :                     const char *name, const char *namespace,
   10785             :                     const char *owner, CatalogId catalogId,
   10786             :                     int subid, DumpId dumpId,
   10787             :                     const char *initdb_comment)
   10788             : {
   10789       12966 :     DumpOptions *dopt = fout->dopt;
   10790             :     CommentItem *comments;
   10791             :     int         ncomments;
   10792             : 
   10793             :     /* do nothing, if --no-comments is supplied */
   10794       12966 :     if (dopt->no_comments)
   10795           0 :         return;
   10796             : 
   10797             :     /* Comments are schema not data ... except LO comments are data */
   10798       12966 :     if (strcmp(type, "LARGE OBJECT") != 0)
   10799             :     {
   10800       12862 :         if (!dopt->dumpSchema)
   10801           0 :             return;
   10802             :     }
   10803             :     else
   10804             :     {
   10805             :         /* We do dump LO comments in binary-upgrade mode */
   10806         104 :         if (!dopt->dumpData && !dopt->binary_upgrade)
   10807           0 :             return;
   10808             :     }
   10809             : 
   10810             :     /* Search for comments associated with catalogId, using table */
   10811       12966 :     ncomments = findComments(catalogId.tableoid, catalogId.oid,
   10812             :                              &comments);
   10813             : 
   10814             :     /* Is there one matching the subid? */
   10815       12966 :     while (ncomments > 0)
   10816             :     {
   10817       12878 :         if (comments->objsubid == subid)
   10818       12878 :             break;
   10819           0 :         comments++;
   10820           0 :         ncomments--;
   10821             :     }
   10822             : 
   10823       12966 :     if (initdb_comment != NULL)
   10824             :     {
   10825             :         static CommentItem empty_comment = {.descr = ""};
   10826             : 
   10827             :         /*
   10828             :          * initdb creates this object with a comment.  Skip dumping the
   10829             :          * initdb-provided comment, which would complicate matters for
   10830             :          * non-superuser use of pg_dump.  When the DBA has removed initdb's
   10831             :          * comment, replicate that.
   10832             :          */
   10833         226 :         if (ncomments == 0)
   10834             :         {
   10835           8 :             comments = &empty_comment;
   10836           8 :             ncomments = 1;
   10837             :         }
   10838         218 :         else if (strcmp(comments->descr, initdb_comment) == 0)
   10839         218 :             ncomments = 0;
   10840             :     }
   10841             : 
   10842             :     /* If a comment exists, build COMMENT ON statement */
   10843       12966 :     if (ncomments > 0)
   10844             :     {
   10845       12668 :         PQExpBuffer query = createPQExpBuffer();
   10846       12668 :         PQExpBuffer tag = createPQExpBuffer();
   10847             : 
   10848       12668 :         appendPQExpBuffer(query, "COMMENT ON %s ", type);
   10849       12668 :         if (namespace && *namespace)
   10850       12316 :             appendPQExpBuffer(query, "%s.", fmtId(namespace));
   10851       12668 :         appendPQExpBuffer(query, "%s IS ", name);
   10852       12668 :         appendStringLiteralAH(query, comments->descr, fout);
   10853       12668 :         appendPQExpBufferStr(query, ";\n");
   10854             : 
   10855       12668 :         appendPQExpBuffer(tag, "%s %s", type, name);
   10856             : 
   10857             :         /*
   10858             :          * We mark comments as SECTION_NONE because they really belong in the
   10859             :          * same section as their parent, whether that is pre-data or
   10860             :          * post-data.
   10861             :          */
   10862       12668 :         ArchiveEntry(fout, nilCatalogId, createDumpId(),
   10863       12668 :                      ARCHIVE_OPTS(.tag = tag->data,
   10864             :                                   .namespace = namespace,
   10865             :                                   .owner = owner,
   10866             :                                   .description = "COMMENT",
   10867             :                                   .section = SECTION_NONE,
   10868             :                                   .createStmt = query->data,
   10869             :                                   .deps = &dumpId,
   10870             :                                   .nDeps = 1));
   10871             : 
   10872       12668 :         destroyPQExpBuffer(query);
   10873       12668 :         destroyPQExpBuffer(tag);
   10874             :     }
   10875             : }
   10876             : 
   10877             : /*
   10878             :  * dumpComment --
   10879             :  *
   10880             :  * Typical simplification of the above function.
   10881             :  */
   10882             : static inline void
   10883       12662 : dumpComment(Archive *fout, const char *type,
   10884             :             const char *name, const char *namespace,
   10885             :             const char *owner, CatalogId catalogId,
   10886             :             int subid, DumpId dumpId)
   10887             : {
   10888       12662 :     dumpCommentExtended(fout, type, name, namespace, owner,
   10889             :                         catalogId, subid, dumpId, NULL);
   10890       12662 : }
   10891             : 
   10892             : /*
   10893             :  * appendNamedArgument --
   10894             :  *
   10895             :  * Convenience routine for constructing parameters of the form:
   10896             :  * 'paraname', 'value'::type
   10897             :  */
   10898             : static void
   10899       10082 : appendNamedArgument(PQExpBuffer out, Archive *fout, const char *argname,
   10900             :                     const char *argtype, const char *argval)
   10901             : {
   10902       10082 :     appendPQExpBufferStr(out, ",\n\t");
   10903             : 
   10904       10082 :     appendStringLiteralAH(out, argname, fout);
   10905       10082 :     appendPQExpBufferStr(out, ", ");
   10906             : 
   10907       10082 :     appendStringLiteralAH(out, argval, fout);
   10908       10082 :     appendPQExpBuffer(out, "::%s", argtype);
   10909       10082 : }
   10910             : 
   10911             : /*
   10912             :  * fetchAttributeStats --
   10913             :  *
   10914             :  * Fetch next batch of attribute statistics for dumpRelationStats_dumper().
   10915             :  */
   10916             : static PGresult *
   10917        2234 : fetchAttributeStats(Archive *fout)
   10918             : {
   10919        2234 :     ArchiveHandle *AH = (ArchiveHandle *) fout;
   10920        2234 :     PQExpBuffer nspnames = createPQExpBuffer();
   10921        2234 :     PQExpBuffer relnames = createPQExpBuffer();
   10922        2234 :     int         count = 0;
   10923        2234 :     PGresult   *res = NULL;
   10924             :     static TocEntry *te;
   10925             :     static bool restarted;
   10926        2234 :     int         max_rels = MAX_ATTR_STATS_RELS;
   10927             : 
   10928             :     /*
   10929             :      * Our query for retrieving statistics for multiple relations uses WITH
   10930             :      * ORDINALITY and multi-argument UNNEST(), both of which were introduced
   10931             :      * in v9.4.  For older versions, we resort to gathering statistics for a
   10932             :      * single relation at a time.
   10933             :      */
   10934        2234 :     if (fout->remoteVersion < 90400)
   10935           0 :         max_rels = 1;
   10936             : 
   10937             :     /* If we're just starting, set our TOC pointer. */
   10938        2234 :     if (!te)
   10939         114 :         te = AH->toc->next;
   10940             : 
   10941             :     /*
   10942             :      * We can't easily avoid a second TOC scan for the tar format because it
   10943             :      * writes restore.sql separately, which means we must execute the queries
   10944             :      * twice.  This feels risky, but there is no known reason it should
   10945             :      * generate different output than the first pass.  Even if it does, the
   10946             :      * worst-case scenario is that restore.sql might have different statistics
   10947             :      * data than the archive.
   10948             :      */
   10949        2234 :     if (!restarted && te == AH->toc && AH->format == archTar)
   10950             :     {
   10951           2 :         te = AH->toc->next;
   10952           2 :         restarted = true;
   10953             :     }
   10954             : 
   10955        2234 :     appendPQExpBufferChar(nspnames, '{');
   10956        2234 :     appendPQExpBufferChar(relnames, '{');
   10957             : 
   10958             :     /*
   10959             :      * Scan the TOC for the next set of relevant stats entries.  We assume
   10960             :      * that statistics are dumped in the order they are listed in the TOC.
   10961             :      * This is perhaps not the sturdiest assumption, so we verify it matches
   10962             :      * reality in dumpRelationStats_dumper().
   10963             :      */
   10964       33756 :     for (; te != AH->toc && count < max_rels; te = te->next)
   10965             :     {
   10966       31522 :         if ((te->reqs & REQ_STATS) != 0 &&
   10967        7008 :             strcmp(te->desc, "STATISTICS DATA") == 0)
   10968             :         {
   10969        7008 :             appendPGArray(nspnames, te->namespace);
   10970        7008 :             appendPGArray(relnames, te->tag);
   10971        7008 :             count++;
   10972             :         }
   10973             :     }
   10974             : 
   10975        2234 :     appendPQExpBufferChar(nspnames, '}');
   10976        2234 :     appendPQExpBufferChar(relnames, '}');
   10977             : 
   10978             :     /* Execute the query for the next batch of relations. */
   10979        2234 :     if (count > 0)
   10980             :     {
   10981         206 :         PQExpBuffer query = createPQExpBuffer();
   10982             : 
   10983         206 :         appendPQExpBufferStr(query, "EXECUTE getAttributeStats(");
   10984         206 :         appendStringLiteralAH(query, nspnames->data, fout);
   10985         206 :         appendPQExpBufferStr(query, "::pg_catalog.name[],");
   10986         206 :         appendStringLiteralAH(query, relnames->data, fout);
   10987         206 :         appendPQExpBufferStr(query, "::pg_catalog.name[])");
   10988         206 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   10989         206 :         destroyPQExpBuffer(query);
   10990             :     }
   10991             : 
   10992        2234 :     destroyPQExpBuffer(nspnames);
   10993        2234 :     destroyPQExpBuffer(relnames);
   10994        2234 :     return res;
   10995             : }
   10996             : 
   10997             : /*
   10998             :  * dumpRelationStats_dumper --
   10999             :  *
   11000             :  * Generate command to import stats into the relation on the new database.
   11001             :  * This routine is called by the Archiver when it wants the statistics to be
   11002             :  * dumped.
   11003             :  */
   11004             : static char *
   11005        7008 : dumpRelationStats_dumper(Archive *fout, const void *userArg, const TocEntry *te)
   11006             : {
   11007        7008 :     const RelStatsInfo *rsinfo = (RelStatsInfo *) userArg;
   11008             :     static PGresult *res;
   11009             :     static int  rownum;
   11010             :     PQExpBuffer query;
   11011             :     PQExpBufferData out_data;
   11012        7008 :     PQExpBuffer out = &out_data;
   11013             :     int         i_schemaname;
   11014             :     int         i_tablename;
   11015             :     int         i_attname;
   11016             :     int         i_inherited;
   11017             :     int         i_null_frac;
   11018             :     int         i_avg_width;
   11019             :     int         i_n_distinct;
   11020             :     int         i_most_common_vals;
   11021             :     int         i_most_common_freqs;
   11022             :     int         i_histogram_bounds;
   11023             :     int         i_correlation;
   11024             :     int         i_most_common_elems;
   11025             :     int         i_most_common_elem_freqs;
   11026             :     int         i_elem_count_histogram;
   11027             :     int         i_range_length_histogram;
   11028             :     int         i_range_empty_frac;
   11029             :     int         i_range_bounds_histogram;
   11030             :     static TocEntry *expected_te;
   11031             : 
   11032             :     /*
   11033             :      * fetchAttributeStats() assumes that the statistics are dumped in the
   11034             :      * order they are listed in the TOC.  We verify that here for safety.
   11035             :      */
   11036        7008 :     if (!expected_te)
   11037         114 :         expected_te = ((ArchiveHandle *) fout)->toc;
   11038             : 
   11039        7008 :     expected_te = expected_te->next;
   11040       27830 :     while ((expected_te->reqs & REQ_STATS) == 0 ||
   11041        7008 :            strcmp(expected_te->desc, "STATISTICS DATA") != 0)
   11042       20822 :         expected_te = expected_te->next;
   11043             : 
   11044        7008 :     if (te != expected_te)
   11045           0 :         pg_fatal("statistics dumped out of order (current: %d %s %s, expected: %d %s %s)",
   11046             :                  te->dumpId, te->desc, te->tag,
   11047             :                  expected_te->dumpId, expected_te->desc, expected_te->tag);
   11048             : 
   11049        7008 :     query = createPQExpBuffer();
   11050        7008 :     if (!fout->is_prepared[PREPQUERY_GETATTRIBUTESTATS])
   11051             :     {
   11052         114 :         appendPQExpBufferStr(query,
   11053             :                              "PREPARE getAttributeStats(pg_catalog.name[], pg_catalog.name[]) AS\n"
   11054             :                              "SELECT s.schemaname, s.tablename, s.attname, s.inherited, "
   11055             :                              "s.null_frac, s.avg_width, s.n_distinct, "
   11056             :                              "s.most_common_vals, s.most_common_freqs, "
   11057             :                              "s.histogram_bounds, s.correlation, "
   11058             :                              "s.most_common_elems, s.most_common_elem_freqs, "
   11059             :                              "s.elem_count_histogram, ");
   11060             : 
   11061         114 :         if (fout->remoteVersion >= 170000)
   11062         114 :             appendPQExpBufferStr(query,
   11063             :                                  "s.range_length_histogram, "
   11064             :                                  "s.range_empty_frac, "
   11065             :                                  "s.range_bounds_histogram ");
   11066             :         else
   11067           0 :             appendPQExpBufferStr(query,
   11068             :                                  "NULL AS range_length_histogram,"
   11069             :                                  "NULL AS range_empty_frac,"
   11070             :                                  "NULL AS range_bounds_histogram ");
   11071             : 
   11072             :         /*
   11073             :          * The results must be in the order of the relations supplied in the
   11074             :          * parameters to ensure we remain in sync as we walk through the TOC.
   11075             :          * The redundant filter clause on s.tablename = ANY(...) seems
   11076             :          * sufficient to convince the planner to use
   11077             :          * pg_class_relname_nsp_index, which avoids a full scan of pg_stats.
   11078             :          * This may not work for all versions.
   11079             :          *
   11080             :          * Our query for retrieving statistics for multiple relations uses
   11081             :          * WITH ORDINALITY and multi-argument UNNEST(), both of which were
   11082             :          * introduced in v9.4.  For older versions, we resort to gathering
   11083             :          * statistics for a single relation at a time.
   11084             :          */
   11085         114 :         if (fout->remoteVersion >= 90400)
   11086         114 :             appendPQExpBufferStr(query,
   11087             :                                  "FROM pg_catalog.pg_stats s "
   11088             :                                  "JOIN unnest($1, $2) WITH ORDINALITY AS u (schemaname, tablename, ord) "
   11089             :                                  "ON s.schemaname = u.schemaname "
   11090             :                                  "AND s.tablename = u.tablename "
   11091             :                                  "WHERE s.tablename = ANY($2) "
   11092             :                                  "ORDER BY u.ord, s.attname, s.inherited");
   11093             :         else
   11094           0 :             appendPQExpBufferStr(query,
   11095             :                                  "FROM pg_catalog.pg_stats s "
   11096             :                                  "WHERE s.schemaname = $1[1] "
   11097             :                                  "AND s.tablename = $2[1] "
   11098             :                                  "ORDER BY s.attname, s.inherited");
   11099             : 
   11100         114 :         ExecuteSqlStatement(fout, query->data);
   11101             : 
   11102         114 :         fout->is_prepared[PREPQUERY_GETATTRIBUTESTATS] = true;
   11103         114 :         resetPQExpBuffer(query);
   11104             :     }
   11105             : 
   11106        7008 :     initPQExpBuffer(out);
   11107             : 
   11108             :     /* restore relation stats */
   11109        7008 :     appendPQExpBufferStr(out, "SELECT * FROM pg_catalog.pg_restore_relation_stats(\n");
   11110        7008 :     appendPQExpBuffer(out, "\t'version', '%d'::integer,\n",
   11111             :                       fout->remoteVersion);
   11112        7008 :     appendPQExpBufferStr(out, "\t'schemaname', ");
   11113        7008 :     appendStringLiteralAH(out, rsinfo->dobj.namespace->dobj.name, fout);
   11114        7008 :     appendPQExpBufferStr(out, ",\n");
   11115        7008 :     appendPQExpBufferStr(out, "\t'relname', ");
   11116        7008 :     appendStringLiteralAH(out, rsinfo->dobj.name, fout);
   11117        7008 :     appendPQExpBufferStr(out, ",\n");
   11118        7008 :     appendPQExpBuffer(out, "\t'relpages', '%d'::integer,\n", rsinfo->relpages);
   11119             : 
   11120             :     /*
   11121             :      * Before v14, a reltuples value of 0 was ambiguous: it could either mean
   11122             :      * the relation is empty, or it could mean that it hadn't yet been
   11123             :      * vacuumed or analyzed.  (Newer versions use -1 for the latter case.)
   11124             :      * This ambiguity allegedly can cause the planner to choose inefficient
   11125             :      * plans after restoring to v18 or newer.  To deal with this, let's just
   11126             :      * set reltuples to -1 in that case.
   11127             :      */
   11128        7008 :     if (fout->remoteVersion < 140000 && strcmp("0", rsinfo->reltuples) == 0)
   11129           0 :         appendPQExpBufferStr(out, "\t'reltuples', '-1'::real,\n");
   11130             :     else
   11131        7008 :         appendPQExpBuffer(out, "\t'reltuples', '%s'::real,\n", rsinfo->reltuples);
   11132             : 
   11133        7008 :     appendPQExpBuffer(out, "\t'relallvisible', '%d'::integer",
   11134        7008 :                       rsinfo->relallvisible);
   11135             : 
   11136        7008 :     if (fout->remoteVersion >= 180000)
   11137        7008 :         appendPQExpBuffer(out, ",\n\t'relallfrozen', '%d'::integer", rsinfo->relallfrozen);
   11138             : 
   11139        7008 :     appendPQExpBufferStr(out, "\n);\n");
   11140             : 
   11141             :     /* Fetch the next batch of attribute statistics if needed. */
   11142        7008 :     if (rownum >= PQntuples(res))
   11143             :     {
   11144        2234 :         PQclear(res);
   11145        2234 :         res = fetchAttributeStats(fout);
   11146        2234 :         rownum = 0;
   11147             :     }
   11148             : 
   11149        7008 :     i_schemaname = PQfnumber(res, "schemaname");
   11150        7008 :     i_tablename = PQfnumber(res, "tablename");
   11151        7008 :     i_attname = PQfnumber(res, "attname");
   11152        7008 :     i_inherited = PQfnumber(res, "inherited");
   11153        7008 :     i_null_frac = PQfnumber(res, "null_frac");
   11154        7008 :     i_avg_width = PQfnumber(res, "avg_width");
   11155        7008 :     i_n_distinct = PQfnumber(res, "n_distinct");
   11156        7008 :     i_most_common_vals = PQfnumber(res, "most_common_vals");
   11157        7008 :     i_most_common_freqs = PQfnumber(res, "most_common_freqs");
   11158        7008 :     i_histogram_bounds = PQfnumber(res, "histogram_bounds");
   11159        7008 :     i_correlation = PQfnumber(res, "correlation");
   11160        7008 :     i_most_common_elems = PQfnumber(res, "most_common_elems");
   11161        7008 :     i_most_common_elem_freqs = PQfnumber(res, "most_common_elem_freqs");
   11162        7008 :     i_elem_count_histogram = PQfnumber(res, "elem_count_histogram");
   11163        7008 :     i_range_length_histogram = PQfnumber(res, "range_length_histogram");
   11164        7008 :     i_range_empty_frac = PQfnumber(res, "range_empty_frac");
   11165        7008 :     i_range_bounds_histogram = PQfnumber(res, "range_bounds_histogram");
   11166             : 
   11167             :     /* restore attribute stats */
   11168        8534 :     for (; rownum < PQntuples(res); rownum++)
   11169             :     {
   11170             :         const char *attname;
   11171             : 
   11172             :         /* Stop if the next stat row in our cache isn't for this relation. */
   11173        6300 :         if (strcmp(te->tag, PQgetvalue(res, rownum, i_tablename)) != 0 ||
   11174        1526 :             strcmp(te->namespace, PQgetvalue(res, rownum, i_schemaname)) != 0)
   11175             :             break;
   11176             : 
   11177        1526 :         appendPQExpBufferStr(out, "SELECT * FROM pg_catalog.pg_restore_attribute_stats(\n");
   11178        1526 :         appendPQExpBuffer(out, "\t'version', '%d'::integer,\n",
   11179             :                           fout->remoteVersion);
   11180        1526 :         appendPQExpBufferStr(out, "\t'schemaname', ");
   11181        1526 :         appendStringLiteralAH(out, rsinfo->dobj.namespace->dobj.name, fout);
   11182        1526 :         appendPQExpBufferStr(out, ",\n\t'relname', ");
   11183        1526 :         appendStringLiteralAH(out, rsinfo->dobj.name, fout);
   11184             : 
   11185        1526 :         if (PQgetisnull(res, rownum, i_attname))
   11186           0 :             pg_fatal("unexpected null attname");
   11187        1526 :         attname = PQgetvalue(res, rownum, i_attname);
   11188             : 
   11189             :         /*
   11190             :          * Indexes look up attname in indAttNames to derive attnum, all others
   11191             :          * use attname directly.  We must specify attnum for indexes, since
   11192             :          * their attnames are not necessarily stable across dump/reload.
   11193             :          */
   11194        1526 :         if (rsinfo->nindAttNames == 0)
   11195             :         {
   11196        1450 :             appendPQExpBufferStr(out, ",\n\t'attname', ");
   11197        1450 :             appendStringLiteralAH(out, attname, fout);
   11198             :         }
   11199             :         else
   11200             :         {
   11201          76 :             bool        found = false;
   11202             : 
   11203         144 :             for (int i = 0; i < rsinfo->nindAttNames; i++)
   11204             :             {
   11205         144 :                 if (strcmp(attname, rsinfo->indAttNames[i]) == 0)
   11206             :                 {
   11207          76 :                     appendPQExpBuffer(out, ",\n\t'attnum', '%d'::smallint",
   11208             :                                       i + 1);
   11209          76 :                     found = true;
   11210          76 :                     break;
   11211             :                 }
   11212             :             }
   11213             : 
   11214          76 :             if (!found)
   11215           0 :                 pg_fatal("could not find index attname \"%s\"", attname);
   11216             :         }
   11217             : 
   11218        1526 :         if (!PQgetisnull(res, rownum, i_inherited))
   11219        1526 :             appendNamedArgument(out, fout, "inherited", "boolean",
   11220        1526 :                                 PQgetvalue(res, rownum, i_inherited));
   11221        1526 :         if (!PQgetisnull(res, rownum, i_null_frac))
   11222        1526 :             appendNamedArgument(out, fout, "null_frac", "real",
   11223        1526 :                                 PQgetvalue(res, rownum, i_null_frac));
   11224        1526 :         if (!PQgetisnull(res, rownum, i_avg_width))
   11225        1526 :             appendNamedArgument(out, fout, "avg_width", "integer",
   11226        1526 :                                 PQgetvalue(res, rownum, i_avg_width));
   11227        1526 :         if (!PQgetisnull(res, rownum, i_n_distinct))
   11228        1526 :             appendNamedArgument(out, fout, "n_distinct", "real",
   11229        1526 :                                 PQgetvalue(res, rownum, i_n_distinct));
   11230        1526 :         if (!PQgetisnull(res, rownum, i_most_common_vals))
   11231         764 :             appendNamedArgument(out, fout, "most_common_vals", "text",
   11232         764 :                                 PQgetvalue(res, rownum, i_most_common_vals));
   11233        1526 :         if (!PQgetisnull(res, rownum, i_most_common_freqs))
   11234         764 :             appendNamedArgument(out, fout, "most_common_freqs", "real[]",
   11235         764 :                                 PQgetvalue(res, rownum, i_most_common_freqs));
   11236        1526 :         if (!PQgetisnull(res, rownum, i_histogram_bounds))
   11237         922 :             appendNamedArgument(out, fout, "histogram_bounds", "text",
   11238         922 :                                 PQgetvalue(res, rownum, i_histogram_bounds));
   11239        1526 :         if (!PQgetisnull(res, rownum, i_correlation))
   11240        1464 :             appendNamedArgument(out, fout, "correlation", "real",
   11241        1464 :                                 PQgetvalue(res, rownum, i_correlation));
   11242        1526 :         if (!PQgetisnull(res, rownum, i_most_common_elems))
   11243          16 :             appendNamedArgument(out, fout, "most_common_elems", "text",
   11244          16 :                                 PQgetvalue(res, rownum, i_most_common_elems));
   11245        1526 :         if (!PQgetisnull(res, rownum, i_most_common_elem_freqs))
   11246          16 :             appendNamedArgument(out, fout, "most_common_elem_freqs", "real[]",
   11247          16 :                                 PQgetvalue(res, rownum, i_most_common_elem_freqs));
   11248        1526 :         if (!PQgetisnull(res, rownum, i_elem_count_histogram))
   11249          14 :             appendNamedArgument(out, fout, "elem_count_histogram", "real[]",
   11250          14 :                                 PQgetvalue(res, rownum, i_elem_count_histogram));
   11251        1526 :         if (fout->remoteVersion >= 170000)
   11252             :         {
   11253        1526 :             if (!PQgetisnull(res, rownum, i_range_length_histogram))
   11254           6 :                 appendNamedArgument(out, fout, "range_length_histogram", "text",
   11255           6 :                                     PQgetvalue(res, rownum, i_range_length_histogram));
   11256        1526 :             if (!PQgetisnull(res, rownum, i_range_empty_frac))
   11257           6 :                 appendNamedArgument(out, fout, "range_empty_frac", "real",
   11258           6 :                                     PQgetvalue(res, rownum, i_range_empty_frac));
   11259        1526 :             if (!PQgetisnull(res, rownum, i_range_bounds_histogram))
   11260           6 :                 appendNamedArgument(out, fout, "range_bounds_histogram", "text",
   11261           6 :                                     PQgetvalue(res, rownum, i_range_bounds_histogram));
   11262             :         }
   11263        1526 :         appendPQExpBufferStr(out, "\n);\n");
   11264             :     }
   11265             : 
   11266        7008 :     destroyPQExpBuffer(query);
   11267        7008 :     return out->data;
   11268             : }
   11269             : 
   11270             : /*
   11271             :  * dumpRelationStats --
   11272             :  *
   11273             :  * Make an ArchiveEntry for the relation statistics.  The Archiver will take
   11274             :  * care of gathering the statistics and generating the restore commands when
   11275             :  * they are needed.
   11276             :  */
   11277             : static void
   11278        7152 : dumpRelationStats(Archive *fout, const RelStatsInfo *rsinfo)
   11279             : {
   11280        7152 :     const DumpableObject *dobj = &rsinfo->dobj;
   11281             : 
   11282             :     /* nothing to do if we are not dumping statistics */
   11283        7152 :     if (!fout->dopt->dumpStatistics)
   11284           0 :         return;
   11285             : 
   11286        7152 :     ArchiveEntry(fout, nilCatalogId, createDumpId(),
   11287        7152 :                  ARCHIVE_OPTS(.tag = dobj->name,
   11288             :                               .namespace = dobj->namespace->dobj.name,
   11289             :                               .description = "STATISTICS DATA",
   11290             :                               .section = rsinfo->section,
   11291             :                               .defnFn = dumpRelationStats_dumper,
   11292             :                               .defnArg = rsinfo,
   11293             :                               .deps = dobj->dependencies,
   11294             :                               .nDeps = dobj->nDeps));
   11295             : }
   11296             : 
   11297             : /*
   11298             :  * dumpTableComment --
   11299             :  *
   11300             :  * As above, but dump comments for both the specified table (or view)
   11301             :  * and its columns.
   11302             :  */
   11303             : static void
   11304         160 : dumpTableComment(Archive *fout, const TableInfo *tbinfo,
   11305             :                  const char *reltypename)
   11306             : {
   11307         160 :     DumpOptions *dopt = fout->dopt;
   11308             :     CommentItem *comments;
   11309             :     int         ncomments;
   11310             :     PQExpBuffer query;
   11311             :     PQExpBuffer tag;
   11312             : 
   11313             :     /* do nothing, if --no-comments is supplied */
   11314         160 :     if (dopt->no_comments)
   11315           0 :         return;
   11316             : 
   11317             :     /* Comments are SCHEMA not data */
   11318         160 :     if (!dopt->dumpSchema)
   11319           0 :         return;
   11320             : 
   11321             :     /* Search for comments associated with relation, using table */
   11322         160 :     ncomments = findComments(tbinfo->dobj.catId.tableoid,
   11323         160 :                              tbinfo->dobj.catId.oid,
   11324             :                              &comments);
   11325             : 
   11326             :     /* If comments exist, build COMMENT ON statements */
   11327         160 :     if (ncomments <= 0)
   11328           0 :         return;
   11329             : 
   11330         160 :     query = createPQExpBuffer();
   11331         160 :     tag = createPQExpBuffer();
   11332             : 
   11333         460 :     while (ncomments > 0)
   11334             :     {
   11335         300 :         const char *descr = comments->descr;
   11336         300 :         int         objsubid = comments->objsubid;
   11337             : 
   11338         300 :         if (objsubid == 0)
   11339             :         {
   11340          70 :             resetPQExpBuffer(tag);
   11341          70 :             appendPQExpBuffer(tag, "%s %s", reltypename,
   11342          70 :                               fmtId(tbinfo->dobj.name));
   11343             : 
   11344          70 :             resetPQExpBuffer(query);
   11345          70 :             appendPQExpBuffer(query, "COMMENT ON %s %s IS ", reltypename,
   11346          70 :                               fmtQualifiedDumpable(tbinfo));
   11347          70 :             appendStringLiteralAH(query, descr, fout);
   11348          70 :             appendPQExpBufferStr(query, ";\n");
   11349             : 
   11350          70 :             ArchiveEntry(fout, nilCatalogId, createDumpId(),
   11351          70 :                          ARCHIVE_OPTS(.tag = tag->data,
   11352             :                                       .namespace = tbinfo->dobj.namespace->dobj.name,
   11353             :                                       .owner = tbinfo->rolname,
   11354             :                                       .description = "COMMENT",
   11355             :                                       .section = SECTION_NONE,
   11356             :                                       .createStmt = query->data,
   11357             :                                       .deps = &(tbinfo->dobj.dumpId),
   11358             :                                       .nDeps = 1));
   11359             :         }
   11360         230 :         else if (objsubid > 0 && objsubid <= tbinfo->numatts)
   11361             :         {
   11362         230 :             resetPQExpBuffer(tag);
   11363         230 :             appendPQExpBuffer(tag, "COLUMN %s.",
   11364         230 :                               fmtId(tbinfo->dobj.name));
   11365         230 :             appendPQExpBufferStr(tag, fmtId(tbinfo->attnames[objsubid - 1]));
   11366             : 
   11367         230 :             resetPQExpBuffer(query);
   11368         230 :             appendPQExpBuffer(query, "COMMENT ON COLUMN %s.",
   11369         230 :                               fmtQualifiedDumpable(tbinfo));
   11370         230 :             appendPQExpBuffer(query, "%s IS ",
   11371         230 :                               fmtId(tbinfo->attnames[objsubid - 1]));
   11372         230 :             appendStringLiteralAH(query, descr, fout);
   11373         230 :             appendPQExpBufferStr(query, ";\n");
   11374             : 
   11375         230 :             ArchiveEntry(fout, nilCatalogId, createDumpId(),
   11376         230 :                          ARCHIVE_OPTS(.tag = tag->data,
   11377             :                                       .namespace = tbinfo->dobj.namespace->dobj.name,
   11378             :                                       .owner = tbinfo->rolname,
   11379             :                                       .description = "COMMENT",
   11380             :                                       .section = SECTION_NONE,
   11381             :                                       .createStmt = query->data,
   11382             :                                       .deps = &(tbinfo->dobj.dumpId),
   11383             :                                       .nDeps = 1));
   11384             :         }
   11385             : 
   11386         300 :         comments++;
   11387         300 :         ncomments--;
   11388             :     }
   11389             : 
   11390         160 :     destroyPQExpBuffer(query);
   11391         160 :     destroyPQExpBuffer(tag);
   11392             : }
   11393             : 
   11394             : /*
   11395             :  * findComments --
   11396             :  *
   11397             :  * Find the comment(s), if any, associated with the given object.  All the
   11398             :  * objsubid values associated with the given classoid/objoid are found with
   11399             :  * one search.
   11400             :  */
   11401             : static int
   11402       13196 : findComments(Oid classoid, Oid objoid, CommentItem **items)
   11403             : {
   11404       13196 :     CommentItem *middle = NULL;
   11405             :     CommentItem *low;
   11406             :     CommentItem *high;
   11407             :     int         nmatch;
   11408             : 
   11409             :     /*
   11410             :      * Do binary search to find some item matching the object.
   11411             :      */
   11412       13196 :     low = &comments[0];
   11413       13196 :     high = &comments[ncomments - 1];
   11414      131426 :     while (low <= high)
   11415             :     {
   11416      131338 :         middle = low + (high - low) / 2;
   11417             : 
   11418      131338 :         if (classoid < middle->classoid)
   11419       14870 :             high = middle - 1;
   11420      116468 :         else if (classoid > middle->classoid)
   11421       14356 :             low = middle + 1;
   11422      102112 :         else if (objoid < middle->objoid)
   11423       43126 :             high = middle - 1;
   11424       58986 :         else if (objoid > middle->objoid)
   11425       45878 :             low = middle + 1;
   11426             :         else
   11427       13108 :             break;              /* found a match */
   11428             :     }
   11429             : 
   11430       13196 :     if (low > high)              /* no matches */
   11431             :     {
   11432          88 :         *items = NULL;
   11433          88 :         return 0;
   11434             :     }
   11435             : 
   11436             :     /*
   11437             :      * Now determine how many items match the object.  The search loop
   11438             :      * invariant still holds: only items between low and high inclusive could
   11439             :      * match.
   11440             :      */
   11441       13108 :     nmatch = 1;
   11442       13248 :     while (middle > low)
   11443             :     {
   11444        6134 :         if (classoid != middle[-1].classoid ||
   11445        5876 :             objoid != middle[-1].objoid)
   11446             :             break;
   11447         140 :         middle--;
   11448         140 :         nmatch++;
   11449             :     }
   11450             : 
   11451       13108 :     *items = middle;
   11452             : 
   11453       13108 :     middle += nmatch;
   11454       13108 :     while (middle <= high)
   11455             :     {
   11456        7046 :         if (classoid != middle->classoid ||
   11457        6428 :             objoid != middle->objoid)
   11458             :             break;
   11459           0 :         middle++;
   11460           0 :         nmatch++;
   11461             :     }
   11462             : 
   11463       13108 :     return nmatch;
   11464             : }
   11465             : 
   11466             : /*
   11467             :  * collectComments --
   11468             :  *
   11469             :  * Construct a table of all comments available for database objects;
   11470             :  * also set the has-comment component flag for each relevant object.
   11471             :  *
   11472             :  * We used to do per-object queries for the comments, but it's much faster
   11473             :  * to pull them all over at once, and on most databases the memory cost
   11474             :  * isn't high.
   11475             :  *
   11476             :  * The table is sorted by classoid/objid/objsubid for speed in lookup.
   11477             :  */
   11478             : static void
   11479         364 : collectComments(Archive *fout)
   11480             : {
   11481             :     PGresult   *res;
   11482             :     PQExpBuffer query;
   11483             :     int         i_description;
   11484             :     int         i_classoid;
   11485             :     int         i_objoid;
   11486             :     int         i_objsubid;
   11487             :     int         ntups;
   11488             :     int         i;
   11489             :     DumpableObject *dobj;
   11490             : 
   11491         364 :     query = createPQExpBuffer();
   11492             : 
   11493         364 :     appendPQExpBufferStr(query, "SELECT description, classoid, objoid, objsubid "
   11494             :                          "FROM pg_catalog.pg_description "
   11495             :                          "ORDER BY classoid, objoid, objsubid");
   11496             : 
   11497         364 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   11498             : 
   11499             :     /* Construct lookup table containing OIDs in numeric form */
   11500             : 
   11501         364 :     i_description = PQfnumber(res, "description");
   11502         364 :     i_classoid = PQfnumber(res, "classoid");
   11503         364 :     i_objoid = PQfnumber(res, "objoid");
   11504         364 :     i_objsubid = PQfnumber(res, "objsubid");
   11505             : 
   11506         364 :     ntups = PQntuples(res);
   11507             : 
   11508         364 :     comments = (CommentItem *) pg_malloc(ntups * sizeof(CommentItem));
   11509         364 :     ncomments = 0;
   11510         364 :     dobj = NULL;
   11511             : 
   11512     1939322 :     for (i = 0; i < ntups; i++)
   11513             :     {
   11514             :         CatalogId   objId;
   11515             :         int         subid;
   11516             : 
   11517     1938958 :         objId.tableoid = atooid(PQgetvalue(res, i, i_classoid));
   11518     1938958 :         objId.oid = atooid(PQgetvalue(res, i, i_objoid));
   11519     1938958 :         subid = atoi(PQgetvalue(res, i, i_objsubid));
   11520             : 
   11521             :         /* We needn't remember comments that don't match any dumpable object */
   11522     1938958 :         if (dobj == NULL ||
   11523      698686 :             dobj->catId.tableoid != objId.tableoid ||
   11524      694268 :             dobj->catId.oid != objId.oid)
   11525     1938766 :             dobj = findObjectByCatalogId(objId);
   11526     1938958 :         if (dobj == NULL)
   11527     1239920 :             continue;
   11528             : 
   11529             :         /*
   11530             :          * Comments on columns of composite types are linked to the type's
   11531             :          * pg_class entry, but we need to set the DUMP_COMPONENT_COMMENT flag
   11532             :          * in the type's own DumpableObject.
   11533             :          */
   11534      699038 :         if (subid != 0 && dobj->objType == DO_TABLE &&
   11535         412 :             ((TableInfo *) dobj)->relkind == RELKIND_COMPOSITE_TYPE)
   11536          96 :         {
   11537             :             TypeInfo   *cTypeInfo;
   11538             : 
   11539          96 :             cTypeInfo = findTypeByOid(((TableInfo *) dobj)->reltype);
   11540          96 :             if (cTypeInfo)
   11541          96 :                 cTypeInfo->dobj.components |= DUMP_COMPONENT_COMMENT;
   11542             :         }
   11543             :         else
   11544      698942 :             dobj->components |= DUMP_COMPONENT_COMMENT;
   11545             : 
   11546      699038 :         comments[ncomments].descr = pg_strdup(PQgetvalue(res, i, i_description));
   11547      699038 :         comments[ncomments].classoid = objId.tableoid;
   11548      699038 :         comments[ncomments].objoid = objId.oid;
   11549      699038 :         comments[ncomments].objsubid = subid;
   11550      699038 :         ncomments++;
   11551             :     }
   11552             : 
   11553         364 :     PQclear(res);
   11554         364 :     destroyPQExpBuffer(query);
   11555         364 : }
   11556             : 
   11557             : /*
   11558             :  * dumpDumpableObject
   11559             :  *
   11560             :  * This routine and its subsidiaries are responsible for creating
   11561             :  * ArchiveEntries (TOC objects) for each object to be dumped.
   11562             :  */
   11563             : static void
   11564     1355142 : dumpDumpableObject(Archive *fout, DumpableObject *dobj)
   11565             : {
   11566             :     /*
   11567             :      * Clear any dump-request bits for components that don't exist for this
   11568             :      * object.  (This makes it safe to initially use DUMP_COMPONENT_ALL as the
   11569             :      * request for every kind of object.)
   11570             :      */
   11571     1355142 :     dobj->dump &= dobj->components;
   11572             : 
   11573             :     /* Now, short-circuit if there's nothing to be done here. */
   11574     1355142 :     if (dobj->dump == 0)
   11575     1201090 :         return;
   11576             : 
   11577      154052 :     switch (dobj->objType)
   11578             :     {
   11579         966 :         case DO_NAMESPACE:
   11580         966 :             dumpNamespace(fout, (const NamespaceInfo *) dobj);
   11581         966 :             break;
   11582          38 :         case DO_EXTENSION:
   11583          38 :             dumpExtension(fout, (const ExtensionInfo *) dobj);
   11584          38 :             break;
   11585        1888 :         case DO_TYPE:
   11586        1888 :             dumpType(fout, (const TypeInfo *) dobj);
   11587        1888 :             break;
   11588         152 :         case DO_SHELL_TYPE:
   11589         152 :             dumpShellType(fout, (const ShellTypeInfo *) dobj);
   11590         152 :             break;
   11591        3686 :         case DO_FUNC:
   11592        3686 :             dumpFunc(fout, (const FuncInfo *) dobj);
   11593        3686 :             break;
   11594         590 :         case DO_AGG:
   11595         590 :             dumpAgg(fout, (const AggInfo *) dobj);
   11596         590 :             break;
   11597        5014 :         case DO_OPERATOR:
   11598        5014 :             dumpOpr(fout, (const OprInfo *) dobj);
   11599        5014 :             break;
   11600         172 :         case DO_ACCESS_METHOD:
   11601         172 :             dumpAccessMethod(fout, (const AccessMethodInfo *) dobj);
   11602         172 :             break;
   11603        1338 :         case DO_OPCLASS:
   11604        1338 :             dumpOpclass(fout, (const OpclassInfo *) dobj);
   11605        1338 :             break;
   11606        1110 :         case DO_OPFAMILY:
   11607        1110 :             dumpOpfamily(fout, (const OpfamilyInfo *) dobj);
   11608        1110 :             break;
   11609        5086 :         case DO_COLLATION:
   11610        5086 :             dumpCollation(fout, (const CollInfo *) dobj);
   11611        5086 :             break;
   11612         850 :         case DO_CONVERSION:
   11613         850 :             dumpConversion(fout, (const ConvInfo *) dobj);
   11614         850 :             break;
   11615       61058 :         case DO_TABLE:
   11616       61058 :             dumpTable(fout, (const TableInfo *) dobj);
   11617       61058 :             break;
   11618        2816 :         case DO_TABLE_ATTACH:
   11619        2816 :             dumpTableAttach(fout, (const TableAttachInfo *) dobj);
   11620        2816 :             break;
   11621        2136 :         case DO_ATTRDEF:
   11622        2136 :             dumpAttrDef(fout, (const AttrDefInfo *) dobj);
   11623        2136 :             break;
   11624        5262 :         case DO_INDEX:
   11625        5262 :             dumpIndex(fout, (const IndxInfo *) dobj);
   11626        5262 :             break;
   11627        1176 :         case DO_INDEX_ATTACH:
   11628        1176 :             dumpIndexAttach(fout, (const IndexAttachInfo *) dobj);
   11629        1176 :             break;
   11630         284 :         case DO_STATSEXT:
   11631         284 :             dumpStatisticsExt(fout, (const StatsExtInfo *) dobj);
   11632         284 :             break;
   11633         804 :         case DO_REFRESH_MATVIEW:
   11634         804 :             refreshMatViewData(fout, (const TableDataInfo *) dobj);
   11635         804 :             break;
   11636        2380 :         case DO_RULE:
   11637        2380 :             dumpRule(fout, (const RuleInfo *) dobj);
   11638        2380 :             break;
   11639        1076 :         case DO_TRIGGER:
   11640        1076 :             dumpTrigger(fout, (const TriggerInfo *) dobj);
   11641        1076 :             break;
   11642          90 :         case DO_EVENT_TRIGGER:
   11643          90 :             dumpEventTrigger(fout, (const EventTriggerInfo *) dobj);
   11644          90 :             break;
   11645        4774 :         case DO_CONSTRAINT:
   11646        4774 :             dumpConstraint(fout, (const ConstraintInfo *) dobj);
   11647        4774 :             break;
   11648         354 :         case DO_FK_CONSTRAINT:
   11649         354 :             dumpConstraint(fout, (const ConstraintInfo *) dobj);
   11650         354 :             break;
   11651         176 :         case DO_PROCLANG:
   11652         176 :             dumpProcLang(fout, (const ProcLangInfo *) dobj);
   11653         176 :             break;
   11654         140 :         case DO_CAST:
   11655         140 :             dumpCast(fout, (const CastInfo *) dobj);
   11656         140 :             break;
   11657          90 :         case DO_TRANSFORM:
   11658          90 :             dumpTransform(fout, (const TransformInfo *) dobj);
   11659          90 :             break;
   11660         804 :         case DO_SEQUENCE_SET:
   11661         804 :             dumpSequenceData(fout, (const TableDataInfo *) dobj);
   11662         804 :             break;
   11663        8764 :         case DO_TABLE_DATA:
   11664        8764 :             dumpTableData(fout, (const TableDataInfo *) dobj);
   11665        8764 :             break;
   11666       29144 :         case DO_DUMMY_TYPE:
   11667             :             /* table rowtypes and array types are never dumped separately */
   11668       29144 :             break;
   11669          88 :         case DO_TSPARSER:
   11670          88 :             dumpTSParser(fout, (const TSParserInfo *) dobj);
   11671          88 :             break;
   11672         352 :         case DO_TSDICT:
   11673         352 :             dumpTSDictionary(fout, (const TSDictInfo *) dobj);
   11674         352 :             break;
   11675         112 :         case DO_TSTEMPLATE:
   11676         112 :             dumpTSTemplate(fout, (const TSTemplateInfo *) dobj);
   11677         112 :             break;
   11678         302 :         case DO_TSCONFIG:
   11679         302 :             dumpTSConfig(fout, (const TSConfigInfo *) dobj);
   11680         302 :             break;
   11681         110 :         case DO_FDW:
   11682         110 :             dumpForeignDataWrapper(fout, (const FdwInfo *) dobj);
   11683         110 :             break;
   11684         118 :         case DO_FOREIGN_SERVER:
   11685         118 :             dumpForeignServer(fout, (const ForeignServerInfo *) dobj);
   11686         118 :             break;
   11687         344 :         case DO_DEFAULT_ACL:
   11688         344 :             dumpDefaultACL(fout, (const DefaultACLInfo *) dobj);
   11689         344 :             break;
   11690         156 :         case DO_LARGE_OBJECT:
   11691         156 :             dumpLO(fout, (const LoInfo *) dobj);
   11692         156 :             break;
   11693         158 :         case DO_LARGE_OBJECT_DATA:
   11694         158 :             if (dobj->dump & DUMP_COMPONENT_DATA)
   11695             :             {
   11696             :                 LoInfo     *loinfo;
   11697             :                 TocEntry   *te;
   11698             : 
   11699         158 :                 loinfo = (LoInfo *) findObjectByDumpId(dobj->dependencies[0]);
   11700         158 :                 if (loinfo == NULL)
   11701           0 :                     pg_fatal("missing metadata for large objects \"%s\"",
   11702             :                              dobj->name);
   11703             : 
   11704         158 :                 te = ArchiveEntry(fout, dobj->catId, dobj->dumpId,
   11705         158 :                                   ARCHIVE_OPTS(.tag = dobj->name,
   11706             :                                                .owner = loinfo->rolname,
   11707             :                                                .description = "BLOBS",
   11708             :                                                .section = SECTION_DATA,
   11709             :                                                .deps = dobj->dependencies,
   11710             :                                                .nDeps = dobj->nDeps,
   11711             :                                                .dumpFn = dumpLOs,
   11712             :                                                .dumpArg = loinfo));
   11713             : 
   11714             :                 /*
   11715             :                  * Set the TocEntry's dataLength in case we are doing a
   11716             :                  * parallel dump and want to order dump jobs by table size.
   11717             :                  * (We need some size estimate for every TocEntry with a
   11718             :                  * DataDumper function.)  We don't currently have any cheap
   11719             :                  * way to estimate the size of LOs, but fortunately it doesn't
   11720             :                  * matter too much as long as we get large batches of LOs
   11721             :                  * processed reasonably early.  Assume 8K per blob.
   11722             :                  */
   11723         158 :                 te->dataLength = loinfo->numlos * (pgoff_t) 8192;
   11724             :             }
   11725         158 :             break;
   11726         694 :         case DO_POLICY:
   11727         694 :             dumpPolicy(fout, (const PolicyInfo *) dobj);
   11728         694 :             break;
   11729         452 :         case DO_PUBLICATION:
   11730         452 :             dumpPublication(fout, (const PublicationInfo *) dobj);
   11731         452 :             break;
   11732         610 :         case DO_PUBLICATION_REL:
   11733         610 :             dumpPublicationTable(fout, (const PublicationRelInfo *) dobj);
   11734         610 :             break;
   11735         210 :         case DO_PUBLICATION_TABLE_IN_SCHEMA:
   11736         210 :             dumpPublicationNamespace(fout,
   11737             :                                      (const PublicationSchemaInfo *) dobj);
   11738         210 :             break;
   11739         244 :         case DO_SUBSCRIPTION:
   11740         244 :             dumpSubscription(fout, (const SubscriptionInfo *) dobj);
   11741         244 :             break;
   11742           4 :         case DO_SUBSCRIPTION_REL:
   11743           4 :             dumpSubscriptionTable(fout, (const SubRelInfo *) dobj);
   11744           4 :             break;
   11745        7152 :         case DO_REL_STATS:
   11746        7152 :             dumpRelationStats(fout, (const RelStatsInfo *) dobj);
   11747        7152 :             break;
   11748         728 :         case DO_PRE_DATA_BOUNDARY:
   11749             :         case DO_POST_DATA_BOUNDARY:
   11750             :             /* never dumped, nothing to do */
   11751         728 :             break;
   11752             :     }
   11753             : }
   11754             : 
   11755             : /*
   11756             :  * dumpNamespace
   11757             :  *    writes out to fout the queries to recreate a user-defined namespace
   11758             :  */
   11759             : static void
   11760         966 : dumpNamespace(Archive *fout, const NamespaceInfo *nspinfo)
   11761             : {
   11762         966 :     DumpOptions *dopt = fout->dopt;
   11763             :     PQExpBuffer q;
   11764             :     PQExpBuffer delq;
   11765             :     char       *qnspname;
   11766             : 
   11767             :     /* Do nothing if not dumping schema */
   11768         966 :     if (!dopt->dumpSchema)
   11769          56 :         return;
   11770             : 
   11771         910 :     q = createPQExpBuffer();
   11772         910 :     delq = createPQExpBuffer();
   11773             : 
   11774         910 :     qnspname = pg_strdup(fmtId(nspinfo->dobj.name));
   11775             : 
   11776         910 :     if (nspinfo->create)
   11777             :     {
   11778         616 :         appendPQExpBuffer(delq, "DROP SCHEMA %s;\n", qnspname);
   11779         616 :         appendPQExpBuffer(q, "CREATE SCHEMA %s;\n", qnspname);
   11780             :     }
   11781             :     else
   11782             :     {
   11783             :         /* see selectDumpableNamespace() */
   11784         294 :         appendPQExpBufferStr(delq,
   11785             :                              "-- *not* dropping schema, since initdb creates it\n");
   11786         294 :         appendPQExpBufferStr(q,
   11787             :                              "-- *not* creating schema, since initdb creates it\n");
   11788             :     }
   11789             : 
   11790         910 :     if (dopt->binary_upgrade)
   11791         180 :         binary_upgrade_extension_member(q, &nspinfo->dobj,
   11792             :                                         "SCHEMA", qnspname, NULL);
   11793             : 
   11794         910 :     if (nspinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   11795         388 :         ArchiveEntry(fout, nspinfo->dobj.catId, nspinfo->dobj.dumpId,
   11796         388 :                      ARCHIVE_OPTS(.tag = nspinfo->dobj.name,
   11797             :                                   .owner = nspinfo->rolname,
   11798             :                                   .description = "SCHEMA",
   11799             :                                   .section = SECTION_PRE_DATA,
   11800             :                                   .createStmt = q->data,
   11801             :                                   .dropStmt = delq->data));
   11802             : 
   11803             :     /* Dump Schema Comments and Security Labels */
   11804         910 :     if (nspinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   11805             :     {
   11806         304 :         const char *initdb_comment = NULL;
   11807             : 
   11808         304 :         if (!nspinfo->create && strcmp(qnspname, "public") == 0)
   11809         226 :             initdb_comment = "standard public schema";
   11810         304 :         dumpCommentExtended(fout, "SCHEMA", qnspname,
   11811         304 :                             NULL, nspinfo->rolname,
   11812         304 :                             nspinfo->dobj.catId, 0, nspinfo->dobj.dumpId,
   11813             :                             initdb_comment);
   11814             :     }
   11815             : 
   11816         910 :     if (nspinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
   11817           0 :         dumpSecLabel(fout, "SCHEMA", qnspname,
   11818           0 :                      NULL, nspinfo->rolname,
   11819           0 :                      nspinfo->dobj.catId, 0, nspinfo->dobj.dumpId);
   11820             : 
   11821         910 :     if (nspinfo->dobj.dump & DUMP_COMPONENT_ACL)
   11822         700 :         dumpACL(fout, nspinfo->dobj.dumpId, InvalidDumpId, "SCHEMA",
   11823             :                 qnspname, NULL, NULL,
   11824         700 :                 NULL, nspinfo->rolname, &nspinfo->dacl);
   11825             : 
   11826         910 :     free(qnspname);
   11827             : 
   11828         910 :     destroyPQExpBuffer(q);
   11829         910 :     destroyPQExpBuffer(delq);
   11830             : }
   11831             : 
   11832             : /*
   11833             :  * dumpExtension
   11834             :  *    writes out to fout the queries to recreate an extension
   11835             :  */
   11836             : static void
   11837          38 : dumpExtension(Archive *fout, const ExtensionInfo *extinfo)
   11838             : {
   11839          38 :     DumpOptions *dopt = fout->dopt;
   11840             :     PQExpBuffer q;
   11841             :     PQExpBuffer delq;
   11842             :     char       *qextname;
   11843             : 
   11844             :     /* Do nothing if not dumping schema */
   11845          38 :     if (!dopt->dumpSchema)
   11846           2 :         return;
   11847             : 
   11848          36 :     q = createPQExpBuffer();
   11849          36 :     delq = createPQExpBuffer();
   11850             : 
   11851          36 :     qextname = pg_strdup(fmtId(extinfo->dobj.name));
   11852             : 
   11853          36 :     appendPQExpBuffer(delq, "DROP EXTENSION %s;\n", qextname);
   11854             : 
   11855          36 :     if (!dopt->binary_upgrade)
   11856             :     {
   11857             :         /*
   11858             :          * In a regular dump, we simply create the extension, intentionally
   11859             :          * not specifying a version, so that the destination installation's
   11860             :          * default version is used.
   11861             :          *
   11862             :          * Use of IF NOT EXISTS here is unlike our behavior for other object
   11863             :          * types; but there are various scenarios in which it's convenient to
   11864             :          * manually create the desired extension before restoring, so we
   11865             :          * prefer to allow it to exist already.
   11866             :          */
   11867          34 :         appendPQExpBuffer(q, "CREATE EXTENSION IF NOT EXISTS %s WITH SCHEMA %s;\n",
   11868          34 :                           qextname, fmtId(extinfo->namespace));
   11869             :     }
   11870             :     else
   11871             :     {
   11872             :         /*
   11873             :          * In binary-upgrade mode, it's critical to reproduce the state of the
   11874             :          * database exactly, so our procedure is to create an empty extension,
   11875             :          * restore all the contained objects normally, and add them to the
   11876             :          * extension one by one.  This function performs just the first of
   11877             :          * those steps.  binary_upgrade_extension_member() takes care of
   11878             :          * adding member objects as they're created.
   11879             :          */
   11880             :         int         i;
   11881             :         int         n;
   11882             : 
   11883           2 :         appendPQExpBufferStr(q, "-- For binary upgrade, create an empty extension and insert objects into it\n");
   11884             : 
   11885             :         /*
   11886             :          * We unconditionally create the extension, so we must drop it if it
   11887             :          * exists.  This could happen if the user deleted 'plpgsql' and then
   11888             :          * readded it, causing its oid to be greater than g_last_builtin_oid.
   11889             :          */
   11890           2 :         appendPQExpBuffer(q, "DROP EXTENSION IF EXISTS %s;\n", qextname);
   11891             : 
   11892           2 :         appendPQExpBufferStr(q,
   11893             :                              "SELECT pg_catalog.binary_upgrade_create_empty_extension(");
   11894           2 :         appendStringLiteralAH(q, extinfo->dobj.name, fout);
   11895           2 :         appendPQExpBufferStr(q, ", ");
   11896           2 :         appendStringLiteralAH(q, extinfo->namespace, fout);
   11897           2 :         appendPQExpBufferStr(q, ", ");
   11898           2 :         appendPQExpBuffer(q, "%s, ", extinfo->relocatable ? "true" : "false");
   11899           2 :         appendStringLiteralAH(q, extinfo->extversion, fout);
   11900           2 :         appendPQExpBufferStr(q, ", ");
   11901             : 
   11902             :         /*
   11903             :          * Note that we're pushing extconfig (an OID array) back into
   11904             :          * pg_extension exactly as-is.  This is OK because pg_class OIDs are
   11905             :          * preserved in binary upgrade.
   11906             :          */
   11907           2 :         if (strlen(extinfo->extconfig) > 2)
   11908           2 :             appendStringLiteralAH(q, extinfo->extconfig, fout);
   11909             :         else
   11910           0 :             appendPQExpBufferStr(q, "NULL");
   11911           2 :         appendPQExpBufferStr(q, ", ");
   11912           2 :         if (strlen(extinfo->extcondition) > 2)
   11913           2 :             appendStringLiteralAH(q, extinfo->extcondition, fout);
   11914             :         else
   11915           0 :             appendPQExpBufferStr(q, "NULL");
   11916           2 :         appendPQExpBufferStr(q, ", ");
   11917           2 :         appendPQExpBufferStr(q, "ARRAY[");
   11918           2 :         n = 0;
   11919           4 :         for (i = 0; i < extinfo->dobj.nDeps; i++)
   11920             :         {
   11921             :             DumpableObject *extobj;
   11922             : 
   11923           2 :             extobj = findObjectByDumpId(extinfo->dobj.dependencies[i]);
   11924           2 :             if (extobj && extobj->objType == DO_EXTENSION)
   11925             :             {
   11926           0 :                 if (n++ > 0)
   11927           0 :                     appendPQExpBufferChar(q, ',');
   11928           0 :                 appendStringLiteralAH(q, extobj->name, fout);
   11929             :             }
   11930             :         }
   11931           2 :         appendPQExpBufferStr(q, "]::pg_catalog.text[]");
   11932           2 :         appendPQExpBufferStr(q, ");\n");
   11933             :     }
   11934             : 
   11935          36 :     if (extinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   11936          36 :         ArchiveEntry(fout, extinfo->dobj.catId, extinfo->dobj.dumpId,
   11937          36 :                      ARCHIVE_OPTS(.tag = extinfo->dobj.name,
   11938             :                                   .description = "EXTENSION",
   11939             :                                   .section = SECTION_PRE_DATA,
   11940             :                                   .createStmt = q->data,
   11941             :                                   .dropStmt = delq->data));
   11942             : 
   11943             :     /* Dump Extension Comments and Security Labels */
   11944          36 :     if (extinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   11945          36 :         dumpComment(fout, "EXTENSION", qextname,
   11946             :                     NULL, "",
   11947          36 :                     extinfo->dobj.catId, 0, extinfo->dobj.dumpId);
   11948             : 
   11949          36 :     if (extinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
   11950           0 :         dumpSecLabel(fout, "EXTENSION", qextname,
   11951             :                      NULL, "",
   11952           0 :                      extinfo->dobj.catId, 0, extinfo->dobj.dumpId);
   11953             : 
   11954          36 :     free(qextname);
   11955             : 
   11956          36 :     destroyPQExpBuffer(q);
   11957          36 :     destroyPQExpBuffer(delq);
   11958             : }
   11959             : 
   11960             : /*
   11961             :  * dumpType
   11962             :  *    writes out to fout the queries to recreate a user-defined type
   11963             :  */
   11964             : static void
   11965        1888 : dumpType(Archive *fout, const TypeInfo *tyinfo)
   11966             : {
   11967        1888 :     DumpOptions *dopt = fout->dopt;
   11968             : 
   11969             :     /* Do nothing if not dumping schema */
   11970        1888 :     if (!dopt->dumpSchema)
   11971          98 :         return;
   11972             : 
   11973             :     /* Dump out in proper style */
   11974        1790 :     if (tyinfo->typtype == TYPTYPE_BASE)
   11975         566 :         dumpBaseType(fout, tyinfo);
   11976        1224 :     else if (tyinfo->typtype == TYPTYPE_DOMAIN)
   11977         310 :         dumpDomain(fout, tyinfo);
   11978         914 :     else if (tyinfo->typtype == TYPTYPE_COMPOSITE)
   11979         266 :         dumpCompositeType(fout, tyinfo);
   11980         648 :     else if (tyinfo->typtype == TYPTYPE_ENUM)
   11981         182 :         dumpEnumType(fout, tyinfo);
   11982         466 :     else if (tyinfo->typtype == TYPTYPE_RANGE)
   11983         236 :         dumpRangeType(fout, tyinfo);
   11984         230 :     else if (tyinfo->typtype == TYPTYPE_PSEUDO && !tyinfo->isDefined)
   11985          80 :         dumpUndefinedType(fout, tyinfo);
   11986             :     else
   11987         150 :         pg_log_warning("typtype of data type \"%s\" appears to be invalid",
   11988             :                        tyinfo->dobj.name);
   11989             : }
   11990             : 
   11991             : /*
   11992             :  * dumpEnumType
   11993             :  *    writes out to fout the queries to recreate a user-defined enum type
   11994             :  */
   11995             : static void
   11996         182 : dumpEnumType(Archive *fout, const TypeInfo *tyinfo)
   11997             : {
   11998         182 :     DumpOptions *dopt = fout->dopt;
   11999         182 :     PQExpBuffer q = createPQExpBuffer();
   12000         182 :     PQExpBuffer delq = createPQExpBuffer();
   12001         182 :     PQExpBuffer query = createPQExpBuffer();
   12002             :     PGresult   *res;
   12003             :     int         num,
   12004             :                 i;
   12005             :     Oid         enum_oid;
   12006             :     char       *qtypname;
   12007             :     char       *qualtypname;
   12008             :     char       *label;
   12009             :     int         i_enumlabel;
   12010             :     int         i_oid;
   12011             : 
   12012         182 :     if (!fout->is_prepared[PREPQUERY_DUMPENUMTYPE])
   12013             :     {
   12014             :         /* Set up query for enum-specific details */
   12015          86 :         appendPQExpBufferStr(query,
   12016             :                              "PREPARE dumpEnumType(pg_catalog.oid) AS\n"
   12017             :                              "SELECT oid, enumlabel "
   12018             :                              "FROM pg_catalog.pg_enum "
   12019             :                              "WHERE enumtypid = $1 "
   12020             :                              "ORDER BY enumsortorder");
   12021             : 
   12022          86 :         ExecuteSqlStatement(fout, query->data);
   12023             : 
   12024          86 :         fout->is_prepared[PREPQUERY_DUMPENUMTYPE] = true;
   12025             :     }
   12026             : 
   12027         182 :     printfPQExpBuffer(query,
   12028             :                       "EXECUTE dumpEnumType('%u')",
   12029         182 :                       tyinfo->dobj.catId.oid);
   12030             : 
   12031         182 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   12032             : 
   12033         182 :     num = PQntuples(res);
   12034             : 
   12035         182 :     qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
   12036         182 :     qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
   12037             : 
   12038             :     /*
   12039             :      * CASCADE shouldn't be required here as for normal types since the I/O
   12040             :      * functions are generic and do not get dropped.
   12041             :      */
   12042         182 :     appendPQExpBuffer(delq, "DROP TYPE %s;\n", qualtypname);
   12043             : 
   12044         182 :     if (dopt->binary_upgrade)
   12045          12 :         binary_upgrade_set_type_oids_by_type_oid(fout, q,
   12046          12 :                                                  tyinfo->dobj.catId.oid,
   12047             :                                                  false, false);
   12048             : 
   12049         182 :     appendPQExpBuffer(q, "CREATE TYPE %s AS ENUM (",
   12050             :                       qualtypname);
   12051             : 
   12052         182 :     if (!dopt->binary_upgrade)
   12053             :     {
   12054         170 :         i_enumlabel = PQfnumber(res, "enumlabel");
   12055             : 
   12056             :         /* Labels with server-assigned oids */
   12057        1012 :         for (i = 0; i < num; i++)
   12058             :         {
   12059         842 :             label = PQgetvalue(res, i, i_enumlabel);
   12060         842 :             if (i > 0)
   12061         672 :                 appendPQExpBufferChar(q, ',');
   12062         842 :             appendPQExpBufferStr(q, "\n    ");
   12063         842 :             appendStringLiteralAH(q, label, fout);
   12064             :         }
   12065             :     }
   12066             : 
   12067         182 :     appendPQExpBufferStr(q, "\n);\n");
   12068             : 
   12069         182 :     if (dopt->binary_upgrade)
   12070             :     {
   12071          12 :         i_oid = PQfnumber(res, "oid");
   12072          12 :         i_enumlabel = PQfnumber(res, "enumlabel");
   12073             : 
   12074             :         /* Labels with dump-assigned (preserved) oids */
   12075         124 :         for (i = 0; i < num; i++)
   12076             :         {
   12077         112 :             enum_oid = atooid(PQgetvalue(res, i, i_oid));
   12078         112 :             label = PQgetvalue(res, i, i_enumlabel);
   12079             : 
   12080         112 :             if (i == 0)
   12081          12 :                 appendPQExpBufferStr(q, "\n-- For binary upgrade, must preserve pg_enum oids\n");
   12082         112 :             appendPQExpBuffer(q,
   12083             :                               "SELECT pg_catalog.binary_upgrade_set_next_pg_enum_oid('%u'::pg_catalog.oid);\n",
   12084             :                               enum_oid);
   12085         112 :             appendPQExpBuffer(q, "ALTER TYPE %s ADD VALUE ", qualtypname);
   12086         112 :             appendStringLiteralAH(q, label, fout);
   12087         112 :             appendPQExpBufferStr(q, ";\n\n");
   12088             :         }
   12089             :     }
   12090             : 
   12091         182 :     if (dopt->binary_upgrade)
   12092          12 :         binary_upgrade_extension_member(q, &tyinfo->dobj,
   12093             :                                         "TYPE", qtypname,
   12094          12 :                                         tyinfo->dobj.namespace->dobj.name);
   12095             : 
   12096         182 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   12097         182 :         ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
   12098         182 :                      ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
   12099             :                                   .namespace = tyinfo->dobj.namespace->dobj.name,
   12100             :                                   .owner = tyinfo->rolname,
   12101             :                                   .description = "TYPE",
   12102             :                                   .section = SECTION_PRE_DATA,
   12103             :                                   .createStmt = q->data,
   12104             :                                   .dropStmt = delq->data));
   12105             : 
   12106             :     /* Dump Type Comments and Security Labels */
   12107         182 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   12108          70 :         dumpComment(fout, "TYPE", qtypname,
   12109          70 :                     tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
   12110          70 :                     tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
   12111             : 
   12112         182 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
   12113           0 :         dumpSecLabel(fout, "TYPE", qtypname,
   12114           0 :                      tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
   12115           0 :                      tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
   12116             : 
   12117         182 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
   12118          70 :         dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
   12119             :                 qtypname, NULL,
   12120          70 :                 tyinfo->dobj.namespace->dobj.name,
   12121          70 :                 NULL, tyinfo->rolname, &tyinfo->dacl);
   12122             : 
   12123         182 :     PQclear(res);
   12124         182 :     destroyPQExpBuffer(q);
   12125         182 :     destroyPQExpBuffer(delq);
   12126         182 :     destroyPQExpBuffer(query);
   12127         182 :     free(qtypname);
   12128         182 :     free(qualtypname);
   12129         182 : }
   12130             : 
   12131             : /*
   12132             :  * dumpRangeType
   12133             :  *    writes out to fout the queries to recreate a user-defined range type
   12134             :  */
   12135             : static void
   12136         236 : dumpRangeType(Archive *fout, const TypeInfo *tyinfo)
   12137             : {
   12138         236 :     DumpOptions *dopt = fout->dopt;
   12139         236 :     PQExpBuffer q = createPQExpBuffer();
   12140         236 :     PQExpBuffer delq = createPQExpBuffer();
   12141         236 :     PQExpBuffer query = createPQExpBuffer();
   12142             :     PGresult   *res;
   12143             :     Oid         collationOid;
   12144             :     char       *qtypname;
   12145             :     char       *qualtypname;
   12146             :     char       *procname;
   12147             : 
   12148         236 :     if (!fout->is_prepared[PREPQUERY_DUMPRANGETYPE])
   12149             :     {
   12150             :         /* Set up query for range-specific details */
   12151          86 :         appendPQExpBufferStr(query,
   12152             :                              "PREPARE dumpRangeType(pg_catalog.oid) AS\n");
   12153             : 
   12154          86 :         appendPQExpBufferStr(query,
   12155             :                              "SELECT ");
   12156             : 
   12157          86 :         if (fout->remoteVersion >= 140000)
   12158          86 :             appendPQExpBufferStr(query,
   12159             :                                  "pg_catalog.format_type(rngmultitypid, NULL) AS rngmultitype, ");
   12160             :         else
   12161           0 :             appendPQExpBufferStr(query,
   12162             :                                  "NULL AS rngmultitype, ");
   12163             : 
   12164          86 :         appendPQExpBufferStr(query,
   12165             :                              "pg_catalog.format_type(rngsubtype, NULL) AS rngsubtype, "
   12166             :                              "opc.opcname AS opcname, "
   12167             :                              "(SELECT nspname FROM pg_catalog.pg_namespace nsp "
   12168             :                              "  WHERE nsp.oid = opc.opcnamespace) AS opcnsp, "
   12169             :                              "opc.opcdefault, "
   12170             :                              "CASE WHEN rngcollation = st.typcollation THEN 0 "
   12171             :                              "     ELSE rngcollation END AS collation, "
   12172             :                              "rngcanonical, rngsubdiff "
   12173             :                              "FROM pg_catalog.pg_range r, pg_catalog.pg_type st, "
   12174             :                              "     pg_catalog.pg_opclass opc "
   12175             :                              "WHERE st.oid = rngsubtype AND opc.oid = rngsubopc AND "
   12176             :                              "rngtypid = $1");
   12177             : 
   12178          86 :         ExecuteSqlStatement(fout, query->data);
   12179             : 
   12180          86 :         fout->is_prepared[PREPQUERY_DUMPRANGETYPE] = true;
   12181             :     }
   12182             : 
   12183         236 :     printfPQExpBuffer(query,
   12184             :                       "EXECUTE dumpRangeType('%u')",
   12185         236 :                       tyinfo->dobj.catId.oid);
   12186             : 
   12187         236 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   12188             : 
   12189         236 :     qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
   12190         236 :     qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
   12191             : 
   12192             :     /*
   12193             :      * CASCADE shouldn't be required here as for normal types since the I/O
   12194             :      * functions are generic and do not get dropped.
   12195             :      */
   12196         236 :     appendPQExpBuffer(delq, "DROP TYPE %s;\n", qualtypname);
   12197             : 
   12198         236 :     if (dopt->binary_upgrade)
   12199          16 :         binary_upgrade_set_type_oids_by_type_oid(fout, q,
   12200          16 :                                                  tyinfo->dobj.catId.oid,
   12201             :                                                  false, true);
   12202             : 
   12203         236 :     appendPQExpBuffer(q, "CREATE TYPE %s AS RANGE (",
   12204             :                       qualtypname);
   12205             : 
   12206         236 :     appendPQExpBuffer(q, "\n    subtype = %s",
   12207             :                       PQgetvalue(res, 0, PQfnumber(res, "rngsubtype")));
   12208             : 
   12209         236 :     if (!PQgetisnull(res, 0, PQfnumber(res, "rngmultitype")))
   12210         236 :         appendPQExpBuffer(q, ",\n    multirange_type_name = %s",
   12211             :                           PQgetvalue(res, 0, PQfnumber(res, "rngmultitype")));
   12212             : 
   12213             :     /* print subtype_opclass only if not default for subtype */
   12214         236 :     if (PQgetvalue(res, 0, PQfnumber(res, "opcdefault"))[0] != 't')
   12215             :     {
   12216          70 :         char       *opcname = PQgetvalue(res, 0, PQfnumber(res, "opcname"));
   12217          70 :         char       *nspname = PQgetvalue(res, 0, PQfnumber(res, "opcnsp"));
   12218             : 
   12219          70 :         appendPQExpBuffer(q, ",\n    subtype_opclass = %s.",
   12220             :                           fmtId(nspname));
   12221          70 :         appendPQExpBufferStr(q, fmtId(opcname));
   12222             :     }
   12223             : 
   12224         236 :     collationOid = atooid(PQgetvalue(res, 0, PQfnumber(res, "collation")));
   12225         236 :     if (OidIsValid(collationOid))
   12226             :     {
   12227          80 :         CollInfo   *coll = findCollationByOid(collationOid);
   12228             : 
   12229          80 :         if (coll)
   12230          80 :             appendPQExpBuffer(q, ",\n    collation = %s",
   12231          80 :                               fmtQualifiedDumpable(coll));
   12232             :     }
   12233             : 
   12234         236 :     procname = PQgetvalue(res, 0, PQfnumber(res, "rngcanonical"));
   12235         236 :     if (strcmp(procname, "-") != 0)
   12236          18 :         appendPQExpBuffer(q, ",\n    canonical = %s", procname);
   12237             : 
   12238         236 :     procname = PQgetvalue(res, 0, PQfnumber(res, "rngsubdiff"));
   12239         236 :     if (strcmp(procname, "-") != 0)
   12240          46 :         appendPQExpBuffer(q, ",\n    subtype_diff = %s", procname);
   12241             : 
   12242         236 :     appendPQExpBufferStr(q, "\n);\n");
   12243             : 
   12244         236 :     if (dopt->binary_upgrade)
   12245          16 :         binary_upgrade_extension_member(q, &tyinfo->dobj,
   12246             :                                         "TYPE", qtypname,
   12247          16 :                                         tyinfo->dobj.namespace->dobj.name);
   12248             : 
   12249         236 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   12250         236 :         ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
   12251         236 :                      ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
   12252             :                                   .namespace = tyinfo->dobj.namespace->dobj.name,
   12253             :                                   .owner = tyinfo->rolname,
   12254             :                                   .description = "TYPE",
   12255             :                                   .section = SECTION_PRE_DATA,
   12256             :                                   .createStmt = q->data,
   12257             :                                   .dropStmt = delq->data));
   12258             : 
   12259             :     /* Dump Type Comments and Security Labels */
   12260         236 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   12261         106 :         dumpComment(fout, "TYPE", qtypname,
   12262         106 :                     tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
   12263         106 :                     tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
   12264             : 
   12265         236 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
   12266           0 :         dumpSecLabel(fout, "TYPE", qtypname,
   12267           0 :                      tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
   12268           0 :                      tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
   12269             : 
   12270         236 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
   12271          70 :         dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
   12272             :                 qtypname, NULL,
   12273          70 :                 tyinfo->dobj.namespace->dobj.name,
   12274          70 :                 NULL, tyinfo->rolname, &tyinfo->dacl);
   12275             : 
   12276         236 :     PQclear(res);
   12277         236 :     destroyPQExpBuffer(q);
   12278         236 :     destroyPQExpBuffer(delq);
   12279         236 :     destroyPQExpBuffer(query);
   12280         236 :     free(qtypname);
   12281         236 :     free(qualtypname);
   12282         236 : }
   12283             : 
   12284             : /*
   12285             :  * dumpUndefinedType
   12286             :  *    writes out to fout the queries to recreate a !typisdefined type
   12287             :  *
   12288             :  * This is a shell type, but we use different terminology to distinguish
   12289             :  * this case from where we have to emit a shell type definition to break
   12290             :  * circular dependencies.  An undefined type shouldn't ever have anything
   12291             :  * depending on it.
   12292             :  */
   12293             : static void
   12294          80 : dumpUndefinedType(Archive *fout, const TypeInfo *tyinfo)
   12295             : {
   12296          80 :     DumpOptions *dopt = fout->dopt;
   12297          80 :     PQExpBuffer q = createPQExpBuffer();
   12298          80 :     PQExpBuffer delq = createPQExpBuffer();
   12299             :     char       *qtypname;
   12300             :     char       *qualtypname;
   12301             : 
   12302          80 :     qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
   12303          80 :     qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
   12304             : 
   12305          80 :     appendPQExpBuffer(delq, "DROP TYPE %s;\n", qualtypname);
   12306             : 
   12307          80 :     if (dopt->binary_upgrade)
   12308           4 :         binary_upgrade_set_type_oids_by_type_oid(fout, q,
   12309           4 :                                                  tyinfo->dobj.catId.oid,
   12310             :                                                  false, false);
   12311             : 
   12312          80 :     appendPQExpBuffer(q, "CREATE TYPE %s;\n",
   12313             :                       qualtypname);
   12314             : 
   12315          80 :     if (dopt->binary_upgrade)
   12316           4 :         binary_upgrade_extension_member(q, &tyinfo->dobj,
   12317             :                                         "TYPE", qtypname,
   12318           4 :                                         tyinfo->dobj.namespace->dobj.name);
   12319             : 
   12320          80 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   12321          80 :         ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
   12322          80 :                      ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
   12323             :                                   .namespace = tyinfo->dobj.namespace->dobj.name,
   12324             :                                   .owner = tyinfo->rolname,
   12325             :                                   .description = "TYPE",
   12326             :                                   .section = SECTION_PRE_DATA,
   12327             :                                   .createStmt = q->data,
   12328             :                                   .dropStmt = delq->data));
   12329             : 
   12330             :     /* Dump Type Comments and Security Labels */
   12331          80 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   12332          70 :         dumpComment(fout, "TYPE", qtypname,
   12333          70 :                     tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
   12334          70 :                     tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
   12335             : 
   12336          80 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
   12337           0 :         dumpSecLabel(fout, "TYPE", qtypname,
   12338           0 :                      tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
   12339           0 :                      tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
   12340             : 
   12341          80 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
   12342           0 :         dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
   12343             :                 qtypname, NULL,
   12344           0 :                 tyinfo->dobj.namespace->dobj.name,
   12345           0 :                 NULL, tyinfo->rolname, &tyinfo->dacl);
   12346             : 
   12347          80 :     destroyPQExpBuffer(q);
   12348          80 :     destroyPQExpBuffer(delq);
   12349          80 :     free(qtypname);
   12350          80 :     free(qualtypname);
   12351          80 : }
   12352             : 
   12353             : /*
   12354             :  * dumpBaseType
   12355             :  *    writes out to fout the queries to recreate a user-defined base type
   12356             :  */
   12357             : static void
   12358         566 : dumpBaseType(Archive *fout, const TypeInfo *tyinfo)
   12359             : {
   12360         566 :     DumpOptions *dopt = fout->dopt;
   12361         566 :     PQExpBuffer q = createPQExpBuffer();
   12362         566 :     PQExpBuffer delq = createPQExpBuffer();
   12363         566 :     PQExpBuffer query = createPQExpBuffer();
   12364             :     PGresult   *res;
   12365             :     char       *qtypname;
   12366             :     char       *qualtypname;
   12367             :     char       *typlen;
   12368             :     char       *typinput;
   12369             :     char       *typoutput;
   12370             :     char       *typreceive;
   12371             :     char       *typsend;
   12372             :     char       *typmodin;
   12373             :     char       *typmodout;
   12374             :     char       *typanalyze;
   12375             :     char       *typsubscript;
   12376             :     Oid         typreceiveoid;
   12377             :     Oid         typsendoid;
   12378             :     Oid         typmodinoid;
   12379             :     Oid         typmodoutoid;
   12380             :     Oid         typanalyzeoid;
   12381             :     Oid         typsubscriptoid;
   12382             :     char       *typcategory;
   12383             :     char       *typispreferred;
   12384             :     char       *typdelim;
   12385             :     char       *typbyval;
   12386             :     char       *typalign;
   12387             :     char       *typstorage;
   12388             :     char       *typcollatable;
   12389             :     char       *typdefault;
   12390         566 :     bool        typdefault_is_literal = false;
   12391             : 
   12392         566 :     if (!fout->is_prepared[PREPQUERY_DUMPBASETYPE])
   12393             :     {
   12394             :         /* Set up query for type-specific details */
   12395          86 :         appendPQExpBufferStr(query,
   12396             :                              "PREPARE dumpBaseType(pg_catalog.oid) AS\n"
   12397             :                              "SELECT typlen, "
   12398             :                              "typinput, typoutput, typreceive, typsend, "
   12399             :                              "typreceive::pg_catalog.oid AS typreceiveoid, "
   12400             :                              "typsend::pg_catalog.oid AS typsendoid, "
   12401             :                              "typanalyze, "
   12402             :                              "typanalyze::pg_catalog.oid AS typanalyzeoid, "
   12403             :                              "typdelim, typbyval, typalign, typstorage, "
   12404             :                              "typmodin, typmodout, "
   12405             :                              "typmodin::pg_catalog.oid AS typmodinoid, "
   12406             :                              "typmodout::pg_catalog.oid AS typmodoutoid, "
   12407             :                              "typcategory, typispreferred, "
   12408             :                              "(typcollation <> 0) AS typcollatable, "
   12409             :                              "pg_catalog.pg_get_expr(typdefaultbin, 0) AS typdefaultbin, typdefault, ");
   12410             : 
   12411          86 :         if (fout->remoteVersion >= 140000)
   12412          86 :             appendPQExpBufferStr(query,
   12413             :                                  "typsubscript, "
   12414             :                                  "typsubscript::pg_catalog.oid AS typsubscriptoid ");
   12415             :         else
   12416           0 :             appendPQExpBufferStr(query,
   12417             :                                  "'-' AS typsubscript, 0 AS typsubscriptoid ");
   12418             : 
   12419          86 :         appendPQExpBufferStr(query, "FROM pg_catalog.pg_type "
   12420             :                              "WHERE oid = $1");
   12421             : 
   12422          86 :         ExecuteSqlStatement(fout, query->data);
   12423             : 
   12424          86 :         fout->is_prepared[PREPQUERY_DUMPBASETYPE] = true;
   12425             :     }
   12426             : 
   12427         566 :     printfPQExpBuffer(query,
   12428             :                       "EXECUTE dumpBaseType('%u')",
   12429         566 :                       tyinfo->dobj.catId.oid);
   12430             : 
   12431         566 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   12432             : 
   12433         566 :     typlen = PQgetvalue(res, 0, PQfnumber(res, "typlen"));
   12434         566 :     typinput = PQgetvalue(res, 0, PQfnumber(res, "typinput"));
   12435         566 :     typoutput = PQgetvalue(res, 0, PQfnumber(res, "typoutput"));
   12436         566 :     typreceive = PQgetvalue(res, 0, PQfnumber(res, "typreceive"));
   12437         566 :     typsend = PQgetvalue(res, 0, PQfnumber(res, "typsend"));
   12438         566 :     typmodin = PQgetvalue(res, 0, PQfnumber(res, "typmodin"));
   12439         566 :     typmodout = PQgetvalue(res, 0, PQfnumber(res, "typmodout"));
   12440         566 :     typanalyze = PQgetvalue(res, 0, PQfnumber(res, "typanalyze"));
   12441         566 :     typsubscript = PQgetvalue(res, 0, PQfnumber(res, "typsubscript"));
   12442         566 :     typreceiveoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typreceiveoid")));
   12443         566 :     typsendoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typsendoid")));
   12444         566 :     typmodinoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typmodinoid")));
   12445         566 :     typmodoutoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typmodoutoid")));
   12446         566 :     typanalyzeoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typanalyzeoid")));
   12447         566 :     typsubscriptoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typsubscriptoid")));
   12448         566 :     typcategory = PQgetvalue(res, 0, PQfnumber(res, "typcategory"));
   12449         566 :     typispreferred = PQgetvalue(res, 0, PQfnumber(res, "typispreferred"));
   12450         566 :     typdelim = PQgetvalue(res, 0, PQfnumber(res, "typdelim"));
   12451         566 :     typbyval = PQgetvalue(res, 0, PQfnumber(res, "typbyval"));
   12452         566 :     typalign = PQgetvalue(res, 0, PQfnumber(res, "typalign"));
   12453         566 :     typstorage = PQgetvalue(res, 0, PQfnumber(res, "typstorage"));
   12454         566 :     typcollatable = PQgetvalue(res, 0, PQfnumber(res, "typcollatable"));
   12455         566 :     if (!PQgetisnull(res, 0, PQfnumber(res, "typdefaultbin")))
   12456           0 :         typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefaultbin"));
   12457         566 :     else if (!PQgetisnull(res, 0, PQfnumber(res, "typdefault")))
   12458             :     {
   12459          90 :         typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefault"));
   12460          90 :         typdefault_is_literal = true;   /* it needs quotes */
   12461             :     }
   12462             :     else
   12463         476 :         typdefault = NULL;
   12464             : 
   12465         566 :     qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
   12466         566 :     qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
   12467             : 
   12468             :     /*
   12469             :      * The reason we include CASCADE is that the circular dependency between
   12470             :      * the type and its I/O functions makes it impossible to drop the type any
   12471             :      * other way.
   12472             :      */
   12473         566 :     appendPQExpBuffer(delq, "DROP TYPE %s CASCADE;\n", qualtypname);
   12474             : 
   12475             :     /*
   12476             :      * We might already have a shell type, but setting pg_type_oid is
   12477             :      * harmless, and in any case we'd better set the array type OID.
   12478             :      */
   12479         566 :     if (dopt->binary_upgrade)
   12480          16 :         binary_upgrade_set_type_oids_by_type_oid(fout, q,
   12481          16 :                                                  tyinfo->dobj.catId.oid,
   12482             :                                                  false, false);
   12483             : 
   12484         566 :     appendPQExpBuffer(q,
   12485             :                       "CREATE TYPE %s (\n"
   12486             :                       "    INTERNALLENGTH = %s",
   12487             :                       qualtypname,
   12488         566 :                       (strcmp(typlen, "-1") == 0) ? "variable" : typlen);
   12489             : 
   12490             :     /* regproc result is sufficiently quoted already */
   12491         566 :     appendPQExpBuffer(q, ",\n    INPUT = %s", typinput);
   12492         566 :     appendPQExpBuffer(q, ",\n    OUTPUT = %s", typoutput);
   12493         566 :     if (OidIsValid(typreceiveoid))
   12494         414 :         appendPQExpBuffer(q, ",\n    RECEIVE = %s", typreceive);
   12495         566 :     if (OidIsValid(typsendoid))
   12496         414 :         appendPQExpBuffer(q, ",\n    SEND = %s", typsend);
   12497         566 :     if (OidIsValid(typmodinoid))
   12498          70 :         appendPQExpBuffer(q, ",\n    TYPMOD_IN = %s", typmodin);
   12499         566 :     if (OidIsValid(typmodoutoid))
   12500          70 :         appendPQExpBuffer(q, ",\n    TYPMOD_OUT = %s", typmodout);
   12501         566 :     if (OidIsValid(typanalyzeoid))
   12502           6 :         appendPQExpBuffer(q, ",\n    ANALYZE = %s", typanalyze);
   12503             : 
   12504         566 :     if (strcmp(typcollatable, "t") == 0)
   12505          60 :         appendPQExpBufferStr(q, ",\n    COLLATABLE = true");
   12506             : 
   12507         566 :     if (typdefault != NULL)
   12508             :     {
   12509          90 :         appendPQExpBufferStr(q, ",\n    DEFAULT = ");
   12510          90 :         if (typdefault_is_literal)
   12511          90 :             appendStringLiteralAH(q, typdefault, fout);
   12512             :         else
   12513           0 :             appendPQExpBufferStr(q, typdefault);
   12514             :     }
   12515             : 
   12516         566 :     if (OidIsValid(typsubscriptoid))
   12517          58 :         appendPQExpBuffer(q, ",\n    SUBSCRIPT = %s", typsubscript);
   12518             : 
   12519         566 :     if (OidIsValid(tyinfo->typelem))
   12520          52 :         appendPQExpBuffer(q, ",\n    ELEMENT = %s",
   12521          52 :                           getFormattedTypeName(fout, tyinfo->typelem,
   12522             :                                                zeroIsError));
   12523             : 
   12524         566 :     if (strcmp(typcategory, "U") != 0)
   12525             :     {
   12526         316 :         appendPQExpBufferStr(q, ",\n    CATEGORY = ");
   12527         316 :         appendStringLiteralAH(q, typcategory, fout);
   12528             :     }
   12529             : 
   12530         566 :     if (strcmp(typispreferred, "t") == 0)
   12531          58 :         appendPQExpBufferStr(q, ",\n    PREFERRED = true");
   12532             : 
   12533         566 :     if (typdelim && strcmp(typdelim, ",") != 0)
   12534             :     {
   12535           6 :         appendPQExpBufferStr(q, ",\n    DELIMITER = ");
   12536           6 :         appendStringLiteralAH(q, typdelim, fout);
   12537             :     }
   12538             : 
   12539         566 :     if (*typalign == TYPALIGN_CHAR)
   12540          24 :         appendPQExpBufferStr(q, ",\n    ALIGNMENT = char");
   12541         542 :     else if (*typalign == TYPALIGN_SHORT)
   12542          12 :         appendPQExpBufferStr(q, ",\n    ALIGNMENT = int2");
   12543         530 :     else if (*typalign == TYPALIGN_INT)
   12544         380 :         appendPQExpBufferStr(q, ",\n    ALIGNMENT = int4");
   12545         150 :     else if (*typalign == TYPALIGN_DOUBLE)
   12546         150 :         appendPQExpBufferStr(q, ",\n    ALIGNMENT = double");
   12547             : 
   12548         566 :     if (*typstorage == TYPSTORAGE_PLAIN)
   12549         416 :         appendPQExpBufferStr(q, ",\n    STORAGE = plain");
   12550         150 :     else if (*typstorage == TYPSTORAGE_EXTERNAL)
   12551           0 :         appendPQExpBufferStr(q, ",\n    STORAGE = external");
   12552         150 :     else if (*typstorage == TYPSTORAGE_EXTENDED)
   12553         132 :         appendPQExpBufferStr(q, ",\n    STORAGE = extended");
   12554          18 :     else if (*typstorage == TYPSTORAGE_MAIN)
   12555          18 :         appendPQExpBufferStr(q, ",\n    STORAGE = main");
   12556             : 
   12557         566 :     if (strcmp(typbyval, "t") == 0)
   12558         274 :         appendPQExpBufferStr(q, ",\n    PASSEDBYVALUE");
   12559             : 
   12560         566 :     appendPQExpBufferStr(q, "\n);\n");
   12561             : 
   12562         566 :     if (dopt->binary_upgrade)
   12563          16 :         binary_upgrade_extension_member(q, &tyinfo->dobj,
   12564             :                                         "TYPE", qtypname,
   12565          16 :                                         tyinfo->dobj.namespace->dobj.name);
   12566             : 
   12567         566 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   12568         566 :         ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
   12569         566 :                      ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
   12570             :                                   .namespace = tyinfo->dobj.namespace->dobj.name,
   12571             :                                   .owner = tyinfo->rolname,
   12572             :                                   .description = "TYPE",
   12573             :                                   .section = SECTION_PRE_DATA,
   12574             :                                   .createStmt = q->data,
   12575             :                                   .dropStmt = delq->data));
   12576             : 
   12577             :     /* Dump Type Comments and Security Labels */
   12578         566 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   12579         496 :         dumpComment(fout, "TYPE", qtypname,
   12580         496 :                     tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
   12581         496 :                     tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
   12582             : 
   12583         566 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
   12584           0 :         dumpSecLabel(fout, "TYPE", qtypname,
   12585           0 :                      tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
   12586           0 :                      tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
   12587             : 
   12588         566 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
   12589          70 :         dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
   12590             :                 qtypname, NULL,
   12591          70 :                 tyinfo->dobj.namespace->dobj.name,
   12592          70 :                 NULL, tyinfo->rolname, &tyinfo->dacl);
   12593             : 
   12594         566 :     PQclear(res);
   12595         566 :     destroyPQExpBuffer(q);
   12596         566 :     destroyPQExpBuffer(delq);
   12597         566 :     destroyPQExpBuffer(query);
   12598         566 :     free(qtypname);
   12599         566 :     free(qualtypname);
   12600         566 : }
   12601             : 
   12602             : /*
   12603             :  * dumpDomain
   12604             :  *    writes out to fout the queries to recreate a user-defined domain
   12605             :  */
   12606             : static void
   12607         310 : dumpDomain(Archive *fout, const TypeInfo *tyinfo)
   12608             : {
   12609         310 :     DumpOptions *dopt = fout->dopt;
   12610         310 :     PQExpBuffer q = createPQExpBuffer();
   12611         310 :     PQExpBuffer delq = createPQExpBuffer();
   12612         310 :     PQExpBuffer query = createPQExpBuffer();
   12613             :     PGresult   *res;
   12614             :     int         i;
   12615             :     char       *qtypname;
   12616             :     char       *qualtypname;
   12617             :     char       *typnotnull;
   12618             :     char       *typdefn;
   12619             :     char       *typdefault;
   12620             :     Oid         typcollation;
   12621         310 :     bool        typdefault_is_literal = false;
   12622             : 
   12623         310 :     if (!fout->is_prepared[PREPQUERY_DUMPDOMAIN])
   12624             :     {
   12625             :         /* Set up query for domain-specific details */
   12626          80 :         appendPQExpBufferStr(query,
   12627             :                              "PREPARE dumpDomain(pg_catalog.oid) AS\n");
   12628             : 
   12629          80 :         appendPQExpBufferStr(query, "SELECT t.typnotnull, "
   12630             :                              "pg_catalog.format_type(t.typbasetype, t.typtypmod) AS typdefn, "
   12631             :                              "pg_catalog.pg_get_expr(t.typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, "
   12632             :                              "t.typdefault, "
   12633             :                              "CASE WHEN t.typcollation <> u.typcollation "
   12634             :                              "THEN t.typcollation ELSE 0 END AS typcollation "
   12635             :                              "FROM pg_catalog.pg_type t "
   12636             :                              "LEFT JOIN pg_catalog.pg_type u ON (t.typbasetype = u.oid) "
   12637             :                              "WHERE t.oid = $1");
   12638             : 
   12639          80 :         ExecuteSqlStatement(fout, query->data);
   12640             : 
   12641          80 :         fout->is_prepared[PREPQUERY_DUMPDOMAIN] = true;
   12642             :     }
   12643             : 
   12644         310 :     printfPQExpBuffer(query,
   12645             :                       "EXECUTE dumpDomain('%u')",
   12646         310 :                       tyinfo->dobj.catId.oid);
   12647             : 
   12648         310 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   12649             : 
   12650         310 :     typnotnull = PQgetvalue(res, 0, PQfnumber(res, "typnotnull"));
   12651         310 :     typdefn = PQgetvalue(res, 0, PQfnumber(res, "typdefn"));
   12652         310 :     if (!PQgetisnull(res, 0, PQfnumber(res, "typdefaultbin")))
   12653          80 :         typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefaultbin"));
   12654         230 :     else if (!PQgetisnull(res, 0, PQfnumber(res, "typdefault")))
   12655             :     {
   12656           0 :         typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefault"));
   12657           0 :         typdefault_is_literal = true;   /* it needs quotes */
   12658             :     }
   12659             :     else
   12660         230 :         typdefault = NULL;
   12661         310 :     typcollation = atooid(PQgetvalue(res, 0, PQfnumber(res, "typcollation")));
   12662             : 
   12663         310 :     if (dopt->binary_upgrade)
   12664          50 :         binary_upgrade_set_type_oids_by_type_oid(fout, q,
   12665          50 :                                                  tyinfo->dobj.catId.oid,
   12666             :                                                  true,  /* force array type */
   12667             :                                                  false);    /* force multirange type */
   12668             : 
   12669         310 :     qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
   12670         310 :     qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
   12671             : 
   12672         310 :     appendPQExpBuffer(q,
   12673             :                       "CREATE DOMAIN %s AS %s",
   12674             :                       qualtypname,
   12675             :                       typdefn);
   12676             : 
   12677             :     /* Print collation only if different from base type's collation */
   12678         310 :     if (OidIsValid(typcollation))
   12679             :     {
   12680             :         CollInfo   *coll;
   12681             : 
   12682          70 :         coll = findCollationByOid(typcollation);
   12683          70 :         if (coll)
   12684          70 :             appendPQExpBuffer(q, " COLLATE %s", fmtQualifiedDumpable(coll));
   12685             :     }
   12686             : 
   12687             :     /*
   12688             :      * Print a not-null constraint if there's one.  In servers older than 17
   12689             :      * these don't have names, so just print it unadorned; in newer ones they
   12690             :      * do, but most of the time it's going to be the standard generated one,
   12691             :      * so omit the name in that case also.
   12692             :      */
   12693         310 :     if (typnotnull[0] == 't')
   12694             :     {
   12695         100 :         if (fout->remoteVersion < 170000 || tyinfo->notnull == NULL)
   12696           0 :             appendPQExpBufferStr(q, " NOT NULL");
   12697             :         else
   12698             :         {
   12699         100 :             ConstraintInfo *notnull = tyinfo->notnull;
   12700             : 
   12701         100 :             if (!notnull->separate)
   12702             :             {
   12703             :                 char       *default_name;
   12704             : 
   12705             :                 /* XXX should match ChooseConstraintName better */
   12706         100 :                 default_name = psprintf("%s_not_null", tyinfo->dobj.name);
   12707             : 
   12708         100 :                 if (strcmp(default_name, notnull->dobj.name) == 0)
   12709          30 :                     appendPQExpBufferStr(q, " NOT NULL");
   12710             :                 else
   12711          70 :                     appendPQExpBuffer(q, " CONSTRAINT %s %s",
   12712          70 :                                       fmtId(notnull->dobj.name), notnull->condef);
   12713         100 :                 free(default_name);
   12714             :             }
   12715             :         }
   12716             :     }
   12717             : 
   12718         310 :     if (typdefault != NULL)
   12719             :     {
   12720          80 :         appendPQExpBufferStr(q, " DEFAULT ");
   12721          80 :         if (typdefault_is_literal)
   12722           0 :             appendStringLiteralAH(q, typdefault, fout);
   12723             :         else
   12724          80 :             appendPQExpBufferStr(q, typdefault);
   12725             :     }
   12726             : 
   12727         310 :     PQclear(res);
   12728             : 
   12729             :     /*
   12730             :      * Add any CHECK constraints for the domain
   12731             :      */
   12732         530 :     for (i = 0; i < tyinfo->nDomChecks; i++)
   12733             :     {
   12734         220 :         ConstraintInfo *domcheck = &(tyinfo->domChecks[i]);
   12735             : 
   12736         220 :         if (!domcheck->separate && domcheck->contype == 'c')
   12737         210 :             appendPQExpBuffer(q, "\n\tCONSTRAINT %s %s",
   12738         210 :                               fmtId(domcheck->dobj.name), domcheck->condef);
   12739             :     }
   12740             : 
   12741         310 :     appendPQExpBufferStr(q, ";\n");
   12742             : 
   12743         310 :     appendPQExpBuffer(delq, "DROP DOMAIN %s;\n", qualtypname);
   12744             : 
   12745         310 :     if (dopt->binary_upgrade)
   12746          50 :         binary_upgrade_extension_member(q, &tyinfo->dobj,
   12747             :                                         "DOMAIN", qtypname,
   12748          50 :                                         tyinfo->dobj.namespace->dobj.name);
   12749             : 
   12750         310 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   12751         310 :         ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
   12752         310 :                      ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
   12753             :                                   .namespace = tyinfo->dobj.namespace->dobj.name,
   12754             :                                   .owner = tyinfo->rolname,
   12755             :                                   .description = "DOMAIN",
   12756             :                                   .section = SECTION_PRE_DATA,
   12757             :                                   .createStmt = q->data,
   12758             :                                   .dropStmt = delq->data));
   12759             : 
   12760             :     /* Dump Domain Comments and Security Labels */
   12761         310 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   12762           0 :         dumpComment(fout, "DOMAIN", qtypname,
   12763           0 :                     tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
   12764           0 :                     tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
   12765             : 
   12766         310 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
   12767           0 :         dumpSecLabel(fout, "DOMAIN", qtypname,
   12768           0 :                      tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
   12769           0 :                      tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
   12770             : 
   12771         310 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
   12772          70 :         dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
   12773             :                 qtypname, NULL,
   12774          70 :                 tyinfo->dobj.namespace->dobj.name,
   12775          70 :                 NULL, tyinfo->rolname, &tyinfo->dacl);
   12776             : 
   12777             :     /* Dump any per-constraint comments */
   12778         530 :     for (i = 0; i < tyinfo->nDomChecks; i++)
   12779             :     {
   12780         220 :         ConstraintInfo *domcheck = &(tyinfo->domChecks[i]);
   12781             :         PQExpBuffer conprefix;
   12782             : 
   12783             :         /* but only if the constraint itself was dumped here */
   12784         220 :         if (domcheck->separate)
   12785          10 :             continue;
   12786             : 
   12787         210 :         conprefix = createPQExpBuffer();
   12788         210 :         appendPQExpBuffer(conprefix, "CONSTRAINT %s ON DOMAIN",
   12789         210 :                           fmtId(domcheck->dobj.name));
   12790             : 
   12791         210 :         if (domcheck->dobj.dump & DUMP_COMPONENT_COMMENT)
   12792          70 :             dumpComment(fout, conprefix->data, qtypname,
   12793          70 :                         tyinfo->dobj.namespace->dobj.name,
   12794          70 :                         tyinfo->rolname,
   12795          70 :                         domcheck->dobj.catId, 0, tyinfo->dobj.dumpId);
   12796             : 
   12797         210 :         destroyPQExpBuffer(conprefix);
   12798             :     }
   12799             : 
   12800             :     /*
   12801             :      * And a comment on the not-null constraint, if there's one -- but only if
   12802             :      * the constraint itself was dumped here
   12803             :      */
   12804         310 :     if (tyinfo->notnull != NULL && !tyinfo->notnull->separate)
   12805             :     {
   12806         100 :         PQExpBuffer conprefix = createPQExpBuffer();
   12807             : 
   12808         100 :         appendPQExpBuffer(conprefix, "CONSTRAINT %s ON DOMAIN",
   12809         100 :                           fmtId(tyinfo->notnull->dobj.name));
   12810             : 
   12811         100 :         if (tyinfo->notnull->dobj.dump & DUMP_COMPONENT_COMMENT)
   12812          70 :             dumpComment(fout, conprefix->data, qtypname,
   12813          70 :                         tyinfo->dobj.namespace->dobj.name,
   12814          70 :                         tyinfo->rolname,
   12815          70 :                         tyinfo->notnull->dobj.catId, 0, tyinfo->dobj.dumpId);
   12816         100 :         destroyPQExpBuffer(conprefix);
   12817             :     }
   12818             : 
   12819         310 :     destroyPQExpBuffer(q);
   12820         310 :     destroyPQExpBuffer(delq);
   12821         310 :     destroyPQExpBuffer(query);
   12822         310 :     free(qtypname);
   12823         310 :     free(qualtypname);
   12824         310 : }
   12825             : 
   12826             : /*
   12827             :  * dumpCompositeType
   12828             :  *    writes out to fout the queries to recreate a user-defined stand-alone
   12829             :  *    composite type
   12830             :  */
   12831             : static void
   12832         266 : dumpCompositeType(Archive *fout, const TypeInfo *tyinfo)
   12833             : {
   12834         266 :     DumpOptions *dopt = fout->dopt;
   12835         266 :     PQExpBuffer q = createPQExpBuffer();
   12836         266 :     PQExpBuffer dropped = createPQExpBuffer();
   12837         266 :     PQExpBuffer delq = createPQExpBuffer();
   12838         266 :     PQExpBuffer query = createPQExpBuffer();
   12839             :     PGresult   *res;
   12840             :     char       *qtypname;
   12841             :     char       *qualtypname;
   12842             :     int         ntups;
   12843             :     int         i_attname;
   12844             :     int         i_atttypdefn;
   12845             :     int         i_attlen;
   12846             :     int         i_attalign;
   12847             :     int         i_attisdropped;
   12848             :     int         i_attcollation;
   12849             :     int         i;
   12850             :     int         actual_atts;
   12851             : 
   12852         266 :     if (!fout->is_prepared[PREPQUERY_DUMPCOMPOSITETYPE])
   12853             :     {
   12854             :         /*
   12855             :          * Set up query for type-specific details.
   12856             :          *
   12857             :          * Since we only want to dump COLLATE clauses for attributes whose
   12858             :          * collation is different from their type's default, we use a CASE
   12859             :          * here to suppress uninteresting attcollations cheaply.  atttypid
   12860             :          * will be 0 for dropped columns; collation does not matter for those.
   12861             :          */
   12862         116 :         appendPQExpBufferStr(query,
   12863             :                              "PREPARE dumpCompositeType(pg_catalog.oid) AS\n"
   12864             :                              "SELECT a.attname, a.attnum, "
   12865             :                              "pg_catalog.format_type(a.atttypid, a.atttypmod) AS atttypdefn, "
   12866             :                              "a.attlen, a.attalign, a.attisdropped, "
   12867             :                              "CASE WHEN a.attcollation <> at.typcollation "
   12868             :                              "THEN a.attcollation ELSE 0 END AS attcollation "
   12869             :                              "FROM pg_catalog.pg_type ct "
   12870             :                              "JOIN pg_catalog.pg_attribute a ON a.attrelid = ct.typrelid "
   12871             :                              "LEFT JOIN pg_catalog.pg_type at ON at.oid = a.atttypid "
   12872             :                              "WHERE ct.oid = $1 "
   12873             :                              "ORDER BY a.attnum");
   12874             : 
   12875         116 :         ExecuteSqlStatement(fout, query->data);
   12876             : 
   12877         116 :         fout->is_prepared[PREPQUERY_DUMPCOMPOSITETYPE] = true;
   12878             :     }
   12879             : 
   12880         266 :     printfPQExpBuffer(query,
   12881             :                       "EXECUTE dumpCompositeType('%u')",
   12882         266 :                       tyinfo->dobj.catId.oid);
   12883             : 
   12884         266 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   12885             : 
   12886         266 :     ntups = PQntuples(res);
   12887             : 
   12888         266 :     i_attname = PQfnumber(res, "attname");
   12889         266 :     i_atttypdefn = PQfnumber(res, "atttypdefn");
   12890         266 :     i_attlen = PQfnumber(res, "attlen");
   12891         266 :     i_attalign = PQfnumber(res, "attalign");
   12892         266 :     i_attisdropped = PQfnumber(res, "attisdropped");
   12893         266 :     i_attcollation = PQfnumber(res, "attcollation");
   12894             : 
   12895         266 :     if (dopt->binary_upgrade)
   12896             :     {
   12897          36 :         binary_upgrade_set_type_oids_by_type_oid(fout, q,
   12898          36 :                                                  tyinfo->dobj.catId.oid,
   12899             :                                                  false, false);
   12900          36 :         binary_upgrade_set_pg_class_oids(fout, q, tyinfo->typrelid);
   12901             :     }
   12902             : 
   12903         266 :     qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
   12904         266 :     qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
   12905             : 
   12906         266 :     appendPQExpBuffer(q, "CREATE TYPE %s AS (",
   12907             :                       qualtypname);
   12908             : 
   12909         266 :     actual_atts = 0;
   12910         842 :     for (i = 0; i < ntups; i++)
   12911             :     {
   12912             :         char       *attname;
   12913             :         char       *atttypdefn;
   12914             :         char       *attlen;
   12915             :         char       *attalign;
   12916             :         bool        attisdropped;
   12917             :         Oid         attcollation;
   12918             : 
   12919         576 :         attname = PQgetvalue(res, i, i_attname);
   12920         576 :         atttypdefn = PQgetvalue(res, i, i_atttypdefn);
   12921         576 :         attlen = PQgetvalue(res, i, i_attlen);
   12922         576 :         attalign = PQgetvalue(res, i, i_attalign);
   12923         576 :         attisdropped = (PQgetvalue(res, i, i_attisdropped)[0] == 't');
   12924         576 :         attcollation = atooid(PQgetvalue(res, i, i_attcollation));
   12925             : 
   12926         576 :         if (attisdropped && !dopt->binary_upgrade)
   12927          16 :             continue;
   12928             : 
   12929             :         /* Format properly if not first attr */
   12930         560 :         if (actual_atts++ > 0)
   12931         294 :             appendPQExpBufferChar(q, ',');
   12932         560 :         appendPQExpBufferStr(q, "\n\t");
   12933             : 
   12934         560 :         if (!attisdropped)
   12935             :         {
   12936         556 :             appendPQExpBuffer(q, "%s %s", fmtId(attname), atttypdefn);
   12937             : 
   12938             :             /* Add collation if not default for the column type */
   12939         556 :             if (OidIsValid(attcollation))
   12940             :             {
   12941             :                 CollInfo   *coll;
   12942             : 
   12943           0 :                 coll = findCollationByOid(attcollation);
   12944           0 :                 if (coll)
   12945           0 :                     appendPQExpBuffer(q, " COLLATE %s",
   12946           0 :                                       fmtQualifiedDumpable(coll));
   12947             :             }
   12948             :         }
   12949             :         else
   12950             :         {
   12951             :             /*
   12952             :              * This is a dropped attribute and we're in binary_upgrade mode.
   12953             :              * Insert a placeholder for it in the CREATE TYPE command, and set
   12954             :              * length and alignment with direct UPDATE to the catalogs
   12955             :              * afterwards. See similar code in dumpTableSchema().
   12956             :              */
   12957           4 :             appendPQExpBuffer(q, "%s INTEGER /* dummy */", fmtId(attname));
   12958             : 
   12959             :             /* stash separately for insertion after the CREATE TYPE */
   12960           4 :             appendPQExpBufferStr(dropped,
   12961             :                                  "\n-- For binary upgrade, recreate dropped column.\n");
   12962           4 :             appendPQExpBuffer(dropped, "UPDATE pg_catalog.pg_attribute\n"
   12963             :                               "SET attlen = %s, "
   12964             :                               "attalign = '%s', attbyval = false\n"
   12965             :                               "WHERE attname = ", attlen, attalign);
   12966           4 :             appendStringLiteralAH(dropped, attname, fout);
   12967           4 :             appendPQExpBufferStr(dropped, "\n  AND attrelid = ");
   12968           4 :             appendStringLiteralAH(dropped, qualtypname, fout);
   12969           4 :             appendPQExpBufferStr(dropped, "::pg_catalog.regclass;\n");
   12970             : 
   12971           4 :             appendPQExpBuffer(dropped, "ALTER TYPE %s ",
   12972             :                               qualtypname);
   12973           4 :             appendPQExpBuffer(dropped, "DROP ATTRIBUTE %s;\n",
   12974             :                               fmtId(attname));
   12975             :         }
   12976             :     }
   12977         266 :     appendPQExpBufferStr(q, "\n);\n");
   12978         266 :     appendPQExpBufferStr(q, dropped->data);
   12979             : 
   12980         266 :     appendPQExpBuffer(delq, "DROP TYPE %s;\n", qualtypname);
   12981             : 
   12982         266 :     if (dopt->binary_upgrade)
   12983          36 :         binary_upgrade_extension_member(q, &tyinfo->dobj,
   12984             :                                         "TYPE", qtypname,
   12985          36 :                                         tyinfo->dobj.namespace->dobj.name);
   12986             : 
   12987         266 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   12988         232 :         ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
   12989         232 :                      ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
   12990             :                                   .namespace = tyinfo->dobj.namespace->dobj.name,
   12991             :                                   .owner = tyinfo->rolname,
   12992             :                                   .description = "TYPE",
   12993             :                                   .section = SECTION_PRE_DATA,
   12994             :                                   .createStmt = q->data,
   12995             :                                   .dropStmt = delq->data));
   12996             : 
   12997             : 
   12998             :     /* Dump Type Comments and Security Labels */
   12999         266 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   13000          70 :         dumpComment(fout, "TYPE", qtypname,
   13001          70 :                     tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
   13002          70 :                     tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
   13003             : 
   13004         266 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
   13005           0 :         dumpSecLabel(fout, "TYPE", qtypname,
   13006           0 :                      tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
   13007           0 :                      tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
   13008             : 
   13009         266 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
   13010          36 :         dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
   13011             :                 qtypname, NULL,
   13012          36 :                 tyinfo->dobj.namespace->dobj.name,
   13013          36 :                 NULL, tyinfo->rolname, &tyinfo->dacl);
   13014             : 
   13015             :     /* Dump any per-column comments */
   13016         266 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   13017          70 :         dumpCompositeTypeColComments(fout, tyinfo, res);
   13018             : 
   13019         266 :     PQclear(res);
   13020         266 :     destroyPQExpBuffer(q);
   13021         266 :     destroyPQExpBuffer(dropped);
   13022         266 :     destroyPQExpBuffer(delq);
   13023         266 :     destroyPQExpBuffer(query);
   13024         266 :     free(qtypname);
   13025         266 :     free(qualtypname);
   13026         266 : }
   13027             : 
   13028             : /*
   13029             :  * dumpCompositeTypeColComments
   13030             :  *    writes out to fout the queries to recreate comments on the columns of
   13031             :  *    a user-defined stand-alone composite type.
   13032             :  *
   13033             :  * The caller has already made a query to collect the names and attnums
   13034             :  * of the type's columns, so we just pass that result into here rather
   13035             :  * than reading them again.
   13036             :  */
   13037             : static void
   13038          70 : dumpCompositeTypeColComments(Archive *fout, const TypeInfo *tyinfo,
   13039             :                              PGresult *res)
   13040             : {
   13041             :     CommentItem *comments;
   13042             :     int         ncomments;
   13043             :     PQExpBuffer query;
   13044             :     PQExpBuffer target;
   13045             :     int         i;
   13046             :     int         ntups;
   13047             :     int         i_attname;
   13048             :     int         i_attnum;
   13049             :     int         i_attisdropped;
   13050             : 
   13051             :     /* do nothing, if --no-comments is supplied */
   13052          70 :     if (fout->dopt->no_comments)
   13053           0 :         return;
   13054             : 
   13055             :     /* Search for comments associated with type's pg_class OID */
   13056          70 :     ncomments = findComments(RelationRelationId, tyinfo->typrelid,
   13057             :                              &comments);
   13058             : 
   13059             :     /* If no comments exist, we're done */
   13060          70 :     if (ncomments <= 0)
   13061           0 :         return;
   13062             : 
   13063             :     /* Build COMMENT ON statements */
   13064          70 :     query = createPQExpBuffer();
   13065          70 :     target = createPQExpBuffer();
   13066             : 
   13067          70 :     ntups = PQntuples(res);
   13068          70 :     i_attnum = PQfnumber(res, "attnum");
   13069          70 :     i_attname = PQfnumber(res, "attname");
   13070          70 :     i_attisdropped = PQfnumber(res, "attisdropped");
   13071         140 :     while (ncomments > 0)
   13072             :     {
   13073             :         const char *attname;
   13074             : 
   13075          70 :         attname = NULL;
   13076          70 :         for (i = 0; i < ntups; i++)
   13077             :         {
   13078          70 :             if (atoi(PQgetvalue(res, i, i_attnum)) == comments->objsubid &&
   13079          70 :                 PQgetvalue(res, i, i_attisdropped)[0] != 't')
   13080             :             {
   13081          70 :                 attname = PQgetvalue(res, i, i_attname);
   13082          70 :                 break;
   13083             :             }
   13084             :         }
   13085          70 :         if (attname)            /* just in case we don't find it */
   13086             :         {
   13087          70 :             const char *descr = comments->descr;
   13088             : 
   13089          70 :             resetPQExpBuffer(target);
   13090          70 :             appendPQExpBuffer(target, "COLUMN %s.",
   13091          70 :                               fmtId(tyinfo->dobj.name));
   13092          70 :             appendPQExpBufferStr(target, fmtId(attname));
   13093             : 
   13094          70 :             resetPQExpBuffer(query);
   13095          70 :             appendPQExpBuffer(query, "COMMENT ON COLUMN %s.",
   13096          70 :                               fmtQualifiedDumpable(tyinfo));
   13097          70 :             appendPQExpBuffer(query, "%s IS ", fmtId(attname));
   13098          70 :             appendStringLiteralAH(query, descr, fout);
   13099          70 :             appendPQExpBufferStr(query, ";\n");
   13100             : 
   13101          70 :             ArchiveEntry(fout, nilCatalogId, createDumpId(),
   13102          70 :                          ARCHIVE_OPTS(.tag = target->data,
   13103             :                                       .namespace = tyinfo->dobj.namespace->dobj.name,
   13104             :                                       .owner = tyinfo->rolname,
   13105             :                                       .description = "COMMENT",
   13106             :                                       .section = SECTION_NONE,
   13107             :                                       .createStmt = query->data,
   13108             :                                       .deps = &(tyinfo->dobj.dumpId),
   13109             :                                       .nDeps = 1));
   13110             :         }
   13111             : 
   13112          70 :         comments++;
   13113          70 :         ncomments--;
   13114             :     }
   13115             : 
   13116          70 :     destroyPQExpBuffer(query);
   13117          70 :     destroyPQExpBuffer(target);
   13118             : }
   13119             : 
   13120             : /*
   13121             :  * dumpShellType
   13122             :  *    writes out to fout the queries to create a shell type
   13123             :  *
   13124             :  * We dump a shell definition in advance of the I/O functions for the type.
   13125             :  */
   13126             : static void
   13127         152 : dumpShellType(Archive *fout, const ShellTypeInfo *stinfo)
   13128             : {
   13129         152 :     DumpOptions *dopt = fout->dopt;
   13130             :     PQExpBuffer q;
   13131             : 
   13132             :     /* Do nothing if not dumping schema */
   13133         152 :     if (!dopt->dumpSchema)
   13134          12 :         return;
   13135             : 
   13136         140 :     q = createPQExpBuffer();
   13137             : 
   13138             :     /*
   13139             :      * Note the lack of a DROP command for the shell type; any required DROP
   13140             :      * is driven off the base type entry, instead.  This interacts with
   13141             :      * _printTocEntry()'s use of the presence of a DROP command to decide
   13142             :      * whether an entry needs an ALTER OWNER command.  We don't want to alter
   13143             :      * the shell type's owner immediately on creation; that should happen only
   13144             :      * after it's filled in, otherwise the backend complains.
   13145             :      */
   13146             : 
   13147         140 :     if (dopt->binary_upgrade)
   13148          16 :         binary_upgrade_set_type_oids_by_type_oid(fout, q,
   13149          16 :                                                  stinfo->baseType->dobj.catId.oid,
   13150             :                                                  false, false);
   13151             : 
   13152         140 :     appendPQExpBuffer(q, "CREATE TYPE %s;\n",
   13153         140 :                       fmtQualifiedDumpable(stinfo));
   13154             : 
   13155         140 :     if (stinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   13156         140 :         ArchiveEntry(fout, stinfo->dobj.catId, stinfo->dobj.dumpId,
   13157         140 :                      ARCHIVE_OPTS(.tag = stinfo->dobj.name,
   13158             :                                   .namespace = stinfo->dobj.namespace->dobj.name,
   13159             :                                   .owner = stinfo->baseType->rolname,
   13160             :                                   .description = "SHELL TYPE",
   13161             :                                   .section = SECTION_PRE_DATA,
   13162             :                                   .createStmt = q->data));
   13163             : 
   13164         140 :     destroyPQExpBuffer(q);
   13165             : }
   13166             : 
   13167             : /*
   13168             :  * dumpProcLang
   13169             :  *        writes out to fout the queries to recreate a user-defined
   13170             :  *        procedural language
   13171             :  */
   13172             : static void
   13173         176 : dumpProcLang(Archive *fout, const ProcLangInfo *plang)
   13174             : {
   13175         176 :     DumpOptions *dopt = fout->dopt;
   13176             :     PQExpBuffer defqry;
   13177             :     PQExpBuffer delqry;
   13178             :     bool        useParams;
   13179             :     char       *qlanname;
   13180             :     FuncInfo   *funcInfo;
   13181         176 :     FuncInfo   *inlineInfo = NULL;
   13182         176 :     FuncInfo   *validatorInfo = NULL;
   13183             : 
   13184             :     /* Do nothing if not dumping schema */
   13185         176 :     if (!dopt->dumpSchema)
   13186          26 :         return;
   13187             : 
   13188             :     /*
   13189             :      * Try to find the support function(s).  It is not an error if we don't
   13190             :      * find them --- if the functions are in the pg_catalog schema, as is
   13191             :      * standard in 8.1 and up, then we won't have loaded them. (In this case
   13192             :      * we will emit a parameterless CREATE LANGUAGE command, which will
   13193             :      * require PL template knowledge in the backend to reload.)
   13194             :      */
   13195             : 
   13196         150 :     funcInfo = findFuncByOid(plang->lanplcallfoid);
   13197         150 :     if (funcInfo != NULL && !funcInfo->dobj.dump)
   13198           4 :         funcInfo = NULL;        /* treat not-dumped same as not-found */
   13199             : 
   13200         150 :     if (OidIsValid(plang->laninline))
   13201             :     {
   13202          82 :         inlineInfo = findFuncByOid(plang->laninline);
   13203          82 :         if (inlineInfo != NULL && !inlineInfo->dobj.dump)
   13204           2 :             inlineInfo = NULL;
   13205             :     }
   13206             : 
   13207         150 :     if (OidIsValid(plang->lanvalidator))
   13208             :     {
   13209          82 :         validatorInfo = findFuncByOid(plang->lanvalidator);
   13210          82 :         if (validatorInfo != NULL && !validatorInfo->dobj.dump)
   13211           2 :             validatorInfo = NULL;
   13212             :     }
   13213             : 
   13214             :     /*
   13215             :      * If the functions are dumpable then emit a complete CREATE LANGUAGE with
   13216             :      * parameters.  Otherwise, we'll write a parameterless command, which will
   13217             :      * be interpreted as CREATE EXTENSION.
   13218             :      */
   13219          66 :     useParams = (funcInfo != NULL &&
   13220         282 :                  (inlineInfo != NULL || !OidIsValid(plang->laninline)) &&
   13221          66 :                  (validatorInfo != NULL || !OidIsValid(plang->lanvalidator)));
   13222             : 
   13223         150 :     defqry = createPQExpBuffer();
   13224         150 :     delqry = createPQExpBuffer();
   13225             : 
   13226         150 :     qlanname = pg_strdup(fmtId(plang->dobj.name));
   13227             : 
   13228         150 :     appendPQExpBuffer(delqry, "DROP PROCEDURAL LANGUAGE %s;\n",
   13229             :                       qlanname);
   13230             : 
   13231         150 :     if (useParams)
   13232             :     {
   13233          66 :         appendPQExpBuffer(defqry, "CREATE %sPROCEDURAL LANGUAGE %s",
   13234          66 :                           plang->lanpltrusted ? "TRUSTED " : "",
   13235             :                           qlanname);
   13236          66 :         appendPQExpBuffer(defqry, " HANDLER %s",
   13237          66 :                           fmtQualifiedDumpable(funcInfo));
   13238          66 :         if (OidIsValid(plang->laninline))
   13239           0 :             appendPQExpBuffer(defqry, " INLINE %s",
   13240           0 :                               fmtQualifiedDumpable(inlineInfo));
   13241          66 :         if (OidIsValid(plang->lanvalidator))
   13242           0 :             appendPQExpBuffer(defqry, " VALIDATOR %s",
   13243           0 :                               fmtQualifiedDumpable(validatorInfo));
   13244             :     }
   13245             :     else
   13246             :     {
   13247             :         /*
   13248             :          * If not dumping parameters, then use CREATE OR REPLACE so that the
   13249             :          * command will not fail if the language is preinstalled in the target
   13250             :          * database.
   13251             :          *
   13252             :          * Modern servers will interpret this as CREATE EXTENSION IF NOT
   13253             :          * EXISTS; perhaps we should emit that instead?  But it might just add
   13254             :          * confusion.
   13255             :          */
   13256          84 :         appendPQExpBuffer(defqry, "CREATE OR REPLACE PROCEDURAL LANGUAGE %s",
   13257             :                           qlanname);
   13258             :     }
   13259         150 :     appendPQExpBufferStr(defqry, ";\n");
   13260             : 
   13261         150 :     if (dopt->binary_upgrade)
   13262           4 :         binary_upgrade_extension_member(defqry, &plang->dobj,
   13263             :                                         "LANGUAGE", qlanname, NULL);
   13264             : 
   13265         150 :     if (plang->dobj.dump & DUMP_COMPONENT_DEFINITION)
   13266          68 :         ArchiveEntry(fout, plang->dobj.catId, plang->dobj.dumpId,
   13267          68 :                      ARCHIVE_OPTS(.tag = plang->dobj.name,
   13268             :                                   .owner = plang->lanowner,
   13269             :                                   .description = "PROCEDURAL LANGUAGE",
   13270             :                                   .section = SECTION_PRE_DATA,
   13271             :                                   .createStmt = defqry->data,
   13272             :                                   .dropStmt = delqry->data,
   13273             :                                   ));
   13274             : 
   13275             :     /* Dump Proc Lang Comments and Security Labels */
   13276         150 :     if (plang->dobj.dump & DUMP_COMPONENT_COMMENT)
   13277           0 :         dumpComment(fout, "LANGUAGE", qlanname,
   13278           0 :                     NULL, plang->lanowner,
   13279           0 :                     plang->dobj.catId, 0, plang->dobj.dumpId);
   13280             : 
   13281         150 :     if (plang->dobj.dump & DUMP_COMPONENT_SECLABEL)
   13282           0 :         dumpSecLabel(fout, "LANGUAGE", qlanname,
   13283           0 :                      NULL, plang->lanowner,
   13284           0 :                      plang->dobj.catId, 0, plang->dobj.dumpId);
   13285             : 
   13286         150 :     if (plang->lanpltrusted && plang->dobj.dump & DUMP_COMPONENT_ACL)
   13287          82 :         dumpACL(fout, plang->dobj.dumpId, InvalidDumpId, "LANGUAGE",
   13288             :                 qlanname, NULL, NULL,
   13289          82 :                 NULL, plang->lanowner, &plang->dacl);
   13290             : 
   13291         150 :     free(qlanname);
   13292             : 
   13293         150 :     destroyPQExpBuffer(defqry);
   13294         150 :     destroyPQExpBuffer(delqry);
   13295             : }
   13296             : 
   13297             : /*
   13298             :  * format_function_arguments: generate function name and argument list
   13299             :  *
   13300             :  * This is used when we can rely on pg_get_function_arguments to format
   13301             :  * the argument list.  Note, however, that pg_get_function_arguments
   13302             :  * does not special-case zero-argument aggregates.
   13303             :  */
   13304             : static char *
   13305        8276 : format_function_arguments(const FuncInfo *finfo, const char *funcargs, bool is_agg)
   13306             : {
   13307             :     PQExpBufferData fn;
   13308             : 
   13309        8276 :     initPQExpBuffer(&fn);
   13310        8276 :     appendPQExpBufferStr(&fn, fmtId(finfo->dobj.name));
   13311        8276 :     if (is_agg && finfo->nargs == 0)
   13312         160 :         appendPQExpBufferStr(&fn, "(*)");
   13313             :     else
   13314        8116 :         appendPQExpBuffer(&fn, "(%s)", funcargs);
   13315        8276 :     return fn.data;
   13316             : }
   13317             : 
   13318             : /*
   13319             :  * format_function_signature: generate function name and argument list
   13320             :  *
   13321             :  * Only a minimal list of input argument types is generated; this is
   13322             :  * sufficient to reference the function, but not to define it.
   13323             :  *
   13324             :  * If honor_quotes is false then the function name is never quoted.
   13325             :  * This is appropriate for use in TOC tags, but not in SQL commands.
   13326             :  */
   13327             : static char *
   13328        4372 : format_function_signature(Archive *fout, const FuncInfo *finfo, bool honor_quotes)
   13329             : {
   13330             :     PQExpBufferData fn;
   13331             :     int         j;
   13332             : 
   13333        4372 :     initPQExpBuffer(&fn);
   13334        4372 :     if (honor_quotes)
   13335         810 :         appendPQExpBuffer(&fn, "%s(", fmtId(finfo->dobj.name));
   13336             :     else
   13337        3562 :         appendPQExpBuffer(&fn, "%s(", finfo->dobj.name);
   13338        8012 :     for (j = 0; j < finfo->nargs; j++)
   13339             :     {
   13340        3640 :         if (j > 0)
   13341         844 :             appendPQExpBufferStr(&fn, ", ");
   13342             : 
   13343        3640 :         appendPQExpBufferStr(&fn,
   13344        3640 :                              getFormattedTypeName(fout, finfo->argtypes[j],
   13345             :                                                   zeroIsError));
   13346             :     }
   13347        4372 :     appendPQExpBufferChar(&fn, ')');
   13348        4372 :     return fn.data;
   13349             : }
   13350             : 
   13351             : 
   13352             : /*
   13353             :  * dumpFunc:
   13354             :  *    dump out one function
   13355             :  */
   13356             : static void
   13357        3686 : dumpFunc(Archive *fout, const FuncInfo *finfo)
   13358             : {
   13359        3686 :     DumpOptions *dopt = fout->dopt;
   13360             :     PQExpBuffer query;
   13361             :     PQExpBuffer q;
   13362             :     PQExpBuffer delqry;
   13363             :     PQExpBuffer asPart;
   13364             :     PGresult   *res;
   13365             :     char       *funcsig;        /* identity signature */
   13366        3686 :     char       *funcfullsig = NULL; /* full signature */
   13367             :     char       *funcsig_tag;
   13368             :     char       *qual_funcsig;
   13369             :     char       *proretset;
   13370             :     char       *prosrc;
   13371             :     char       *probin;
   13372             :     char       *prosqlbody;
   13373             :     char       *funcargs;
   13374             :     char       *funciargs;
   13375             :     char       *funcresult;
   13376             :     char       *protrftypes;
   13377             :     char       *prokind;
   13378             :     char       *provolatile;
   13379             :     char       *proisstrict;
   13380             :     char       *prosecdef;
   13381             :     char       *proleakproof;
   13382             :     char       *proconfig;
   13383             :     char       *procost;
   13384             :     char       *prorows;
   13385             :     char       *prosupport;
   13386             :     char       *proparallel;
   13387             :     char       *lanname;
   13388        3686 :     char      **configitems = NULL;
   13389        3686 :     int         nconfigitems = 0;
   13390             :     const char *keyword;
   13391             : 
   13392             :     /* Do nothing if not dumping schema */
   13393        3686 :     if (!dopt->dumpSchema)
   13394         124 :         return;
   13395             : 
   13396        3562 :     query = createPQExpBuffer();
   13397        3562 :     q = createPQExpBuffer();
   13398        3562 :     delqry = createPQExpBuffer();
   13399        3562 :     asPart = createPQExpBuffer();
   13400             : 
   13401        3562 :     if (!fout->is_prepared[PREPQUERY_DUMPFUNC])
   13402             :     {
   13403             :         /* Set up query for function-specific details */
   13404         128 :         appendPQExpBufferStr(query,
   13405             :                              "PREPARE dumpFunc(pg_catalog.oid) AS\n");
   13406             : 
   13407         128 :         appendPQExpBufferStr(query,
   13408             :                              "SELECT\n"
   13409             :                              "proretset,\n"
   13410             :                              "prosrc,\n"
   13411             :                              "probin,\n"
   13412             :                              "provolatile,\n"
   13413             :                              "proisstrict,\n"
   13414             :                              "prosecdef,\n"
   13415             :                              "lanname,\n"
   13416             :                              "proconfig,\n"
   13417             :                              "procost,\n"
   13418             :                              "prorows,\n"
   13419             :                              "pg_catalog.pg_get_function_arguments(p.oid) AS funcargs,\n"
   13420             :                              "pg_catalog.pg_get_function_identity_arguments(p.oid) AS funciargs,\n"
   13421             :                              "pg_catalog.pg_get_function_result(p.oid) AS funcresult,\n"
   13422             :                              "proleakproof,\n");
   13423             : 
   13424         128 :         if (fout->remoteVersion >= 90500)
   13425         128 :             appendPQExpBufferStr(query,
   13426             :                                  "array_to_string(protrftypes, ' ') AS protrftypes,\n");
   13427             :         else
   13428           0 :             appendPQExpBufferStr(query,
   13429             :                                  "NULL AS protrftypes,\n");
   13430             : 
   13431         128 :         if (fout->remoteVersion >= 90600)
   13432         128 :             appendPQExpBufferStr(query,
   13433             :                                  "proparallel,\n");
   13434             :         else
   13435           0 :             appendPQExpBufferStr(query,
   13436             :                                  "'u' AS proparallel,\n");
   13437             : 
   13438         128 :         if (fout->remoteVersion >= 110000)
   13439         128 :             appendPQExpBufferStr(query,
   13440             :                                  "prokind,\n");
   13441             :         else
   13442           0 :             appendPQExpBufferStr(query,
   13443             :                                  "CASE WHEN proiswindow THEN 'w' ELSE 'f' END AS prokind,\n");
   13444             : 
   13445         128 :         if (fout->remoteVersion >= 120000)
   13446         128 :             appendPQExpBufferStr(query,
   13447             :                                  "prosupport,\n");
   13448             :         else
   13449           0 :             appendPQExpBufferStr(query,
   13450             :                                  "'-' AS prosupport,\n");
   13451             : 
   13452         128 :         if (fout->remoteVersion >= 140000)
   13453         128 :             appendPQExpBufferStr(query,
   13454             :                                  "pg_get_function_sqlbody(p.oid) AS prosqlbody\n");
   13455             :         else
   13456           0 :             appendPQExpBufferStr(query,
   13457             :                                  "NULL AS prosqlbody\n");
   13458             : 
   13459         128 :         appendPQExpBufferStr(query,
   13460             :                              "FROM pg_catalog.pg_proc p, pg_catalog.pg_language l\n"
   13461             :                              "WHERE p.oid = $1 "
   13462             :                              "AND l.oid = p.prolang");
   13463             : 
   13464         128 :         ExecuteSqlStatement(fout, query->data);
   13465             : 
   13466         128 :         fout->is_prepared[PREPQUERY_DUMPFUNC] = true;
   13467             :     }
   13468             : 
   13469        3562 :     printfPQExpBuffer(query,
   13470             :                       "EXECUTE dumpFunc('%u')",
   13471        3562 :                       finfo->dobj.catId.oid);
   13472             : 
   13473        3562 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   13474             : 
   13475        3562 :     proretset = PQgetvalue(res, 0, PQfnumber(res, "proretset"));
   13476        3562 :     if (PQgetisnull(res, 0, PQfnumber(res, "prosqlbody")))
   13477             :     {
   13478        3460 :         prosrc = PQgetvalue(res, 0, PQfnumber(res, "prosrc"));
   13479        3460 :         probin = PQgetvalue(res, 0, PQfnumber(res, "probin"));
   13480        3460 :         prosqlbody = NULL;
   13481             :     }
   13482             :     else
   13483             :     {
   13484         102 :         prosrc = NULL;
   13485         102 :         probin = NULL;
   13486         102 :         prosqlbody = PQgetvalue(res, 0, PQfnumber(res, "prosqlbody"));
   13487             :     }
   13488        3562 :     funcargs = PQgetvalue(res, 0, PQfnumber(res, "funcargs"));
   13489        3562 :     funciargs = PQgetvalue(res, 0, PQfnumber(res, "funciargs"));
   13490        3562 :     funcresult = PQgetvalue(res, 0, PQfnumber(res, "funcresult"));
   13491        3562 :     protrftypes = PQgetvalue(res, 0, PQfnumber(res, "protrftypes"));
   13492        3562 :     prokind = PQgetvalue(res, 0, PQfnumber(res, "prokind"));
   13493        3562 :     provolatile = PQgetvalue(res, 0, PQfnumber(res, "provolatile"));
   13494        3562 :     proisstrict = PQgetvalue(res, 0, PQfnumber(res, "proisstrict"));
   13495        3562 :     prosecdef = PQgetvalue(res, 0, PQfnumber(res, "prosecdef"));
   13496        3562 :     proleakproof = PQgetvalue(res, 0, PQfnumber(res, "proleakproof"));
   13497        3562 :     proconfig = PQgetvalue(res, 0, PQfnumber(res, "proconfig"));
   13498        3562 :     procost = PQgetvalue(res, 0, PQfnumber(res, "procost"));
   13499        3562 :     prorows = PQgetvalue(res, 0, PQfnumber(res, "prorows"));
   13500        3562 :     prosupport = PQgetvalue(res, 0, PQfnumber(res, "prosupport"));
   13501        3562 :     proparallel = PQgetvalue(res, 0, PQfnumber(res, "proparallel"));
   13502        3562 :     lanname = PQgetvalue(res, 0, PQfnumber(res, "lanname"));
   13503             : 
   13504             :     /*
   13505             :      * See backend/commands/functioncmds.c for details of how the 'AS' clause
   13506             :      * is used.
   13507             :      */
   13508        3562 :     if (prosqlbody)
   13509             :     {
   13510         102 :         appendPQExpBufferStr(asPart, prosqlbody);
   13511             :     }
   13512        3460 :     else if (probin[0] != '\0')
   13513             :     {
   13514         270 :         appendPQExpBufferStr(asPart, "AS ");
   13515         270 :         appendStringLiteralAH(asPart, probin, fout);
   13516         270 :         if (prosrc[0] != '\0')
   13517             :         {
   13518         270 :             appendPQExpBufferStr(asPart, ", ");
   13519             : 
   13520             :             /*
   13521             :              * where we have bin, use dollar quoting if allowed and src
   13522             :              * contains quote or backslash; else use regular quoting.
   13523             :              */
   13524         270 :             if (dopt->disable_dollar_quoting ||
   13525         270 :                 (strchr(prosrc, '\'') == NULL && strchr(prosrc, '\\') == NULL))
   13526         270 :                 appendStringLiteralAH(asPart, prosrc, fout);
   13527             :             else
   13528           0 :                 appendStringLiteralDQ(asPart, prosrc, NULL);
   13529             :         }
   13530             :     }
   13531             :     else
   13532             :     {
   13533        3190 :         appendPQExpBufferStr(asPart, "AS ");
   13534             :         /* with no bin, dollar quote src unconditionally if allowed */
   13535        3190 :         if (dopt->disable_dollar_quoting)
   13536           0 :             appendStringLiteralAH(asPart, prosrc, fout);
   13537             :         else
   13538        3190 :             appendStringLiteralDQ(asPart, prosrc, NULL);
   13539             :     }
   13540             : 
   13541        3562 :     if (*proconfig)
   13542             :     {
   13543          30 :         if (!parsePGArray(proconfig, &configitems, &nconfigitems))
   13544           0 :             pg_fatal("could not parse %s array", "proconfig");
   13545             :     }
   13546             :     else
   13547             :     {
   13548        3532 :         configitems = NULL;
   13549        3532 :         nconfigitems = 0;
   13550             :     }
   13551             : 
   13552        3562 :     funcfullsig = format_function_arguments(finfo, funcargs, false);
   13553        3562 :     funcsig = format_function_arguments(finfo, funciargs, false);
   13554             : 
   13555        3562 :     funcsig_tag = format_function_signature(fout, finfo, false);
   13556             : 
   13557        3562 :     qual_funcsig = psprintf("%s.%s",
   13558        3562 :                             fmtId(finfo->dobj.namespace->dobj.name),
   13559             :                             funcsig);
   13560             : 
   13561        3562 :     if (prokind[0] == PROKIND_PROCEDURE)
   13562         190 :         keyword = "PROCEDURE";
   13563             :     else
   13564        3372 :         keyword = "FUNCTION"; /* works for window functions too */
   13565             : 
   13566        3562 :     appendPQExpBuffer(delqry, "DROP %s %s;\n",
   13567             :                       keyword, qual_funcsig);
   13568             : 
   13569        7124 :     appendPQExpBuffer(q, "CREATE %s %s.%s",
   13570             :                       keyword,
   13571        3562 :                       fmtId(finfo->dobj.namespace->dobj.name),
   13572             :                       funcfullsig ? funcfullsig :
   13573             :                       funcsig);
   13574             : 
   13575        3562 :     if (prokind[0] == PROKIND_PROCEDURE)
   13576             :          /* no result type to output */ ;
   13577        3372 :     else if (funcresult)
   13578        3372 :         appendPQExpBuffer(q, " RETURNS %s", funcresult);
   13579             :     else
   13580           0 :         appendPQExpBuffer(q, " RETURNS %s%s",
   13581           0 :                           (proretset[0] == 't') ? "SETOF " : "",
   13582           0 :                           getFormattedTypeName(fout, finfo->prorettype,
   13583             :                                                zeroIsError));
   13584             : 
   13585        3562 :     appendPQExpBuffer(q, "\n    LANGUAGE %s", fmtId(lanname));
   13586             : 
   13587        3562 :     if (*protrftypes)
   13588             :     {
   13589           0 :         Oid        *typeids = pg_malloc(FUNC_MAX_ARGS * sizeof(Oid));
   13590             :         int         i;
   13591             : 
   13592           0 :         appendPQExpBufferStr(q, " TRANSFORM ");
   13593           0 :         parseOidArray(protrftypes, typeids, FUNC_MAX_ARGS);
   13594           0 :         for (i = 0; typeids[i]; i++)
   13595             :         {
   13596           0 :             if (i != 0)
   13597           0 :                 appendPQExpBufferStr(q, ", ");
   13598           0 :             appendPQExpBuffer(q, "FOR TYPE %s",
   13599           0 :                               getFormattedTypeName(fout, typeids[i], zeroAsNone));
   13600             :         }
   13601             : 
   13602           0 :         free(typeids);
   13603             :     }
   13604             : 
   13605        3562 :     if (prokind[0] == PROKIND_WINDOW)
   13606          10 :         appendPQExpBufferStr(q, " WINDOW");
   13607             : 
   13608        3562 :     if (provolatile[0] != PROVOLATILE_VOLATILE)
   13609             :     {
   13610         714 :         if (provolatile[0] == PROVOLATILE_IMMUTABLE)
   13611         672 :             appendPQExpBufferStr(q, " IMMUTABLE");
   13612          42 :         else if (provolatile[0] == PROVOLATILE_STABLE)
   13613          42 :             appendPQExpBufferStr(q, " STABLE");
   13614           0 :         else if (provolatile[0] != PROVOLATILE_VOLATILE)
   13615           0 :             pg_fatal("unrecognized provolatile value for function \"%s\"",
   13616             :                      finfo->dobj.name);
   13617             :     }
   13618             : 
   13619        3562 :     if (proisstrict[0] == 't')
   13620         724 :         appendPQExpBufferStr(q, " STRICT");
   13621             : 
   13622        3562 :     if (prosecdef[0] == 't')
   13623           0 :         appendPQExpBufferStr(q, " SECURITY DEFINER");
   13624             : 
   13625        3562 :     if (proleakproof[0] == 't')
   13626          20 :         appendPQExpBufferStr(q, " LEAKPROOF");
   13627             : 
   13628             :     /*
   13629             :      * COST and ROWS are emitted only if present and not default, so as not to
   13630             :      * break backwards-compatibility of the dump without need.  Keep this code
   13631             :      * in sync with the defaults in functioncmds.c.
   13632             :      */
   13633        3562 :     if (strcmp(procost, "0") != 0)
   13634             :     {
   13635        3562 :         if (strcmp(lanname, "internal") == 0 || strcmp(lanname, "c") == 0)
   13636             :         {
   13637             :             /* default cost is 1 */
   13638         752 :             if (strcmp(procost, "1") != 0)
   13639           0 :                 appendPQExpBuffer(q, " COST %s", procost);
   13640             :         }
   13641             :         else
   13642             :         {
   13643             :             /* default cost is 100 */
   13644        2810 :             if (strcmp(procost, "100") != 0)
   13645          12 :                 appendPQExpBuffer(q, " COST %s", procost);
   13646             :         }
   13647             :     }
   13648        3562 :     if (proretset[0] == 't' &&
   13649         380 :         strcmp(prorows, "0") != 0 && strcmp(prorows, "1000") != 0)
   13650           0 :         appendPQExpBuffer(q, " ROWS %s", prorows);
   13651             : 
   13652        3562 :     if (strcmp(prosupport, "-") != 0)
   13653             :     {
   13654             :         /* We rely on regprocout to provide quoting and qualification */
   13655          90 :         appendPQExpBuffer(q, " SUPPORT %s", prosupport);
   13656             :     }
   13657             : 
   13658        3562 :     if (proparallel[0] != PROPARALLEL_UNSAFE)
   13659             :     {
   13660         244 :         if (proparallel[0] == PROPARALLEL_SAFE)
   13661         234 :             appendPQExpBufferStr(q, " PARALLEL SAFE");
   13662          10 :         else if (proparallel[0] == PROPARALLEL_RESTRICTED)
   13663          10 :             appendPQExpBufferStr(q, " PARALLEL RESTRICTED");
   13664           0 :         else if (proparallel[0] != PROPARALLEL_UNSAFE)
   13665           0 :             pg_fatal("unrecognized proparallel value for function \"%s\"",
   13666             :                      finfo->dobj.name);
   13667             :     }
   13668             : 
   13669        3632 :     for (int i = 0; i < nconfigitems; i++)
   13670             :     {
   13671             :         /* we feel free to scribble on configitems[] here */
   13672          70 :         char       *configitem = configitems[i];
   13673             :         char       *pos;
   13674             : 
   13675          70 :         pos = strchr(configitem, '=');
   13676          70 :         if (pos == NULL)
   13677           0 :             continue;
   13678          70 :         *pos++ = '\0';
   13679          70 :         appendPQExpBuffer(q, "\n    SET %s TO ", fmtId(configitem));
   13680             : 
   13681             :         /*
   13682             :          * Variables that are marked GUC_LIST_QUOTE were already fully quoted
   13683             :          * by flatten_set_variable_args() before they were put into the
   13684             :          * proconfig array.  However, because the quoting rules used there
   13685             :          * aren't exactly like SQL's, we have to break the list value apart
   13686             :          * and then quote the elements as string literals.  (The elements may
   13687             :          * be double-quoted as-is, but we can't just feed them to the SQL
   13688             :          * parser; it would do the wrong thing with elements that are
   13689             :          * zero-length or longer than NAMEDATALEN.)
   13690             :          *
   13691             :          * Variables that are not so marked should just be emitted as simple
   13692             :          * string literals.  If the variable is not known to
   13693             :          * variable_is_guc_list_quote(), we'll do that; this makes it unsafe
   13694             :          * to use GUC_LIST_QUOTE for extension variables.
   13695             :          */
   13696          70 :         if (variable_is_guc_list_quote(configitem))
   13697             :         {
   13698             :             char      **namelist;
   13699             :             char      **nameptr;
   13700             : 
   13701             :             /* Parse string into list of identifiers */
   13702             :             /* this shouldn't fail really */
   13703          20 :             if (SplitGUCList(pos, ',', &namelist))
   13704             :             {
   13705          70 :                 for (nameptr = namelist; *nameptr; nameptr++)
   13706             :                 {
   13707          50 :                     if (nameptr != namelist)
   13708          30 :                         appendPQExpBufferStr(q, ", ");
   13709          50 :                     appendStringLiteralAH(q, *nameptr, fout);
   13710             :                 }
   13711             :             }
   13712          20 :             pg_free(namelist);
   13713             :         }
   13714             :         else
   13715          50 :             appendStringLiteralAH(q, pos, fout);
   13716             :     }
   13717             : 
   13718        3562 :     appendPQExpBuffer(q, "\n    %s;\n", asPart->data);
   13719             : 
   13720        3562 :     append_depends_on_extension(fout, q, &finfo->dobj,
   13721             :                                 "pg_catalog.pg_proc", keyword,
   13722             :                                 qual_funcsig);
   13723             : 
   13724        3562 :     if (dopt->binary_upgrade)
   13725         576 :         binary_upgrade_extension_member(q, &finfo->dobj,
   13726             :                                         keyword, funcsig,
   13727         576 :                                         finfo->dobj.namespace->dobj.name);
   13728             : 
   13729        3562 :     if (finfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   13730        3358 :         ArchiveEntry(fout, finfo->dobj.catId, finfo->dobj.dumpId,
   13731        3358 :                      ARCHIVE_OPTS(.tag = funcsig_tag,
   13732             :                                   .namespace = finfo->dobj.namespace->dobj.name,
   13733             :                                   .owner = finfo->rolname,
   13734             :                                   .description = keyword,
   13735             :                                   .section = finfo->postponed_def ?
   13736             :                                   SECTION_POST_DATA : SECTION_PRE_DATA,
   13737             :                                   .createStmt = q->data,
   13738             :                                   .dropStmt = delqry->data));
   13739             : 
   13740             :     /* Dump Function Comments and Security Labels */
   13741        3562 :     if (finfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   13742          18 :         dumpComment(fout, keyword, funcsig,
   13743          18 :                     finfo->dobj.namespace->dobj.name, finfo->rolname,
   13744          18 :                     finfo->dobj.catId, 0, finfo->dobj.dumpId);
   13745             : 
   13746        3562 :     if (finfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
   13747           0 :         dumpSecLabel(fout, keyword, funcsig,
   13748           0 :                      finfo->dobj.namespace->dobj.name, finfo->rolname,
   13749           0 :                      finfo->dobj.catId, 0, finfo->dobj.dumpId);
   13750             : 
   13751        3562 :     if (finfo->dobj.dump & DUMP_COMPONENT_ACL)
   13752         212 :         dumpACL(fout, finfo->dobj.dumpId, InvalidDumpId, keyword,
   13753             :                 funcsig, NULL,
   13754         212 :                 finfo->dobj.namespace->dobj.name,
   13755         212 :                 NULL, finfo->rolname, &finfo->dacl);
   13756             : 
   13757        3562 :     PQclear(res);
   13758             : 
   13759        3562 :     destroyPQExpBuffer(query);
   13760        3562 :     destroyPQExpBuffer(q);
   13761        3562 :     destroyPQExpBuffer(delqry);
   13762        3562 :     destroyPQExpBuffer(asPart);
   13763        3562 :     free(funcsig);
   13764        3562 :     free(funcfullsig);
   13765        3562 :     free(funcsig_tag);
   13766        3562 :     free(qual_funcsig);
   13767        3562 :     free(configitems);
   13768             : }
   13769             : 
   13770             : 
   13771             : /*
   13772             :  * Dump a user-defined cast
   13773             :  */
   13774             : static void
   13775         140 : dumpCast(Archive *fout, const CastInfo *cast)
   13776             : {
   13777         140 :     DumpOptions *dopt = fout->dopt;
   13778             :     PQExpBuffer defqry;
   13779             :     PQExpBuffer delqry;
   13780             :     PQExpBuffer labelq;
   13781             :     PQExpBuffer castargs;
   13782         140 :     FuncInfo   *funcInfo = NULL;
   13783             :     const char *sourceType;
   13784             :     const char *targetType;
   13785             : 
   13786             :     /* Do nothing if not dumping schema */
   13787         140 :     if (!dopt->dumpSchema)
   13788          12 :         return;
   13789             : 
   13790             :     /* Cannot dump if we don't have the cast function's info */
   13791         128 :     if (OidIsValid(cast->castfunc))
   13792             :     {
   13793          78 :         funcInfo = findFuncByOid(cast->castfunc);
   13794          78 :         if (funcInfo == NULL)
   13795           0 :             pg_fatal("could not find function definition for function with OID %u",
   13796             :                      cast->castfunc);
   13797             :     }
   13798             : 
   13799         128 :     defqry = createPQExpBuffer();
   13800         128 :     delqry = createPQExpBuffer();
   13801         128 :     labelq = createPQExpBuffer();
   13802         128 :     castargs = createPQExpBuffer();
   13803             : 
   13804         128 :     sourceType = getFormattedTypeName(fout, cast->castsource, zeroAsNone);
   13805         128 :     targetType = getFormattedTypeName(fout, cast->casttarget, zeroAsNone);
   13806         128 :     appendPQExpBuffer(delqry, "DROP CAST (%s AS %s);\n",
   13807             :                       sourceType, targetType);
   13808             : 
   13809         128 :     appendPQExpBuffer(defqry, "CREATE CAST (%s AS %s) ",
   13810             :                       sourceType, targetType);
   13811             : 
   13812         128 :     switch (cast->castmethod)
   13813             :     {
   13814          50 :         case COERCION_METHOD_BINARY:
   13815          50 :             appendPQExpBufferStr(defqry, "WITHOUT FUNCTION");
   13816          50 :             break;
   13817           0 :         case COERCION_METHOD_INOUT:
   13818           0 :             appendPQExpBufferStr(defqry, "WITH INOUT");
   13819           0 :             break;
   13820          78 :         case COERCION_METHOD_FUNCTION:
   13821          78 :             if (funcInfo)
   13822             :             {
   13823          78 :                 char       *fsig = format_function_signature(fout, funcInfo, true);
   13824             : 
   13825             :                 /*
   13826             :                  * Always qualify the function name (format_function_signature
   13827             :                  * won't qualify it).
   13828             :                  */
   13829          78 :                 appendPQExpBuffer(defqry, "WITH FUNCTION %s.%s",
   13830          78 :                                   fmtId(funcInfo->dobj.namespace->dobj.name), fsig);
   13831          78 :                 free(fsig);
   13832             :             }
   13833             :             else
   13834           0 :                 pg_log_warning("bogus value in pg_cast.castfunc or pg_cast.castmethod field");
   13835          78 :             break;
   13836           0 :         default:
   13837           0 :             pg_log_warning("bogus value in pg_cast.castmethod field");
   13838             :     }
   13839             : 
   13840         128 :     if (cast->castcontext == 'a')
   13841          68 :         appendPQExpBufferStr(defqry, " AS ASSIGNMENT");
   13842          60 :     else if (cast->castcontext == 'i')
   13843          20 :         appendPQExpBufferStr(defqry, " AS IMPLICIT");
   13844         128 :     appendPQExpBufferStr(defqry, ";\n");
   13845             : 
   13846         128 :     appendPQExpBuffer(labelq, "CAST (%s AS %s)",
   13847             :                       sourceType, targetType);
   13848             : 
   13849         128 :     appendPQExpBuffer(castargs, "(%s AS %s)",
   13850             :                       sourceType, targetType);
   13851             : 
   13852         128 :     if (dopt->binary_upgrade)
   13853          14 :         binary_upgrade_extension_member(defqry, &cast->dobj,
   13854          14 :                                         "CAST", castargs->data, NULL);
   13855             : 
   13856         128 :     if (cast->dobj.dump & DUMP_COMPONENT_DEFINITION)
   13857         128 :         ArchiveEntry(fout, cast->dobj.catId, cast->dobj.dumpId,
   13858         128 :                      ARCHIVE_OPTS(.tag = labelq->data,
   13859             :                                   .description = "CAST",
   13860             :                                   .section = SECTION_PRE_DATA,
   13861             :                                   .createStmt = defqry->data,
   13862             :                                   .dropStmt = delqry->data));
   13863             : 
   13864             :     /* Dump Cast Comments */
   13865         128 :     if (cast->dobj.dump & DUMP_COMPONENT_COMMENT)
   13866           0 :         dumpComment(fout, "CAST", castargs->data,
   13867             :                     NULL, "",
   13868           0 :                     cast->dobj.catId, 0, cast->dobj.dumpId);
   13869             : 
   13870         128 :     destroyPQExpBuffer(defqry);
   13871         128 :     destroyPQExpBuffer(delqry);
   13872         128 :     destroyPQExpBuffer(labelq);
   13873         128 :     destroyPQExpBuffer(castargs);
   13874             : }
   13875             : 
   13876             : /*
   13877             :  * Dump a transform
   13878             :  */
   13879             : static void
   13880          90 : dumpTransform(Archive *fout, const TransformInfo *transform)
   13881             : {
   13882          90 :     DumpOptions *dopt = fout->dopt;
   13883             :     PQExpBuffer defqry;
   13884             :     PQExpBuffer delqry;
   13885             :     PQExpBuffer labelq;
   13886             :     PQExpBuffer transformargs;
   13887          90 :     FuncInfo   *fromsqlFuncInfo = NULL;
   13888          90 :     FuncInfo   *tosqlFuncInfo = NULL;
   13889             :     char       *lanname;
   13890             :     const char *transformType;
   13891             : 
   13892             :     /* Do nothing if not dumping schema */
   13893          90 :     if (!dopt->dumpSchema)
   13894          12 :         return;
   13895             : 
   13896             :     /* Cannot dump if we don't have the transform functions' info */
   13897          78 :     if (OidIsValid(transform->trffromsql))
   13898             :     {
   13899          78 :         fromsqlFuncInfo = findFuncByOid(transform->trffromsql);
   13900          78 :         if (fromsqlFuncInfo == NULL)
   13901           0 :             pg_fatal("could not find function definition for function with OID %u",
   13902             :                      transform->trffromsql);
   13903             :     }
   13904          78 :     if (OidIsValid(transform->trftosql))
   13905             :     {
   13906          78 :         tosqlFuncInfo = findFuncByOid(transform->trftosql);
   13907          78 :         if (tosqlFuncInfo == NULL)
   13908           0 :             pg_fatal("could not find function definition for function with OID %u",
   13909             :                      transform->trftosql);
   13910             :     }
   13911             : 
   13912          78 :     defqry = createPQExpBuffer();
   13913          78 :     delqry = createPQExpBuffer();
   13914          78 :     labelq = createPQExpBuffer();
   13915          78 :     transformargs = createPQExpBuffer();
   13916             : 
   13917          78 :     lanname = get_language_name(fout, transform->trflang);
   13918          78 :     transformType = getFormattedTypeName(fout, transform->trftype, zeroAsNone);
   13919             : 
   13920          78 :     appendPQExpBuffer(delqry, "DROP TRANSFORM FOR %s LANGUAGE %s;\n",
   13921             :                       transformType, lanname);
   13922             : 
   13923          78 :     appendPQExpBuffer(defqry, "CREATE TRANSFORM FOR %s LANGUAGE %s (",
   13924             :                       transformType, lanname);
   13925             : 
   13926          78 :     if (!transform->trffromsql && !transform->trftosql)
   13927           0 :         pg_log_warning("bogus transform definition, at least one of trffromsql and trftosql should be nonzero");
   13928             : 
   13929          78 :     if (transform->trffromsql)
   13930             :     {
   13931          78 :         if (fromsqlFuncInfo)
   13932             :         {
   13933          78 :             char       *fsig = format_function_signature(fout, fromsqlFuncInfo, true);
   13934             : 
   13935             :             /*
   13936             :              * Always qualify the function name (format_function_signature
   13937             :              * won't qualify it).
   13938             :              */
   13939          78 :             appendPQExpBuffer(defqry, "FROM SQL WITH FUNCTION %s.%s",
   13940          78 :                               fmtId(fromsqlFuncInfo->dobj.namespace->dobj.name), fsig);
   13941          78 :             free(fsig);
   13942             :         }
   13943             :         else
   13944           0 :             pg_log_warning("bogus value in pg_transform.trffromsql field");
   13945             :     }
   13946             : 
   13947          78 :     if (transform->trftosql)
   13948             :     {
   13949          78 :         if (transform->trffromsql)
   13950          78 :             appendPQExpBufferStr(defqry, ", ");
   13951             : 
   13952          78 :         if (tosqlFuncInfo)
   13953             :         {
   13954          78 :             char       *fsig = format_function_signature(fout, tosqlFuncInfo, true);
   13955             : 
   13956             :             /*
   13957             :              * Always qualify the function name (format_function_signature
   13958             :              * won't qualify it).
   13959             :              */
   13960          78 :             appendPQExpBuffer(defqry, "TO SQL WITH FUNCTION %s.%s",
   13961          78 :                               fmtId(tosqlFuncInfo->dobj.namespace->dobj.name), fsig);
   13962          78 :             free(fsig);
   13963             :         }
   13964             :         else
   13965           0 :             pg_log_warning("bogus value in pg_transform.trftosql field");
   13966             :     }
   13967             : 
   13968          78 :     appendPQExpBufferStr(defqry, ");\n");
   13969             : 
   13970          78 :     appendPQExpBuffer(labelq, "TRANSFORM FOR %s LANGUAGE %s",
   13971             :                       transformType, lanname);
   13972             : 
   13973          78 :     appendPQExpBuffer(transformargs, "FOR %s LANGUAGE %s",
   13974             :                       transformType, lanname);
   13975             : 
   13976          78 :     if (dopt->binary_upgrade)
   13977           4 :         binary_upgrade_extension_member(defqry, &transform->dobj,
   13978           4 :                                         "TRANSFORM", transformargs->data, NULL);
   13979             : 
   13980          78 :     if (transform->dobj.dump & DUMP_COMPONENT_DEFINITION)
   13981          78 :         ArchiveEntry(fout, transform->dobj.catId, transform->dobj.dumpId,
   13982          78 :                      ARCHIVE_OPTS(.tag = labelq->data,
   13983             :                                   .description = "TRANSFORM",
   13984             :                                   .section = SECTION_PRE_DATA,
   13985             :                                   .createStmt = defqry->data,
   13986             :                                   .dropStmt = delqry->data,
   13987             :                                   .deps = transform->dobj.dependencies,
   13988             :                                   .nDeps = transform->dobj.nDeps));
   13989             : 
   13990             :     /* Dump Transform Comments */
   13991          78 :     if (transform->dobj.dump & DUMP_COMPONENT_COMMENT)
   13992           0 :         dumpComment(fout, "TRANSFORM", transformargs->data,
   13993             :                     NULL, "",
   13994           0 :                     transform->dobj.catId, 0, transform->dobj.dumpId);
   13995             : 
   13996          78 :     free(lanname);
   13997          78 :     destroyPQExpBuffer(defqry);
   13998          78 :     destroyPQExpBuffer(delqry);
   13999          78 :     destroyPQExpBuffer(labelq);
   14000          78 :     destroyPQExpBuffer(transformargs);
   14001             : }
   14002             : 
   14003             : 
   14004             : /*
   14005             :  * dumpOpr
   14006             :  *    write out a single operator definition
   14007             :  */
   14008             : static void
   14009        5014 : dumpOpr(Archive *fout, const OprInfo *oprinfo)
   14010             : {
   14011        5014 :     DumpOptions *dopt = fout->dopt;
   14012             :     PQExpBuffer query;
   14013             :     PQExpBuffer q;
   14014             :     PQExpBuffer delq;
   14015             :     PQExpBuffer oprid;
   14016             :     PQExpBuffer details;
   14017             :     PGresult   *res;
   14018             :     int         i_oprkind;
   14019             :     int         i_oprcode;
   14020             :     int         i_oprleft;
   14021             :     int         i_oprright;
   14022             :     int         i_oprcom;
   14023             :     int         i_oprnegate;
   14024             :     int         i_oprrest;
   14025             :     int         i_oprjoin;
   14026             :     int         i_oprcanmerge;
   14027             :     int         i_oprcanhash;
   14028             :     char       *oprkind;
   14029             :     char       *oprcode;
   14030             :     char       *oprleft;
   14031             :     char       *oprright;
   14032             :     char       *oprcom;
   14033             :     char       *oprnegate;
   14034             :     char       *oprrest;
   14035             :     char       *oprjoin;
   14036             :     char       *oprcanmerge;
   14037             :     char       *oprcanhash;
   14038             :     char       *oprregproc;
   14039             :     char       *oprref;
   14040             : 
   14041             :     /* Do nothing if not dumping schema */
   14042        5014 :     if (!dopt->dumpSchema)
   14043          12 :         return;
   14044             : 
   14045             :     /*
   14046             :      * some operators are invalid because they were the result of user
   14047             :      * defining operators before commutators exist
   14048             :      */
   14049        5002 :     if (!OidIsValid(oprinfo->oprcode))
   14050          28 :         return;
   14051             : 
   14052        4974 :     query = createPQExpBuffer();
   14053        4974 :     q = createPQExpBuffer();
   14054        4974 :     delq = createPQExpBuffer();
   14055        4974 :     oprid = createPQExpBuffer();
   14056        4974 :     details = createPQExpBuffer();
   14057             : 
   14058        4974 :     if (!fout->is_prepared[PREPQUERY_DUMPOPR])
   14059             :     {
   14060             :         /* Set up query for operator-specific details */
   14061          86 :         appendPQExpBufferStr(query,
   14062             :                              "PREPARE dumpOpr(pg_catalog.oid) AS\n"
   14063             :                              "SELECT oprkind, "
   14064             :                              "oprcode::pg_catalog.regprocedure, "
   14065             :                              "oprleft::pg_catalog.regtype, "
   14066             :                              "oprright::pg_catalog.regtype, "
   14067             :                              "oprcom, "
   14068             :                              "oprnegate, "
   14069             :                              "oprrest::pg_catalog.regprocedure, "
   14070             :                              "oprjoin::pg_catalog.regprocedure, "
   14071             :                              "oprcanmerge, oprcanhash "
   14072             :                              "FROM pg_catalog.pg_operator "
   14073             :                              "WHERE oid = $1");
   14074             : 
   14075          86 :         ExecuteSqlStatement(fout, query->data);
   14076             : 
   14077          86 :         fout->is_prepared[PREPQUERY_DUMPOPR] = true;
   14078             :     }
   14079             : 
   14080        4974 :     printfPQExpBuffer(query,
   14081             :                       "EXECUTE dumpOpr('%u')",
   14082        4974 :                       oprinfo->dobj.catId.oid);
   14083             : 
   14084        4974 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   14085             : 
   14086        4974 :     i_oprkind = PQfnumber(res, "oprkind");
   14087        4974 :     i_oprcode = PQfnumber(res, "oprcode");
   14088        4974 :     i_oprleft = PQfnumber(res, "oprleft");
   14089        4974 :     i_oprright = PQfnumber(res, "oprright");
   14090        4974 :     i_oprcom = PQfnumber(res, "oprcom");
   14091        4974 :     i_oprnegate = PQfnumber(res, "oprnegate");
   14092        4974 :     i_oprrest = PQfnumber(res, "oprrest");
   14093        4974 :     i_oprjoin = PQfnumber(res, "oprjoin");
   14094        4974 :     i_oprcanmerge = PQfnumber(res, "oprcanmerge");
   14095        4974 :     i_oprcanhash = PQfnumber(res, "oprcanhash");
   14096             : 
   14097        4974 :     oprkind = PQgetvalue(res, 0, i_oprkind);
   14098        4974 :     oprcode = PQgetvalue(res, 0, i_oprcode);
   14099        4974 :     oprleft = PQgetvalue(res, 0, i_oprleft);
   14100        4974 :     oprright = PQgetvalue(res, 0, i_oprright);
   14101        4974 :     oprcom = PQgetvalue(res, 0, i_oprcom);
   14102        4974 :     oprnegate = PQgetvalue(res, 0, i_oprnegate);
   14103        4974 :     oprrest = PQgetvalue(res, 0, i_oprrest);
   14104        4974 :     oprjoin = PQgetvalue(res, 0, i_oprjoin);
   14105        4974 :     oprcanmerge = PQgetvalue(res, 0, i_oprcanmerge);
   14106        4974 :     oprcanhash = PQgetvalue(res, 0, i_oprcanhash);
   14107             : 
   14108             :     /* In PG14 upwards postfix operator support does not exist anymore. */
   14109        4974 :     if (strcmp(oprkind, "r") == 0)
   14110           0 :         pg_log_warning("postfix operators are not supported anymore (operator \"%s\")",
   14111             :                        oprcode);
   14112             : 
   14113        4974 :     oprregproc = convertRegProcReference(oprcode);
   14114        4974 :     if (oprregproc)
   14115             :     {
   14116        4974 :         appendPQExpBuffer(details, "    FUNCTION = %s", oprregproc);
   14117        4974 :         free(oprregproc);
   14118             :     }
   14119             : 
   14120        4974 :     appendPQExpBuffer(oprid, "%s (",
   14121        4974 :                       oprinfo->dobj.name);
   14122             : 
   14123             :     /*
   14124             :      * right unary means there's a left arg and left unary means there's a
   14125             :      * right arg.  (Although the "r" case is dead code for PG14 and later,
   14126             :      * continue to support it in case we're dumping from an old server.)
   14127             :      */
   14128        4974 :     if (strcmp(oprkind, "r") == 0 ||
   14129        4974 :         strcmp(oprkind, "b") == 0)
   14130             :     {
   14131        4688 :         appendPQExpBuffer(details, ",\n    LEFTARG = %s", oprleft);
   14132        4688 :         appendPQExpBufferStr(oprid, oprleft);
   14133             :     }
   14134             :     else
   14135         286 :         appendPQExpBufferStr(oprid, "NONE");
   14136             : 
   14137        4974 :     if (strcmp(oprkind, "l") == 0 ||
   14138        4688 :         strcmp(oprkind, "b") == 0)
   14139             :     {
   14140        4974 :         appendPQExpBuffer(details, ",\n    RIGHTARG = %s", oprright);
   14141        4974 :         appendPQExpBuffer(oprid, ", %s)", oprright);
   14142             :     }
   14143             :     else
   14144           0 :         appendPQExpBufferStr(oprid, ", NONE)");
   14145             : 
   14146        4974 :     oprref = getFormattedOperatorName(oprcom);
   14147        4974 :     if (oprref)
   14148             :     {
   14149        3322 :         appendPQExpBuffer(details, ",\n    COMMUTATOR = %s", oprref);
   14150        3322 :         free(oprref);
   14151             :     }
   14152             : 
   14153        4974 :     oprref = getFormattedOperatorName(oprnegate);
   14154        4974 :     if (oprref)
   14155             :     {
   14156        2326 :         appendPQExpBuffer(details, ",\n    NEGATOR = %s", oprref);
   14157        2326 :         free(oprref);
   14158             :     }
   14159             : 
   14160        4974 :     if (strcmp(oprcanmerge, "t") == 0)
   14161         370 :         appendPQExpBufferStr(details, ",\n    MERGES");
   14162             : 
   14163        4974 :     if (strcmp(oprcanhash, "t") == 0)
   14164         276 :         appendPQExpBufferStr(details, ",\n    HASHES");
   14165             : 
   14166        4974 :     oprregproc = convertRegProcReference(oprrest);
   14167        4974 :     if (oprregproc)
   14168             :     {
   14169        3028 :         appendPQExpBuffer(details, ",\n    RESTRICT = %s", oprregproc);
   14170        3028 :         free(oprregproc);
   14171             :     }
   14172             : 
   14173        4974 :     oprregproc = convertRegProcReference(oprjoin);
   14174        4974 :     if (oprregproc)
   14175             :     {
   14176        3028 :         appendPQExpBuffer(details, ",\n    JOIN = %s", oprregproc);
   14177        3028 :         free(oprregproc);
   14178             :     }
   14179             : 
   14180        4974 :     appendPQExpBuffer(delq, "DROP OPERATOR %s.%s;\n",
   14181        4974 :                       fmtId(oprinfo->dobj.namespace->dobj.name),
   14182             :                       oprid->data);
   14183             : 
   14184        4974 :     appendPQExpBuffer(q, "CREATE OPERATOR %s.%s (\n%s\n);\n",
   14185        4974 :                       fmtId(oprinfo->dobj.namespace->dobj.name),
   14186        4974 :                       oprinfo->dobj.name, details->data);
   14187             : 
   14188        4974 :     if (dopt->binary_upgrade)
   14189          24 :         binary_upgrade_extension_member(q, &oprinfo->dobj,
   14190          24 :                                         "OPERATOR", oprid->data,
   14191          24 :                                         oprinfo->dobj.namespace->dobj.name);
   14192             : 
   14193        4974 :     if (oprinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   14194        4974 :         ArchiveEntry(fout, oprinfo->dobj.catId, oprinfo->dobj.dumpId,
   14195        4974 :                      ARCHIVE_OPTS(.tag = oprinfo->dobj.name,
   14196             :                                   .namespace = oprinfo->dobj.namespace->dobj.name,
   14197             :                                   .owner = oprinfo->rolname,
   14198             :                                   .description = "OPERATOR",
   14199             :                                   .section = SECTION_PRE_DATA,
   14200             :                                   .createStmt = q->data,
   14201             :                                   .dropStmt = delq->data));
   14202             : 
   14203             :     /* Dump Operator Comments */
   14204        4974 :     if (oprinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   14205        4794 :         dumpComment(fout, "OPERATOR", oprid->data,
   14206        4794 :                     oprinfo->dobj.namespace->dobj.name, oprinfo->rolname,
   14207        4794 :                     oprinfo->dobj.catId, 0, oprinfo->dobj.dumpId);
   14208             : 
   14209        4974 :     PQclear(res);
   14210             : 
   14211        4974 :     destroyPQExpBuffer(query);
   14212        4974 :     destroyPQExpBuffer(q);
   14213        4974 :     destroyPQExpBuffer(delq);
   14214        4974 :     destroyPQExpBuffer(oprid);
   14215        4974 :     destroyPQExpBuffer(details);
   14216             : }
   14217             : 
   14218             : /*
   14219             :  * Convert a function reference obtained from pg_operator
   14220             :  *
   14221             :  * Returns allocated string of what to print, or NULL if function references
   14222             :  * is InvalidOid. Returned string is expected to be free'd by the caller.
   14223             :  *
   14224             :  * The input is a REGPROCEDURE display; we have to strip the argument-types
   14225             :  * part.
   14226             :  */
   14227             : static char *
   14228       14922 : convertRegProcReference(const char *proc)
   14229             : {
   14230             :     char       *name;
   14231             :     char       *paren;
   14232             :     bool        inquote;
   14233             : 
   14234             :     /* In all cases "-" means a null reference */
   14235       14922 :     if (strcmp(proc, "-") == 0)
   14236        3892 :         return NULL;
   14237             : 
   14238       11030 :     name = pg_strdup(proc);
   14239             :     /* find non-double-quoted left paren */
   14240       11030 :     inquote = false;
   14241      132906 :     for (paren = name; *paren; paren++)
   14242             :     {
   14243      132906 :         if (*paren == '(' && !inquote)
   14244             :         {
   14245       11030 :             *paren = '\0';
   14246       11030 :             break;
   14247             :         }
   14248      121876 :         if (*paren == '"')
   14249         100 :             inquote = !inquote;
   14250             :     }
   14251       11030 :     return name;
   14252             : }
   14253             : 
   14254             : /*
   14255             :  * getFormattedOperatorName - retrieve the operator name for the
   14256             :  * given operator OID (presented in string form).
   14257             :  *
   14258             :  * Returns an allocated string, or NULL if the given OID is invalid.
   14259             :  * Caller is responsible for free'ing result string.
   14260             :  *
   14261             :  * What we produce has the format "OPERATOR(schema.oprname)".  This is only
   14262             :  * useful in commands where the operator's argument types can be inferred from
   14263             :  * context.  We always schema-qualify the name, though.  The predecessor to
   14264             :  * this code tried to skip the schema qualification if possible, but that led
   14265             :  * to wrong results in corner cases, such as if an operator and its negator
   14266             :  * are in different schemas.
   14267             :  */
   14268             : static char *
   14269       10524 : getFormattedOperatorName(const char *oproid)
   14270             : {
   14271             :     OprInfo    *oprInfo;
   14272             : 
   14273             :     /* In all cases "0" means a null reference */
   14274       10524 :     if (strcmp(oproid, "0") == 0)
   14275        4876 :         return NULL;
   14276             : 
   14277        5648 :     oprInfo = findOprByOid(atooid(oproid));
   14278        5648 :     if (oprInfo == NULL)
   14279             :     {
   14280           0 :         pg_log_warning("could not find operator with OID %s",
   14281             :                        oproid);
   14282           0 :         return NULL;
   14283             :     }
   14284             : 
   14285        5648 :     return psprintf("OPERATOR(%s.%s)",
   14286        5648 :                     fmtId(oprInfo->dobj.namespace->dobj.name),
   14287             :                     oprInfo->dobj.name);
   14288             : }
   14289             : 
   14290             : /*
   14291             :  * Convert a function OID obtained from pg_ts_parser or pg_ts_template
   14292             :  *
   14293             :  * It is sufficient to use REGPROC rather than REGPROCEDURE, since the
   14294             :  * argument lists of these functions are predetermined.  Note that the
   14295             :  * caller should ensure we are in the proper schema, because the results
   14296             :  * are search path dependent!
   14297             :  */
   14298             : static char *
   14299         440 : convertTSFunction(Archive *fout, Oid funcOid)
   14300             : {
   14301             :     char       *result;
   14302             :     char        query[128];
   14303             :     PGresult   *res;
   14304             : 
   14305         440 :     snprintf(query, sizeof(query),
   14306             :              "SELECT '%u'::pg_catalog.regproc", funcOid);
   14307         440 :     res = ExecuteSqlQueryForSingleRow(fout, query);
   14308             : 
   14309         440 :     result = pg_strdup(PQgetvalue(res, 0, 0));
   14310             : 
   14311         440 :     PQclear(res);
   14312             : 
   14313         440 :     return result;
   14314             : }
   14315             : 
   14316             : /*
   14317             :  * dumpAccessMethod
   14318             :  *    write out a single access method definition
   14319             :  */
   14320             : static void
   14321         172 : dumpAccessMethod(Archive *fout, const AccessMethodInfo *aminfo)
   14322             : {
   14323         172 :     DumpOptions *dopt = fout->dopt;
   14324             :     PQExpBuffer q;
   14325             :     PQExpBuffer delq;
   14326             :     char       *qamname;
   14327             : 
   14328             :     /* Do nothing if not dumping schema */
   14329         172 :     if (!dopt->dumpSchema)
   14330          24 :         return;
   14331             : 
   14332         148 :     q = createPQExpBuffer();
   14333         148 :     delq = createPQExpBuffer();
   14334             : 
   14335         148 :     qamname = pg_strdup(fmtId(aminfo->dobj.name));
   14336             : 
   14337         148 :     appendPQExpBuffer(q, "CREATE ACCESS METHOD %s ", qamname);
   14338             : 
   14339         148 :     switch (aminfo->amtype)
   14340             :     {
   14341          70 :         case AMTYPE_INDEX:
   14342          70 :             appendPQExpBufferStr(q, "TYPE INDEX ");
   14343          70 :             break;
   14344          78 :         case AMTYPE_TABLE:
   14345          78 :             appendPQExpBufferStr(q, "TYPE TABLE ");
   14346          78 :             break;
   14347           0 :         default:
   14348           0 :             pg_log_warning("invalid type \"%c\" of access method \"%s\"",
   14349             :                            aminfo->amtype, qamname);
   14350           0 :             destroyPQExpBuffer(q);
   14351           0 :             destroyPQExpBuffer(delq);
   14352           0 :             free(qamname);
   14353           0 :             return;
   14354             :     }
   14355             : 
   14356         148 :     appendPQExpBuffer(q, "HANDLER %s;\n", aminfo->amhandler);
   14357             : 
   14358         148 :     appendPQExpBuffer(delq, "DROP ACCESS METHOD %s;\n",
   14359             :                       qamname);
   14360             : 
   14361         148 :     if (dopt->binary_upgrade)
   14362           8 :         binary_upgrade_extension_member(q, &aminfo->dobj,
   14363             :                                         "ACCESS METHOD", qamname, NULL);
   14364             : 
   14365         148 :     if (aminfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   14366         148 :         ArchiveEntry(fout, aminfo->dobj.catId, aminfo->dobj.dumpId,
   14367         148 :                      ARCHIVE_OPTS(.tag = aminfo->dobj.name,
   14368             :                                   .description = "ACCESS METHOD",
   14369             :                                   .section = SECTION_PRE_DATA,
   14370             :                                   .createStmt = q->data,
   14371             :                                   .dropStmt = delq->data));
   14372             : 
   14373             :     /* Dump Access Method Comments */
   14374         148 :     if (aminfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   14375           0 :         dumpComment(fout, "ACCESS METHOD", qamname,
   14376             :                     NULL, "",
   14377           0 :                     aminfo->dobj.catId, 0, aminfo->dobj.dumpId);
   14378             : 
   14379         148 :     destroyPQExpBuffer(q);
   14380         148 :     destroyPQExpBuffer(delq);
   14381         148 :     free(qamname);
   14382             : }
   14383             : 
   14384             : /*
   14385             :  * dumpOpclass
   14386             :  *    write out a single operator class definition
   14387             :  */
   14388             : static void
   14389        1338 : dumpOpclass(Archive *fout, const OpclassInfo *opcinfo)
   14390             : {
   14391        1338 :     DumpOptions *dopt = fout->dopt;
   14392             :     PQExpBuffer query;
   14393             :     PQExpBuffer q;
   14394             :     PQExpBuffer delq;
   14395             :     PQExpBuffer nameusing;
   14396             :     PGresult   *res;
   14397             :     int         ntups;
   14398             :     int         i_opcintype;
   14399             :     int         i_opckeytype;
   14400             :     int         i_opcdefault;
   14401             :     int         i_opcfamily;
   14402             :     int         i_opcfamilyname;
   14403             :     int         i_opcfamilynsp;
   14404             :     int         i_amname;
   14405             :     int         i_amopstrategy;
   14406             :     int         i_amopopr;
   14407             :     int         i_sortfamily;
   14408             :     int         i_sortfamilynsp;
   14409             :     int         i_amprocnum;
   14410             :     int         i_amproc;
   14411             :     int         i_amproclefttype;
   14412             :     int         i_amprocrighttype;
   14413             :     char       *opcintype;
   14414             :     char       *opckeytype;
   14415             :     char       *opcdefault;
   14416             :     char       *opcfamily;
   14417             :     char       *opcfamilyname;
   14418             :     char       *opcfamilynsp;
   14419             :     char       *amname;
   14420             :     char       *amopstrategy;
   14421             :     char       *amopopr;
   14422             :     char       *sortfamily;
   14423             :     char       *sortfamilynsp;
   14424             :     char       *amprocnum;
   14425             :     char       *amproc;
   14426             :     char       *amproclefttype;
   14427             :     char       *amprocrighttype;
   14428             :     bool        needComma;
   14429             :     int         i;
   14430             : 
   14431             :     /* Do nothing if not dumping schema */
   14432        1338 :     if (!dopt->dumpSchema)
   14433          36 :         return;
   14434             : 
   14435        1302 :     query = createPQExpBuffer();
   14436        1302 :     q = createPQExpBuffer();
   14437        1302 :     delq = createPQExpBuffer();
   14438        1302 :     nameusing = createPQExpBuffer();
   14439             : 
   14440             :     /* Get additional fields from the pg_opclass row */
   14441        1302 :     appendPQExpBuffer(query, "SELECT opcintype::pg_catalog.regtype, "
   14442             :                       "opckeytype::pg_catalog.regtype, "
   14443             :                       "opcdefault, opcfamily, "
   14444             :                       "opfname AS opcfamilyname, "
   14445             :                       "nspname AS opcfamilynsp, "
   14446             :                       "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opcmethod) AS amname "
   14447             :                       "FROM pg_catalog.pg_opclass c "
   14448             :                       "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = opcfamily "
   14449             :                       "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
   14450             :                       "WHERE c.oid = '%u'::pg_catalog.oid",
   14451        1302 :                       opcinfo->dobj.catId.oid);
   14452             : 
   14453        1302 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   14454             : 
   14455        1302 :     i_opcintype = PQfnumber(res, "opcintype");
   14456        1302 :     i_opckeytype = PQfnumber(res, "opckeytype");
   14457        1302 :     i_opcdefault = PQfnumber(res, "opcdefault");
   14458        1302 :     i_opcfamily = PQfnumber(res, "opcfamily");
   14459        1302 :     i_opcfamilyname = PQfnumber(res, "opcfamilyname");
   14460        1302 :     i_opcfamilynsp = PQfnumber(res, "opcfamilynsp");
   14461        1302 :     i_amname = PQfnumber(res, "amname");
   14462             : 
   14463             :     /* opcintype may still be needed after we PQclear res */
   14464        1302 :     opcintype = pg_strdup(PQgetvalue(res, 0, i_opcintype));
   14465        1302 :     opckeytype = PQgetvalue(res, 0, i_opckeytype);
   14466        1302 :     opcdefault = PQgetvalue(res, 0, i_opcdefault);
   14467             :     /* opcfamily will still be needed after we PQclear res */
   14468        1302 :     opcfamily = pg_strdup(PQgetvalue(res, 0, i_opcfamily));
   14469        1302 :     opcfamilyname = PQgetvalue(res, 0, i_opcfamilyname);
   14470        1302 :     opcfamilynsp = PQgetvalue(res, 0, i_opcfamilynsp);
   14471             :     /* amname will still be needed after we PQclear res */
   14472        1302 :     amname = pg_strdup(PQgetvalue(res, 0, i_amname));
   14473             : 
   14474        1302 :     appendPQExpBuffer(delq, "DROP OPERATOR CLASS %s",
   14475        1302 :                       fmtQualifiedDumpable(opcinfo));
   14476        1302 :     appendPQExpBuffer(delq, " USING %s;\n",
   14477             :                       fmtId(amname));
   14478             : 
   14479             :     /* Build the fixed portion of the CREATE command */
   14480        1302 :     appendPQExpBuffer(q, "CREATE OPERATOR CLASS %s\n    ",
   14481        1302 :                       fmtQualifiedDumpable(opcinfo));
   14482        1302 :     if (strcmp(opcdefault, "t") == 0)
   14483         714 :         appendPQExpBufferStr(q, "DEFAULT ");
   14484        1302 :     appendPQExpBuffer(q, "FOR TYPE %s USING %s",
   14485             :                       opcintype,
   14486             :                       fmtId(amname));
   14487        1302 :     if (strlen(opcfamilyname) > 0)
   14488             :     {
   14489        1302 :         appendPQExpBufferStr(q, " FAMILY ");
   14490        1302 :         appendPQExpBuffer(q, "%s.", fmtId(opcfamilynsp));
   14491        1302 :         appendPQExpBufferStr(q, fmtId(opcfamilyname));
   14492             :     }
   14493        1302 :     appendPQExpBufferStr(q, " AS\n    ");
   14494             : 
   14495        1302 :     needComma = false;
   14496             : 
   14497        1302 :     if (strcmp(opckeytype, "-") != 0)
   14498             :     {
   14499         504 :         appendPQExpBuffer(q, "STORAGE %s",
   14500             :                           opckeytype);
   14501         504 :         needComma = true;
   14502             :     }
   14503             : 
   14504        1302 :     PQclear(res);
   14505             : 
   14506             :     /*
   14507             :      * Now fetch and print the OPERATOR entries (pg_amop rows).
   14508             :      *
   14509             :      * Print only those opfamily members that are tied to the opclass by
   14510             :      * pg_depend entries.
   14511             :      */
   14512        1302 :     resetPQExpBuffer(query);
   14513        1302 :     appendPQExpBuffer(query, "SELECT amopstrategy, "
   14514             :                       "amopopr::pg_catalog.regoperator, "
   14515             :                       "opfname AS sortfamily, "
   14516             :                       "nspname AS sortfamilynsp "
   14517             :                       "FROM pg_catalog.pg_amop ao JOIN pg_catalog.pg_depend ON "
   14518             :                       "(classid = 'pg_catalog.pg_amop'::pg_catalog.regclass AND objid = ao.oid) "
   14519             :                       "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = amopsortfamily "
   14520             :                       "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
   14521             :                       "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
   14522             :                       "AND refobjid = '%u'::pg_catalog.oid "
   14523             :                       "AND amopfamily = '%s'::pg_catalog.oid "
   14524             :                       "ORDER BY amopstrategy",
   14525        1302 :                       opcinfo->dobj.catId.oid,
   14526             :                       opcfamily);
   14527             : 
   14528        1302 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   14529             : 
   14530        1302 :     ntups = PQntuples(res);
   14531             : 
   14532        1302 :     i_amopstrategy = PQfnumber(res, "amopstrategy");
   14533        1302 :     i_amopopr = PQfnumber(res, "amopopr");
   14534        1302 :     i_sortfamily = PQfnumber(res, "sortfamily");
   14535        1302 :     i_sortfamilynsp = PQfnumber(res, "sortfamilynsp");
   14536             : 
   14537        1742 :     for (i = 0; i < ntups; i++)
   14538             :     {
   14539         440 :         amopstrategy = PQgetvalue(res, i, i_amopstrategy);
   14540         440 :         amopopr = PQgetvalue(res, i, i_amopopr);
   14541         440 :         sortfamily = PQgetvalue(res, i, i_sortfamily);
   14542         440 :         sortfamilynsp = PQgetvalue(res, i, i_sortfamilynsp);
   14543             : 
   14544         440 :         if (needComma)
   14545         280 :             appendPQExpBufferStr(q, " ,\n    ");
   14546             : 
   14547         440 :         appendPQExpBuffer(q, "OPERATOR %s %s",
   14548             :                           amopstrategy, amopopr);
   14549             : 
   14550         440 :         if (strlen(sortfamily) > 0)
   14551             :         {
   14552           0 :             appendPQExpBufferStr(q, " FOR ORDER BY ");
   14553           0 :             appendPQExpBuffer(q, "%s.", fmtId(sortfamilynsp));
   14554           0 :             appendPQExpBufferStr(q, fmtId(sortfamily));
   14555             :         }
   14556             : 
   14557         440 :         needComma = true;
   14558             :     }
   14559             : 
   14560        1302 :     PQclear(res);
   14561             : 
   14562             :     /*
   14563             :      * Now fetch and print the FUNCTION entries (pg_amproc rows).
   14564             :      *
   14565             :      * Print only those opfamily members that are tied to the opclass by
   14566             :      * pg_depend entries.
   14567             :      *
   14568             :      * We print the amproclefttype/amprocrighttype even though in most cases
   14569             :      * the backend could deduce the right values, because of the corner case
   14570             :      * of a btree sort support function for a cross-type comparison.
   14571             :      */
   14572        1302 :     resetPQExpBuffer(query);
   14573             : 
   14574        1302 :     appendPQExpBuffer(query, "SELECT amprocnum, "
   14575             :                       "amproc::pg_catalog.regprocedure, "
   14576             :                       "amproclefttype::pg_catalog.regtype, "
   14577             :                       "amprocrighttype::pg_catalog.regtype "
   14578             :                       "FROM pg_catalog.pg_amproc ap, pg_catalog.pg_depend "
   14579             :                       "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
   14580             :                       "AND refobjid = '%u'::pg_catalog.oid "
   14581             :                       "AND classid = 'pg_catalog.pg_amproc'::pg_catalog.regclass "
   14582             :                       "AND objid = ap.oid "
   14583             :                       "ORDER BY amprocnum",
   14584        1302 :                       opcinfo->dobj.catId.oid);
   14585             : 
   14586        1302 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   14587             : 
   14588        1302 :     ntups = PQntuples(res);
   14589             : 
   14590        1302 :     i_amprocnum = PQfnumber(res, "amprocnum");
   14591        1302 :     i_amproc = PQfnumber(res, "amproc");
   14592        1302 :     i_amproclefttype = PQfnumber(res, "amproclefttype");
   14593        1302 :     i_amprocrighttype = PQfnumber(res, "amprocrighttype");
   14594             : 
   14595        1372 :     for (i = 0; i < ntups; i++)
   14596             :     {
   14597          70 :         amprocnum = PQgetvalue(res, i, i_amprocnum);
   14598          70 :         amproc = PQgetvalue(res, i, i_amproc);
   14599          70 :         amproclefttype = PQgetvalue(res, i, i_amproclefttype);
   14600          70 :         amprocrighttype = PQgetvalue(res, i, i_amprocrighttype);
   14601             : 
   14602          70 :         if (needComma)
   14603          70 :             appendPQExpBufferStr(q, " ,\n    ");
   14604             : 
   14605          70 :         appendPQExpBuffer(q, "FUNCTION %s", amprocnum);
   14606             : 
   14607          70 :         if (*amproclefttype && *amprocrighttype)
   14608          70 :             appendPQExpBuffer(q, " (%s, %s)", amproclefttype, amprocrighttype);
   14609             : 
   14610          70 :         appendPQExpBuffer(q, " %s", amproc);
   14611             : 
   14612          70 :         needComma = true;
   14613             :     }
   14614             : 
   14615        1302 :     PQclear(res);
   14616             : 
   14617             :     /*
   14618             :      * If needComma is still false it means we haven't added anything after
   14619             :      * the AS keyword.  To avoid printing broken SQL, append a dummy STORAGE
   14620             :      * clause with the same datatype.  This isn't sanctioned by the
   14621             :      * documentation, but actually DefineOpClass will treat it as a no-op.
   14622             :      */
   14623        1302 :     if (!needComma)
   14624         638 :         appendPQExpBuffer(q, "STORAGE %s", opcintype);
   14625             : 
   14626        1302 :     appendPQExpBufferStr(q, ";\n");
   14627             : 
   14628        1302 :     appendPQExpBufferStr(nameusing, fmtId(opcinfo->dobj.name));
   14629        1302 :     appendPQExpBuffer(nameusing, " USING %s",
   14630             :                       fmtId(amname));
   14631             : 
   14632        1302 :     if (dopt->binary_upgrade)
   14633          12 :         binary_upgrade_extension_member(q, &opcinfo->dobj,
   14634          12 :                                         "OPERATOR CLASS", nameusing->data,
   14635          12 :                                         opcinfo->dobj.namespace->dobj.name);
   14636             : 
   14637        1302 :     if (opcinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   14638        1302 :         ArchiveEntry(fout, opcinfo->dobj.catId, opcinfo->dobj.dumpId,
   14639        1302 :                      ARCHIVE_OPTS(.tag = opcinfo->dobj.name,
   14640             :                                   .namespace = opcinfo->dobj.namespace->dobj.name,
   14641             :                                   .owner = opcinfo->rolname,
   14642             :                                   .description = "OPERATOR CLASS",
   14643             :                                   .section = SECTION_PRE_DATA,
   14644             :                                   .createStmt = q->data,
   14645             :                                   .dropStmt = delq->data));
   14646             : 
   14647             :     /* Dump Operator Class Comments */
   14648        1302 :     if (opcinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   14649           0 :         dumpComment(fout, "OPERATOR CLASS", nameusing->data,
   14650           0 :                     opcinfo->dobj.namespace->dobj.name, opcinfo->rolname,
   14651           0 :                     opcinfo->dobj.catId, 0, opcinfo->dobj.dumpId);
   14652             : 
   14653        1302 :     free(opcintype);
   14654        1302 :     free(opcfamily);
   14655        1302 :     free(amname);
   14656        1302 :     destroyPQExpBuffer(query);
   14657        1302 :     destroyPQExpBuffer(q);
   14658        1302 :     destroyPQExpBuffer(delq);
   14659        1302 :     destroyPQExpBuffer(nameusing);
   14660             : }
   14661             : 
   14662             : /*
   14663             :  * dumpOpfamily
   14664             :  *    write out a single operator family definition
   14665             :  *
   14666             :  * Note: this also dumps any "loose" operator members that aren't bound to a
   14667             :  * specific opclass within the opfamily.
   14668             :  */
   14669             : static void
   14670        1110 : dumpOpfamily(Archive *fout, const OpfamilyInfo *opfinfo)
   14671             : {
   14672        1110 :     DumpOptions *dopt = fout->dopt;
   14673             :     PQExpBuffer query;
   14674             :     PQExpBuffer q;
   14675             :     PQExpBuffer delq;
   14676             :     PQExpBuffer nameusing;
   14677             :     PGresult   *res;
   14678             :     PGresult   *res_ops;
   14679             :     PGresult   *res_procs;
   14680             :     int         ntups;
   14681             :     int         i_amname;
   14682             :     int         i_amopstrategy;
   14683             :     int         i_amopopr;
   14684             :     int         i_sortfamily;
   14685             :     int         i_sortfamilynsp;
   14686             :     int         i_amprocnum;
   14687             :     int         i_amproc;
   14688             :     int         i_amproclefttype;
   14689             :     int         i_amprocrighttype;
   14690             :     char       *amname;
   14691             :     char       *amopstrategy;
   14692             :     char       *amopopr;
   14693             :     char       *sortfamily;
   14694             :     char       *sortfamilynsp;
   14695             :     char       *amprocnum;
   14696             :     char       *amproc;
   14697             :     char       *amproclefttype;
   14698             :     char       *amprocrighttype;
   14699             :     bool        needComma;
   14700             :     int         i;
   14701             : 
   14702             :     /* Do nothing if not dumping schema */
   14703        1110 :     if (!dopt->dumpSchema)
   14704          24 :         return;
   14705             : 
   14706        1086 :     query = createPQExpBuffer();
   14707        1086 :     q = createPQExpBuffer();
   14708        1086 :     delq = createPQExpBuffer();
   14709        1086 :     nameusing = createPQExpBuffer();
   14710             : 
   14711             :     /*
   14712             :      * Fetch only those opfamily members that are tied directly to the
   14713             :      * opfamily by pg_depend entries.
   14714             :      */
   14715        1086 :     appendPQExpBuffer(query, "SELECT amopstrategy, "
   14716             :                       "amopopr::pg_catalog.regoperator, "
   14717             :                       "opfname AS sortfamily, "
   14718             :                       "nspname AS sortfamilynsp "
   14719             :                       "FROM pg_catalog.pg_amop ao JOIN pg_catalog.pg_depend ON "
   14720             :                       "(classid = 'pg_catalog.pg_amop'::pg_catalog.regclass AND objid = ao.oid) "
   14721             :                       "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = amopsortfamily "
   14722             :                       "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
   14723             :                       "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
   14724             :                       "AND refobjid = '%u'::pg_catalog.oid "
   14725             :                       "AND amopfamily = '%u'::pg_catalog.oid "
   14726             :                       "ORDER BY amopstrategy",
   14727        1086 :                       opfinfo->dobj.catId.oid,
   14728        1086 :                       opfinfo->dobj.catId.oid);
   14729             : 
   14730        1086 :     res_ops = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   14731             : 
   14732        1086 :     resetPQExpBuffer(query);
   14733             : 
   14734        1086 :     appendPQExpBuffer(query, "SELECT amprocnum, "
   14735             :                       "amproc::pg_catalog.regprocedure, "
   14736             :                       "amproclefttype::pg_catalog.regtype, "
   14737             :                       "amprocrighttype::pg_catalog.regtype "
   14738             :                       "FROM pg_catalog.pg_amproc ap, pg_catalog.pg_depend "
   14739             :                       "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
   14740             :                       "AND refobjid = '%u'::pg_catalog.oid "
   14741             :                       "AND classid = 'pg_catalog.pg_amproc'::pg_catalog.regclass "
   14742             :                       "AND objid = ap.oid "
   14743             :                       "ORDER BY amprocnum",
   14744        1086 :                       opfinfo->dobj.catId.oid);
   14745             : 
   14746        1086 :     res_procs = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   14747             : 
   14748             :     /* Get additional fields from the pg_opfamily row */
   14749        1086 :     resetPQExpBuffer(query);
   14750             : 
   14751        1086 :     appendPQExpBuffer(query, "SELECT "
   14752             :                       "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opfmethod) AS amname "
   14753             :                       "FROM pg_catalog.pg_opfamily "
   14754             :                       "WHERE oid = '%u'::pg_catalog.oid",
   14755        1086 :                       opfinfo->dobj.catId.oid);
   14756             : 
   14757        1086 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   14758             : 
   14759        1086 :     i_amname = PQfnumber(res, "amname");
   14760             : 
   14761             :     /* amname will still be needed after we PQclear res */
   14762        1086 :     amname = pg_strdup(PQgetvalue(res, 0, i_amname));
   14763             : 
   14764        1086 :     appendPQExpBuffer(delq, "DROP OPERATOR FAMILY %s",
   14765        1086 :                       fmtQualifiedDumpable(opfinfo));
   14766        1086 :     appendPQExpBuffer(delq, " USING %s;\n",
   14767             :                       fmtId(amname));
   14768             : 
   14769             :     /* Build the fixed portion of the CREATE command */
   14770        1086 :     appendPQExpBuffer(q, "CREATE OPERATOR FAMILY %s",
   14771        1086 :                       fmtQualifiedDumpable(opfinfo));
   14772        1086 :     appendPQExpBuffer(q, " USING %s;\n",
   14773             :                       fmtId(amname));
   14774             : 
   14775        1086 :     PQclear(res);
   14776             : 
   14777             :     /* Do we need an ALTER to add loose members? */
   14778        1086 :     if (PQntuples(res_ops) > 0 || PQntuples(res_procs) > 0)
   14779             :     {
   14780         100 :         appendPQExpBuffer(q, "ALTER OPERATOR FAMILY %s",
   14781         100 :                           fmtQualifiedDumpable(opfinfo));
   14782         100 :         appendPQExpBuffer(q, " USING %s ADD\n    ",
   14783             :                           fmtId(amname));
   14784             : 
   14785         100 :         needComma = false;
   14786             : 
   14787             :         /*
   14788             :          * Now fetch and print the OPERATOR entries (pg_amop rows).
   14789             :          */
   14790         100 :         ntups = PQntuples(res_ops);
   14791             : 
   14792         100 :         i_amopstrategy = PQfnumber(res_ops, "amopstrategy");
   14793         100 :         i_amopopr = PQfnumber(res_ops, "amopopr");
   14794         100 :         i_sortfamily = PQfnumber(res_ops, "sortfamily");
   14795         100 :         i_sortfamilynsp = PQfnumber(res_ops, "sortfamilynsp");
   14796             : 
   14797         450 :         for (i = 0; i < ntups; i++)
   14798             :         {
   14799         350 :             amopstrategy = PQgetvalue(res_ops, i, i_amopstrategy);
   14800         350 :             amopopr = PQgetvalue(res_ops, i, i_amopopr);
   14801         350 :             sortfamily = PQgetvalue(res_ops, i, i_sortfamily);
   14802         350 :             sortfamilynsp = PQgetvalue(res_ops, i, i_sortfamilynsp);
   14803             : 
   14804         350 :             if (needComma)
   14805         280 :                 appendPQExpBufferStr(q, " ,\n    ");
   14806             : 
   14807         350 :             appendPQExpBuffer(q, "OPERATOR %s %s",
   14808             :                               amopstrategy, amopopr);
   14809             : 
   14810         350 :             if (strlen(sortfamily) > 0)
   14811             :             {
   14812           0 :                 appendPQExpBufferStr(q, " FOR ORDER BY ");
   14813           0 :                 appendPQExpBuffer(q, "%s.", fmtId(sortfamilynsp));
   14814           0 :                 appendPQExpBufferStr(q, fmtId(sortfamily));
   14815             :             }
   14816             : 
   14817         350 :             needComma = true;
   14818             :         }
   14819             : 
   14820             :         /*
   14821             :          * Now fetch and print the FUNCTION entries (pg_amproc rows).
   14822             :          */
   14823         100 :         ntups = PQntuples(res_procs);
   14824             : 
   14825         100 :         i_amprocnum = PQfnumber(res_procs, "amprocnum");
   14826         100 :         i_amproc = PQfnumber(res_procs, "amproc");
   14827         100 :         i_amproclefttype = PQfnumber(res_procs, "amproclefttype");
   14828         100 :         i_amprocrighttype = PQfnumber(res_procs, "amprocrighttype");
   14829             : 
   14830         480 :         for (i = 0; i < ntups; i++)
   14831             :         {
   14832         380 :             amprocnum = PQgetvalue(res_procs, i, i_amprocnum);
   14833         380 :             amproc = PQgetvalue(res_procs, i, i_amproc);
   14834         380 :             amproclefttype = PQgetvalue(res_procs, i, i_amproclefttype);
   14835         380 :             amprocrighttype = PQgetvalue(res_procs, i, i_amprocrighttype);
   14836             : 
   14837         380 :             if (needComma)
   14838         350 :                 appendPQExpBufferStr(q, " ,\n    ");
   14839             : 
   14840         380 :             appendPQExpBuffer(q, "FUNCTION %s (%s, %s) %s",
   14841             :                               amprocnum, amproclefttype, amprocrighttype,
   14842             :                               amproc);
   14843             : 
   14844         380 :             needComma = true;
   14845             :         }
   14846             : 
   14847         100 :         appendPQExpBufferStr(q, ";\n");
   14848             :     }
   14849             : 
   14850        1086 :     appendPQExpBufferStr(nameusing, fmtId(opfinfo->dobj.name));
   14851        1086 :     appendPQExpBuffer(nameusing, " USING %s",
   14852             :                       fmtId(amname));
   14853             : 
   14854        1086 :     if (dopt->binary_upgrade)
   14855          18 :         binary_upgrade_extension_member(q, &opfinfo->dobj,
   14856          18 :                                         "OPERATOR FAMILY", nameusing->data,
   14857          18 :                                         opfinfo->dobj.namespace->dobj.name);
   14858             : 
   14859        1086 :     if (opfinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   14860        1086 :         ArchiveEntry(fout, opfinfo->dobj.catId, opfinfo->dobj.dumpId,
   14861        1086 :                      ARCHIVE_OPTS(.tag = opfinfo->dobj.name,
   14862             :                                   .namespace = opfinfo->dobj.namespace->dobj.name,
   14863             :                                   .owner = opfinfo->rolname,
   14864             :                                   .description = "OPERATOR FAMILY",
   14865             :                                   .section = SECTION_PRE_DATA,
   14866             :                                   .createStmt = q->data,
   14867             :                                   .dropStmt = delq->data));
   14868             : 
   14869             :     /* Dump Operator Family Comments */
   14870        1086 :     if (opfinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   14871           0 :         dumpComment(fout, "OPERATOR FAMILY", nameusing->data,
   14872           0 :                     opfinfo->dobj.namespace->dobj.name, opfinfo->rolname,
   14873           0 :                     opfinfo->dobj.catId, 0, opfinfo->dobj.dumpId);
   14874             : 
   14875        1086 :     free(amname);
   14876        1086 :     PQclear(res_ops);
   14877        1086 :     PQclear(res_procs);
   14878        1086 :     destroyPQExpBuffer(query);
   14879        1086 :     destroyPQExpBuffer(q);
   14880        1086 :     destroyPQExpBuffer(delq);
   14881        1086 :     destroyPQExpBuffer(nameusing);
   14882             : }
   14883             : 
   14884             : /*
   14885             :  * dumpCollation
   14886             :  *    write out a single collation definition
   14887             :  */
   14888             : static void
   14889        5086 : dumpCollation(Archive *fout, const CollInfo *collinfo)
   14890             : {
   14891        5086 :     DumpOptions *dopt = fout->dopt;
   14892             :     PQExpBuffer query;
   14893             :     PQExpBuffer q;
   14894             :     PQExpBuffer delq;
   14895             :     char       *qcollname;
   14896             :     PGresult   *res;
   14897             :     int         i_collprovider;
   14898             :     int         i_collisdeterministic;
   14899             :     int         i_collcollate;
   14900             :     int         i_collctype;
   14901             :     int         i_colllocale;
   14902             :     int         i_collicurules;
   14903             :     const char *collprovider;
   14904             :     const char *collcollate;
   14905             :     const char *collctype;
   14906             :     const char *colllocale;
   14907             :     const char *collicurules;
   14908             : 
   14909             :     /* Do nothing if not dumping schema */
   14910        5086 :     if (!dopt->dumpSchema)
   14911          24 :         return;
   14912             : 
   14913        5062 :     query = createPQExpBuffer();
   14914        5062 :     q = createPQExpBuffer();
   14915        5062 :     delq = createPQExpBuffer();
   14916             : 
   14917        5062 :     qcollname = pg_strdup(fmtId(collinfo->dobj.name));
   14918             : 
   14919             :     /* Get collation-specific details */
   14920        5062 :     appendPQExpBufferStr(query, "SELECT ");
   14921             : 
   14922        5062 :     if (fout->remoteVersion >= 100000)
   14923        5062 :         appendPQExpBufferStr(query,
   14924             :                              "collprovider, "
   14925             :                              "collversion, ");
   14926             :     else
   14927           0 :         appendPQExpBufferStr(query,
   14928             :                              "'c' AS collprovider, "
   14929             :                              "NULL AS collversion, ");
   14930             : 
   14931        5062 :     if (fout->remoteVersion >= 120000)
   14932        5062 :         appendPQExpBufferStr(query,
   14933             :                              "collisdeterministic, ");
   14934             :     else
   14935           0 :         appendPQExpBufferStr(query,
   14936             :                              "true AS collisdeterministic, ");
   14937             : 
   14938        5062 :     if (fout->remoteVersion >= 170000)
   14939        5062 :         appendPQExpBufferStr(query,
   14940             :                              "colllocale, ");
   14941           0 :     else if (fout->remoteVersion >= 150000)
   14942           0 :         appendPQExpBufferStr(query,
   14943             :                              "colliculocale AS colllocale, ");
   14944             :     else
   14945           0 :         appendPQExpBufferStr(query,
   14946             :                              "NULL AS colllocale, ");
   14947             : 
   14948        5062 :     if (fout->remoteVersion >= 160000)
   14949        5062 :         appendPQExpBufferStr(query,
   14950             :                              "collicurules, ");
   14951             :     else
   14952           0 :         appendPQExpBufferStr(query,
   14953             :                              "NULL AS collicurules, ");
   14954             : 
   14955        5062 :     appendPQExpBuffer(query,
   14956             :                       "collcollate, "
   14957             :                       "collctype "
   14958             :                       "FROM pg_catalog.pg_collation c "
   14959             :                       "WHERE c.oid = '%u'::pg_catalog.oid",
   14960        5062 :                       collinfo->dobj.catId.oid);
   14961             : 
   14962        5062 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   14963             : 
   14964        5062 :     i_collprovider = PQfnumber(res, "collprovider");
   14965        5062 :     i_collisdeterministic = PQfnumber(res, "collisdeterministic");
   14966        5062 :     i_collcollate = PQfnumber(res, "collcollate");
   14967        5062 :     i_collctype = PQfnumber(res, "collctype");
   14968        5062 :     i_colllocale = PQfnumber(res, "colllocale");
   14969        5062 :     i_collicurules = PQfnumber(res, "collicurules");
   14970             : 
   14971        5062 :     collprovider = PQgetvalue(res, 0, i_collprovider);
   14972             : 
   14973        5062 :     if (!PQgetisnull(res, 0, i_collcollate))
   14974          98 :         collcollate = PQgetvalue(res, 0, i_collcollate);
   14975             :     else
   14976        4964 :         collcollate = NULL;
   14977             : 
   14978        5062 :     if (!PQgetisnull(res, 0, i_collctype))
   14979          98 :         collctype = PQgetvalue(res, 0, i_collctype);
   14980             :     else
   14981        4964 :         collctype = NULL;
   14982             : 
   14983             :     /*
   14984             :      * Before version 15, collcollate and collctype were of type NAME and
   14985             :      * non-nullable. Treat empty strings as NULL for consistency.
   14986             :      */
   14987        5062 :     if (fout->remoteVersion < 150000)
   14988             :     {
   14989           0 :         if (collcollate[0] == '\0')
   14990           0 :             collcollate = NULL;
   14991           0 :         if (collctype[0] == '\0')
   14992           0 :             collctype = NULL;
   14993             :     }
   14994             : 
   14995        5062 :     if (!PQgetisnull(res, 0, i_colllocale))
   14996        4958 :         colllocale = PQgetvalue(res, 0, i_colllocale);
   14997             :     else
   14998         104 :         colllocale = NULL;
   14999             : 
   15000        5062 :     if (!PQgetisnull(res, 0, i_collicurules))
   15001           0 :         collicurules = PQgetvalue(res, 0, i_collicurules);
   15002             :     else
   15003        5062 :         collicurules = NULL;
   15004             : 
   15005        5062 :     appendPQExpBuffer(delq, "DROP COLLATION %s;\n",
   15006        5062 :                       fmtQualifiedDumpable(collinfo));
   15007             : 
   15008        5062 :     appendPQExpBuffer(q, "CREATE COLLATION %s (",
   15009        5062 :                       fmtQualifiedDumpable(collinfo));
   15010             : 
   15011        5062 :     appendPQExpBufferStr(q, "provider = ");
   15012        5062 :     if (collprovider[0] == 'b')
   15013          38 :         appendPQExpBufferStr(q, "builtin");
   15014        5024 :     else if (collprovider[0] == 'c')
   15015          98 :         appendPQExpBufferStr(q, "libc");
   15016        4926 :     else if (collprovider[0] == 'i')
   15017        4920 :         appendPQExpBufferStr(q, "icu");
   15018           6 :     else if (collprovider[0] == 'd')
   15019             :         /* to allow dumping pg_catalog; not accepted on input */
   15020           6 :         appendPQExpBufferStr(q, "default");
   15021             :     else
   15022           0 :         pg_fatal("unrecognized collation provider: %s",
   15023             :                  collprovider);
   15024             : 
   15025        5062 :     if (strcmp(PQgetvalue(res, 0, i_collisdeterministic), "f") == 0)
   15026           0 :         appendPQExpBufferStr(q, ", deterministic = false");
   15027             : 
   15028        5062 :     if (collprovider[0] == 'd')
   15029             :     {
   15030           6 :         if (collcollate || collctype || colllocale || collicurules)
   15031           0 :             pg_log_warning("invalid collation \"%s\"", qcollname);
   15032             : 
   15033             :         /* no locale -- the default collation cannot be reloaded anyway */
   15034             :     }
   15035        5056 :     else if (collprovider[0] == 'b')
   15036             :     {
   15037          38 :         if (collcollate || collctype || !colllocale || collicurules)
   15038           0 :             pg_log_warning("invalid collation \"%s\"", qcollname);
   15039             : 
   15040          38 :         appendPQExpBufferStr(q, ", locale = ");
   15041          38 :         appendStringLiteralAH(q, colllocale ? colllocale : "",
   15042             :                               fout);
   15043             :     }
   15044        5018 :     else if (collprovider[0] == 'i')
   15045             :     {
   15046        4920 :         if (fout->remoteVersion >= 150000)
   15047             :         {
   15048        4920 :             if (collcollate || collctype || !colllocale)
   15049           0 :                 pg_log_warning("invalid collation \"%s\"", qcollname);
   15050             : 
   15051        4920 :             appendPQExpBufferStr(q, ", locale = ");
   15052        4920 :             appendStringLiteralAH(q, colllocale ? colllocale : "",
   15053             :                                   fout);
   15054             :         }
   15055             :         else
   15056             :         {
   15057           0 :             if (!collcollate || !collctype || colllocale ||
   15058           0 :                 strcmp(collcollate, collctype) != 0)
   15059           0 :                 pg_log_warning("invalid collation \"%s\"", qcollname);
   15060             : 
   15061           0 :             appendPQExpBufferStr(q, ", locale = ");
   15062           0 :             appendStringLiteralAH(q, collcollate ? collcollate : "", fout);
   15063             :         }
   15064             : 
   15065        4920 :         if (collicurules)
   15066             :         {
   15067           0 :             appendPQExpBufferStr(q, ", rules = ");
   15068           0 :             appendStringLiteralAH(q, collicurules ? collicurules : "", fout);
   15069             :         }
   15070             :     }
   15071          98 :     else if (collprovider[0] == 'c')
   15072             :     {
   15073          98 :         if (colllocale || collicurules || !collcollate || !collctype)
   15074           0 :             pg_log_warning("invalid collation \"%s\"", qcollname);
   15075             : 
   15076          98 :         if (collcollate && collctype && strcmp(collcollate, collctype) == 0)
   15077             :         {
   15078          98 :             appendPQExpBufferStr(q, ", locale = ");
   15079          98 :             appendStringLiteralAH(q, collcollate ? collcollate : "", fout);
   15080             :         }
   15081             :         else
   15082             :         {
   15083           0 :             appendPQExpBufferStr(q, ", lc_collate = ");
   15084           0 :             appendStringLiteralAH(q, collcollate ? collcollate : "", fout);
   15085           0 :             appendPQExpBufferStr(q, ", lc_ctype = ");
   15086           0 :             appendStringLiteralAH(q, collctype ? collctype : "", fout);
   15087             :         }
   15088             :     }
   15089             :     else
   15090           0 :         pg_fatal("unrecognized collation provider: %s", collprovider);
   15091             : 
   15092             :     /*
   15093             :      * For binary upgrade, carry over the collation version.  For normal
   15094             :      * dump/restore, omit the version, so that it is computed upon restore.
   15095             :      */
   15096        5062 :     if (dopt->binary_upgrade)
   15097             :     {
   15098             :         int         i_collversion;
   15099             : 
   15100          10 :         i_collversion = PQfnumber(res, "collversion");
   15101          10 :         if (!PQgetisnull(res, 0, i_collversion))
   15102             :         {
   15103           8 :             appendPQExpBufferStr(q, ", version = ");
   15104           8 :             appendStringLiteralAH(q,
   15105             :                                   PQgetvalue(res, 0, i_collversion),
   15106             :                                   fout);
   15107             :         }
   15108             :     }
   15109             : 
   15110        5062 :     appendPQExpBufferStr(q, ");\n");
   15111             : 
   15112        5062 :     if (dopt->binary_upgrade)
   15113          10 :         binary_upgrade_extension_member(q, &collinfo->dobj,
   15114             :                                         "COLLATION", qcollname,
   15115          10 :                                         collinfo->dobj.namespace->dobj.name);
   15116             : 
   15117        5062 :     if (collinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   15118        5062 :         ArchiveEntry(fout, collinfo->dobj.catId, collinfo->dobj.dumpId,
   15119        5062 :                      ARCHIVE_OPTS(.tag = collinfo->dobj.name,
   15120             :                                   .namespace = collinfo->dobj.namespace->dobj.name,
   15121             :                                   .owner = collinfo->rolname,
   15122             :                                   .description = "COLLATION",
   15123             :                                   .section = SECTION_PRE_DATA,
   15124             :                                   .createStmt = q->data,
   15125             :                                   .dropStmt = delq->data));
   15126             : 
   15127             :     /* Dump Collation Comments */
   15128        5062 :     if (collinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   15129        4868 :         dumpComment(fout, "COLLATION", qcollname,
   15130        4868 :                     collinfo->dobj.namespace->dobj.name, collinfo->rolname,
   15131        4868 :                     collinfo->dobj.catId, 0, collinfo->dobj.dumpId);
   15132             : 
   15133        5062 :     PQclear(res);
   15134             : 
   15135        5062 :     destroyPQExpBuffer(query);
   15136        5062 :     destroyPQExpBuffer(q);
   15137        5062 :     destroyPQExpBuffer(delq);
   15138        5062 :     free(qcollname);
   15139             : }
   15140             : 
   15141             : /*
   15142             :  * dumpConversion
   15143             :  *    write out a single conversion definition
   15144             :  */
   15145             : static void
   15146         850 : dumpConversion(Archive *fout, const ConvInfo *convinfo)
   15147             : {
   15148         850 :     DumpOptions *dopt = fout->dopt;
   15149             :     PQExpBuffer query;
   15150             :     PQExpBuffer q;
   15151             :     PQExpBuffer delq;
   15152             :     char       *qconvname;
   15153             :     PGresult   *res;
   15154             :     int         i_conforencoding;
   15155             :     int         i_contoencoding;
   15156             :     int         i_conproc;
   15157             :     int         i_condefault;
   15158             :     const char *conforencoding;
   15159             :     const char *contoencoding;
   15160             :     const char *conproc;
   15161             :     bool        condefault;
   15162             : 
   15163             :     /* Do nothing if not dumping schema */
   15164         850 :     if (!dopt->dumpSchema)
   15165          12 :         return;
   15166             : 
   15167         838 :     query = createPQExpBuffer();
   15168         838 :     q = createPQExpBuffer();
   15169         838 :     delq = createPQExpBuffer();
   15170             : 
   15171         838 :     qconvname = pg_strdup(fmtId(convinfo->dobj.name));
   15172             : 
   15173             :     /* Get conversion-specific details */
   15174         838 :     appendPQExpBuffer(query, "SELECT "
   15175             :                       "pg_catalog.pg_encoding_to_char(conforencoding) AS conforencoding, "
   15176             :                       "pg_catalog.pg_encoding_to_char(contoencoding) AS contoencoding, "
   15177             :                       "conproc, condefault "
   15178             :                       "FROM pg_catalog.pg_conversion c "
   15179             :                       "WHERE c.oid = '%u'::pg_catalog.oid",
   15180         838 :                       convinfo->dobj.catId.oid);
   15181             : 
   15182         838 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   15183             : 
   15184         838 :     i_conforencoding = PQfnumber(res, "conforencoding");
   15185         838 :     i_contoencoding = PQfnumber(res, "contoencoding");
   15186         838 :     i_conproc = PQfnumber(res, "conproc");
   15187         838 :     i_condefault = PQfnumber(res, "condefault");
   15188             : 
   15189         838 :     conforencoding = PQgetvalue(res, 0, i_conforencoding);
   15190         838 :     contoencoding = PQgetvalue(res, 0, i_contoencoding);
   15191         838 :     conproc = PQgetvalue(res, 0, i_conproc);
   15192         838 :     condefault = (PQgetvalue(res, 0, i_condefault)[0] == 't');
   15193             : 
   15194         838 :     appendPQExpBuffer(delq, "DROP CONVERSION %s;\n",
   15195         838 :                       fmtQualifiedDumpable(convinfo));
   15196             : 
   15197         838 :     appendPQExpBuffer(q, "CREATE %sCONVERSION %s FOR ",
   15198             :                       (condefault) ? "DEFAULT " : "",
   15199         838 :                       fmtQualifiedDumpable(convinfo));
   15200         838 :     appendStringLiteralAH(q, conforencoding, fout);
   15201         838 :     appendPQExpBufferStr(q, " TO ");
   15202         838 :     appendStringLiteralAH(q, contoencoding, fout);
   15203             :     /* regproc output is already sufficiently quoted */
   15204         838 :     appendPQExpBuffer(q, " FROM %s;\n", conproc);
   15205             : 
   15206         838 :     if (dopt->binary_upgrade)
   15207           2 :         binary_upgrade_extension_member(q, &convinfo->dobj,
   15208             :                                         "CONVERSION", qconvname,
   15209           2 :                                         convinfo->dobj.namespace->dobj.name);
   15210             : 
   15211         838 :     if (convinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   15212         838 :         ArchiveEntry(fout, convinfo->dobj.catId, convinfo->dobj.dumpId,
   15213         838 :                      ARCHIVE_OPTS(.tag = convinfo->dobj.name,
   15214             :                                   .namespace = convinfo->dobj.namespace->dobj.name,
   15215             :                                   .owner = convinfo->rolname,
   15216             :                                   .description = "CONVERSION",
   15217             :                                   .section = SECTION_PRE_DATA,
   15218             :                                   .createStmt = q->data,
   15219             :                                   .dropStmt = delq->data));
   15220             : 
   15221             :     /* Dump Conversion Comments */
   15222         838 :     if (convinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   15223         838 :         dumpComment(fout, "CONVERSION", qconvname,
   15224         838 :                     convinfo->dobj.namespace->dobj.name, convinfo->rolname,
   15225         838 :                     convinfo->dobj.catId, 0, convinfo->dobj.dumpId);
   15226             : 
   15227         838 :     PQclear(res);
   15228             : 
   15229         838 :     destroyPQExpBuffer(query);
   15230         838 :     destroyPQExpBuffer(q);
   15231         838 :     destroyPQExpBuffer(delq);
   15232         838 :     free(qconvname);
   15233             : }
   15234             : 
   15235             : /*
   15236             :  * format_aggregate_signature: generate aggregate name and argument list
   15237             :  *
   15238             :  * The argument type names are qualified if needed.  The aggregate name
   15239             :  * is never qualified.
   15240             :  */
   15241             : static char *
   15242         576 : format_aggregate_signature(const AggInfo *agginfo, Archive *fout, bool honor_quotes)
   15243             : {
   15244             :     PQExpBufferData buf;
   15245             :     int         j;
   15246             : 
   15247         576 :     initPQExpBuffer(&buf);
   15248         576 :     if (honor_quotes)
   15249           0 :         appendPQExpBufferStr(&buf, fmtId(agginfo->aggfn.dobj.name));
   15250             :     else
   15251         576 :         appendPQExpBufferStr(&buf, agginfo->aggfn.dobj.name);
   15252             : 
   15253         576 :     if (agginfo->aggfn.nargs == 0)
   15254          80 :         appendPQExpBufferStr(&buf, "(*)");
   15255             :     else
   15256             :     {
   15257         496 :         appendPQExpBufferChar(&buf, '(');
   15258        1082 :         for (j = 0; j < agginfo->aggfn.nargs; j++)
   15259         586 :             appendPQExpBuffer(&buf, "%s%s",
   15260             :                               (j > 0) ? ", " : "",
   15261             :                               getFormattedTypeName(fout,
   15262         586 :                                                    agginfo->aggfn.argtypes[j],
   15263             :                                                    zeroIsError));
   15264         496 :         appendPQExpBufferChar(&buf, ')');
   15265             :     }
   15266         576 :     return buf.data;
   15267             : }
   15268             : 
   15269             : /*
   15270             :  * dumpAgg
   15271             :  *    write out a single aggregate definition
   15272             :  */
   15273             : static void
   15274         590 : dumpAgg(Archive *fout, const AggInfo *agginfo)
   15275             : {
   15276         590 :     DumpOptions *dopt = fout->dopt;
   15277             :     PQExpBuffer query;
   15278             :     PQExpBuffer q;
   15279             :     PQExpBuffer delq;
   15280             :     PQExpBuffer details;
   15281             :     char       *aggsig;         /* identity signature */
   15282         590 :     char       *aggfullsig = NULL;  /* full signature */
   15283             :     char       *aggsig_tag;
   15284             :     PGresult   *res;
   15285             :     int         i_agginitval;
   15286             :     int         i_aggminitval;
   15287             :     const char *aggtransfn;
   15288             :     const char *aggfinalfn;
   15289             :     const char *aggcombinefn;
   15290             :     const char *aggserialfn;
   15291             :     const char *aggdeserialfn;
   15292             :     const char *aggmtransfn;
   15293             :     const char *aggminvtransfn;
   15294             :     const char *aggmfinalfn;
   15295             :     bool        aggfinalextra;
   15296             :     bool        aggmfinalextra;
   15297             :     char        aggfinalmodify;
   15298             :     char        aggmfinalmodify;
   15299             :     const char *aggsortop;
   15300             :     char       *aggsortconvop;
   15301             :     char        aggkind;
   15302             :     const char *aggtranstype;
   15303             :     const char *aggtransspace;
   15304             :     const char *aggmtranstype;
   15305             :     const char *aggmtransspace;
   15306             :     const char *agginitval;
   15307             :     const char *aggminitval;
   15308             :     const char *proparallel;
   15309             :     char        defaultfinalmodify;
   15310             : 
   15311             :     /* Do nothing if not dumping schema */
   15312         590 :     if (!dopt->dumpSchema)
   15313          14 :         return;
   15314             : 
   15315         576 :     query = createPQExpBuffer();
   15316         576 :     q = createPQExpBuffer();
   15317         576 :     delq = createPQExpBuffer();
   15318         576 :     details = createPQExpBuffer();
   15319             : 
   15320         576 :     if (!fout->is_prepared[PREPQUERY_DUMPAGG])
   15321             :     {
   15322             :         /* Set up query for aggregate-specific details */
   15323         116 :         appendPQExpBufferStr(query,
   15324             :                              "PREPARE dumpAgg(pg_catalog.oid) AS\n");
   15325             : 
   15326         116 :         appendPQExpBufferStr(query,
   15327             :                              "SELECT "
   15328             :                              "aggtransfn,\n"
   15329             :                              "aggfinalfn,\n"
   15330             :                              "aggtranstype::pg_catalog.regtype,\n"
   15331             :                              "agginitval,\n"
   15332             :                              "aggsortop,\n"
   15333             :                              "pg_catalog.pg_get_function_arguments(p.oid) AS funcargs,\n"
   15334             :                              "pg_catalog.pg_get_function_identity_arguments(p.oid) AS funciargs,\n");
   15335             : 
   15336         116 :         if (fout->remoteVersion >= 90400)
   15337         116 :             appendPQExpBufferStr(query,
   15338             :                                  "aggkind,\n"
   15339             :                                  "aggmtransfn,\n"
   15340             :                                  "aggminvtransfn,\n"
   15341             :                                  "aggmfinalfn,\n"
   15342             :                                  "aggmtranstype::pg_catalog.regtype,\n"
   15343             :                                  "aggfinalextra,\n"
   15344             :                                  "aggmfinalextra,\n"
   15345             :                                  "aggtransspace,\n"
   15346             :                                  "aggmtransspace,\n"
   15347             :                                  "aggminitval,\n");
   15348             :         else
   15349           0 :             appendPQExpBufferStr(query,
   15350             :                                  "'n' AS aggkind,\n"
   15351             :                                  "'-' AS aggmtransfn,\n"
   15352             :                                  "'-' AS aggminvtransfn,\n"
   15353             :                                  "'-' AS aggmfinalfn,\n"
   15354             :                                  "0 AS aggmtranstype,\n"
   15355             :                                  "false AS aggfinalextra,\n"
   15356             :                                  "false AS aggmfinalextra,\n"
   15357             :                                  "0 AS aggtransspace,\n"
   15358             :                                  "0 AS aggmtransspace,\n"
   15359             :                                  "NULL AS aggminitval,\n");
   15360             : 
   15361         116 :         if (fout->remoteVersion >= 90600)
   15362         116 :             appendPQExpBufferStr(query,
   15363             :                                  "aggcombinefn,\n"
   15364             :                                  "aggserialfn,\n"
   15365             :                                  "aggdeserialfn,\n"
   15366             :                                  "proparallel,\n");
   15367             :         else
   15368           0 :             appendPQExpBufferStr(query,
   15369             :                                  "'-' AS aggcombinefn,\n"
   15370             :                                  "'-' AS aggserialfn,\n"
   15371             :                                  "'-' AS aggdeserialfn,\n"
   15372             :                                  "'u' AS proparallel,\n");
   15373             : 
   15374         116 :         if (fout->remoteVersion >= 110000)
   15375         116 :             appendPQExpBufferStr(query,
   15376             :                                  "aggfinalmodify,\n"
   15377             :                                  "aggmfinalmodify\n");
   15378             :         else
   15379           0 :             appendPQExpBufferStr(query,
   15380             :                                  "'0' AS aggfinalmodify,\n"
   15381             :                                  "'0' AS aggmfinalmodify\n");
   15382             : 
   15383         116 :         appendPQExpBufferStr(query,
   15384             :                              "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
   15385             :                              "WHERE a.aggfnoid = p.oid "
   15386             :                              "AND p.oid = $1");
   15387             : 
   15388         116 :         ExecuteSqlStatement(fout, query->data);
   15389             : 
   15390         116 :         fout->is_prepared[PREPQUERY_DUMPAGG] = true;
   15391             :     }
   15392             : 
   15393         576 :     printfPQExpBuffer(query,
   15394             :                       "EXECUTE dumpAgg('%u')",
   15395         576 :                       agginfo->aggfn.dobj.catId.oid);
   15396             : 
   15397         576 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   15398             : 
   15399         576 :     i_agginitval = PQfnumber(res, "agginitval");
   15400         576 :     i_aggminitval = PQfnumber(res, "aggminitval");
   15401             : 
   15402         576 :     aggtransfn = PQgetvalue(res, 0, PQfnumber(res, "aggtransfn"));
   15403         576 :     aggfinalfn = PQgetvalue(res, 0, PQfnumber(res, "aggfinalfn"));
   15404         576 :     aggcombinefn = PQgetvalue(res, 0, PQfnumber(res, "aggcombinefn"));
   15405         576 :     aggserialfn = PQgetvalue(res, 0, PQfnumber(res, "aggserialfn"));
   15406         576 :     aggdeserialfn = PQgetvalue(res, 0, PQfnumber(res, "aggdeserialfn"));
   15407         576 :     aggmtransfn = PQgetvalue(res, 0, PQfnumber(res, "aggmtransfn"));
   15408         576 :     aggminvtransfn = PQgetvalue(res, 0, PQfnumber(res, "aggminvtransfn"));
   15409         576 :     aggmfinalfn = PQgetvalue(res, 0, PQfnumber(res, "aggmfinalfn"));
   15410         576 :     aggfinalextra = (PQgetvalue(res, 0, PQfnumber(res, "aggfinalextra"))[0] == 't');
   15411         576 :     aggmfinalextra = (PQgetvalue(res, 0, PQfnumber(res, "aggmfinalextra"))[0] == 't');
   15412         576 :     aggfinalmodify = PQgetvalue(res, 0, PQfnumber(res, "aggfinalmodify"))[0];
   15413         576 :     aggmfinalmodify = PQgetvalue(res, 0, PQfnumber(res, "aggmfinalmodify"))[0];
   15414         576 :     aggsortop = PQgetvalue(res, 0, PQfnumber(res, "aggsortop"));
   15415         576 :     aggkind = PQgetvalue(res, 0, PQfnumber(res, "aggkind"))[0];
   15416         576 :     aggtranstype = PQgetvalue(res, 0, PQfnumber(res, "aggtranstype"));
   15417         576 :     aggtransspace = PQgetvalue(res, 0, PQfnumber(res, "aggtransspace"));
   15418         576 :     aggmtranstype = PQgetvalue(res, 0, PQfnumber(res, "aggmtranstype"));
   15419         576 :     aggmtransspace = PQgetvalue(res, 0, PQfnumber(res, "aggmtransspace"));
   15420         576 :     agginitval = PQgetvalue(res, 0, i_agginitval);
   15421         576 :     aggminitval = PQgetvalue(res, 0, i_aggminitval);
   15422         576 :     proparallel = PQgetvalue(res, 0, PQfnumber(res, "proparallel"));
   15423             : 
   15424             :     {
   15425             :         char       *funcargs;
   15426             :         char       *funciargs;
   15427             : 
   15428         576 :         funcargs = PQgetvalue(res, 0, PQfnumber(res, "funcargs"));
   15429         576 :         funciargs = PQgetvalue(res, 0, PQfnumber(res, "funciargs"));
   15430         576 :         aggfullsig = format_function_arguments(&agginfo->aggfn, funcargs, true);
   15431         576 :         aggsig = format_function_arguments(&agginfo->aggfn, funciargs, true);
   15432             :     }
   15433             : 
   15434         576 :     aggsig_tag = format_aggregate_signature(agginfo, fout, false);
   15435             : 
   15436             :     /* identify default modify flag for aggkind (must match DefineAggregate) */
   15437         576 :     defaultfinalmodify = (aggkind == AGGKIND_NORMAL) ? AGGMODIFY_READ_ONLY : AGGMODIFY_READ_WRITE;
   15438             :     /* replace omitted flags for old versions */
   15439         576 :     if (aggfinalmodify == '0')
   15440           0 :         aggfinalmodify = defaultfinalmodify;
   15441         576 :     if (aggmfinalmodify == '0')
   15442           0 :         aggmfinalmodify = defaultfinalmodify;
   15443             : 
   15444             :     /* regproc and regtype output is already sufficiently quoted */
   15445         576 :     appendPQExpBuffer(details, "    SFUNC = %s,\n    STYPE = %s",
   15446             :                       aggtransfn, aggtranstype);
   15447             : 
   15448         576 :     if (strcmp(aggtransspace, "0") != 0)
   15449             :     {
   15450          10 :         appendPQExpBuffer(details, ",\n    SSPACE = %s",
   15451             :                           aggtransspace);
   15452             :     }
   15453             : 
   15454         576 :     if (!PQgetisnull(res, 0, i_agginitval))
   15455             :     {
   15456         420 :         appendPQExpBufferStr(details, ",\n    INITCOND = ");
   15457         420 :         appendStringLiteralAH(details, agginitval, fout);
   15458             :     }
   15459             : 
   15460         576 :     if (strcmp(aggfinalfn, "-") != 0)
   15461             :     {
   15462         270 :         appendPQExpBuffer(details, ",\n    FINALFUNC = %s",
   15463             :                           aggfinalfn);
   15464         270 :         if (aggfinalextra)
   15465          20 :             appendPQExpBufferStr(details, ",\n    FINALFUNC_EXTRA");
   15466         270 :         if (aggfinalmodify != defaultfinalmodify)
   15467             :         {
   15468          70 :             switch (aggfinalmodify)
   15469             :             {
   15470           0 :                 case AGGMODIFY_READ_ONLY:
   15471           0 :                     appendPQExpBufferStr(details, ",\n    FINALFUNC_MODIFY = READ_ONLY");
   15472           0 :                     break;
   15473          70 :                 case AGGMODIFY_SHAREABLE:
   15474          70 :                     appendPQExpBufferStr(details, ",\n    FINALFUNC_MODIFY = SHAREABLE");
   15475          70 :                     break;
   15476           0 :                 case AGGMODIFY_READ_WRITE:
   15477           0 :                     appendPQExpBufferStr(details, ",\n    FINALFUNC_MODIFY = READ_WRITE");
   15478           0 :                     break;
   15479           0 :                 default:
   15480           0 :                     pg_fatal("unrecognized aggfinalmodify value for aggregate \"%s\"",
   15481             :                              agginfo->aggfn.dobj.name);
   15482             :                     break;
   15483             :             }
   15484             :         }
   15485             :     }
   15486             : 
   15487         576 :     if (strcmp(aggcombinefn, "-") != 0)
   15488           0 :         appendPQExpBuffer(details, ",\n    COMBINEFUNC = %s", aggcombinefn);
   15489             : 
   15490         576 :     if (strcmp(aggserialfn, "-") != 0)
   15491           0 :         appendPQExpBuffer(details, ",\n    SERIALFUNC = %s", aggserialfn);
   15492             : 
   15493         576 :     if (strcmp(aggdeserialfn, "-") != 0)
   15494           0 :         appendPQExpBuffer(details, ",\n    DESERIALFUNC = %s", aggdeserialfn);
   15495             : 
   15496         576 :     if (strcmp(aggmtransfn, "-") != 0)
   15497             :     {
   15498          60 :         appendPQExpBuffer(details, ",\n    MSFUNC = %s,\n    MINVFUNC = %s,\n    MSTYPE = %s",
   15499             :                           aggmtransfn,
   15500             :                           aggminvtransfn,
   15501             :                           aggmtranstype);
   15502             :     }
   15503             : 
   15504         576 :     if (strcmp(aggmtransspace, "0") != 0)
   15505             :     {
   15506           0 :         appendPQExpBuffer(details, ",\n    MSSPACE = %s",
   15507             :                           aggmtransspace);
   15508             :     }
   15509             : 
   15510         576 :     if (!PQgetisnull(res, 0, i_aggminitval))
   15511             :     {
   15512          20 :         appendPQExpBufferStr(details, ",\n    MINITCOND = ");
   15513          20 :         appendStringLiteralAH(details, aggminitval, fout);
   15514             :     }
   15515             : 
   15516         576 :     if (strcmp(aggmfinalfn, "-") != 0)
   15517             :     {
   15518           0 :         appendPQExpBuffer(details, ",\n    MFINALFUNC = %s",
   15519             :                           aggmfinalfn);
   15520           0 :         if (aggmfinalextra)
   15521           0 :             appendPQExpBufferStr(details, ",\n    MFINALFUNC_EXTRA");
   15522           0 :         if (aggmfinalmodify != defaultfinalmodify)
   15523             :         {
   15524           0 :             switch (aggmfinalmodify)
   15525             :             {
   15526           0 :                 case AGGMODIFY_READ_ONLY:
   15527           0 :                     appendPQExpBufferStr(details, ",\n    MFINALFUNC_MODIFY = READ_ONLY");
   15528           0 :                     break;
   15529           0 :                 case AGGMODIFY_SHAREABLE:
   15530           0 :                     appendPQExpBufferStr(details, ",\n    MFINALFUNC_MODIFY = SHAREABLE");
   15531           0 :                     break;
   15532           0 :                 case AGGMODIFY_READ_WRITE:
   15533           0 :                     appendPQExpBufferStr(details, ",\n    MFINALFUNC_MODIFY = READ_WRITE");
   15534           0 :                     break;
   15535           0 :                 default:
   15536           0 :                     pg_fatal("unrecognized aggmfinalmodify value for aggregate \"%s\"",
   15537             :                              agginfo->aggfn.dobj.name);
   15538             :                     break;
   15539             :             }
   15540             :         }
   15541             :     }
   15542             : 
   15543         576 :     aggsortconvop = getFormattedOperatorName(aggsortop);
   15544         576 :     if (aggsortconvop)
   15545             :     {
   15546           0 :         appendPQExpBuffer(details, ",\n    SORTOP = %s",
   15547             :                           aggsortconvop);
   15548           0 :         free(aggsortconvop);
   15549             :     }
   15550             : 
   15551         576 :     if (aggkind == AGGKIND_HYPOTHETICAL)
   15552          10 :         appendPQExpBufferStr(details, ",\n    HYPOTHETICAL");
   15553             : 
   15554         576 :     if (proparallel[0] != PROPARALLEL_UNSAFE)
   15555             :     {
   15556          10 :         if (proparallel[0] == PROPARALLEL_SAFE)
   15557          10 :             appendPQExpBufferStr(details, ",\n    PARALLEL = safe");
   15558           0 :         else if (proparallel[0] == PROPARALLEL_RESTRICTED)
   15559           0 :             appendPQExpBufferStr(details, ",\n    PARALLEL = restricted");
   15560           0 :         else if (proparallel[0] != PROPARALLEL_UNSAFE)
   15561           0 :             pg_fatal("unrecognized proparallel value for function \"%s\"",
   15562             :                      agginfo->aggfn.dobj.name);
   15563             :     }
   15564             : 
   15565         576 :     appendPQExpBuffer(delq, "DROP AGGREGATE %s.%s;\n",
   15566         576 :                       fmtId(agginfo->aggfn.dobj.namespace->dobj.name),
   15567             :                       aggsig);
   15568             : 
   15569        1152 :     appendPQExpBuffer(q, "CREATE AGGREGATE %s.%s (\n%s\n);\n",
   15570         576 :                       fmtId(agginfo->aggfn.dobj.namespace->dobj.name),
   15571             :                       aggfullsig ? aggfullsig : aggsig, details->data);
   15572             : 
   15573         576 :     if (dopt->binary_upgrade)
   15574          98 :         binary_upgrade_extension_member(q, &agginfo->aggfn.dobj,
   15575             :                                         "AGGREGATE", aggsig,
   15576          98 :                                         agginfo->aggfn.dobj.namespace->dobj.name);
   15577             : 
   15578         576 :     if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_DEFINITION)
   15579         542 :         ArchiveEntry(fout, agginfo->aggfn.dobj.catId,
   15580         542 :                      agginfo->aggfn.dobj.dumpId,
   15581         542 :                      ARCHIVE_OPTS(.tag = aggsig_tag,
   15582             :                                   .namespace = agginfo->aggfn.dobj.namespace->dobj.name,
   15583             :                                   .owner = agginfo->aggfn.rolname,
   15584             :                                   .description = "AGGREGATE",
   15585             :                                   .section = SECTION_PRE_DATA,
   15586             :                                   .createStmt = q->data,
   15587             :                                   .dropStmt = delq->data));
   15588             : 
   15589             :     /* Dump Aggregate Comments */
   15590         576 :     if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_COMMENT)
   15591          20 :         dumpComment(fout, "AGGREGATE", aggsig,
   15592          20 :                     agginfo->aggfn.dobj.namespace->dobj.name,
   15593          20 :                     agginfo->aggfn.rolname,
   15594          20 :                     agginfo->aggfn.dobj.catId, 0, agginfo->aggfn.dobj.dumpId);
   15595             : 
   15596         576 :     if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_SECLABEL)
   15597           0 :         dumpSecLabel(fout, "AGGREGATE", aggsig,
   15598           0 :                      agginfo->aggfn.dobj.namespace->dobj.name,
   15599           0 :                      agginfo->aggfn.rolname,
   15600           0 :                      agginfo->aggfn.dobj.catId, 0, agginfo->aggfn.dobj.dumpId);
   15601             : 
   15602             :     /*
   15603             :      * Since there is no GRANT ON AGGREGATE syntax, we have to make the ACL
   15604             :      * command look like a function's GRANT; in particular this affects the
   15605             :      * syntax for zero-argument aggregates and ordered-set aggregates.
   15606             :      */
   15607         576 :     free(aggsig);
   15608             : 
   15609         576 :     aggsig = format_function_signature(fout, &agginfo->aggfn, true);
   15610             : 
   15611         576 :     if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_ACL)
   15612          36 :         dumpACL(fout, agginfo->aggfn.dobj.dumpId, InvalidDumpId,
   15613             :                 "FUNCTION", aggsig, NULL,
   15614          36 :                 agginfo->aggfn.dobj.namespace->dobj.name,
   15615          36 :                 NULL, agginfo->aggfn.rolname, &agginfo->aggfn.dacl);
   15616             : 
   15617         576 :     free(aggsig);
   15618         576 :     free(aggfullsig);
   15619         576 :     free(aggsig_tag);
   15620             : 
   15621         576 :     PQclear(res);
   15622             : 
   15623         576 :     destroyPQExpBuffer(query);
   15624         576 :     destroyPQExpBuffer(q);
   15625         576 :     destroyPQExpBuffer(delq);
   15626         576 :     destroyPQExpBuffer(details);
   15627             : }
   15628             : 
   15629             : /*
   15630             :  * dumpTSParser
   15631             :  *    write out a single text search parser
   15632             :  */
   15633             : static void
   15634          88 : dumpTSParser(Archive *fout, const TSParserInfo *prsinfo)
   15635             : {
   15636          88 :     DumpOptions *dopt = fout->dopt;
   15637             :     PQExpBuffer q;
   15638             :     PQExpBuffer delq;
   15639             :     char       *qprsname;
   15640             : 
   15641             :     /* Do nothing if not dumping schema */
   15642          88 :     if (!dopt->dumpSchema)
   15643          12 :         return;
   15644             : 
   15645          76 :     q = createPQExpBuffer();
   15646          76 :     delq = createPQExpBuffer();
   15647             : 
   15648          76 :     qprsname = pg_strdup(fmtId(prsinfo->dobj.name));
   15649             : 
   15650          76 :     appendPQExpBuffer(q, "CREATE TEXT SEARCH PARSER %s (\n",
   15651          76 :                       fmtQualifiedDumpable(prsinfo));
   15652             : 
   15653          76 :     appendPQExpBuffer(q, "    START = %s,\n",
   15654          76 :                       convertTSFunction(fout, prsinfo->prsstart));
   15655          76 :     appendPQExpBuffer(q, "    GETTOKEN = %s,\n",
   15656          76 :                       convertTSFunction(fout, prsinfo->prstoken));
   15657          76 :     appendPQExpBuffer(q, "    END = %s,\n",
   15658          76 :                       convertTSFunction(fout, prsinfo->prsend));
   15659          76 :     if (prsinfo->prsheadline != InvalidOid)
   15660           6 :         appendPQExpBuffer(q, "    HEADLINE = %s,\n",
   15661           6 :                           convertTSFunction(fout, prsinfo->prsheadline));
   15662          76 :     appendPQExpBuffer(q, "    LEXTYPES = %s );\n",
   15663          76 :                       convertTSFunction(fout, prsinfo->prslextype));
   15664             : 
   15665          76 :     appendPQExpBuffer(delq, "DROP TEXT SEARCH PARSER %s;\n",
   15666          76 :                       fmtQualifiedDumpable(prsinfo));
   15667             : 
   15668          76 :     if (dopt->binary_upgrade)
   15669           2 :         binary_upgrade_extension_member(q, &prsinfo->dobj,
   15670             :                                         "TEXT SEARCH PARSER", qprsname,
   15671           2 :                                         prsinfo->dobj.namespace->dobj.name);
   15672             : 
   15673          76 :     if (prsinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   15674          76 :         ArchiveEntry(fout, prsinfo->dobj.catId, prsinfo->dobj.dumpId,
   15675          76 :                      ARCHIVE_OPTS(.tag = prsinfo->dobj.name,
   15676             :                                   .namespace = prsinfo->dobj.namespace->dobj.name,
   15677             :                                   .description = "TEXT SEARCH PARSER",
   15678             :                                   .section = SECTION_PRE_DATA,
   15679             :                                   .createStmt = q->data,
   15680             :                                   .dropStmt = delq->data));
   15681             : 
   15682             :     /* Dump Parser Comments */
   15683          76 :     if (prsinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   15684          76 :         dumpComment(fout, "TEXT SEARCH PARSER", qprsname,
   15685          76 :                     prsinfo->dobj.namespace->dobj.name, "",
   15686          76 :                     prsinfo->dobj.catId, 0, prsinfo->dobj.dumpId);
   15687             : 
   15688          76 :     destroyPQExpBuffer(q);
   15689          76 :     destroyPQExpBuffer(delq);
   15690          76 :     free(qprsname);
   15691             : }
   15692             : 
   15693             : /*
   15694             :  * dumpTSDictionary
   15695             :  *    write out a single text search dictionary
   15696             :  */
   15697             : static void
   15698         352 : dumpTSDictionary(Archive *fout, const TSDictInfo *dictinfo)
   15699             : {
   15700         352 :     DumpOptions *dopt = fout->dopt;
   15701             :     PQExpBuffer q;
   15702             :     PQExpBuffer delq;
   15703             :     PQExpBuffer query;
   15704             :     char       *qdictname;
   15705             :     PGresult   *res;
   15706             :     char       *nspname;
   15707             :     char       *tmplname;
   15708             : 
   15709             :     /* Do nothing if not dumping schema */
   15710         352 :     if (!dopt->dumpSchema)
   15711          12 :         return;
   15712             : 
   15713         340 :     q = createPQExpBuffer();
   15714         340 :     delq = createPQExpBuffer();
   15715         340 :     query = createPQExpBuffer();
   15716             : 
   15717         340 :     qdictname = pg_strdup(fmtId(dictinfo->dobj.name));
   15718             : 
   15719             :     /* Fetch name and namespace of the dictionary's template */
   15720         340 :     appendPQExpBuffer(query, "SELECT nspname, tmplname "
   15721             :                       "FROM pg_ts_template p, pg_namespace n "
   15722             :                       "WHERE p.oid = '%u' AND n.oid = tmplnamespace",
   15723         340 :                       dictinfo->dicttemplate);
   15724         340 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   15725         340 :     nspname = PQgetvalue(res, 0, 0);
   15726         340 :     tmplname = PQgetvalue(res, 0, 1);
   15727             : 
   15728         340 :     appendPQExpBuffer(q, "CREATE TEXT SEARCH DICTIONARY %s (\n",
   15729         340 :                       fmtQualifiedDumpable(dictinfo));
   15730             : 
   15731         340 :     appendPQExpBufferStr(q, "    TEMPLATE = ");
   15732         340 :     appendPQExpBuffer(q, "%s.", fmtId(nspname));
   15733         340 :     appendPQExpBufferStr(q, fmtId(tmplname));
   15734             : 
   15735         340 :     PQclear(res);
   15736             : 
   15737             :     /* the dictinitoption can be dumped straight into the command */
   15738         340 :     if (dictinfo->dictinitoption)
   15739         264 :         appendPQExpBuffer(q, ",\n    %s", dictinfo->dictinitoption);
   15740             : 
   15741         340 :     appendPQExpBufferStr(q, " );\n");
   15742             : 
   15743         340 :     appendPQExpBuffer(delq, "DROP TEXT SEARCH DICTIONARY %s;\n",
   15744         340 :                       fmtQualifiedDumpable(dictinfo));
   15745             : 
   15746         340 :     if (dopt->binary_upgrade)
   15747          20 :         binary_upgrade_extension_member(q, &dictinfo->dobj,
   15748             :                                         "TEXT SEARCH DICTIONARY", qdictname,
   15749          20 :                                         dictinfo->dobj.namespace->dobj.name);
   15750             : 
   15751         340 :     if (dictinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   15752         340 :         ArchiveEntry(fout, dictinfo->dobj.catId, dictinfo->dobj.dumpId,
   15753         340 :                      ARCHIVE_OPTS(.tag = dictinfo->dobj.name,
   15754             :                                   .namespace = dictinfo->dobj.namespace->dobj.name,
   15755             :                                   .owner = dictinfo->rolname,
   15756             :                                   .description = "TEXT SEARCH DICTIONARY",
   15757             :                                   .section = SECTION_PRE_DATA,
   15758             :                                   .createStmt = q->data,
   15759             :                                   .dropStmt = delq->data));
   15760             : 
   15761             :     /* Dump Dictionary Comments */
   15762         340 :     if (dictinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   15763         250 :         dumpComment(fout, "TEXT SEARCH DICTIONARY", qdictname,
   15764         250 :                     dictinfo->dobj.namespace->dobj.name, dictinfo->rolname,
   15765         250 :                     dictinfo->dobj.catId, 0, dictinfo->dobj.dumpId);
   15766             : 
   15767         340 :     destroyPQExpBuffer(q);
   15768         340 :     destroyPQExpBuffer(delq);
   15769         340 :     destroyPQExpBuffer(query);
   15770         340 :     free(qdictname);
   15771             : }
   15772             : 
   15773             : /*
   15774             :  * dumpTSTemplate
   15775             :  *    write out a single text search template
   15776             :  */
   15777             : static void
   15778         112 : dumpTSTemplate(Archive *fout, const TSTemplateInfo *tmplinfo)
   15779             : {
   15780         112 :     DumpOptions *dopt = fout->dopt;
   15781             :     PQExpBuffer q;
   15782             :     PQExpBuffer delq;
   15783             :     char       *qtmplname;
   15784             : 
   15785             :     /* Do nothing if not dumping schema */
   15786         112 :     if (!dopt->dumpSchema)
   15787          12 :         return;
   15788             : 
   15789         100 :     q = createPQExpBuffer();
   15790         100 :     delq = createPQExpBuffer();
   15791             : 
   15792         100 :     qtmplname = pg_strdup(fmtId(tmplinfo->dobj.name));
   15793             : 
   15794         100 :     appendPQExpBuffer(q, "CREATE TEXT SEARCH TEMPLATE %s (\n",
   15795         100 :                       fmtQualifiedDumpable(tmplinfo));
   15796             : 
   15797         100 :     if (tmplinfo->tmplinit != InvalidOid)
   15798          30 :         appendPQExpBuffer(q, "    INIT = %s,\n",
   15799          30 :                           convertTSFunction(fout, tmplinfo->tmplinit));
   15800         100 :     appendPQExpBuffer(q, "    LEXIZE = %s );\n",
   15801         100 :                       convertTSFunction(fout, tmplinfo->tmpllexize));
   15802             : 
   15803         100 :     appendPQExpBuffer(delq, "DROP TEXT SEARCH TEMPLATE %s;\n",
   15804         100 :                       fmtQualifiedDumpable(tmplinfo));
   15805             : 
   15806         100 :     if (dopt->binary_upgrade)
   15807           2 :         binary_upgrade_extension_member(q, &tmplinfo->dobj,
   15808             :                                         "TEXT SEARCH TEMPLATE", qtmplname,
   15809           2 :                                         tmplinfo->dobj.namespace->dobj.name);
   15810             : 
   15811         100 :     if (tmplinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   15812         100 :         ArchiveEntry(fout, tmplinfo->dobj.catId, tmplinfo->dobj.dumpId,
   15813         100 :                      ARCHIVE_OPTS(.tag = tmplinfo->dobj.name,
   15814             :                                   .namespace = tmplinfo->dobj.namespace->dobj.name,
   15815             :                                   .description = "TEXT SEARCH TEMPLATE",
   15816             :                                   .section = SECTION_PRE_DATA,
   15817             :                                   .createStmt = q->data,
   15818             :                                   .dropStmt = delq->data));
   15819             : 
   15820             :     /* Dump Template Comments */
   15821         100 :     if (tmplinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   15822         100 :         dumpComment(fout, "TEXT SEARCH TEMPLATE", qtmplname,
   15823         100 :                     tmplinfo->dobj.namespace->dobj.name, "",
   15824         100 :                     tmplinfo->dobj.catId, 0, tmplinfo->dobj.dumpId);
   15825             : 
   15826         100 :     destroyPQExpBuffer(q);
   15827         100 :     destroyPQExpBuffer(delq);
   15828         100 :     free(qtmplname);
   15829             : }
   15830             : 
   15831             : /*
   15832             :  * dumpTSConfig
   15833             :  *    write out a single text search configuration
   15834             :  */
   15835             : static void
   15836         302 : dumpTSConfig(Archive *fout, const TSConfigInfo *cfginfo)
   15837             : {
   15838         302 :     DumpOptions *dopt = fout->dopt;
   15839             :     PQExpBuffer q;
   15840             :     PQExpBuffer delq;
   15841             :     PQExpBuffer query;
   15842             :     char       *qcfgname;
   15843             :     PGresult   *res;
   15844             :     char       *nspname;
   15845             :     char       *prsname;
   15846             :     int         ntups,
   15847             :                 i;
   15848             :     int         i_tokenname;
   15849             :     int         i_dictname;
   15850             : 
   15851             :     /* Do nothing if not dumping schema */
   15852         302 :     if (!dopt->dumpSchema)
   15853          12 :         return;
   15854             : 
   15855         290 :     q = createPQExpBuffer();
   15856         290 :     delq = createPQExpBuffer();
   15857         290 :     query = createPQExpBuffer();
   15858             : 
   15859         290 :     qcfgname = pg_strdup(fmtId(cfginfo->dobj.name));
   15860             : 
   15861             :     /* Fetch name and namespace of the config's parser */
   15862         290 :     appendPQExpBuffer(query, "SELECT nspname, prsname "
   15863             :                       "FROM pg_ts_parser p, pg_namespace n "
   15864             :                       "WHERE p.oid = '%u' AND n.oid = prsnamespace",
   15865         290 :                       cfginfo->cfgparser);
   15866         290 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   15867         290 :     nspname = PQgetvalue(res, 0, 0);
   15868         290 :     prsname = PQgetvalue(res, 0, 1);
   15869             : 
   15870         290 :     appendPQExpBuffer(q, "CREATE TEXT SEARCH CONFIGURATION %s (\n",
   15871         290 :                       fmtQualifiedDumpable(cfginfo));
   15872             : 
   15873         290 :     appendPQExpBuffer(q, "    PARSER = %s.", fmtId(nspname));
   15874         290 :     appendPQExpBuffer(q, "%s );\n", fmtId(prsname));
   15875             : 
   15876         290 :     PQclear(res);
   15877             : 
   15878         290 :     resetPQExpBuffer(query);
   15879         290 :     appendPQExpBuffer(query,
   15880             :                       "SELECT\n"
   15881             :                       "  ( SELECT alias FROM pg_catalog.ts_token_type('%u'::pg_catalog.oid) AS t\n"
   15882             :                       "    WHERE t.tokid = m.maptokentype ) AS tokenname,\n"
   15883             :                       "  m.mapdict::pg_catalog.regdictionary AS dictname\n"
   15884             :                       "FROM pg_catalog.pg_ts_config_map AS m\n"
   15885             :                       "WHERE m.mapcfg = '%u'\n"
   15886             :                       "ORDER BY m.mapcfg, m.maptokentype, m.mapseqno",
   15887         290 :                       cfginfo->cfgparser, cfginfo->dobj.catId.oid);
   15888             : 
   15889         290 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   15890         290 :     ntups = PQntuples(res);
   15891             : 
   15892         290 :     i_tokenname = PQfnumber(res, "tokenname");
   15893         290 :     i_dictname = PQfnumber(res, "dictname");
   15894             : 
   15895        6070 :     for (i = 0; i < ntups; i++)
   15896             :     {
   15897        5780 :         char       *tokenname = PQgetvalue(res, i, i_tokenname);
   15898        5780 :         char       *dictname = PQgetvalue(res, i, i_dictname);
   15899             : 
   15900        5780 :         if (i == 0 ||
   15901        5490 :             strcmp(tokenname, PQgetvalue(res, i - 1, i_tokenname)) != 0)
   15902             :         {
   15903             :             /* starting a new token type, so start a new command */
   15904        5510 :             if (i > 0)
   15905        5220 :                 appendPQExpBufferStr(q, ";\n");
   15906        5510 :             appendPQExpBuffer(q, "\nALTER TEXT SEARCH CONFIGURATION %s\n",
   15907        5510 :                               fmtQualifiedDumpable(cfginfo));
   15908             :             /* tokenname needs quoting, dictname does NOT */
   15909        5510 :             appendPQExpBuffer(q, "    ADD MAPPING FOR %s WITH %s",
   15910             :                               fmtId(tokenname), dictname);
   15911             :         }
   15912             :         else
   15913         270 :             appendPQExpBuffer(q, ", %s", dictname);
   15914             :     }
   15915             : 
   15916         290 :     if (ntups > 0)
   15917         290 :         appendPQExpBufferStr(q, ";\n");
   15918             : 
   15919         290 :     PQclear(res);
   15920             : 
   15921         290 :     appendPQExpBuffer(delq, "DROP TEXT SEARCH CONFIGURATION %s;\n",
   15922         290 :                       fmtQualifiedDumpable(cfginfo));
   15923             : 
   15924         290 :     if (dopt->binary_upgrade)
   15925          10 :         binary_upgrade_extension_member(q, &cfginfo->dobj,
   15926             :                                         "TEXT SEARCH CONFIGURATION", qcfgname,
   15927          10 :                                         cfginfo->dobj.namespace->dobj.name);
   15928             : 
   15929         290 :     if (cfginfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   15930         290 :         ArchiveEntry(fout, cfginfo->dobj.catId, cfginfo->dobj.dumpId,
   15931         290 :                      ARCHIVE_OPTS(.tag = cfginfo->dobj.name,
   15932             :                                   .namespace = cfginfo->dobj.namespace->dobj.name,
   15933             :                                   .owner = cfginfo->rolname,
   15934             :                                   .description = "TEXT SEARCH CONFIGURATION",
   15935             :                                   .section = SECTION_PRE_DATA,
   15936             :                                   .createStmt = q->data,
   15937             :                                   .dropStmt = delq->data));
   15938             : 
   15939             :     /* Dump Configuration Comments */
   15940         290 :     if (cfginfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   15941         250 :         dumpComment(fout, "TEXT SEARCH CONFIGURATION", qcfgname,
   15942         250 :                     cfginfo->dobj.namespace->dobj.name, cfginfo->rolname,
   15943         250 :                     cfginfo->dobj.catId, 0, cfginfo->dobj.dumpId);
   15944             : 
   15945         290 :     destroyPQExpBuffer(q);
   15946         290 :     destroyPQExpBuffer(delq);
   15947         290 :     destroyPQExpBuffer(query);
   15948         290 :     free(qcfgname);
   15949             : }
   15950             : 
   15951             : /*
   15952             :  * dumpForeignDataWrapper
   15953             :  *    write out a single foreign-data wrapper definition
   15954             :  */
   15955             : static void
   15956         110 : dumpForeignDataWrapper(Archive *fout, const FdwInfo *fdwinfo)
   15957             : {
   15958         110 :     DumpOptions *dopt = fout->dopt;
   15959             :     PQExpBuffer q;
   15960             :     PQExpBuffer delq;
   15961             :     char       *qfdwname;
   15962             : 
   15963             :     /* Do nothing if not dumping schema */
   15964         110 :     if (!dopt->dumpSchema)
   15965          14 :         return;
   15966             : 
   15967          96 :     q = createPQExpBuffer();
   15968          96 :     delq = createPQExpBuffer();
   15969             : 
   15970          96 :     qfdwname = pg_strdup(fmtId(fdwinfo->dobj.name));
   15971             : 
   15972          96 :     appendPQExpBuffer(q, "CREATE FOREIGN DATA WRAPPER %s",
   15973             :                       qfdwname);
   15974             : 
   15975          96 :     if (strcmp(fdwinfo->fdwhandler, "-") != 0)
   15976           0 :         appendPQExpBuffer(q, " HANDLER %s", fdwinfo->fdwhandler);
   15977             : 
   15978          96 :     if (strcmp(fdwinfo->fdwvalidator, "-") != 0)
   15979           0 :         appendPQExpBuffer(q, " VALIDATOR %s", fdwinfo->fdwvalidator);
   15980             : 
   15981          96 :     if (strlen(fdwinfo->fdwoptions) > 0)
   15982           0 :         appendPQExpBuffer(q, " OPTIONS (\n    %s\n)", fdwinfo->fdwoptions);
   15983             : 
   15984          96 :     appendPQExpBufferStr(q, ";\n");
   15985             : 
   15986          96 :     appendPQExpBuffer(delq, "DROP FOREIGN DATA WRAPPER %s;\n",
   15987             :                       qfdwname);
   15988             : 
   15989          96 :     if (dopt->binary_upgrade)
   15990           4 :         binary_upgrade_extension_member(q, &fdwinfo->dobj,
   15991             :                                         "FOREIGN DATA WRAPPER", qfdwname,
   15992             :                                         NULL);
   15993             : 
   15994          96 :     if (fdwinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   15995          96 :         ArchiveEntry(fout, fdwinfo->dobj.catId, fdwinfo->dobj.dumpId,
   15996          96 :                      ARCHIVE_OPTS(.tag = fdwinfo->dobj.name,
   15997             :                                   .owner = fdwinfo->rolname,
   15998             :                                   .description = "FOREIGN DATA WRAPPER",
   15999             :                                   .section = SECTION_PRE_DATA,
   16000             :                                   .createStmt = q->data,
   16001             :                                   .dropStmt = delq->data));
   16002             : 
   16003             :     /* Dump Foreign Data Wrapper Comments */
   16004          96 :     if (fdwinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   16005           0 :         dumpComment(fout, "FOREIGN DATA WRAPPER", qfdwname,
   16006           0 :                     NULL, fdwinfo->rolname,
   16007           0 :                     fdwinfo->dobj.catId, 0, fdwinfo->dobj.dumpId);
   16008             : 
   16009             :     /* Handle the ACL */
   16010          96 :     if (fdwinfo->dobj.dump & DUMP_COMPONENT_ACL)
   16011          68 :         dumpACL(fout, fdwinfo->dobj.dumpId, InvalidDumpId,
   16012             :                 "FOREIGN DATA WRAPPER", qfdwname, NULL, NULL,
   16013          68 :                 NULL, fdwinfo->rolname, &fdwinfo->dacl);
   16014             : 
   16015          96 :     free(qfdwname);
   16016             : 
   16017          96 :     destroyPQExpBuffer(q);
   16018          96 :     destroyPQExpBuffer(delq);
   16019             : }
   16020             : 
   16021             : /*
   16022             :  * dumpForeignServer
   16023             :  *    write out a foreign server definition
   16024             :  */
   16025             : static void
   16026         118 : dumpForeignServer(Archive *fout, const ForeignServerInfo *srvinfo)
   16027             : {
   16028         118 :     DumpOptions *dopt = fout->dopt;
   16029             :     PQExpBuffer q;
   16030             :     PQExpBuffer delq;
   16031             :     PQExpBuffer query;
   16032             :     PGresult   *res;
   16033             :     char       *qsrvname;
   16034             :     char       *fdwname;
   16035             : 
   16036             :     /* Do nothing if not dumping schema */
   16037         118 :     if (!dopt->dumpSchema)
   16038          18 :         return;
   16039             : 
   16040         100 :     q = createPQExpBuffer();
   16041         100 :     delq = createPQExpBuffer();
   16042         100 :     query = createPQExpBuffer();
   16043             : 
   16044         100 :     qsrvname = pg_strdup(fmtId(srvinfo->dobj.name));
   16045             : 
   16046             :     /* look up the foreign-data wrapper */
   16047         100 :     appendPQExpBuffer(query, "SELECT fdwname "
   16048             :                       "FROM pg_foreign_data_wrapper w "
   16049             :                       "WHERE w.oid = '%u'",
   16050         100 :                       srvinfo->srvfdw);
   16051         100 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   16052         100 :     fdwname = PQgetvalue(res, 0, 0);
   16053             : 
   16054         100 :     appendPQExpBuffer(q, "CREATE SERVER %s", qsrvname);
   16055         100 :     if (srvinfo->srvtype && strlen(srvinfo->srvtype) > 0)
   16056             :     {
   16057           0 :         appendPQExpBufferStr(q, " TYPE ");
   16058           0 :         appendStringLiteralAH(q, srvinfo->srvtype, fout);
   16059             :     }
   16060         100 :     if (srvinfo->srvversion && strlen(srvinfo->srvversion) > 0)
   16061             :     {
   16062           0 :         appendPQExpBufferStr(q, " VERSION ");
   16063           0 :         appendStringLiteralAH(q, srvinfo->srvversion, fout);
   16064             :     }
   16065             : 
   16066         100 :     appendPQExpBufferStr(q, " FOREIGN DATA WRAPPER ");
   16067         100 :     appendPQExpBufferStr(q, fmtId(fdwname));
   16068             : 
   16069         100 :     if (srvinfo->srvoptions && strlen(srvinfo->srvoptions) > 0)
   16070           0 :         appendPQExpBuffer(q, " OPTIONS (\n    %s\n)", srvinfo->srvoptions);
   16071             : 
   16072         100 :     appendPQExpBufferStr(q, ";\n");
   16073             : 
   16074         100 :     appendPQExpBuffer(delq, "DROP SERVER %s;\n",
   16075             :                       qsrvname);
   16076             : 
   16077         100 :     if (dopt->binary_upgrade)
   16078           4 :         binary_upgrade_extension_member(q, &srvinfo->dobj,
   16079             :                                         "SERVER", qsrvname, NULL);
   16080             : 
   16081         100 :     if (srvinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   16082         100 :         ArchiveEntry(fout, srvinfo->dobj.catId, srvinfo->dobj.dumpId,
   16083         100 :                      ARCHIVE_OPTS(.tag = srvinfo->dobj.name,
   16084             :                                   .owner = srvinfo->rolname,
   16085             :                                   .description = "SERVER",
   16086             :                                   .section = SECTION_PRE_DATA,
   16087             :                                   .createStmt = q->data,
   16088             :                                   .dropStmt = delq->data));
   16089             : 
   16090             :     /* Dump Foreign Server Comments */
   16091         100 :     if (srvinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   16092           0 :         dumpComment(fout, "SERVER", qsrvname,
   16093           0 :                     NULL, srvinfo->rolname,
   16094           0 :                     srvinfo->dobj.catId, 0, srvinfo->dobj.dumpId);
   16095             : 
   16096             :     /* Handle the ACL */
   16097         100 :     if (srvinfo->dobj.dump & DUMP_COMPONENT_ACL)
   16098          68 :         dumpACL(fout, srvinfo->dobj.dumpId, InvalidDumpId,
   16099             :                 "FOREIGN SERVER", qsrvname, NULL, NULL,
   16100          68 :                 NULL, srvinfo->rolname, &srvinfo->dacl);
   16101             : 
   16102             :     /* Dump user mappings */
   16103         100 :     if (srvinfo->dobj.dump & DUMP_COMPONENT_USERMAP)
   16104         100 :         dumpUserMappings(fout,
   16105         100 :                          srvinfo->dobj.name, NULL,
   16106         100 :                          srvinfo->rolname,
   16107         100 :                          srvinfo->dobj.catId, srvinfo->dobj.dumpId);
   16108             : 
   16109         100 :     PQclear(res);
   16110             : 
   16111         100 :     free(qsrvname);
   16112             : 
   16113         100 :     destroyPQExpBuffer(q);
   16114         100 :     destroyPQExpBuffer(delq);
   16115         100 :     destroyPQExpBuffer(query);
   16116             : }
   16117             : 
   16118             : /*
   16119             :  * dumpUserMappings
   16120             :  *
   16121             :  * This routine is used to dump any user mappings associated with the
   16122             :  * server handed to this routine. Should be called after ArchiveEntry()
   16123             :  * for the server.
   16124             :  */
   16125             : static void
   16126         100 : dumpUserMappings(Archive *fout,
   16127             :                  const char *servername, const char *namespace,
   16128             :                  const char *owner,
   16129             :                  CatalogId catalogId, DumpId dumpId)
   16130             : {
   16131             :     PQExpBuffer q;
   16132             :     PQExpBuffer delq;
   16133             :     PQExpBuffer query;
   16134             :     PQExpBuffer tag;
   16135             :     PGresult   *res;
   16136             :     int         ntups;
   16137             :     int         i_usename;
   16138             :     int         i_umoptions;
   16139             :     int         i;
   16140             : 
   16141         100 :     q = createPQExpBuffer();
   16142         100 :     tag = createPQExpBuffer();
   16143         100 :     delq = createPQExpBuffer();
   16144         100 :     query = createPQExpBuffer();
   16145             : 
   16146             :     /*
   16147             :      * We read from the publicly accessible view pg_user_mappings, so as not
   16148             :      * to fail if run by a non-superuser.  Note that the view will show
   16149             :      * umoptions as null if the user hasn't got privileges for the associated
   16150             :      * server; this means that pg_dump will dump such a mapping, but with no
   16151             :      * OPTIONS clause.  A possible alternative is to skip such mappings
   16152             :      * altogether, but it's not clear that that's an improvement.
   16153             :      */
   16154         100 :     appendPQExpBuffer(query,
   16155             :                       "SELECT usename, "
   16156             :                       "array_to_string(ARRAY("
   16157             :                       "SELECT quote_ident(option_name) || ' ' || "
   16158             :                       "quote_literal(option_value) "
   16159             :                       "FROM pg_options_to_table(umoptions) "
   16160             :                       "ORDER BY option_name"
   16161             :                       "), E',\n    ') AS umoptions "
   16162             :                       "FROM pg_user_mappings "
   16163             :                       "WHERE srvid = '%u' "
   16164             :                       "ORDER BY usename",
   16165             :                       catalogId.oid);
   16166             : 
   16167         100 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   16168             : 
   16169         100 :     ntups = PQntuples(res);
   16170         100 :     i_usename = PQfnumber(res, "usename");
   16171         100 :     i_umoptions = PQfnumber(res, "umoptions");
   16172             : 
   16173         168 :     for (i = 0; i < ntups; i++)
   16174             :     {
   16175             :         char       *usename;
   16176             :         char       *umoptions;
   16177             : 
   16178          68 :         usename = PQgetvalue(res, i, i_usename);
   16179          68 :         umoptions = PQgetvalue(res, i, i_umoptions);
   16180             : 
   16181          68 :         resetPQExpBuffer(q);
   16182          68 :         appendPQExpBuffer(q, "CREATE USER MAPPING FOR %s", fmtId(usename));
   16183          68 :         appendPQExpBuffer(q, " SERVER %s", fmtId(servername));
   16184             : 
   16185          68 :         if (umoptions && strlen(umoptions) > 0)
   16186           0 :             appendPQExpBuffer(q, " OPTIONS (\n    %s\n)", umoptions);
   16187             : 
   16188          68 :         appendPQExpBufferStr(q, ";\n");
   16189             : 
   16190          68 :         resetPQExpBuffer(delq);
   16191          68 :         appendPQExpBuffer(delq, "DROP USER MAPPING FOR %s", fmtId(usename));
   16192          68 :         appendPQExpBuffer(delq, " SERVER %s;\n", fmtId(servername));
   16193             : 
   16194          68 :         resetPQExpBuffer(tag);
   16195          68 :         appendPQExpBuffer(tag, "USER MAPPING %s SERVER %s",
   16196             :                           usename, servername);
   16197             : 
   16198          68 :         ArchiveEntry(fout, nilCatalogId, createDumpId(),
   16199          68 :                      ARCHIVE_OPTS(.tag = tag->data,
   16200             :                                   .namespace = namespace,
   16201             :                                   .owner = owner,
   16202             :                                   .description = "USER MAPPING",
   16203             :                                   .section = SECTION_PRE_DATA,
   16204             :                                   .createStmt = q->data,
   16205             :                                   .dropStmt = delq->data));
   16206             :     }
   16207             : 
   16208         100 :     PQclear(res);
   16209             : 
   16210         100 :     destroyPQExpBuffer(query);
   16211         100 :     destroyPQExpBuffer(delq);
   16212         100 :     destroyPQExpBuffer(tag);
   16213         100 :     destroyPQExpBuffer(q);
   16214         100 : }
   16215             : 
   16216             : /*
   16217             :  * Write out default privileges information
   16218             :  */
   16219             : static void
   16220         344 : dumpDefaultACL(Archive *fout, const DefaultACLInfo *daclinfo)
   16221             : {
   16222         344 :     DumpOptions *dopt = fout->dopt;
   16223             :     PQExpBuffer q;
   16224             :     PQExpBuffer tag;
   16225             :     const char *type;
   16226             : 
   16227             :     /* Do nothing if not dumping schema, or if we're skipping ACLs */
   16228         344 :     if (!dopt->dumpSchema || dopt->aclsSkip)
   16229          56 :         return;
   16230             : 
   16231         288 :     q = createPQExpBuffer();
   16232         288 :     tag = createPQExpBuffer();
   16233             : 
   16234         288 :     switch (daclinfo->defaclobjtype)
   16235             :     {
   16236         134 :         case DEFACLOBJ_RELATION:
   16237         134 :             type = "TABLES";
   16238         134 :             break;
   16239           0 :         case DEFACLOBJ_SEQUENCE:
   16240           0 :             type = "SEQUENCES";
   16241           0 :             break;
   16242         134 :         case DEFACLOBJ_FUNCTION:
   16243         134 :             type = "FUNCTIONS";
   16244         134 :             break;
   16245          20 :         case DEFACLOBJ_TYPE:
   16246          20 :             type = "TYPES";
   16247          20 :             break;
   16248           0 :         case DEFACLOBJ_NAMESPACE:
   16249           0 :             type = "SCHEMAS";
   16250           0 :             break;
   16251           0 :         case DEFACLOBJ_LARGEOBJECT:
   16252           0 :             type = "LARGE OBJECTS";
   16253           0 :             break;
   16254           0 :         default:
   16255             :             /* shouldn't get here */
   16256           0 :             pg_fatal("unrecognized object type in default privileges: %d",
   16257             :                      (int) daclinfo->defaclobjtype);
   16258             :             type = "";            /* keep compiler quiet */
   16259             :     }
   16260             : 
   16261         288 :     appendPQExpBuffer(tag, "DEFAULT PRIVILEGES FOR %s", type);
   16262             : 
   16263             :     /* build the actual command(s) for this tuple */
   16264         288 :     if (!buildDefaultACLCommands(type,
   16265         288 :                                  daclinfo->dobj.namespace != NULL ?
   16266         136 :                                  daclinfo->dobj.namespace->dobj.name : NULL,
   16267         288 :                                  daclinfo->dacl.acl,
   16268         288 :                                  daclinfo->dacl.acldefault,
   16269         288 :                                  daclinfo->defaclrole,
   16270             :                                  fout->remoteVersion,
   16271             :                                  q))
   16272           0 :         pg_fatal("could not parse default ACL list (%s)",
   16273             :                  daclinfo->dacl.acl);
   16274             : 
   16275         288 :     if (daclinfo->dobj.dump & DUMP_COMPONENT_ACL)
   16276         288 :         ArchiveEntry(fout, daclinfo->dobj.catId, daclinfo->dobj.dumpId,
   16277         288 :                      ARCHIVE_OPTS(.tag = tag->data,
   16278             :                                   .namespace = daclinfo->dobj.namespace ?
   16279             :                                   daclinfo->dobj.namespace->dobj.name : NULL,
   16280             :                                   .owner = daclinfo->defaclrole,
   16281             :                                   .description = "DEFAULT ACL",
   16282             :                                   .section = SECTION_POST_DATA,
   16283             :                                   .createStmt = q->data));
   16284             : 
   16285         288 :     destroyPQExpBuffer(tag);
   16286         288 :     destroyPQExpBuffer(q);
   16287             : }
   16288             : 
   16289             : /*----------
   16290             :  * Write out grant/revoke information
   16291             :  *
   16292             :  * 'objDumpId' is the dump ID of the underlying object.
   16293             :  * 'altDumpId' can be a second dumpId that the ACL entry must also depend on,
   16294             :  *      or InvalidDumpId if there is no need for a second dependency.
   16295             :  * 'type' must be one of
   16296             :  *      TABLE, SEQUENCE, FUNCTION, LANGUAGE, SCHEMA, DATABASE, TABLESPACE,
   16297             :  *      FOREIGN DATA WRAPPER, SERVER, or LARGE OBJECT.
   16298             :  * 'name' is the formatted name of the object.  Must be quoted etc. already.
   16299             :  * 'subname' is the formatted name of the sub-object, if any.  Must be quoted.
   16300             :  *      (Currently we assume that subname is only provided for table columns.)
   16301             :  * 'nspname' is the namespace the object is in (NULL if none).
   16302             :  * 'tag' is the tag to use for the ACL TOC entry; typically, this is NULL
   16303             :  *      to use the default for the object type.
   16304             :  * 'owner' is the owner, NULL if there is no owner (for languages).
   16305             :  * 'dacl' is the DumpableAcl struct for the object.
   16306             :  *
   16307             :  * Returns the dump ID assigned to the ACL TocEntry, or InvalidDumpId if
   16308             :  * no ACL entry was created.
   16309             :  *----------
   16310             :  */
   16311             : static DumpId
   16312       55376 : dumpACL(Archive *fout, DumpId objDumpId, DumpId altDumpId,
   16313             :         const char *type, const char *name, const char *subname,
   16314             :         const char *nspname, const char *tag, const char *owner,
   16315             :         const DumpableAcl *dacl)
   16316             : {
   16317       55376 :     DumpId      aclDumpId = InvalidDumpId;
   16318       55376 :     DumpOptions *dopt = fout->dopt;
   16319       55376 :     const char *acls = dacl->acl;
   16320       55376 :     const char *acldefault = dacl->acldefault;
   16321       55376 :     char        privtype = dacl->privtype;
   16322       55376 :     const char *initprivs = dacl->initprivs;
   16323             :     const char *baseacls;
   16324             :     PQExpBuffer sql;
   16325             : 
   16326             :     /* Do nothing if ACL dump is not enabled */
   16327       55376 :     if (dopt->aclsSkip)
   16328         648 :         return InvalidDumpId;
   16329             : 
   16330             :     /* --data-only skips ACLs *except* large object ACLs */
   16331       54728 :     if (!dopt->dumpSchema && strcmp(type, "LARGE OBJECT") != 0)
   16332           0 :         return InvalidDumpId;
   16333             : 
   16334       54728 :     sql = createPQExpBuffer();
   16335             : 
   16336             :     /*
   16337             :      * In binary upgrade mode, we don't run an extension's script but instead
   16338             :      * dump out the objects independently and then recreate them.  To preserve
   16339             :      * any initial privileges which were set on extension objects, we need to
   16340             :      * compute the set of GRANT and REVOKE commands necessary to get from the
   16341             :      * default privileges of an object to its initial privileges as recorded
   16342             :      * in pg_init_privs.
   16343             :      *
   16344             :      * At restore time, we apply these commands after having called
   16345             :      * binary_upgrade_set_record_init_privs(true).  That tells the backend to
   16346             :      * copy the results into pg_init_privs.  This is how we preserve the
   16347             :      * contents of that catalog across binary upgrades.
   16348             :      */
   16349       54728 :     if (dopt->binary_upgrade && privtype == 'e' &&
   16350          26 :         initprivs && *initprivs != '\0')
   16351             :     {
   16352          26 :         appendPQExpBufferStr(sql, "SELECT pg_catalog.binary_upgrade_set_record_init_privs(true);\n");
   16353          26 :         if (!buildACLCommands(name, subname, nspname, type,
   16354             :                               initprivs, acldefault, owner,
   16355             :                               "", fout->remoteVersion, sql))
   16356           0 :             pg_fatal("could not parse initial ACL list (%s) or default (%s) for object \"%s\" (%s)",
   16357             :                      initprivs, acldefault, name, type);
   16358          26 :         appendPQExpBufferStr(sql, "SELECT pg_catalog.binary_upgrade_set_record_init_privs(false);\n");
   16359             :     }
   16360             : 
   16361             :     /*
   16362             :      * Now figure the GRANT and REVOKE commands needed to get to the object's
   16363             :      * actual current ACL, starting from the initprivs if given, else from the
   16364             :      * object-type-specific default.  Also, while buildACLCommands will assume
   16365             :      * that a NULL/empty acls string means it needn't do anything, what that
   16366             :      * actually represents is the object-type-specific default; so we need to
   16367             :      * substitute the acldefault string to get the right results in that case.
   16368             :      */
   16369       54728 :     if (initprivs && *initprivs != '\0')
   16370             :     {
   16371       50988 :         baseacls = initprivs;
   16372       50988 :         if (acls == NULL || *acls == '\0')
   16373          34 :             acls = acldefault;
   16374             :     }
   16375             :     else
   16376        3740 :         baseacls = acldefault;
   16377             : 
   16378       54728 :     if (!buildACLCommands(name, subname, nspname, type,
   16379             :                           acls, baseacls, owner,
   16380             :                           "", fout->remoteVersion, sql))
   16381           0 :         pg_fatal("could not parse ACL list (%s) or default (%s) for object \"%s\" (%s)",
   16382             :                  acls, baseacls, name, type);
   16383             : 
   16384       54728 :     if (sql->len > 0)
   16385             :     {
   16386        3874 :         PQExpBuffer tagbuf = createPQExpBuffer();
   16387             :         DumpId      aclDeps[2];
   16388        3874 :         int         nDeps = 0;
   16389             : 
   16390        3874 :         if (tag)
   16391           0 :             appendPQExpBufferStr(tagbuf, tag);
   16392        3874 :         else if (subname)
   16393        2286 :             appendPQExpBuffer(tagbuf, "COLUMN %s.%s", name, subname);
   16394             :         else
   16395        1588 :             appendPQExpBuffer(tagbuf, "%s %s", type, name);
   16396             : 
   16397        3874 :         aclDeps[nDeps++] = objDumpId;
   16398        3874 :         if (altDumpId != InvalidDumpId)
   16399        2112 :             aclDeps[nDeps++] = altDumpId;
   16400             : 
   16401        3874 :         aclDumpId = createDumpId();
   16402             : 
   16403        3874 :         ArchiveEntry(fout, nilCatalogId, aclDumpId,
   16404        3874 :                      ARCHIVE_OPTS(.tag = tagbuf->data,
   16405             :                                   .namespace = nspname,
   16406             :                                   .owner = owner,
   16407             :                                   .description = "ACL",
   16408             :                                   .section = SECTION_NONE,
   16409             :                                   .createStmt = sql->data,
   16410             :                                   .deps = aclDeps,
   16411             :                                   .nDeps = nDeps));
   16412             : 
   16413        3874 :         destroyPQExpBuffer(tagbuf);
   16414             :     }
   16415             : 
   16416       54728 :     destroyPQExpBuffer(sql);
   16417             : 
   16418       54728 :     return aclDumpId;
   16419             : }
   16420             : 
   16421             : /*
   16422             :  * dumpSecLabel
   16423             :  *
   16424             :  * This routine is used to dump any security labels associated with the
   16425             :  * object handed to this routine. The routine takes the object type
   16426             :  * and object name (ready to print, except for schema decoration), plus
   16427             :  * the namespace and owner of the object (for labeling the ArchiveEntry),
   16428             :  * plus catalog ID and subid which are the lookup key for pg_seclabel,
   16429             :  * plus the dump ID for the object (for setting a dependency).
   16430             :  * If a matching pg_seclabel entry is found, it is dumped.
   16431             :  *
   16432             :  * Note: although this routine takes a dumpId for dependency purposes,
   16433             :  * that purpose is just to mark the dependency in the emitted dump file
   16434             :  * for possible future use by pg_restore.  We do NOT use it for determining
   16435             :  * ordering of the label in the dump file, because this routine is called
   16436             :  * after dependency sorting occurs.  This routine should be called just after
   16437             :  * calling ArchiveEntry() for the specified object.
   16438             :  */
   16439             : static void
   16440           0 : dumpSecLabel(Archive *fout, const char *type, const char *name,
   16441             :              const char *namespace, const char *owner,
   16442             :              CatalogId catalogId, int subid, DumpId dumpId)
   16443             : {
   16444           0 :     DumpOptions *dopt = fout->dopt;
   16445             :     SecLabelItem *labels;
   16446             :     int         nlabels;
   16447             :     int         i;
   16448             :     PQExpBuffer query;
   16449             : 
   16450             :     /* do nothing, if --no-security-labels is supplied */
   16451           0 :     if (dopt->no_security_labels)
   16452           0 :         return;
   16453             : 
   16454             :     /*
   16455             :      * Security labels are schema not data ... except large object labels are
   16456             :      * data
   16457             :      */
   16458           0 :     if (strcmp(type, "LARGE OBJECT") != 0)
   16459             :     {
   16460           0 :         if (!dopt->dumpSchema)
   16461           0 :             return;
   16462             :     }
   16463             :     else
   16464             :     {
   16465             :         /* We do dump large object security labels in binary-upgrade mode */
   16466           0 :         if (!dopt->dumpData && !dopt->binary_upgrade)
   16467           0 :             return;
   16468             :     }
   16469             : 
   16470             :     /* Search for security labels associated with catalogId, using table */
   16471           0 :     nlabels = findSecLabels(catalogId.tableoid, catalogId.oid, &labels);
   16472             : 
   16473           0 :     query = createPQExpBuffer();
   16474             : 
   16475           0 :     for (i = 0; i < nlabels; i++)
   16476             :     {
   16477             :         /*
   16478             :          * Ignore label entries for which the subid doesn't match.
   16479             :          */
   16480           0 :         if (labels[i].objsubid != subid)
   16481           0 :             continue;
   16482             : 
   16483           0 :         appendPQExpBuffer(query,
   16484             :                           "SECURITY LABEL FOR %s ON %s ",
   16485           0 :                           fmtId(labels[i].provider), type);
   16486           0 :         if (namespace && *namespace)
   16487           0 :             appendPQExpBuffer(query, "%s.", fmtId(namespace));
   16488           0 :         appendPQExpBuffer(query, "%s IS ", name);
   16489           0 :         appendStringLiteralAH(query, labels[i].label, fout);
   16490           0 :         appendPQExpBufferStr(query, ";\n");
   16491             :     }
   16492             : 
   16493           0 :     if (query->len > 0)
   16494             :     {
   16495           0 :         PQExpBuffer tag = createPQExpBuffer();
   16496             : 
   16497           0 :         appendPQExpBuffer(tag, "%s %s", type, name);
   16498           0 :         ArchiveEntry(fout, nilCatalogId, createDumpId(),
   16499           0 :                      ARCHIVE_OPTS(.tag = tag->data,
   16500             :                                   .namespace = namespace,
   16501             :                                   .owner = owner,
   16502             :                                   .description = "SECURITY LABEL",
   16503             :                                   .section = SECTION_NONE,
   16504             :                                   .createStmt = query->data,
   16505             :                                   .deps = &dumpId,
   16506             :                                   .nDeps = 1));
   16507           0 :         destroyPQExpBuffer(tag);
   16508             :     }
   16509             : 
   16510           0 :     destroyPQExpBuffer(query);
   16511             : }
   16512             : 
   16513             : /*
   16514             :  * dumpTableSecLabel
   16515             :  *
   16516             :  * As above, but dump security label for both the specified table (or view)
   16517             :  * and its columns.
   16518             :  */
   16519             : static void
   16520           0 : dumpTableSecLabel(Archive *fout, const TableInfo *tbinfo, const char *reltypename)
   16521             : {
   16522           0 :     DumpOptions *dopt = fout->dopt;
   16523             :     SecLabelItem *labels;
   16524             :     int         nlabels;
   16525             :     int         i;
   16526             :     PQExpBuffer query;
   16527             :     PQExpBuffer target;
   16528             : 
   16529             :     /* do nothing, if --no-security-labels is supplied */
   16530           0 :     if (dopt->no_security_labels)
   16531           0 :         return;
   16532             : 
   16533             :     /* SecLabel are SCHEMA not data */
   16534           0 :     if (!dopt->dumpSchema)
   16535           0 :         return;
   16536             : 
   16537             :     /* Search for comments associated with relation, using table */
   16538           0 :     nlabels = findSecLabels(tbinfo->dobj.catId.tableoid,
   16539           0 :                             tbinfo->dobj.catId.oid,
   16540             :                             &labels);
   16541             : 
   16542             :     /* If security labels exist, build SECURITY LABEL statements */
   16543           0 :     if (nlabels <= 0)
   16544           0 :         return;
   16545             : 
   16546           0 :     query = createPQExpBuffer();
   16547           0 :     target = createPQExpBuffer();
   16548             : 
   16549           0 :     for (i = 0; i < nlabels; i++)
   16550             :     {
   16551             :         const char *colname;
   16552           0 :         const char *provider = labels[i].provider;
   16553           0 :         const char *label = labels[i].label;
   16554           0 :         int         objsubid = labels[i].objsubid;
   16555             : 
   16556           0 :         resetPQExpBuffer(target);
   16557           0 :         if (objsubid == 0)
   16558             :         {
   16559           0 :             appendPQExpBuffer(target, "%s %s", reltypename,
   16560           0 :                               fmtQualifiedDumpable(tbinfo));
   16561             :         }
   16562             :         else
   16563             :         {
   16564           0 :             colname = getAttrName(objsubid, tbinfo);
   16565             :             /* first fmtXXX result must be consumed before calling again */
   16566           0 :             appendPQExpBuffer(target, "COLUMN %s",
   16567           0 :                               fmtQualifiedDumpable(tbinfo));
   16568           0 :             appendPQExpBuffer(target, ".%s", fmtId(colname));
   16569             :         }
   16570           0 :         appendPQExpBuffer(query, "SECURITY LABEL FOR %s ON %s IS ",
   16571             :                           fmtId(provider), target->data);
   16572           0 :         appendStringLiteralAH(query, label, fout);
   16573           0 :         appendPQExpBufferStr(query, ";\n");
   16574             :     }
   16575           0 :     if (query->len > 0)
   16576             :     {
   16577           0 :         resetPQExpBuffer(target);
   16578           0 :         appendPQExpBuffer(target, "%s %s", reltypename,
   16579           0 :                           fmtId(tbinfo->dobj.name));
   16580           0 :         ArchiveEntry(fout, nilCatalogId, createDumpId(),
   16581           0 :                      ARCHIVE_OPTS(.tag = target->data,
   16582             :                                   .namespace = tbinfo->dobj.namespace->dobj.name,
   16583             :                                   .owner = tbinfo->rolname,
   16584             :                                   .description = "SECURITY LABEL",
   16585             :                                   .section = SECTION_NONE,
   16586             :                                   .createStmt = query->data,
   16587             :                                   .deps = &(tbinfo->dobj.dumpId),
   16588             :                                   .nDeps = 1));
   16589             :     }
   16590           0 :     destroyPQExpBuffer(query);
   16591           0 :     destroyPQExpBuffer(target);
   16592             : }
   16593             : 
   16594             : /*
   16595             :  * findSecLabels
   16596             :  *
   16597             :  * Find the security label(s), if any, associated with the given object.
   16598             :  * All the objsubid values associated with the given classoid/objoid are
   16599             :  * found with one search.
   16600             :  */
   16601             : static int
   16602           0 : findSecLabels(Oid classoid, Oid objoid, SecLabelItem **items)
   16603             : {
   16604           0 :     SecLabelItem *middle = NULL;
   16605             :     SecLabelItem *low;
   16606             :     SecLabelItem *high;
   16607             :     int         nmatch;
   16608             : 
   16609           0 :     if (nseclabels <= 0)     /* no labels, so no match is possible */
   16610             :     {
   16611           0 :         *items = NULL;
   16612           0 :         return 0;
   16613             :     }
   16614             : 
   16615             :     /*
   16616             :      * Do binary search to find some item matching the object.
   16617             :      */
   16618           0 :     low = &seclabels[0];
   16619           0 :     high = &seclabels[nseclabels - 1];
   16620           0 :     while (low <= high)
   16621             :     {
   16622           0 :         middle = low + (high - low) / 2;
   16623             : 
   16624           0 :         if (classoid < middle->classoid)
   16625           0 :             high = middle - 1;
   16626           0 :         else if (classoid > middle->classoid)
   16627           0 :             low = middle + 1;
   16628           0 :         else if (objoid < middle->objoid)
   16629           0 :             high = middle - 1;
   16630           0 :         else if (objoid > middle->objoid)
   16631           0 :             low = middle + 1;
   16632             :         else
   16633           0 :             break;              /* found a match */
   16634             :     }
   16635             : 
   16636           0 :     if (low > high)              /* no matches */
   16637             :     {
   16638           0 :         *items = NULL;
   16639           0 :         return 0;
   16640             :     }
   16641             : 
   16642             :     /*
   16643             :      * Now determine how many items match the object.  The search loop
   16644             :      * invariant still holds: only items between low and high inclusive could
   16645             :      * match.
   16646             :      */
   16647           0 :     nmatch = 1;
   16648           0 :     while (middle > low)
   16649             :     {
   16650           0 :         if (classoid != middle[-1].classoid ||
   16651           0 :             objoid != middle[-1].objoid)
   16652             :             break;
   16653           0 :         middle--;
   16654           0 :         nmatch++;
   16655             :     }
   16656             : 
   16657           0 :     *items = middle;
   16658             : 
   16659           0 :     middle += nmatch;
   16660           0 :     while (middle <= high)
   16661             :     {
   16662           0 :         if (classoid != middle->classoid ||
   16663           0 :             objoid != middle->objoid)
   16664             :             break;
   16665           0 :         middle++;
   16666           0 :         nmatch++;
   16667             :     }
   16668             : 
   16669           0 :     return nmatch;
   16670             : }
   16671             : 
   16672             : /*
   16673             :  * collectSecLabels
   16674             :  *
   16675             :  * Construct a table of all security labels available for database objects;
   16676             :  * also set the has-seclabel component flag for each relevant object.
   16677             :  *
   16678             :  * The table is sorted by classoid/objid/objsubid for speed in lookup.
   16679             :  */
   16680             : static void
   16681         364 : collectSecLabels(Archive *fout)
   16682             : {
   16683             :     PGresult   *res;
   16684             :     PQExpBuffer query;
   16685             :     int         i_label;
   16686             :     int         i_provider;
   16687             :     int         i_classoid;
   16688             :     int         i_objoid;
   16689             :     int         i_objsubid;
   16690             :     int         ntups;
   16691             :     int         i;
   16692             :     DumpableObject *dobj;
   16693             : 
   16694         364 :     query = createPQExpBuffer();
   16695             : 
   16696         364 :     appendPQExpBufferStr(query,
   16697             :                          "SELECT label, provider, classoid, objoid, objsubid "
   16698             :                          "FROM pg_catalog.pg_seclabel "
   16699             :                          "ORDER BY classoid, objoid, objsubid");
   16700             : 
   16701         364 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   16702             : 
   16703             :     /* Construct lookup table containing OIDs in numeric form */
   16704         364 :     i_label = PQfnumber(res, "label");
   16705         364 :     i_provider = PQfnumber(res, "provider");
   16706         364 :     i_classoid = PQfnumber(res, "classoid");
   16707         364 :     i_objoid = PQfnumber(res, "objoid");
   16708         364 :     i_objsubid = PQfnumber(res, "objsubid");
   16709             : 
   16710         364 :     ntups = PQntuples(res);
   16711             : 
   16712         364 :     seclabels = (SecLabelItem *) pg_malloc(ntups * sizeof(SecLabelItem));
   16713         364 :     nseclabels = 0;
   16714         364 :     dobj = NULL;
   16715             : 
   16716         364 :     for (i = 0; i < ntups; i++)
   16717             :     {
   16718             :         CatalogId   objId;
   16719             :         int         subid;
   16720             : 
   16721           0 :         objId.tableoid = atooid(PQgetvalue(res, i, i_classoid));
   16722           0 :         objId.oid = atooid(PQgetvalue(res, i, i_objoid));
   16723           0 :         subid = atoi(PQgetvalue(res, i, i_objsubid));
   16724             : 
   16725             :         /* We needn't remember labels that don't match any dumpable object */
   16726           0 :         if (dobj == NULL ||
   16727           0 :             dobj->catId.tableoid != objId.tableoid ||
   16728           0 :             dobj->catId.oid != objId.oid)
   16729           0 :             dobj = findObjectByCatalogId(objId);
   16730           0 :         if (dobj == NULL)
   16731           0 :             continue;
   16732             : 
   16733             :         /*
   16734             :          * Labels on columns of composite types are linked to the type's
   16735             :          * pg_class entry, but we need to set the DUMP_COMPONENT_SECLABEL flag
   16736             :          * in the type's own DumpableObject.
   16737             :          */
   16738           0 :         if (subid != 0 && dobj->objType == DO_TABLE &&
   16739           0 :             ((TableInfo *) dobj)->relkind == RELKIND_COMPOSITE_TYPE)
   16740           0 :         {
   16741             :             TypeInfo   *cTypeInfo;
   16742             : 
   16743           0 :             cTypeInfo = findTypeByOid(((TableInfo *) dobj)->reltype);
   16744           0 :             if (cTypeInfo)
   16745           0 :                 cTypeInfo->dobj.components |= DUMP_COMPONENT_SECLABEL;
   16746             :         }
   16747             :         else
   16748           0 :             dobj->components |= DUMP_COMPONENT_SECLABEL;
   16749             : 
   16750           0 :         seclabels[nseclabels].label = pg_strdup(PQgetvalue(res, i, i_label));
   16751           0 :         seclabels[nseclabels].provider = pg_strdup(PQgetvalue(res, i, i_provider));
   16752           0 :         seclabels[nseclabels].classoid = objId.tableoid;
   16753           0 :         seclabels[nseclabels].objoid = objId.oid;
   16754           0 :         seclabels[nseclabels].objsubid = subid;
   16755           0 :         nseclabels++;
   16756             :     }
   16757             : 
   16758         364 :     PQclear(res);
   16759         364 :     destroyPQExpBuffer(query);
   16760         364 : }
   16761             : 
   16762             : /*
   16763             :  * dumpTable
   16764             :  *    write out to fout the declarations (not data) of a user-defined table
   16765             :  */
   16766             : static void
   16767       61058 : dumpTable(Archive *fout, const TableInfo *tbinfo)
   16768             : {
   16769       61058 :     DumpOptions *dopt = fout->dopt;
   16770       61058 :     DumpId      tableAclDumpId = InvalidDumpId;
   16771             :     char       *namecopy;
   16772             : 
   16773             :     /* Do nothing if not dumping schema */
   16774       61058 :     if (!dopt->dumpSchema)
   16775        3036 :         return;
   16776             : 
   16777       58022 :     if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   16778             :     {
   16779       13636 :         if (tbinfo->relkind == RELKIND_SEQUENCE)
   16780         768 :             dumpSequence(fout, tbinfo);
   16781             :         else
   16782       12868 :             dumpTableSchema(fout, tbinfo);
   16783             :     }
   16784             : 
   16785             :     /* Handle the ACL here */
   16786       58022 :     namecopy = pg_strdup(fmtId(tbinfo->dobj.name));
   16787       58022 :     if (tbinfo->dobj.dump & DUMP_COMPONENT_ACL)
   16788             :     {
   16789       45864 :         const char *objtype =
   16790       45864 :             (tbinfo->relkind == RELKIND_SEQUENCE) ? "SEQUENCE" : "TABLE";
   16791             : 
   16792             :         tableAclDumpId =
   16793       45864 :             dumpACL(fout, tbinfo->dobj.dumpId, InvalidDumpId,
   16794             :                     objtype, namecopy, NULL,
   16795       45864 :                     tbinfo->dobj.namespace->dobj.name,
   16796       45864 :                     NULL, tbinfo->rolname, &tbinfo->dacl);
   16797             :     }
   16798             : 
   16799             :     /*
   16800             :      * Handle column ACLs, if any.  Note: we pull these with a separate query
   16801             :      * rather than trying to fetch them during getTableAttrs, so that we won't
   16802             :      * miss ACLs on system columns.  Doing it this way also allows us to dump
   16803             :      * ACLs for catalogs that we didn't mark "interesting" back in getTables.
   16804             :      */
   16805       58022 :     if ((tbinfo->dobj.dump & DUMP_COMPONENT_ACL) && tbinfo->hascolumnACLs)
   16806             :     {
   16807         572 :         PQExpBuffer query = createPQExpBuffer();
   16808             :         PGresult   *res;
   16809             :         int         i;
   16810             : 
   16811         572 :         if (!fout->is_prepared[PREPQUERY_GETCOLUMNACLS])
   16812             :         {
   16813             :             /* Set up query for column ACLs */
   16814         312 :             appendPQExpBufferStr(query,
   16815             :                                  "PREPARE getColumnACLs(pg_catalog.oid) AS\n");
   16816             : 
   16817         312 :             if (fout->remoteVersion >= 90600)
   16818             :             {
   16819             :                 /*
   16820             :                  * In principle we should call acldefault('c', relowner) to
   16821             :                  * get the default ACL for a column.  However, we don't
   16822             :                  * currently store the numeric OID of the relowner in
   16823             :                  * TableInfo.  We could convert the owner name using regrole,
   16824             :                  * but that creates a risk of failure due to concurrent role
   16825             :                  * renames.  Given that the default ACL for columns is empty
   16826             :                  * and is likely to stay that way, it's not worth extra cycles
   16827             :                  * and risk to avoid hard-wiring that knowledge here.
   16828             :                  */
   16829         312 :                 appendPQExpBufferStr(query,
   16830             :                                      "SELECT at.attname, "
   16831             :                                      "at.attacl, "
   16832             :                                      "'{}' AS acldefault, "
   16833             :                                      "pip.privtype, pip.initprivs "
   16834             :                                      "FROM pg_catalog.pg_attribute at "
   16835             :                                      "LEFT JOIN pg_catalog.pg_init_privs pip ON "
   16836             :                                      "(at.attrelid = pip.objoid "
   16837             :                                      "AND pip.classoid = 'pg_catalog.pg_class'::pg_catalog.regclass "
   16838             :                                      "AND at.attnum = pip.objsubid) "
   16839             :                                      "WHERE at.attrelid = $1 AND "
   16840             :                                      "NOT at.attisdropped "
   16841             :                                      "AND (at.attacl IS NOT NULL OR pip.initprivs IS NOT NULL) "
   16842             :                                      "ORDER BY at.attnum");
   16843             :             }
   16844             :             else
   16845             :             {
   16846           0 :                 appendPQExpBufferStr(query,
   16847             :                                      "SELECT attname, attacl, '{}' AS acldefault, "
   16848             :                                      "NULL AS privtype, NULL AS initprivs "
   16849             :                                      "FROM pg_catalog.pg_attribute "
   16850             :                                      "WHERE attrelid = $1 AND NOT attisdropped "
   16851             :                                      "AND attacl IS NOT NULL "
   16852             :                                      "ORDER BY attnum");
   16853             :             }
   16854             : 
   16855         312 :             ExecuteSqlStatement(fout, query->data);
   16856             : 
   16857         312 :             fout->is_prepared[PREPQUERY_GETCOLUMNACLS] = true;
   16858             :         }
   16859             : 
   16860         572 :         printfPQExpBuffer(query,
   16861             :                           "EXECUTE getColumnACLs('%u')",
   16862         572 :                           tbinfo->dobj.catId.oid);
   16863             : 
   16864         572 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   16865             : 
   16866        8366 :         for (i = 0; i < PQntuples(res); i++)
   16867             :         {
   16868        7794 :             char       *attname = PQgetvalue(res, i, 0);
   16869        7794 :             char       *attacl = PQgetvalue(res, i, 1);
   16870        7794 :             char       *acldefault = PQgetvalue(res, i, 2);
   16871        7794 :             char        privtype = *(PQgetvalue(res, i, 3));
   16872        7794 :             char       *initprivs = PQgetvalue(res, i, 4);
   16873             :             DumpableAcl coldacl;
   16874             :             char       *attnamecopy;
   16875             : 
   16876        7794 :             coldacl.acl = attacl;
   16877        7794 :             coldacl.acldefault = acldefault;
   16878        7794 :             coldacl.privtype = privtype;
   16879        7794 :             coldacl.initprivs = initprivs;
   16880        7794 :             attnamecopy = pg_strdup(fmtId(attname));
   16881             : 
   16882             :             /*
   16883             :              * Column's GRANT type is always TABLE.  Each column ACL depends
   16884             :              * on the table-level ACL, since we can restore column ACLs in
   16885             :              * parallel but the table-level ACL has to be done first.
   16886             :              */
   16887        7794 :             dumpACL(fout, tbinfo->dobj.dumpId, tableAclDumpId,
   16888             :                     "TABLE", namecopy, attnamecopy,
   16889        7794 :                     tbinfo->dobj.namespace->dobj.name,
   16890        7794 :                     NULL, tbinfo->rolname, &coldacl);
   16891        7794 :             free(attnamecopy);
   16892             :         }
   16893         572 :         PQclear(res);
   16894         572 :         destroyPQExpBuffer(query);
   16895             :     }
   16896             : 
   16897       58022 :     free(namecopy);
   16898             : }
   16899             : 
   16900             : /*
   16901             :  * Create the AS clause for a view or materialized view. The semicolon is
   16902             :  * stripped because a materialized view must add a WITH NO DATA clause.
   16903             :  *
   16904             :  * This returns a new buffer which must be freed by the caller.
   16905             :  */
   16906             : static PQExpBuffer
   16907        1846 : createViewAsClause(Archive *fout, const TableInfo *tbinfo)
   16908             : {
   16909        1846 :     PQExpBuffer query = createPQExpBuffer();
   16910        1846 :     PQExpBuffer result = createPQExpBuffer();
   16911             :     PGresult   *res;
   16912             :     int         len;
   16913             : 
   16914             :     /* Fetch the view definition */
   16915        1846 :     appendPQExpBuffer(query,
   16916             :                       "SELECT pg_catalog.pg_get_viewdef('%u'::pg_catalog.oid) AS viewdef",
   16917        1846 :                       tbinfo->dobj.catId.oid);
   16918             : 
   16919        1846 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   16920             : 
   16921        1846 :     if (PQntuples(res) != 1)
   16922             :     {
   16923           0 :         if (PQntuples(res) < 1)
   16924           0 :             pg_fatal("query to obtain definition of view \"%s\" returned no data",
   16925             :                      tbinfo->dobj.name);
   16926             :         else
   16927           0 :             pg_fatal("query to obtain definition of view \"%s\" returned more than one definition",
   16928             :                      tbinfo->dobj.name);
   16929             :     }
   16930             : 
   16931        1846 :     len = PQgetlength(res, 0, 0);
   16932             : 
   16933        1846 :     if (len == 0)
   16934           0 :         pg_fatal("definition of view \"%s\" appears to be empty (length zero)",
   16935             :                  tbinfo->dobj.name);
   16936             : 
   16937             :     /* Strip off the trailing semicolon so that other things may follow. */
   16938             :     Assert(PQgetvalue(res, 0, 0)[len - 1] == ';');
   16939        1846 :     appendBinaryPQExpBuffer(result, PQgetvalue(res, 0, 0), len - 1);
   16940             : 
   16941        1846 :     PQclear(res);
   16942        1846 :     destroyPQExpBuffer(query);
   16943             : 
   16944        1846 :     return result;
   16945             : }
   16946             : 
   16947             : /*
   16948             :  * Create a dummy AS clause for a view.  This is used when the real view
   16949             :  * definition has to be postponed because of circular dependencies.
   16950             :  * We must duplicate the view's external properties -- column names and types
   16951             :  * (including collation) -- so that it works for subsequent references.
   16952             :  *
   16953             :  * This returns a new buffer which must be freed by the caller.
   16954             :  */
   16955             : static PQExpBuffer
   16956          40 : createDummyViewAsClause(Archive *fout, const TableInfo *tbinfo)
   16957             : {
   16958          40 :     PQExpBuffer result = createPQExpBuffer();
   16959             :     int         j;
   16960             : 
   16961          40 :     appendPQExpBufferStr(result, "SELECT");
   16962             : 
   16963          80 :     for (j = 0; j < tbinfo->numatts; j++)
   16964             :     {
   16965          40 :         if (j > 0)
   16966          20 :             appendPQExpBufferChar(result, ',');
   16967          40 :         appendPQExpBufferStr(result, "\n    ");
   16968             : 
   16969          40 :         appendPQExpBuffer(result, "NULL::%s", tbinfo->atttypnames[j]);
   16970             : 
   16971             :         /*
   16972             :          * Must add collation if not default for the type, because CREATE OR
   16973             :          * REPLACE VIEW won't change it
   16974             :          */
   16975          40 :         if (OidIsValid(tbinfo->attcollation[j]))
   16976             :         {
   16977             :             CollInfo   *coll;
   16978             : 
   16979           0 :             coll = findCollationByOid(tbinfo->attcollation[j]);
   16980           0 :             if (coll)
   16981           0 :                 appendPQExpBuffer(result, " COLLATE %s",
   16982           0 :                                   fmtQualifiedDumpable(coll));
   16983             :         }
   16984             : 
   16985          40 :         appendPQExpBuffer(result, " AS %s", fmtId(tbinfo->attnames[j]));
   16986             :     }
   16987             : 
   16988          40 :     return result;
   16989             : }
   16990             : 
   16991             : /*
   16992             :  * dumpTableSchema
   16993             :  *    write the declaration (not data) of one user-defined table or view
   16994             :  */
   16995             : static void
   16996       12868 : dumpTableSchema(Archive *fout, const TableInfo *tbinfo)
   16997             : {
   16998       12868 :     DumpOptions *dopt = fout->dopt;
   16999       12868 :     PQExpBuffer q = createPQExpBuffer();
   17000       12868 :     PQExpBuffer delq = createPQExpBuffer();
   17001       12868 :     PQExpBuffer extra = createPQExpBuffer();
   17002             :     char       *qrelname;
   17003             :     char       *qualrelname;
   17004             :     int         numParents;
   17005             :     TableInfo **parents;
   17006             :     int         actual_atts;    /* number of attrs in this CREATE statement */
   17007             :     const char *reltypename;
   17008             :     char       *storage;
   17009             :     int         j,
   17010             :                 k;
   17011             : 
   17012             :     /* We had better have loaded per-column details about this table */
   17013             :     Assert(tbinfo->interesting);
   17014             : 
   17015       12868 :     qrelname = pg_strdup(fmtId(tbinfo->dobj.name));
   17016       12868 :     qualrelname = pg_strdup(fmtQualifiedDumpable(tbinfo));
   17017             : 
   17018       12868 :     if (tbinfo->hasoids)
   17019           0 :         pg_log_warning("WITH OIDS is not supported anymore (table \"%s\")",
   17020             :                        qrelname);
   17021             : 
   17022       12868 :     if (dopt->binary_upgrade)
   17023        1736 :         binary_upgrade_set_type_oids_by_rel(fout, q, tbinfo);
   17024             : 
   17025             :     /* Is it a table or a view? */
   17026       12868 :     if (tbinfo->relkind == RELKIND_VIEW)
   17027             :     {
   17028             :         PQExpBuffer result;
   17029             : 
   17030             :         /*
   17031             :          * Note: keep this code in sync with the is_view case in dumpRule()
   17032             :          */
   17033             : 
   17034        1066 :         reltypename = "VIEW";
   17035             : 
   17036        1066 :         appendPQExpBuffer(delq, "DROP VIEW %s;\n", qualrelname);
   17037             : 
   17038        1066 :         if (dopt->binary_upgrade)
   17039         104 :             binary_upgrade_set_pg_class_oids(fout, q,
   17040         104 :                                              tbinfo->dobj.catId.oid);
   17041             : 
   17042        1066 :         appendPQExpBuffer(q, "CREATE VIEW %s", qualrelname);
   17043             : 
   17044        1066 :         if (tbinfo->dummy_view)
   17045          20 :             result = createDummyViewAsClause(fout, tbinfo);
   17046             :         else
   17047             :         {
   17048        1046 :             if (nonemptyReloptions(tbinfo->reloptions))
   17049             :             {
   17050         128 :                 appendPQExpBufferStr(q, " WITH (");
   17051         128 :                 appendReloptionsArrayAH(q, tbinfo->reloptions, "", fout);
   17052         128 :                 appendPQExpBufferChar(q, ')');
   17053             :             }
   17054        1046 :             result = createViewAsClause(fout, tbinfo);
   17055             :         }
   17056        1066 :         appendPQExpBuffer(q, " AS\n%s", result->data);
   17057        1066 :         destroyPQExpBuffer(result);
   17058             : 
   17059        1066 :         if (tbinfo->checkoption != NULL && !tbinfo->dummy_view)
   17060          70 :             appendPQExpBuffer(q, "\n  WITH %s CHECK OPTION", tbinfo->checkoption);
   17061        1066 :         appendPQExpBufferStr(q, ";\n");
   17062             :     }
   17063             :     else
   17064             :     {
   17065       11802 :         char       *partkeydef = NULL;
   17066       11802 :         char       *ftoptions = NULL;
   17067       11802 :         char       *srvname = NULL;
   17068       11802 :         const char *foreign = "";
   17069             : 
   17070             :         /*
   17071             :          * Set reltypename, and collect any relkind-specific data that we
   17072             :          * didn't fetch during getTables().
   17073             :          */
   17074       11802 :         switch (tbinfo->relkind)
   17075             :         {
   17076        1156 :             case RELKIND_PARTITIONED_TABLE:
   17077             :                 {
   17078        1156 :                     PQExpBuffer query = createPQExpBuffer();
   17079             :                     PGresult   *res;
   17080             : 
   17081        1156 :                     reltypename = "TABLE";
   17082             : 
   17083             :                     /* retrieve partition key definition */
   17084        1156 :                     appendPQExpBuffer(query,
   17085             :                                       "SELECT pg_get_partkeydef('%u')",
   17086        1156 :                                       tbinfo->dobj.catId.oid);
   17087        1156 :                     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   17088        1156 :                     partkeydef = pg_strdup(PQgetvalue(res, 0, 0));
   17089        1156 :                     PQclear(res);
   17090        1156 :                     destroyPQExpBuffer(query);
   17091        1156 :                     break;
   17092             :                 }
   17093          74 :             case RELKIND_FOREIGN_TABLE:
   17094             :                 {
   17095          74 :                     PQExpBuffer query = createPQExpBuffer();
   17096             :                     PGresult   *res;
   17097             :                     int         i_srvname;
   17098             :                     int         i_ftoptions;
   17099             : 
   17100          74 :                     reltypename = "FOREIGN TABLE";
   17101             : 
   17102             :                     /* retrieve name of foreign server and generic options */
   17103          74 :                     appendPQExpBuffer(query,
   17104             :                                       "SELECT fs.srvname, "
   17105             :                                       "pg_catalog.array_to_string(ARRAY("
   17106             :                                       "SELECT pg_catalog.quote_ident(option_name) || "
   17107             :                                       "' ' || pg_catalog.quote_literal(option_value) "
   17108             :                                       "FROM pg_catalog.pg_options_to_table(ftoptions) "
   17109             :                                       "ORDER BY option_name"
   17110             :                                       "), E',\n    ') AS ftoptions "
   17111             :                                       "FROM pg_catalog.pg_foreign_table ft "
   17112             :                                       "JOIN pg_catalog.pg_foreign_server fs "
   17113             :                                       "ON (fs.oid = ft.ftserver) "
   17114             :                                       "WHERE ft.ftrelid = '%u'",
   17115          74 :                                       tbinfo->dobj.catId.oid);
   17116          74 :                     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   17117          74 :                     i_srvname = PQfnumber(res, "srvname");
   17118          74 :                     i_ftoptions = PQfnumber(res, "ftoptions");
   17119          74 :                     srvname = pg_strdup(PQgetvalue(res, 0, i_srvname));
   17120          74 :                     ftoptions = pg_strdup(PQgetvalue(res, 0, i_ftoptions));
   17121          74 :                     PQclear(res);
   17122          74 :                     destroyPQExpBuffer(query);
   17123             : 
   17124          74 :                     foreign = "FOREIGN ";
   17125          74 :                     break;
   17126             :                 }
   17127         780 :             case RELKIND_MATVIEW:
   17128         780 :                 reltypename = "MATERIALIZED VIEW";
   17129         780 :                 break;
   17130        9792 :             default:
   17131        9792 :                 reltypename = "TABLE";
   17132        9792 :                 break;
   17133             :         }
   17134             : 
   17135       11802 :         numParents = tbinfo->numParents;
   17136       11802 :         parents = tbinfo->parents;
   17137             : 
   17138       11802 :         appendPQExpBuffer(delq, "DROP %s %s;\n", reltypename, qualrelname);
   17139             : 
   17140       11802 :         if (dopt->binary_upgrade)
   17141        1632 :             binary_upgrade_set_pg_class_oids(fout, q,
   17142        1632 :                                              tbinfo->dobj.catId.oid);
   17143             : 
   17144             :         /*
   17145             :          * PostgreSQL 18 has disabled UNLOGGED for partitioned tables, so
   17146             :          * ignore it when dumping if it was set in this case.
   17147             :          */
   17148       11802 :         appendPQExpBuffer(q, "CREATE %s%s %s",
   17149       11802 :                           (tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED &&
   17150          40 :                            tbinfo->relkind != RELKIND_PARTITIONED_TABLE) ?
   17151             :                           "UNLOGGED " : "",
   17152             :                           reltypename,
   17153             :                           qualrelname);
   17154             : 
   17155             :         /*
   17156             :          * Attach to type, if reloftype; except in case of a binary upgrade,
   17157             :          * we dump the table normally and attach it to the type afterward.
   17158             :          */
   17159       11802 :         if (OidIsValid(tbinfo->reloftype) && !dopt->binary_upgrade)
   17160          48 :             appendPQExpBuffer(q, " OF %s",
   17161          48 :                               getFormattedTypeName(fout, tbinfo->reloftype,
   17162             :                                                    zeroIsError));
   17163             : 
   17164       11802 :         if (tbinfo->relkind != RELKIND_MATVIEW)
   17165             :         {
   17166             :             /* Dump the attributes */
   17167       11022 :             actual_atts = 0;
   17168       51178 :             for (j = 0; j < tbinfo->numatts; j++)
   17169             :             {
   17170             :                 /*
   17171             :                  * Normally, dump if it's locally defined in this table, and
   17172             :                  * not dropped.  But for binary upgrade, we'll dump all the
   17173             :                  * columns, and then fix up the dropped and nonlocal cases
   17174             :                  * below.
   17175             :                  */
   17176       40156 :                 if (shouldPrintColumn(dopt, tbinfo, j))
   17177             :                 {
   17178             :                     bool        print_default;
   17179             :                     bool        print_notnull;
   17180             : 
   17181             :                     /*
   17182             :                      * Default value --- suppress if to be printed separately
   17183             :                      * or not at all.
   17184             :                      */
   17185       78458 :                     print_default = (tbinfo->attrdefs[j] != NULL &&
   17186       40208 :                                      tbinfo->attrdefs[j]->dobj.dump &&
   17187        2058 :                                      !tbinfo->attrdefs[j]->separate);
   17188             : 
   17189             :                     /*
   17190             :                      * Not Null constraint --- print it if it is locally
   17191             :                      * defined, or if binary upgrade.  (In the latter case, we
   17192             :                      * reset conislocal below.)
   17193             :                      */
   17194       42710 :                     print_notnull = (tbinfo->notnull_constrs[j] != NULL &&
   17195        4560 :                                      (tbinfo->notnull_islocal[j] ||
   17196        1268 :                                       dopt->binary_upgrade ||
   17197        1100 :                                       tbinfo->ispartition));
   17198             : 
   17199             :                     /*
   17200             :                      * Skip column if fully defined by reloftype, except in
   17201             :                      * binary upgrade
   17202             :                      */
   17203       38150 :                     if (OidIsValid(tbinfo->reloftype) &&
   17204         100 :                         !print_default && !print_notnull &&
   17205          60 :                         !dopt->binary_upgrade)
   17206          48 :                         continue;
   17207             : 
   17208             :                     /* Format properly if not first attr */
   17209       38102 :                     if (actual_atts == 0)
   17210       10342 :                         appendPQExpBufferStr(q, " (");
   17211             :                     else
   17212       27760 :                         appendPQExpBufferChar(q, ',');
   17213       38102 :                     appendPQExpBufferStr(q, "\n    ");
   17214       38102 :                     actual_atts++;
   17215             : 
   17216             :                     /* Attribute name */
   17217       38102 :                     appendPQExpBufferStr(q, fmtId(tbinfo->attnames[j]));
   17218             : 
   17219       38102 :                     if (tbinfo->attisdropped[j])
   17220             :                     {
   17221             :                         /*
   17222             :                          * ALTER TABLE DROP COLUMN clears
   17223             :                          * pg_attribute.atttypid, so we will not have gotten a
   17224             :                          * valid type name; insert INTEGER as a stopgap. We'll
   17225             :                          * clean things up later.
   17226             :                          */
   17227         168 :                         appendPQExpBufferStr(q, " INTEGER /* dummy */");
   17228             :                         /* and skip to the next column */
   17229         168 :                         continue;
   17230             :                     }
   17231             : 
   17232             :                     /*
   17233             :                      * Attribute type; print it except when creating a typed
   17234             :                      * table ('OF type_name'), but in binary-upgrade mode,
   17235             :                      * print it in that case too.
   17236             :                      */
   17237       37934 :                     if (dopt->binary_upgrade || !OidIsValid(tbinfo->reloftype))
   17238             :                     {
   17239       37902 :                         appendPQExpBuffer(q, " %s",
   17240       37902 :                                           tbinfo->atttypnames[j]);
   17241             :                     }
   17242             : 
   17243       37934 :                     if (print_default)
   17244             :                     {
   17245        1786 :                         if (tbinfo->attgenerated[j] == ATTRIBUTE_GENERATED_STORED)
   17246         572 :                             appendPQExpBuffer(q, " GENERATED ALWAYS AS (%s) STORED",
   17247         572 :                                               tbinfo->attrdefs[j]->adef_expr);
   17248        1214 :                         else if (tbinfo->attgenerated[j] == ATTRIBUTE_GENERATED_VIRTUAL)
   17249         452 :                             appendPQExpBuffer(q, " GENERATED ALWAYS AS (%s)",
   17250         452 :                                               tbinfo->attrdefs[j]->adef_expr);
   17251             :                         else
   17252         762 :                             appendPQExpBuffer(q, " DEFAULT %s",
   17253         762 :                                               tbinfo->attrdefs[j]->adef_expr);
   17254             :                     }
   17255             : 
   17256       37934 :                     if (print_notnull)
   17257             :                     {
   17258        4492 :                         if (tbinfo->notnull_constrs[j][0] == '\0')
   17259        3170 :                             appendPQExpBufferStr(q, " NOT NULL");
   17260             :                         else
   17261        1322 :                             appendPQExpBuffer(q, " CONSTRAINT %s NOT NULL",
   17262        1322 :                                               fmtId(tbinfo->notnull_constrs[j]));
   17263             : 
   17264        4492 :                         if (tbinfo->notnull_noinh[j])
   17265           0 :                             appendPQExpBufferStr(q, " NO INHERIT");
   17266             :                     }
   17267             : 
   17268             :                     /* Add collation if not default for the type */
   17269       37934 :                     if (OidIsValid(tbinfo->attcollation[j]))
   17270             :                     {
   17271             :                         CollInfo   *coll;
   17272             : 
   17273         394 :                         coll = findCollationByOid(tbinfo->attcollation[j]);
   17274         394 :                         if (coll)
   17275         394 :                             appendPQExpBuffer(q, " COLLATE %s",
   17276         394 :                                               fmtQualifiedDumpable(coll));
   17277             :                     }
   17278             :                 }
   17279             : 
   17280             :                 /*
   17281             :                  * On the other hand, if we choose not to print a column
   17282             :                  * (likely because it is created by inheritance), but the
   17283             :                  * column has a locally-defined not-null constraint, we need
   17284             :                  * to dump the constraint as a standalone object.
   17285             :                  *
   17286             :                  * This syntax isn't SQL-conforming, but if you wanted
   17287             :                  * standard output you wouldn't be creating non-standard
   17288             :                  * objects to begin with.
   17289             :                  */
   17290       39940 :                 if (!shouldPrintColumn(dopt, tbinfo, j) &&
   17291        2006 :                     !tbinfo->attisdropped[j] &&
   17292        1274 :                     tbinfo->notnull_constrs[j] != NULL &&
   17293         364 :                     tbinfo->notnull_islocal[j])
   17294             :                 {
   17295             :                     /* Format properly if not first attr */
   17296         116 :                     if (actual_atts == 0)
   17297         108 :                         appendPQExpBufferStr(q, " (");
   17298             :                     else
   17299           8 :                         appendPQExpBufferChar(q, ',');
   17300         116 :                     appendPQExpBufferStr(q, "\n    ");
   17301         116 :                     actual_atts++;
   17302             : 
   17303         116 :                     if (tbinfo->notnull_constrs[j][0] == '\0')
   17304           8 :                         appendPQExpBuffer(q, "NOT NULL %s",
   17305           8 :                                           fmtId(tbinfo->attnames[j]));
   17306             :                     else
   17307         216 :                         appendPQExpBuffer(q, "CONSTRAINT %s NOT NULL %s",
   17308         108 :                                           tbinfo->notnull_constrs[j],
   17309         108 :                                           fmtId(tbinfo->attnames[j]));
   17310             :                 }
   17311             :             }
   17312             : 
   17313             :             /*
   17314             :              * Add non-inherited CHECK constraints, if any.
   17315             :              *
   17316             :              * For partitions, we need to include check constraints even if
   17317             :              * they're not defined locally, because the ALTER TABLE ATTACH
   17318             :              * PARTITION that we'll emit later expects the constraint to be
   17319             :              * there.  (No need to fix conislocal: ATTACH PARTITION does that)
   17320             :              */
   17321       12248 :             for (j = 0; j < tbinfo->ncheck; j++)
   17322             :             {
   17323        1226 :                 ConstraintInfo *constr = &(tbinfo->checkexprs[j]);
   17324             : 
   17325        1226 :                 if (constr->separate ||
   17326        1086 :                     (!constr->conislocal && !tbinfo->ispartition))
   17327         220 :                     continue;
   17328             : 
   17329        1006 :                 if (actual_atts == 0)
   17330          32 :                     appendPQExpBufferStr(q, " (\n    ");
   17331             :                 else
   17332         974 :                     appendPQExpBufferStr(q, ",\n    ");
   17333             : 
   17334        1006 :                 appendPQExpBuffer(q, "CONSTRAINT %s ",
   17335        1006 :                                   fmtId(constr->dobj.name));
   17336        1006 :                 appendPQExpBufferStr(q, constr->condef);
   17337             : 
   17338        1006 :                 actual_atts++;
   17339             :             }
   17340             : 
   17341       11022 :             if (actual_atts)
   17342       10482 :                 appendPQExpBufferStr(q, "\n)");
   17343         540 :             else if (!(OidIsValid(tbinfo->reloftype) && !dopt->binary_upgrade))
   17344             :             {
   17345             :                 /*
   17346             :                  * No attributes? we must have a parenthesized attribute list,
   17347             :                  * even though empty, when not using the OF TYPE syntax.
   17348             :                  */
   17349         516 :                 appendPQExpBufferStr(q, " (\n)");
   17350             :             }
   17351             : 
   17352             :             /*
   17353             :              * Emit the INHERITS clause (not for partitions), except in
   17354             :              * binary-upgrade mode.
   17355             :              */
   17356       11022 :             if (numParents > 0 && !tbinfo->ispartition &&
   17357        1004 :                 !dopt->binary_upgrade)
   17358             :             {
   17359         878 :                 appendPQExpBufferStr(q, "\nINHERITS (");
   17360        1904 :                 for (k = 0; k < numParents; k++)
   17361             :                 {
   17362        1026 :                     TableInfo  *parentRel = parents[k];
   17363             : 
   17364        1026 :                     if (k > 0)
   17365         148 :                         appendPQExpBufferStr(q, ", ");
   17366        1026 :                     appendPQExpBufferStr(q, fmtQualifiedDumpable(parentRel));
   17367             :                 }
   17368         878 :                 appendPQExpBufferChar(q, ')');
   17369             :             }
   17370             : 
   17371       11022 :             if (tbinfo->relkind == RELKIND_PARTITIONED_TABLE)
   17372        1156 :                 appendPQExpBuffer(q, "\nPARTITION BY %s", partkeydef);
   17373             : 
   17374       11022 :             if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
   17375          74 :                 appendPQExpBuffer(q, "\nSERVER %s", fmtId(srvname));
   17376             :         }
   17377             : 
   17378       23314 :         if (nonemptyReloptions(tbinfo->reloptions) ||
   17379       11512 :             nonemptyReloptions(tbinfo->toast_reloptions))
   17380             :         {
   17381         290 :             bool        addcomma = false;
   17382             : 
   17383         290 :             appendPQExpBufferStr(q, "\nWITH (");
   17384         290 :             if (nonemptyReloptions(tbinfo->reloptions))
   17385             :             {
   17386         290 :                 addcomma = true;
   17387         290 :                 appendReloptionsArrayAH(q, tbinfo->reloptions, "", fout);
   17388             :             }
   17389         290 :             if (nonemptyReloptions(tbinfo->toast_reloptions))
   17390             :             {
   17391          10 :                 if (addcomma)
   17392          10 :                     appendPQExpBufferStr(q, ", ");
   17393          10 :                 appendReloptionsArrayAH(q, tbinfo->toast_reloptions, "toast.",
   17394             :                                         fout);
   17395             :             }
   17396         290 :             appendPQExpBufferChar(q, ')');
   17397             :         }
   17398             : 
   17399             :         /* Dump generic options if any */
   17400       11802 :         if (ftoptions && ftoptions[0])
   17401          70 :             appendPQExpBuffer(q, "\nOPTIONS (\n    %s\n)", ftoptions);
   17402             : 
   17403             :         /*
   17404             :          * For materialized views, create the AS clause just like a view. At
   17405             :          * this point, we always mark the view as not populated.
   17406             :          */
   17407       11802 :         if (tbinfo->relkind == RELKIND_MATVIEW)
   17408             :         {
   17409             :             PQExpBuffer result;
   17410             : 
   17411         780 :             result = createViewAsClause(fout, tbinfo);
   17412         780 :             appendPQExpBuffer(q, " AS\n%s\n  WITH NO DATA;\n",
   17413             :                               result->data);
   17414         780 :             destroyPQExpBuffer(result);
   17415             :         }
   17416             :         else
   17417       11022 :             appendPQExpBufferStr(q, ";\n");
   17418             : 
   17419             :         /* Materialized views can depend on extensions */
   17420       11802 :         if (tbinfo->relkind == RELKIND_MATVIEW)
   17421         780 :             append_depends_on_extension(fout, q, &tbinfo->dobj,
   17422             :                                         "pg_catalog.pg_class",
   17423             :                                         "MATERIALIZED VIEW",
   17424             :                                         qualrelname);
   17425             : 
   17426             :         /*
   17427             :          * in binary upgrade mode, update the catalog with any missing values
   17428             :          * that might be present.
   17429             :          */
   17430       11802 :         if (dopt->binary_upgrade)
   17431             :         {
   17432        7904 :             for (j = 0; j < tbinfo->numatts; j++)
   17433             :             {
   17434        6272 :                 if (tbinfo->attmissingval[j][0] != '\0')
   17435             :                 {
   17436           4 :                     appendPQExpBufferStr(q, "\n-- set missing value.\n");
   17437           4 :                     appendPQExpBufferStr(q,
   17438             :                                          "SELECT pg_catalog.binary_upgrade_set_missing_value(");
   17439           4 :                     appendStringLiteralAH(q, qualrelname, fout);
   17440           4 :                     appendPQExpBufferStr(q, "::pg_catalog.regclass,");
   17441           4 :                     appendStringLiteralAH(q, tbinfo->attnames[j], fout);
   17442           4 :                     appendPQExpBufferChar(q, ',');
   17443           4 :                     appendStringLiteralAH(q, tbinfo->attmissingval[j], fout);
   17444           4 :                     appendPQExpBufferStr(q, ");\n\n");
   17445             :                 }
   17446             :             }
   17447             :         }
   17448             : 
   17449             :         /*
   17450             :          * To create binary-compatible heap files, we have to ensure the same
   17451             :          * physical column order, including dropped columns, as in the
   17452             :          * original.  Therefore, we create dropped columns above and drop them
   17453             :          * here, also updating their attlen/attalign values so that the
   17454             :          * dropped column can be skipped properly.  (We do not bother with
   17455             :          * restoring the original attbyval setting.)  Also, inheritance
   17456             :          * relationships are set up by doing ALTER TABLE INHERIT rather than
   17457             :          * using an INHERITS clause --- the latter would possibly mess up the
   17458             :          * column order.  That also means we have to take care about setting
   17459             :          * attislocal correctly, plus fix up any inherited CHECK constraints.
   17460             :          * Analogously, we set up typed tables using ALTER TABLE / OF here.
   17461             :          *
   17462             :          * We process foreign and partitioned tables here, even though they
   17463             :          * lack heap storage, because they can participate in inheritance
   17464             :          * relationships and we want this stuff to be consistent across the
   17465             :          * inheritance tree.  We can exclude indexes, toast tables, sequences
   17466             :          * and matviews, even though they have storage, because we don't
   17467             :          * support altering or dropping columns in them, nor can they be part
   17468             :          * of inheritance trees.
   17469             :          */
   17470       11802 :         if (dopt->binary_upgrade &&
   17471        1632 :             (tbinfo->relkind == RELKIND_RELATION ||
   17472         220 :              tbinfo->relkind == RELKIND_FOREIGN_TABLE ||
   17473         218 :              tbinfo->relkind == RELKIND_PARTITIONED_TABLE))
   17474             :         {
   17475             :             bool        firstitem;
   17476             :             bool        firstitem_extra;
   17477             : 
   17478             :             /*
   17479             :              * Drop any dropped columns.  Merge the pg_attribute manipulations
   17480             :              * into a single SQL command, so that we don't cause repeated
   17481             :              * relcache flushes on the target table.  Otherwise we risk O(N^2)
   17482             :              * relcache bloat while dropping N columns.
   17483             :              */
   17484        1596 :             resetPQExpBuffer(extra);
   17485        1596 :             firstitem = true;
   17486        7824 :             for (j = 0; j < tbinfo->numatts; j++)
   17487             :             {
   17488        6228 :                 if (tbinfo->attisdropped[j])
   17489             :                 {
   17490         168 :                     if (firstitem)
   17491             :                     {
   17492          76 :                         appendPQExpBufferStr(q, "\n-- For binary upgrade, recreate dropped columns.\n"
   17493             :                                              "UPDATE pg_catalog.pg_attribute\n"
   17494             :                                              "SET attlen = v.dlen, "
   17495             :                                              "attalign = v.dalign, "
   17496             :                                              "attbyval = false\n"
   17497             :                                              "FROM (VALUES ");
   17498          76 :                         firstitem = false;
   17499             :                     }
   17500             :                     else
   17501          92 :                         appendPQExpBufferStr(q, ",\n             ");
   17502         168 :                     appendPQExpBufferChar(q, '(');
   17503         168 :                     appendStringLiteralAH(q, tbinfo->attnames[j], fout);
   17504         168 :                     appendPQExpBuffer(q, ", %d, '%c')",
   17505         168 :                                       tbinfo->attlen[j],
   17506         168 :                                       tbinfo->attalign[j]);
   17507             :                     /* The ALTER ... DROP COLUMN commands must come after */
   17508         168 :                     appendPQExpBuffer(extra, "ALTER %sTABLE ONLY %s ",
   17509             :                                       foreign, qualrelname);
   17510         168 :                     appendPQExpBuffer(extra, "DROP COLUMN %s;\n",
   17511         168 :                                       fmtId(tbinfo->attnames[j]));
   17512             :                 }
   17513             :             }
   17514        1596 :             if (!firstitem)
   17515             :             {
   17516          76 :                 appendPQExpBufferStr(q, ") v(dname, dlen, dalign)\n"
   17517             :                                      "WHERE attrelid = ");
   17518          76 :                 appendStringLiteralAH(q, qualrelname, fout);
   17519          76 :                 appendPQExpBufferStr(q, "::pg_catalog.regclass\n"
   17520             :                                      "  AND attname = v.dname;\n");
   17521             :                 /* Now we can issue the actual DROP COLUMN commands */
   17522          76 :                 appendBinaryPQExpBuffer(q, extra->data, extra->len);
   17523             :             }
   17524             : 
   17525             :             /*
   17526             :              * Fix up inherited columns.  As above, do the pg_attribute
   17527             :              * manipulations in a single SQL command.
   17528             :              */
   17529        1596 :             firstitem = true;
   17530        7824 :             for (j = 0; j < tbinfo->numatts; j++)
   17531             :             {
   17532        6228 :                 if (!tbinfo->attisdropped[j] &&
   17533        6060 :                     !tbinfo->attislocal[j])
   17534             :                 {
   17535        1206 :                     if (firstitem)
   17536             :                     {
   17537         532 :                         appendPQExpBufferStr(q, "\n-- For binary upgrade, recreate inherited columns.\n");
   17538         532 :                         appendPQExpBufferStr(q, "UPDATE pg_catalog.pg_attribute\n"
   17539             :                                              "SET attislocal = false\n"
   17540             :                                              "WHERE attrelid = ");
   17541         532 :                         appendStringLiteralAH(q, qualrelname, fout);
   17542         532 :                         appendPQExpBufferStr(q, "::pg_catalog.regclass\n"
   17543             :                                              "  AND attname IN (");
   17544         532 :                         firstitem = false;
   17545             :                     }
   17546             :                     else
   17547         674 :                         appendPQExpBufferStr(q, ", ");
   17548        1206 :                     appendStringLiteralAH(q, tbinfo->attnames[j], fout);
   17549             :                 }
   17550             :             }
   17551        1596 :             if (!firstitem)
   17552         532 :                 appendPQExpBufferStr(q, ");\n");
   17553             : 
   17554             :             /*
   17555             :              * Fix up not-null constraints that come from inheritance.  As
   17556             :              * above, do the pg_constraint manipulations in a single SQL
   17557             :              * command.  (Actually, two in special cases, if we're doing an
   17558             :              * upgrade from < 18).
   17559             :              */
   17560        1596 :             firstitem = true;
   17561        1596 :             firstitem_extra = true;
   17562        1596 :             resetPQExpBuffer(extra);
   17563        7824 :             for (j = 0; j < tbinfo->numatts; j++)
   17564             :             {
   17565             :                 /*
   17566             :                  * If a not-null constraint comes from inheritance, reset
   17567             :                  * conislocal.  The inhcount is fixed by ALTER TABLE INHERIT,
   17568             :                  * below.  Special hack: in versions < 18, columns with no
   17569             :                  * local definition need their constraint to be matched by
   17570             :                  * column number in conkeys instead of by constraint name,
   17571             :                  * because the latter is not available.  (We distinguish the
   17572             :                  * case because the constraint name is the empty string.)
   17573             :                  */
   17574        6228 :                 if (tbinfo->notnull_constrs[j] != NULL &&
   17575         580 :                     !tbinfo->notnull_islocal[j])
   17576             :                 {
   17577         168 :                     if (tbinfo->notnull_constrs[j][0] != '\0')
   17578             :                     {
   17579         142 :                         if (firstitem)
   17580             :                         {
   17581         122 :                             appendPQExpBufferStr(q, "UPDATE pg_catalog.pg_constraint\n"
   17582             :                                                  "SET conislocal = false\n"
   17583             :                                                  "WHERE contype = 'n' AND conrelid = ");
   17584         122 :                             appendStringLiteralAH(q, qualrelname, fout);
   17585         122 :                             appendPQExpBufferStr(q, "::pg_catalog.regclass AND\n"
   17586             :                                                  "conname IN (");
   17587         122 :                             firstitem = false;
   17588             :                         }
   17589             :                         else
   17590          20 :                             appendPQExpBufferStr(q, ", ");
   17591         142 :                         appendStringLiteralAH(q, tbinfo->notnull_constrs[j], fout);
   17592             :                     }
   17593             :                     else
   17594             :                     {
   17595          26 :                         if (firstitem_extra)
   17596             :                         {
   17597          26 :                             appendPQExpBufferStr(extra, "UPDATE pg_catalog.pg_constraint\n"
   17598             :                                                  "SET conislocal = false\n"
   17599             :                                                  "WHERE contype = 'n' AND conrelid = ");
   17600          26 :                             appendStringLiteralAH(extra, qualrelname, fout);
   17601          26 :                             appendPQExpBufferStr(extra, "::pg_catalog.regclass AND\n"
   17602             :                                                  "conkey IN (");
   17603          26 :                             firstitem_extra = false;
   17604             :                         }
   17605             :                         else
   17606           0 :                             appendPQExpBufferStr(extra, ", ");
   17607          26 :                         appendPQExpBuffer(extra, "'{%d}'", j + 1);
   17608             :                     }
   17609             :                 }
   17610             :             }
   17611        1596 :             if (!firstitem)
   17612         122 :                 appendPQExpBufferStr(q, ");\n");
   17613        1596 :             if (!firstitem_extra)
   17614          26 :                 appendPQExpBufferStr(extra, ");\n");
   17615             : 
   17616        1596 :             if (extra->len > 0)
   17617          26 :                 appendBinaryPQExpBuffer(q, extra->data, extra->len);
   17618             : 
   17619             :             /*
   17620             :              * Add inherited CHECK constraints, if any.
   17621             :              *
   17622             :              * For partitions, they were already dumped, and conislocal
   17623             :              * doesn't need fixing.
   17624             :              *
   17625             :              * As above, issue only one direct manipulation of pg_constraint.
   17626             :              * Although it is tempting to merge the ALTER ADD CONSTRAINT
   17627             :              * commands into one as well, refrain for now due to concern about
   17628             :              * possible backend memory bloat if there are many such
   17629             :              * constraints.
   17630             :              */
   17631        1596 :             resetPQExpBuffer(extra);
   17632        1596 :             firstitem = true;
   17633        1724 :             for (k = 0; k < tbinfo->ncheck; k++)
   17634             :             {
   17635         128 :                 ConstraintInfo *constr = &(tbinfo->checkexprs[k]);
   17636             : 
   17637         128 :                 if (constr->separate || constr->conislocal || tbinfo->ispartition)
   17638         124 :                     continue;
   17639             : 
   17640           4 :                 if (firstitem)
   17641           4 :                     appendPQExpBufferStr(q, "\n-- For binary upgrade, set up inherited constraints.\n");
   17642           4 :                 appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s ADD CONSTRAINT %s %s;\n",
   17643             :                                   foreign, qualrelname,
   17644           4 :                                   fmtId(constr->dobj.name),
   17645             :                                   constr->condef);
   17646             :                 /* Update pg_constraint after all the ALTER TABLEs */
   17647           4 :                 if (firstitem)
   17648             :                 {
   17649           4 :                     appendPQExpBufferStr(extra, "UPDATE pg_catalog.pg_constraint\n"
   17650             :                                          "SET conislocal = false\n"
   17651             :                                          "WHERE contype = 'c' AND conrelid = ");
   17652           4 :                     appendStringLiteralAH(extra, qualrelname, fout);
   17653           4 :                     appendPQExpBufferStr(extra, "::pg_catalog.regclass\n");
   17654           4 :                     appendPQExpBufferStr(extra, "  AND conname IN (");
   17655           4 :                     firstitem = false;
   17656             :                 }
   17657             :                 else
   17658           0 :                     appendPQExpBufferStr(extra, ", ");
   17659           4 :                 appendStringLiteralAH(extra, constr->dobj.name, fout);
   17660             :             }
   17661        1596 :             if (!firstitem)
   17662             :             {
   17663           4 :                 appendPQExpBufferStr(extra, ");\n");
   17664           4 :                 appendBinaryPQExpBuffer(q, extra->data, extra->len);
   17665             :             }
   17666             : 
   17667        1596 :             if (numParents > 0 && !tbinfo->ispartition)
   17668             :             {
   17669         126 :                 appendPQExpBufferStr(q, "\n-- For binary upgrade, set up inheritance this way.\n");
   17670         274 :                 for (k = 0; k < numParents; k++)
   17671             :                 {
   17672         148 :                     TableInfo  *parentRel = parents[k];
   17673             : 
   17674         148 :                     appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s INHERIT %s;\n", foreign,
   17675             :                                       qualrelname,
   17676         148 :                                       fmtQualifiedDumpable(parentRel));
   17677             :                 }
   17678             :             }
   17679             : 
   17680        1596 :             if (OidIsValid(tbinfo->reloftype))
   17681             :             {
   17682          12 :                 appendPQExpBufferStr(q, "\n-- For binary upgrade, set up typed tables this way.\n");
   17683          12 :                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s OF %s;\n",
   17684             :                                   qualrelname,
   17685          12 :                                   getFormattedTypeName(fout, tbinfo->reloftype,
   17686             :                                                        zeroIsError));
   17687             :             }
   17688             :         }
   17689             : 
   17690             :         /*
   17691             :          * In binary_upgrade mode, arrange to restore the old relfrozenxid and
   17692             :          * relminmxid of all vacuumable relations.  (While vacuum.c processes
   17693             :          * TOAST tables semi-independently, here we see them only as children
   17694             :          * of other relations; so this "if" lacks RELKIND_TOASTVALUE, and the
   17695             :          * child toast table is handled below.)
   17696             :          */
   17697       11802 :         if (dopt->binary_upgrade &&
   17698        1632 :             (tbinfo->relkind == RELKIND_RELATION ||
   17699         220 :              tbinfo->relkind == RELKIND_MATVIEW))
   17700             :         {
   17701        1448 :             appendPQExpBufferStr(q, "\n-- For binary upgrade, set heap's relfrozenxid and relminmxid\n");
   17702        1448 :             appendPQExpBuffer(q, "UPDATE pg_catalog.pg_class\n"
   17703             :                               "SET relfrozenxid = '%u', relminmxid = '%u'\n"
   17704             :                               "WHERE oid = ",
   17705        1448 :                               tbinfo->frozenxid, tbinfo->minmxid);
   17706        1448 :             appendStringLiteralAH(q, qualrelname, fout);
   17707        1448 :             appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
   17708             : 
   17709        1448 :             if (tbinfo->toast_oid)
   17710             :             {
   17711             :                 /*
   17712             :                  * The toast table will have the same OID at restore, so we
   17713             :                  * can safely target it by OID.
   17714             :                  */
   17715         560 :                 appendPQExpBufferStr(q, "\n-- For binary upgrade, set toast's relfrozenxid and relminmxid\n");
   17716         560 :                 appendPQExpBuffer(q, "UPDATE pg_catalog.pg_class\n"
   17717             :                                   "SET relfrozenxid = '%u', relminmxid = '%u'\n"
   17718             :                                   "WHERE oid = '%u';\n",
   17719         560 :                                   tbinfo->toast_frozenxid,
   17720         560 :                                   tbinfo->toast_minmxid, tbinfo->toast_oid);
   17721             :             }
   17722             :         }
   17723             : 
   17724             :         /*
   17725             :          * In binary_upgrade mode, restore matviews' populated status by
   17726             :          * poking pg_class directly.  This is pretty ugly, but we can't use
   17727             :          * REFRESH MATERIALIZED VIEW since it's possible that some underlying
   17728             :          * matview is not populated even though this matview is; in any case,
   17729             :          * we want to transfer the matview's heap storage, not run REFRESH.
   17730             :          */
   17731       11802 :         if (dopt->binary_upgrade && tbinfo->relkind == RELKIND_MATVIEW &&
   17732          36 :             tbinfo->relispopulated)
   17733             :         {
   17734          32 :             appendPQExpBufferStr(q, "\n-- For binary upgrade, mark materialized view as populated\n");
   17735          32 :             appendPQExpBufferStr(q, "UPDATE pg_catalog.pg_class\n"
   17736             :                                  "SET relispopulated = 't'\n"
   17737             :                                  "WHERE oid = ");
   17738          32 :             appendStringLiteralAH(q, qualrelname, fout);
   17739          32 :             appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
   17740             :         }
   17741             : 
   17742             :         /*
   17743             :          * Dump additional per-column properties that we can't handle in the
   17744             :          * main CREATE TABLE command.
   17745             :          */
   17746       52898 :         for (j = 0; j < tbinfo->numatts; j++)
   17747             :         {
   17748             :             /* None of this applies to dropped columns */
   17749       41096 :             if (tbinfo->attisdropped[j])
   17750         900 :                 continue;
   17751             : 
   17752             :             /*
   17753             :              * Dump per-column statistics information. We only issue an ALTER
   17754             :              * TABLE statement if the attstattarget entry for this column is
   17755             :              * not the default value.
   17756             :              */
   17757       40196 :             if (tbinfo->attstattarget[j] >= 0)
   17758          70 :                 appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s ALTER COLUMN %s SET STATISTICS %d;\n",
   17759             :                                   foreign, qualrelname,
   17760          70 :                                   fmtId(tbinfo->attnames[j]),
   17761          70 :                                   tbinfo->attstattarget[j]);
   17762             : 
   17763             :             /*
   17764             :              * Dump per-column storage information.  The statement is only
   17765             :              * dumped if the storage has been changed from the type's default.
   17766             :              */
   17767       40196 :             if (tbinfo->attstorage[j] != tbinfo->typstorage[j])
   17768             :             {
   17769         170 :                 switch (tbinfo->attstorage[j])
   17770             :                 {
   17771          20 :                     case TYPSTORAGE_PLAIN:
   17772          20 :                         storage = "PLAIN";
   17773          20 :                         break;
   17774          80 :                     case TYPSTORAGE_EXTERNAL:
   17775          80 :                         storage = "EXTERNAL";
   17776          80 :                         break;
   17777           0 :                     case TYPSTORAGE_EXTENDED:
   17778           0 :                         storage = "EXTENDED";
   17779           0 :                         break;
   17780          70 :                     case TYPSTORAGE_MAIN:
   17781          70 :                         storage = "MAIN";
   17782          70 :                         break;
   17783           0 :                     default:
   17784           0 :                         storage = NULL;
   17785             :                 }
   17786             : 
   17787             :                 /*
   17788             :                  * Only dump the statement if it's a storage type we recognize
   17789             :                  */
   17790         170 :                 if (storage != NULL)
   17791         170 :                     appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s ALTER COLUMN %s SET STORAGE %s;\n",
   17792             :                                       foreign, qualrelname,
   17793         170 :                                       fmtId(tbinfo->attnames[j]),
   17794             :                                       storage);
   17795             :             }
   17796             : 
   17797             :             /*
   17798             :              * Dump per-column compression, if it's been set.
   17799             :              */
   17800       40196 :             if (!dopt->no_toast_compression)
   17801             :             {
   17802             :                 const char *cmname;
   17803             : 
   17804       40000 :                 switch (tbinfo->attcompression[j])
   17805             :                 {
   17806         148 :                     case 'p':
   17807         148 :                         cmname = "pglz";
   17808         148 :                         break;
   17809         186 :                     case 'l':
   17810         186 :                         cmname = "lz4";
   17811         186 :                         break;
   17812       39666 :                     default:
   17813       39666 :                         cmname = NULL;
   17814       39666 :                         break;
   17815             :                 }
   17816             : 
   17817       40000 :                 if (cmname != NULL)
   17818         334 :                     appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s ALTER COLUMN %s SET COMPRESSION %s;\n",
   17819             :                                       foreign, qualrelname,
   17820         334 :                                       fmtId(tbinfo->attnames[j]),
   17821             :                                       cmname);
   17822             :             }
   17823             : 
   17824             :             /*
   17825             :              * Dump per-column attributes.
   17826             :              */
   17827       40196 :             if (tbinfo->attoptions[j][0] != '\0')
   17828          70 :                 appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s ALTER COLUMN %s SET (%s);\n",
   17829             :                                   foreign, qualrelname,
   17830          70 :                                   fmtId(tbinfo->attnames[j]),
   17831          70 :                                   tbinfo->attoptions[j]);
   17832             : 
   17833             :             /*
   17834             :              * Dump per-column fdw options.
   17835             :              */
   17836       40196 :             if (tbinfo->relkind == RELKIND_FOREIGN_TABLE &&
   17837          74 :                 tbinfo->attfdwoptions[j][0] != '\0')
   17838          70 :                 appendPQExpBuffer(q,
   17839             :                                   "ALTER FOREIGN TABLE ONLY %s ALTER COLUMN %s OPTIONS (\n"
   17840             :                                   "    %s\n"
   17841             :                                   ");\n",
   17842             :                                   qualrelname,
   17843          70 :                                   fmtId(tbinfo->attnames[j]),
   17844          70 :                                   tbinfo->attfdwoptions[j]);
   17845             :         }                       /* end loop over columns */
   17846             : 
   17847       11802 :         free(partkeydef);
   17848       11802 :         free(ftoptions);
   17849       11802 :         free(srvname);
   17850             :     }
   17851             : 
   17852             :     /*
   17853             :      * dump properties we only have ALTER TABLE syntax for
   17854             :      */
   17855       12868 :     if ((tbinfo->relkind == RELKIND_RELATION ||
   17856        3076 :          tbinfo->relkind == RELKIND_PARTITIONED_TABLE ||
   17857        1920 :          tbinfo->relkind == RELKIND_MATVIEW) &&
   17858       11728 :         tbinfo->relreplident != REPLICA_IDENTITY_DEFAULT)
   17859             :     {
   17860         384 :         if (tbinfo->relreplident == REPLICA_IDENTITY_INDEX)
   17861             :         {
   17862             :             /* nothing to do, will be set when the index is dumped */
   17863             :         }
   17864         384 :         else if (tbinfo->relreplident == REPLICA_IDENTITY_NOTHING)
   17865             :         {
   17866         384 :             appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY NOTHING;\n",
   17867             :                               qualrelname);
   17868             :         }
   17869           0 :         else if (tbinfo->relreplident == REPLICA_IDENTITY_FULL)
   17870             :         {
   17871           0 :             appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY FULL;\n",
   17872             :                               qualrelname);
   17873             :         }
   17874             :     }
   17875             : 
   17876       12868 :     if (tbinfo->forcerowsec)
   17877          10 :         appendPQExpBuffer(q, "\nALTER TABLE ONLY %s FORCE ROW LEVEL SECURITY;\n",
   17878             :                           qualrelname);
   17879             : 
   17880       12868 :     if (dopt->binary_upgrade)
   17881        1736 :         binary_upgrade_extension_member(q, &tbinfo->dobj,
   17882             :                                         reltypename, qrelname,
   17883        1736 :                                         tbinfo->dobj.namespace->dobj.name);
   17884             : 
   17885       12868 :     if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   17886             :     {
   17887       12868 :         char       *tablespace = NULL;
   17888       12868 :         char       *tableam = NULL;
   17889             : 
   17890             :         /*
   17891             :          * _selectTablespace() relies on tablespace-enabled objects in the
   17892             :          * default tablespace to have a tablespace of "" (empty string) versus
   17893             :          * non-tablespace-enabled objects to have a tablespace of NULL.
   17894             :          * getTables() sets tbinfo->reltablespace to "" for the default
   17895             :          * tablespace (not NULL).
   17896             :          */
   17897       12868 :         if (RELKIND_HAS_TABLESPACE(tbinfo->relkind))
   17898       11728 :             tablespace = tbinfo->reltablespace;
   17899             : 
   17900       12868 :         if (RELKIND_HAS_TABLE_AM(tbinfo->relkind) ||
   17901        2296 :             tbinfo->relkind == RELKIND_PARTITIONED_TABLE)
   17902       11728 :             tableam = tbinfo->amname;
   17903             : 
   17904       12868 :         ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
   17905       12868 :                      ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
   17906             :                                   .namespace = tbinfo->dobj.namespace->dobj.name,
   17907             :                                   .tablespace = tablespace,
   17908             :                                   .tableam = tableam,
   17909             :                                   .relkind = tbinfo->relkind,
   17910             :                                   .owner = tbinfo->rolname,
   17911             :                                   .description = reltypename,
   17912             :                                   .section = tbinfo->postponed_def ?
   17913             :                                   SECTION_POST_DATA : SECTION_PRE_DATA,
   17914             :                                   .createStmt = q->data,
   17915             :                                   .dropStmt = delq->data));
   17916             :     }
   17917             : 
   17918             :     /* Dump Table Comments */
   17919       12868 :     if (tbinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   17920         160 :         dumpTableComment(fout, tbinfo, reltypename);
   17921             : 
   17922             :     /* Dump Table Security Labels */
   17923       12868 :     if (tbinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
   17924           0 :         dumpTableSecLabel(fout, tbinfo, reltypename);
   17925             : 
   17926             :     /*
   17927             :      * Dump comments for not-null constraints that aren't to be dumped
   17928             :      * separately (those are processed by collectComments/dumpComment).
   17929             :      */
   17930       12868 :     if (!fout->dopt->no_comments && dopt->dumpSchema &&
   17931       12868 :         fout->remoteVersion >= 180000)
   17932             :     {
   17933       12868 :         PQExpBuffer comment = NULL;
   17934       12868 :         PQExpBuffer tag = NULL;
   17935             : 
   17936       60666 :         for (j = 0; j < tbinfo->numatts; j++)
   17937             :         {
   17938       47798 :             if (tbinfo->notnull_constrs[j] != NULL &&
   17939        4924 :                 tbinfo->notnull_comment[j] != NULL)
   17940             :             {
   17941          90 :                 if (comment == NULL)
   17942             :                 {
   17943          90 :                     comment = createPQExpBuffer();
   17944          90 :                     tag = createPQExpBuffer();
   17945             :                 }
   17946             :                 else
   17947             :                 {
   17948           0 :                     resetPQExpBuffer(comment);
   17949           0 :                     resetPQExpBuffer(tag);
   17950             :                 }
   17951             : 
   17952          90 :                 appendPQExpBuffer(comment, "COMMENT ON CONSTRAINT %s ON %s IS ",
   17953          90 :                                   fmtId(tbinfo->notnull_constrs[j]), qualrelname);
   17954          90 :                 appendStringLiteralAH(comment, tbinfo->notnull_comment[j], fout);
   17955          90 :                 appendPQExpBufferStr(comment, ";\n");
   17956             : 
   17957          90 :                 appendPQExpBuffer(tag, "CONSTRAINT %s ON %s",
   17958          90 :                                   fmtId(tbinfo->notnull_constrs[j]), qrelname);
   17959             : 
   17960          90 :                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
   17961          90 :                              ARCHIVE_OPTS(.tag = tag->data,
   17962             :                                           .namespace = tbinfo->dobj.namespace->dobj.name,
   17963             :                                           .owner = tbinfo->rolname,
   17964             :                                           .description = "COMMENT",
   17965             :                                           .section = SECTION_NONE,
   17966             :                                           .createStmt = comment->data,
   17967             :                                           .deps = &(tbinfo->dobj.dumpId),
   17968             :                                           .nDeps = 1));
   17969             :             }
   17970             :         }
   17971             : 
   17972       12868 :         destroyPQExpBuffer(comment);
   17973       12868 :         destroyPQExpBuffer(tag);
   17974             :     }
   17975             : 
   17976             :     /* Dump comments on inlined table constraints */
   17977       14094 :     for (j = 0; j < tbinfo->ncheck; j++)
   17978             :     {
   17979        1226 :         ConstraintInfo *constr = &(tbinfo->checkexprs[j]);
   17980             : 
   17981        1226 :         if (constr->separate || !constr->conislocal)
   17982         518 :             continue;
   17983             : 
   17984         708 :         if (constr->dobj.dump & DUMP_COMPONENT_COMMENT)
   17985          80 :             dumpTableConstraintComment(fout, constr);
   17986             :     }
   17987             : 
   17988       12868 :     destroyPQExpBuffer(q);
   17989       12868 :     destroyPQExpBuffer(delq);
   17990       12868 :     destroyPQExpBuffer(extra);
   17991       12868 :     free(qrelname);
   17992       12868 :     free(qualrelname);
   17993       12868 : }
   17994             : 
   17995             : /*
   17996             :  * dumpTableAttach
   17997             :  *    write to fout the commands to attach a child partition
   17998             :  *
   17999             :  * Child partitions are always made by creating them separately
   18000             :  * and then using ATTACH PARTITION, rather than using
   18001             :  * CREATE TABLE ... PARTITION OF.  This is important for preserving
   18002             :  * any possible discrepancy in column layout, to allow assigning the
   18003             :  * correct tablespace if different, and so that it's possible to restore
   18004             :  * a partition without restoring its parent.  (You'll get an error from
   18005             :  * the ATTACH PARTITION command, but that can be ignored, or skipped
   18006             :  * using "pg_restore -L" if you prefer.)  The last point motivates
   18007             :  * treating ATTACH PARTITION as a completely separate ArchiveEntry
   18008             :  * rather than emitting it within the child partition's ArchiveEntry.
   18009             :  */
   18010             : static void
   18011        2816 : dumpTableAttach(Archive *fout, const TableAttachInfo *attachinfo)
   18012             : {
   18013        2816 :     DumpOptions *dopt = fout->dopt;
   18014             :     PQExpBuffer q;
   18015             :     PGresult   *res;
   18016             :     char       *partbound;
   18017             : 
   18018             :     /* Do nothing if not dumping schema */
   18019        2816 :     if (!dopt->dumpSchema)
   18020         108 :         return;
   18021             : 
   18022        2708 :     q = createPQExpBuffer();
   18023             : 
   18024        2708 :     if (!fout->is_prepared[PREPQUERY_DUMPTABLEATTACH])
   18025             :     {
   18026             :         /* Set up query for partbound details */
   18027          92 :         appendPQExpBufferStr(q,
   18028             :                              "PREPARE dumpTableAttach(pg_catalog.oid) AS\n");
   18029             : 
   18030          92 :         appendPQExpBufferStr(q,
   18031             :                              "SELECT pg_get_expr(c.relpartbound, c.oid) "
   18032             :                              "FROM pg_class c "
   18033             :                              "WHERE c.oid = $1");
   18034             : 
   18035          92 :         ExecuteSqlStatement(fout, q->data);
   18036             : 
   18037          92 :         fout->is_prepared[PREPQUERY_DUMPTABLEATTACH] = true;
   18038             :     }
   18039             : 
   18040        2708 :     printfPQExpBuffer(q,
   18041             :                       "EXECUTE dumpTableAttach('%u')",
   18042        2708 :                       attachinfo->partitionTbl->dobj.catId.oid);
   18043             : 
   18044        2708 :     res = ExecuteSqlQueryForSingleRow(fout, q->data);
   18045        2708 :     partbound = PQgetvalue(res, 0, 0);
   18046             : 
   18047             :     /* Perform ALTER TABLE on the parent */
   18048        2708 :     printfPQExpBuffer(q,
   18049             :                       "ALTER TABLE ONLY %s ",
   18050        2708 :                       fmtQualifiedDumpable(attachinfo->parentTbl));
   18051        2708 :     appendPQExpBuffer(q,
   18052             :                       "ATTACH PARTITION %s %s;\n",
   18053        2708 :                       fmtQualifiedDumpable(attachinfo->partitionTbl),
   18054             :                       partbound);
   18055             : 
   18056             :     /*
   18057             :      * There is no point in creating a drop query as the drop is done by table
   18058             :      * drop.  (If you think to change this, see also _printTocEntry().)
   18059             :      * Although this object doesn't really have ownership as such, set the
   18060             :      * owner field anyway to ensure that the command is run by the correct
   18061             :      * role at restore time.
   18062             :      */
   18063        2708 :     ArchiveEntry(fout, attachinfo->dobj.catId, attachinfo->dobj.dumpId,
   18064        2708 :                  ARCHIVE_OPTS(.tag = attachinfo->dobj.name,
   18065             :                               .namespace = attachinfo->dobj.namespace->dobj.name,
   18066             :                               .owner = attachinfo->partitionTbl->rolname,
   18067             :                               .description = "TABLE ATTACH",
   18068             :                               .section = SECTION_PRE_DATA,
   18069             :                               .createStmt = q->data));
   18070             : 
   18071        2708 :     PQclear(res);
   18072        2708 :     destroyPQExpBuffer(q);
   18073             : }
   18074             : 
   18075             : /*
   18076             :  * dumpAttrDef --- dump an attribute's default-value declaration
   18077             :  */
   18078             : static void
   18079        2136 : dumpAttrDef(Archive *fout, const AttrDefInfo *adinfo)
   18080             : {
   18081        2136 :     DumpOptions *dopt = fout->dopt;
   18082        2136 :     TableInfo  *tbinfo = adinfo->adtable;
   18083        2136 :     int         adnum = adinfo->adnum;
   18084             :     PQExpBuffer q;
   18085             :     PQExpBuffer delq;
   18086             :     char       *qualrelname;
   18087             :     char       *tag;
   18088             :     char       *foreign;
   18089             : 
   18090             :     /* Do nothing if not dumping schema */
   18091        2136 :     if (!dopt->dumpSchema)
   18092           0 :         return;
   18093             : 
   18094             :     /* Skip if not "separate"; it was dumped in the table's definition */
   18095        2136 :     if (!adinfo->separate)
   18096        1786 :         return;
   18097             : 
   18098         350 :     q = createPQExpBuffer();
   18099         350 :     delq = createPQExpBuffer();
   18100             : 
   18101         350 :     qualrelname = pg_strdup(fmtQualifiedDumpable(tbinfo));
   18102             : 
   18103         350 :     foreign = tbinfo->relkind == RELKIND_FOREIGN_TABLE ? "FOREIGN " : "";
   18104             : 
   18105         350 :     appendPQExpBuffer(q,
   18106             :                       "ALTER %sTABLE ONLY %s ALTER COLUMN %s SET DEFAULT %s;\n",
   18107         350 :                       foreign, qualrelname, fmtId(tbinfo->attnames[adnum - 1]),
   18108         350 :                       adinfo->adef_expr);
   18109             : 
   18110         350 :     appendPQExpBuffer(delq, "ALTER %sTABLE %s ALTER COLUMN %s DROP DEFAULT;\n",
   18111             :                       foreign, qualrelname,
   18112         350 :                       fmtId(tbinfo->attnames[adnum - 1]));
   18113             : 
   18114         350 :     tag = psprintf("%s %s", tbinfo->dobj.name, tbinfo->attnames[adnum - 1]);
   18115             : 
   18116         350 :     if (adinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   18117         350 :         ArchiveEntry(fout, adinfo->dobj.catId, adinfo->dobj.dumpId,
   18118         350 :                      ARCHIVE_OPTS(.tag = tag,
   18119             :                                   .namespace = tbinfo->dobj.namespace->dobj.name,
   18120             :                                   .owner = tbinfo->rolname,
   18121             :                                   .description = "DEFAULT",
   18122             :                                   .section = SECTION_PRE_DATA,
   18123             :                                   .createStmt = q->data,
   18124             :                                   .dropStmt = delq->data));
   18125             : 
   18126         350 :     free(tag);
   18127         350 :     destroyPQExpBuffer(q);
   18128         350 :     destroyPQExpBuffer(delq);
   18129         350 :     free(qualrelname);
   18130             : }
   18131             : 
   18132             : /*
   18133             :  * getAttrName: extract the correct name for an attribute
   18134             :  *
   18135             :  * The array tblInfo->attnames[] only provides names of user attributes;
   18136             :  * if a system attribute number is supplied, we have to fake it.
   18137             :  * We also do a little bit of bounds checking for safety's sake.
   18138             :  */
   18139             : static const char *
   18140        4192 : getAttrName(int attrnum, const TableInfo *tblInfo)
   18141             : {
   18142        4192 :     if (attrnum > 0 && attrnum <= tblInfo->numatts)
   18143        4192 :         return tblInfo->attnames[attrnum - 1];
   18144           0 :     switch (attrnum)
   18145             :     {
   18146           0 :         case SelfItemPointerAttributeNumber:
   18147           0 :             return "ctid";
   18148           0 :         case MinTransactionIdAttributeNumber:
   18149           0 :             return "xmin";
   18150           0 :         case MinCommandIdAttributeNumber:
   18151           0 :             return "cmin";
   18152           0 :         case MaxTransactionIdAttributeNumber:
   18153           0 :             return "xmax";
   18154           0 :         case MaxCommandIdAttributeNumber:
   18155           0 :             return "cmax";
   18156           0 :         case TableOidAttributeNumber:
   18157           0 :             return "tableoid";
   18158             :     }
   18159           0 :     pg_fatal("invalid column number %d for table \"%s\"",
   18160             :              attrnum, tblInfo->dobj.name);
   18161             :     return NULL;                /* keep compiler quiet */
   18162             : }
   18163             : 
   18164             : /*
   18165             :  * dumpIndex
   18166             :  *    write out to fout a user-defined index
   18167             :  */
   18168             : static void
   18169        5262 : dumpIndex(Archive *fout, const IndxInfo *indxinfo)
   18170             : {
   18171        5262 :     DumpOptions *dopt = fout->dopt;
   18172        5262 :     TableInfo  *tbinfo = indxinfo->indextable;
   18173        5262 :     bool        is_constraint = (indxinfo->indexconstraint != 0);
   18174             :     PQExpBuffer q;
   18175             :     PQExpBuffer delq;
   18176             :     char       *qindxname;
   18177             :     char       *qqindxname;
   18178             : 
   18179             :     /* Do nothing if not dumping schema */
   18180        5262 :     if (!dopt->dumpSchema)
   18181         234 :         return;
   18182             : 
   18183        5028 :     q = createPQExpBuffer();
   18184        5028 :     delq = createPQExpBuffer();
   18185             : 
   18186        5028 :     qindxname = pg_strdup(fmtId(indxinfo->dobj.name));
   18187        5028 :     qqindxname = pg_strdup(fmtQualifiedDumpable(indxinfo));
   18188             : 
   18189             :     /*
   18190             :      * If there's an associated constraint, don't dump the index per se, but
   18191             :      * do dump any comment for it.  (This is safe because dependency ordering
   18192             :      * will have ensured the constraint is emitted first.)  Note that the
   18193             :      * emitted comment has to be shown as depending on the constraint, not the
   18194             :      * index, in such cases.
   18195             :      */
   18196        5028 :     if (!is_constraint)
   18197             :     {
   18198        2112 :         char       *indstatcols = indxinfo->indstatcols;
   18199        2112 :         char       *indstatvals = indxinfo->indstatvals;
   18200        2112 :         char      **indstatcolsarray = NULL;
   18201        2112 :         char      **indstatvalsarray = NULL;
   18202        2112 :         int         nstatcols = 0;
   18203        2112 :         int         nstatvals = 0;
   18204             : 
   18205        2112 :         if (dopt->binary_upgrade)
   18206         312 :             binary_upgrade_set_pg_class_oids(fout, q,
   18207         312 :                                              indxinfo->dobj.catId.oid);
   18208             : 
   18209             :         /* Plain secondary index */
   18210        2112 :         appendPQExpBuffer(q, "%s;\n", indxinfo->indexdef);
   18211             : 
   18212             :         /*
   18213             :          * Append ALTER TABLE commands as needed to set properties that we
   18214             :          * only have ALTER TABLE syntax for.  Keep this in sync with the
   18215             :          * similar code in dumpConstraint!
   18216             :          */
   18217             : 
   18218             :         /* If the index is clustered, we need to record that. */
   18219        2112 :         if (indxinfo->indisclustered)
   18220             :         {
   18221           0 :             appendPQExpBuffer(q, "\nALTER TABLE %s CLUSTER",
   18222           0 :                               fmtQualifiedDumpable(tbinfo));
   18223             :             /* index name is not qualified in this syntax */
   18224           0 :             appendPQExpBuffer(q, " ON %s;\n",
   18225             :                               qindxname);
   18226             :         }
   18227             : 
   18228             :         /*
   18229             :          * If the index has any statistics on some of its columns, generate
   18230             :          * the associated ALTER INDEX queries.
   18231             :          */
   18232        2112 :         if (strlen(indstatcols) != 0 || strlen(indstatvals) != 0)
   18233             :         {
   18234             :             int         j;
   18235             : 
   18236          70 :             if (!parsePGArray(indstatcols, &indstatcolsarray, &nstatcols))
   18237           0 :                 pg_fatal("could not parse index statistic columns");
   18238          70 :             if (!parsePGArray(indstatvals, &indstatvalsarray, &nstatvals))
   18239           0 :                 pg_fatal("could not parse index statistic values");
   18240          70 :             if (nstatcols != nstatvals)
   18241           0 :                 pg_fatal("mismatched number of columns and values for index statistics");
   18242             : 
   18243         210 :             for (j = 0; j < nstatcols; j++)
   18244             :             {
   18245         140 :                 appendPQExpBuffer(q, "ALTER INDEX %s ", qqindxname);
   18246             : 
   18247             :                 /*
   18248             :                  * Note that this is a column number, so no quotes should be
   18249             :                  * used.
   18250             :                  */
   18251         140 :                 appendPQExpBuffer(q, "ALTER COLUMN %s ",
   18252         140 :                                   indstatcolsarray[j]);
   18253         140 :                 appendPQExpBuffer(q, "SET STATISTICS %s;\n",
   18254         140 :                                   indstatvalsarray[j]);
   18255             :             }
   18256             :         }
   18257             : 
   18258             :         /* Indexes can depend on extensions */
   18259        2112 :         append_depends_on_extension(fout, q, &indxinfo->dobj,
   18260             :                                     "pg_catalog.pg_class",
   18261             :                                     "INDEX", qqindxname);
   18262             : 
   18263             :         /* If the index defines identity, we need to record that. */
   18264        2112 :         if (indxinfo->indisreplident)
   18265             :         {
   18266           0 :             appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY USING",
   18267           0 :                               fmtQualifiedDumpable(tbinfo));
   18268             :             /* index name is not qualified in this syntax */
   18269           0 :             appendPQExpBuffer(q, " INDEX %s;\n",
   18270             :                               qindxname);
   18271             :         }
   18272             : 
   18273             :         /*
   18274             :          * If this index is a member of a partitioned index, the backend will
   18275             :          * not allow us to drop it separately, so don't try.  It will go away
   18276             :          * automatically when we drop either the index's table or the
   18277             :          * partitioned index.  (If, in a selective restore with --clean, we
   18278             :          * drop neither of those, then this index will not be dropped either.
   18279             :          * But that's fine, and even if you think it's not, the backend won't
   18280             :          * let us do differently.)
   18281             :          */
   18282        2112 :         if (indxinfo->parentidx == 0)
   18283        1724 :             appendPQExpBuffer(delq, "DROP INDEX %s;\n", qqindxname);
   18284             : 
   18285        2112 :         if (indxinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   18286        2112 :             ArchiveEntry(fout, indxinfo->dobj.catId, indxinfo->dobj.dumpId,
   18287        2112 :                          ARCHIVE_OPTS(.tag = indxinfo->dobj.name,
   18288             :                                       .namespace = tbinfo->dobj.namespace->dobj.name,
   18289             :                                       .tablespace = indxinfo->tablespace,
   18290             :                                       .owner = tbinfo->rolname,
   18291             :                                       .description = "INDEX",
   18292             :                                       .section = SECTION_POST_DATA,
   18293             :                                       .createStmt = q->data,
   18294             :                                       .dropStmt = delq->data));
   18295             : 
   18296        2112 :         free(indstatcolsarray);
   18297        2112 :         free(indstatvalsarray);
   18298             :     }
   18299             : 
   18300             :     /* Dump Index Comments */
   18301        5028 :     if (indxinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   18302          30 :         dumpComment(fout, "INDEX", qindxname,
   18303          30 :                     tbinfo->dobj.namespace->dobj.name,
   18304             :                     tbinfo->rolname,
   18305             :                     indxinfo->dobj.catId, 0,
   18306             :                     is_constraint ? indxinfo->indexconstraint :
   18307             :                     indxinfo->dobj.dumpId);
   18308             : 
   18309        5028 :     destroyPQExpBuffer(q);
   18310        5028 :     destroyPQExpBuffer(delq);
   18311        5028 :     free(qindxname);
   18312        5028 :     free(qqindxname);
   18313             : }
   18314             : 
   18315             : /*
   18316             :  * dumpIndexAttach
   18317             :  *    write out to fout a partitioned-index attachment clause
   18318             :  */
   18319             : static void
   18320        1176 : dumpIndexAttach(Archive *fout, const IndexAttachInfo *attachinfo)
   18321             : {
   18322             :     /* Do nothing if not dumping schema */
   18323        1176 :     if (!fout->dopt->dumpSchema)
   18324          96 :         return;
   18325             : 
   18326        1080 :     if (attachinfo->partitionIdx->dobj.dump & DUMP_COMPONENT_DEFINITION)
   18327             :     {
   18328        1080 :         PQExpBuffer q = createPQExpBuffer();
   18329             : 
   18330        1080 :         appendPQExpBuffer(q, "ALTER INDEX %s ",
   18331        1080 :                           fmtQualifiedDumpable(attachinfo->parentIdx));
   18332        1080 :         appendPQExpBuffer(q, "ATTACH PARTITION %s;\n",
   18333        1080 :                           fmtQualifiedDumpable(attachinfo->partitionIdx));
   18334             : 
   18335             :         /*
   18336             :          * There is no need for a dropStmt since the drop is done implicitly
   18337             :          * when we drop either the index's table or the partitioned index.
   18338             :          * Moreover, since there's no ALTER INDEX DETACH PARTITION command,
   18339             :          * there's no way to do it anyway.  (If you think to change this,
   18340             :          * consider also what to do with --if-exists.)
   18341             :          *
   18342             :          * Although this object doesn't really have ownership as such, set the
   18343             :          * owner field anyway to ensure that the command is run by the correct
   18344             :          * role at restore time.
   18345             :          */
   18346        1080 :         ArchiveEntry(fout, attachinfo->dobj.catId, attachinfo->dobj.dumpId,
   18347        1080 :                      ARCHIVE_OPTS(.tag = attachinfo->dobj.name,
   18348             :                                   .namespace = attachinfo->dobj.namespace->dobj.name,
   18349             :                                   .owner = attachinfo->parentIdx->indextable->rolname,
   18350             :                                   .description = "INDEX ATTACH",
   18351             :                                   .section = SECTION_POST_DATA,
   18352             :                                   .createStmt = q->data));
   18353             : 
   18354        1080 :         destroyPQExpBuffer(q);
   18355             :     }
   18356             : }
   18357             : 
   18358             : /*
   18359             :  * dumpStatisticsExt
   18360             :  *    write out to fout an extended statistics object
   18361             :  */
   18362             : static void
   18363         284 : dumpStatisticsExt(Archive *fout, const StatsExtInfo *statsextinfo)
   18364             : {
   18365         284 :     DumpOptions *dopt = fout->dopt;
   18366             :     PQExpBuffer q;
   18367             :     PQExpBuffer delq;
   18368             :     PQExpBuffer query;
   18369             :     char       *qstatsextname;
   18370             :     PGresult   *res;
   18371             :     char       *stxdef;
   18372             : 
   18373             :     /* Do nothing if not dumping schema */
   18374         284 :     if (!dopt->dumpSchema)
   18375          36 :         return;
   18376             : 
   18377         248 :     q = createPQExpBuffer();
   18378         248 :     delq = createPQExpBuffer();
   18379         248 :     query = createPQExpBuffer();
   18380             : 
   18381         248 :     qstatsextname = pg_strdup(fmtId(statsextinfo->dobj.name));
   18382             : 
   18383         248 :     appendPQExpBuffer(query, "SELECT "
   18384             :                       "pg_catalog.pg_get_statisticsobjdef('%u'::pg_catalog.oid)",
   18385         248 :                       statsextinfo->dobj.catId.oid);
   18386             : 
   18387         248 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   18388             : 
   18389         248 :     stxdef = PQgetvalue(res, 0, 0);
   18390             : 
   18391             :     /* Result of pg_get_statisticsobjdef is complete except for semicolon */
   18392         248 :     appendPQExpBuffer(q, "%s;\n", stxdef);
   18393             : 
   18394             :     /*
   18395             :      * We only issue an ALTER STATISTICS statement if the stxstattarget entry
   18396             :      * for this statistics object is not the default value.
   18397             :      */
   18398         248 :     if (statsextinfo->stattarget >= 0)
   18399             :     {
   18400          70 :         appendPQExpBuffer(q, "ALTER STATISTICS %s ",
   18401          70 :                           fmtQualifiedDumpable(statsextinfo));
   18402          70 :         appendPQExpBuffer(q, "SET STATISTICS %d;\n",
   18403          70 :                           statsextinfo->stattarget);
   18404             :     }
   18405             : 
   18406         248 :     appendPQExpBuffer(delq, "DROP STATISTICS %s;\n",
   18407         248 :                       fmtQualifiedDumpable(statsextinfo));
   18408             : 
   18409         248 :     if (statsextinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   18410         248 :         ArchiveEntry(fout, statsextinfo->dobj.catId,
   18411         248 :                      statsextinfo->dobj.dumpId,
   18412         248 :                      ARCHIVE_OPTS(.tag = statsextinfo->dobj.name,
   18413             :                                   .namespace = statsextinfo->dobj.namespace->dobj.name,
   18414             :                                   .owner = statsextinfo->rolname,
   18415             :                                   .description = "STATISTICS",
   18416             :                                   .section = SECTION_POST_DATA,
   18417             :                                   .createStmt = q->data,
   18418             :                                   .dropStmt = delq->data));
   18419             : 
   18420             :     /* Dump Statistics Comments */
   18421         248 :     if (statsextinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   18422           0 :         dumpComment(fout, "STATISTICS", qstatsextname,
   18423           0 :                     statsextinfo->dobj.namespace->dobj.name,
   18424           0 :                     statsextinfo->rolname,
   18425             :                     statsextinfo->dobj.catId, 0,
   18426           0 :                     statsextinfo->dobj.dumpId);
   18427             : 
   18428         248 :     PQclear(res);
   18429         248 :     destroyPQExpBuffer(q);
   18430         248 :     destroyPQExpBuffer(delq);
   18431         248 :     destroyPQExpBuffer(query);
   18432         248 :     free(qstatsextname);
   18433             : }
   18434             : 
   18435             : /*
   18436             :  * dumpConstraint
   18437             :  *    write out to fout a user-defined constraint
   18438             :  */
   18439             : static void
   18440        5128 : dumpConstraint(Archive *fout, const ConstraintInfo *coninfo)
   18441             : {
   18442        5128 :     DumpOptions *dopt = fout->dopt;
   18443        5128 :     TableInfo  *tbinfo = coninfo->contable;
   18444             :     PQExpBuffer q;
   18445             :     PQExpBuffer delq;
   18446        5128 :     char       *tag = NULL;
   18447             :     char       *foreign;
   18448             : 
   18449             :     /* Do nothing if not dumping schema */
   18450        5128 :     if (!dopt->dumpSchema)
   18451         196 :         return;
   18452             : 
   18453        4932 :     q = createPQExpBuffer();
   18454        4932 :     delq = createPQExpBuffer();
   18455             : 
   18456        9544 :     foreign = tbinfo &&
   18457        4932 :         tbinfo->relkind == RELKIND_FOREIGN_TABLE ? "FOREIGN " : "";
   18458             : 
   18459        4932 :     if (coninfo->contype == 'p' ||
   18460        2500 :         coninfo->contype == 'u' ||
   18461        2036 :         coninfo->contype == 'x')
   18462        2916 :     {
   18463             :         /* Index-related constraint */
   18464             :         IndxInfo   *indxinfo;
   18465             :         int         k;
   18466             : 
   18467        2916 :         indxinfo = (IndxInfo *) findObjectByDumpId(coninfo->conindex);
   18468             : 
   18469        2916 :         if (indxinfo == NULL)
   18470           0 :             pg_fatal("missing index for constraint \"%s\"",
   18471             :                      coninfo->dobj.name);
   18472             : 
   18473        2916 :         if (dopt->binary_upgrade)
   18474         292 :             binary_upgrade_set_pg_class_oids(fout, q,
   18475             :                                              indxinfo->dobj.catId.oid);
   18476             : 
   18477        2916 :         appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s\n", foreign,
   18478        2916 :                           fmtQualifiedDumpable(tbinfo));
   18479        2916 :         appendPQExpBuffer(q, "    ADD CONSTRAINT %s ",
   18480        2916 :                           fmtId(coninfo->dobj.name));
   18481             : 
   18482        2916 :         if (coninfo->condef)
   18483             :         {
   18484             :             /* pg_get_constraintdef should have provided everything */
   18485          20 :             appendPQExpBuffer(q, "%s;\n", coninfo->condef);
   18486             :         }
   18487             :         else
   18488             :         {
   18489        2896 :             appendPQExpBufferStr(q,
   18490        2896 :                                  coninfo->contype == 'p' ? "PRIMARY KEY" : "UNIQUE");
   18491             : 
   18492             :             /*
   18493             :              * PRIMARY KEY constraints should not be using NULLS NOT DISTINCT
   18494             :              * indexes. Being able to create this was fixed, but we need to
   18495             :              * make the index distinct in order to be able to restore the
   18496             :              * dump.
   18497             :              */
   18498        2896 :             if (indxinfo->indnullsnotdistinct && coninfo->contype != 'p')
   18499           0 :                 appendPQExpBufferStr(q, " NULLS NOT DISTINCT");
   18500        2896 :             appendPQExpBufferStr(q, " (");
   18501        7008 :             for (k = 0; k < indxinfo->indnkeyattrs; k++)
   18502             :             {
   18503        4112 :                 int         indkey = (int) indxinfo->indkeys[k];
   18504             :                 const char *attname;
   18505             : 
   18506        4112 :                 if (indkey == InvalidAttrNumber)
   18507           0 :                     break;
   18508        4112 :                 attname = getAttrName(indkey, tbinfo);
   18509             : 
   18510        4112 :                 appendPQExpBuffer(q, "%s%s",
   18511             :                                   (k == 0) ? "" : ", ",
   18512             :                                   fmtId(attname));
   18513             :             }
   18514        2896 :             if (coninfo->conperiod)
   18515         220 :                 appendPQExpBufferStr(q, " WITHOUT OVERLAPS");
   18516             : 
   18517        2896 :             if (indxinfo->indnkeyattrs < indxinfo->indnattrs)
   18518          40 :                 appendPQExpBufferStr(q, ") INCLUDE (");
   18519             : 
   18520        2976 :             for (k = indxinfo->indnkeyattrs; k < indxinfo->indnattrs; k++)
   18521             :             {
   18522          80 :                 int         indkey = (int) indxinfo->indkeys[k];
   18523             :                 const char *attname;
   18524             : 
   18525          80 :                 if (indkey == InvalidAttrNumber)
   18526           0 :                     break;
   18527          80 :                 attname = getAttrName(indkey, tbinfo);
   18528             : 
   18529         160 :                 appendPQExpBuffer(q, "%s%s",
   18530          80 :                                   (k == indxinfo->indnkeyattrs) ? "" : ", ",
   18531             :                                   fmtId(attname));
   18532             :             }
   18533             : 
   18534        2896 :             appendPQExpBufferChar(q, ')');
   18535             : 
   18536        2896 :             if (nonemptyReloptions(indxinfo->indreloptions))
   18537             :             {
   18538           0 :                 appendPQExpBufferStr(q, " WITH (");
   18539           0 :                 appendReloptionsArrayAH(q, indxinfo->indreloptions, "", fout);
   18540           0 :                 appendPQExpBufferChar(q, ')');
   18541             :             }
   18542             : 
   18543        2896 :             if (coninfo->condeferrable)
   18544             :             {
   18545          50 :                 appendPQExpBufferStr(q, " DEFERRABLE");
   18546          50 :                 if (coninfo->condeferred)
   18547          30 :                     appendPQExpBufferStr(q, " INITIALLY DEFERRED");
   18548             :             }
   18549             : 
   18550        2896 :             appendPQExpBufferStr(q, ";\n");
   18551             :         }
   18552             : 
   18553             :         /*
   18554             :          * Append ALTER TABLE commands as needed to set properties that we
   18555             :          * only have ALTER TABLE syntax for.  Keep this in sync with the
   18556             :          * similar code in dumpIndex!
   18557             :          */
   18558             : 
   18559             :         /* If the index is clustered, we need to record that. */
   18560        2916 :         if (indxinfo->indisclustered)
   18561             :         {
   18562          70 :             appendPQExpBuffer(q, "\nALTER TABLE %s CLUSTER",
   18563          70 :                               fmtQualifiedDumpable(tbinfo));
   18564             :             /* index name is not qualified in this syntax */
   18565          70 :             appendPQExpBuffer(q, " ON %s;\n",
   18566          70 :                               fmtId(indxinfo->dobj.name));
   18567             :         }
   18568             : 
   18569             :         /* If the index defines identity, we need to record that. */
   18570        2916 :         if (indxinfo->indisreplident)
   18571             :         {
   18572           0 :             appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY USING",
   18573           0 :                               fmtQualifiedDumpable(tbinfo));
   18574             :             /* index name is not qualified in this syntax */
   18575           0 :             appendPQExpBuffer(q, " INDEX %s;\n",
   18576           0 :                               fmtId(indxinfo->dobj.name));
   18577             :         }
   18578             : 
   18579             :         /* Indexes can depend on extensions */
   18580        2916 :         append_depends_on_extension(fout, q, &indxinfo->dobj,
   18581             :                                     "pg_catalog.pg_class", "INDEX",
   18582        2916 :                                     fmtQualifiedDumpable(indxinfo));
   18583             : 
   18584        2916 :         appendPQExpBuffer(delq, "ALTER %sTABLE ONLY %s ", foreign,
   18585        2916 :                           fmtQualifiedDumpable(tbinfo));
   18586        2916 :         appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
   18587        2916 :                           fmtId(coninfo->dobj.name));
   18588             : 
   18589        2916 :         tag = psprintf("%s %s", tbinfo->dobj.name, coninfo->dobj.name);
   18590             : 
   18591        2916 :         if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   18592        2916 :             ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
   18593        2916 :                          ARCHIVE_OPTS(.tag = tag,
   18594             :                                       .namespace = tbinfo->dobj.namespace->dobj.name,
   18595             :                                       .tablespace = indxinfo->tablespace,
   18596             :                                       .owner = tbinfo->rolname,
   18597             :                                       .description = "CONSTRAINT",
   18598             :                                       .section = SECTION_POST_DATA,
   18599             :                                       .createStmt = q->data,
   18600             :                                       .dropStmt = delq->data));
   18601             :     }
   18602        2016 :     else if (coninfo->contype == 'f')
   18603             :     {
   18604             :         char       *only;
   18605             : 
   18606             :         /*
   18607             :          * Foreign keys on partitioned tables are always declared as
   18608             :          * inheriting to partitions; for all other cases, emit them as
   18609             :          * applying ONLY directly to the named table, because that's how they
   18610             :          * work for regular inherited tables.
   18611             :          */
   18612         330 :         only = tbinfo->relkind == RELKIND_PARTITIONED_TABLE ? "" : "ONLY ";
   18613             : 
   18614             :         /*
   18615             :          * XXX Potentially wrap in a 'SET CONSTRAINTS OFF' block so that the
   18616             :          * current table data is not processed
   18617             :          */
   18618         330 :         appendPQExpBuffer(q, "ALTER %sTABLE %s%s\n", foreign,
   18619         330 :                           only, fmtQualifiedDumpable(tbinfo));
   18620         330 :         appendPQExpBuffer(q, "    ADD CONSTRAINT %s %s;\n",
   18621         330 :                           fmtId(coninfo->dobj.name),
   18622         330 :                           coninfo->condef);
   18623             : 
   18624         330 :         appendPQExpBuffer(delq, "ALTER %sTABLE %s%s ", foreign,
   18625         330 :                           only, fmtQualifiedDumpable(tbinfo));
   18626         330 :         appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
   18627         330 :                           fmtId(coninfo->dobj.name));
   18628             : 
   18629         330 :         tag = psprintf("%s %s", tbinfo->dobj.name, coninfo->dobj.name);
   18630             : 
   18631         330 :         if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   18632         330 :             ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
   18633         330 :                          ARCHIVE_OPTS(.tag = tag,
   18634             :                                       .namespace = tbinfo->dobj.namespace->dobj.name,
   18635             :                                       .owner = tbinfo->rolname,
   18636             :                                       .description = "FK CONSTRAINT",
   18637             :                                       .section = SECTION_POST_DATA,
   18638             :                                       .createStmt = q->data,
   18639             :                                       .dropStmt = delq->data));
   18640             :     }
   18641        1686 :     else if ((coninfo->contype == 'c' || coninfo->contype == 'n') && tbinfo)
   18642             :     {
   18643             :         /* CHECK or invalid not-null constraint on a table */
   18644             : 
   18645             :         /* Ignore if not to be dumped separately, or if it was inherited */
   18646        1366 :         if (coninfo->separate && coninfo->conislocal)
   18647             :         {
   18648             :             const char *keyword;
   18649             : 
   18650         220 :             if (coninfo->contype == 'c')
   18651          90 :                 keyword = "CHECK CONSTRAINT";
   18652             :             else
   18653         130 :                 keyword = "CONSTRAINT";
   18654             : 
   18655             :             /* not ONLY since we want it to propagate to children */
   18656         220 :             appendPQExpBuffer(q, "ALTER %sTABLE %s\n", foreign,
   18657         220 :                               fmtQualifiedDumpable(tbinfo));
   18658         220 :             appendPQExpBuffer(q, "    ADD CONSTRAINT %s %s;\n",
   18659         220 :                               fmtId(coninfo->dobj.name),
   18660         220 :                               coninfo->condef);
   18661             : 
   18662         220 :             appendPQExpBuffer(delq, "ALTER %sTABLE %s ", foreign,
   18663         220 :                               fmtQualifiedDumpable(tbinfo));
   18664         220 :             appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
   18665         220 :                               fmtId(coninfo->dobj.name));
   18666             : 
   18667         220 :             tag = psprintf("%s %s", tbinfo->dobj.name, coninfo->dobj.name);
   18668             : 
   18669         220 :             if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   18670         220 :                 ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
   18671         220 :                              ARCHIVE_OPTS(.tag = tag,
   18672             :                                           .namespace = tbinfo->dobj.namespace->dobj.name,
   18673             :                                           .owner = tbinfo->rolname,
   18674             :                                           .description = keyword,
   18675             :                                           .section = SECTION_POST_DATA,
   18676             :                                           .createStmt = q->data,
   18677             :                                           .dropStmt = delq->data));
   18678             :         }
   18679             :     }
   18680         320 :     else if (tbinfo == NULL)
   18681             :     {
   18682             :         /* CHECK, NOT NULL constraint on a domain */
   18683         320 :         TypeInfo   *tyinfo = coninfo->condomain;
   18684             : 
   18685             :         Assert(coninfo->contype == 'c' || coninfo->contype == 'n');
   18686             : 
   18687             :         /* Ignore if not to be dumped separately */
   18688         320 :         if (coninfo->separate)
   18689             :         {
   18690             :             const char *keyword;
   18691             : 
   18692          10 :             if (coninfo->contype == 'c')
   18693          10 :                 keyword = "CHECK CONSTRAINT";
   18694             :             else
   18695           0 :                 keyword = "CONSTRAINT";
   18696             : 
   18697          10 :             appendPQExpBuffer(q, "ALTER DOMAIN %s\n",
   18698          10 :                               fmtQualifiedDumpable(tyinfo));
   18699          10 :             appendPQExpBuffer(q, "    ADD CONSTRAINT %s %s;\n",
   18700          10 :                               fmtId(coninfo->dobj.name),
   18701          10 :                               coninfo->condef);
   18702             : 
   18703          10 :             appendPQExpBuffer(delq, "ALTER DOMAIN %s ",
   18704          10 :                               fmtQualifiedDumpable(tyinfo));
   18705          10 :             appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
   18706          10 :                               fmtId(coninfo->dobj.name));
   18707             : 
   18708          10 :             tag = psprintf("%s %s", tyinfo->dobj.name, coninfo->dobj.name);
   18709             : 
   18710          10 :             if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   18711          10 :                 ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
   18712          10 :                              ARCHIVE_OPTS(.tag = tag,
   18713             :                                           .namespace = tyinfo->dobj.namespace->dobj.name,
   18714             :                                           .owner = tyinfo->rolname,
   18715             :                                           .description = keyword,
   18716             :                                           .section = SECTION_POST_DATA,
   18717             :                                           .createStmt = q->data,
   18718             :                                           .dropStmt = delq->data));
   18719             : 
   18720          10 :             if (coninfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   18721             :             {
   18722          10 :                 PQExpBuffer conprefix = createPQExpBuffer();
   18723          10 :                 char       *qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
   18724             : 
   18725          10 :                 appendPQExpBuffer(conprefix, "CONSTRAINT %s ON DOMAIN",
   18726          10 :                                   fmtId(coninfo->dobj.name));
   18727             : 
   18728          10 :                 dumpComment(fout, conprefix->data, qtypname,
   18729          10 :                             tyinfo->dobj.namespace->dobj.name,
   18730             :                             tyinfo->rolname,
   18731             :                             coninfo->dobj.catId, 0, tyinfo->dobj.dumpId);
   18732          10 :                 destroyPQExpBuffer(conprefix);
   18733          10 :                 free(qtypname);
   18734             :             }
   18735             :         }
   18736             :     }
   18737             :     else
   18738             :     {
   18739           0 :         pg_fatal("unrecognized constraint type: %c",
   18740             :                  coninfo->contype);
   18741             :     }
   18742             : 
   18743             :     /* Dump Constraint Comments --- only works for table constraints */
   18744        4932 :     if (tbinfo && coninfo->separate &&
   18745        3526 :         coninfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   18746         100 :         dumpTableConstraintComment(fout, coninfo);
   18747             : 
   18748        4932 :     free(tag);
   18749        4932 :     destroyPQExpBuffer(q);
   18750        4932 :     destroyPQExpBuffer(delq);
   18751             : }
   18752             : 
   18753             : /*
   18754             :  * dumpTableConstraintComment --- dump a constraint's comment if any
   18755             :  *
   18756             :  * This is split out because we need the function in two different places
   18757             :  * depending on whether the constraint is dumped as part of CREATE TABLE
   18758             :  * or as a separate ALTER command.
   18759             :  */
   18760             : static void
   18761         180 : dumpTableConstraintComment(Archive *fout, const ConstraintInfo *coninfo)
   18762             : {
   18763         180 :     TableInfo  *tbinfo = coninfo->contable;
   18764         180 :     PQExpBuffer conprefix = createPQExpBuffer();
   18765             :     char       *qtabname;
   18766             : 
   18767         180 :     qtabname = pg_strdup(fmtId(tbinfo->dobj.name));
   18768             : 
   18769         180 :     appendPQExpBuffer(conprefix, "CONSTRAINT %s ON",
   18770         180 :                       fmtId(coninfo->dobj.name));
   18771             : 
   18772         180 :     if (coninfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   18773         180 :         dumpComment(fout, conprefix->data, qtabname,
   18774         180 :                     tbinfo->dobj.namespace->dobj.name,
   18775             :                     tbinfo->rolname,
   18776             :                     coninfo->dobj.catId, 0,
   18777         180 :                     coninfo->separate ? coninfo->dobj.dumpId : tbinfo->dobj.dumpId);
   18778             : 
   18779         180 :     destroyPQExpBuffer(conprefix);
   18780         180 :     free(qtabname);
   18781         180 : }
   18782             : 
   18783             : static inline SeqType
   18784        1294 : parse_sequence_type(const char *name)
   18785             : {
   18786        2886 :     for (int i = 0; i < lengthof(SeqTypeNames); i++)
   18787             :     {
   18788        2886 :         if (strcmp(SeqTypeNames[i], name) == 0)
   18789        1294 :             return (SeqType) i;
   18790             :     }
   18791             : 
   18792           0 :     pg_fatal("unrecognized sequence type: %s", name);
   18793             :     return (SeqType) 0;         /* keep compiler quiet */
   18794             : }
   18795             : 
   18796             : /*
   18797             :  * bsearch() comparator for SequenceItem
   18798             :  */
   18799             : static int
   18800        5968 : SequenceItemCmp(const void *p1, const void *p2)
   18801             : {
   18802        5968 :     SequenceItem v1 = *((const SequenceItem *) p1);
   18803        5968 :     SequenceItem v2 = *((const SequenceItem *) p2);
   18804             : 
   18805        5968 :     return pg_cmp_u32(v1.oid, v2.oid);
   18806             : }
   18807             : 
   18808             : /*
   18809             :  * collectSequences
   18810             :  *
   18811             :  * Construct a table of sequence information.  This table is sorted by OID for
   18812             :  * speed in lookup.
   18813             :  */
   18814             : static void
   18815         364 : collectSequences(Archive *fout)
   18816             : {
   18817             :     PGresult   *res;
   18818             :     const char *query;
   18819             : 
   18820             :     /*
   18821             :      * Before Postgres 10, sequence metadata is in the sequence itself.  With
   18822             :      * some extra effort, we might be able to use the sorted table for those
   18823             :      * versions, but for now it seems unlikely to be worth it.
   18824             :      *
   18825             :      * Since version 18, we can gather the sequence data in this query with
   18826             :      * pg_get_sequence_data(), but we only do so for non-schema-only dumps.
   18827             :      */
   18828         364 :     if (fout->remoteVersion < 100000)
   18829           0 :         return;
   18830         364 :     else if (fout->remoteVersion < 180000 ||
   18831         364 :              (!fout->dopt->dumpData && !fout->dopt->sequence_data))
   18832          16 :         query = "SELECT seqrelid, format_type(seqtypid, NULL), "
   18833             :             "seqstart, seqincrement, "
   18834             :             "seqmax, seqmin, "
   18835             :             "seqcache, seqcycle, "
   18836             :             "NULL, 'f' "
   18837             :             "FROM pg_catalog.pg_sequence "
   18838             :             "ORDER BY seqrelid";
   18839             :     else
   18840         348 :         query = "SELECT seqrelid, format_type(seqtypid, NULL), "
   18841             :             "seqstart, seqincrement, "
   18842             :             "seqmax, seqmin, "
   18843             :             "seqcache, seqcycle, "
   18844             :             "last_value, is_called "
   18845             :             "FROM pg_catalog.pg_sequence, "
   18846             :             "pg_get_sequence_data(seqrelid) "
   18847             :             "ORDER BY seqrelid;";
   18848             : 
   18849         364 :     res = ExecuteSqlQuery(fout, query, PGRES_TUPLES_OK);
   18850             : 
   18851         364 :     nsequences = PQntuples(res);
   18852         364 :     sequences = (SequenceItem *) pg_malloc(nsequences * sizeof(SequenceItem));
   18853             : 
   18854        1658 :     for (int i = 0; i < nsequences; i++)
   18855             :     {
   18856        1294 :         sequences[i].oid = atooid(PQgetvalue(res, i, 0));
   18857        1294 :         sequences[i].seqtype = parse_sequence_type(PQgetvalue(res, i, 1));
   18858        1294 :         sequences[i].startv = strtoi64(PQgetvalue(res, i, 2), NULL, 10);
   18859        1294 :         sequences[i].incby = strtoi64(PQgetvalue(res, i, 3), NULL, 10);
   18860        1294 :         sequences[i].maxv = strtoi64(PQgetvalue(res, i, 4), NULL, 10);
   18861        1294 :         sequences[i].minv = strtoi64(PQgetvalue(res, i, 5), NULL, 10);
   18862        1294 :         sequences[i].cache = strtoi64(PQgetvalue(res, i, 6), NULL, 10);
   18863        1294 :         sequences[i].cycled = (strcmp(PQgetvalue(res, i, 7), "t") == 0);
   18864        1294 :         sequences[i].last_value = strtoi64(PQgetvalue(res, i, 8), NULL, 10);
   18865        1294 :         sequences[i].is_called = (strcmp(PQgetvalue(res, i, 9), "t") == 0);
   18866             :     }
   18867             : 
   18868         364 :     PQclear(res);
   18869             : }
   18870             : 
   18871             : /*
   18872             :  * dumpSequence
   18873             :  *    write the declaration (not data) of one user-defined sequence
   18874             :  */
   18875             : static void
   18876         768 : dumpSequence(Archive *fout, const TableInfo *tbinfo)
   18877             : {
   18878         768 :     DumpOptions *dopt = fout->dopt;
   18879             :     SequenceItem *seq;
   18880             :     bool        is_ascending;
   18881             :     int64       default_minv,
   18882             :                 default_maxv;
   18883         768 :     PQExpBuffer query = createPQExpBuffer();
   18884         768 :     PQExpBuffer delqry = createPQExpBuffer();
   18885             :     char       *qseqname;
   18886         768 :     TableInfo  *owning_tab = NULL;
   18887             : 
   18888         768 :     qseqname = pg_strdup(fmtId(tbinfo->dobj.name));
   18889             : 
   18890             :     /*
   18891             :      * For versions >= 10, the sequence information is gathered in a sorted
   18892             :      * table before any calls to dumpSequence().  See collectSequences() for
   18893             :      * more information.
   18894             :      */
   18895         768 :     if (fout->remoteVersion >= 100000)
   18896             :     {
   18897         768 :         SequenceItem key = {0};
   18898             : 
   18899             :         Assert(sequences);
   18900             : 
   18901         768 :         key.oid = tbinfo->dobj.catId.oid;
   18902         768 :         seq = bsearch(&key, sequences, nsequences,
   18903             :                       sizeof(SequenceItem), SequenceItemCmp);
   18904             :     }
   18905             :     else
   18906             :     {
   18907             :         PGresult   *res;
   18908             : 
   18909             :         /*
   18910             :          * Before PostgreSQL 10, sequence metadata is in the sequence itself.
   18911             :          *
   18912             :          * Note: it might seem that 'bigint' potentially needs to be
   18913             :          * schema-qualified, but actually that's a keyword.
   18914             :          */
   18915           0 :         appendPQExpBuffer(query,
   18916             :                           "SELECT 'bigint' AS sequence_type, "
   18917             :                           "start_value, increment_by, max_value, min_value, "
   18918             :                           "cache_value, is_cycled FROM %s",
   18919           0 :                           fmtQualifiedDumpable(tbinfo));
   18920             : 
   18921           0 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   18922             : 
   18923           0 :         if (PQntuples(res) != 1)
   18924           0 :             pg_fatal(ngettext("query to get data of sequence \"%s\" returned %d row (expected 1)",
   18925             :                               "query to get data of sequence \"%s\" returned %d rows (expected 1)",
   18926             :                               PQntuples(res)),
   18927             :                      tbinfo->dobj.name, PQntuples(res));
   18928             : 
   18929           0 :         seq = pg_malloc0(sizeof(SequenceItem));
   18930           0 :         seq->seqtype = parse_sequence_type(PQgetvalue(res, 0, 0));
   18931           0 :         seq->startv = strtoi64(PQgetvalue(res, 0, 1), NULL, 10);
   18932           0 :         seq->incby = strtoi64(PQgetvalue(res, 0, 2), NULL, 10);
   18933           0 :         seq->maxv = strtoi64(PQgetvalue(res, 0, 3), NULL, 10);
   18934           0 :         seq->minv = strtoi64(PQgetvalue(res, 0, 4), NULL, 10);
   18935           0 :         seq->cache = strtoi64(PQgetvalue(res, 0, 5), NULL, 10);
   18936           0 :         seq->cycled = (strcmp(PQgetvalue(res, 0, 6), "t") == 0);
   18937             : 
   18938           0 :         PQclear(res);
   18939             :     }
   18940             : 
   18941             :     /* Calculate default limits for a sequence of this type */
   18942         768 :     is_ascending = (seq->incby >= 0);
   18943         768 :     if (seq->seqtype == SEQTYPE_SMALLINT)
   18944             :     {
   18945          50 :         default_minv = is_ascending ? 1 : PG_INT16_MIN;
   18946          50 :         default_maxv = is_ascending ? PG_INT16_MAX : -1;
   18947             :     }
   18948         718 :     else if (seq->seqtype == SEQTYPE_INTEGER)
   18949             :     {
   18950         586 :         default_minv = is_ascending ? 1 : PG_INT32_MIN;
   18951         586 :         default_maxv = is_ascending ? PG_INT32_MAX : -1;
   18952             :     }
   18953         132 :     else if (seq->seqtype == SEQTYPE_BIGINT)
   18954             :     {
   18955         132 :         default_minv = is_ascending ? 1 : PG_INT64_MIN;
   18956         132 :         default_maxv = is_ascending ? PG_INT64_MAX : -1;
   18957             :     }
   18958             :     else
   18959             :     {
   18960           0 :         pg_fatal("unrecognized sequence type: %d", seq->seqtype);
   18961             :         default_minv = default_maxv = 0;    /* keep compiler quiet */
   18962             :     }
   18963             : 
   18964             :     /*
   18965             :      * Identity sequences are not to be dropped separately.
   18966             :      */
   18967         768 :     if (!tbinfo->is_identity_sequence)
   18968             :     {
   18969         478 :         appendPQExpBuffer(delqry, "DROP SEQUENCE %s;\n",
   18970         478 :                           fmtQualifiedDumpable(tbinfo));
   18971             :     }
   18972             : 
   18973         768 :     resetPQExpBuffer(query);
   18974             : 
   18975         768 :     if (dopt->binary_upgrade)
   18976             :     {
   18977         132 :         binary_upgrade_set_pg_class_oids(fout, query,
   18978         132 :                                          tbinfo->dobj.catId.oid);
   18979             : 
   18980             :         /*
   18981             :          * In older PG versions a sequence will have a pg_type entry, but v14
   18982             :          * and up don't use that, so don't attempt to preserve the type OID.
   18983             :          */
   18984             :     }
   18985             : 
   18986         768 :     if (tbinfo->is_identity_sequence)
   18987             :     {
   18988         290 :         owning_tab = findTableByOid(tbinfo->owning_tab);
   18989             : 
   18990         290 :         appendPQExpBuffer(query,
   18991             :                           "ALTER TABLE %s ",
   18992         290 :                           fmtQualifiedDumpable(owning_tab));
   18993         290 :         appendPQExpBuffer(query,
   18994             :                           "ALTER COLUMN %s ADD GENERATED ",
   18995         290 :                           fmtId(owning_tab->attnames[tbinfo->owning_col - 1]));
   18996         290 :         if (owning_tab->attidentity[tbinfo->owning_col - 1] == ATTRIBUTE_IDENTITY_ALWAYS)
   18997         210 :             appendPQExpBufferStr(query, "ALWAYS");
   18998          80 :         else if (owning_tab->attidentity[tbinfo->owning_col - 1] == ATTRIBUTE_IDENTITY_BY_DEFAULT)
   18999          80 :             appendPQExpBufferStr(query, "BY DEFAULT");
   19000         290 :         appendPQExpBuffer(query, " AS IDENTITY (\n    SEQUENCE NAME %s\n",
   19001         290 :                           fmtQualifiedDumpable(tbinfo));
   19002             : 
   19003             :         /*
   19004             :          * Emit persistence option only if it's different from the owning
   19005             :          * table's.  This avoids using this new syntax unnecessarily.
   19006             :          */
   19007         290 :         if (tbinfo->relpersistence != owning_tab->relpersistence)
   19008          20 :             appendPQExpBuffer(query, "    %s\n",
   19009          20 :                               tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED ?
   19010             :                               "UNLOGGED" : "LOGGED");
   19011             :     }
   19012             :     else
   19013             :     {
   19014         478 :         appendPQExpBuffer(query,
   19015             :                           "CREATE %sSEQUENCE %s\n",
   19016         478 :                           tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED ?
   19017             :                           "UNLOGGED " : "",
   19018         478 :                           fmtQualifiedDumpable(tbinfo));
   19019             : 
   19020         478 :         if (seq->seqtype != SEQTYPE_BIGINT)
   19021         376 :             appendPQExpBuffer(query, "    AS %s\n", SeqTypeNames[seq->seqtype]);
   19022             :     }
   19023             : 
   19024         768 :     appendPQExpBuffer(query, "    START WITH " INT64_FORMAT "\n", seq->startv);
   19025             : 
   19026         768 :     appendPQExpBuffer(query, "    INCREMENT BY " INT64_FORMAT "\n", seq->incby);
   19027             : 
   19028         768 :     if (seq->minv != default_minv)
   19029          30 :         appendPQExpBuffer(query, "    MINVALUE " INT64_FORMAT "\n", seq->minv);
   19030             :     else
   19031         738 :         appendPQExpBufferStr(query, "    NO MINVALUE\n");
   19032             : 
   19033         768 :     if (seq->maxv != default_maxv)
   19034          30 :         appendPQExpBuffer(query, "    MAXVALUE " INT64_FORMAT "\n", seq->maxv);
   19035             :     else
   19036         738 :         appendPQExpBufferStr(query, "    NO MAXVALUE\n");
   19037             : 
   19038         768 :     appendPQExpBuffer(query,
   19039             :                       "    CACHE " INT64_FORMAT "%s",
   19040         768 :                       seq->cache, (seq->cycled ? "\n    CYCLE" : ""));
   19041             : 
   19042         768 :     if (tbinfo->is_identity_sequence)
   19043         290 :         appendPQExpBufferStr(query, "\n);\n");
   19044             :     else
   19045         478 :         appendPQExpBufferStr(query, ";\n");
   19046             : 
   19047             :     /* binary_upgrade:  no need to clear TOAST table oid */
   19048             : 
   19049         768 :     if (dopt->binary_upgrade)
   19050         132 :         binary_upgrade_extension_member(query, &tbinfo->dobj,
   19051             :                                         "SEQUENCE", qseqname,
   19052         132 :                                         tbinfo->dobj.namespace->dobj.name);
   19053             : 
   19054         768 :     if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   19055         768 :         ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
   19056         768 :                      ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
   19057             :                                   .namespace = tbinfo->dobj.namespace->dobj.name,
   19058             :                                   .owner = tbinfo->rolname,
   19059             :                                   .description = "SEQUENCE",
   19060             :                                   .section = SECTION_PRE_DATA,
   19061             :                                   .createStmt = query->data,
   19062             :                                   .dropStmt = delqry->data));
   19063             : 
   19064             :     /*
   19065             :      * If the sequence is owned by a table column, emit the ALTER for it as a
   19066             :      * separate TOC entry immediately following the sequence's own entry. It's
   19067             :      * OK to do this rather than using full sorting logic, because the
   19068             :      * dependency that tells us it's owned will have forced the table to be
   19069             :      * created first.  We can't just include the ALTER in the TOC entry
   19070             :      * because it will fail if we haven't reassigned the sequence owner to
   19071             :      * match the table's owner.
   19072             :      *
   19073             :      * We need not schema-qualify the table reference because both sequence
   19074             :      * and table must be in the same schema.
   19075             :      */
   19076         768 :     if (OidIsValid(tbinfo->owning_tab) && !tbinfo->is_identity_sequence)
   19077             :     {
   19078         286 :         owning_tab = findTableByOid(tbinfo->owning_tab);
   19079             : 
   19080         286 :         if (owning_tab == NULL)
   19081           0 :             pg_fatal("failed sanity check, parent table with OID %u of sequence with OID %u not found",
   19082             :                      tbinfo->owning_tab, tbinfo->dobj.catId.oid);
   19083             : 
   19084         286 :         if (owning_tab->dobj.dump & DUMP_COMPONENT_DEFINITION)
   19085             :         {
   19086         282 :             resetPQExpBuffer(query);
   19087         282 :             appendPQExpBuffer(query, "ALTER SEQUENCE %s",
   19088         282 :                               fmtQualifiedDumpable(tbinfo));
   19089         282 :             appendPQExpBuffer(query, " OWNED BY %s",
   19090         282 :                               fmtQualifiedDumpable(owning_tab));
   19091         282 :             appendPQExpBuffer(query, ".%s;\n",
   19092         282 :                               fmtId(owning_tab->attnames[tbinfo->owning_col - 1]));
   19093             : 
   19094         282 :             if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   19095         282 :                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
   19096         282 :                              ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
   19097             :                                           .namespace = tbinfo->dobj.namespace->dobj.name,
   19098             :                                           .owner = tbinfo->rolname,
   19099             :                                           .description = "SEQUENCE OWNED BY",
   19100             :                                           .section = SECTION_PRE_DATA,
   19101             :                                           .createStmt = query->data,
   19102             :                                           .deps = &(tbinfo->dobj.dumpId),
   19103             :                                           .nDeps = 1));
   19104             :         }
   19105             :     }
   19106             : 
   19107             :     /* Dump Sequence Comments and Security Labels */
   19108         768 :     if (tbinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   19109           0 :         dumpComment(fout, "SEQUENCE", qseqname,
   19110           0 :                     tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
   19111           0 :                     tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
   19112             : 
   19113         768 :     if (tbinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
   19114           0 :         dumpSecLabel(fout, "SEQUENCE", qseqname,
   19115           0 :                      tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
   19116           0 :                      tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
   19117             : 
   19118         768 :     if (fout->remoteVersion < 100000)
   19119           0 :         pg_free(seq);
   19120         768 :     destroyPQExpBuffer(query);
   19121         768 :     destroyPQExpBuffer(delqry);
   19122         768 :     free(qseqname);
   19123         768 : }
   19124             : 
   19125             : /*
   19126             :  * dumpSequenceData
   19127             :  *    write the data of one user-defined sequence
   19128             :  */
   19129             : static void
   19130         804 : dumpSequenceData(Archive *fout, const TableDataInfo *tdinfo)
   19131             : {
   19132         804 :     TableInfo  *tbinfo = tdinfo->tdtable;
   19133             :     int64       last;
   19134             :     bool        called;
   19135         804 :     PQExpBuffer query = createPQExpBuffer();
   19136             : 
   19137             :     /*
   19138             :      * For versions >= 18, the sequence information is gathered in the sorted
   19139             :      * array before any calls to dumpSequenceData().  See collectSequences()
   19140             :      * for more information.
   19141             :      *
   19142             :      * For older versions, we have to query the sequence relations
   19143             :      * individually.
   19144             :      */
   19145         804 :     if (fout->remoteVersion < 180000)
   19146             :     {
   19147             :         PGresult   *res;
   19148             : 
   19149           0 :         appendPQExpBuffer(query,
   19150             :                           "SELECT last_value, is_called FROM %s",
   19151           0 :                           fmtQualifiedDumpable(tbinfo));
   19152             : 
   19153           0 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   19154             : 
   19155           0 :         if (PQntuples(res) != 1)
   19156           0 :             pg_fatal(ngettext("query to get data of sequence \"%s\" returned %d row (expected 1)",
   19157             :                               "query to get data of sequence \"%s\" returned %d rows (expected 1)",
   19158             :                               PQntuples(res)),
   19159             :                      tbinfo->dobj.name, PQntuples(res));
   19160             : 
   19161           0 :         last = strtoi64(PQgetvalue(res, 0, 0), NULL, 10);
   19162           0 :         called = (strcmp(PQgetvalue(res, 0, 1), "t") == 0);
   19163             : 
   19164           0 :         PQclear(res);
   19165             :     }
   19166             :     else
   19167             :     {
   19168         804 :         SequenceItem key = {0};
   19169             :         SequenceItem *entry;
   19170             : 
   19171             :         Assert(sequences);
   19172             :         Assert(tbinfo->dobj.catId.oid);
   19173             : 
   19174         804 :         key.oid = tbinfo->dobj.catId.oid;
   19175         804 :         entry = bsearch(&key, sequences, nsequences,
   19176             :                         sizeof(SequenceItem), SequenceItemCmp);
   19177             : 
   19178         804 :         last = entry->last_value;
   19179         804 :         called = entry->is_called;
   19180             :     }
   19181             : 
   19182         804 :     resetPQExpBuffer(query);
   19183         804 :     appendPQExpBufferStr(query, "SELECT pg_catalog.setval(");
   19184         804 :     appendStringLiteralAH(query, fmtQualifiedDumpable(tbinfo), fout);
   19185         804 :     appendPQExpBuffer(query, ", " INT64_FORMAT ", %s);\n",
   19186             :                       last, (called ? "true" : "false"));
   19187             : 
   19188         804 :     if (tdinfo->dobj.dump & DUMP_COMPONENT_DATA)
   19189         804 :         ArchiveEntry(fout, nilCatalogId, createDumpId(),
   19190         804 :                      ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
   19191             :                                   .namespace = tbinfo->dobj.namespace->dobj.name,
   19192             :                                   .owner = tbinfo->rolname,
   19193             :                                   .description = "SEQUENCE SET",
   19194             :                                   .section = SECTION_DATA,
   19195             :                                   .createStmt = query->data,
   19196             :                                   .deps = &(tbinfo->dobj.dumpId),
   19197             :                                   .nDeps = 1));
   19198             : 
   19199         804 :     destroyPQExpBuffer(query);
   19200         804 : }
   19201             : 
   19202             : /*
   19203             :  * dumpTrigger
   19204             :  *    write the declaration of one user-defined table trigger
   19205             :  */
   19206             : static void
   19207        1076 : dumpTrigger(Archive *fout, const TriggerInfo *tginfo)
   19208             : {
   19209        1076 :     DumpOptions *dopt = fout->dopt;
   19210        1076 :     TableInfo  *tbinfo = tginfo->tgtable;
   19211             :     PQExpBuffer query;
   19212             :     PQExpBuffer delqry;
   19213             :     PQExpBuffer trigprefix;
   19214             :     PQExpBuffer trigidentity;
   19215             :     char       *qtabname;
   19216             :     char       *tag;
   19217             : 
   19218             :     /* Do nothing if not dumping schema */
   19219        1076 :     if (!dopt->dumpSchema)
   19220          62 :         return;
   19221             : 
   19222        1014 :     query = createPQExpBuffer();
   19223        1014 :     delqry = createPQExpBuffer();
   19224        1014 :     trigprefix = createPQExpBuffer();
   19225        1014 :     trigidentity = createPQExpBuffer();
   19226             : 
   19227        1014 :     qtabname = pg_strdup(fmtId(tbinfo->dobj.name));
   19228             : 
   19229        1014 :     appendPQExpBuffer(trigidentity, "%s ", fmtId(tginfo->dobj.name));
   19230        1014 :     appendPQExpBuffer(trigidentity, "ON %s", fmtQualifiedDumpable(tbinfo));
   19231             : 
   19232        1014 :     appendPQExpBuffer(query, "%s;\n", tginfo->tgdef);
   19233        1014 :     appendPQExpBuffer(delqry, "DROP TRIGGER %s;\n", trigidentity->data);
   19234             : 
   19235             :     /* Triggers can depend on extensions */
   19236        1014 :     append_depends_on_extension(fout, query, &tginfo->dobj,
   19237             :                                 "pg_catalog.pg_trigger", "TRIGGER",
   19238        1014 :                                 trigidentity->data);
   19239             : 
   19240        1014 :     if (tginfo->tgispartition)
   19241             :     {
   19242             :         Assert(tbinfo->ispartition);
   19243             : 
   19244             :         /*
   19245             :          * Partition triggers only appear here because their 'tgenabled' flag
   19246             :          * differs from its parent's.  The trigger is created already, so
   19247             :          * remove the CREATE and replace it with an ALTER.  (Clear out the
   19248             :          * DROP query too, so that pg_dump --create does not cause errors.)
   19249             :          */
   19250         236 :         resetPQExpBuffer(query);
   19251         236 :         resetPQExpBuffer(delqry);
   19252         236 :         appendPQExpBuffer(query, "\nALTER %sTABLE %s ",
   19253         236 :                           tbinfo->relkind == RELKIND_FOREIGN_TABLE ? "FOREIGN " : "",
   19254         236 :                           fmtQualifiedDumpable(tbinfo));
   19255         236 :         switch (tginfo->tgenabled)
   19256             :         {
   19257          82 :             case 'f':
   19258             :             case 'D':
   19259          82 :                 appendPQExpBufferStr(query, "DISABLE");
   19260          82 :                 break;
   19261           0 :             case 't':
   19262             :             case 'O':
   19263           0 :                 appendPQExpBufferStr(query, "ENABLE");
   19264           0 :                 break;
   19265          72 :             case 'R':
   19266          72 :                 appendPQExpBufferStr(query, "ENABLE REPLICA");
   19267          72 :                 break;
   19268          82 :             case 'A':
   19269          82 :                 appendPQExpBufferStr(query, "ENABLE ALWAYS");
   19270          82 :                 break;
   19271             :         }
   19272         236 :         appendPQExpBuffer(query, " TRIGGER %s;\n",
   19273         236 :                           fmtId(tginfo->dobj.name));
   19274             :     }
   19275         778 :     else if (tginfo->tgenabled != 't' && tginfo->tgenabled != 'O')
   19276             :     {
   19277           0 :         appendPQExpBuffer(query, "\nALTER %sTABLE %s ",
   19278           0 :                           tbinfo->relkind == RELKIND_FOREIGN_TABLE ? "FOREIGN " : "",
   19279           0 :                           fmtQualifiedDumpable(tbinfo));
   19280           0 :         switch (tginfo->tgenabled)
   19281             :         {
   19282           0 :             case 'D':
   19283             :             case 'f':
   19284           0 :                 appendPQExpBufferStr(query, "DISABLE");
   19285           0 :                 break;
   19286           0 :             case 'A':
   19287           0 :                 appendPQExpBufferStr(query, "ENABLE ALWAYS");
   19288           0 :                 break;
   19289           0 :             case 'R':
   19290           0 :                 appendPQExpBufferStr(query, "ENABLE REPLICA");
   19291           0 :                 break;
   19292           0 :             default:
   19293           0 :                 appendPQExpBufferStr(query, "ENABLE");
   19294           0 :                 break;
   19295             :         }
   19296           0 :         appendPQExpBuffer(query, " TRIGGER %s;\n",
   19297           0 :                           fmtId(tginfo->dobj.name));
   19298             :     }
   19299             : 
   19300        1014 :     appendPQExpBuffer(trigprefix, "TRIGGER %s ON",
   19301        1014 :                       fmtId(tginfo->dobj.name));
   19302             : 
   19303        1014 :     tag = psprintf("%s %s", tbinfo->dobj.name, tginfo->dobj.name);
   19304             : 
   19305        1014 :     if (tginfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   19306        1014 :         ArchiveEntry(fout, tginfo->dobj.catId, tginfo->dobj.dumpId,
   19307        1014 :                      ARCHIVE_OPTS(.tag = tag,
   19308             :                                   .namespace = tbinfo->dobj.namespace->dobj.name,
   19309             :                                   .owner = tbinfo->rolname,
   19310             :                                   .description = "TRIGGER",
   19311             :                                   .section = SECTION_POST_DATA,
   19312             :                                   .createStmt = query->data,
   19313             :                                   .dropStmt = delqry->data));
   19314             : 
   19315        1014 :     if (tginfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   19316           0 :         dumpComment(fout, trigprefix->data, qtabname,
   19317           0 :                     tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
   19318           0 :                     tginfo->dobj.catId, 0, tginfo->dobj.dumpId);
   19319             : 
   19320        1014 :     free(tag);
   19321        1014 :     destroyPQExpBuffer(query);
   19322        1014 :     destroyPQExpBuffer(delqry);
   19323        1014 :     destroyPQExpBuffer(trigprefix);
   19324        1014 :     destroyPQExpBuffer(trigidentity);
   19325        1014 :     free(qtabname);
   19326             : }
   19327             : 
   19328             : /*
   19329             :  * dumpEventTrigger
   19330             :  *    write the declaration of one user-defined event trigger
   19331             :  */
   19332             : static void
   19333          90 : dumpEventTrigger(Archive *fout, const EventTriggerInfo *evtinfo)
   19334             : {
   19335          90 :     DumpOptions *dopt = fout->dopt;
   19336             :     PQExpBuffer query;
   19337             :     PQExpBuffer delqry;
   19338             :     char       *qevtname;
   19339             : 
   19340             :     /* Do nothing if not dumping schema */
   19341          90 :     if (!dopt->dumpSchema)
   19342          12 :         return;
   19343             : 
   19344          78 :     query = createPQExpBuffer();
   19345          78 :     delqry = createPQExpBuffer();
   19346             : 
   19347          78 :     qevtname = pg_strdup(fmtId(evtinfo->dobj.name));
   19348             : 
   19349          78 :     appendPQExpBufferStr(query, "CREATE EVENT TRIGGER ");
   19350          78 :     appendPQExpBufferStr(query, qevtname);
   19351          78 :     appendPQExpBufferStr(query, " ON ");
   19352          78 :     appendPQExpBufferStr(query, fmtId(evtinfo->evtevent));
   19353             : 
   19354          78 :     if (strcmp("", evtinfo->evttags) != 0)
   19355             :     {
   19356          10 :         appendPQExpBufferStr(query, "\n         WHEN TAG IN (");
   19357          10 :         appendPQExpBufferStr(query, evtinfo->evttags);
   19358          10 :         appendPQExpBufferChar(query, ')');
   19359             :     }
   19360             : 
   19361          78 :     appendPQExpBufferStr(query, "\n   EXECUTE FUNCTION ");
   19362          78 :     appendPQExpBufferStr(query, evtinfo->evtfname);
   19363          78 :     appendPQExpBufferStr(query, "();\n");
   19364             : 
   19365          78 :     if (evtinfo->evtenabled != 'O')
   19366             :     {
   19367           0 :         appendPQExpBuffer(query, "\nALTER EVENT TRIGGER %s ",
   19368             :                           qevtname);
   19369           0 :         switch (evtinfo->evtenabled)
   19370             :         {
   19371           0 :             case 'D':
   19372           0 :                 appendPQExpBufferStr(query, "DISABLE");
   19373           0 :                 break;
   19374           0 :             case 'A':
   19375           0 :                 appendPQExpBufferStr(query, "ENABLE ALWAYS");
   19376           0 :                 break;
   19377           0 :             case 'R':
   19378           0 :                 appendPQExpBufferStr(query, "ENABLE REPLICA");
   19379           0 :                 break;
   19380           0 :             default:
   19381           0 :                 appendPQExpBufferStr(query, "ENABLE");
   19382           0 :                 break;
   19383             :         }
   19384           0 :         appendPQExpBufferStr(query, ";\n");
   19385             :     }
   19386             : 
   19387          78 :     appendPQExpBuffer(delqry, "DROP EVENT TRIGGER %s;\n",
   19388             :                       qevtname);
   19389             : 
   19390          78 :     if (dopt->binary_upgrade)
   19391           4 :         binary_upgrade_extension_member(query, &evtinfo->dobj,
   19392             :                                         "EVENT TRIGGER", qevtname, NULL);
   19393             : 
   19394          78 :     if (evtinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   19395          78 :         ArchiveEntry(fout, evtinfo->dobj.catId, evtinfo->dobj.dumpId,
   19396          78 :                      ARCHIVE_OPTS(.tag = evtinfo->dobj.name,
   19397             :                                   .owner = evtinfo->evtowner,
   19398             :                                   .description = "EVENT TRIGGER",
   19399             :                                   .section = SECTION_POST_DATA,
   19400             :                                   .createStmt = query->data,
   19401             :                                   .dropStmt = delqry->data));
   19402             : 
   19403          78 :     if (evtinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   19404           0 :         dumpComment(fout, "EVENT TRIGGER", qevtname,
   19405           0 :                     NULL, evtinfo->evtowner,
   19406           0 :                     evtinfo->dobj.catId, 0, evtinfo->dobj.dumpId);
   19407             : 
   19408          78 :     destroyPQExpBuffer(query);
   19409          78 :     destroyPQExpBuffer(delqry);
   19410          78 :     free(qevtname);
   19411             : }
   19412             : 
   19413             : /*
   19414             :  * dumpRule
   19415             :  *      Dump a rule
   19416             :  */
   19417             : static void
   19418        2380 : dumpRule(Archive *fout, const RuleInfo *rinfo)
   19419             : {
   19420        2380 :     DumpOptions *dopt = fout->dopt;
   19421        2380 :     TableInfo  *tbinfo = rinfo->ruletable;
   19422             :     bool        is_view;
   19423             :     PQExpBuffer query;
   19424             :     PQExpBuffer cmd;
   19425             :     PQExpBuffer delcmd;
   19426             :     PQExpBuffer ruleprefix;
   19427             :     char       *qtabname;
   19428             :     PGresult   *res;
   19429             :     char       *tag;
   19430             : 
   19431             :     /* Do nothing if not dumping schema */
   19432        2380 :     if (!dopt->dumpSchema)
   19433         132 :         return;
   19434             : 
   19435             :     /*
   19436             :      * If it is an ON SELECT rule that is created implicitly by CREATE VIEW,
   19437             :      * we do not want to dump it as a separate object.
   19438             :      */
   19439        2248 :     if (!rinfo->separate)
   19440        1826 :         return;
   19441             : 
   19442             :     /*
   19443             :      * If it's an ON SELECT rule, we want to print it as a view definition,
   19444             :      * instead of a rule.
   19445             :      */
   19446         422 :     is_view = (rinfo->ev_type == '1' && rinfo->is_instead);
   19447             : 
   19448         422 :     query = createPQExpBuffer();
   19449         422 :     cmd = createPQExpBuffer();
   19450         422 :     delcmd = createPQExpBuffer();
   19451         422 :     ruleprefix = createPQExpBuffer();
   19452             : 
   19453         422 :     qtabname = pg_strdup(fmtId(tbinfo->dobj.name));
   19454             : 
   19455         422 :     if (is_view)
   19456             :     {
   19457             :         PQExpBuffer result;
   19458             : 
   19459             :         /*
   19460             :          * We need OR REPLACE here because we'll be replacing a dummy view.
   19461             :          * Otherwise this should look largely like the regular view dump code.
   19462             :          */
   19463          20 :         appendPQExpBuffer(cmd, "CREATE OR REPLACE VIEW %s",
   19464          20 :                           fmtQualifiedDumpable(tbinfo));
   19465          20 :         if (nonemptyReloptions(tbinfo->reloptions))
   19466             :         {
   19467           0 :             appendPQExpBufferStr(cmd, " WITH (");
   19468           0 :             appendReloptionsArrayAH(cmd, tbinfo->reloptions, "", fout);
   19469           0 :             appendPQExpBufferChar(cmd, ')');
   19470             :         }
   19471          20 :         result = createViewAsClause(fout, tbinfo);
   19472          20 :         appendPQExpBuffer(cmd, " AS\n%s", result->data);
   19473          20 :         destroyPQExpBuffer(result);
   19474          20 :         if (tbinfo->checkoption != NULL)
   19475           0 :             appendPQExpBuffer(cmd, "\n  WITH %s CHECK OPTION",
   19476             :                               tbinfo->checkoption);
   19477          20 :         appendPQExpBufferStr(cmd, ";\n");
   19478             :     }
   19479             :     else
   19480             :     {
   19481             :         /* In the rule case, just print pg_get_ruledef's result verbatim */
   19482         402 :         appendPQExpBuffer(query,
   19483             :                           "SELECT pg_catalog.pg_get_ruledef('%u'::pg_catalog.oid)",
   19484         402 :                           rinfo->dobj.catId.oid);
   19485             : 
   19486         402 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   19487             : 
   19488         402 :         if (PQntuples(res) != 1)
   19489           0 :             pg_fatal("query to get rule \"%s\" for table \"%s\" failed: wrong number of rows returned",
   19490             :                      rinfo->dobj.name, tbinfo->dobj.name);
   19491             : 
   19492         402 :         printfPQExpBuffer(cmd, "%s\n", PQgetvalue(res, 0, 0));
   19493             : 
   19494         402 :         PQclear(res);
   19495             :     }
   19496             : 
   19497             :     /*
   19498             :      * Add the command to alter the rules replication firing semantics if it
   19499             :      * differs from the default.
   19500             :      */
   19501         422 :     if (rinfo->ev_enabled != 'O')
   19502             :     {
   19503          30 :         appendPQExpBuffer(cmd, "ALTER TABLE %s ", fmtQualifiedDumpable(tbinfo));
   19504          30 :         switch (rinfo->ev_enabled)
   19505             :         {
   19506           0 :             case 'A':
   19507           0 :                 appendPQExpBuffer(cmd, "ENABLE ALWAYS RULE %s;\n",
   19508           0 :                                   fmtId(rinfo->dobj.name));
   19509           0 :                 break;
   19510           0 :             case 'R':
   19511           0 :                 appendPQExpBuffer(cmd, "ENABLE REPLICA RULE %s;\n",
   19512           0 :                                   fmtId(rinfo->dobj.name));
   19513           0 :                 break;
   19514          30 :             case 'D':
   19515          30 :                 appendPQExpBuffer(cmd, "DISABLE RULE %s;\n",
   19516          30 :                                   fmtId(rinfo->dobj.name));
   19517          30 :                 break;
   19518             :         }
   19519             :     }
   19520             : 
   19521         422 :     if (is_view)
   19522             :     {
   19523             :         /*
   19524             :          * We can't DROP a view's ON SELECT rule.  Instead, use CREATE OR
   19525             :          * REPLACE VIEW to replace the rule with something with minimal
   19526             :          * dependencies.
   19527             :          */
   19528             :         PQExpBuffer result;
   19529             : 
   19530          20 :         appendPQExpBuffer(delcmd, "CREATE OR REPLACE VIEW %s",
   19531          20 :                           fmtQualifiedDumpable(tbinfo));
   19532          20 :         result = createDummyViewAsClause(fout, tbinfo);
   19533          20 :         appendPQExpBuffer(delcmd, " AS\n%s;\n", result->data);
   19534          20 :         destroyPQExpBuffer(result);
   19535             :     }
   19536             :     else
   19537             :     {
   19538         402 :         appendPQExpBuffer(delcmd, "DROP RULE %s ",
   19539         402 :                           fmtId(rinfo->dobj.name));
   19540         402 :         appendPQExpBuffer(delcmd, "ON %s;\n",
   19541         402 :                           fmtQualifiedDumpable(tbinfo));
   19542             :     }
   19543             : 
   19544         422 :     appendPQExpBuffer(ruleprefix, "RULE %s ON",
   19545         422 :                       fmtId(rinfo->dobj.name));
   19546             : 
   19547         422 :     tag = psprintf("%s %s", tbinfo->dobj.name, rinfo->dobj.name);
   19548             : 
   19549         422 :     if (rinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   19550         422 :         ArchiveEntry(fout, rinfo->dobj.catId, rinfo->dobj.dumpId,
   19551         422 :                      ARCHIVE_OPTS(.tag = tag,
   19552             :                                   .namespace = tbinfo->dobj.namespace->dobj.name,
   19553             :                                   .owner = tbinfo->rolname,
   19554             :                                   .description = "RULE",
   19555             :                                   .section = SECTION_POST_DATA,
   19556             :                                   .createStmt = cmd->data,
   19557             :                                   .dropStmt = delcmd->data));
   19558             : 
   19559             :     /* Dump rule comments */
   19560         422 :     if (rinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   19561           0 :         dumpComment(fout, ruleprefix->data, qtabname,
   19562           0 :                     tbinfo->dobj.namespace->dobj.name,
   19563             :                     tbinfo->rolname,
   19564           0 :                     rinfo->dobj.catId, 0, rinfo->dobj.dumpId);
   19565             : 
   19566         422 :     free(tag);
   19567         422 :     destroyPQExpBuffer(query);
   19568         422 :     destroyPQExpBuffer(cmd);
   19569         422 :     destroyPQExpBuffer(delcmd);
   19570         422 :     destroyPQExpBuffer(ruleprefix);
   19571         422 :     free(qtabname);
   19572             : }
   19573             : 
   19574             : /*
   19575             :  * getExtensionMembership --- obtain extension membership data
   19576             :  *
   19577             :  * We need to identify objects that are extension members as soon as they're
   19578             :  * loaded, so that we can correctly determine whether they need to be dumped.
   19579             :  * Generally speaking, extension member objects will get marked as *not* to
   19580             :  * be dumped, as they will be recreated by the single CREATE EXTENSION
   19581             :  * command.  However, in binary upgrade mode we still need to dump the members
   19582             :  * individually.
   19583             :  */
   19584             : void
   19585         366 : getExtensionMembership(Archive *fout, ExtensionInfo extinfo[],
   19586             :                        int numExtensions)
   19587             : {
   19588             :     PQExpBuffer query;
   19589             :     PGresult   *res;
   19590             :     int         ntups,
   19591             :                 i;
   19592             :     int         i_classid,
   19593             :                 i_objid,
   19594             :                 i_refobjid;
   19595             :     ExtensionInfo *ext;
   19596             : 
   19597             :     /* Nothing to do if no extensions */
   19598         366 :     if (numExtensions == 0)
   19599           0 :         return;
   19600             : 
   19601         366 :     query = createPQExpBuffer();
   19602             : 
   19603             :     /* refclassid constraint is redundant but may speed the search */
   19604         366 :     appendPQExpBufferStr(query, "SELECT "
   19605             :                          "classid, objid, refobjid "
   19606             :                          "FROM pg_depend "
   19607             :                          "WHERE refclassid = 'pg_extension'::regclass "
   19608             :                          "AND deptype = 'e' "
   19609             :                          "ORDER BY 3");
   19610             : 
   19611         366 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   19612             : 
   19613         366 :     ntups = PQntuples(res);
   19614             : 
   19615         366 :     i_classid = PQfnumber(res, "classid");
   19616         366 :     i_objid = PQfnumber(res, "objid");
   19617         366 :     i_refobjid = PQfnumber(res, "refobjid");
   19618             : 
   19619             :     /*
   19620             :      * Since we ordered the SELECT by referenced ID, we can expect that
   19621             :      * multiple entries for the same extension will appear together; this
   19622             :      * saves on searches.
   19623             :      */
   19624         366 :     ext = NULL;
   19625             : 
   19626        3030 :     for (i = 0; i < ntups; i++)
   19627             :     {
   19628             :         CatalogId   objId;
   19629             :         Oid         extId;
   19630             : 
   19631        2664 :         objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
   19632        2664 :         objId.oid = atooid(PQgetvalue(res, i, i_objid));
   19633        2664 :         extId = atooid(PQgetvalue(res, i, i_refobjid));
   19634             : 
   19635        2664 :         if (ext == NULL ||
   19636        2298 :             ext->dobj.catId.oid != extId)
   19637         416 :             ext = findExtensionByOid(extId);
   19638             : 
   19639        2664 :         if (ext == NULL)
   19640             :         {
   19641             :             /* shouldn't happen */
   19642           0 :             pg_log_warning("could not find referenced extension %u", extId);
   19643           0 :             continue;
   19644             :         }
   19645             : 
   19646        2664 :         recordExtensionMembership(objId, ext);
   19647             :     }
   19648             : 
   19649         366 :     PQclear(res);
   19650             : 
   19651         366 :     destroyPQExpBuffer(query);
   19652             : }
   19653             : 
   19654             : /*
   19655             :  * processExtensionTables --- deal with extension configuration tables
   19656             :  *
   19657             :  * There are two parts to this process:
   19658             :  *
   19659             :  * 1. Identify and create dump records for extension configuration tables.
   19660             :  *
   19661             :  *    Extensions can mark tables as "configuration", which means that the user
   19662             :  *    is able and expected to modify those tables after the extension has been
   19663             :  *    loaded.  For these tables, we dump out only the data- the structure is
   19664             :  *    expected to be handled at CREATE EXTENSION time, including any indexes or
   19665             :  *    foreign keys, which brings us to-
   19666             :  *
   19667             :  * 2. Record FK dependencies between configuration tables.
   19668             :  *
   19669             :  *    Due to the FKs being created at CREATE EXTENSION time and therefore before
   19670             :  *    the data is loaded, we have to work out what the best order for reloading
   19671             :  *    the data is, to avoid FK violations when the tables are restored.  This is
   19672             :  *    not perfect- we can't handle circular dependencies and if any exist they
   19673             :  *    will cause an invalid dump to be produced (though at least all of the data
   19674             :  *    is included for a user to manually restore).  This is currently documented
   19675             :  *    but perhaps we can provide a better solution in the future.
   19676             :  */
   19677             : void
   19678         364 : processExtensionTables(Archive *fout, ExtensionInfo extinfo[],
   19679             :                        int numExtensions)
   19680             : {
   19681         364 :     DumpOptions *dopt = fout->dopt;
   19682             :     PQExpBuffer query;
   19683             :     PGresult   *res;
   19684             :     int         ntups,
   19685             :                 i;
   19686             :     int         i_conrelid,
   19687             :                 i_confrelid;
   19688             : 
   19689             :     /* Nothing to do if no extensions */
   19690         364 :     if (numExtensions == 0)
   19691           0 :         return;
   19692             : 
   19693             :     /*
   19694             :      * Identify extension configuration tables and create TableDataInfo
   19695             :      * objects for them, ensuring their data will be dumped even though the
   19696             :      * tables themselves won't be.
   19697             :      *
   19698             :      * Note that we create TableDataInfo objects even in schema-only mode, ie,
   19699             :      * user data in a configuration table is treated like schema data. This
   19700             :      * seems appropriate since system data in a config table would get
   19701             :      * reloaded by CREATE EXTENSION.  If the extension is not listed in the
   19702             :      * list of extensions to be included, none of its data is dumped.
   19703             :      */
   19704         778 :     for (i = 0; i < numExtensions; i++)
   19705             :     {
   19706         414 :         ExtensionInfo *curext = &(extinfo[i]);
   19707         414 :         char       *extconfig = curext->extconfig;
   19708         414 :         char       *extcondition = curext->extcondition;
   19709         414 :         char      **extconfigarray = NULL;
   19710         414 :         char      **extconditionarray = NULL;
   19711         414 :         int         nconfigitems = 0;
   19712         414 :         int         nconditionitems = 0;
   19713             : 
   19714             :         /*
   19715             :          * Check if this extension is listed as to include in the dump.  If
   19716             :          * not, any table data associated with it is discarded.
   19717             :          */
   19718         414 :         if (extension_include_oids.head != NULL &&
   19719          16 :             !simple_oid_list_member(&extension_include_oids,
   19720             :                                     curext->dobj.catId.oid))
   19721          12 :             continue;
   19722             : 
   19723             :         /*
   19724             :          * Check if this extension is listed as to exclude in the dump.  If
   19725             :          * yes, any table data associated with it is discarded.
   19726             :          */
   19727         414 :         if (extension_exclude_oids.head != NULL &&
   19728           8 :             simple_oid_list_member(&extension_exclude_oids,
   19729             :                                    curext->dobj.catId.oid))
   19730           4 :             continue;
   19731             : 
   19732         402 :         if (strlen(extconfig) != 0 || strlen(extcondition) != 0)
   19733             :         {
   19734             :             int         j;
   19735             : 
   19736          40 :             if (!parsePGArray(extconfig, &extconfigarray, &nconfigitems))
   19737           0 :                 pg_fatal("could not parse %s array", "extconfig");
   19738          40 :             if (!parsePGArray(extcondition, &extconditionarray, &nconditionitems))
   19739           0 :                 pg_fatal("could not parse %s array", "extcondition");
   19740          40 :             if (nconfigitems != nconditionitems)
   19741           0 :                 pg_fatal("mismatched number of configurations and conditions for extension");
   19742             : 
   19743         120 :             for (j = 0; j < nconfigitems; j++)
   19744             :             {
   19745             :                 TableInfo  *configtbl;
   19746          80 :                 Oid         configtbloid = atooid(extconfigarray[j]);
   19747          80 :                 bool        dumpobj =
   19748          80 :                     curext->dobj.dump & DUMP_COMPONENT_DEFINITION;
   19749             : 
   19750          80 :                 configtbl = findTableByOid(configtbloid);
   19751          80 :                 if (configtbl == NULL)
   19752           0 :                     continue;
   19753             : 
   19754             :                 /*
   19755             :                  * Tables of not-to-be-dumped extensions shouldn't be dumped
   19756             :                  * unless the table or its schema is explicitly included
   19757             :                  */
   19758          80 :                 if (!(curext->dobj.dump & DUMP_COMPONENT_DEFINITION))
   19759             :                 {
   19760             :                     /* check table explicitly requested */
   19761           4 :                     if (table_include_oids.head != NULL &&
   19762           0 :                         simple_oid_list_member(&table_include_oids,
   19763             :                                                configtbloid))
   19764           0 :                         dumpobj = true;
   19765             : 
   19766             :                     /* check table's schema explicitly requested */
   19767           4 :                     if (configtbl->dobj.namespace->dobj.dump &
   19768             :                         DUMP_COMPONENT_DATA)
   19769           4 :                         dumpobj = true;
   19770             :                 }
   19771             : 
   19772             :                 /* check table excluded by an exclusion switch */
   19773          88 :                 if (table_exclude_oids.head != NULL &&
   19774           8 :                     simple_oid_list_member(&table_exclude_oids,
   19775             :                                            configtbloid))
   19776           2 :                     dumpobj = false;
   19777             : 
   19778             :                 /* check schema excluded by an exclusion switch */
   19779          80 :                 if (simple_oid_list_member(&schema_exclude_oids,
   19780          80 :                                            configtbl->dobj.namespace->dobj.catId.oid))
   19781           0 :                     dumpobj = false;
   19782             : 
   19783          80 :                 if (dumpobj)
   19784             :                 {
   19785          78 :                     makeTableDataInfo(dopt, configtbl);
   19786          78 :                     if (configtbl->dataObj != NULL)
   19787             :                     {
   19788          78 :                         if (strlen(extconditionarray[j]) > 0)
   19789           0 :                             configtbl->dataObj->filtercond = pg_strdup(extconditionarray[j]);
   19790             :                     }
   19791             :                 }
   19792             :             }
   19793             :         }
   19794         402 :         if (extconfigarray)
   19795          40 :             free(extconfigarray);
   19796         402 :         if (extconditionarray)
   19797          40 :             free(extconditionarray);
   19798             :     }
   19799             : 
   19800             :     /*
   19801             :      * Now that all the TableDataInfo objects have been created for all the
   19802             :      * extensions, check their FK dependencies and register them to try and
   19803             :      * dump the data out in an order that they can be restored in.
   19804             :      *
   19805             :      * Note that this is not a problem for user tables as their FKs are
   19806             :      * recreated after the data has been loaded.
   19807             :      */
   19808             : 
   19809         364 :     query = createPQExpBuffer();
   19810             : 
   19811         364 :     printfPQExpBuffer(query,
   19812             :                       "SELECT conrelid, confrelid "
   19813             :                       "FROM pg_constraint "
   19814             :                       "JOIN pg_depend ON (objid = confrelid) "
   19815             :                       "WHERE contype = 'f' "
   19816             :                       "AND refclassid = 'pg_extension'::regclass "
   19817             :                       "AND classid = 'pg_class'::regclass;");
   19818             : 
   19819         364 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   19820         364 :     ntups = PQntuples(res);
   19821             : 
   19822         364 :     i_conrelid = PQfnumber(res, "conrelid");
   19823         364 :     i_confrelid = PQfnumber(res, "confrelid");
   19824             : 
   19825             :     /* Now get the dependencies and register them */
   19826         364 :     for (i = 0; i < ntups; i++)
   19827             :     {
   19828             :         Oid         conrelid,
   19829             :                     confrelid;
   19830             :         TableInfo  *reftable,
   19831             :                    *contable;
   19832             : 
   19833           0 :         conrelid = atooid(PQgetvalue(res, i, i_conrelid));
   19834           0 :         confrelid = atooid(PQgetvalue(res, i, i_confrelid));
   19835           0 :         contable = findTableByOid(conrelid);
   19836           0 :         reftable = findTableByOid(confrelid);
   19837             : 
   19838           0 :         if (reftable == NULL ||
   19839           0 :             reftable->dataObj == NULL ||
   19840           0 :             contable == NULL ||
   19841           0 :             contable->dataObj == NULL)
   19842           0 :             continue;
   19843             : 
   19844             :         /*
   19845             :          * Make referencing TABLE_DATA object depend on the referenced table's
   19846             :          * TABLE_DATA object.
   19847             :          */
   19848           0 :         addObjectDependency(&contable->dataObj->dobj,
   19849           0 :                             reftable->dataObj->dobj.dumpId);
   19850             :     }
   19851         364 :     PQclear(res);
   19852         364 :     destroyPQExpBuffer(query);
   19853             : }
   19854             : 
   19855             : /*
   19856             :  * getDependencies --- obtain available dependency data
   19857             :  */
   19858             : static void
   19859         364 : getDependencies(Archive *fout)
   19860             : {
   19861             :     PQExpBuffer query;
   19862             :     PGresult   *res;
   19863             :     int         ntups,
   19864             :                 i;
   19865             :     int         i_classid,
   19866             :                 i_objid,
   19867             :                 i_refclassid,
   19868             :                 i_refobjid,
   19869             :                 i_deptype;
   19870             :     DumpableObject *dobj,
   19871             :                *refdobj;
   19872             : 
   19873         364 :     pg_log_info("reading dependency data");
   19874             : 
   19875         364 :     query = createPQExpBuffer();
   19876             : 
   19877             :     /*
   19878             :      * Messy query to collect the dependency data we need.  Note that we
   19879             :      * ignore the sub-object column, so that dependencies of or on a column
   19880             :      * look the same as dependencies of or on a whole table.
   19881             :      *
   19882             :      * PIN dependencies aren't interesting, and EXTENSION dependencies were
   19883             :      * already processed by getExtensionMembership.
   19884             :      */
   19885         364 :     appendPQExpBufferStr(query, "SELECT "
   19886             :                          "classid, objid, refclassid, refobjid, deptype "
   19887             :                          "FROM pg_depend "
   19888             :                          "WHERE deptype != 'p' AND deptype != 'e'\n");
   19889             : 
   19890             :     /*
   19891             :      * Since we don't treat pg_amop entries as separate DumpableObjects, we
   19892             :      * have to translate their dependencies into dependencies of their parent
   19893             :      * opfamily.  Ignore internal dependencies though, as those will point to
   19894             :      * their parent opclass, which we needn't consider here (and if we did,
   19895             :      * it'd just result in circular dependencies).  Also, "loose" opfamily
   19896             :      * entries will have dependencies on their parent opfamily, which we
   19897             :      * should drop since they'd likewise become useless self-dependencies.
   19898             :      * (But be sure to keep deps on *other* opfamilies; see amopsortfamily.)
   19899             :      */
   19900         364 :     appendPQExpBufferStr(query, "UNION ALL\n"
   19901             :                          "SELECT 'pg_opfamily'::regclass AS classid, amopfamily AS objid, refclassid, refobjid, deptype "
   19902             :                          "FROM pg_depend d, pg_amop o "
   19903             :                          "WHERE deptype NOT IN ('p', 'e', 'i') AND "
   19904             :                          "classid = 'pg_amop'::regclass AND objid = o.oid "
   19905             :                          "AND NOT (refclassid = 'pg_opfamily'::regclass AND amopfamily = refobjid)\n");
   19906             : 
   19907             :     /* Likewise for pg_amproc entries */
   19908         364 :     appendPQExpBufferStr(query, "UNION ALL\n"
   19909             :                          "SELECT 'pg_opfamily'::regclass AS classid, amprocfamily AS objid, refclassid, refobjid, deptype "
   19910             :                          "FROM pg_depend d, pg_amproc p "
   19911             :                          "WHERE deptype NOT IN ('p', 'e', 'i') AND "
   19912             :                          "classid = 'pg_amproc'::regclass AND objid = p.oid "
   19913             :                          "AND NOT (refclassid = 'pg_opfamily'::regclass AND amprocfamily = refobjid)\n");
   19914             : 
   19915             :     /* Sort the output for efficiency below */
   19916         364 :     appendPQExpBufferStr(query, "ORDER BY 1,2");
   19917             : 
   19918         364 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   19919             : 
   19920         364 :     ntups = PQntuples(res);
   19921             : 
   19922         364 :     i_classid = PQfnumber(res, "classid");
   19923         364 :     i_objid = PQfnumber(res, "objid");
   19924         364 :     i_refclassid = PQfnumber(res, "refclassid");
   19925         364 :     i_refobjid = PQfnumber(res, "refobjid");
   19926         364 :     i_deptype = PQfnumber(res, "deptype");
   19927             : 
   19928             :     /*
   19929             :      * Since we ordered the SELECT by referencing ID, we can expect that
   19930             :      * multiple entries for the same object will appear together; this saves
   19931             :      * on searches.
   19932             :      */
   19933         364 :     dobj = NULL;
   19934             : 
   19935      791026 :     for (i = 0; i < ntups; i++)
   19936             :     {
   19937             :         CatalogId   objId;
   19938             :         CatalogId   refobjId;
   19939             :         char        deptype;
   19940             : 
   19941      790662 :         objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
   19942      790662 :         objId.oid = atooid(PQgetvalue(res, i, i_objid));
   19943      790662 :         refobjId.tableoid = atooid(PQgetvalue(res, i, i_refclassid));
   19944      790662 :         refobjId.oid = atooid(PQgetvalue(res, i, i_refobjid));
   19945      790662 :         deptype = *(PQgetvalue(res, i, i_deptype));
   19946             : 
   19947      790662 :         if (dobj == NULL ||
   19948      740192 :             dobj->catId.tableoid != objId.tableoid ||
   19949      736028 :             dobj->catId.oid != objId.oid)
   19950      348854 :             dobj = findObjectByCatalogId(objId);
   19951             : 
   19952             :         /*
   19953             :          * Failure to find objects mentioned in pg_depend is not unexpected,
   19954             :          * since for example we don't collect info about TOAST tables.
   19955             :          */
   19956      790662 :         if (dobj == NULL)
   19957             :         {
   19958             : #ifdef NOT_USED
   19959             :             pg_log_warning("no referencing object %u %u",
   19960             :                            objId.tableoid, objId.oid);
   19961             : #endif
   19962       51774 :             continue;
   19963             :         }
   19964             : 
   19965      740556 :         refdobj = findObjectByCatalogId(refobjId);
   19966             : 
   19967      740556 :         if (refdobj == NULL)
   19968             :         {
   19969             : #ifdef NOT_USED
   19970             :             pg_log_warning("no referenced object %u %u",
   19971             :                            refobjId.tableoid, refobjId.oid);
   19972             : #endif
   19973        1668 :             continue;
   19974             :         }
   19975             : 
   19976             :         /*
   19977             :          * For 'x' dependencies, mark the object for later; we still add the
   19978             :          * normal dependency, for possible ordering purposes.  Currently
   19979             :          * pg_dump_sort.c knows to put extensions ahead of all object types
   19980             :          * that could possibly depend on them, but this is safer.
   19981             :          */
   19982      738888 :         if (deptype == 'x')
   19983          88 :             dobj->depends_on_ext = true;
   19984             : 
   19985             :         /*
   19986             :          * Ordinarily, table rowtypes have implicit dependencies on their
   19987             :          * tables.  However, for a composite type the implicit dependency goes
   19988             :          * the other way in pg_depend; which is the right thing for DROP but
   19989             :          * it doesn't produce the dependency ordering we need. So in that one
   19990             :          * case, we reverse the direction of the dependency.
   19991             :          */
   19992      738888 :         if (deptype == 'i' &&
   19993      208208 :             dobj->objType == DO_TABLE &&
   19994        2524 :             refdobj->objType == DO_TYPE)
   19995         370 :             addObjectDependency(refdobj, dobj->dumpId);
   19996             :         else
   19997             :             /* normal case */
   19998      738518 :             addObjectDependency(dobj, refdobj->dumpId);
   19999             :     }
   20000             : 
   20001         364 :     PQclear(res);
   20002             : 
   20003         364 :     destroyPQExpBuffer(query);
   20004         364 : }
   20005             : 
   20006             : 
   20007             : /*
   20008             :  * createBoundaryObjects - create dummy DumpableObjects to represent
   20009             :  * dump section boundaries.
   20010             :  */
   20011             : static DumpableObject *
   20012         364 : createBoundaryObjects(void)
   20013             : {
   20014             :     DumpableObject *dobjs;
   20015             : 
   20016         364 :     dobjs = (DumpableObject *) pg_malloc(2 * sizeof(DumpableObject));
   20017             : 
   20018         364 :     dobjs[0].objType = DO_PRE_DATA_BOUNDARY;
   20019         364 :     dobjs[0].catId = nilCatalogId;
   20020         364 :     AssignDumpId(dobjs + 0);
   20021         364 :     dobjs[0].name = pg_strdup("PRE-DATA BOUNDARY");
   20022             : 
   20023         364 :     dobjs[1].objType = DO_POST_DATA_BOUNDARY;
   20024         364 :     dobjs[1].catId = nilCatalogId;
   20025         364 :     AssignDumpId(dobjs + 1);
   20026         364 :     dobjs[1].name = pg_strdup("POST-DATA BOUNDARY");
   20027             : 
   20028         364 :     return dobjs;
   20029             : }
   20030             : 
   20031             : /*
   20032             :  * addBoundaryDependencies - add dependencies as needed to enforce the dump
   20033             :  * section boundaries.
   20034             :  */
   20035             : static void
   20036         364 : addBoundaryDependencies(DumpableObject **dobjs, int numObjs,
   20037             :                         DumpableObject *boundaryObjs)
   20038             : {
   20039         364 :     DumpableObject *preDataBound = boundaryObjs + 0;
   20040         364 :     DumpableObject *postDataBound = boundaryObjs + 1;
   20041             :     int         i;
   20042             : 
   20043     1355506 :     for (i = 0; i < numObjs; i++)
   20044             :     {
   20045     1355142 :         DumpableObject *dobj = dobjs[i];
   20046             : 
   20047             :         /*
   20048             :          * The classification of object types here must match the SECTION_xxx
   20049             :          * values assigned during subsequent ArchiveEntry calls!
   20050             :          */
   20051     1355142 :         switch (dobj->objType)
   20052             :         {
   20053     1264126 :             case DO_NAMESPACE:
   20054             :             case DO_EXTENSION:
   20055             :             case DO_TYPE:
   20056             :             case DO_SHELL_TYPE:
   20057             :             case DO_FUNC:
   20058             :             case DO_AGG:
   20059             :             case DO_OPERATOR:
   20060             :             case DO_ACCESS_METHOD:
   20061             :             case DO_OPCLASS:
   20062             :             case DO_OPFAMILY:
   20063             :             case DO_COLLATION:
   20064             :             case DO_CONVERSION:
   20065             :             case DO_TABLE:
   20066             :             case DO_TABLE_ATTACH:
   20067             :             case DO_ATTRDEF:
   20068             :             case DO_PROCLANG:
   20069             :             case DO_CAST:
   20070             :             case DO_DUMMY_TYPE:
   20071             :             case DO_TSPARSER:
   20072             :             case DO_TSDICT:
   20073             :             case DO_TSTEMPLATE:
   20074             :             case DO_TSCONFIG:
   20075             :             case DO_FDW:
   20076             :             case DO_FOREIGN_SERVER:
   20077             :             case DO_TRANSFORM:
   20078             :                 /* Pre-data objects: must come before the pre-data boundary */
   20079     1264126 :                 addObjectDependency(preDataBound, dobj->dumpId);
   20080     1264126 :                 break;
   20081        9884 :             case DO_TABLE_DATA:
   20082             :             case DO_SEQUENCE_SET:
   20083             :             case DO_LARGE_OBJECT:
   20084             :             case DO_LARGE_OBJECT_DATA:
   20085             :                 /* Data objects: must come between the boundaries */
   20086        9884 :                 addObjectDependency(dobj, preDataBound->dumpId);
   20087        9884 :                 addObjectDependency(postDataBound, dobj->dumpId);
   20088        9884 :                 break;
   20089       11736 :             case DO_INDEX:
   20090             :             case DO_INDEX_ATTACH:
   20091             :             case DO_STATSEXT:
   20092             :             case DO_REFRESH_MATVIEW:
   20093             :             case DO_TRIGGER:
   20094             :             case DO_EVENT_TRIGGER:
   20095             :             case DO_DEFAULT_ACL:
   20096             :             case DO_POLICY:
   20097             :             case DO_PUBLICATION:
   20098             :             case DO_PUBLICATION_REL:
   20099             :             case DO_PUBLICATION_TABLE_IN_SCHEMA:
   20100             :             case DO_SUBSCRIPTION:
   20101             :             case DO_SUBSCRIPTION_REL:
   20102             :                 /* Post-data objects: must come after the post-data boundary */
   20103       11736 :                 addObjectDependency(dobj, postDataBound->dumpId);
   20104       11736 :                 break;
   20105       56300 :             case DO_RULE:
   20106             :                 /* Rules are post-data, but only if dumped separately */
   20107       56300 :                 if (((RuleInfo *) dobj)->separate)
   20108        1274 :                     addObjectDependency(dobj, postDataBound->dumpId);
   20109       56300 :                 break;
   20110        5216 :             case DO_CONSTRAINT:
   20111             :             case DO_FK_CONSTRAINT:
   20112             :                 /* Constraints are post-data, but only if dumped separately */
   20113        5216 :                 if (((ConstraintInfo *) dobj)->separate)
   20114        3708 :                     addObjectDependency(dobj, postDataBound->dumpId);
   20115        5216 :                 break;
   20116         364 :             case DO_PRE_DATA_BOUNDARY:
   20117             :                 /* nothing to do */
   20118         364 :                 break;
   20119         364 :             case DO_POST_DATA_BOUNDARY:
   20120             :                 /* must come after the pre-data boundary */
   20121         364 :                 addObjectDependency(dobj, preDataBound->dumpId);
   20122         364 :                 break;
   20123        7152 :             case DO_REL_STATS:
   20124             :                 /* stats section varies by parent object type, DATA or POST */
   20125        7152 :                 if (((RelStatsInfo *) dobj)->section == SECTION_DATA)
   20126             :                 {
   20127        4586 :                     addObjectDependency(dobj, preDataBound->dumpId);
   20128        4586 :                     addObjectDependency(postDataBound, dobj->dumpId);
   20129             :                 }
   20130             :                 else
   20131        2566 :                     addObjectDependency(dobj, postDataBound->dumpId);
   20132        7152 :                 break;
   20133             :         }
   20134             :     }
   20135         364 : }
   20136             : 
   20137             : 
   20138             : /*
   20139             :  * BuildArchiveDependencies - create dependency data for archive TOC entries
   20140             :  *
   20141             :  * The raw dependency data obtained by getDependencies() is not terribly
   20142             :  * useful in an archive dump, because in many cases there are dependency
   20143             :  * chains linking through objects that don't appear explicitly in the dump.
   20144             :  * For example, a view will depend on its _RETURN rule while the _RETURN rule
   20145             :  * will depend on other objects --- but the rule will not appear as a separate
   20146             :  * object in the dump.  We need to adjust the view's dependencies to include
   20147             :  * whatever the rule depends on that is included in the dump.
   20148             :  *
   20149             :  * Just to make things more complicated, there are also "special" dependencies
   20150             :  * such as the dependency of a TABLE DATA item on its TABLE, which we must
   20151             :  * not rearrange because pg_restore knows that TABLE DATA only depends on
   20152             :  * its table.  In these cases we must leave the dependencies strictly as-is
   20153             :  * even if they refer to not-to-be-dumped objects.
   20154             :  *
   20155             :  * To handle this, the convention is that "special" dependencies are created
   20156             :  * during ArchiveEntry calls, and an archive TOC item that has any such
   20157             :  * entries will not be touched here.  Otherwise, we recursively search the
   20158             :  * DumpableObject data structures to build the correct dependencies for each
   20159             :  * archive TOC item.
   20160             :  */
   20161             : static void
   20162         106 : BuildArchiveDependencies(Archive *fout)
   20163             : {
   20164         106 :     ArchiveHandle *AH = (ArchiveHandle *) fout;
   20165             :     TocEntry   *te;
   20166             : 
   20167             :     /* Scan all TOC entries in the archive */
   20168       14520 :     for (te = AH->toc->next; te != AH->toc; te = te->next)
   20169             :     {
   20170             :         DumpableObject *dobj;
   20171             :         DumpId     *dependencies;
   20172             :         int         nDeps;
   20173             :         int         allocDeps;
   20174             : 
   20175             :         /* No need to process entries that will not be dumped */
   20176       14414 :         if (te->reqs == 0)
   20177        7082 :             continue;
   20178             :         /* Ignore entries that already have "special" dependencies */
   20179       14408 :         if (te->nDeps > 0)
   20180        6274 :             continue;
   20181             :         /* Otherwise, look up the item's original DumpableObject, if any */
   20182        8134 :         dobj = findObjectByDumpId(te->dumpId);
   20183        8134 :         if (dobj == NULL)
   20184         582 :             continue;
   20185             :         /* No work if it has no dependencies */
   20186        7552 :         if (dobj->nDeps <= 0)
   20187         220 :             continue;
   20188             :         /* Set up work array */
   20189        7332 :         allocDeps = 64;
   20190        7332 :         dependencies = (DumpId *) pg_malloc(allocDeps * sizeof(DumpId));
   20191        7332 :         nDeps = 0;
   20192             :         /* Recursively find all dumpable dependencies */
   20193        7332 :         findDumpableDependencies(AH, dobj,
   20194             :                                  &dependencies, &nDeps, &allocDeps);
   20195             :         /* And save 'em ... */
   20196        7332 :         if (nDeps > 0)
   20197             :         {
   20198        5640 :             dependencies = (DumpId *) pg_realloc(dependencies,
   20199             :                                                  nDeps * sizeof(DumpId));
   20200        5640 :             te->dependencies = dependencies;
   20201        5640 :             te->nDeps = nDeps;
   20202             :         }
   20203             :         else
   20204        1692 :             free(dependencies);
   20205             :     }
   20206         106 : }
   20207             : 
   20208             : /* Recursive search subroutine for BuildArchiveDependencies */
   20209             : static void
   20210       17574 : findDumpableDependencies(ArchiveHandle *AH, const DumpableObject *dobj,
   20211             :                          DumpId **dependencies, int *nDeps, int *allocDeps)
   20212             : {
   20213             :     int         i;
   20214             : 
   20215             :     /*
   20216             :      * Ignore section boundary objects: if we search through them, we'll
   20217             :      * report lots of bogus dependencies.
   20218             :      */
   20219       17574 :     if (dobj->objType == DO_PRE_DATA_BOUNDARY ||
   20220       17542 :         dobj->objType == DO_POST_DATA_BOUNDARY)
   20221        3060 :         return;
   20222             : 
   20223       36632 :     for (i = 0; i < dobj->nDeps; i++)
   20224             :     {
   20225       22118 :         DumpId      depid = dobj->dependencies[i];
   20226             : 
   20227       22118 :         if (TocIDRequired(AH, depid) != 0)
   20228             :         {
   20229             :             /* Object will be dumped, so just reference it as a dependency */
   20230       11876 :             if (*nDeps >= *allocDeps)
   20231             :             {
   20232           0 :                 *allocDeps *= 2;
   20233           0 :                 *dependencies = (DumpId *) pg_realloc(*dependencies,
   20234           0 :                                                       *allocDeps * sizeof(DumpId));
   20235             :             }
   20236       11876 :             (*dependencies)[*nDeps] = depid;
   20237       11876 :             (*nDeps)++;
   20238             :         }
   20239             :         else
   20240             :         {
   20241             :             /*
   20242             :              * Object will not be dumped, so recursively consider its deps. We
   20243             :              * rely on the assumption that sortDumpableObjects already broke
   20244             :              * any dependency loops, else we might recurse infinitely.
   20245             :              */
   20246       10242 :             DumpableObject *otherdobj = findObjectByDumpId(depid);
   20247             : 
   20248       10242 :             if (otherdobj)
   20249       10242 :                 findDumpableDependencies(AH, otherdobj,
   20250             :                                          dependencies, nDeps, allocDeps);
   20251             :         }
   20252             :     }
   20253             : }
   20254             : 
   20255             : 
   20256             : /*
   20257             :  * getFormattedTypeName - retrieve a nicely-formatted type name for the
   20258             :  * given type OID.
   20259             :  *
   20260             :  * This does not guarantee to schema-qualify the output, so it should not
   20261             :  * be used to create the target object name for CREATE or ALTER commands.
   20262             :  *
   20263             :  * Note that the result is cached and must not be freed by the caller.
   20264             :  */
   20265             : static const char *
   20266        4672 : getFormattedTypeName(Archive *fout, Oid oid, OidOptions opts)
   20267             : {
   20268             :     TypeInfo   *typeInfo;
   20269             :     char       *result;
   20270             :     PQExpBuffer query;
   20271             :     PGresult   *res;
   20272             : 
   20273        4672 :     if (oid == 0)
   20274             :     {
   20275           0 :         if ((opts & zeroAsStar) != 0)
   20276           0 :             return "*";
   20277           0 :         else if ((opts & zeroAsNone) != 0)
   20278           0 :             return "NONE";
   20279             :     }
   20280             : 
   20281             :     /* see if we have the result cached in the type's TypeInfo record */
   20282        4672 :     typeInfo = findTypeByOid(oid);
   20283        4672 :     if (typeInfo && typeInfo->ftypname)
   20284        3696 :         return typeInfo->ftypname;
   20285             : 
   20286         976 :     query = createPQExpBuffer();
   20287         976 :     appendPQExpBuffer(query, "SELECT pg_catalog.format_type('%u'::pg_catalog.oid, NULL)",
   20288             :                       oid);
   20289             : 
   20290         976 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   20291             : 
   20292             :     /* result of format_type is already quoted */
   20293         976 :     result = pg_strdup(PQgetvalue(res, 0, 0));
   20294             : 
   20295         976 :     PQclear(res);
   20296         976 :     destroyPQExpBuffer(query);
   20297             : 
   20298             :     /*
   20299             :      * Cache the result for re-use in later requests, if possible.  If we
   20300             :      * don't have a TypeInfo for the type, the string will be leaked once the
   20301             :      * caller is done with it ... but that case really should not happen, so
   20302             :      * leaking if it does seems acceptable.
   20303             :      */
   20304         976 :     if (typeInfo)
   20305         976 :         typeInfo->ftypname = result;
   20306             : 
   20307         976 :     return result;
   20308             : }
   20309             : 
   20310             : /*
   20311             :  * Return a column list clause for the given relation.
   20312             :  *
   20313             :  * Special case: if there are no undropped columns in the relation, return
   20314             :  * "", not an invalid "()" column list.
   20315             :  */
   20316             : static const char *
   20317       17020 : fmtCopyColumnList(const TableInfo *ti, PQExpBuffer buffer)
   20318             : {
   20319       17020 :     int         numatts = ti->numatts;
   20320       17020 :     char      **attnames = ti->attnames;
   20321       17020 :     bool       *attisdropped = ti->attisdropped;
   20322       17020 :     char       *attgenerated = ti->attgenerated;
   20323             :     bool        needComma;
   20324             :     int         i;
   20325             : 
   20326       17020 :     appendPQExpBufferChar(buffer, '(');
   20327       17020 :     needComma = false;
   20328       81696 :     for (i = 0; i < numatts; i++)
   20329             :     {
   20330       64676 :         if (attisdropped[i])
   20331        1208 :             continue;
   20332       63468 :         if (attgenerated[i])
   20333        2304 :             continue;
   20334       61164 :         if (needComma)
   20335       44628 :             appendPQExpBufferStr(buffer, ", ");
   20336       61164 :         appendPQExpBufferStr(buffer, fmtId(attnames[i]));
   20337       61164 :         needComma = true;
   20338             :     }
   20339             : 
   20340       17020 :     if (!needComma)
   20341         484 :         return "";                /* no undropped columns */
   20342             : 
   20343       16536 :     appendPQExpBufferChar(buffer, ')');
   20344       16536 :     return buffer->data;
   20345             : }
   20346             : 
   20347             : /*
   20348             :  * Check if a reloptions array is nonempty.
   20349             :  */
   20350             : static bool
   20351       27856 : nonemptyReloptions(const char *reloptions)
   20352             : {
   20353             :     /* Don't want to print it if it's just "{}" */
   20354       27856 :     return (reloptions != NULL && strlen(reloptions) > 2);
   20355             : }
   20356             : 
   20357             : /*
   20358             :  * Format a reloptions array and append it to the given buffer.
   20359             :  *
   20360             :  * "prefix" is prepended to the option names; typically it's "" or "toast.".
   20361             :  */
   20362             : static void
   20363         428 : appendReloptionsArrayAH(PQExpBuffer buffer, const char *reloptions,
   20364             :                         const char *prefix, Archive *fout)
   20365             : {
   20366             :     bool        res;
   20367             : 
   20368         428 :     res = appendReloptionsArray(buffer, reloptions, prefix, fout->encoding,
   20369         428 :                                 fout->std_strings);
   20370         428 :     if (!res)
   20371           0 :         pg_log_warning("could not parse %s array", "reloptions");
   20372         428 : }
   20373             : 
   20374             : /*
   20375             :  * read_dump_filters - retrieve object identifier patterns from file
   20376             :  *
   20377             :  * Parse the specified filter file for include and exclude patterns, and add
   20378             :  * them to the relevant lists.  If the filename is "-" then filters will be
   20379             :  * read from STDIN rather than a file.
   20380             :  */
   20381             : static void
   20382          52 : read_dump_filters(const char *filename, DumpOptions *dopt)
   20383             : {
   20384             :     FilterStateData fstate;
   20385             :     char       *objname;
   20386             :     FilterCommandType comtype;
   20387             :     FilterObjectType objtype;
   20388             : 
   20389          52 :     filter_init(&fstate, filename, exit_nicely);
   20390             : 
   20391         168 :     while (filter_read_item(&fstate, &objname, &comtype, &objtype))
   20392             :     {
   20393          66 :         if (comtype == FILTER_COMMAND_TYPE_INCLUDE)
   20394             :         {
   20395          34 :             switch (objtype)
   20396             :             {
   20397           0 :                 case FILTER_OBJECT_TYPE_NONE:
   20398           0 :                     break;
   20399           0 :                 case FILTER_OBJECT_TYPE_DATABASE:
   20400             :                 case FILTER_OBJECT_TYPE_FUNCTION:
   20401             :                 case FILTER_OBJECT_TYPE_INDEX:
   20402             :                 case FILTER_OBJECT_TYPE_TABLE_DATA:
   20403             :                 case FILTER_OBJECT_TYPE_TABLE_DATA_AND_CHILDREN:
   20404             :                 case FILTER_OBJECT_TYPE_TRIGGER:
   20405           0 :                     pg_log_filter_error(&fstate, _("%s filter for \"%s\" is not allowed"),
   20406             :                                         "include",
   20407             :                                         filter_object_type_name(objtype));
   20408           0 :                     exit_nicely(1);
   20409             :                     break;      /* unreachable */
   20410             : 
   20411           2 :                 case FILTER_OBJECT_TYPE_EXTENSION:
   20412           2 :                     simple_string_list_append(&extension_include_patterns, objname);
   20413           2 :                     break;
   20414           2 :                 case FILTER_OBJECT_TYPE_FOREIGN_DATA:
   20415           2 :                     simple_string_list_append(&foreign_servers_include_patterns, objname);
   20416           2 :                     break;
   20417           2 :                 case FILTER_OBJECT_TYPE_SCHEMA:
   20418           2 :                     simple_string_list_append(&schema_include_patterns, objname);
   20419           2 :                     dopt->include_everything = false;
   20420           2 :                     break;
   20421          26 :                 case FILTER_OBJECT_TYPE_TABLE:
   20422          26 :                     simple_string_list_append(&table_include_patterns, objname);
   20423          26 :                     dopt->include_everything = false;
   20424          26 :                     break;
   20425           2 :                 case FILTER_OBJECT_TYPE_TABLE_AND_CHILDREN:
   20426           2 :                     simple_string_list_append(&table_include_patterns_and_children,
   20427             :                                               objname);
   20428           2 :                     dopt->include_everything = false;
   20429           2 :                     break;
   20430             :             }
   20431             :         }
   20432          32 :         else if (comtype == FILTER_COMMAND_TYPE_EXCLUDE)
   20433             :         {
   20434          18 :             switch (objtype)
   20435             :             {
   20436           0 :                 case FILTER_OBJECT_TYPE_NONE:
   20437           0 :                     break;
   20438           2 :                 case FILTER_OBJECT_TYPE_DATABASE:
   20439             :                 case FILTER_OBJECT_TYPE_FUNCTION:
   20440             :                 case FILTER_OBJECT_TYPE_INDEX:
   20441             :                 case FILTER_OBJECT_TYPE_TRIGGER:
   20442             :                 case FILTER_OBJECT_TYPE_FOREIGN_DATA:
   20443           2 :                     pg_log_filter_error(&fstate, _("%s filter for \"%s\" is not allowed"),
   20444             :                                         "exclude",
   20445             :                                         filter_object_type_name(objtype));
   20446           2 :                     exit_nicely(1);
   20447             :                     break;
   20448             : 
   20449           2 :                 case FILTER_OBJECT_TYPE_EXTENSION:
   20450           2 :                     simple_string_list_append(&extension_exclude_patterns, objname);
   20451           2 :                     break;
   20452           2 :                 case FILTER_OBJECT_TYPE_TABLE_DATA:
   20453           2 :                     simple_string_list_append(&tabledata_exclude_patterns,
   20454             :                                               objname);
   20455           2 :                     break;
   20456           2 :                 case FILTER_OBJECT_TYPE_TABLE_DATA_AND_CHILDREN:
   20457           2 :                     simple_string_list_append(&tabledata_exclude_patterns_and_children,
   20458             :                                               objname);
   20459           2 :                     break;
   20460           4 :                 case FILTER_OBJECT_TYPE_SCHEMA:
   20461           4 :                     simple_string_list_append(&schema_exclude_patterns, objname);
   20462           4 :                     break;
   20463           4 :                 case FILTER_OBJECT_TYPE_TABLE:
   20464           4 :                     simple_string_list_append(&table_exclude_patterns, objname);
   20465           4 :                     break;
   20466           2 :                 case FILTER_OBJECT_TYPE_TABLE_AND_CHILDREN:
   20467           2 :                     simple_string_list_append(&table_exclude_patterns_and_children,
   20468             :                                               objname);
   20469           2 :                     break;
   20470             :             }
   20471             :         }
   20472             :         else
   20473             :         {
   20474             :             Assert(comtype == FILTER_COMMAND_TYPE_NONE);
   20475             :             Assert(objtype == FILTER_OBJECT_TYPE_NONE);
   20476             :         }
   20477             : 
   20478          64 :         if (objname)
   20479          50 :             free(objname);
   20480             :     }
   20481             : 
   20482          44 :     filter_free(&fstate);
   20483          44 : }

Generated by: LCOV version 1.16