LCOV - code coverage report
Current view: top level - src/bin/pg_dump - pg_dump.c (source / functions) Hit Total Coverage
Test: PostgreSQL 19devel Lines: 7470 8289 90.1 %
Date: 2025-07-30 02:18:37 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         698 : main(int argc, char **argv)
     422             : {
     423             :     int         c;
     424         698 :     const char *filename = NULL;
     425         698 :     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         698 :     bool        g_verbose = false;
     436         698 :     const char *dumpencoding = NULL;
     437         698 :     const char *dumpsnapshot = NULL;
     438         698 :     char       *use_role = NULL;
     439         698 :     int         numWorkers = 1;
     440         698 :     int         plainText = 0;
     441         698 :     ArchiveFormat archiveFormat = archUnknown;
     442             :     ArchiveMode archiveMode;
     443         698 :     pg_compress_specification compression_spec = {0};
     444         698 :     char       *compression_detail = NULL;
     445         698 :     char       *compression_algorithm_str = "none";
     446         698 :     char       *error_detail = NULL;
     447         698 :     bool        user_compression_defined = false;
     448         698 :     DataDirSyncMethod sync_method = DATA_DIR_SYNC_METHOD_FSYNC;
     449         698 :     bool        data_only = false;
     450         698 :     bool        schema_only = false;
     451         698 :     bool        statistics_only = false;
     452         698 :     bool        with_data = false;
     453         698 :     bool        with_schema = false;
     454         698 :     bool        with_statistics = false;
     455         698 :     bool        no_data = false;
     456         698 :     bool        no_schema = false;
     457         698 :     bool        no_statistics = false;
     458             : 
     459             :     static DumpOptions dopt;
     460             : 
     461             :     static struct option long_options[] = {
     462             :         {"data-only", no_argument, NULL, 'a'},
     463             :         {"blobs", no_argument, NULL, 'b'},
     464             :         {"large-objects", no_argument, NULL, 'b'},
     465             :         {"no-blobs", no_argument, NULL, 'B'},
     466             :         {"no-large-objects", no_argument, NULL, 'B'},
     467             :         {"clean", no_argument, NULL, 'c'},
     468             :         {"create", no_argument, NULL, 'C'},
     469             :         {"dbname", required_argument, NULL, 'd'},
     470             :         {"extension", required_argument, NULL, 'e'},
     471             :         {"file", required_argument, NULL, 'f'},
     472             :         {"format", required_argument, NULL, 'F'},
     473             :         {"host", required_argument, NULL, 'h'},
     474             :         {"jobs", 1, NULL, 'j'},
     475             :         {"no-reconnect", no_argument, NULL, 'R'},
     476             :         {"no-owner", no_argument, NULL, 'O'},
     477             :         {"port", required_argument, NULL, 'p'},
     478             :         {"schema", required_argument, NULL, 'n'},
     479             :         {"exclude-schema", required_argument, NULL, 'N'},
     480             :         {"schema-only", no_argument, NULL, 's'},
     481             :         {"superuser", required_argument, NULL, 'S'},
     482             :         {"table", required_argument, NULL, 't'},
     483             :         {"exclude-table", required_argument, NULL, 'T'},
     484             :         {"no-password", no_argument, NULL, 'w'},
     485             :         {"password", no_argument, NULL, 'W'},
     486             :         {"username", required_argument, NULL, 'U'},
     487             :         {"verbose", no_argument, NULL, 'v'},
     488             :         {"no-privileges", no_argument, NULL, 'x'},
     489             :         {"no-acl", no_argument, NULL, 'x'},
     490             :         {"compress", required_argument, NULL, 'Z'},
     491             :         {"encoding", required_argument, NULL, 'E'},
     492             :         {"help", no_argument, NULL, '?'},
     493             :         {"version", no_argument, NULL, 'V'},
     494             : 
     495             :         /*
     496             :          * the following options don't have an equivalent short option letter
     497             :          */
     498             :         {"attribute-inserts", no_argument, &dopt.column_inserts, 1},
     499             :         {"binary-upgrade", no_argument, &dopt.binary_upgrade, 1},
     500             :         {"column-inserts", no_argument, &dopt.column_inserts, 1},
     501             :         {"disable-dollar-quoting", no_argument, &dopt.disable_dollar_quoting, 1},
     502             :         {"disable-triggers", no_argument, &dopt.disable_triggers, 1},
     503             :         {"enable-row-security", no_argument, &dopt.enable_row_security, 1},
     504             :         {"exclude-table-data", required_argument, NULL, 4},
     505             :         {"extra-float-digits", required_argument, NULL, 8},
     506             :         {"if-exists", no_argument, &dopt.if_exists, 1},
     507             :         {"inserts", no_argument, NULL, 9},
     508             :         {"lock-wait-timeout", required_argument, NULL, 2},
     509             :         {"no-table-access-method", no_argument, &dopt.outputNoTableAm, 1},
     510             :         {"no-tablespaces", no_argument, &dopt.outputNoTablespaces, 1},
     511             :         {"quote-all-identifiers", no_argument, &quote_all_identifiers, 1},
     512             :         {"load-via-partition-root", no_argument, &dopt.load_via_partition_root, 1},
     513             :         {"role", required_argument, NULL, 3},
     514             :         {"section", required_argument, NULL, 5},
     515             :         {"serializable-deferrable", no_argument, &dopt.serializable_deferrable, 1},
     516             :         {"snapshot", required_argument, NULL, 6},
     517             :         {"statistics-only", no_argument, NULL, 18},
     518             :         {"strict-names", no_argument, &strict_names, 1},
     519             :         {"use-set-session-authorization", no_argument, &dopt.use_setsessauth, 1},
     520             :         {"no-comments", no_argument, &dopt.no_comments, 1},
     521             :         {"no-data", no_argument, NULL, 19},
     522             :         {"no-policies", no_argument, &dopt.no_policies, 1},
     523             :         {"no-publications", no_argument, &dopt.no_publications, 1},
     524             :         {"no-schema", no_argument, NULL, 20},
     525             :         {"no-security-labels", no_argument, &dopt.no_security_labels, 1},
     526             :         {"no-statistics", no_argument, NULL, 21},
     527             :         {"no-subscriptions", no_argument, &dopt.no_subscriptions, 1},
     528             :         {"no-toast-compression", no_argument, &dopt.no_toast_compression, 1},
     529             :         {"no-unlogged-table-data", no_argument, &dopt.no_unlogged_table_data, 1},
     530             :         {"no-sync", no_argument, NULL, 7},
     531             :         {"with-data", no_argument, NULL, 22},
     532             :         {"with-schema", no_argument, NULL, 23},
     533             :         {"with-statistics", no_argument, NULL, 24},
     534             :         {"on-conflict-do-nothing", no_argument, &dopt.do_nothing, 1},
     535             :         {"rows-per-insert", required_argument, NULL, 10},
     536             :         {"include-foreign-data", required_argument, NULL, 11},
     537             :         {"table-and-children", required_argument, NULL, 12},
     538             :         {"exclude-table-and-children", required_argument, NULL, 13},
     539             :         {"exclude-table-data-and-children", required_argument, NULL, 14},
     540             :         {"sync-method", required_argument, NULL, 15},
     541             :         {"filter", required_argument, NULL, 16},
     542             :         {"exclude-extension", required_argument, NULL, 17},
     543             :         {"sequence-data", no_argument, &dopt.sequence_data, 1},
     544             : 
     545             :         {NULL, 0, NULL, 0}
     546             :     };
     547             : 
     548         698 :     pg_logging_init(argv[0]);
     549         698 :     pg_logging_set_level(PG_LOG_WARNING);
     550         698 :     set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_dump"));
     551             : 
     552             :     /*
     553             :      * Initialize what we need for parallel execution, especially for thread
     554             :      * support on Windows.
     555             :      */
     556         698 :     init_parallel_dump_utils();
     557             : 
     558         698 :     progname = get_progname(argv[0]);
     559             : 
     560         698 :     if (argc > 1)
     561             :     {
     562         698 :         if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
     563             :         {
     564           2 :             help(progname);
     565           2 :             exit_nicely(0);
     566             :         }
     567         696 :         if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
     568             :         {
     569         140 :             puts("pg_dump (PostgreSQL) " PG_VERSION);
     570         140 :             exit_nicely(0);
     571             :         }
     572             :     }
     573             : 
     574         556 :     InitDumpOptions(&dopt);
     575             : 
     576        2780 :     while ((c = getopt_long(argc, argv, "abBcCd:e:E:f:F:h:j:n:N:Op:RsS:t:T:U:vwWxXZ:",
     577        2780 :                             long_options, &optindex)) != -1)
     578             :     {
     579        2240 :         switch (c)
     580             :         {
     581          18 :             case 'a':           /* Dump data only */
     582          18 :                 data_only = true;
     583          18 :                 break;
     584             : 
     585           2 :             case 'b':           /* Dump LOs */
     586           2 :                 dopt.outputLOs = true;
     587           2 :                 break;
     588             : 
     589           4 :             case 'B':           /* Don't dump LOs */
     590           4 :                 dopt.dontOutputLOs = true;
     591           4 :                 break;
     592             : 
     593          12 :             case 'c':           /* clean (i.e., drop) schema prior to create */
     594          12 :                 dopt.outputClean = 1;
     595          12 :                 break;
     596             : 
     597         140 :             case 'C':           /* Create DB */
     598         140 :                 dopt.outputCreateDB = 1;
     599         140 :                 break;
     600             : 
     601          16 :             case 'd':           /* database name */
     602          16 :                 dopt.cparams.dbname = pg_strdup(optarg);
     603          16 :                 break;
     604             : 
     605           8 :             case 'e':           /* include extension(s) */
     606           8 :                 simple_string_list_append(&extension_include_patterns, optarg);
     607           8 :                 dopt.include_everything = false;
     608           8 :                 break;
     609             : 
     610           4 :             case 'E':           /* Dump encoding */
     611           4 :                 dumpencoding = pg_strdup(optarg);
     612           4 :                 break;
     613             : 
     614         466 :             case 'f':
     615         466 :                 filename = pg_strdup(optarg);
     616         466 :                 break;
     617             : 
     618         314 :             case 'F':
     619         314 :                 format = pg_strdup(optarg);
     620         314 :                 break;
     621             : 
     622          58 :             case 'h':           /* server host */
     623          58 :                 dopt.cparams.pghost = pg_strdup(optarg);
     624          58 :                 break;
     625             : 
     626          24 :             case 'j':           /* number of dump jobs */
     627          24 :                 if (!option_parse_int(optarg, "-j/--jobs", 1,
     628             :                                       PG_MAX_JOBS,
     629             :                                       &numWorkers))
     630           2 :                     exit_nicely(1);
     631          22 :                 break;
     632             : 
     633          34 :             case 'n':           /* include schema(s) */
     634          34 :                 simple_string_list_append(&schema_include_patterns, optarg);
     635          34 :                 dopt.include_everything = false;
     636          34 :                 break;
     637             : 
     638           2 :             case 'N':           /* exclude schema(s) */
     639           2 :                 simple_string_list_append(&schema_exclude_patterns, optarg);
     640           2 :                 break;
     641             : 
     642           4 :             case 'O':           /* Don't reconnect to match owner */
     643           4 :                 dopt.outputNoOwner = 1;
     644           4 :                 break;
     645             : 
     646         134 :             case 'p':           /* server port */
     647         134 :                 dopt.cparams.pgport = pg_strdup(optarg);
     648         134 :                 break;
     649             : 
     650           4 :             case 'R':
     651             :                 /* no-op, still accepted for backwards compatibility */
     652           4 :                 break;
     653             : 
     654          14 :             case 's':           /* dump schema only */
     655          14 :                 schema_only = true;
     656          14 :                 break;
     657             : 
     658           2 :             case 'S':           /* Username for superuser in plain text output */
     659           2 :                 dopt.outputSuperuser = pg_strdup(optarg);
     660           2 :                 break;
     661             : 
     662          16 :             case 't':           /* include table(s) */
     663          16 :                 simple_string_list_append(&table_include_patterns, optarg);
     664          16 :                 dopt.include_everything = false;
     665          16 :                 break;
     666             : 
     667           8 :             case 'T':           /* exclude table(s) */
     668           8 :                 simple_string_list_append(&table_exclude_patterns, optarg);
     669           8 :                 break;
     670             : 
     671          62 :             case 'U':
     672          62 :                 dopt.cparams.username = pg_strdup(optarg);
     673          62 :                 break;
     674             : 
     675          12 :             case 'v':           /* verbose */
     676          12 :                 g_verbose = true;
     677          12 :                 pg_logging_increase_verbosity();
     678          12 :                 break;
     679             : 
     680           2 :             case 'w':
     681           2 :                 dopt.cparams.promptPassword = TRI_NO;
     682           2 :                 break;
     683             : 
     684           0 :             case 'W':
     685           0 :                 dopt.cparams.promptPassword = TRI_YES;
     686           0 :                 break;
     687             : 
     688           4 :             case 'x':           /* skip ACL dump */
     689           4 :                 dopt.aclsSkip = true;
     690           4 :                 break;
     691             : 
     692          24 :             case 'Z':           /* Compression */
     693          24 :                 parse_compress_options(optarg, &compression_algorithm_str,
     694             :                                        &compression_detail);
     695          24 :                 user_compression_defined = true;
     696          24 :                 break;
     697             : 
     698         226 :             case 0:
     699             :                 /* This covers the long options. */
     700         226 :                 break;
     701             : 
     702           4 :             case 2:             /* lock-wait-timeout */
     703           4 :                 dopt.lockWaitTimeout = pg_strdup(optarg);
     704           4 :                 break;
     705             : 
     706           6 :             case 3:             /* SET ROLE */
     707           6 :                 use_role = pg_strdup(optarg);
     708           6 :                 break;
     709             : 
     710           2 :             case 4:             /* exclude table(s) data */
     711           2 :                 simple_string_list_append(&tabledata_exclude_patterns, optarg);
     712           2 :                 break;
     713             : 
     714          12 :             case 5:             /* section */
     715          12 :                 set_dump_section(optarg, &dopt.dumpSections);
     716          12 :                 break;
     717             : 
     718           0 :             case 6:             /* snapshot */
     719           0 :                 dumpsnapshot = pg_strdup(optarg);
     720           0 :                 break;
     721             : 
     722         274 :             case 7:             /* no-sync */
     723         274 :                 dosync = false;
     724         274 :                 break;
     725             : 
     726           2 :             case 8:
     727           2 :                 have_extra_float_digits = true;
     728           2 :                 if (!option_parse_int(optarg, "--extra-float-digits", -15, 3,
     729             :                                       &extra_float_digits))
     730           2 :                     exit_nicely(1);
     731           0 :                 break;
     732             : 
     733           4 :             case 9:             /* inserts */
     734             : 
     735             :                 /*
     736             :                  * dump_inserts also stores --rows-per-insert, careful not to
     737             :                  * overwrite that.
     738             :                  */
     739           4 :                 if (dopt.dump_inserts == 0)
     740           4 :                     dopt.dump_inserts = DUMP_DEFAULT_ROWS_PER_INSERT;
     741           4 :                 break;
     742             : 
     743           4 :             case 10:            /* rows per insert */
     744           4 :                 if (!option_parse_int(optarg, "--rows-per-insert", 1, INT_MAX,
     745             :                                       &dopt.dump_inserts))
     746           2 :                     exit_nicely(1);
     747           2 :                 break;
     748             : 
     749           8 :             case 11:            /* include foreign data */
     750           8 :                 simple_string_list_append(&foreign_servers_include_patterns,
     751             :                                           optarg);
     752           8 :                 break;
     753             : 
     754           2 :             case 12:            /* include table(s) and their children */
     755           2 :                 simple_string_list_append(&table_include_patterns_and_children,
     756             :                                           optarg);
     757           2 :                 dopt.include_everything = false;
     758           2 :                 break;
     759             : 
     760           2 :             case 13:            /* exclude table(s) and their children */
     761           2 :                 simple_string_list_append(&table_exclude_patterns_and_children,
     762             :                                           optarg);
     763           2 :                 break;
     764             : 
     765           2 :             case 14:            /* exclude data of table(s) and children */
     766           2 :                 simple_string_list_append(&tabledata_exclude_patterns_and_children,
     767             :                                           optarg);
     768           2 :                 break;
     769             : 
     770           0 :             case 15:
     771           0 :                 if (!parse_sync_method(optarg, &sync_method))
     772           0 :                     exit_nicely(1);
     773           0 :                 break;
     774             : 
     775          52 :             case 16:            /* read object filters from file */
     776          52 :                 read_dump_filters(optarg, &dopt);
     777          44 :                 break;
     778             : 
     779           2 :             case 17:            /* exclude extension(s) */
     780           2 :                 simple_string_list_append(&extension_exclude_patterns,
     781             :                                           optarg);
     782           2 :                 break;
     783             : 
     784           8 :             case 18:
     785           8 :                 statistics_only = true;
     786           8 :                 break;
     787             : 
     788          62 :             case 19:
     789          62 :                 no_data = true;
     790          62 :                 break;
     791             : 
     792           4 :             case 20:
     793           4 :                 no_schema = true;
     794           4 :                 break;
     795             : 
     796          16 :             case 21:
     797          16 :                 no_statistics = true;
     798          16 :                 break;
     799             : 
     800           0 :             case 22:
     801           0 :                 with_data = true;
     802           0 :                 break;
     803             : 
     804           0 :             case 23:
     805           0 :                 with_schema = true;
     806           0 :                 break;
     807             : 
     808         158 :             case 24:
     809         158 :                 with_statistics = true;
     810         158 :                 break;
     811             : 
     812           2 :             default:
     813             :                 /* getopt_long already emitted a complaint */
     814           2 :                 pg_log_error_hint("Try \"%s --help\" for more information.", progname);
     815           2 :                 exit_nicely(1);
     816             :         }
     817             :     }
     818             : 
     819             :     /*
     820             :      * Non-option argument specifies database name as long as it wasn't
     821             :      * already specified with -d / --dbname
     822             :      */
     823         540 :     if (optind < argc && dopt.cparams.dbname == NULL)
     824         464 :         dopt.cparams.dbname = argv[optind++];
     825             : 
     826             :     /* Complain if any arguments remain */
     827         540 :     if (optind < argc)
     828             :     {
     829           2 :         pg_log_error("too many command-line arguments (first is \"%s\")",
     830             :                      argv[optind]);
     831           2 :         pg_log_error_hint("Try \"%s --help\" for more information.", progname);
     832           2 :         exit_nicely(1);
     833             :     }
     834             : 
     835             :     /* --column-inserts implies --inserts */
     836         538 :     if (dopt.column_inserts && dopt.dump_inserts == 0)
     837           2 :         dopt.dump_inserts = DUMP_DEFAULT_ROWS_PER_INSERT;
     838             : 
     839             :     /* reject conflicting "-only" options */
     840         538 :     if (data_only && schema_only)
     841           2 :         pg_fatal("options -s/--schema-only and -a/--data-only cannot be used together");
     842         536 :     if (schema_only && statistics_only)
     843           2 :         pg_fatal("options -s/--schema-only and --statistics-only cannot be used together");
     844         534 :     if (data_only && statistics_only)
     845           2 :         pg_fatal("options -a/--data-only and --statistics-only cannot be used together");
     846             : 
     847             :     /* reject conflicting "-only" and "no-" options */
     848         532 :     if (data_only && no_data)
     849           0 :         pg_fatal("options -a/--data-only and --no-data cannot be used together");
     850         532 :     if (schema_only && no_schema)
     851           0 :         pg_fatal("options -s/--schema-only and --no-schema cannot be used together");
     852         532 :     if (statistics_only && no_statistics)
     853           2 :         pg_fatal("options --statistics-only and --no-statistics cannot be used together");
     854             : 
     855             :     /* reject conflicting "with-" and "no-" options */
     856         530 :     if (with_data && no_data)
     857           0 :         pg_fatal("options --with-data and --no-data cannot be used together");
     858         530 :     if (with_schema && no_schema)
     859           0 :         pg_fatal("options --with-schema and --no-schema cannot be used together");
     860         530 :     if (with_statistics && no_statistics)
     861           0 :         pg_fatal("options --with-statistics and --no-statistics cannot be used together");
     862             : 
     863         530 :     if (schema_only && foreign_servers_include_patterns.head != NULL)
     864           2 :         pg_fatal("options -s/--schema-only and --include-foreign-data cannot be used together");
     865             : 
     866         528 :     if (numWorkers > 1 && foreign_servers_include_patterns.head != NULL)
     867           2 :         pg_fatal("option --include-foreign-data is not supported with parallel backup");
     868             : 
     869         526 :     if (data_only && dopt.outputClean)
     870           2 :         pg_fatal("options -c/--clean and -a/--data-only cannot be used together");
     871             : 
     872         524 :     if (dopt.if_exists && !dopt.outputClean)
     873           2 :         pg_fatal("option --if-exists requires option -c/--clean");
     874             : 
     875             :     /*
     876             :      * Set derivative flags. An "-only" option may be overridden by an
     877             :      * explicit "with-" option; e.g. "--schema-only --with-statistics" will
     878             :      * include schema and statistics. Other ambiguous or nonsensical
     879             :      * combinations, e.g. "--schema-only --no-schema", will have already
     880             :      * caused an error in one of the checks above.
     881             :      */
     882         522 :     dopt.dumpData = ((dopt.dumpData && !schema_only && !statistics_only) ||
     883        1044 :                      (data_only || with_data)) && !no_data;
     884         522 :     dopt.dumpSchema = ((dopt.dumpSchema && !data_only && !statistics_only) ||
     885        1044 :                        (schema_only || with_schema)) && !no_schema;
     886         522 :     dopt.dumpStatistics = ((dopt.dumpStatistics && !schema_only && !data_only) ||
     887        1044 :                            (statistics_only || with_statistics)) && !no_statistics;
     888             : 
     889             : 
     890             :     /*
     891             :      * --inserts are already implied above if --column-inserts or
     892             :      * --rows-per-insert were specified.
     893             :      */
     894         522 :     if (dopt.do_nothing && dopt.dump_inserts == 0)
     895           2 :         pg_fatal("option --on-conflict-do-nothing requires option --inserts, --rows-per-insert, or --column-inserts");
     896             : 
     897             :     /* Identify archive format to emit */
     898         520 :     archiveFormat = parseArchiveFormat(format, &archiveMode);
     899             : 
     900             :     /* archiveFormat specific setup */
     901         518 :     if (archiveFormat == archNull)
     902         310 :         plainText = 1;
     903             : 
     904             :     /*
     905             :      * Custom and directory formats are compressed by default with gzip when
     906             :      * available, not the others.  If gzip is not available, no compression is
     907             :      * done by default.
     908             :      */
     909         518 :     if ((archiveFormat == archCustom || archiveFormat == archDirectory) &&
     910         186 :         !user_compression_defined)
     911             :     {
     912             : #ifdef HAVE_LIBZ
     913         176 :         compression_algorithm_str = "gzip";
     914             : #else
     915             :         compression_algorithm_str = "none";
     916             : #endif
     917             :     }
     918             : 
     919             :     /*
     920             :      * Compression options
     921             :      */
     922         518 :     if (!parse_compress_algorithm(compression_algorithm_str,
     923             :                                   &compression_algorithm))
     924           2 :         pg_fatal("unrecognized compression algorithm: \"%s\"",
     925             :                  compression_algorithm_str);
     926             : 
     927         516 :     parse_compress_specification(compression_algorithm, compression_detail,
     928             :                                  &compression_spec);
     929         516 :     error_detail = validate_compress_specification(&compression_spec);
     930         516 :     if (error_detail != NULL)
     931           6 :         pg_fatal("invalid compression specification: %s",
     932             :                  error_detail);
     933             : 
     934         510 :     error_detail = supports_compression(compression_spec);
     935         510 :     if (error_detail != NULL)
     936           0 :         pg_fatal("%s", error_detail);
     937             : 
     938             :     /*
     939             :      * Disable support for zstd workers for now - these are based on
     940             :      * threading, and it's unclear how it interacts with parallel dumps on
     941             :      * platforms where that relies on threads too (e.g. Windows).
     942             :      */
     943         510 :     if (compression_spec.options & PG_COMPRESSION_OPTION_WORKERS)
     944           0 :         pg_log_warning("compression option \"%s\" is not currently supported by pg_dump",
     945             :                        "workers");
     946             : 
     947             :     /*
     948             :      * If emitting an archive format, we always want to emit a DATABASE item,
     949             :      * in case --create is specified at pg_restore time.
     950             :      */
     951         510 :     if (!plainText)
     952         208 :         dopt.outputCreateDB = 1;
     953             : 
     954             :     /* Parallel backup only in the directory archive format so far */
     955         510 :     if (archiveFormat != archDirectory && numWorkers > 1)
     956           2 :         pg_fatal("parallel backup only supported by the directory format");
     957             : 
     958             :     /* Open the output file */
     959         508 :     fout = CreateArchive(filename, archiveFormat, compression_spec,
     960             :                          dosync, archiveMode, setupDumpWorker, sync_method);
     961             : 
     962             :     /* Make dump options accessible right away */
     963         506 :     SetArchiveOptions(fout, &dopt, NULL);
     964             : 
     965             :     /* Register the cleanup hook */
     966         506 :     on_exit_close_archive(fout);
     967             : 
     968             :     /* Let the archiver know how noisy to be */
     969         506 :     fout->verbose = g_verbose;
     970             : 
     971             : 
     972             :     /*
     973             :      * We allow the server to be back to 9.2, and up to any minor release of
     974             :      * our own major version.  (See also version check in pg_dumpall.c.)
     975             :      */
     976         506 :     fout->minRemoteVersion = 90200;
     977         506 :     fout->maxRemoteVersion = (PG_VERSION_NUM / 100) * 100 + 99;
     978             : 
     979         506 :     fout->numWorkers = numWorkers;
     980             : 
     981             :     /*
     982             :      * Open the database using the Archiver, so it knows about it. Errors mean
     983             :      * death.
     984             :      */
     985         506 :     ConnectDatabaseAhx(fout, &dopt.cparams, false);
     986         502 :     setup_connection(fout, dumpencoding, dumpsnapshot, use_role);
     987             : 
     988             :     /*
     989             :      * On hot standbys, never try to dump unlogged table data, since it will
     990             :      * just throw an error.
     991             :      */
     992         502 :     if (fout->isStandby)
     993           8 :         dopt.no_unlogged_table_data = true;
     994             : 
     995             :     /*
     996             :      * Find the last built-in OID, if needed (prior to 8.1)
     997             :      *
     998             :      * With 8.1 and above, we can just use FirstNormalObjectId - 1.
     999             :      */
    1000         502 :     g_last_builtin_oid = FirstNormalObjectId - 1;
    1001             : 
    1002         502 :     pg_log_info("last built-in OID is %u", g_last_builtin_oid);
    1003             : 
    1004             :     /* Expand schema selection patterns into OID lists */
    1005         502 :     if (schema_include_patterns.head != NULL)
    1006             :     {
    1007          36 :         expand_schema_name_patterns(fout, &schema_include_patterns,
    1008             :                                     &schema_include_oids,
    1009             :                                     strict_names);
    1010          24 :         if (schema_include_oids.head == NULL)
    1011           2 :             pg_fatal("no matching schemas were found");
    1012             :     }
    1013         488 :     expand_schema_name_patterns(fout, &schema_exclude_patterns,
    1014             :                                 &schema_exclude_oids,
    1015             :                                 false);
    1016             :     /* non-matching exclusion patterns aren't an error */
    1017             : 
    1018             :     /* Expand table selection patterns into OID lists */
    1019         488 :     expand_table_name_patterns(fout, &table_include_patterns,
    1020             :                                &table_include_oids,
    1021             :                                strict_names, false);
    1022         478 :     expand_table_name_patterns(fout, &table_include_patterns_and_children,
    1023             :                                &table_include_oids,
    1024             :                                strict_names, true);
    1025         478 :     if ((table_include_patterns.head != NULL ||
    1026         456 :          table_include_patterns_and_children.head != NULL) &&
    1027          26 :         table_include_oids.head == NULL)
    1028           4 :         pg_fatal("no matching tables were found");
    1029             : 
    1030         474 :     expand_table_name_patterns(fout, &table_exclude_patterns,
    1031             :                                &table_exclude_oids,
    1032             :                                false, false);
    1033         474 :     expand_table_name_patterns(fout, &table_exclude_patterns_and_children,
    1034             :                                &table_exclude_oids,
    1035             :                                false, true);
    1036             : 
    1037         474 :     expand_table_name_patterns(fout, &tabledata_exclude_patterns,
    1038             :                                &tabledata_exclude_oids,
    1039             :                                false, false);
    1040         474 :     expand_table_name_patterns(fout, &tabledata_exclude_patterns_and_children,
    1041             :                                &tabledata_exclude_oids,
    1042             :                                false, true);
    1043             : 
    1044         474 :     expand_foreign_server_name_patterns(fout, &foreign_servers_include_patterns,
    1045             :                                         &foreign_servers_include_oids);
    1046             : 
    1047             :     /* non-matching exclusion patterns aren't an error */
    1048             : 
    1049             :     /* Expand extension selection patterns into OID lists */
    1050         472 :     if (extension_include_patterns.head != NULL)
    1051             :     {
    1052          10 :         expand_extension_name_patterns(fout, &extension_include_patterns,
    1053             :                                        &extension_include_oids,
    1054             :                                        strict_names);
    1055          10 :         if (extension_include_oids.head == NULL)
    1056           2 :             pg_fatal("no matching extensions were found");
    1057             :     }
    1058         470 :     expand_extension_name_patterns(fout, &extension_exclude_patterns,
    1059             :                                    &extension_exclude_oids,
    1060             :                                    false);
    1061             :     /* non-matching exclusion patterns aren't an error */
    1062             : 
    1063             :     /*
    1064             :      * Dumping LOs is the default for dumps where an inclusion switch is not
    1065             :      * used (an "include everything" dump).  -B can be used to exclude LOs
    1066             :      * from those dumps.  -b can be used to include LOs even when an inclusion
    1067             :      * switch is used.
    1068             :      *
    1069             :      * -s means "schema only" and LOs are data, not schema, so we never
    1070             :      * include LOs when -s is used.
    1071             :      */
    1072         470 :     if (dopt.include_everything && dopt.dumpData && !dopt.dontOutputLOs)
    1073         348 :         dopt.outputLOs = true;
    1074             : 
    1075             :     /*
    1076             :      * Collect role names so we can map object owner OIDs to names.
    1077             :      */
    1078         470 :     collectRoleNames(fout);
    1079             : 
    1080             :     /*
    1081             :      * Now scan the database and create DumpableObject structs for all the
    1082             :      * objects we intend to dump.
    1083             :      */
    1084         470 :     tblinfo = getSchemaData(fout, &numTables);
    1085             : 
    1086         468 :     if (dopt.dumpData)
    1087             :     {
    1088         396 :         getTableData(&dopt, tblinfo, numTables, 0);
    1089         396 :         buildMatViewRefreshDependencies(fout);
    1090         396 :         if (!dopt.dumpSchema)
    1091          14 :             getTableDataFKConstraints();
    1092             :     }
    1093             : 
    1094         468 :     if (!dopt.dumpData && dopt.sequence_data)
    1095          56 :         getTableData(&dopt, tblinfo, numTables, RELKIND_SEQUENCE);
    1096             : 
    1097             :     /*
    1098             :      * For binary upgrade mode, dump pg_largeobject_metadata and the
    1099             :      * associated pg_shdepend rows. This is faster to restore than the
    1100             :      * equivalent set of large object commands.  We can only do this for
    1101             :      * upgrades from v12 and newer; in older versions, pg_largeobject_metadata
    1102             :      * was created WITH OIDS, so the OID column is hidden and won't be dumped.
    1103             :      */
    1104         468 :     if (dopt.binary_upgrade && fout->remoteVersion >= 120000)
    1105             :     {
    1106          62 :         TableInfo  *lo_metadata = findTableByOid(LargeObjectMetadataRelationId);
    1107          62 :         TableInfo  *shdepend = findTableByOid(SharedDependRelationId);
    1108             : 
    1109          62 :         makeTableDataInfo(&dopt, lo_metadata);
    1110          62 :         makeTableDataInfo(&dopt, shdepend);
    1111             : 
    1112             :         /*
    1113             :          * Save pg_largeobject_metadata's dump ID for use as a dependency for
    1114             :          * pg_shdepend and any large object comments/seclabels.
    1115             :          */
    1116          62 :         lo_metadata_dumpId = lo_metadata->dataObj->dobj.dumpId;
    1117          62 :         addObjectDependency(&shdepend->dataObj->dobj, lo_metadata_dumpId);
    1118             : 
    1119             :         /*
    1120             :          * Only dump large object shdepend rows for this database.
    1121             :          */
    1122          62 :         shdepend->dataObj->filtercond = "WHERE classid = 'pg_largeobject'::regclass "
    1123             :             "AND dbid = (SELECT oid FROM pg_database "
    1124             :             "            WHERE datname = current_database())";
    1125             :     }
    1126             : 
    1127             :     /*
    1128             :      * In binary-upgrade mode, we do not have to worry about the actual LO
    1129             :      * data or the associated metadata that resides in the pg_largeobject and
    1130             :      * pg_largeobject_metadata tables, respectively.
    1131             :      *
    1132             :      * However, we do need to collect LO information as there may be comments
    1133             :      * or other information on LOs that we do need to dump out.
    1134             :      */
    1135         468 :     if (dopt.outputLOs || dopt.binary_upgrade)
    1136         410 :         getLOs(fout);
    1137             : 
    1138             :     /*
    1139             :      * Collect dependency data to assist in ordering the objects.
    1140             :      */
    1141         468 :     getDependencies(fout);
    1142             : 
    1143             :     /*
    1144             :      * Collect ACLs, comments, and security labels, if wanted.
    1145             :      */
    1146         468 :     if (!dopt.aclsSkip)
    1147         464 :         getAdditionalACLs(fout);
    1148         468 :     if (!dopt.no_comments)
    1149         468 :         collectComments(fout);
    1150         468 :     if (!dopt.no_security_labels)
    1151         468 :         collectSecLabels(fout);
    1152             : 
    1153             :     /* For binary upgrade mode, collect required pg_class information. */
    1154         468 :     if (dopt.binary_upgrade)
    1155          62 :         collectBinaryUpgradeClassOids(fout);
    1156             : 
    1157             :     /* Collect sequence information. */
    1158         468 :     collectSequences(fout);
    1159             : 
    1160             :     /* Lastly, create dummy objects to represent the section boundaries */
    1161         468 :     boundaryObjs = createBoundaryObjects();
    1162             : 
    1163             :     /* Get pointers to all the known DumpableObjects */
    1164         468 :     getDumpableObjects(&dobjs, &numObjs);
    1165             : 
    1166             :     /*
    1167             :      * Add dummy dependencies to enforce the dump section ordering.
    1168             :      */
    1169         468 :     addBoundaryDependencies(dobjs, numObjs, boundaryObjs);
    1170             : 
    1171             :     /*
    1172             :      * Sort the objects into a safe dump order (no forward references).
    1173             :      *
    1174             :      * We rely on dependency information to help us determine a safe order, so
    1175             :      * the initial sort is mostly for cosmetic purposes: we sort by name to
    1176             :      * ensure that logically identical schemas will dump identically.
    1177             :      */
    1178         468 :     sortDumpableObjectsByTypeName(dobjs, numObjs);
    1179             : 
    1180         468 :     sortDumpableObjects(dobjs, numObjs,
    1181         468 :                         boundaryObjs[0].dumpId, boundaryObjs[1].dumpId);
    1182             : 
    1183             :     /*
    1184             :      * Create archive TOC entries for all the objects to be dumped, in a safe
    1185             :      * order.
    1186             :      */
    1187             : 
    1188             :     /*
    1189             :      * First the special entries for ENCODING, STDSTRINGS, and SEARCHPATH.
    1190             :      */
    1191         468 :     dumpEncoding(fout);
    1192         468 :     dumpStdStrings(fout);
    1193         468 :     dumpSearchPath(fout);
    1194             : 
    1195             :     /* The database items are always next, unless we don't want them at all */
    1196         468 :     if (dopt.outputCreateDB)
    1197         264 :         dumpDatabase(fout);
    1198             : 
    1199             :     /* Now the rearrangeable objects. */
    1200     1740674 :     for (i = 0; i < numObjs; i++)
    1201     1740206 :         dumpDumpableObject(fout, dobjs[i]);
    1202             : 
    1203             :     /*
    1204             :      * Set up options info to ensure we dump what we want.
    1205             :      */
    1206         468 :     ropt = NewRestoreOptions();
    1207         468 :     ropt->filename = filename;
    1208             : 
    1209             :     /* if you change this list, see dumpOptionsFromRestoreOptions */
    1210         468 :     ropt->cparams.dbname = dopt.cparams.dbname ? pg_strdup(dopt.cparams.dbname) : NULL;
    1211         468 :     ropt->cparams.pgport = dopt.cparams.pgport ? pg_strdup(dopt.cparams.pgport) : NULL;
    1212         468 :     ropt->cparams.pghost = dopt.cparams.pghost ? pg_strdup(dopt.cparams.pghost) : NULL;
    1213         468 :     ropt->cparams.username = dopt.cparams.username ? pg_strdup(dopt.cparams.username) : NULL;
    1214         468 :     ropt->cparams.promptPassword = dopt.cparams.promptPassword;
    1215         468 :     ropt->dropSchema = dopt.outputClean;
    1216         468 :     ropt->dumpData = dopt.dumpData;
    1217         468 :     ropt->dumpSchema = dopt.dumpSchema;
    1218         468 :     ropt->dumpStatistics = dopt.dumpStatistics;
    1219         468 :     ropt->if_exists = dopt.if_exists;
    1220         468 :     ropt->column_inserts = dopt.column_inserts;
    1221         468 :     ropt->dumpSections = dopt.dumpSections;
    1222         468 :     ropt->aclsSkip = dopt.aclsSkip;
    1223         468 :     ropt->superuser = dopt.outputSuperuser;
    1224         468 :     ropt->createDB = dopt.outputCreateDB;
    1225         468 :     ropt->noOwner = dopt.outputNoOwner;
    1226         468 :     ropt->noTableAm = dopt.outputNoTableAm;
    1227         468 :     ropt->noTablespace = dopt.outputNoTablespaces;
    1228         468 :     ropt->disable_triggers = dopt.disable_triggers;
    1229         468 :     ropt->use_setsessauth = dopt.use_setsessauth;
    1230         468 :     ropt->disable_dollar_quoting = dopt.disable_dollar_quoting;
    1231         468 :     ropt->dump_inserts = dopt.dump_inserts;
    1232         468 :     ropt->no_comments = dopt.no_comments;
    1233         468 :     ropt->no_policies = dopt.no_policies;
    1234         468 :     ropt->no_publications = dopt.no_publications;
    1235         468 :     ropt->no_security_labels = dopt.no_security_labels;
    1236         468 :     ropt->no_subscriptions = dopt.no_subscriptions;
    1237         468 :     ropt->lockWaitTimeout = dopt.lockWaitTimeout;
    1238         468 :     ropt->include_everything = dopt.include_everything;
    1239         468 :     ropt->enable_row_security = dopt.enable_row_security;
    1240         468 :     ropt->sequence_data = dopt.sequence_data;
    1241         468 :     ropt->binary_upgrade = dopt.binary_upgrade;
    1242             : 
    1243         468 :     ropt->compression_spec = compression_spec;
    1244             : 
    1245         468 :     ropt->suppressDumpWarnings = true;   /* We've already shown them */
    1246             : 
    1247         468 :     SetArchiveOptions(fout, &dopt, ropt);
    1248             : 
    1249             :     /* Mark which entries should be output */
    1250         468 :     ProcessArchiveRestoreOptions(fout);
    1251             : 
    1252             :     /*
    1253             :      * The archive's TOC entries are now marked as to which ones will actually
    1254             :      * be output, so we can set up their dependency lists properly. This isn't
    1255             :      * necessary for plain-text output, though.
    1256             :      */
    1257         468 :     if (!plainText)
    1258         206 :         BuildArchiveDependencies(fout);
    1259             : 
    1260             :     /*
    1261             :      * And finally we can do the actual output.
    1262             :      *
    1263             :      * Note: for non-plain-text output formats, the output file is written
    1264             :      * inside CloseArchive().  This is, um, bizarre; but not worth changing
    1265             :      * right now.
    1266             :      */
    1267         468 :     if (plainText)
    1268         262 :         RestoreArchive(fout, false);
    1269             : 
    1270         466 :     CloseArchive(fout);
    1271             : 
    1272         466 :     exit_nicely(0);
    1273             : }
    1274             : 
    1275             : 
    1276             : static void
    1277           2 : help(const char *progname)
    1278             : {
    1279           2 :     printf(_("%s exports a PostgreSQL database as an SQL script or to other formats.\n\n"), progname);
    1280           2 :     printf(_("Usage:\n"));
    1281           2 :     printf(_("  %s [OPTION]... [DBNAME]\n"), progname);
    1282             : 
    1283           2 :     printf(_("\nGeneral options:\n"));
    1284           2 :     printf(_("  -f, --file=FILENAME          output file or directory name\n"));
    1285           2 :     printf(_("  -F, --format=c|d|t|p         output file format (custom, directory, tar,\n"
    1286             :              "                               plain text (default))\n"));
    1287           2 :     printf(_("  -j, --jobs=NUM               use this many parallel jobs to dump\n"));
    1288           2 :     printf(_("  -v, --verbose                verbose mode\n"));
    1289           2 :     printf(_("  -V, --version                output version information, then exit\n"));
    1290           2 :     printf(_("  -Z, --compress=METHOD[:DETAIL]\n"
    1291             :              "                               compress as specified\n"));
    1292           2 :     printf(_("  --lock-wait-timeout=TIMEOUT  fail after waiting TIMEOUT for a table lock\n"));
    1293           2 :     printf(_("  --no-sync                    do not wait for changes to be written safely to disk\n"));
    1294           2 :     printf(_("  --sync-method=METHOD         set method for syncing files to disk\n"));
    1295           2 :     printf(_("  -?, --help                   show this help, then exit\n"));
    1296             : 
    1297           2 :     printf(_("\nOptions controlling the output content:\n"));
    1298           2 :     printf(_("  -a, --data-only              dump only the data, not the schema or statistics\n"));
    1299           2 :     printf(_("  -b, --large-objects          include large objects in dump\n"));
    1300           2 :     printf(_("  --blobs                      (same as --large-objects, deprecated)\n"));
    1301           2 :     printf(_("  -B, --no-large-objects       exclude large objects in dump\n"));
    1302           2 :     printf(_("  --no-blobs                   (same as --no-large-objects, deprecated)\n"));
    1303           2 :     printf(_("  -c, --clean                  clean (drop) database objects before recreating\n"));
    1304           2 :     printf(_("  -C, --create                 include commands to create database in dump\n"));
    1305           2 :     printf(_("  -e, --extension=PATTERN      dump the specified extension(s) only\n"));
    1306           2 :     printf(_("  -E, --encoding=ENCODING      dump the data in encoding ENCODING\n"));
    1307           2 :     printf(_("  -n, --schema=PATTERN         dump the specified schema(s) only\n"));
    1308           2 :     printf(_("  -N, --exclude-schema=PATTERN do NOT dump the specified schema(s)\n"));
    1309           2 :     printf(_("  -O, --no-owner               skip restoration of object ownership in\n"
    1310             :              "                               plain-text format\n"));
    1311           2 :     printf(_("  -s, --schema-only            dump only the schema, no data or statistics\n"));
    1312           2 :     printf(_("  -S, --superuser=NAME         superuser user name to use in plain-text format\n"));
    1313           2 :     printf(_("  -t, --table=PATTERN          dump only the specified table(s)\n"));
    1314           2 :     printf(_("  -T, --exclude-table=PATTERN  do NOT dump the specified table(s)\n"));
    1315           2 :     printf(_("  -x, --no-privileges          do not dump privileges (grant/revoke)\n"));
    1316           2 :     printf(_("  --binary-upgrade             for use by upgrade utilities only\n"));
    1317           2 :     printf(_("  --column-inserts             dump data as INSERT commands with column names\n"));
    1318           2 :     printf(_("  --disable-dollar-quoting     disable dollar quoting, use SQL standard quoting\n"));
    1319           2 :     printf(_("  --disable-triggers           disable triggers during data-only restore\n"));
    1320           2 :     printf(_("  --enable-row-security        enable row security (dump only content user has\n"
    1321             :              "                               access to)\n"));
    1322           2 :     printf(_("  --exclude-extension=PATTERN  do NOT dump the specified extension(s)\n"));
    1323           2 :     printf(_("  --exclude-table-and-children=PATTERN\n"
    1324             :              "                               do NOT dump the specified table(s), including\n"
    1325             :              "                               child and partition tables\n"));
    1326           2 :     printf(_("  --exclude-table-data=PATTERN do NOT dump data for the specified table(s)\n"));
    1327           2 :     printf(_("  --exclude-table-data-and-children=PATTERN\n"
    1328             :              "                               do NOT dump data for the specified table(s),\n"
    1329             :              "                               including child and partition tables\n"));
    1330           2 :     printf(_("  --extra-float-digits=NUM     override default setting for extra_float_digits\n"));
    1331           2 :     printf(_("  --filter=FILENAME            include or exclude objects and data from dump\n"
    1332             :              "                               based on expressions in FILENAME\n"));
    1333           2 :     printf(_("  --if-exists                  use IF EXISTS when dropping objects\n"));
    1334           2 :     printf(_("  --include-foreign-data=PATTERN\n"
    1335             :              "                               include data of foreign tables on foreign\n"
    1336             :              "                               servers matching PATTERN\n"));
    1337           2 :     printf(_("  --inserts                    dump data as INSERT commands, rather than COPY\n"));
    1338           2 :     printf(_("  --load-via-partition-root    load partitions via the root table\n"));
    1339           2 :     printf(_("  --no-comments                do not dump comment commands\n"));
    1340           2 :     printf(_("  --no-data                    do not dump data\n"));
    1341           2 :     printf(_("  --no-policies                do not dump row security policies\n"));
    1342           2 :     printf(_("  --no-publications            do not dump publications\n"));
    1343           2 :     printf(_("  --no-schema                  do not dump schema\n"));
    1344           2 :     printf(_("  --no-security-labels         do not dump security label assignments\n"));
    1345           2 :     printf(_("  --no-statistics              do not dump statistics\n"));
    1346           2 :     printf(_("  --no-subscriptions           do not dump subscriptions\n"));
    1347           2 :     printf(_("  --no-table-access-method     do not dump table access methods\n"));
    1348           2 :     printf(_("  --no-tablespaces             do not dump tablespace assignments\n"));
    1349           2 :     printf(_("  --no-toast-compression       do not dump TOAST compression methods\n"));
    1350           2 :     printf(_("  --no-unlogged-table-data     do not dump unlogged table data\n"));
    1351           2 :     printf(_("  --on-conflict-do-nothing     add ON CONFLICT DO NOTHING to INSERT commands\n"));
    1352           2 :     printf(_("  --quote-all-identifiers      quote all identifiers, even if not key words\n"));
    1353           2 :     printf(_("  --rows-per-insert=NROWS      number of rows per INSERT; implies --inserts\n"));
    1354           2 :     printf(_("  --section=SECTION            dump named section (pre-data, data, or post-data)\n"));
    1355           2 :     printf(_("  --sequence-data              include sequence data in dump\n"));
    1356           2 :     printf(_("  --serializable-deferrable    wait until the dump can run without anomalies\n"));
    1357           2 :     printf(_("  --snapshot=SNAPSHOT          use given snapshot for the dump\n"));
    1358           2 :     printf(_("  --statistics-only            dump only the statistics, not schema or data\n"));
    1359           2 :     printf(_("  --strict-names               require table and/or schema include patterns to\n"
    1360             :              "                               match at least one entity each\n"));
    1361           2 :     printf(_("  --table-and-children=PATTERN dump only the specified table(s), including\n"
    1362             :              "                               child and partition tables\n"));
    1363           2 :     printf(_("  --use-set-session-authorization\n"
    1364             :              "                               use SET SESSION AUTHORIZATION commands instead of\n"
    1365             :              "                               ALTER OWNER commands to set ownership\n"));
    1366           2 :     printf(_("  --with-data                  dump the data\n"));
    1367           2 :     printf(_("  --with-schema                dump the schema\n"));
    1368           2 :     printf(_("  --with-statistics            dump the statistics\n"));
    1369             : 
    1370           2 :     printf(_("\nConnection options:\n"));
    1371           2 :     printf(_("  -d, --dbname=DBNAME      database to dump\n"));
    1372           2 :     printf(_("  -h, --host=HOSTNAME      database server host or socket directory\n"));
    1373           2 :     printf(_("  -p, --port=PORT          database server port number\n"));
    1374           2 :     printf(_("  -U, --username=NAME      connect as specified database user\n"));
    1375           2 :     printf(_("  -w, --no-password        never prompt for password\n"));
    1376           2 :     printf(_("  -W, --password           force password prompt (should happen automatically)\n"));
    1377           2 :     printf(_("  --role=ROLENAME          do SET ROLE before dump\n"));
    1378             : 
    1379           2 :     printf(_("\nIf no database name is supplied, then the PGDATABASE environment\n"
    1380             :              "variable value is used.\n\n"));
    1381           2 :     printf(_("Report bugs to <%s>.\n"), PACKAGE_BUGREPORT);
    1382           2 :     printf(_("%s home page: <%s>\n"), PACKAGE_NAME, PACKAGE_URL);
    1383           2 : }
    1384             : 
    1385             : static void
    1386         538 : setup_connection(Archive *AH, const char *dumpencoding,
    1387             :                  const char *dumpsnapshot, char *use_role)
    1388             : {
    1389         538 :     DumpOptions *dopt = AH->dopt;
    1390         538 :     PGconn     *conn = GetConnection(AH);
    1391             :     const char *std_strings;
    1392             : 
    1393         538 :     PQclear(ExecuteSqlQueryForSingleRow(AH, ALWAYS_SECURE_SEARCH_PATH_SQL));
    1394             : 
    1395             :     /*
    1396             :      * Set the client encoding if requested.
    1397             :      */
    1398         538 :     if (dumpencoding)
    1399             :     {
    1400          40 :         if (PQsetClientEncoding(conn, dumpencoding) < 0)
    1401           0 :             pg_fatal("invalid client encoding \"%s\" specified",
    1402             :                      dumpencoding);
    1403             :     }
    1404             : 
    1405             :     /*
    1406             :      * Get the active encoding and the standard_conforming_strings setting, so
    1407             :      * we know how to escape strings.
    1408             :      */
    1409         538 :     AH->encoding = PQclientEncoding(conn);
    1410         538 :     setFmtEncoding(AH->encoding);
    1411             : 
    1412         538 :     std_strings = PQparameterStatus(conn, "standard_conforming_strings");
    1413         538 :     AH->std_strings = (std_strings && strcmp(std_strings, "on") == 0);
    1414             : 
    1415             :     /*
    1416             :      * Set the role if requested.  In a parallel dump worker, we'll be passed
    1417             :      * use_role == NULL, but AH->use_role is already set (if user specified it
    1418             :      * originally) and we should use that.
    1419             :      */
    1420         538 :     if (!use_role && AH->use_role)
    1421           4 :         use_role = AH->use_role;
    1422             : 
    1423             :     /* Set the role if requested */
    1424         538 :     if (use_role)
    1425             :     {
    1426          10 :         PQExpBuffer query = createPQExpBuffer();
    1427             : 
    1428          10 :         appendPQExpBuffer(query, "SET ROLE %s", fmtId(use_role));
    1429          10 :         ExecuteSqlStatement(AH, query->data);
    1430          10 :         destroyPQExpBuffer(query);
    1431             : 
    1432             :         /* save it for possible later use by parallel workers */
    1433          10 :         if (!AH->use_role)
    1434           6 :             AH->use_role = pg_strdup(use_role);
    1435             :     }
    1436             : 
    1437             :     /* Set the datestyle to ISO to ensure the dump's portability */
    1438         538 :     ExecuteSqlStatement(AH, "SET DATESTYLE = ISO");
    1439             : 
    1440             :     /* Likewise, avoid using sql_standard intervalstyle */
    1441         538 :     ExecuteSqlStatement(AH, "SET INTERVALSTYLE = POSTGRES");
    1442             : 
    1443             :     /*
    1444             :      * Use an explicitly specified extra_float_digits if it has been provided.
    1445             :      * Otherwise, set extra_float_digits so that we can dump float data
    1446             :      * exactly (given correctly implemented float I/O code, anyway).
    1447             :      */
    1448         538 :     if (have_extra_float_digits)
    1449             :     {
    1450           0 :         PQExpBuffer q = createPQExpBuffer();
    1451             : 
    1452           0 :         appendPQExpBuffer(q, "SET extra_float_digits TO %d",
    1453             :                           extra_float_digits);
    1454           0 :         ExecuteSqlStatement(AH, q->data);
    1455           0 :         destroyPQExpBuffer(q);
    1456             :     }
    1457             :     else
    1458         538 :         ExecuteSqlStatement(AH, "SET extra_float_digits TO 3");
    1459             : 
    1460             :     /*
    1461             :      * Disable synchronized scanning, to prevent unpredictable changes in row
    1462             :      * ordering across a dump and reload.
    1463             :      */
    1464         538 :     ExecuteSqlStatement(AH, "SET synchronize_seqscans TO off");
    1465             : 
    1466             :     /*
    1467             :      * Disable timeouts if supported.
    1468             :      */
    1469         538 :     ExecuteSqlStatement(AH, "SET statement_timeout = 0");
    1470         538 :     if (AH->remoteVersion >= 90300)
    1471         538 :         ExecuteSqlStatement(AH, "SET lock_timeout = 0");
    1472         538 :     if (AH->remoteVersion >= 90600)
    1473         538 :         ExecuteSqlStatement(AH, "SET idle_in_transaction_session_timeout = 0");
    1474         538 :     if (AH->remoteVersion >= 170000)
    1475         538 :         ExecuteSqlStatement(AH, "SET transaction_timeout = 0");
    1476             : 
    1477             :     /*
    1478             :      * Quote all identifiers, if requested.
    1479             :      */
    1480         538 :     if (quote_all_identifiers)
    1481          58 :         ExecuteSqlStatement(AH, "SET quote_all_identifiers = true");
    1482             : 
    1483             :     /*
    1484             :      * Adjust row-security mode, if supported.
    1485             :      */
    1486         538 :     if (AH->remoteVersion >= 90500)
    1487             :     {
    1488         538 :         if (dopt->enable_row_security)
    1489           0 :             ExecuteSqlStatement(AH, "SET row_security = on");
    1490             :         else
    1491         538 :             ExecuteSqlStatement(AH, "SET row_security = off");
    1492             :     }
    1493             : 
    1494             :     /*
    1495             :      * For security reasons, we restrict the expansion of non-system views and
    1496             :      * access to foreign tables during the pg_dump process. This restriction
    1497             :      * is adjusted when dumping foreign table data.
    1498             :      */
    1499         538 :     set_restrict_relation_kind(AH, "view, foreign-table");
    1500             : 
    1501             :     /*
    1502             :      * Initialize prepared-query state to "nothing prepared".  We do this here
    1503             :      * so that a parallel dump worker will have its own state.
    1504             :      */
    1505         538 :     AH->is_prepared = (bool *) pg_malloc0(NUM_PREP_QUERIES * sizeof(bool));
    1506             : 
    1507             :     /*
    1508             :      * Start transaction-snapshot mode transaction to dump consistent data.
    1509             :      */
    1510         538 :     ExecuteSqlStatement(AH, "BEGIN");
    1511             : 
    1512             :     /*
    1513             :      * To support the combination of serializable_deferrable with the jobs
    1514             :      * option we use REPEATABLE READ for the worker connections that are
    1515             :      * passed a snapshot.  As long as the snapshot is acquired in a
    1516             :      * SERIALIZABLE, READ ONLY, DEFERRABLE transaction, its use within a
    1517             :      * REPEATABLE READ transaction provides the appropriate integrity
    1518             :      * guarantees.  This is a kluge, but safe for back-patching.
    1519             :      */
    1520         538 :     if (dopt->serializable_deferrable && AH->sync_snapshot_id == NULL)
    1521           0 :         ExecuteSqlStatement(AH,
    1522             :                             "SET TRANSACTION ISOLATION LEVEL "
    1523             :                             "SERIALIZABLE, READ ONLY, DEFERRABLE");
    1524             :     else
    1525         538 :         ExecuteSqlStatement(AH,
    1526             :                             "SET TRANSACTION ISOLATION LEVEL "
    1527             :                             "REPEATABLE READ, READ ONLY");
    1528             : 
    1529             :     /*
    1530             :      * If user specified a snapshot to use, select that.  In a parallel dump
    1531             :      * worker, we'll be passed dumpsnapshot == NULL, but AH->sync_snapshot_id
    1532             :      * is already set (if the server can handle it) and we should use that.
    1533             :      */
    1534         538 :     if (dumpsnapshot)
    1535           0 :         AH->sync_snapshot_id = pg_strdup(dumpsnapshot);
    1536             : 
    1537         538 :     if (AH->sync_snapshot_id)
    1538             :     {
    1539          36 :         PQExpBuffer query = createPQExpBuffer();
    1540             : 
    1541          36 :         appendPQExpBufferStr(query, "SET TRANSACTION SNAPSHOT ");
    1542          36 :         appendStringLiteralConn(query, AH->sync_snapshot_id, conn);
    1543          36 :         ExecuteSqlStatement(AH, query->data);
    1544          36 :         destroyPQExpBuffer(query);
    1545             :     }
    1546         502 :     else if (AH->numWorkers > 1)
    1547             :     {
    1548          18 :         if (AH->isStandby && AH->remoteVersion < 100000)
    1549           0 :             pg_fatal("parallel dumps from standby servers are not supported by this server version");
    1550          18 :         AH->sync_snapshot_id = get_synchronized_snapshot(AH);
    1551             :     }
    1552         538 : }
    1553             : 
    1554             : /* Set up connection for a parallel worker process */
    1555             : static void
    1556          36 : setupDumpWorker(Archive *AH)
    1557             : {
    1558             :     /*
    1559             :      * We want to re-select all the same values the leader connection is
    1560             :      * using.  We'll have inherited directly-usable values in
    1561             :      * AH->sync_snapshot_id and AH->use_role, but we need to translate the
    1562             :      * inherited encoding value back to a string to pass to setup_connection.
    1563             :      */
    1564          36 :     setup_connection(AH,
    1565             :                      pg_encoding_to_char(AH->encoding),
    1566             :                      NULL,
    1567             :                      NULL);
    1568          36 : }
    1569             : 
    1570             : static char *
    1571          18 : get_synchronized_snapshot(Archive *fout)
    1572             : {
    1573          18 :     char       *query = "SELECT pg_catalog.pg_export_snapshot()";
    1574             :     char       *result;
    1575             :     PGresult   *res;
    1576             : 
    1577          18 :     res = ExecuteSqlQueryForSingleRow(fout, query);
    1578          18 :     result = pg_strdup(PQgetvalue(res, 0, 0));
    1579          18 :     PQclear(res);
    1580             : 
    1581          18 :     return result;
    1582             : }
    1583             : 
    1584             : static ArchiveFormat
    1585         520 : parseArchiveFormat(const char *format, ArchiveMode *mode)
    1586             : {
    1587             :     ArchiveFormat archiveFormat;
    1588             : 
    1589         520 :     *mode = archModeWrite;
    1590             : 
    1591         520 :     if (pg_strcasecmp(format, "a") == 0 || pg_strcasecmp(format, "append") == 0)
    1592             :     {
    1593             :         /* This is used by pg_dumpall, and is not documented */
    1594          86 :         archiveFormat = archNull;
    1595          86 :         *mode = archModeAppend;
    1596             :     }
    1597         434 :     else if (pg_strcasecmp(format, "c") == 0)
    1598           0 :         archiveFormat = archCustom;
    1599         434 :     else if (pg_strcasecmp(format, "custom") == 0)
    1600          88 :         archiveFormat = archCustom;
    1601         346 :     else if (pg_strcasecmp(format, "d") == 0)
    1602           2 :         archiveFormat = archDirectory;
    1603         344 :     else if (pg_strcasecmp(format, "directory") == 0)
    1604          96 :         archiveFormat = archDirectory;
    1605         248 :     else if (pg_strcasecmp(format, "p") == 0)
    1606         218 :         archiveFormat = archNull;
    1607          30 :     else if (pg_strcasecmp(format, "plain") == 0)
    1608           6 :         archiveFormat = archNull;
    1609          24 :     else if (pg_strcasecmp(format, "t") == 0)
    1610           0 :         archiveFormat = archTar;
    1611          24 :     else if (pg_strcasecmp(format, "tar") == 0)
    1612          22 :         archiveFormat = archTar;
    1613             :     else
    1614           2 :         pg_fatal("invalid output format \"%s\" specified", format);
    1615         518 :     return archiveFormat;
    1616             : }
    1617             : 
    1618             : /*
    1619             :  * Find the OIDs of all schemas matching the given list of patterns,
    1620             :  * and append them to the given OID list.
    1621             :  */
    1622             : static void
    1623         524 : expand_schema_name_patterns(Archive *fout,
    1624             :                             SimpleStringList *patterns,
    1625             :                             SimpleOidList *oids,
    1626             :                             bool strict_names)
    1627             : {
    1628             :     PQExpBuffer query;
    1629             :     PGresult   *res;
    1630             :     SimpleStringListCell *cell;
    1631             :     int         i;
    1632             : 
    1633         524 :     if (patterns->head == NULL)
    1634         482 :         return;                 /* nothing to do */
    1635             : 
    1636          42 :     query = createPQExpBuffer();
    1637             : 
    1638             :     /*
    1639             :      * The loop below runs multiple SELECTs might sometimes result in
    1640             :      * duplicate entries in the OID list, but we don't care.
    1641             :      */
    1642             : 
    1643          72 :     for (cell = patterns->head; cell; cell = cell->next)
    1644             :     {
    1645             :         PQExpBufferData dbbuf;
    1646             :         int         dotcnt;
    1647             : 
    1648          42 :         appendPQExpBufferStr(query,
    1649             :                              "SELECT oid FROM pg_catalog.pg_namespace n\n");
    1650          42 :         initPQExpBuffer(&dbbuf);
    1651          42 :         processSQLNamePattern(GetConnection(fout), query, cell->val, false,
    1652             :                               false, NULL, "n.nspname", NULL, NULL, &dbbuf,
    1653             :                               &dotcnt);
    1654          42 :         if (dotcnt > 1)
    1655           4 :             pg_fatal("improper qualified name (too many dotted names): %s",
    1656             :                      cell->val);
    1657          38 :         else if (dotcnt == 1)
    1658           6 :             prohibit_crossdb_refs(GetConnection(fout), dbbuf.data, cell->val);
    1659          32 :         termPQExpBuffer(&dbbuf);
    1660             : 
    1661          32 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    1662          32 :         if (strict_names && PQntuples(res) == 0)
    1663           2 :             pg_fatal("no matching schemas were found for pattern \"%s\"", cell->val);
    1664             : 
    1665          58 :         for (i = 0; i < PQntuples(res); i++)
    1666             :         {
    1667          28 :             simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
    1668             :         }
    1669             : 
    1670          30 :         PQclear(res);
    1671          30 :         resetPQExpBuffer(query);
    1672             :     }
    1673             : 
    1674          30 :     destroyPQExpBuffer(query);
    1675             : }
    1676             : 
    1677             : /*
    1678             :  * Find the OIDs of all extensions matching the given list of patterns,
    1679             :  * and append them to the given OID list.
    1680             :  */
    1681             : static void
    1682         480 : expand_extension_name_patterns(Archive *fout,
    1683             :                                SimpleStringList *patterns,
    1684             :                                SimpleOidList *oids,
    1685             :                                bool strict_names)
    1686             : {
    1687             :     PQExpBuffer query;
    1688             :     PGresult   *res;
    1689             :     SimpleStringListCell *cell;
    1690             :     int         i;
    1691             : 
    1692         480 :     if (patterns->head == NULL)
    1693         466 :         return;                 /* nothing to do */
    1694             : 
    1695          14 :     query = createPQExpBuffer();
    1696             : 
    1697             :     /*
    1698             :      * The loop below runs multiple SELECTs might sometimes result in
    1699             :      * duplicate entries in the OID list, but we don't care.
    1700             :      */
    1701          28 :     for (cell = patterns->head; cell; cell = cell->next)
    1702             :     {
    1703             :         int         dotcnt;
    1704             : 
    1705          14 :         appendPQExpBufferStr(query,
    1706             :                              "SELECT oid FROM pg_catalog.pg_extension e\n");
    1707          14 :         processSQLNamePattern(GetConnection(fout), query, cell->val, false,
    1708             :                               false, NULL, "e.extname", NULL, NULL, NULL,
    1709             :                               &dotcnt);
    1710          14 :         if (dotcnt > 0)
    1711           0 :             pg_fatal("improper qualified name (too many dotted names): %s",
    1712             :                      cell->val);
    1713             : 
    1714          14 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    1715          14 :         if (strict_names && PQntuples(res) == 0)
    1716           0 :             pg_fatal("no matching extensions were found for pattern \"%s\"", cell->val);
    1717             : 
    1718          26 :         for (i = 0; i < PQntuples(res); i++)
    1719             :         {
    1720          12 :             simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
    1721             :         }
    1722             : 
    1723          14 :         PQclear(res);
    1724          14 :         resetPQExpBuffer(query);
    1725             :     }
    1726             : 
    1727          14 :     destroyPQExpBuffer(query);
    1728             : }
    1729             : 
    1730             : /*
    1731             :  * Find the OIDs of all foreign servers matching the given list of patterns,
    1732             :  * and append them to the given OID list.
    1733             :  */
    1734             : static void
    1735         474 : expand_foreign_server_name_patterns(Archive *fout,
    1736             :                                     SimpleStringList *patterns,
    1737             :                                     SimpleOidList *oids)
    1738             : {
    1739             :     PQExpBuffer query;
    1740             :     PGresult   *res;
    1741             :     SimpleStringListCell *cell;
    1742             :     int         i;
    1743             : 
    1744         474 :     if (patterns->head == NULL)
    1745         468 :         return;                 /* nothing to do */
    1746             : 
    1747           6 :     query = createPQExpBuffer();
    1748             : 
    1749             :     /*
    1750             :      * The loop below runs multiple SELECTs might sometimes result in
    1751             :      * duplicate entries in the OID list, but we don't care.
    1752             :      */
    1753             : 
    1754          10 :     for (cell = patterns->head; cell; cell = cell->next)
    1755             :     {
    1756             :         int         dotcnt;
    1757             : 
    1758           6 :         appendPQExpBufferStr(query,
    1759             :                              "SELECT oid FROM pg_catalog.pg_foreign_server s\n");
    1760           6 :         processSQLNamePattern(GetConnection(fout), query, cell->val, false,
    1761             :                               false, NULL, "s.srvname", NULL, NULL, NULL,
    1762             :                               &dotcnt);
    1763           6 :         if (dotcnt > 0)
    1764           0 :             pg_fatal("improper qualified name (too many dotted names): %s",
    1765             :                      cell->val);
    1766             : 
    1767           6 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    1768           6 :         if (PQntuples(res) == 0)
    1769           2 :             pg_fatal("no matching foreign servers were found for pattern \"%s\"", cell->val);
    1770             : 
    1771           8 :         for (i = 0; i < PQntuples(res); i++)
    1772           4 :             simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
    1773             : 
    1774           4 :         PQclear(res);
    1775           4 :         resetPQExpBuffer(query);
    1776             :     }
    1777             : 
    1778           4 :     destroyPQExpBuffer(query);
    1779             : }
    1780             : 
    1781             : /*
    1782             :  * Find the OIDs of all tables matching the given list of patterns,
    1783             :  * and append them to the given OID list. See also expand_dbname_patterns()
    1784             :  * in pg_dumpall.c
    1785             :  */
    1786             : static void
    1787        2862 : expand_table_name_patterns(Archive *fout,
    1788             :                            SimpleStringList *patterns, SimpleOidList *oids,
    1789             :                            bool strict_names, bool with_child_tables)
    1790             : {
    1791             :     PQExpBuffer query;
    1792             :     PGresult   *res;
    1793             :     SimpleStringListCell *cell;
    1794             :     int         i;
    1795             : 
    1796        2862 :     if (patterns->head == NULL)
    1797        2804 :         return;                 /* nothing to do */
    1798             : 
    1799          58 :     query = createPQExpBuffer();
    1800             : 
    1801             :     /*
    1802             :      * this might sometimes result in duplicate entries in the OID list, but
    1803             :      * we don't care.
    1804             :      */
    1805             : 
    1806         118 :     for (cell = patterns->head; cell; cell = cell->next)
    1807             :     {
    1808             :         PQExpBufferData dbbuf;
    1809             :         int         dotcnt;
    1810             : 
    1811             :         /*
    1812             :          * Query must remain ABSOLUTELY devoid of unqualified names.  This
    1813             :          * would be unnecessary given a pg_table_is_visible() variant taking a
    1814             :          * search_path argument.
    1815             :          *
    1816             :          * For with_child_tables, we start with the basic query's results and
    1817             :          * recursively search the inheritance tree to add child tables.
    1818             :          */
    1819          70 :         if (with_child_tables)
    1820             :         {
    1821          12 :             appendPQExpBufferStr(query, "WITH RECURSIVE partition_tree (relid) AS (\n");
    1822             :         }
    1823             : 
    1824          70 :         appendPQExpBuffer(query,
    1825             :                           "SELECT c.oid"
    1826             :                           "\nFROM pg_catalog.pg_class c"
    1827             :                           "\n     LEFT JOIN pg_catalog.pg_namespace n"
    1828             :                           "\n     ON n.oid OPERATOR(pg_catalog.=) c.relnamespace"
    1829             :                           "\nWHERE c.relkind OPERATOR(pg_catalog.=) ANY"
    1830             :                           "\n    (array['%c', '%c', '%c', '%c', '%c', '%c'])\n",
    1831             :                           RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_VIEW,
    1832             :                           RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE,
    1833             :                           RELKIND_PARTITIONED_TABLE);
    1834          70 :         initPQExpBuffer(&dbbuf);
    1835          70 :         processSQLNamePattern(GetConnection(fout), query, cell->val, true,
    1836             :                               false, "n.nspname", "c.relname", NULL,
    1837             :                               "pg_catalog.pg_table_is_visible(c.oid)", &dbbuf,
    1838             :                               &dotcnt);
    1839          70 :         if (dotcnt > 2)
    1840           2 :             pg_fatal("improper relation name (too many dotted names): %s",
    1841             :                      cell->val);
    1842          68 :         else if (dotcnt == 2)
    1843           4 :             prohibit_crossdb_refs(GetConnection(fout), dbbuf.data, cell->val);
    1844          64 :         termPQExpBuffer(&dbbuf);
    1845             : 
    1846          64 :         if (with_child_tables)
    1847             :         {
    1848          12 :             appendPQExpBufferStr(query, "UNION"
    1849             :                                  "\nSELECT i.inhrelid"
    1850             :                                  "\nFROM partition_tree p"
    1851             :                                  "\n     JOIN pg_catalog.pg_inherits i"
    1852             :                                  "\n     ON p.relid OPERATOR(pg_catalog.=) i.inhparent"
    1853             :                                  "\n)"
    1854             :                                  "\nSELECT relid FROM partition_tree");
    1855             :         }
    1856             : 
    1857          64 :         ExecuteSqlStatement(fout, "RESET search_path");
    1858          64 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    1859          64 :         PQclear(ExecuteSqlQueryForSingleRow(fout,
    1860             :                                             ALWAYS_SECURE_SEARCH_PATH_SQL));
    1861          64 :         if (strict_names && PQntuples(res) == 0)
    1862           4 :             pg_fatal("no matching tables were found for pattern \"%s\"", cell->val);
    1863             : 
    1864         148 :         for (i = 0; i < PQntuples(res); i++)
    1865             :         {
    1866          88 :             simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
    1867             :         }
    1868             : 
    1869          60 :         PQclear(res);
    1870          60 :         resetPQExpBuffer(query);
    1871             :     }
    1872             : 
    1873          48 :     destroyPQExpBuffer(query);
    1874             : }
    1875             : 
    1876             : /*
    1877             :  * Verifies that the connected database name matches the given database name,
    1878             :  * and if not, dies with an error about the given pattern.
    1879             :  *
    1880             :  * The 'dbname' argument should be a literal name parsed from 'pattern'.
    1881             :  */
    1882             : static void
    1883          10 : prohibit_crossdb_refs(PGconn *conn, const char *dbname, const char *pattern)
    1884             : {
    1885             :     const char *db;
    1886             : 
    1887          10 :     db = PQdb(conn);
    1888          10 :     if (db == NULL)
    1889           0 :         pg_fatal("You are currently not connected to a database.");
    1890             : 
    1891          10 :     if (strcmp(db, dbname) != 0)
    1892          10 :         pg_fatal("cross-database references are not implemented: %s",
    1893             :                  pattern);
    1894           0 : }
    1895             : 
    1896             : /*
    1897             :  * checkExtensionMembership
    1898             :  *      Determine whether object is an extension member, and if so,
    1899             :  *      record an appropriate dependency and set the object's dump flag.
    1900             :  *
    1901             :  * It's important to call this for each object that could be an extension
    1902             :  * member.  Generally, we integrate this with determining the object's
    1903             :  * to-be-dumped-ness, since extension membership overrides other rules for that.
    1904             :  *
    1905             :  * Returns true if object is an extension member, else false.
    1906             :  */
    1907             : static bool
    1908     1476554 : checkExtensionMembership(DumpableObject *dobj, Archive *fout)
    1909             : {
    1910     1476554 :     ExtensionInfo *ext = findOwningExtension(dobj->catId);
    1911             : 
    1912     1476554 :     if (ext == NULL)
    1913     1474900 :         return false;
    1914             : 
    1915        1654 :     dobj->ext_member = true;
    1916             : 
    1917             :     /* Record dependency so that getDependencies needn't deal with that */
    1918        1654 :     addObjectDependency(dobj, ext->dobj.dumpId);
    1919             : 
    1920             :     /*
    1921             :      * In 9.6 and above, mark the member object to have any non-initial ACLs
    1922             :      * dumped.  (Any initial ACLs will be removed later, using data from
    1923             :      * pg_init_privs, so that we'll dump only the delta from the extension's
    1924             :      * initial setup.)
    1925             :      *
    1926             :      * Prior to 9.6, we do not include any extension member components.
    1927             :      *
    1928             :      * In binary upgrades, we still dump all components of the members
    1929             :      * individually, since the idea is to exactly reproduce the database
    1930             :      * contents rather than replace the extension contents with something
    1931             :      * different.
    1932             :      *
    1933             :      * Note: it might be interesting someday to implement storage and delta
    1934             :      * dumping of extension members' RLS policies and/or security labels.
    1935             :      * However there is a pitfall for RLS policies: trying to dump them
    1936             :      * requires getting a lock on their tables, and the calling user might not
    1937             :      * have privileges for that.  We need no lock to examine a table's ACLs,
    1938             :      * so the current feature doesn't have a problem of that sort.
    1939             :      */
    1940        1654 :     if (fout->dopt->binary_upgrade)
    1941         288 :         dobj->dump = ext->dobj.dump;
    1942             :     else
    1943             :     {
    1944        1366 :         if (fout->remoteVersion < 90600)
    1945           0 :             dobj->dump = DUMP_COMPONENT_NONE;
    1946             :         else
    1947        1366 :             dobj->dump = ext->dobj.dump_contains & (DUMP_COMPONENT_ACL);
    1948             :     }
    1949             : 
    1950        1654 :     return true;
    1951             : }
    1952             : 
    1953             : /*
    1954             :  * selectDumpableNamespace: policy-setting subroutine
    1955             :  *      Mark a namespace as to be dumped or not
    1956             :  */
    1957             : static void
    1958        3892 : selectDumpableNamespace(NamespaceInfo *nsinfo, Archive *fout)
    1959             : {
    1960             :     /*
    1961             :      * DUMP_COMPONENT_DEFINITION typically implies a CREATE SCHEMA statement
    1962             :      * and (for --clean) a DROP SCHEMA statement.  (In the absence of
    1963             :      * DUMP_COMPONENT_DEFINITION, this value is irrelevant.)
    1964             :      */
    1965        3892 :     nsinfo->create = true;
    1966             : 
    1967             :     /*
    1968             :      * If specific tables are being dumped, do not dump any complete
    1969             :      * namespaces. If specific namespaces are being dumped, dump just those
    1970             :      * namespaces. Otherwise, dump all non-system namespaces.
    1971             :      */
    1972        3892 :     if (table_include_oids.head != NULL)
    1973         100 :         nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
    1974        3792 :     else if (schema_include_oids.head != NULL)
    1975         366 :         nsinfo->dobj.dump_contains = nsinfo->dobj.dump =
    1976         366 :             simple_oid_list_member(&schema_include_oids,
    1977             :                                    nsinfo->dobj.catId.oid) ?
    1978         366 :             DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
    1979        3426 :     else if (fout->remoteVersion >= 90600 &&
    1980        3426 :              strcmp(nsinfo->dobj.name, "pg_catalog") == 0)
    1981             :     {
    1982             :         /*
    1983             :          * In 9.6 and above, we dump out any ACLs defined in pg_catalog, if
    1984             :          * they are interesting (and not the original ACLs which were set at
    1985             :          * initdb time, see pg_init_privs).
    1986             :          */
    1987         426 :         nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_ACL;
    1988             :     }
    1989        3000 :     else if (strncmp(nsinfo->dobj.name, "pg_", 3) == 0 ||
    1990        1286 :              strcmp(nsinfo->dobj.name, "information_schema") == 0)
    1991             :     {
    1992             :         /* Other system schemas don't get dumped */
    1993        2140 :         nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
    1994             :     }
    1995         860 :     else if (strcmp(nsinfo->dobj.name, "public") == 0)
    1996             :     {
    1997             :         /*
    1998             :          * The public schema is a strange beast that sits in a sort of
    1999             :          * no-mans-land between being a system object and a user object.
    2000             :          * CREATE SCHEMA would fail, so its DUMP_COMPONENT_DEFINITION is just
    2001             :          * a comment and an indication of ownership.  If the owner is the
    2002             :          * default, omit that superfluous DUMP_COMPONENT_DEFINITION.  Before
    2003             :          * v15, the default owner was BOOTSTRAP_SUPERUSERID.
    2004             :          */
    2005         418 :         nsinfo->create = false;
    2006         418 :         nsinfo->dobj.dump = DUMP_COMPONENT_ALL;
    2007         418 :         if (nsinfo->nspowner == ROLE_PG_DATABASE_OWNER)
    2008         326 :             nsinfo->dobj.dump &= ~DUMP_COMPONENT_DEFINITION;
    2009         418 :         nsinfo->dobj.dump_contains = DUMP_COMPONENT_ALL;
    2010             : 
    2011             :         /*
    2012             :          * Also, make like it has a comment even if it doesn't; this is so
    2013             :          * that we'll emit a command to drop the comment, if appropriate.
    2014             :          * (Without this, we'd not call dumpCommentExtended for it.)
    2015             :          */
    2016         418 :         nsinfo->dobj.components |= DUMP_COMPONENT_COMMENT;
    2017             :     }
    2018             :     else
    2019         442 :         nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_ALL;
    2020             : 
    2021             :     /*
    2022             :      * In any case, a namespace can be excluded by an exclusion switch
    2023             :      */
    2024        5200 :     if (nsinfo->dobj.dump_contains &&
    2025        1308 :         simple_oid_list_member(&schema_exclude_oids,
    2026             :                                nsinfo->dobj.catId.oid))
    2027           6 :         nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
    2028             : 
    2029             :     /*
    2030             :      * If the schema belongs to an extension, allow extension membership to
    2031             :      * override the dump decision for the schema itself.  However, this does
    2032             :      * not change dump_contains, so this won't change what we do with objects
    2033             :      * within the schema.  (If they belong to the extension, they'll get
    2034             :      * suppressed by it, otherwise not.)
    2035             :      */
    2036        3892 :     (void) checkExtensionMembership(&nsinfo->dobj, fout);
    2037        3892 : }
    2038             : 
    2039             : /*
    2040             :  * selectDumpableTable: policy-setting subroutine
    2041             :  *      Mark a table as to be dumped or not
    2042             :  */
    2043             : static void
    2044      123860 : selectDumpableTable(TableInfo *tbinfo, Archive *fout)
    2045             : {
    2046      123860 :     if (checkExtensionMembership(&tbinfo->dobj, fout))
    2047         450 :         return;                 /* extension membership overrides all else */
    2048             : 
    2049             :     /*
    2050             :      * If specific tables are being dumped, dump just those tables; else, dump
    2051             :      * according to the parent namespace's dump flag.
    2052             :      */
    2053      123410 :     if (table_include_oids.head != NULL)
    2054       10320 :         tbinfo->dobj.dump = simple_oid_list_member(&table_include_oids,
    2055             :                                                    tbinfo->dobj.catId.oid) ?
    2056        5160 :             DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
    2057             :     else
    2058      118250 :         tbinfo->dobj.dump = tbinfo->dobj.namespace->dobj.dump_contains;
    2059             : 
    2060             :     /*
    2061             :      * In any case, a table can be excluded by an exclusion switch
    2062             :      */
    2063      204666 :     if (tbinfo->dobj.dump &&
    2064       81256 :         simple_oid_list_member(&table_exclude_oids,
    2065             :                                tbinfo->dobj.catId.oid))
    2066          24 :         tbinfo->dobj.dump = DUMP_COMPONENT_NONE;
    2067             : }
    2068             : 
    2069             : /*
    2070             :  * selectDumpableType: policy-setting subroutine
    2071             :  *      Mark a type as to be dumped or not
    2072             :  *
    2073             :  * If it's a table's rowtype or an autogenerated array type, we also apply a
    2074             :  * special type code to facilitate sorting into the desired order.  (We don't
    2075             :  * want to consider those to be ordinary types because that would bring tables
    2076             :  * up into the datatype part of the dump order.)  We still set the object's
    2077             :  * dump flag; that's not going to cause the dummy type to be dumped, but we
    2078             :  * need it so that casts involving such types will be dumped correctly -- see
    2079             :  * dumpCast.  This means the flag should be set the same as for the underlying
    2080             :  * object (the table or base type).
    2081             :  */
    2082             : static void
    2083      339894 : selectDumpableType(TypeInfo *tyinfo, Archive *fout)
    2084             : {
    2085             :     /* skip complex types, except for standalone composite types */
    2086      339894 :     if (OidIsValid(tyinfo->typrelid) &&
    2087      122160 :         tyinfo->typrelkind != RELKIND_COMPOSITE_TYPE)
    2088             :     {
    2089      121692 :         TableInfo  *tytable = findTableByOid(tyinfo->typrelid);
    2090             : 
    2091      121692 :         tyinfo->dobj.objType = DO_DUMMY_TYPE;
    2092      121692 :         if (tytable != NULL)
    2093      121692 :             tyinfo->dobj.dump = tytable->dobj.dump;
    2094             :         else
    2095           0 :             tyinfo->dobj.dump = DUMP_COMPONENT_NONE;
    2096      121692 :         return;
    2097             :     }
    2098             : 
    2099             :     /* skip auto-generated array and multirange types */
    2100      218202 :     if (tyinfo->isArray || tyinfo->isMultirange)
    2101             :     {
    2102      166226 :         tyinfo->dobj.objType = DO_DUMMY_TYPE;
    2103             : 
    2104             :         /*
    2105             :          * Fall through to set the dump flag; we assume that the subsequent
    2106             :          * rules will do the same thing as they would for the array's base
    2107             :          * type or multirange's range type.  (We cannot reliably look up the
    2108             :          * base type here, since getTypes may not have processed it yet.)
    2109             :          */
    2110             :     }
    2111             : 
    2112      218202 :     if (checkExtensionMembership(&tyinfo->dobj, fout))
    2113         300 :         return;                 /* extension membership overrides all else */
    2114             : 
    2115             :     /* Dump based on if the contents of the namespace are being dumped */
    2116      217902 :     tyinfo->dobj.dump = tyinfo->dobj.namespace->dobj.dump_contains;
    2117             : }
    2118             : 
    2119             : /*
    2120             :  * selectDumpableDefaultACL: policy-setting subroutine
    2121             :  *      Mark a default ACL as to be dumped or not
    2122             :  *
    2123             :  * For per-schema default ACLs, dump if the schema is to be dumped.
    2124             :  * Otherwise dump if we are dumping "everything".  Note that dumpSchema
    2125             :  * and aclsSkip are checked separately.
    2126             :  */
    2127             : static void
    2128         392 : selectDumpableDefaultACL(DefaultACLInfo *dinfo, DumpOptions *dopt)
    2129             : {
    2130             :     /* Default ACLs can't be extension members */
    2131             : 
    2132         392 :     if (dinfo->dobj.namespace)
    2133             :         /* default ACLs are considered part of the namespace */
    2134         196 :         dinfo->dobj.dump = dinfo->dobj.namespace->dobj.dump_contains;
    2135             :     else
    2136         196 :         dinfo->dobj.dump = dopt->include_everything ?
    2137         196 :             DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
    2138         392 : }
    2139             : 
    2140             : /*
    2141             :  * selectDumpableCast: policy-setting subroutine
    2142             :  *      Mark a cast as to be dumped or not
    2143             :  *
    2144             :  * Casts do not belong to any particular namespace (since they haven't got
    2145             :  * names), nor do they have identifiable owners.  To distinguish user-defined
    2146             :  * casts from built-in ones, we must resort to checking whether the cast's
    2147             :  * OID is in the range reserved for initdb.
    2148             :  */
    2149             : static void
    2150      110666 : selectDumpableCast(CastInfo *cast, Archive *fout)
    2151             : {
    2152      110666 :     if (checkExtensionMembership(&cast->dobj, fout))
    2153           0 :         return;                 /* extension membership overrides all else */
    2154             : 
    2155             :     /*
    2156             :      * This would be DUMP_COMPONENT_ACL for from-initdb casts, but they do not
    2157             :      * support ACLs currently.
    2158             :      */
    2159      110666 :     if (cast->dobj.catId.oid <= (Oid) g_last_builtin_oid)
    2160      110448 :         cast->dobj.dump = DUMP_COMPONENT_NONE;
    2161             :     else
    2162         218 :         cast->dobj.dump = fout->dopt->include_everything ?
    2163         218 :             DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
    2164             : }
    2165             : 
    2166             : /*
    2167             :  * selectDumpableProcLang: policy-setting subroutine
    2168             :  *      Mark a procedural language as to be dumped or not
    2169             :  *
    2170             :  * Procedural languages do not belong to any particular namespace.  To
    2171             :  * identify built-in languages, we must resort to checking whether the
    2172             :  * language's OID is in the range reserved for initdb.
    2173             :  */
    2174             : static void
    2175         566 : selectDumpableProcLang(ProcLangInfo *plang, Archive *fout)
    2176             : {
    2177         566 :     if (checkExtensionMembership(&plang->dobj, fout))
    2178         468 :         return;                 /* extension membership overrides all else */
    2179             : 
    2180             :     /*
    2181             :      * Only include procedural languages when we are dumping everything.
    2182             :      *
    2183             :      * For from-initdb procedural languages, only include ACLs, as we do for
    2184             :      * the pg_catalog namespace.  We need this because procedural languages do
    2185             :      * not live in any namespace.
    2186             :      */
    2187          98 :     if (!fout->dopt->include_everything)
    2188          16 :         plang->dobj.dump = DUMP_COMPONENT_NONE;
    2189             :     else
    2190             :     {
    2191          82 :         if (plang->dobj.catId.oid <= (Oid) g_last_builtin_oid)
    2192           0 :             plang->dobj.dump = fout->remoteVersion < 90600 ?
    2193           0 :                 DUMP_COMPONENT_NONE : DUMP_COMPONENT_ACL;
    2194             :         else
    2195          82 :             plang->dobj.dump = DUMP_COMPONENT_ALL;
    2196             :     }
    2197             : }
    2198             : 
    2199             : /*
    2200             :  * selectDumpableAccessMethod: policy-setting subroutine
    2201             :  *      Mark an access method as to be dumped or not
    2202             :  *
    2203             :  * Access methods do not belong to any particular namespace.  To identify
    2204             :  * built-in access methods, we must resort to checking whether the
    2205             :  * method's OID is in the range reserved for initdb.
    2206             :  */
    2207             : static void
    2208        3542 : selectDumpableAccessMethod(AccessMethodInfo *method, Archive *fout)
    2209             : {
    2210        3542 :     if (checkExtensionMembership(&method->dobj, fout))
    2211          50 :         return;                 /* extension membership overrides all else */
    2212             : 
    2213             :     /*
    2214             :      * This would be DUMP_COMPONENT_ACL for from-initdb access methods, but
    2215             :      * they do not support ACLs currently.
    2216             :      */
    2217        3492 :     if (method->dobj.catId.oid <= (Oid) g_last_builtin_oid)
    2218        3276 :         method->dobj.dump = DUMP_COMPONENT_NONE;
    2219             :     else
    2220         216 :         method->dobj.dump = fout->dopt->include_everything ?
    2221         216 :             DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
    2222             : }
    2223             : 
    2224             : /*
    2225             :  * selectDumpableExtension: policy-setting subroutine
    2226             :  *      Mark an extension as to be dumped or not
    2227             :  *
    2228             :  * Built-in extensions should be skipped except for checking ACLs, since we
    2229             :  * assume those will already be installed in the target database.  We identify
    2230             :  * such extensions by their having OIDs in the range reserved for initdb.
    2231             :  * We dump all user-added extensions by default.  No extensions are dumped
    2232             :  * if include_everything is false (i.e., a --schema or --table switch was
    2233             :  * given), except if --extension specifies a list of extensions to dump.
    2234             :  */
    2235             : static void
    2236         520 : selectDumpableExtension(ExtensionInfo *extinfo, DumpOptions *dopt)
    2237             : {
    2238             :     /*
    2239             :      * Use DUMP_COMPONENT_ACL for built-in extensions, to allow users to
    2240             :      * change permissions on their member objects, if they wish to, and have
    2241             :      * those changes preserved.
    2242             :      */
    2243         520 :     if (extinfo->dobj.catId.oid <= (Oid) g_last_builtin_oid)
    2244         470 :         extinfo->dobj.dump = extinfo->dobj.dump_contains = DUMP_COMPONENT_ACL;
    2245             :     else
    2246             :     {
    2247             :         /* check if there is a list of extensions to dump */
    2248          50 :         if (extension_include_oids.head != NULL)
    2249           8 :             extinfo->dobj.dump = extinfo->dobj.dump_contains =
    2250           8 :                 simple_oid_list_member(&extension_include_oids,
    2251             :                                        extinfo->dobj.catId.oid) ?
    2252           8 :                 DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
    2253             :         else
    2254          42 :             extinfo->dobj.dump = extinfo->dobj.dump_contains =
    2255          42 :                 dopt->include_everything ?
    2256          42 :                 DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
    2257             : 
    2258             :         /* check that the extension is not explicitly excluded */
    2259          92 :         if (extinfo->dobj.dump &&
    2260          42 :             simple_oid_list_member(&extension_exclude_oids,
    2261             :                                    extinfo->dobj.catId.oid))
    2262           4 :             extinfo->dobj.dump = extinfo->dobj.dump_contains = DUMP_COMPONENT_NONE;
    2263             :     }
    2264         520 : }
    2265             : 
    2266             : /*
    2267             :  * selectDumpablePublicationObject: policy-setting subroutine
    2268             :  *      Mark a publication object as to be dumped or not
    2269             :  *
    2270             :  * A publication can have schemas and tables which have schemas, but those are
    2271             :  * ignored in decision making, because publications are only dumped when we are
    2272             :  * dumping everything.
    2273             :  */
    2274             : static void
    2275         882 : selectDumpablePublicationObject(DumpableObject *dobj, Archive *fout)
    2276             : {
    2277         882 :     if (checkExtensionMembership(dobj, fout))
    2278           0 :         return;                 /* extension membership overrides all else */
    2279             : 
    2280         882 :     dobj->dump = fout->dopt->include_everything ?
    2281         882 :         DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
    2282             : }
    2283             : 
    2284             : /*
    2285             :  * selectDumpableStatisticsObject: policy-setting subroutine
    2286             :  *      Mark an extended statistics object as to be dumped or not
    2287             :  *
    2288             :  * We dump an extended statistics object if the schema it's in and the table
    2289             :  * it's for are being dumped.  (This'll need more thought if statistics
    2290             :  * objects ever support cross-table stats.)
    2291             :  */
    2292             : static void
    2293         374 : selectDumpableStatisticsObject(StatsExtInfo *sobj, Archive *fout)
    2294             : {
    2295         374 :     if (checkExtensionMembership(&sobj->dobj, fout))
    2296           0 :         return;                 /* extension membership overrides all else */
    2297             : 
    2298         374 :     sobj->dobj.dump = sobj->dobj.namespace->dobj.dump_contains;
    2299         374 :     if (sobj->stattable == NULL ||
    2300         374 :         !(sobj->stattable->dobj.dump & DUMP_COMPONENT_DEFINITION))
    2301          56 :         sobj->dobj.dump = DUMP_COMPONENT_NONE;
    2302             : }
    2303             : 
    2304             : /*
    2305             :  * selectDumpableObject: policy-setting subroutine
    2306             :  *      Mark a generic dumpable object as to be dumped or not
    2307             :  *
    2308             :  * Use this only for object types without a special-case routine above.
    2309             :  */
    2310             : static void
    2311     1014570 : selectDumpableObject(DumpableObject *dobj, Archive *fout)
    2312             : {
    2313     1014570 :     if (checkExtensionMembership(dobj, fout))
    2314         336 :         return;                 /* extension membership overrides all else */
    2315             : 
    2316             :     /*
    2317             :      * Default policy is to dump if parent namespace is dumpable, or for
    2318             :      * non-namespace-associated items, dump if we're dumping "everything".
    2319             :      */
    2320     1014234 :     if (dobj->namespace)
    2321     1012896 :         dobj->dump = dobj->namespace->dobj.dump_contains;
    2322             :     else
    2323        1338 :         dobj->dump = fout->dopt->include_everything ?
    2324        1338 :             DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
    2325             : }
    2326             : 
    2327             : /*
    2328             :  *  Dump a table's contents for loading using the COPY command
    2329             :  *  - this routine is called by the Archiver when it wants the table
    2330             :  *    to be dumped.
    2331             :  */
    2332             : static int
    2333       12272 : dumpTableData_copy(Archive *fout, const void *dcontext)
    2334             : {
    2335       12272 :     TableDataInfo *tdinfo = (TableDataInfo *) dcontext;
    2336       12272 :     TableInfo  *tbinfo = tdinfo->tdtable;
    2337       12272 :     const char *classname = tbinfo->dobj.name;
    2338       12272 :     PQExpBuffer q = createPQExpBuffer();
    2339             : 
    2340             :     /*
    2341             :      * Note: can't use getThreadLocalPQExpBuffer() here, we're calling fmtId
    2342             :      * which uses it already.
    2343             :      */
    2344       12272 :     PQExpBuffer clistBuf = createPQExpBuffer();
    2345       12272 :     PGconn     *conn = GetConnection(fout);
    2346             :     PGresult   *res;
    2347             :     int         ret;
    2348             :     char       *copybuf;
    2349             :     const char *column_list;
    2350             : 
    2351       12272 :     pg_log_info("dumping contents of table \"%s.%s\"",
    2352             :                 tbinfo->dobj.namespace->dobj.name, classname);
    2353             : 
    2354             :     /*
    2355             :      * Specify the column list explicitly so that we have no possibility of
    2356             :      * retrieving data in the wrong column order.  (The default column
    2357             :      * ordering of COPY will not be what we want in certain corner cases
    2358             :      * involving ADD COLUMN and inheritance.)
    2359             :      */
    2360       12272 :     column_list = fmtCopyColumnList(tbinfo, clistBuf);
    2361             : 
    2362             :     /*
    2363             :      * Use COPY (SELECT ...) TO when dumping a foreign table's data, and when
    2364             :      * a filter condition was specified.  For other cases a simple COPY
    2365             :      * suffices.
    2366             :      */
    2367       12272 :     if (tdinfo->filtercond || tbinfo->relkind == RELKIND_FOREIGN_TABLE)
    2368             :     {
    2369             :         /* Temporary allows to access to foreign tables to dump data */
    2370          64 :         if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
    2371           2 :             set_restrict_relation_kind(fout, "view");
    2372             : 
    2373          64 :         appendPQExpBufferStr(q, "COPY (SELECT ");
    2374             :         /* klugery to get rid of parens in column list */
    2375          64 :         if (strlen(column_list) > 2)
    2376             :         {
    2377          64 :             appendPQExpBufferStr(q, column_list + 1);
    2378          64 :             q->data[q->len - 1] = ' ';
    2379             :         }
    2380             :         else
    2381           0 :             appendPQExpBufferStr(q, "* ");
    2382             : 
    2383         128 :         appendPQExpBuffer(q, "FROM %s %s) TO stdout;",
    2384          64 :                           fmtQualifiedDumpable(tbinfo),
    2385          64 :                           tdinfo->filtercond ? tdinfo->filtercond : "");
    2386             :     }
    2387             :     else
    2388             :     {
    2389       12208 :         appendPQExpBuffer(q, "COPY %s %s TO stdout;",
    2390       12208 :                           fmtQualifiedDumpable(tbinfo),
    2391             :                           column_list);
    2392             :     }
    2393       12272 :     res = ExecuteSqlQuery(fout, q->data, PGRES_COPY_OUT);
    2394       12270 :     PQclear(res);
    2395       12270 :     destroyPQExpBuffer(clistBuf);
    2396             : 
    2397             :     for (;;)
    2398             :     {
    2399     6136478 :         ret = PQgetCopyData(conn, &copybuf, 0);
    2400             : 
    2401     6136478 :         if (ret < 0)
    2402       12270 :             break;              /* done or error */
    2403             : 
    2404     6124208 :         if (copybuf)
    2405             :         {
    2406     6124208 :             WriteData(fout, copybuf, ret);
    2407     6124208 :             PQfreemem(copybuf);
    2408             :         }
    2409             : 
    2410             :         /* ----------
    2411             :          * THROTTLE:
    2412             :          *
    2413             :          * There was considerable discussion in late July, 2000 regarding
    2414             :          * slowing down pg_dump when backing up large tables. Users with both
    2415             :          * slow & fast (multi-processor) machines experienced performance
    2416             :          * degradation when doing a backup.
    2417             :          *
    2418             :          * Initial attempts based on sleeping for a number of ms for each ms
    2419             :          * of work were deemed too complex, then a simple 'sleep in each loop'
    2420             :          * implementation was suggested. The latter failed because the loop
    2421             :          * was too tight. Finally, the following was implemented:
    2422             :          *
    2423             :          * If throttle is non-zero, then
    2424             :          *      See how long since the last sleep.
    2425             :          *      Work out how long to sleep (based on ratio).
    2426             :          *      If sleep is more than 100ms, then
    2427             :          *          sleep
    2428             :          *          reset timer
    2429             :          *      EndIf
    2430             :          * EndIf
    2431             :          *
    2432             :          * where the throttle value was the number of ms to sleep per ms of
    2433             :          * work. The calculation was done in each loop.
    2434             :          *
    2435             :          * Most of the hard work is done in the backend, and this solution
    2436             :          * still did not work particularly well: on slow machines, the ratio
    2437             :          * was 50:1, and on medium paced machines, 1:1, and on fast
    2438             :          * multi-processor machines, it had little or no effect, for reasons
    2439             :          * that were unclear.
    2440             :          *
    2441             :          * Further discussion ensued, and the proposal was dropped.
    2442             :          *
    2443             :          * For those people who want this feature, it can be implemented using
    2444             :          * gettimeofday in each loop, calculating the time since last sleep,
    2445             :          * multiplying that by the sleep ratio, then if the result is more
    2446             :          * than a preset 'minimum sleep time' (say 100ms), call the 'select'
    2447             :          * function to sleep for a subsecond period ie.
    2448             :          *
    2449             :          * select(0, NULL, NULL, NULL, &tvi);
    2450             :          *
    2451             :          * This will return after the interval specified in the structure tvi.
    2452             :          * Finally, call gettimeofday again to save the 'last sleep time'.
    2453             :          * ----------
    2454             :          */
    2455             :     }
    2456       12270 :     archprintf(fout, "\\.\n\n\n");
    2457             : 
    2458       12270 :     if (ret == -2)
    2459             :     {
    2460             :         /* copy data transfer failed */
    2461           0 :         pg_log_error("Dumping the contents of table \"%s\" failed: PQgetCopyData() failed.", classname);
    2462           0 :         pg_log_error_detail("Error message from server: %s", PQerrorMessage(conn));
    2463           0 :         pg_log_error_detail("Command was: %s", q->data);
    2464           0 :         exit_nicely(1);
    2465             :     }
    2466             : 
    2467             :     /* Check command status and return to normal libpq state */
    2468       12270 :     res = PQgetResult(conn);
    2469       12270 :     if (PQresultStatus(res) != PGRES_COMMAND_OK)
    2470             :     {
    2471           0 :         pg_log_error("Dumping the contents of table \"%s\" failed: PQgetResult() failed.", classname);
    2472           0 :         pg_log_error_detail("Error message from server: %s", PQerrorMessage(conn));
    2473           0 :         pg_log_error_detail("Command was: %s", q->data);
    2474           0 :         exit_nicely(1);
    2475             :     }
    2476       12270 :     PQclear(res);
    2477             : 
    2478             :     /* Do this to ensure we've pumped libpq back to idle state */
    2479       12270 :     if (PQgetResult(conn) != NULL)
    2480           0 :         pg_log_warning("unexpected extra results during COPY of table \"%s\"",
    2481             :                        classname);
    2482             : 
    2483       12270 :     destroyPQExpBuffer(q);
    2484             : 
    2485             :     /* Revert back the setting */
    2486       12270 :     if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
    2487           0 :         set_restrict_relation_kind(fout, "view, foreign-table");
    2488             : 
    2489       12270 :     return 1;
    2490             : }
    2491             : 
    2492             : /*
    2493             :  * Dump table data using INSERT commands.
    2494             :  *
    2495             :  * Caution: when we restore from an archive file direct to database, the
    2496             :  * INSERT commands emitted by this function have to be parsed by
    2497             :  * pg_backup_db.c's ExecuteSimpleCommands(), which will not handle comments,
    2498             :  * E'' strings, or dollar-quoted strings.  So don't emit anything like that.
    2499             :  */
    2500             : static int
    2501         162 : dumpTableData_insert(Archive *fout, const void *dcontext)
    2502             : {
    2503         162 :     TableDataInfo *tdinfo = (TableDataInfo *) dcontext;
    2504         162 :     TableInfo  *tbinfo = tdinfo->tdtable;
    2505         162 :     DumpOptions *dopt = fout->dopt;
    2506         162 :     PQExpBuffer q = createPQExpBuffer();
    2507         162 :     PQExpBuffer insertStmt = NULL;
    2508             :     char       *attgenerated;
    2509             :     PGresult   *res;
    2510             :     int         nfields,
    2511             :                 i;
    2512         162 :     int         rows_per_statement = dopt->dump_inserts;
    2513         162 :     int         rows_this_statement = 0;
    2514             : 
    2515             :     /* Temporary allows to access to foreign tables to dump data */
    2516         162 :     if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
    2517           0 :         set_restrict_relation_kind(fout, "view");
    2518             : 
    2519             :     /*
    2520             :      * If we're going to emit INSERTs with column names, the most efficient
    2521             :      * way to deal with generated columns is to exclude them entirely.  For
    2522             :      * INSERTs without column names, we have to emit DEFAULT rather than the
    2523             :      * actual column value --- but we can save a few cycles by fetching nulls
    2524             :      * rather than the uninteresting-to-us value.
    2525             :      */
    2526         162 :     attgenerated = (char *) pg_malloc(tbinfo->numatts * sizeof(char));
    2527         162 :     appendPQExpBufferStr(q, "DECLARE _pg_dump_cursor CURSOR FOR SELECT ");
    2528         162 :     nfields = 0;
    2529         506 :     for (i = 0; i < tbinfo->numatts; i++)
    2530             :     {
    2531         344 :         if (tbinfo->attisdropped[i])
    2532           4 :             continue;
    2533         340 :         if (tbinfo->attgenerated[i] && dopt->column_inserts)
    2534          16 :             continue;
    2535         324 :         if (nfields > 0)
    2536         176 :             appendPQExpBufferStr(q, ", ");
    2537         324 :         if (tbinfo->attgenerated[i])
    2538          16 :             appendPQExpBufferStr(q, "NULL");
    2539             :         else
    2540         308 :             appendPQExpBufferStr(q, fmtId(tbinfo->attnames[i]));
    2541         324 :         attgenerated[nfields] = tbinfo->attgenerated[i];
    2542         324 :         nfields++;
    2543             :     }
    2544             :     /* Servers before 9.4 will complain about zero-column SELECT */
    2545         162 :     if (nfields == 0)
    2546          14 :         appendPQExpBufferStr(q, "NULL");
    2547         162 :     appendPQExpBuffer(q, " FROM ONLY %s",
    2548         162 :                       fmtQualifiedDumpable(tbinfo));
    2549         162 :     if (tdinfo->filtercond)
    2550           0 :         appendPQExpBuffer(q, " %s", tdinfo->filtercond);
    2551             : 
    2552         162 :     ExecuteSqlStatement(fout, q->data);
    2553             : 
    2554             :     while (1)
    2555             :     {
    2556         266 :         res = ExecuteSqlQuery(fout, "FETCH 100 FROM _pg_dump_cursor",
    2557             :                               PGRES_TUPLES_OK);
    2558             : 
    2559             :         /* cross-check field count, allowing for dummy NULL if any */
    2560         266 :         if (nfields != PQnfields(res) &&
    2561          20 :             !(nfields == 0 && PQnfields(res) == 1))
    2562           0 :             pg_fatal("wrong number of fields retrieved from table \"%s\"",
    2563             :                      tbinfo->dobj.name);
    2564             : 
    2565             :         /*
    2566             :          * First time through, we build as much of the INSERT statement as
    2567             :          * possible in "insertStmt", which we can then just print for each
    2568             :          * statement. If the table happens to have zero dumpable columns then
    2569             :          * this will be a complete statement, otherwise it will end in
    2570             :          * "VALUES" and be ready to have the row's column values printed.
    2571             :          */
    2572         266 :         if (insertStmt == NULL)
    2573             :         {
    2574             :             TableInfo  *targettab;
    2575             : 
    2576         162 :             insertStmt = createPQExpBuffer();
    2577             : 
    2578             :             /*
    2579             :              * When load-via-partition-root is set or forced, get the root
    2580             :              * table name for the partition table, so that we can reload data
    2581             :              * through the root table.
    2582             :              */
    2583         162 :             if (tbinfo->ispartition &&
    2584          80 :                 (dopt->load_via_partition_root ||
    2585          40 :                  forcePartitionRootLoad(tbinfo)))
    2586           6 :                 targettab = getRootTableInfo(tbinfo);
    2587             :             else
    2588         156 :                 targettab = tbinfo;
    2589             : 
    2590         162 :             appendPQExpBuffer(insertStmt, "INSERT INTO %s ",
    2591         162 :                               fmtQualifiedDumpable(targettab));
    2592             : 
    2593             :             /* corner case for zero-column table */
    2594         162 :             if (nfields == 0)
    2595             :             {
    2596          14 :                 appendPQExpBufferStr(insertStmt, "DEFAULT VALUES;\n");
    2597             :             }
    2598             :             else
    2599             :             {
    2600             :                 /* append the list of column names if required */
    2601         148 :                 if (dopt->column_inserts)
    2602             :                 {
    2603          66 :                     appendPQExpBufferChar(insertStmt, '(');
    2604         202 :                     for (int field = 0; field < nfields; field++)
    2605             :                     {
    2606         136 :                         if (field > 0)
    2607          70 :                             appendPQExpBufferStr(insertStmt, ", ");
    2608         136 :                         appendPQExpBufferStr(insertStmt,
    2609         136 :                                              fmtId(PQfname(res, field)));
    2610             :                     }
    2611          66 :                     appendPQExpBufferStr(insertStmt, ") ");
    2612             :                 }
    2613             : 
    2614         148 :                 if (tbinfo->needs_override)
    2615           4 :                     appendPQExpBufferStr(insertStmt, "OVERRIDING SYSTEM VALUE ");
    2616             : 
    2617         148 :                 appendPQExpBufferStr(insertStmt, "VALUES");
    2618             :             }
    2619             :         }
    2620             : 
    2621        6808 :         for (int tuple = 0; tuple < PQntuples(res); tuple++)
    2622             :         {
    2623             :             /* Write the INSERT if not in the middle of a multi-row INSERT. */
    2624        6542 :             if (rows_this_statement == 0)
    2625        6530 :                 archputs(insertStmt->data, fout);
    2626             : 
    2627             :             /*
    2628             :              * If it is zero-column table then we've already written the
    2629             :              * complete statement, which will mean we've disobeyed
    2630             :              * --rows-per-insert when it's set greater than 1.  We do support
    2631             :              * a way to make this multi-row with: SELECT UNION ALL SELECT
    2632             :              * UNION ALL ... but that's non-standard so we should avoid it
    2633             :              * given that using INSERTs is mostly only ever needed for
    2634             :              * cross-database exports.
    2635             :              */
    2636        6542 :             if (nfields == 0)
    2637          12 :                 continue;
    2638             : 
    2639             :             /* Emit a row heading */
    2640        6530 :             if (rows_per_statement == 1)
    2641        6512 :                 archputs(" (", fout);
    2642          18 :             else if (rows_this_statement > 0)
    2643          12 :                 archputs(",\n\t(", fout);
    2644             :             else
    2645           6 :                 archputs("\n\t(", fout);
    2646             : 
    2647       19698 :             for (int field = 0; field < nfields; field++)
    2648             :             {
    2649       13168 :                 if (field > 0)
    2650        6638 :                     archputs(", ", fout);
    2651       13168 :                 if (attgenerated[field])
    2652             :                 {
    2653           4 :                     archputs("DEFAULT", fout);
    2654           4 :                     continue;
    2655             :                 }
    2656       13164 :                 if (PQgetisnull(res, tuple, field))
    2657             :                 {
    2658         166 :                     archputs("NULL", fout);
    2659         166 :                     continue;
    2660             :                 }
    2661             : 
    2662             :                 /* XXX This code is partially duplicated in ruleutils.c */
    2663       12998 :                 switch (PQftype(res, field))
    2664             :                 {
    2665        8938 :                     case INT2OID:
    2666             :                     case INT4OID:
    2667             :                     case INT8OID:
    2668             :                     case OIDOID:
    2669             :                     case FLOAT4OID:
    2670             :                     case FLOAT8OID:
    2671             :                     case NUMERICOID:
    2672             :                         {
    2673             :                             /*
    2674             :                              * These types are printed without quotes unless
    2675             :                              * they contain values that aren't accepted by the
    2676             :                              * scanner unquoted (e.g., 'NaN').  Note that
    2677             :                              * strtod() and friends might accept NaN, so we
    2678             :                              * can't use that to test.
    2679             :                              *
    2680             :                              * In reality we only need to defend against
    2681             :                              * infinity and NaN, so we need not get too crazy
    2682             :                              * about pattern matching here.
    2683             :                              */
    2684        8938 :                             const char *s = PQgetvalue(res, tuple, field);
    2685             : 
    2686        8938 :                             if (strspn(s, "0123456789 +-eE.") == strlen(s))
    2687        8934 :                                 archputs(s, fout);
    2688             :                             else
    2689           4 :                                 archprintf(fout, "'%s'", s);
    2690             :                         }
    2691        8938 :                         break;
    2692             : 
    2693           4 :                     case BITOID:
    2694             :                     case VARBITOID:
    2695           4 :                         archprintf(fout, "B'%s'",
    2696             :                                    PQgetvalue(res, tuple, field));
    2697           4 :                         break;
    2698             : 
    2699           8 :                     case BOOLOID:
    2700           8 :                         if (strcmp(PQgetvalue(res, tuple, field), "t") == 0)
    2701           4 :                             archputs("true", fout);
    2702             :                         else
    2703           4 :                             archputs("false", fout);
    2704           8 :                         break;
    2705             : 
    2706        4048 :                     default:
    2707             :                         /* All other types are printed as string literals. */
    2708        4048 :                         resetPQExpBuffer(q);
    2709        4048 :                         appendStringLiteralAH(q,
    2710             :                                               PQgetvalue(res, tuple, field),
    2711             :                                               fout);
    2712        4048 :                         archputs(q->data, fout);
    2713        4048 :                         break;
    2714             :                 }
    2715             :             }
    2716             : 
    2717             :             /* Terminate the row ... */
    2718        6530 :             archputs(")", fout);
    2719             : 
    2720             :             /* ... and the statement, if the target no. of rows is reached */
    2721        6530 :             if (++rows_this_statement >= rows_per_statement)
    2722             :             {
    2723        6516 :                 if (dopt->do_nothing)
    2724           0 :                     archputs(" ON CONFLICT DO NOTHING;\n", fout);
    2725             :                 else
    2726        6516 :                     archputs(";\n", fout);
    2727             :                 /* Reset the row counter */
    2728        6516 :                 rows_this_statement = 0;
    2729             :             }
    2730             :         }
    2731             : 
    2732         266 :         if (PQntuples(res) <= 0)
    2733             :         {
    2734         162 :             PQclear(res);
    2735         162 :             break;
    2736             :         }
    2737         104 :         PQclear(res);
    2738             :     }
    2739             : 
    2740             :     /* Terminate any statements that didn't make the row count. */
    2741         162 :     if (rows_this_statement > 0)
    2742             :     {
    2743           2 :         if (dopt->do_nothing)
    2744           0 :             archputs(" ON CONFLICT DO NOTHING;\n", fout);
    2745             :         else
    2746           2 :             archputs(";\n", fout);
    2747             :     }
    2748             : 
    2749         162 :     archputs("\n\n", fout);
    2750             : 
    2751         162 :     ExecuteSqlStatement(fout, "CLOSE _pg_dump_cursor");
    2752             : 
    2753         162 :     destroyPQExpBuffer(q);
    2754         162 :     if (insertStmt != NULL)
    2755         162 :         destroyPQExpBuffer(insertStmt);
    2756         162 :     free(attgenerated);
    2757             : 
    2758             :     /* Revert back the setting */
    2759         162 :     if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
    2760           0 :         set_restrict_relation_kind(fout, "view, foreign-table");
    2761             : 
    2762         162 :     return 1;
    2763             : }
    2764             : 
    2765             : /*
    2766             :  * getRootTableInfo:
    2767             :  *     get the root TableInfo for the given partition table.
    2768             :  */
    2769             : static TableInfo *
    2770          18 : getRootTableInfo(const TableInfo *tbinfo)
    2771             : {
    2772             :     TableInfo  *parentTbinfo;
    2773             : 
    2774             :     Assert(tbinfo->ispartition);
    2775             :     Assert(tbinfo->numParents == 1);
    2776             : 
    2777          18 :     parentTbinfo = tbinfo->parents[0];
    2778          18 :     while (parentTbinfo->ispartition)
    2779             :     {
    2780             :         Assert(parentTbinfo->numParents == 1);
    2781           0 :         parentTbinfo = parentTbinfo->parents[0];
    2782             :     }
    2783             : 
    2784          18 :     return parentTbinfo;
    2785             : }
    2786             : 
    2787             : /*
    2788             :  * forcePartitionRootLoad
    2789             :  *     Check if we must force load_via_partition_root for this partition.
    2790             :  *
    2791             :  * This is required if any level of ancestral partitioned table has an
    2792             :  * unsafe partitioning scheme.
    2793             :  */
    2794             : static bool
    2795        3060 : forcePartitionRootLoad(const TableInfo *tbinfo)
    2796             : {
    2797             :     TableInfo  *parentTbinfo;
    2798             : 
    2799             :     Assert(tbinfo->ispartition);
    2800             :     Assert(tbinfo->numParents == 1);
    2801             : 
    2802        3060 :     parentTbinfo = tbinfo->parents[0];
    2803        3060 :     if (parentTbinfo->unsafe_partitions)
    2804          18 :         return true;
    2805        3798 :     while (parentTbinfo->ispartition)
    2806             :     {
    2807             :         Assert(parentTbinfo->numParents == 1);
    2808         756 :         parentTbinfo = parentTbinfo->parents[0];
    2809         756 :         if (parentTbinfo->unsafe_partitions)
    2810           0 :             return true;
    2811             :     }
    2812             : 
    2813        3042 :     return false;
    2814             : }
    2815             : 
    2816             : /*
    2817             :  * dumpTableData -
    2818             :  *    dump the contents of a single table
    2819             :  *
    2820             :  * Actually, this just makes an ArchiveEntry for the table contents.
    2821             :  */
    2822             : static void
    2823       12594 : dumpTableData(Archive *fout, const TableDataInfo *tdinfo)
    2824             : {
    2825       12594 :     DumpOptions *dopt = fout->dopt;
    2826       12594 :     TableInfo  *tbinfo = tdinfo->tdtable;
    2827       12594 :     PQExpBuffer copyBuf = createPQExpBuffer();
    2828       12594 :     PQExpBuffer clistBuf = createPQExpBuffer();
    2829             :     DataDumperPtr dumpFn;
    2830       12594 :     char       *tdDefn = NULL;
    2831             :     char       *copyStmt;
    2832             :     const char *copyFrom;
    2833             : 
    2834             :     /* We had better have loaded per-column details about this table */
    2835             :     Assert(tbinfo->interesting);
    2836             : 
    2837             :     /*
    2838             :      * When load-via-partition-root is set or forced, get the root table name
    2839             :      * for the partition table, so that we can reload data through the root
    2840             :      * table.  Then construct a comment to be inserted into the TOC entry's
    2841             :      * defn field, so that such cases can be identified reliably.
    2842             :      */
    2843       12594 :     if (tbinfo->ispartition &&
    2844        6040 :         (dopt->load_via_partition_root ||
    2845        3020 :          forcePartitionRootLoad(tbinfo)))
    2846          12 :     {
    2847             :         TableInfo  *parentTbinfo;
    2848             : 
    2849          12 :         parentTbinfo = getRootTableInfo(tbinfo);
    2850          12 :         copyFrom = fmtQualifiedDumpable(parentTbinfo);
    2851          12 :         printfPQExpBuffer(copyBuf, "-- load via partition root %s",
    2852             :                           copyFrom);
    2853          12 :         tdDefn = pg_strdup(copyBuf->data);
    2854             :     }
    2855             :     else
    2856       12582 :         copyFrom = fmtQualifiedDumpable(tbinfo);
    2857             : 
    2858       12594 :     if (dopt->dump_inserts == 0)
    2859             :     {
    2860             :         /* Dump/restore using COPY */
    2861       12432 :         dumpFn = dumpTableData_copy;
    2862             :         /* must use 2 steps here 'cause fmtId is nonreentrant */
    2863       12432 :         printfPQExpBuffer(copyBuf, "COPY %s ",
    2864             :                           copyFrom);
    2865       12432 :         appendPQExpBuffer(copyBuf, "%s FROM stdin;\n",
    2866             :                           fmtCopyColumnList(tbinfo, clistBuf));
    2867       12432 :         copyStmt = copyBuf->data;
    2868             :     }
    2869             :     else
    2870             :     {
    2871             :         /* Restore using INSERT */
    2872         162 :         dumpFn = dumpTableData_insert;
    2873         162 :         copyStmt = NULL;
    2874             :     }
    2875             : 
    2876             :     /*
    2877             :      * Note: although the TableDataInfo is a full DumpableObject, we treat its
    2878             :      * dependency on its table as "special" and pass it to ArchiveEntry now.
    2879             :      * See comments for BuildArchiveDependencies.
    2880             :      */
    2881       12594 :     if (tdinfo->dobj.dump & DUMP_COMPONENT_DATA)
    2882             :     {
    2883             :         TocEntry   *te;
    2884             : 
    2885       12594 :         te = ArchiveEntry(fout, tdinfo->dobj.catId, tdinfo->dobj.dumpId,
    2886       12594 :                           ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
    2887             :                                        .namespace = tbinfo->dobj.namespace->dobj.name,
    2888             :                                        .owner = tbinfo->rolname,
    2889             :                                        .description = "TABLE DATA",
    2890             :                                        .section = SECTION_DATA,
    2891             :                                        .createStmt = tdDefn,
    2892             :                                        .copyStmt = copyStmt,
    2893             :                                        .deps = &(tbinfo->dobj.dumpId),
    2894             :                                        .nDeps = 1,
    2895             :                                        .dumpFn = dumpFn,
    2896             :                                        .dumpArg = tdinfo));
    2897             : 
    2898             :         /*
    2899             :          * Set the TocEntry's dataLength in case we are doing a parallel dump
    2900             :          * and want to order dump jobs by table size.  We choose to measure
    2901             :          * dataLength in table pages (including TOAST pages) during dump, so
    2902             :          * no scaling is needed.
    2903             :          *
    2904             :          * However, relpages is declared as "integer" in pg_class, and hence
    2905             :          * also in TableInfo, but it's really BlockNumber a/k/a unsigned int.
    2906             :          * Cast so that we get the right interpretation of table sizes
    2907             :          * exceeding INT_MAX pages.
    2908             :          */
    2909       12594 :         te->dataLength = (BlockNumber) tbinfo->relpages;
    2910       12594 :         te->dataLength += (BlockNumber) tbinfo->toastpages;
    2911             : 
    2912             :         /*
    2913             :          * If pgoff_t is only 32 bits wide, the above refinement is useless,
    2914             :          * and instead we'd better worry about integer overflow.  Clamp to
    2915             :          * INT_MAX if the correct result exceeds that.
    2916             :          */
    2917             :         if (sizeof(te->dataLength) == 4 &&
    2918             :             (tbinfo->relpages < 0 || tbinfo->toastpages < 0 ||
    2919             :              te->dataLength < 0))
    2920             :             te->dataLength = INT_MAX;
    2921             :     }
    2922             : 
    2923       12594 :     destroyPQExpBuffer(copyBuf);
    2924       12594 :     destroyPQExpBuffer(clistBuf);
    2925       12594 : }
    2926             : 
    2927             : /*
    2928             :  * refreshMatViewData -
    2929             :  *    load or refresh the contents of a single materialized view
    2930             :  *
    2931             :  * Actually, this just makes an ArchiveEntry for the REFRESH MATERIALIZED VIEW
    2932             :  * statement.
    2933             :  */
    2934             : static void
    2935         852 : refreshMatViewData(Archive *fout, const TableDataInfo *tdinfo)
    2936             : {
    2937         852 :     TableInfo  *tbinfo = tdinfo->tdtable;
    2938             :     PQExpBuffer q;
    2939             : 
    2940             :     /* If the materialized view is not flagged as populated, skip this. */
    2941         852 :     if (!tbinfo->relispopulated)
    2942         148 :         return;
    2943             : 
    2944         704 :     q = createPQExpBuffer();
    2945             : 
    2946         704 :     appendPQExpBuffer(q, "REFRESH MATERIALIZED VIEW %s;\n",
    2947         704 :                       fmtQualifiedDumpable(tbinfo));
    2948             : 
    2949         704 :     if (tdinfo->dobj.dump & DUMP_COMPONENT_DATA)
    2950         704 :         ArchiveEntry(fout,
    2951             :                      tdinfo->dobj.catId, /* catalog ID */
    2952         704 :                      tdinfo->dobj.dumpId,    /* dump ID */
    2953         704 :                      ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
    2954             :                                   .namespace = tbinfo->dobj.namespace->dobj.name,
    2955             :                                   .owner = tbinfo->rolname,
    2956             :                                   .description = "MATERIALIZED VIEW DATA",
    2957             :                                   .section = SECTION_POST_DATA,
    2958             :                                   .createStmt = q->data,
    2959             :                                   .deps = tdinfo->dobj.dependencies,
    2960             :                                   .nDeps = tdinfo->dobj.nDeps));
    2961             : 
    2962         704 :     destroyPQExpBuffer(q);
    2963             : }
    2964             : 
    2965             : /*
    2966             :  * getTableData -
    2967             :  *    set up dumpable objects representing the contents of tables
    2968             :  */
    2969             : static void
    2970         452 : getTableData(DumpOptions *dopt, TableInfo *tblinfo, int numTables, char relkind)
    2971             : {
    2972             :     int         i;
    2973             : 
    2974      120350 :     for (i = 0; i < numTables; i++)
    2975             :     {
    2976      119898 :         if (tblinfo[i].dobj.dump & DUMP_COMPONENT_DATA &&
    2977        1830 :             (!relkind || tblinfo[i].relkind == relkind))
    2978       17236 :             makeTableDataInfo(dopt, &(tblinfo[i]));
    2979             :     }
    2980         452 : }
    2981             : 
    2982             : /*
    2983             :  * Make a dumpable object for the data of this specific table
    2984             :  *
    2985             :  * Note: we make a TableDataInfo if and only if we are going to dump the
    2986             :  * table data; the "dump" field in such objects isn't very interesting.
    2987             :  */
    2988             : static void
    2989       17438 : makeTableDataInfo(DumpOptions *dopt, TableInfo *tbinfo)
    2990             : {
    2991             :     TableDataInfo *tdinfo;
    2992             : 
    2993             :     /*
    2994             :      * Nothing to do if we already decided to dump the table.  This will
    2995             :      * happen for "config" tables.
    2996             :      */
    2997       17438 :     if (tbinfo->dataObj != NULL)
    2998           2 :         return;
    2999             : 
    3000             :     /* Skip VIEWs (no data to dump) */
    3001       17436 :     if (tbinfo->relkind == RELKIND_VIEW)
    3002        1274 :         return;
    3003             :     /* Skip FOREIGN TABLEs (no data to dump) unless requested explicitly */
    3004       16162 :     if (tbinfo->relkind == RELKIND_FOREIGN_TABLE &&
    3005          82 :         (foreign_servers_include_oids.head == NULL ||
    3006           8 :          !simple_oid_list_member(&foreign_servers_include_oids,
    3007             :                                  tbinfo->foreign_server)))
    3008          80 :         return;
    3009             :     /* Skip partitioned tables (data in partitions) */
    3010       16082 :     if (tbinfo->relkind == RELKIND_PARTITIONED_TABLE)
    3011        1448 :         return;
    3012             : 
    3013             :     /* Don't dump data in unlogged tables, if so requested */
    3014       14634 :     if (tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED &&
    3015         136 :         dopt->no_unlogged_table_data)
    3016          36 :         return;
    3017             : 
    3018             :     /* Check that the data is not explicitly excluded */
    3019       14598 :     if (simple_oid_list_member(&tabledata_exclude_oids,
    3020             :                                tbinfo->dobj.catId.oid))
    3021          16 :         return;
    3022             : 
    3023             :     /* OK, let's dump it */
    3024       14582 :     tdinfo = (TableDataInfo *) pg_malloc(sizeof(TableDataInfo));
    3025             : 
    3026       14582 :     if (tbinfo->relkind == RELKIND_MATVIEW)
    3027         852 :         tdinfo->dobj.objType = DO_REFRESH_MATVIEW;
    3028       13730 :     else if (tbinfo->relkind == RELKIND_SEQUENCE)
    3029        1136 :         tdinfo->dobj.objType = DO_SEQUENCE_SET;
    3030             :     else
    3031       12594 :         tdinfo->dobj.objType = DO_TABLE_DATA;
    3032             : 
    3033             :     /*
    3034             :      * Note: use tableoid 0 so that this object won't be mistaken for
    3035             :      * something that pg_depend entries apply to.
    3036             :      */
    3037       14582 :     tdinfo->dobj.catId.tableoid = 0;
    3038       14582 :     tdinfo->dobj.catId.oid = tbinfo->dobj.catId.oid;
    3039       14582 :     AssignDumpId(&tdinfo->dobj);
    3040       14582 :     tdinfo->dobj.name = tbinfo->dobj.name;
    3041       14582 :     tdinfo->dobj.namespace = tbinfo->dobj.namespace;
    3042       14582 :     tdinfo->tdtable = tbinfo;
    3043       14582 :     tdinfo->filtercond = NULL;   /* might get set later */
    3044       14582 :     addObjectDependency(&tdinfo->dobj, tbinfo->dobj.dumpId);
    3045             : 
    3046             :     /* A TableDataInfo contains data, of course */
    3047       14582 :     tdinfo->dobj.components |= DUMP_COMPONENT_DATA;
    3048             : 
    3049       14582 :     tbinfo->dataObj = tdinfo;
    3050             : 
    3051             :     /*
    3052             :      * Materialized view statistics must be restored after the data, because
    3053             :      * REFRESH MATERIALIZED VIEW replaces the storage and resets the stats.
    3054             :      *
    3055             :      * The dependency is added here because the statistics objects are created
    3056             :      * first.
    3057             :      */
    3058       14582 :     if (tbinfo->relkind == RELKIND_MATVIEW && tbinfo->stats != NULL)
    3059             :     {
    3060         640 :         tbinfo->stats->section = SECTION_POST_DATA;
    3061         640 :         addObjectDependency(&tbinfo->stats->dobj, tdinfo->dobj.dumpId);
    3062             :     }
    3063             : 
    3064             :     /* Make sure that we'll collect per-column info for this table. */
    3065       14582 :     tbinfo->interesting = true;
    3066             : }
    3067             : 
    3068             : /*
    3069             :  * The refresh for a materialized view must be dependent on the refresh for
    3070             :  * any materialized view that this one is dependent on.
    3071             :  *
    3072             :  * This must be called after all the objects are created, but before they are
    3073             :  * sorted.
    3074             :  */
    3075             : static void
    3076         396 : buildMatViewRefreshDependencies(Archive *fout)
    3077             : {
    3078             :     PQExpBuffer query;
    3079             :     PGresult   *res;
    3080             :     int         ntups,
    3081             :                 i;
    3082             :     int         i_classid,
    3083             :                 i_objid,
    3084             :                 i_refobjid;
    3085             : 
    3086             :     /* No Mat Views before 9.3. */
    3087         396 :     if (fout->remoteVersion < 90300)
    3088           0 :         return;
    3089             : 
    3090         396 :     query = createPQExpBuffer();
    3091             : 
    3092         396 :     appendPQExpBufferStr(query, "WITH RECURSIVE w AS "
    3093             :                          "( "
    3094             :                          "SELECT d1.objid, d2.refobjid, c2.relkind AS refrelkind "
    3095             :                          "FROM pg_depend d1 "
    3096             :                          "JOIN pg_class c1 ON c1.oid = d1.objid "
    3097             :                          "AND c1.relkind = " CppAsString2(RELKIND_MATVIEW)
    3098             :                          " JOIN pg_rewrite r1 ON r1.ev_class = d1.objid "
    3099             :                          "JOIN pg_depend d2 ON d2.classid = 'pg_rewrite'::regclass "
    3100             :                          "AND d2.objid = r1.oid "
    3101             :                          "AND d2.refobjid <> d1.objid "
    3102             :                          "JOIN pg_class c2 ON c2.oid = d2.refobjid "
    3103             :                          "AND c2.relkind IN (" CppAsString2(RELKIND_MATVIEW) ","
    3104             :                          CppAsString2(RELKIND_VIEW) ") "
    3105             :                          "WHERE d1.classid = 'pg_class'::regclass "
    3106             :                          "UNION "
    3107             :                          "SELECT w.objid, d3.refobjid, c3.relkind "
    3108             :                          "FROM w "
    3109             :                          "JOIN pg_rewrite r3 ON r3.ev_class = w.refobjid "
    3110             :                          "JOIN pg_depend d3 ON d3.classid = 'pg_rewrite'::regclass "
    3111             :                          "AND d3.objid = r3.oid "
    3112             :                          "AND d3.refobjid <> w.refobjid "
    3113             :                          "JOIN pg_class c3 ON c3.oid = d3.refobjid "
    3114             :                          "AND c3.relkind IN (" CppAsString2(RELKIND_MATVIEW) ","
    3115             :                          CppAsString2(RELKIND_VIEW) ") "
    3116             :                          ") "
    3117             :                          "SELECT 'pg_class'::regclass::oid AS classid, objid, refobjid "
    3118             :                          "FROM w "
    3119             :                          "WHERE refrelkind = " CppAsString2(RELKIND_MATVIEW));
    3120             : 
    3121         396 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    3122             : 
    3123         396 :     ntups = PQntuples(res);
    3124             : 
    3125         396 :     i_classid = PQfnumber(res, "classid");
    3126         396 :     i_objid = PQfnumber(res, "objid");
    3127         396 :     i_refobjid = PQfnumber(res, "refobjid");
    3128             : 
    3129         978 :     for (i = 0; i < ntups; i++)
    3130             :     {
    3131             :         CatalogId   objId;
    3132             :         CatalogId   refobjId;
    3133             :         DumpableObject *dobj;
    3134             :         DumpableObject *refdobj;
    3135             :         TableInfo  *tbinfo;
    3136             :         TableInfo  *reftbinfo;
    3137             : 
    3138         582 :         objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
    3139         582 :         objId.oid = atooid(PQgetvalue(res, i, i_objid));
    3140         582 :         refobjId.tableoid = objId.tableoid;
    3141         582 :         refobjId.oid = atooid(PQgetvalue(res, i, i_refobjid));
    3142             : 
    3143         582 :         dobj = findObjectByCatalogId(objId);
    3144         582 :         if (dobj == NULL)
    3145          96 :             continue;
    3146             : 
    3147             :         Assert(dobj->objType == DO_TABLE);
    3148         582 :         tbinfo = (TableInfo *) dobj;
    3149             :         Assert(tbinfo->relkind == RELKIND_MATVIEW);
    3150         582 :         dobj = (DumpableObject *) tbinfo->dataObj;
    3151         582 :         if (dobj == NULL)
    3152          96 :             continue;
    3153             :         Assert(dobj->objType == DO_REFRESH_MATVIEW);
    3154             : 
    3155         486 :         refdobj = findObjectByCatalogId(refobjId);
    3156         486 :         if (refdobj == NULL)
    3157           0 :             continue;
    3158             : 
    3159             :         Assert(refdobj->objType == DO_TABLE);
    3160         486 :         reftbinfo = (TableInfo *) refdobj;
    3161             :         Assert(reftbinfo->relkind == RELKIND_MATVIEW);
    3162         486 :         refdobj = (DumpableObject *) reftbinfo->dataObj;
    3163         486 :         if (refdobj == NULL)
    3164           0 :             continue;
    3165             :         Assert(refdobj->objType == DO_REFRESH_MATVIEW);
    3166             : 
    3167         486 :         addObjectDependency(dobj, refdobj->dumpId);
    3168             : 
    3169         486 :         if (!reftbinfo->relispopulated)
    3170          74 :             tbinfo->relispopulated = false;
    3171             :     }
    3172             : 
    3173         396 :     PQclear(res);
    3174             : 
    3175         396 :     destroyPQExpBuffer(query);
    3176             : }
    3177             : 
    3178             : /*
    3179             :  * getTableDataFKConstraints -
    3180             :  *    add dump-order dependencies reflecting foreign key constraints
    3181             :  *
    3182             :  * This code is executed only in a data-only dump --- in schema+data dumps
    3183             :  * we handle foreign key issues by not creating the FK constraints until
    3184             :  * after the data is loaded.  In a data-only dump, however, we want to
    3185             :  * order the table data objects in such a way that a table's referenced
    3186             :  * tables are restored first.  (In the presence of circular references or
    3187             :  * self-references this may be impossible; we'll detect and complain about
    3188             :  * that during the dependency sorting step.)
    3189             :  */
    3190             : static void
    3191          14 : getTableDataFKConstraints(void)
    3192             : {
    3193             :     DumpableObject **dobjs;
    3194             :     int         numObjs;
    3195             :     int         i;
    3196             : 
    3197             :     /* Search through all the dumpable objects for FK constraints */
    3198          14 :     getDumpableObjects(&dobjs, &numObjs);
    3199       51434 :     for (i = 0; i < numObjs; i++)
    3200             :     {
    3201       51420 :         if (dobjs[i]->objType == DO_FK_CONSTRAINT)
    3202             :         {
    3203          16 :             ConstraintInfo *cinfo = (ConstraintInfo *) dobjs[i];
    3204             :             TableInfo  *ftable;
    3205             : 
    3206             :             /* Not interesting unless both tables are to be dumped */
    3207          16 :             if (cinfo->contable == NULL ||
    3208          16 :                 cinfo->contable->dataObj == NULL)
    3209           8 :                 continue;
    3210           8 :             ftable = findTableByOid(cinfo->confrelid);
    3211           8 :             if (ftable == NULL ||
    3212           8 :                 ftable->dataObj == NULL)
    3213           0 :                 continue;
    3214             : 
    3215             :             /*
    3216             :              * Okay, make referencing table's TABLE_DATA object depend on the
    3217             :              * referenced table's TABLE_DATA object.
    3218             :              */
    3219           8 :             addObjectDependency(&cinfo->contable->dataObj->dobj,
    3220           8 :                                 ftable->dataObj->dobj.dumpId);
    3221             :         }
    3222             :     }
    3223          14 :     free(dobjs);
    3224          14 : }
    3225             : 
    3226             : 
    3227             : /*
    3228             :  * dumpDatabase:
    3229             :  *  dump the database definition
    3230             :  */
    3231             : static void
    3232         264 : dumpDatabase(Archive *fout)
    3233             : {
    3234         264 :     DumpOptions *dopt = fout->dopt;
    3235         264 :     PQExpBuffer dbQry = createPQExpBuffer();
    3236         264 :     PQExpBuffer delQry = createPQExpBuffer();
    3237         264 :     PQExpBuffer creaQry = createPQExpBuffer();
    3238         264 :     PQExpBuffer labelq = createPQExpBuffer();
    3239         264 :     PGconn     *conn = GetConnection(fout);
    3240             :     PGresult   *res;
    3241             :     int         i_tableoid,
    3242             :                 i_oid,
    3243             :                 i_datname,
    3244             :                 i_datdba,
    3245             :                 i_encoding,
    3246             :                 i_datlocprovider,
    3247             :                 i_collate,
    3248             :                 i_ctype,
    3249             :                 i_datlocale,
    3250             :                 i_daticurules,
    3251             :                 i_frozenxid,
    3252             :                 i_minmxid,
    3253             :                 i_datacl,
    3254             :                 i_acldefault,
    3255             :                 i_datistemplate,
    3256             :                 i_datconnlimit,
    3257             :                 i_datcollversion,
    3258             :                 i_tablespace;
    3259             :     CatalogId   dbCatId;
    3260             :     DumpId      dbDumpId;
    3261             :     DumpableAcl dbdacl;
    3262             :     const char *datname,
    3263             :                *dba,
    3264             :                *encoding,
    3265             :                *datlocprovider,
    3266             :                *collate,
    3267             :                *ctype,
    3268             :                *locale,
    3269             :                *icurules,
    3270             :                *datistemplate,
    3271             :                *datconnlimit,
    3272             :                *tablespace;
    3273             :     uint32      frozenxid,
    3274             :                 minmxid;
    3275             :     char       *qdatname;
    3276             : 
    3277         264 :     pg_log_info("saving database definition");
    3278             : 
    3279             :     /*
    3280             :      * Fetch the database-level properties for this database.
    3281             :      */
    3282         264 :     appendPQExpBufferStr(dbQry, "SELECT tableoid, oid, datname, "
    3283             :                          "datdba, "
    3284             :                          "pg_encoding_to_char(encoding) AS encoding, "
    3285             :                          "datcollate, datctype, datfrozenxid, "
    3286             :                          "datacl, acldefault('d', datdba) AS acldefault, "
    3287             :                          "datistemplate, datconnlimit, ");
    3288         264 :     if (fout->remoteVersion >= 90300)
    3289         264 :         appendPQExpBufferStr(dbQry, "datminmxid, ");
    3290             :     else
    3291           0 :         appendPQExpBufferStr(dbQry, "0 AS datminmxid, ");
    3292         264 :     if (fout->remoteVersion >= 170000)
    3293         264 :         appendPQExpBufferStr(dbQry, "datlocprovider, datlocale, datcollversion, ");
    3294           0 :     else if (fout->remoteVersion >= 150000)
    3295           0 :         appendPQExpBufferStr(dbQry, "datlocprovider, daticulocale AS datlocale, datcollversion, ");
    3296             :     else
    3297           0 :         appendPQExpBufferStr(dbQry, "'c' AS datlocprovider, NULL AS datlocale, NULL AS datcollversion, ");
    3298         264 :     if (fout->remoteVersion >= 160000)
    3299         264 :         appendPQExpBufferStr(dbQry, "daticurules, ");
    3300             :     else
    3301           0 :         appendPQExpBufferStr(dbQry, "NULL AS daticurules, ");
    3302         264 :     appendPQExpBufferStr(dbQry,
    3303             :                          "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace, "
    3304             :                          "shobj_description(oid, 'pg_database') AS description "
    3305             :                          "FROM pg_database "
    3306             :                          "WHERE datname = current_database()");
    3307             : 
    3308         264 :     res = ExecuteSqlQueryForSingleRow(fout, dbQry->data);
    3309             : 
    3310         264 :     i_tableoid = PQfnumber(res, "tableoid");
    3311         264 :     i_oid = PQfnumber(res, "oid");
    3312         264 :     i_datname = PQfnumber(res, "datname");
    3313         264 :     i_datdba = PQfnumber(res, "datdba");
    3314         264 :     i_encoding = PQfnumber(res, "encoding");
    3315         264 :     i_datlocprovider = PQfnumber(res, "datlocprovider");
    3316         264 :     i_collate = PQfnumber(res, "datcollate");
    3317         264 :     i_ctype = PQfnumber(res, "datctype");
    3318         264 :     i_datlocale = PQfnumber(res, "datlocale");
    3319         264 :     i_daticurules = PQfnumber(res, "daticurules");
    3320         264 :     i_frozenxid = PQfnumber(res, "datfrozenxid");
    3321         264 :     i_minmxid = PQfnumber(res, "datminmxid");
    3322         264 :     i_datacl = PQfnumber(res, "datacl");
    3323         264 :     i_acldefault = PQfnumber(res, "acldefault");
    3324         264 :     i_datistemplate = PQfnumber(res, "datistemplate");
    3325         264 :     i_datconnlimit = PQfnumber(res, "datconnlimit");
    3326         264 :     i_datcollversion = PQfnumber(res, "datcollversion");
    3327         264 :     i_tablespace = PQfnumber(res, "tablespace");
    3328             : 
    3329         264 :     dbCatId.tableoid = atooid(PQgetvalue(res, 0, i_tableoid));
    3330         264 :     dbCatId.oid = atooid(PQgetvalue(res, 0, i_oid));
    3331         264 :     datname = PQgetvalue(res, 0, i_datname);
    3332         264 :     dba = getRoleName(PQgetvalue(res, 0, i_datdba));
    3333         264 :     encoding = PQgetvalue(res, 0, i_encoding);
    3334         264 :     datlocprovider = PQgetvalue(res, 0, i_datlocprovider);
    3335         264 :     collate = PQgetvalue(res, 0, i_collate);
    3336         264 :     ctype = PQgetvalue(res, 0, i_ctype);
    3337         264 :     if (!PQgetisnull(res, 0, i_datlocale))
    3338          30 :         locale = PQgetvalue(res, 0, i_datlocale);
    3339             :     else
    3340         234 :         locale = NULL;
    3341         264 :     if (!PQgetisnull(res, 0, i_daticurules))
    3342           0 :         icurules = PQgetvalue(res, 0, i_daticurules);
    3343             :     else
    3344         264 :         icurules = NULL;
    3345         264 :     frozenxid = atooid(PQgetvalue(res, 0, i_frozenxid));
    3346         264 :     minmxid = atooid(PQgetvalue(res, 0, i_minmxid));
    3347         264 :     dbdacl.acl = PQgetvalue(res, 0, i_datacl);
    3348         264 :     dbdacl.acldefault = PQgetvalue(res, 0, i_acldefault);
    3349         264 :     datistemplate = PQgetvalue(res, 0, i_datistemplate);
    3350         264 :     datconnlimit = PQgetvalue(res, 0, i_datconnlimit);
    3351         264 :     tablespace = PQgetvalue(res, 0, i_tablespace);
    3352             : 
    3353         264 :     qdatname = pg_strdup(fmtId(datname));
    3354             : 
    3355             :     /*
    3356             :      * Prepare the CREATE DATABASE command.  We must specify OID (if we want
    3357             :      * to preserve that), as well as the encoding, locale, and tablespace
    3358             :      * since those can't be altered later.  Other DB properties are left to
    3359             :      * the DATABASE PROPERTIES entry, so that they can be applied after
    3360             :      * reconnecting to the target DB.
    3361             :      *
    3362             :      * For binary upgrade, we use the FILE_COPY strategy because testing has
    3363             :      * shown it to be faster.  When the server is in binary upgrade mode, it
    3364             :      * will also skip the checkpoints this strategy ordinarily performs.
    3365             :      */
    3366         264 :     if (dopt->binary_upgrade)
    3367             :     {
    3368          60 :         appendPQExpBuffer(creaQry,
    3369             :                           "CREATE DATABASE %s WITH TEMPLATE = template0 "
    3370             :                           "OID = %u STRATEGY = FILE_COPY",
    3371             :                           qdatname, dbCatId.oid);
    3372             :     }
    3373             :     else
    3374             :     {
    3375         204 :         appendPQExpBuffer(creaQry, "CREATE DATABASE %s WITH TEMPLATE = template0",
    3376             :                           qdatname);
    3377             :     }
    3378         264 :     if (strlen(encoding) > 0)
    3379             :     {
    3380         264 :         appendPQExpBufferStr(creaQry, " ENCODING = ");
    3381         264 :         appendStringLiteralAH(creaQry, encoding, fout);
    3382             :     }
    3383             : 
    3384         264 :     appendPQExpBufferStr(creaQry, " LOCALE_PROVIDER = ");
    3385         264 :     if (datlocprovider[0] == 'b')
    3386          30 :         appendPQExpBufferStr(creaQry, "builtin");
    3387         234 :     else if (datlocprovider[0] == 'c')
    3388         234 :         appendPQExpBufferStr(creaQry, "libc");
    3389           0 :     else if (datlocprovider[0] == 'i')
    3390           0 :         appendPQExpBufferStr(creaQry, "icu");
    3391             :     else
    3392           0 :         pg_fatal("unrecognized locale provider: %s",
    3393             :                  datlocprovider);
    3394             : 
    3395         264 :     if (strlen(collate) > 0 && strcmp(collate, ctype) == 0)
    3396             :     {
    3397         264 :         appendPQExpBufferStr(creaQry, " LOCALE = ");
    3398         264 :         appendStringLiteralAH(creaQry, collate, fout);
    3399             :     }
    3400             :     else
    3401             :     {
    3402           0 :         if (strlen(collate) > 0)
    3403             :         {
    3404           0 :             appendPQExpBufferStr(creaQry, " LC_COLLATE = ");
    3405           0 :             appendStringLiteralAH(creaQry, collate, fout);
    3406             :         }
    3407           0 :         if (strlen(ctype) > 0)
    3408             :         {
    3409           0 :             appendPQExpBufferStr(creaQry, " LC_CTYPE = ");
    3410           0 :             appendStringLiteralAH(creaQry, ctype, fout);
    3411             :         }
    3412             :     }
    3413         264 :     if (locale)
    3414             :     {
    3415          30 :         if (datlocprovider[0] == 'b')
    3416          30 :             appendPQExpBufferStr(creaQry, " BUILTIN_LOCALE = ");
    3417             :         else
    3418           0 :             appendPQExpBufferStr(creaQry, " ICU_LOCALE = ");
    3419             : 
    3420          30 :         appendStringLiteralAH(creaQry, locale, fout);
    3421             :     }
    3422             : 
    3423         264 :     if (icurules)
    3424             :     {
    3425           0 :         appendPQExpBufferStr(creaQry, " ICU_RULES = ");
    3426           0 :         appendStringLiteralAH(creaQry, icurules, fout);
    3427             :     }
    3428             : 
    3429             :     /*
    3430             :      * For binary upgrade, carry over the collation version.  For normal
    3431             :      * dump/restore, omit the version, so that it is computed upon restore.
    3432             :      */
    3433         264 :     if (dopt->binary_upgrade)
    3434             :     {
    3435          60 :         if (!PQgetisnull(res, 0, i_datcollversion))
    3436             :         {
    3437          60 :             appendPQExpBufferStr(creaQry, " COLLATION_VERSION = ");
    3438          60 :             appendStringLiteralAH(creaQry,
    3439             :                                   PQgetvalue(res, 0, i_datcollversion),
    3440             :                                   fout);
    3441             :         }
    3442             :     }
    3443             : 
    3444             :     /*
    3445             :      * Note: looking at dopt->outputNoTablespaces here is completely the wrong
    3446             :      * thing; the decision whether to specify a tablespace should be left till
    3447             :      * pg_restore, so that pg_restore --no-tablespaces applies.  Ideally we'd
    3448             :      * label the DATABASE entry with the tablespace and let the normal
    3449             :      * tablespace selection logic work ... but CREATE DATABASE doesn't pay
    3450             :      * attention to default_tablespace, so that won't work.
    3451             :      */
    3452         264 :     if (strlen(tablespace) > 0 && strcmp(tablespace, "pg_default") != 0 &&
    3453           0 :         !dopt->outputNoTablespaces)
    3454           0 :         appendPQExpBuffer(creaQry, " TABLESPACE = %s",
    3455             :                           fmtId(tablespace));
    3456         264 :     appendPQExpBufferStr(creaQry, ";\n");
    3457             : 
    3458         264 :     appendPQExpBuffer(delQry, "DROP DATABASE %s;\n",
    3459             :                       qdatname);
    3460             : 
    3461         264 :     dbDumpId = createDumpId();
    3462             : 
    3463         264 :     ArchiveEntry(fout,
    3464             :                  dbCatId,       /* catalog ID */
    3465             :                  dbDumpId,      /* dump ID */
    3466         264 :                  ARCHIVE_OPTS(.tag = datname,
    3467             :                               .owner = dba,
    3468             :                               .description = "DATABASE",
    3469             :                               .section = SECTION_PRE_DATA,
    3470             :                               .createStmt = creaQry->data,
    3471             :                               .dropStmt = delQry->data));
    3472             : 
    3473             :     /* Compute correct tag for archive entry */
    3474         264 :     appendPQExpBuffer(labelq, "DATABASE %s", qdatname);
    3475             : 
    3476             :     /* Dump DB comment if any */
    3477             :     {
    3478             :         /*
    3479             :          * 8.2 and up keep comments on shared objects in a shared table, so we
    3480             :          * cannot use the dumpComment() code used for other database objects.
    3481             :          * Be careful that the ArchiveEntry parameters match that function.
    3482             :          */
    3483         264 :         char       *comment = PQgetvalue(res, 0, PQfnumber(res, "description"));
    3484             : 
    3485         264 :         if (comment && *comment && !dopt->no_comments)
    3486             :         {
    3487         102 :             resetPQExpBuffer(dbQry);
    3488             : 
    3489             :             /*
    3490             :              * Generates warning when loaded into a differently-named
    3491             :              * database.
    3492             :              */
    3493         102 :             appendPQExpBuffer(dbQry, "COMMENT ON DATABASE %s IS ", qdatname);
    3494         102 :             appendStringLiteralAH(dbQry, comment, fout);
    3495         102 :             appendPQExpBufferStr(dbQry, ";\n");
    3496             : 
    3497         102 :             ArchiveEntry(fout, nilCatalogId, createDumpId(),
    3498         102 :                          ARCHIVE_OPTS(.tag = labelq->data,
    3499             :                                       .owner = dba,
    3500             :                                       .description = "COMMENT",
    3501             :                                       .section = SECTION_NONE,
    3502             :                                       .createStmt = dbQry->data,
    3503             :                                       .deps = &dbDumpId,
    3504             :                                       .nDeps = 1));
    3505             :         }
    3506             :     }
    3507             : 
    3508             :     /* Dump DB security label, if enabled */
    3509         264 :     if (!dopt->no_security_labels)
    3510             :     {
    3511             :         PGresult   *shres;
    3512             :         PQExpBuffer seclabelQry;
    3513             : 
    3514         264 :         seclabelQry = createPQExpBuffer();
    3515             : 
    3516         264 :         buildShSecLabelQuery("pg_database", dbCatId.oid, seclabelQry);
    3517         264 :         shres = ExecuteSqlQuery(fout, seclabelQry->data, PGRES_TUPLES_OK);
    3518         264 :         resetPQExpBuffer(seclabelQry);
    3519         264 :         emitShSecLabels(conn, shres, seclabelQry, "DATABASE", datname);
    3520         264 :         if (seclabelQry->len > 0)
    3521           0 :             ArchiveEntry(fout, nilCatalogId, createDumpId(),
    3522           0 :                          ARCHIVE_OPTS(.tag = labelq->data,
    3523             :                                       .owner = dba,
    3524             :                                       .description = "SECURITY LABEL",
    3525             :                                       .section = SECTION_NONE,
    3526             :                                       .createStmt = seclabelQry->data,
    3527             :                                       .deps = &dbDumpId,
    3528             :                                       .nDeps = 1));
    3529         264 :         destroyPQExpBuffer(seclabelQry);
    3530         264 :         PQclear(shres);
    3531             :     }
    3532             : 
    3533             :     /*
    3534             :      * Dump ACL if any.  Note that we do not support initial privileges
    3535             :      * (pg_init_privs) on databases.
    3536             :      */
    3537         264 :     dbdacl.privtype = 0;
    3538         264 :     dbdacl.initprivs = NULL;
    3539             : 
    3540         264 :     dumpACL(fout, dbDumpId, InvalidDumpId, "DATABASE",
    3541             :             qdatname, NULL, NULL,
    3542             :             NULL, dba, &dbdacl);
    3543             : 
    3544             :     /*
    3545             :      * Now construct a DATABASE PROPERTIES archive entry to restore any
    3546             :      * non-default database-level properties.  (The reason this must be
    3547             :      * separate is that we cannot put any additional commands into the TOC
    3548             :      * entry that has CREATE DATABASE.  pg_restore would execute such a group
    3549             :      * in an implicit transaction block, and the backend won't allow CREATE
    3550             :      * DATABASE in that context.)
    3551             :      */
    3552         264 :     resetPQExpBuffer(creaQry);
    3553         264 :     resetPQExpBuffer(delQry);
    3554             : 
    3555         264 :     if (strlen(datconnlimit) > 0 && strcmp(datconnlimit, "-1") != 0)
    3556           0 :         appendPQExpBuffer(creaQry, "ALTER DATABASE %s CONNECTION LIMIT = %s;\n",
    3557             :                           qdatname, datconnlimit);
    3558             : 
    3559         264 :     if (strcmp(datistemplate, "t") == 0)
    3560             :     {
    3561          34 :         appendPQExpBuffer(creaQry, "ALTER DATABASE %s IS_TEMPLATE = true;\n",
    3562             :                           qdatname);
    3563             : 
    3564             :         /*
    3565             :          * The backend won't accept DROP DATABASE on a template database.  We
    3566             :          * can deal with that by removing the template marking before the DROP
    3567             :          * gets issued.  We'd prefer to use ALTER DATABASE IF EXISTS here, but
    3568             :          * since no such command is currently supported, fake it with a direct
    3569             :          * UPDATE on pg_database.
    3570             :          */
    3571          34 :         appendPQExpBufferStr(delQry, "UPDATE pg_catalog.pg_database "
    3572             :                              "SET datistemplate = false WHERE datname = ");
    3573          34 :         appendStringLiteralAH(delQry, datname, fout);
    3574          34 :         appendPQExpBufferStr(delQry, ";\n");
    3575             :     }
    3576             : 
    3577             :     /*
    3578             :      * We do not restore pg_database.dathasloginevt because it is set
    3579             :      * automatically on login event trigger creation.
    3580             :      */
    3581             : 
    3582             :     /* Add database-specific SET options */
    3583         264 :     dumpDatabaseConfig(fout, creaQry, datname, dbCatId.oid);
    3584             : 
    3585             :     /*
    3586             :      * We stick this binary-upgrade query into the DATABASE PROPERTIES archive
    3587             :      * entry, too, for lack of a better place.
    3588             :      */
    3589         264 :     if (dopt->binary_upgrade)
    3590             :     {
    3591          60 :         appendPQExpBufferStr(creaQry, "\n-- For binary upgrade, set datfrozenxid and datminmxid.\n");
    3592          60 :         appendPQExpBuffer(creaQry, "UPDATE pg_catalog.pg_database\n"
    3593             :                           "SET datfrozenxid = '%u', datminmxid = '%u'\n"
    3594             :                           "WHERE datname = ",
    3595             :                           frozenxid, minmxid);
    3596          60 :         appendStringLiteralAH(creaQry, datname, fout);
    3597          60 :         appendPQExpBufferStr(creaQry, ";\n");
    3598             :     }
    3599             : 
    3600         264 :     if (creaQry->len > 0)
    3601          84 :         ArchiveEntry(fout, nilCatalogId, createDumpId(),
    3602          84 :                      ARCHIVE_OPTS(.tag = datname,
    3603             :                                   .owner = dba,
    3604             :                                   .description = "DATABASE PROPERTIES",
    3605             :                                   .section = SECTION_PRE_DATA,
    3606             :                                   .createStmt = creaQry->data,
    3607             :                                   .dropStmt = delQry->data,
    3608             :                                   .deps = &dbDumpId));
    3609             : 
    3610             :     /*
    3611             :      * pg_largeobject comes from the old system intact, so set its
    3612             :      * relfrozenxids, relminmxids and relfilenode.
    3613             :      */
    3614         264 :     if (dopt->binary_upgrade)
    3615             :     {
    3616             :         PGresult   *lo_res;
    3617          60 :         PQExpBuffer loFrozenQry = createPQExpBuffer();
    3618          60 :         PQExpBuffer loOutQry = createPQExpBuffer();
    3619          60 :         PQExpBuffer loHorizonQry = createPQExpBuffer();
    3620             :         int         ii_relfrozenxid,
    3621             :                     ii_relfilenode,
    3622             :                     ii_oid,
    3623             :                     ii_relminmxid;
    3624             : 
    3625             :         /*
    3626             :          * pg_largeobject
    3627             :          */
    3628          60 :         if (fout->remoteVersion >= 90300)
    3629          60 :             appendPQExpBuffer(loFrozenQry, "SELECT relfrozenxid, relminmxid, relfilenode, oid\n"
    3630             :                               "FROM pg_catalog.pg_class\n"
    3631             :                               "WHERE oid IN (%u, %u);\n",
    3632             :                               LargeObjectRelationId, LargeObjectLOidPNIndexId);
    3633             :         else
    3634           0 :             appendPQExpBuffer(loFrozenQry, "SELECT relfrozenxid, 0 AS relminmxid, relfilenode, oid\n"
    3635             :                               "FROM pg_catalog.pg_class\n"
    3636             :                               "WHERE oid IN (%u, %u);\n",
    3637             :                               LargeObjectRelationId, LargeObjectLOidPNIndexId);
    3638             : 
    3639          60 :         lo_res = ExecuteSqlQuery(fout, loFrozenQry->data, PGRES_TUPLES_OK);
    3640             : 
    3641          60 :         ii_relfrozenxid = PQfnumber(lo_res, "relfrozenxid");
    3642          60 :         ii_relminmxid = PQfnumber(lo_res, "relminmxid");
    3643          60 :         ii_relfilenode = PQfnumber(lo_res, "relfilenode");
    3644          60 :         ii_oid = PQfnumber(lo_res, "oid");
    3645             : 
    3646          60 :         appendPQExpBufferStr(loHorizonQry, "\n-- For binary upgrade, set pg_largeobject relfrozenxid and relminmxid\n");
    3647          60 :         appendPQExpBufferStr(loOutQry, "\n-- For binary upgrade, preserve pg_largeobject and index relfilenodes\n");
    3648         180 :         for (int i = 0; i < PQntuples(lo_res); ++i)
    3649             :         {
    3650             :             Oid         oid;
    3651             :             RelFileNumber relfilenumber;
    3652             : 
    3653         120 :             appendPQExpBuffer(loHorizonQry, "UPDATE pg_catalog.pg_class\n"
    3654             :                               "SET relfrozenxid = '%u', relminmxid = '%u'\n"
    3655             :                               "WHERE oid = %u;\n",
    3656         120 :                               atooid(PQgetvalue(lo_res, i, ii_relfrozenxid)),
    3657         120 :                               atooid(PQgetvalue(lo_res, i, ii_relminmxid)),
    3658         120 :                               atooid(PQgetvalue(lo_res, i, ii_oid)));
    3659             : 
    3660         120 :             oid = atooid(PQgetvalue(lo_res, i, ii_oid));
    3661         120 :             relfilenumber = atooid(PQgetvalue(lo_res, i, ii_relfilenode));
    3662             : 
    3663         120 :             if (oid == LargeObjectRelationId)
    3664          60 :                 appendPQExpBuffer(loOutQry,
    3665             :                                   "SELECT pg_catalog.binary_upgrade_set_next_heap_relfilenode('%u'::pg_catalog.oid);\n",
    3666             :                                   relfilenumber);
    3667          60 :             else if (oid == LargeObjectLOidPNIndexId)
    3668          60 :                 appendPQExpBuffer(loOutQry,
    3669             :                                   "SELECT pg_catalog.binary_upgrade_set_next_index_relfilenode('%u'::pg_catalog.oid);\n",
    3670             :                                   relfilenumber);
    3671             :         }
    3672             : 
    3673          60 :         appendPQExpBufferStr(loOutQry,
    3674             :                              "TRUNCATE pg_catalog.pg_largeobject;\n");
    3675          60 :         appendPQExpBufferStr(loOutQry, loHorizonQry->data);
    3676             : 
    3677          60 :         ArchiveEntry(fout, nilCatalogId, createDumpId(),
    3678          60 :                      ARCHIVE_OPTS(.tag = "pg_largeobject",
    3679             :                                   .description = "pg_largeobject",
    3680             :                                   .section = SECTION_PRE_DATA,
    3681             :                                   .createStmt = loOutQry->data));
    3682             : 
    3683          60 :         PQclear(lo_res);
    3684             : 
    3685          60 :         destroyPQExpBuffer(loFrozenQry);
    3686          60 :         destroyPQExpBuffer(loHorizonQry);
    3687          60 :         destroyPQExpBuffer(loOutQry);
    3688             :     }
    3689             : 
    3690         264 :     PQclear(res);
    3691             : 
    3692         264 :     free(qdatname);
    3693         264 :     destroyPQExpBuffer(dbQry);
    3694         264 :     destroyPQExpBuffer(delQry);
    3695         264 :     destroyPQExpBuffer(creaQry);
    3696         264 :     destroyPQExpBuffer(labelq);
    3697         264 : }
    3698             : 
    3699             : /*
    3700             :  * Collect any database-specific or role-and-database-specific SET options
    3701             :  * for this database, and append them to outbuf.
    3702             :  */
    3703             : static void
    3704         264 : dumpDatabaseConfig(Archive *AH, PQExpBuffer outbuf,
    3705             :                    const char *dbname, Oid dboid)
    3706             : {
    3707         264 :     PGconn     *conn = GetConnection(AH);
    3708         264 :     PQExpBuffer buf = createPQExpBuffer();
    3709             :     PGresult   *res;
    3710             : 
    3711             :     /* First collect database-specific options */
    3712         264 :     printfPQExpBuffer(buf, "SELECT unnest(setconfig) FROM pg_db_role_setting "
    3713             :                       "WHERE setrole = 0 AND setdatabase = '%u'::oid",
    3714             :                       dboid);
    3715             : 
    3716         264 :     res = ExecuteSqlQuery(AH, buf->data, PGRES_TUPLES_OK);
    3717             : 
    3718         336 :     for (int i = 0; i < PQntuples(res); i++)
    3719          72 :         makeAlterConfigCommand(conn, PQgetvalue(res, i, 0),
    3720             :                                "DATABASE", dbname, NULL, NULL,
    3721             :                                outbuf);
    3722             : 
    3723         264 :     PQclear(res);
    3724             : 
    3725             :     /* Now look for role-and-database-specific options */
    3726         264 :     printfPQExpBuffer(buf, "SELECT rolname, unnest(setconfig) "
    3727             :                       "FROM pg_db_role_setting s, pg_roles r "
    3728             :                       "WHERE setrole = r.oid AND setdatabase = '%u'::oid",
    3729             :                       dboid);
    3730             : 
    3731         264 :     res = ExecuteSqlQuery(AH, buf->data, PGRES_TUPLES_OK);
    3732             : 
    3733         264 :     for (int i = 0; i < PQntuples(res); i++)
    3734           0 :         makeAlterConfigCommand(conn, PQgetvalue(res, i, 1),
    3735           0 :                                "ROLE", PQgetvalue(res, i, 0),
    3736             :                                "DATABASE", dbname,
    3737             :                                outbuf);
    3738             : 
    3739         264 :     PQclear(res);
    3740             : 
    3741         264 :     destroyPQExpBuffer(buf);
    3742         264 : }
    3743             : 
    3744             : /*
    3745             :  * dumpEncoding: put the correct encoding into the archive
    3746             :  */
    3747             : static void
    3748         468 : dumpEncoding(Archive *AH)
    3749             : {
    3750         468 :     const char *encname = pg_encoding_to_char(AH->encoding);
    3751         468 :     PQExpBuffer qry = createPQExpBuffer();
    3752             : 
    3753         468 :     pg_log_info("saving encoding = %s", encname);
    3754             : 
    3755         468 :     appendPQExpBufferStr(qry, "SET client_encoding = ");
    3756         468 :     appendStringLiteralAH(qry, encname, AH);
    3757         468 :     appendPQExpBufferStr(qry, ";\n");
    3758             : 
    3759         468 :     ArchiveEntry(AH, nilCatalogId, createDumpId(),
    3760         468 :                  ARCHIVE_OPTS(.tag = "ENCODING",
    3761             :                               .description = "ENCODING",
    3762             :                               .section = SECTION_PRE_DATA,
    3763             :                               .createStmt = qry->data));
    3764             : 
    3765         468 :     destroyPQExpBuffer(qry);
    3766         468 : }
    3767             : 
    3768             : 
    3769             : /*
    3770             :  * dumpStdStrings: put the correct escape string behavior into the archive
    3771             :  */
    3772             : static void
    3773         468 : dumpStdStrings(Archive *AH)
    3774             : {
    3775         468 :     const char *stdstrings = AH->std_strings ? "on" : "off";
    3776         468 :     PQExpBuffer qry = createPQExpBuffer();
    3777             : 
    3778         468 :     pg_log_info("saving \"standard_conforming_strings = %s\"",
    3779             :                 stdstrings);
    3780             : 
    3781         468 :     appendPQExpBuffer(qry, "SET standard_conforming_strings = '%s';\n",
    3782             :                       stdstrings);
    3783             : 
    3784         468 :     ArchiveEntry(AH, nilCatalogId, createDumpId(),
    3785         468 :                  ARCHIVE_OPTS(.tag = "STDSTRINGS",
    3786             :                               .description = "STDSTRINGS",
    3787             :                               .section = SECTION_PRE_DATA,
    3788             :                               .createStmt = qry->data));
    3789             : 
    3790         468 :     destroyPQExpBuffer(qry);
    3791         468 : }
    3792             : 
    3793             : /*
    3794             :  * dumpSearchPath: record the active search_path in the archive
    3795             :  */
    3796             : static void
    3797         468 : dumpSearchPath(Archive *AH)
    3798             : {
    3799         468 :     PQExpBuffer qry = createPQExpBuffer();
    3800         468 :     PQExpBuffer path = createPQExpBuffer();
    3801             :     PGresult   *res;
    3802         468 :     char      **schemanames = NULL;
    3803         468 :     int         nschemanames = 0;
    3804             :     int         i;
    3805             : 
    3806             :     /*
    3807             :      * We use the result of current_schemas(), not the search_path GUC,
    3808             :      * because that might contain wildcards such as "$user", which won't
    3809             :      * necessarily have the same value during restore.  Also, this way avoids
    3810             :      * listing schemas that may appear in search_path but not actually exist,
    3811             :      * which seems like a prudent exclusion.
    3812             :      */
    3813         468 :     res = ExecuteSqlQueryForSingleRow(AH,
    3814             :                                       "SELECT pg_catalog.current_schemas(false)");
    3815             : 
    3816         468 :     if (!parsePGArray(PQgetvalue(res, 0, 0), &schemanames, &nschemanames))
    3817           0 :         pg_fatal("could not parse result of current_schemas()");
    3818             : 
    3819             :     /*
    3820             :      * We use set_config(), not a simple "SET search_path" command, because
    3821             :      * the latter has less-clean behavior if the search path is empty.  While
    3822             :      * that's likely to get fixed at some point, it seems like a good idea to
    3823             :      * be as backwards-compatible as possible in what we put into archives.
    3824             :      */
    3825         468 :     for (i = 0; i < nschemanames; i++)
    3826             :     {
    3827           0 :         if (i > 0)
    3828           0 :             appendPQExpBufferStr(path, ", ");
    3829           0 :         appendPQExpBufferStr(path, fmtId(schemanames[i]));
    3830             :     }
    3831             : 
    3832         468 :     appendPQExpBufferStr(qry, "SELECT pg_catalog.set_config('search_path', ");
    3833         468 :     appendStringLiteralAH(qry, path->data, AH);
    3834         468 :     appendPQExpBufferStr(qry, ", false);\n");
    3835             : 
    3836         468 :     pg_log_info("saving \"search_path = %s\"", path->data);
    3837             : 
    3838         468 :     ArchiveEntry(AH, nilCatalogId, createDumpId(),
    3839         468 :                  ARCHIVE_OPTS(.tag = "SEARCHPATH",
    3840             :                               .description = "SEARCHPATH",
    3841             :                               .section = SECTION_PRE_DATA,
    3842             :                               .createStmt = qry->data));
    3843             : 
    3844             :     /* Also save it in AH->searchpath, in case we're doing plain text dump */
    3845         468 :     AH->searchpath = pg_strdup(qry->data);
    3846             : 
    3847         468 :     free(schemanames);
    3848         468 :     PQclear(res);
    3849         468 :     destroyPQExpBuffer(qry);
    3850         468 :     destroyPQExpBuffer(path);
    3851         468 : }
    3852             : 
    3853             : 
    3854             : /*
    3855             :  * getLOs:
    3856             :  *  Collect schema-level data about large objects
    3857             :  */
    3858             : static void
    3859         410 : getLOs(Archive *fout)
    3860             : {
    3861         410 :     DumpOptions *dopt = fout->dopt;
    3862         410 :     PQExpBuffer loQry = createPQExpBuffer();
    3863             :     PGresult   *res;
    3864             :     int         ntups;
    3865             :     int         i;
    3866             :     int         n;
    3867             :     int         i_oid;
    3868             :     int         i_lomowner;
    3869             :     int         i_lomacl;
    3870             :     int         i_acldefault;
    3871             : 
    3872         410 :     pg_log_info("reading large objects");
    3873             : 
    3874             :     /*
    3875             :      * Fetch LO OIDs and owner/ACL data.  Order the data so that all the blobs
    3876             :      * with the same owner/ACL appear together.
    3877             :      */
    3878         410 :     appendPQExpBufferStr(loQry,
    3879             :                          "SELECT oid, lomowner, lomacl, "
    3880             :                          "acldefault('L', lomowner) AS acldefault "
    3881             :                          "FROM pg_largeobject_metadata "
    3882             :                          "ORDER BY lomowner, lomacl::pg_catalog.text, oid");
    3883             : 
    3884         410 :     res = ExecuteSqlQuery(fout, loQry->data, PGRES_TUPLES_OK);
    3885             : 
    3886         410 :     i_oid = PQfnumber(res, "oid");
    3887         410 :     i_lomowner = PQfnumber(res, "lomowner");
    3888         410 :     i_lomacl = PQfnumber(res, "lomacl");
    3889         410 :     i_acldefault = PQfnumber(res, "acldefault");
    3890             : 
    3891         410 :     ntups = PQntuples(res);
    3892             : 
    3893             :     /*
    3894             :      * Group the blobs into suitably-sized groups that have the same owner and
    3895             :      * ACL setting, and build a metadata and a data DumpableObject for each
    3896             :      * group.  (If we supported initprivs for blobs, we'd have to insist that
    3897             :      * groups also share initprivs settings, since the DumpableObject only has
    3898             :      * room for one.)  i is the index of the first tuple in the current group,
    3899             :      * and n is the number of tuples we include in the group.
    3900             :      */
    3901         574 :     for (i = 0; i < ntups; i += n)
    3902             :     {
    3903         164 :         Oid         thisoid = atooid(PQgetvalue(res, i, i_oid));
    3904         164 :         char       *thisowner = PQgetvalue(res, i, i_lomowner);
    3905         164 :         char       *thisacl = PQgetvalue(res, i, i_lomacl);
    3906             :         LoInfo     *loinfo;
    3907             :         DumpableObject *lodata;
    3908             :         char        namebuf[64];
    3909             : 
    3910             :         /* Scan to find first tuple not to be included in group */
    3911         164 :         n = 1;
    3912         196 :         while (n < MAX_BLOBS_PER_ARCHIVE_ENTRY && i + n < ntups)
    3913             :         {
    3914         106 :             if (strcmp(thisowner, PQgetvalue(res, i + n, i_lomowner)) != 0 ||
    3915         106 :                 strcmp(thisacl, PQgetvalue(res, i + n, i_lomacl)) != 0)
    3916             :                 break;
    3917          32 :             n++;
    3918             :         }
    3919             : 
    3920             :         /* Build the metadata DumpableObject */
    3921         164 :         loinfo = (LoInfo *) pg_malloc(offsetof(LoInfo, looids) + n * sizeof(Oid));
    3922             : 
    3923         164 :         loinfo->dobj.objType = DO_LARGE_OBJECT;
    3924         164 :         loinfo->dobj.catId.tableoid = LargeObjectRelationId;
    3925         164 :         loinfo->dobj.catId.oid = thisoid;
    3926         164 :         AssignDumpId(&loinfo->dobj);
    3927             : 
    3928         164 :         if (n > 1)
    3929          16 :             snprintf(namebuf, sizeof(namebuf), "%u..%u", thisoid,
    3930          16 :                      atooid(PQgetvalue(res, i + n - 1, i_oid)));
    3931             :         else
    3932         148 :             snprintf(namebuf, sizeof(namebuf), "%u", thisoid);
    3933         164 :         loinfo->dobj.name = pg_strdup(namebuf);
    3934         164 :         loinfo->dacl.acl = pg_strdup(thisacl);
    3935         164 :         loinfo->dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
    3936         164 :         loinfo->dacl.privtype = 0;
    3937         164 :         loinfo->dacl.initprivs = NULL;
    3938         164 :         loinfo->rolname = getRoleName(thisowner);
    3939         164 :         loinfo->numlos = n;
    3940         164 :         loinfo->looids[0] = thisoid;
    3941             :         /* Collect OIDs of the remaining blobs in this group */
    3942         196 :         for (int k = 1; k < n; k++)
    3943             :         {
    3944             :             CatalogId   extraID;
    3945             : 
    3946          32 :             loinfo->looids[k] = atooid(PQgetvalue(res, i + k, i_oid));
    3947             : 
    3948             :             /* Make sure we can look up loinfo by any of the blobs' OIDs */
    3949          32 :             extraID.tableoid = LargeObjectRelationId;
    3950          32 :             extraID.oid = loinfo->looids[k];
    3951          32 :             recordAdditionalCatalogID(extraID, &loinfo->dobj);
    3952             :         }
    3953             : 
    3954             :         /* LOs have data */
    3955         164 :         loinfo->dobj.components |= DUMP_COMPONENT_DATA;
    3956             : 
    3957             :         /* Mark whether LO group has a non-empty ACL */
    3958         164 :         if (!PQgetisnull(res, i, i_lomacl))
    3959          74 :             loinfo->dobj.components |= DUMP_COMPONENT_ACL;
    3960             : 
    3961             :         /*
    3962             :          * In binary-upgrade mode for LOs, we do *not* dump out the LO data,
    3963             :          * as it will be copied by pg_upgrade, which simply copies the
    3964             :          * pg_largeobject table. We *do* however dump out anything but the
    3965             :          * data, as pg_upgrade copies just pg_largeobject, but not
    3966             :          * pg_largeobject_metadata, after the dump is restored.  In versions
    3967             :          * before v12, this is done via proper large object commands.  In
    3968             :          * newer versions, we dump the content of pg_largeobject_metadata and
    3969             :          * any associated pg_shdepend rows, which is faster to restore.  (On
    3970             :          * <v12, pg_largeobject_metadata was created WITH OIDS, so the OID
    3971             :          * column is hidden and won't be dumped.)
    3972             :          */
    3973         164 :         if (dopt->binary_upgrade)
    3974             :         {
    3975           6 :             if (fout->remoteVersion >= 120000)
    3976             :             {
    3977             :                 /*
    3978             :                  * We should've saved pg_largeobject_metadata's dump ID before
    3979             :                  * this point.
    3980             :                  */
    3981             :                 Assert(lo_metadata_dumpId);
    3982             : 
    3983           6 :                 loinfo->dobj.dump &= ~(DUMP_COMPONENT_DATA | DUMP_COMPONENT_ACL | DUMP_COMPONENT_DEFINITION);
    3984             : 
    3985             :                 /*
    3986             :                  * Mark the large object as dependent on
    3987             :                  * pg_largeobject_metadata so that any large object
    3988             :                  * comments/seclables are dumped after it.
    3989             :                  */
    3990           6 :                 loinfo->dobj.dependencies = (DumpId *) pg_malloc(sizeof(DumpId));
    3991           6 :                 loinfo->dobj.dependencies[0] = lo_metadata_dumpId;
    3992           6 :                 loinfo->dobj.nDeps = loinfo->dobj.allocDeps = 1;
    3993             :             }
    3994             :             else
    3995           0 :                 loinfo->dobj.dump &= ~DUMP_COMPONENT_DATA;
    3996             :         }
    3997             : 
    3998             :         /*
    3999             :          * Create a "BLOBS" data item for the group, too. This is just a
    4000             :          * placeholder for sorting; it carries no data now.
    4001             :          */
    4002         164 :         lodata = (DumpableObject *) pg_malloc(sizeof(DumpableObject));
    4003         164 :         lodata->objType = DO_LARGE_OBJECT_DATA;
    4004         164 :         lodata->catId = nilCatalogId;
    4005         164 :         AssignDumpId(lodata);
    4006         164 :         lodata->name = pg_strdup(namebuf);
    4007         164 :         lodata->components |= DUMP_COMPONENT_DATA;
    4008             :         /* Set up explicit dependency from data to metadata */
    4009         164 :         lodata->dependencies = (DumpId *) pg_malloc(sizeof(DumpId));
    4010         164 :         lodata->dependencies[0] = loinfo->dobj.dumpId;
    4011         164 :         lodata->nDeps = lodata->allocDeps = 1;
    4012             :     }
    4013             : 
    4014         410 :     PQclear(res);
    4015         410 :     destroyPQExpBuffer(loQry);
    4016         410 : }
    4017             : 
    4018             : /*
    4019             :  * dumpLO
    4020             :  *
    4021             :  * dump the definition (metadata) of the given large object group
    4022             :  */
    4023             : static void
    4024         162 : dumpLO(Archive *fout, const LoInfo *loinfo)
    4025             : {
    4026         162 :     PQExpBuffer cquery = createPQExpBuffer();
    4027             : 
    4028             :     /*
    4029             :      * The "definition" is just a newline-separated list of OIDs.  We need to
    4030             :      * put something into the dropStmt too, but it can just be a comment.
    4031             :      */
    4032         356 :     for (int i = 0; i < loinfo->numlos; i++)
    4033         194 :         appendPQExpBuffer(cquery, "%u\n", loinfo->looids[i]);
    4034             : 
    4035         162 :     if (loinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
    4036         158 :         ArchiveEntry(fout, loinfo->dobj.catId, loinfo->dobj.dumpId,
    4037         158 :                      ARCHIVE_OPTS(.tag = loinfo->dobj.name,
    4038             :                                   .owner = loinfo->rolname,
    4039             :                                   .description = "BLOB METADATA",
    4040             :                                   .section = SECTION_DATA,
    4041             :                                   .createStmt = cquery->data,
    4042             :                                   .dropStmt = "-- dummy"));
    4043             : 
    4044             :     /*
    4045             :      * Dump per-blob comments and seclabels if any.  We assume these are rare
    4046             :      * enough that it's okay to generate retail TOC entries for them.
    4047             :      */
    4048         162 :     if (loinfo->dobj.dump & (DUMP_COMPONENT_COMMENT |
    4049             :                              DUMP_COMPONENT_SECLABEL))
    4050             :     {
    4051         212 :         for (int i = 0; i < loinfo->numlos; i++)
    4052             :         {
    4053             :             CatalogId   catId;
    4054             :             char        namebuf[32];
    4055             : 
    4056             :             /* Build identifying info for this blob */
    4057         122 :             catId.tableoid = loinfo->dobj.catId.tableoid;
    4058         122 :             catId.oid = loinfo->looids[i];
    4059         122 :             snprintf(namebuf, sizeof(namebuf), "%u", loinfo->looids[i]);
    4060             : 
    4061         122 :             if (loinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
    4062         122 :                 dumpComment(fout, "LARGE OBJECT", namebuf,
    4063         122 :                             NULL, loinfo->rolname,
    4064         122 :                             catId, 0, loinfo->dobj.dumpId);
    4065             : 
    4066         122 :             if (loinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
    4067           0 :                 dumpSecLabel(fout, "LARGE OBJECT", namebuf,
    4068           0 :                              NULL, loinfo->rolname,
    4069           0 :                              catId, 0, loinfo->dobj.dumpId);
    4070             :         }
    4071             :     }
    4072             : 
    4073             :     /*
    4074             :      * Dump the ACLs if any (remember that all blobs in the group will have
    4075             :      * the same ACL).  If there's just one blob, dump a simple ACL entry; if
    4076             :      * there's more, make a "LARGE OBJECTS" entry that really contains only
    4077             :      * the ACL for the first blob.  _printTocEntry() will be cued by the tag
    4078             :      * string to emit a mutated version for each blob.
    4079             :      */
    4080         162 :     if (loinfo->dobj.dump & DUMP_COMPONENT_ACL)
    4081             :     {
    4082             :         char        namebuf[32];
    4083             : 
    4084             :         /* Build identifying info for the first blob */
    4085          72 :         snprintf(namebuf, sizeof(namebuf), "%u", loinfo->looids[0]);
    4086             : 
    4087          72 :         if (loinfo->numlos > 1)
    4088             :         {
    4089             :             char        tagbuf[64];
    4090             : 
    4091           0 :             snprintf(tagbuf, sizeof(tagbuf), "LARGE OBJECTS %u..%u",
    4092           0 :                      loinfo->looids[0], loinfo->looids[loinfo->numlos - 1]);
    4093             : 
    4094           0 :             dumpACL(fout, loinfo->dobj.dumpId, InvalidDumpId,
    4095             :                     "LARGE OBJECT", namebuf, NULL, NULL,
    4096           0 :                     tagbuf, loinfo->rolname, &loinfo->dacl);
    4097             :         }
    4098             :         else
    4099             :         {
    4100          72 :             dumpACL(fout, loinfo->dobj.dumpId, InvalidDumpId,
    4101             :                     "LARGE OBJECT", namebuf, NULL, NULL,
    4102          72 :                     NULL, loinfo->rolname, &loinfo->dacl);
    4103             :         }
    4104             :     }
    4105             : 
    4106         162 :     destroyPQExpBuffer(cquery);
    4107         162 : }
    4108             : 
    4109             : /*
    4110             :  * dumpLOs:
    4111             :  *  dump the data contents of the large objects in the given group
    4112             :  */
    4113             : static int
    4114         150 : dumpLOs(Archive *fout, const void *arg)
    4115             : {
    4116         150 :     const LoInfo *loinfo = (const LoInfo *) arg;
    4117         150 :     PGconn     *conn = GetConnection(fout);
    4118             :     char        buf[LOBBUFSIZE];
    4119             : 
    4120         150 :     pg_log_info("saving large objects \"%s\"", loinfo->dobj.name);
    4121             : 
    4122         328 :     for (int i = 0; i < loinfo->numlos; i++)
    4123             :     {
    4124         178 :         Oid         loOid = loinfo->looids[i];
    4125             :         int         loFd;
    4126             :         int         cnt;
    4127             : 
    4128             :         /* Open the LO */
    4129         178 :         loFd = lo_open(conn, loOid, INV_READ);
    4130         178 :         if (loFd == -1)
    4131           0 :             pg_fatal("could not open large object %u: %s",
    4132             :                      loOid, PQerrorMessage(conn));
    4133             : 
    4134         178 :         StartLO(fout, loOid);
    4135             : 
    4136             :         /* Now read it in chunks, sending data to archive */
    4137             :         do
    4138             :         {
    4139         274 :             cnt = lo_read(conn, loFd, buf, LOBBUFSIZE);
    4140         274 :             if (cnt < 0)
    4141           0 :                 pg_fatal("error reading large object %u: %s",
    4142             :                          loOid, PQerrorMessage(conn));
    4143             : 
    4144         274 :             WriteData(fout, buf, cnt);
    4145         274 :         } while (cnt > 0);
    4146             : 
    4147         178 :         lo_close(conn, loFd);
    4148             : 
    4149         178 :         EndLO(fout, loOid);
    4150             :     }
    4151             : 
    4152         150 :     return 1;
    4153             : }
    4154             : 
    4155             : /*
    4156             :  * getPolicies
    4157             :  *    get information about all RLS policies on dumpable tables.
    4158             :  */
    4159             : void
    4160         468 : getPolicies(Archive *fout, TableInfo tblinfo[], int numTables)
    4161             : {
    4162         468 :     DumpOptions *dopt = fout->dopt;
    4163             :     PQExpBuffer query;
    4164             :     PQExpBuffer tbloids;
    4165             :     PGresult   *res;
    4166             :     PolicyInfo *polinfo;
    4167             :     int         i_oid;
    4168             :     int         i_tableoid;
    4169             :     int         i_polrelid;
    4170             :     int         i_polname;
    4171             :     int         i_polcmd;
    4172             :     int         i_polpermissive;
    4173             :     int         i_polroles;
    4174             :     int         i_polqual;
    4175             :     int         i_polwithcheck;
    4176             :     int         i,
    4177             :                 j,
    4178             :                 ntups;
    4179             : 
    4180             :     /* No policies before 9.5 */
    4181         468 :     if (fout->remoteVersion < 90500)
    4182           0 :         return;
    4183             : 
    4184             :     /* Skip if --no-policies was specified */
    4185         468 :     if (dopt->no_policies)
    4186           2 :         return;
    4187             : 
    4188         466 :     query = createPQExpBuffer();
    4189         466 :     tbloids = createPQExpBuffer();
    4190             : 
    4191             :     /*
    4192             :      * Identify tables of interest, and check which ones have RLS enabled.
    4193             :      */
    4194         466 :     appendPQExpBufferChar(tbloids, '{');
    4195      123720 :     for (i = 0; i < numTables; i++)
    4196             :     {
    4197      123254 :         TableInfo  *tbinfo = &tblinfo[i];
    4198             : 
    4199             :         /* Ignore row security on tables not to be dumped */
    4200      123254 :         if (!(tbinfo->dobj.dump & DUMP_COMPONENT_POLICY))
    4201      103984 :             continue;
    4202             : 
    4203             :         /* It can't have RLS or policies if it's not a table */
    4204       19270 :         if (tbinfo->relkind != RELKIND_RELATION &&
    4205        5206 :             tbinfo->relkind != RELKIND_PARTITIONED_TABLE)
    4206        3560 :             continue;
    4207             : 
    4208             :         /* Add it to the list of table OIDs to be probed below */
    4209       15710 :         if (tbloids->len > 1) /* do we have more than the '{'? */
    4210       15398 :             appendPQExpBufferChar(tbloids, ',');
    4211       15710 :         appendPQExpBuffer(tbloids, "%u", tbinfo->dobj.catId.oid);
    4212             : 
    4213             :         /* Is RLS enabled?  (That's separate from whether it has policies) */
    4214       15710 :         if (tbinfo->rowsec)
    4215             :         {
    4216         132 :             tbinfo->dobj.components |= DUMP_COMPONENT_POLICY;
    4217             : 
    4218             :             /*
    4219             :              * We represent RLS being enabled on a table by creating a
    4220             :              * PolicyInfo object with null polname.
    4221             :              *
    4222             :              * Note: use tableoid 0 so that this object won't be mistaken for
    4223             :              * something that pg_depend entries apply to.
    4224             :              */
    4225         132 :             polinfo = pg_malloc(sizeof(PolicyInfo));
    4226         132 :             polinfo->dobj.objType = DO_POLICY;
    4227         132 :             polinfo->dobj.catId.tableoid = 0;
    4228         132 :             polinfo->dobj.catId.oid = tbinfo->dobj.catId.oid;
    4229         132 :             AssignDumpId(&polinfo->dobj);
    4230         132 :             polinfo->dobj.namespace = tbinfo->dobj.namespace;
    4231         132 :             polinfo->dobj.name = pg_strdup(tbinfo->dobj.name);
    4232         132 :             polinfo->poltable = tbinfo;
    4233         132 :             polinfo->polname = NULL;
    4234         132 :             polinfo->polcmd = '\0';
    4235         132 :             polinfo->polpermissive = 0;
    4236         132 :             polinfo->polroles = NULL;
    4237         132 :             polinfo->polqual = NULL;
    4238         132 :             polinfo->polwithcheck = NULL;
    4239             :         }
    4240             :     }
    4241         466 :     appendPQExpBufferChar(tbloids, '}');
    4242             : 
    4243             :     /*
    4244             :      * Now, read all RLS policies belonging to the tables of interest, and
    4245             :      * create PolicyInfo objects for them.  (Note that we must filter the
    4246             :      * results server-side not locally, because we dare not apply pg_get_expr
    4247             :      * to tables we don't have lock on.)
    4248             :      */
    4249         466 :     pg_log_info("reading row-level security policies");
    4250             : 
    4251         466 :     printfPQExpBuffer(query,
    4252             :                       "SELECT pol.oid, pol.tableoid, pol.polrelid, pol.polname, pol.polcmd, ");
    4253         466 :     if (fout->remoteVersion >= 100000)
    4254         466 :         appendPQExpBufferStr(query, "pol.polpermissive, ");
    4255             :     else
    4256           0 :         appendPQExpBufferStr(query, "'t' as polpermissive, ");
    4257         466 :     appendPQExpBuffer(query,
    4258             :                       "CASE WHEN pol.polroles = '{0}' THEN NULL ELSE "
    4259             :                       "   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, "
    4260             :                       "pg_catalog.pg_get_expr(pol.polqual, pol.polrelid) AS polqual, "
    4261             :                       "pg_catalog.pg_get_expr(pol.polwithcheck, pol.polrelid) AS polwithcheck "
    4262             :                       "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
    4263             :                       "JOIN pg_catalog.pg_policy pol ON (src.tbloid = pol.polrelid)",
    4264             :                       tbloids->data);
    4265             : 
    4266         466 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    4267             : 
    4268         466 :     ntups = PQntuples(res);
    4269         466 :     if (ntups > 0)
    4270             :     {
    4271         100 :         i_oid = PQfnumber(res, "oid");
    4272         100 :         i_tableoid = PQfnumber(res, "tableoid");
    4273         100 :         i_polrelid = PQfnumber(res, "polrelid");
    4274         100 :         i_polname = PQfnumber(res, "polname");
    4275         100 :         i_polcmd = PQfnumber(res, "polcmd");
    4276         100 :         i_polpermissive = PQfnumber(res, "polpermissive");
    4277         100 :         i_polroles = PQfnumber(res, "polroles");
    4278         100 :         i_polqual = PQfnumber(res, "polqual");
    4279         100 :         i_polwithcheck = PQfnumber(res, "polwithcheck");
    4280             : 
    4281         100 :         polinfo = pg_malloc(ntups * sizeof(PolicyInfo));
    4282             : 
    4283         748 :         for (j = 0; j < ntups; j++)
    4284             :         {
    4285         648 :             Oid         polrelid = atooid(PQgetvalue(res, j, i_polrelid));
    4286         648 :             TableInfo  *tbinfo = findTableByOid(polrelid);
    4287             : 
    4288         648 :             tbinfo->dobj.components |= DUMP_COMPONENT_POLICY;
    4289             : 
    4290         648 :             polinfo[j].dobj.objType = DO_POLICY;
    4291         648 :             polinfo[j].dobj.catId.tableoid =
    4292         648 :                 atooid(PQgetvalue(res, j, i_tableoid));
    4293         648 :             polinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
    4294         648 :             AssignDumpId(&polinfo[j].dobj);
    4295         648 :             polinfo[j].dobj.namespace = tbinfo->dobj.namespace;
    4296         648 :             polinfo[j].poltable = tbinfo;
    4297         648 :             polinfo[j].polname = pg_strdup(PQgetvalue(res, j, i_polname));
    4298         648 :             polinfo[j].dobj.name = pg_strdup(polinfo[j].polname);
    4299             : 
    4300         648 :             polinfo[j].polcmd = *(PQgetvalue(res, j, i_polcmd));
    4301         648 :             polinfo[j].polpermissive = *(PQgetvalue(res, j, i_polpermissive)) == 't';
    4302             : 
    4303         648 :             if (PQgetisnull(res, j, i_polroles))
    4304         312 :                 polinfo[j].polroles = NULL;
    4305             :             else
    4306         336 :                 polinfo[j].polroles = pg_strdup(PQgetvalue(res, j, i_polroles));
    4307             : 
    4308         648 :             if (PQgetisnull(res, j, i_polqual))
    4309          84 :                 polinfo[j].polqual = NULL;
    4310             :             else
    4311         564 :                 polinfo[j].polqual = pg_strdup(PQgetvalue(res, j, i_polqual));
    4312             : 
    4313         648 :             if (PQgetisnull(res, j, i_polwithcheck))
    4314         348 :                 polinfo[j].polwithcheck = NULL;
    4315             :             else
    4316         300 :                 polinfo[j].polwithcheck
    4317         300 :                     = pg_strdup(PQgetvalue(res, j, i_polwithcheck));
    4318             :         }
    4319             :     }
    4320             : 
    4321         466 :     PQclear(res);
    4322             : 
    4323         466 :     destroyPQExpBuffer(query);
    4324         466 :     destroyPQExpBuffer(tbloids);
    4325             : }
    4326             : 
    4327             : /*
    4328             :  * dumpPolicy
    4329             :  *    dump the definition of the given policy
    4330             :  */
    4331             : static void
    4332         780 : dumpPolicy(Archive *fout, const PolicyInfo *polinfo)
    4333             : {
    4334         780 :     DumpOptions *dopt = fout->dopt;
    4335         780 :     TableInfo  *tbinfo = polinfo->poltable;
    4336             :     PQExpBuffer query;
    4337             :     PQExpBuffer delqry;
    4338             :     PQExpBuffer polprefix;
    4339             :     char       *qtabname;
    4340             :     const char *cmd;
    4341             :     char       *tag;
    4342             : 
    4343             :     /* Do nothing if not dumping schema */
    4344         780 :     if (!dopt->dumpSchema)
    4345          98 :         return;
    4346             : 
    4347             :     /*
    4348             :      * If polname is NULL, then this record is just indicating that ROW LEVEL
    4349             :      * SECURITY is enabled for the table. Dump as ALTER TABLE <table> ENABLE
    4350             :      * ROW LEVEL SECURITY.
    4351             :      */
    4352         682 :     if (polinfo->polname == NULL)
    4353             :     {
    4354         118 :         query = createPQExpBuffer();
    4355             : 
    4356         118 :         appendPQExpBuffer(query, "ALTER TABLE %s ENABLE ROW LEVEL SECURITY;",
    4357         118 :                           fmtQualifiedDumpable(tbinfo));
    4358             : 
    4359             :         /*
    4360             :          * We must emit the ROW SECURITY object's dependency on its table
    4361             :          * explicitly, because it will not match anything in pg_depend (unlike
    4362             :          * the case for other PolicyInfo objects).
    4363             :          */
    4364         118 :         if (polinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
    4365         118 :             ArchiveEntry(fout, polinfo->dobj.catId, polinfo->dobj.dumpId,
    4366         118 :                          ARCHIVE_OPTS(.tag = polinfo->dobj.name,
    4367             :                                       .namespace = polinfo->dobj.namespace->dobj.name,
    4368             :                                       .owner = tbinfo->rolname,
    4369             :                                       .description = "ROW SECURITY",
    4370             :                                       .section = SECTION_POST_DATA,
    4371             :                                       .createStmt = query->data,
    4372             :                                       .deps = &(tbinfo->dobj.dumpId),
    4373             :                                       .nDeps = 1));
    4374             : 
    4375         118 :         destroyPQExpBuffer(query);
    4376         118 :         return;
    4377             :     }
    4378             : 
    4379         564 :     if (polinfo->polcmd == '*')
    4380         188 :         cmd = "";
    4381         376 :     else if (polinfo->polcmd == 'r')
    4382         102 :         cmd = " FOR SELECT";
    4383         274 :     else if (polinfo->polcmd == 'a')
    4384          70 :         cmd = " FOR INSERT";
    4385         204 :     else if (polinfo->polcmd == 'w')
    4386         102 :         cmd = " FOR UPDATE";
    4387         102 :     else if (polinfo->polcmd == 'd')
    4388         102 :         cmd = " FOR DELETE";
    4389             :     else
    4390           0 :         pg_fatal("unexpected policy command type: %c",
    4391             :                  polinfo->polcmd);
    4392             : 
    4393         564 :     query = createPQExpBuffer();
    4394         564 :     delqry = createPQExpBuffer();
    4395         564 :     polprefix = createPQExpBuffer();
    4396             : 
    4397         564 :     qtabname = pg_strdup(fmtId(tbinfo->dobj.name));
    4398             : 
    4399         564 :     appendPQExpBuffer(query, "CREATE POLICY %s", fmtId(polinfo->polname));
    4400             : 
    4401         564 :     appendPQExpBuffer(query, " ON %s%s%s", fmtQualifiedDumpable(tbinfo),
    4402         564 :                       !polinfo->polpermissive ? " AS RESTRICTIVE" : "", cmd);
    4403             : 
    4404         564 :     if (polinfo->polroles != NULL)
    4405         280 :         appendPQExpBuffer(query, " TO %s", polinfo->polroles);
    4406             : 
    4407         564 :     if (polinfo->polqual != NULL)
    4408         494 :         appendPQExpBuffer(query, " USING (%s)", polinfo->polqual);
    4409             : 
    4410         564 :     if (polinfo->polwithcheck != NULL)
    4411         258 :         appendPQExpBuffer(query, " WITH CHECK (%s)", polinfo->polwithcheck);
    4412             : 
    4413         564 :     appendPQExpBufferStr(query, ";\n");
    4414             : 
    4415         564 :     appendPQExpBuffer(delqry, "DROP POLICY %s", fmtId(polinfo->polname));
    4416         564 :     appendPQExpBuffer(delqry, " ON %s;\n", fmtQualifiedDumpable(tbinfo));
    4417             : 
    4418         564 :     appendPQExpBuffer(polprefix, "POLICY %s ON",
    4419         564 :                       fmtId(polinfo->polname));
    4420             : 
    4421         564 :     tag = psprintf("%s %s", tbinfo->dobj.name, polinfo->dobj.name);
    4422             : 
    4423         564 :     if (polinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
    4424         564 :         ArchiveEntry(fout, polinfo->dobj.catId, polinfo->dobj.dumpId,
    4425         564 :                      ARCHIVE_OPTS(.tag = tag,
    4426             :                                   .namespace = polinfo->dobj.namespace->dobj.name,
    4427             :                                   .owner = tbinfo->rolname,
    4428             :                                   .description = "POLICY",
    4429             :                                   .section = SECTION_POST_DATA,
    4430             :                                   .createStmt = query->data,
    4431             :                                   .dropStmt = delqry->data));
    4432             : 
    4433         564 :     if (polinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
    4434           0 :         dumpComment(fout, polprefix->data, qtabname,
    4435           0 :                     tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
    4436           0 :                     polinfo->dobj.catId, 0, polinfo->dobj.dumpId);
    4437             : 
    4438         564 :     free(tag);
    4439         564 :     destroyPQExpBuffer(query);
    4440         564 :     destroyPQExpBuffer(delqry);
    4441         564 :     destroyPQExpBuffer(polprefix);
    4442         564 :     free(qtabname);
    4443             : }
    4444             : 
    4445             : /*
    4446             :  * getPublications
    4447             :  *    get information about publications
    4448             :  */
    4449             : void
    4450         468 : getPublications(Archive *fout)
    4451             : {
    4452         468 :     DumpOptions *dopt = fout->dopt;
    4453             :     PQExpBuffer query;
    4454             :     PGresult   *res;
    4455             :     PublicationInfo *pubinfo;
    4456             :     int         i_tableoid;
    4457             :     int         i_oid;
    4458             :     int         i_pubname;
    4459             :     int         i_pubowner;
    4460             :     int         i_puballtables;
    4461             :     int         i_pubinsert;
    4462             :     int         i_pubupdate;
    4463             :     int         i_pubdelete;
    4464             :     int         i_pubtruncate;
    4465             :     int         i_pubviaroot;
    4466             :     int         i_pubgencols;
    4467             :     int         i,
    4468             :                 ntups;
    4469             : 
    4470         468 :     if (dopt->no_publications || fout->remoteVersion < 100000)
    4471           0 :         return;
    4472             : 
    4473         468 :     query = createPQExpBuffer();
    4474             : 
    4475             :     /* Get the publications. */
    4476         468 :     appendPQExpBufferStr(query, "SELECT p.tableoid, p.oid, p.pubname, "
    4477             :                          "p.pubowner, p.puballtables, p.pubinsert, "
    4478             :                          "p.pubupdate, p.pubdelete, ");
    4479             : 
    4480         468 :     if (fout->remoteVersion >= 110000)
    4481         468 :         appendPQExpBufferStr(query, "p.pubtruncate, ");
    4482             :     else
    4483           0 :         appendPQExpBufferStr(query, "false AS pubtruncate, ");
    4484             : 
    4485         468 :     if (fout->remoteVersion >= 130000)
    4486         468 :         appendPQExpBufferStr(query, "p.pubviaroot, ");
    4487             :     else
    4488           0 :         appendPQExpBufferStr(query, "false AS pubviaroot, ");
    4489             : 
    4490         468 :     if (fout->remoteVersion >= 180000)
    4491         468 :         appendPQExpBufferStr(query, "p.pubgencols ");
    4492             :     else
    4493           0 :         appendPQExpBuffer(query, "'%c' AS pubgencols ", PUBLISH_GENCOLS_NONE);
    4494             : 
    4495         468 :     appendPQExpBufferStr(query, "FROM pg_publication p");
    4496             : 
    4497         468 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    4498             : 
    4499         468 :     ntups = PQntuples(res);
    4500             : 
    4501         468 :     if (ntups == 0)
    4502         368 :         goto cleanup;
    4503             : 
    4504         100 :     i_tableoid = PQfnumber(res, "tableoid");
    4505         100 :     i_oid = PQfnumber(res, "oid");
    4506         100 :     i_pubname = PQfnumber(res, "pubname");
    4507         100 :     i_pubowner = PQfnumber(res, "pubowner");
    4508         100 :     i_puballtables = PQfnumber(res, "puballtables");
    4509         100 :     i_pubinsert = PQfnumber(res, "pubinsert");
    4510         100 :     i_pubupdate = PQfnumber(res, "pubupdate");
    4511         100 :     i_pubdelete = PQfnumber(res, "pubdelete");
    4512         100 :     i_pubtruncate = PQfnumber(res, "pubtruncate");
    4513         100 :     i_pubviaroot = PQfnumber(res, "pubviaroot");
    4514         100 :     i_pubgencols = PQfnumber(res, "pubgencols");
    4515             : 
    4516         100 :     pubinfo = pg_malloc(ntups * sizeof(PublicationInfo));
    4517             : 
    4518         592 :     for (i = 0; i < ntups; i++)
    4519             :     {
    4520         492 :         pubinfo[i].dobj.objType = DO_PUBLICATION;
    4521         492 :         pubinfo[i].dobj.catId.tableoid =
    4522         492 :             atooid(PQgetvalue(res, i, i_tableoid));
    4523         492 :         pubinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    4524         492 :         AssignDumpId(&pubinfo[i].dobj);
    4525         492 :         pubinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_pubname));
    4526         492 :         pubinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_pubowner));
    4527         492 :         pubinfo[i].puballtables =
    4528         492 :             (strcmp(PQgetvalue(res, i, i_puballtables), "t") == 0);
    4529         492 :         pubinfo[i].pubinsert =
    4530         492 :             (strcmp(PQgetvalue(res, i, i_pubinsert), "t") == 0);
    4531         492 :         pubinfo[i].pubupdate =
    4532         492 :             (strcmp(PQgetvalue(res, i, i_pubupdate), "t") == 0);
    4533         492 :         pubinfo[i].pubdelete =
    4534         492 :             (strcmp(PQgetvalue(res, i, i_pubdelete), "t") == 0);
    4535         492 :         pubinfo[i].pubtruncate =
    4536         492 :             (strcmp(PQgetvalue(res, i, i_pubtruncate), "t") == 0);
    4537         492 :         pubinfo[i].pubviaroot =
    4538         492 :             (strcmp(PQgetvalue(res, i, i_pubviaroot), "t") == 0);
    4539         492 :         pubinfo[i].pubgencols_type =
    4540         492 :             *(PQgetvalue(res, i, i_pubgencols));
    4541             : 
    4542             :         /* Decide whether we want to dump it */
    4543         492 :         selectDumpableObject(&(pubinfo[i].dobj), fout);
    4544             :     }
    4545             : 
    4546         100 : cleanup:
    4547         468 :     PQclear(res);
    4548             : 
    4549         468 :     destroyPQExpBuffer(query);
    4550             : }
    4551             : 
    4552             : /*
    4553             :  * dumpPublication
    4554             :  *    dump the definition of the given publication
    4555             :  */
    4556             : static void
    4557         412 : dumpPublication(Archive *fout, const PublicationInfo *pubinfo)
    4558             : {
    4559         412 :     DumpOptions *dopt = fout->dopt;
    4560             :     PQExpBuffer delq;
    4561             :     PQExpBuffer query;
    4562             :     char       *qpubname;
    4563         412 :     bool        first = true;
    4564             : 
    4565             :     /* Do nothing if not dumping schema */
    4566         412 :     if (!dopt->dumpSchema)
    4567          60 :         return;
    4568             : 
    4569         352 :     delq = createPQExpBuffer();
    4570         352 :     query = createPQExpBuffer();
    4571             : 
    4572         352 :     qpubname = pg_strdup(fmtId(pubinfo->dobj.name));
    4573             : 
    4574         352 :     appendPQExpBuffer(delq, "DROP PUBLICATION %s;\n",
    4575             :                       qpubname);
    4576             : 
    4577         352 :     appendPQExpBuffer(query, "CREATE PUBLICATION %s",
    4578             :                       qpubname);
    4579             : 
    4580         352 :     if (pubinfo->puballtables)
    4581          72 :         appendPQExpBufferStr(query, " FOR ALL TABLES");
    4582             : 
    4583         352 :     appendPQExpBufferStr(query, " WITH (publish = '");
    4584         352 :     if (pubinfo->pubinsert)
    4585             :     {
    4586         282 :         appendPQExpBufferStr(query, "insert");
    4587         282 :         first = false;
    4588             :     }
    4589             : 
    4590         352 :     if (pubinfo->pubupdate)
    4591             :     {
    4592         282 :         if (!first)
    4593         282 :             appendPQExpBufferStr(query, ", ");
    4594             : 
    4595         282 :         appendPQExpBufferStr(query, "update");
    4596         282 :         first = false;
    4597             :     }
    4598             : 
    4599         352 :     if (pubinfo->pubdelete)
    4600             :     {
    4601         282 :         if (!first)
    4602         282 :             appendPQExpBufferStr(query, ", ");
    4603             : 
    4604         282 :         appendPQExpBufferStr(query, "delete");
    4605         282 :         first = false;
    4606             :     }
    4607             : 
    4608         352 :     if (pubinfo->pubtruncate)
    4609             :     {
    4610         282 :         if (!first)
    4611         282 :             appendPQExpBufferStr(query, ", ");
    4612             : 
    4613         282 :         appendPQExpBufferStr(query, "truncate");
    4614         282 :         first = false;
    4615             :     }
    4616             : 
    4617         352 :     appendPQExpBufferChar(query, '\'');
    4618             : 
    4619         352 :     if (pubinfo->pubviaroot)
    4620           0 :         appendPQExpBufferStr(query, ", publish_via_partition_root = true");
    4621             : 
    4622         352 :     if (pubinfo->pubgencols_type == PUBLISH_GENCOLS_STORED)
    4623          70 :         appendPQExpBufferStr(query, ", publish_generated_columns = stored");
    4624             : 
    4625         352 :     appendPQExpBufferStr(query, ");\n");
    4626             : 
    4627         352 :     if (pubinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
    4628         352 :         ArchiveEntry(fout, pubinfo->dobj.catId, pubinfo->dobj.dumpId,
    4629         352 :                      ARCHIVE_OPTS(.tag = pubinfo->dobj.name,
    4630             :                                   .owner = pubinfo->rolname,
    4631             :                                   .description = "PUBLICATION",
    4632             :                                   .section = SECTION_POST_DATA,
    4633             :                                   .createStmt = query->data,
    4634             :                                   .dropStmt = delq->data));
    4635             : 
    4636         352 :     if (pubinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
    4637          70 :         dumpComment(fout, "PUBLICATION", qpubname,
    4638          70 :                     NULL, pubinfo->rolname,
    4639          70 :                     pubinfo->dobj.catId, 0, pubinfo->dobj.dumpId);
    4640             : 
    4641         352 :     if (pubinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
    4642           0 :         dumpSecLabel(fout, "PUBLICATION", qpubname,
    4643           0 :                      NULL, pubinfo->rolname,
    4644           0 :                      pubinfo->dobj.catId, 0, pubinfo->dobj.dumpId);
    4645             : 
    4646         352 :     destroyPQExpBuffer(delq);
    4647         352 :     destroyPQExpBuffer(query);
    4648         352 :     free(qpubname);
    4649             : }
    4650             : 
    4651             : /*
    4652             :  * getPublicationNamespaces
    4653             :  *    get information about publication membership for dumpable schemas.
    4654             :  */
    4655             : void
    4656         468 : getPublicationNamespaces(Archive *fout)
    4657             : {
    4658             :     PQExpBuffer query;
    4659             :     PGresult   *res;
    4660             :     PublicationSchemaInfo *pubsinfo;
    4661         468 :     DumpOptions *dopt = fout->dopt;
    4662             :     int         i_tableoid;
    4663             :     int         i_oid;
    4664             :     int         i_pnpubid;
    4665             :     int         i_pnnspid;
    4666             :     int         i,
    4667             :                 j,
    4668             :                 ntups;
    4669             : 
    4670         468 :     if (dopt->no_publications || fout->remoteVersion < 150000)
    4671           0 :         return;
    4672             : 
    4673         468 :     query = createPQExpBuffer();
    4674             : 
    4675             :     /* Collect all publication membership info. */
    4676         468 :     appendPQExpBufferStr(query,
    4677             :                          "SELECT tableoid, oid, pnpubid, pnnspid "
    4678             :                          "FROM pg_catalog.pg_publication_namespace");
    4679         468 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    4680             : 
    4681         468 :     ntups = PQntuples(res);
    4682             : 
    4683         468 :     i_tableoid = PQfnumber(res, "tableoid");
    4684         468 :     i_oid = PQfnumber(res, "oid");
    4685         468 :     i_pnpubid = PQfnumber(res, "pnpubid");
    4686         468 :     i_pnnspid = PQfnumber(res, "pnnspid");
    4687             : 
    4688             :     /* this allocation may be more than we need */
    4689         468 :     pubsinfo = pg_malloc(ntups * sizeof(PublicationSchemaInfo));
    4690         468 :     j = 0;
    4691             : 
    4692         664 :     for (i = 0; i < ntups; i++)
    4693             :     {
    4694         196 :         Oid         pnpubid = atooid(PQgetvalue(res, i, i_pnpubid));
    4695         196 :         Oid         pnnspid = atooid(PQgetvalue(res, i, i_pnnspid));
    4696             :         PublicationInfo *pubinfo;
    4697             :         NamespaceInfo *nspinfo;
    4698             : 
    4699             :         /*
    4700             :          * Ignore any entries for which we aren't interested in either the
    4701             :          * publication or the rel.
    4702             :          */
    4703         196 :         pubinfo = findPublicationByOid(pnpubid);
    4704         196 :         if (pubinfo == NULL)
    4705           0 :             continue;
    4706         196 :         nspinfo = findNamespaceByOid(pnnspid);
    4707         196 :         if (nspinfo == NULL)
    4708           0 :             continue;
    4709             : 
    4710             :         /* OK, make a DumpableObject for this relationship */
    4711         196 :         pubsinfo[j].dobj.objType = DO_PUBLICATION_TABLE_IN_SCHEMA;
    4712         196 :         pubsinfo[j].dobj.catId.tableoid =
    4713         196 :             atooid(PQgetvalue(res, i, i_tableoid));
    4714         196 :         pubsinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    4715         196 :         AssignDumpId(&pubsinfo[j].dobj);
    4716         196 :         pubsinfo[j].dobj.namespace = nspinfo->dobj.namespace;
    4717         196 :         pubsinfo[j].dobj.name = nspinfo->dobj.name;
    4718         196 :         pubsinfo[j].publication = pubinfo;
    4719         196 :         pubsinfo[j].pubschema = nspinfo;
    4720             : 
    4721             :         /* Decide whether we want to dump it */
    4722         196 :         selectDumpablePublicationObject(&(pubsinfo[j].dobj), fout);
    4723             : 
    4724         196 :         j++;
    4725             :     }
    4726             : 
    4727         468 :     PQclear(res);
    4728         468 :     destroyPQExpBuffer(query);
    4729             : }
    4730             : 
    4731             : /*
    4732             :  * getPublicationTables
    4733             :  *    get information about publication membership for dumpable tables.
    4734             :  */
    4735             : void
    4736         468 : getPublicationTables(Archive *fout, TableInfo tblinfo[], int numTables)
    4737             : {
    4738             :     PQExpBuffer query;
    4739             :     PGresult   *res;
    4740             :     PublicationRelInfo *pubrinfo;
    4741         468 :     DumpOptions *dopt = fout->dopt;
    4742             :     int         i_tableoid;
    4743             :     int         i_oid;
    4744             :     int         i_prpubid;
    4745             :     int         i_prrelid;
    4746             :     int         i_prrelqual;
    4747             :     int         i_prattrs;
    4748             :     int         i,
    4749             :                 j,
    4750             :                 ntups;
    4751             : 
    4752         468 :     if (dopt->no_publications || fout->remoteVersion < 100000)
    4753           0 :         return;
    4754             : 
    4755         468 :     query = createPQExpBuffer();
    4756             : 
    4757             :     /* Collect all publication membership info. */
    4758         468 :     if (fout->remoteVersion >= 150000)
    4759         468 :         appendPQExpBufferStr(query,
    4760             :                              "SELECT tableoid, oid, prpubid, prrelid, "
    4761             :                              "pg_catalog.pg_get_expr(prqual, prrelid) AS prrelqual, "
    4762             :                              "(CASE\n"
    4763             :                              "  WHEN pr.prattrs IS NOT NULL THEN\n"
    4764             :                              "    (SELECT array_agg(attname)\n"
    4765             :                              "       FROM\n"
    4766             :                              "         pg_catalog.generate_series(0, pg_catalog.array_upper(pr.prattrs::pg_catalog.int2[], 1)) s,\n"
    4767             :                              "         pg_catalog.pg_attribute\n"
    4768             :                              "      WHERE attrelid = pr.prrelid AND attnum = prattrs[s])\n"
    4769             :                              "  ELSE NULL END) prattrs "
    4770             :                              "FROM pg_catalog.pg_publication_rel pr");
    4771             :     else
    4772           0 :         appendPQExpBufferStr(query,
    4773             :                              "SELECT tableoid, oid, prpubid, prrelid, "
    4774             :                              "NULL AS prrelqual, NULL AS prattrs "
    4775             :                              "FROM pg_catalog.pg_publication_rel");
    4776         468 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    4777             : 
    4778         468 :     ntups = PQntuples(res);
    4779             : 
    4780         468 :     i_tableoid = PQfnumber(res, "tableoid");
    4781         468 :     i_oid = PQfnumber(res, "oid");
    4782         468 :     i_prpubid = PQfnumber(res, "prpubid");
    4783         468 :     i_prrelid = PQfnumber(res, "prrelid");
    4784         468 :     i_prrelqual = PQfnumber(res, "prrelqual");
    4785         468 :     i_prattrs = PQfnumber(res, "prattrs");
    4786             : 
    4787             :     /* this allocation may be more than we need */
    4788         468 :     pubrinfo = pg_malloc(ntups * sizeof(PublicationRelInfo));
    4789         468 :     j = 0;
    4790             : 
    4791        1154 :     for (i = 0; i < ntups; i++)
    4792             :     {
    4793         686 :         Oid         prpubid = atooid(PQgetvalue(res, i, i_prpubid));
    4794         686 :         Oid         prrelid = atooid(PQgetvalue(res, i, i_prrelid));
    4795             :         PublicationInfo *pubinfo;
    4796             :         TableInfo  *tbinfo;
    4797             : 
    4798             :         /*
    4799             :          * Ignore any entries for which we aren't interested in either the
    4800             :          * publication or the rel.
    4801             :          */
    4802         686 :         pubinfo = findPublicationByOid(prpubid);
    4803         686 :         if (pubinfo == NULL)
    4804           0 :             continue;
    4805         686 :         tbinfo = findTableByOid(prrelid);
    4806         686 :         if (tbinfo == NULL)
    4807           0 :             continue;
    4808             : 
    4809             :         /* OK, make a DumpableObject for this relationship */
    4810         686 :         pubrinfo[j].dobj.objType = DO_PUBLICATION_REL;
    4811         686 :         pubrinfo[j].dobj.catId.tableoid =
    4812         686 :             atooid(PQgetvalue(res, i, i_tableoid));
    4813         686 :         pubrinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    4814         686 :         AssignDumpId(&pubrinfo[j].dobj);
    4815         686 :         pubrinfo[j].dobj.namespace = tbinfo->dobj.namespace;
    4816         686 :         pubrinfo[j].dobj.name = tbinfo->dobj.name;
    4817         686 :         pubrinfo[j].publication = pubinfo;
    4818         686 :         pubrinfo[j].pubtable = tbinfo;
    4819         686 :         if (PQgetisnull(res, i, i_prrelqual))
    4820         392 :             pubrinfo[j].pubrelqual = NULL;
    4821             :         else
    4822         294 :             pubrinfo[j].pubrelqual = pg_strdup(PQgetvalue(res, i, i_prrelqual));
    4823             : 
    4824         686 :         if (!PQgetisnull(res, i, i_prattrs))
    4825             :         {
    4826             :             char      **attnames;
    4827             :             int         nattnames;
    4828             :             PQExpBuffer attribs;
    4829             : 
    4830         196 :             if (!parsePGArray(PQgetvalue(res, i, i_prattrs),
    4831             :                               &attnames, &nattnames))
    4832           0 :                 pg_fatal("could not parse %s array", "prattrs");
    4833         196 :             attribs = createPQExpBuffer();
    4834         588 :             for (int k = 0; k < nattnames; k++)
    4835             :             {
    4836         392 :                 if (k > 0)
    4837         196 :                     appendPQExpBufferStr(attribs, ", ");
    4838             : 
    4839         392 :                 appendPQExpBufferStr(attribs, fmtId(attnames[k]));
    4840             :             }
    4841         196 :             pubrinfo[j].pubrattrs = attribs->data;
    4842         196 :             free(attribs);      /* but not attribs->data */
    4843         196 :             free(attnames);
    4844             :         }
    4845             :         else
    4846         490 :             pubrinfo[j].pubrattrs = NULL;
    4847             : 
    4848             :         /* Decide whether we want to dump it */
    4849         686 :         selectDumpablePublicationObject(&(pubrinfo[j].dobj), fout);
    4850             : 
    4851         686 :         j++;
    4852             :     }
    4853             : 
    4854         468 :     PQclear(res);
    4855         468 :     destroyPQExpBuffer(query);
    4856             : }
    4857             : 
    4858             : /*
    4859             :  * dumpPublicationNamespace
    4860             :  *    dump the definition of the given publication schema mapping.
    4861             :  */
    4862             : static void
    4863         164 : dumpPublicationNamespace(Archive *fout, const PublicationSchemaInfo *pubsinfo)
    4864             : {
    4865         164 :     DumpOptions *dopt = fout->dopt;
    4866         164 :     NamespaceInfo *schemainfo = pubsinfo->pubschema;
    4867         164 :     PublicationInfo *pubinfo = pubsinfo->publication;
    4868             :     PQExpBuffer query;
    4869             :     char       *tag;
    4870             : 
    4871             :     /* Do nothing if not dumping schema */
    4872         164 :     if (!dopt->dumpSchema)
    4873          24 :         return;
    4874             : 
    4875         140 :     tag = psprintf("%s %s", pubinfo->dobj.name, schemainfo->dobj.name);
    4876             : 
    4877         140 :     query = createPQExpBuffer();
    4878             : 
    4879         140 :     appendPQExpBuffer(query, "ALTER PUBLICATION %s ", fmtId(pubinfo->dobj.name));
    4880         140 :     appendPQExpBuffer(query, "ADD TABLES IN SCHEMA %s;\n", fmtId(schemainfo->dobj.name));
    4881             : 
    4882             :     /*
    4883             :      * There is no point in creating drop query as the drop is done by schema
    4884             :      * drop.
    4885             :      */
    4886         140 :     if (pubsinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
    4887         140 :         ArchiveEntry(fout, pubsinfo->dobj.catId, pubsinfo->dobj.dumpId,
    4888         140 :                      ARCHIVE_OPTS(.tag = tag,
    4889             :                                   .namespace = schemainfo->dobj.name,
    4890             :                                   .owner = pubinfo->rolname,
    4891             :                                   .description = "PUBLICATION TABLES IN SCHEMA",
    4892             :                                   .section = SECTION_POST_DATA,
    4893             :                                   .createStmt = query->data));
    4894             : 
    4895             :     /* These objects can't currently have comments or seclabels */
    4896             : 
    4897         140 :     free(tag);
    4898         140 :     destroyPQExpBuffer(query);
    4899             : }
    4900             : 
    4901             : /*
    4902             :  * dumpPublicationTable
    4903             :  *    dump the definition of the given publication table mapping
    4904             :  */
    4905             : static void
    4906         574 : dumpPublicationTable(Archive *fout, const PublicationRelInfo *pubrinfo)
    4907             : {
    4908         574 :     DumpOptions *dopt = fout->dopt;
    4909         574 :     PublicationInfo *pubinfo = pubrinfo->publication;
    4910         574 :     TableInfo  *tbinfo = pubrinfo->pubtable;
    4911             :     PQExpBuffer query;
    4912             :     char       *tag;
    4913             : 
    4914             :     /* Do nothing if not dumping schema */
    4915         574 :     if (!dopt->dumpSchema)
    4916          84 :         return;
    4917             : 
    4918         490 :     tag = psprintf("%s %s", pubinfo->dobj.name, tbinfo->dobj.name);
    4919             : 
    4920         490 :     query = createPQExpBuffer();
    4921             : 
    4922         490 :     appendPQExpBuffer(query, "ALTER PUBLICATION %s ADD TABLE ONLY",
    4923         490 :                       fmtId(pubinfo->dobj.name));
    4924         490 :     appendPQExpBuffer(query, " %s",
    4925         490 :                       fmtQualifiedDumpable(tbinfo));
    4926             : 
    4927         490 :     if (pubrinfo->pubrattrs)
    4928         140 :         appendPQExpBuffer(query, " (%s)", pubrinfo->pubrattrs);
    4929             : 
    4930         490 :     if (pubrinfo->pubrelqual)
    4931             :     {
    4932             :         /*
    4933             :          * It's necessary to add parentheses around the expression because
    4934             :          * pg_get_expr won't supply the parentheses for things like WHERE
    4935             :          * TRUE.
    4936             :          */
    4937         210 :         appendPQExpBuffer(query, " WHERE (%s)", pubrinfo->pubrelqual);
    4938             :     }
    4939         490 :     appendPQExpBufferStr(query, ";\n");
    4940             : 
    4941             :     /*
    4942             :      * There is no point in creating a drop query as the drop is done by table
    4943             :      * drop.  (If you think to change this, see also _printTocEntry().)
    4944             :      * Although this object doesn't really have ownership as such, set the
    4945             :      * owner field anyway to ensure that the command is run by the correct
    4946             :      * role at restore time.
    4947             :      */
    4948         490 :     if (pubrinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
    4949         490 :         ArchiveEntry(fout, pubrinfo->dobj.catId, pubrinfo->dobj.dumpId,
    4950         490 :                      ARCHIVE_OPTS(.tag = tag,
    4951             :                                   .namespace = tbinfo->dobj.namespace->dobj.name,
    4952             :                                   .owner = pubinfo->rolname,
    4953             :                                   .description = "PUBLICATION TABLE",
    4954             :                                   .section = SECTION_POST_DATA,
    4955             :                                   .createStmt = query->data));
    4956             : 
    4957             :     /* These objects can't currently have comments or seclabels */
    4958             : 
    4959         490 :     free(tag);
    4960         490 :     destroyPQExpBuffer(query);
    4961             : }
    4962             : 
    4963             : /*
    4964             :  * Is the currently connected user a superuser?
    4965             :  */
    4966             : static bool
    4967         468 : is_superuser(Archive *fout)
    4968             : {
    4969         468 :     ArchiveHandle *AH = (ArchiveHandle *) fout;
    4970             :     const char *val;
    4971             : 
    4972         468 :     val = PQparameterStatus(AH->connection, "is_superuser");
    4973             : 
    4974         468 :     if (val && strcmp(val, "on") == 0)
    4975         462 :         return true;
    4976             : 
    4977           6 :     return false;
    4978             : }
    4979             : 
    4980             : /*
    4981             :  * Set the given value to restrict_nonsystem_relation_kind value. Since
    4982             :  * restrict_nonsystem_relation_kind is introduced in minor version releases,
    4983             :  * the setting query is effective only where available.
    4984             :  */
    4985             : static void
    4986         540 : set_restrict_relation_kind(Archive *AH, const char *value)
    4987             : {
    4988         540 :     PQExpBuffer query = createPQExpBuffer();
    4989             :     PGresult   *res;
    4990             : 
    4991         540 :     appendPQExpBuffer(query,
    4992             :                       "SELECT set_config(name, '%s', false) "
    4993             :                       "FROM pg_settings "
    4994             :                       "WHERE name = 'restrict_nonsystem_relation_kind'",
    4995             :                       value);
    4996         540 :     res = ExecuteSqlQuery(AH, query->data, PGRES_TUPLES_OK);
    4997             : 
    4998         540 :     PQclear(res);
    4999         540 :     destroyPQExpBuffer(query);
    5000         540 : }
    5001             : 
    5002             : /*
    5003             :  * getSubscriptions
    5004             :  *    get information about subscriptions
    5005             :  */
    5006             : void
    5007         468 : getSubscriptions(Archive *fout)
    5008             : {
    5009         468 :     DumpOptions *dopt = fout->dopt;
    5010             :     PQExpBuffer query;
    5011             :     PGresult   *res;
    5012             :     SubscriptionInfo *subinfo;
    5013             :     int         i_tableoid;
    5014             :     int         i_oid;
    5015             :     int         i_subname;
    5016             :     int         i_subowner;
    5017             :     int         i_subbinary;
    5018             :     int         i_substream;
    5019             :     int         i_subtwophasestate;
    5020             :     int         i_subdisableonerr;
    5021             :     int         i_subpasswordrequired;
    5022             :     int         i_subrunasowner;
    5023             :     int         i_subconninfo;
    5024             :     int         i_subslotname;
    5025             :     int         i_subsynccommit;
    5026             :     int         i_subpublications;
    5027             :     int         i_suborigin;
    5028             :     int         i_suboriginremotelsn;
    5029             :     int         i_subenabled;
    5030             :     int         i_subfailover;
    5031             :     int         i_subretaindeadtuples;
    5032             :     int         i,
    5033             :                 ntups;
    5034             : 
    5035         468 :     if (dopt->no_subscriptions || fout->remoteVersion < 100000)
    5036           0 :         return;
    5037             : 
    5038         468 :     if (!is_superuser(fout))
    5039             :     {
    5040             :         int         n;
    5041             : 
    5042           6 :         res = ExecuteSqlQuery(fout,
    5043             :                               "SELECT count(*) FROM pg_subscription "
    5044             :                               "WHERE subdbid = (SELECT oid FROM pg_database"
    5045             :                               "                 WHERE datname = current_database())",
    5046             :                               PGRES_TUPLES_OK);
    5047           6 :         n = atoi(PQgetvalue(res, 0, 0));
    5048           6 :         if (n > 0)
    5049           4 :             pg_log_warning("subscriptions not dumped because current user is not a superuser");
    5050           6 :         PQclear(res);
    5051           6 :         return;
    5052             :     }
    5053             : 
    5054         462 :     query = createPQExpBuffer();
    5055             : 
    5056             :     /* Get the subscriptions in current database. */
    5057         462 :     appendPQExpBufferStr(query,
    5058             :                          "SELECT s.tableoid, s.oid, s.subname,\n"
    5059             :                          " s.subowner,\n"
    5060             :                          " s.subconninfo, s.subslotname, s.subsynccommit,\n"
    5061             :                          " s.subpublications,\n");
    5062             : 
    5063         462 :     if (fout->remoteVersion >= 140000)
    5064         462 :         appendPQExpBufferStr(query, " s.subbinary,\n");
    5065             :     else
    5066           0 :         appendPQExpBufferStr(query, " false AS subbinary,\n");
    5067             : 
    5068         462 :     if (fout->remoteVersion >= 140000)
    5069         462 :         appendPQExpBufferStr(query, " s.substream,\n");
    5070             :     else
    5071           0 :         appendPQExpBufferStr(query, " 'f' AS substream,\n");
    5072             : 
    5073         462 :     if (fout->remoteVersion >= 150000)
    5074         462 :         appendPQExpBufferStr(query,
    5075             :                              " s.subtwophasestate,\n"
    5076             :                              " s.subdisableonerr,\n");
    5077             :     else
    5078           0 :         appendPQExpBuffer(query,
    5079             :                           " '%c' AS subtwophasestate,\n"
    5080             :                           " false AS subdisableonerr,\n",
    5081             :                           LOGICALREP_TWOPHASE_STATE_DISABLED);
    5082             : 
    5083         462 :     if (fout->remoteVersion >= 160000)
    5084         462 :         appendPQExpBufferStr(query,
    5085             :                              " s.subpasswordrequired,\n"
    5086             :                              " s.subrunasowner,\n"
    5087             :                              " s.suborigin,\n");
    5088             :     else
    5089           0 :         appendPQExpBuffer(query,
    5090             :                           " 't' AS subpasswordrequired,\n"
    5091             :                           " 't' AS subrunasowner,\n"
    5092             :                           " '%s' AS suborigin,\n",
    5093             :                           LOGICALREP_ORIGIN_ANY);
    5094             : 
    5095         462 :     if (dopt->binary_upgrade && fout->remoteVersion >= 170000)
    5096          62 :         appendPQExpBufferStr(query, " o.remote_lsn AS suboriginremotelsn,\n"
    5097             :                              " s.subenabled,\n");
    5098             :     else
    5099         400 :         appendPQExpBufferStr(query, " NULL AS suboriginremotelsn,\n"
    5100             :                              " false AS subenabled,\n");
    5101             : 
    5102         462 :     if (fout->remoteVersion >= 170000)
    5103         462 :         appendPQExpBufferStr(query,
    5104             :                              " s.subfailover,\n");
    5105             :     else
    5106           0 :         appendPQExpBufferStr(query,
    5107             :                              " false AS subfailover,\n");
    5108             : 
    5109         462 :     if (fout->remoteVersion >= 190000)
    5110         462 :         appendPQExpBufferStr(query,
    5111             :                              " s.subretaindeadtuples\n");
    5112             :     else
    5113           0 :         appendPQExpBufferStr(query,
    5114             :                              " false AS subretaindeadtuples\n");
    5115             : 
    5116         462 :     appendPQExpBufferStr(query,
    5117             :                          "FROM pg_subscription s\n");
    5118             : 
    5119         462 :     if (dopt->binary_upgrade && fout->remoteVersion >= 170000)
    5120          62 :         appendPQExpBufferStr(query,
    5121             :                              "LEFT JOIN pg_catalog.pg_replication_origin_status o \n"
    5122             :                              "    ON o.external_id = 'pg_' || s.oid::text \n");
    5123             : 
    5124         462 :     appendPQExpBufferStr(query,
    5125             :                          "WHERE s.subdbid = (SELECT oid FROM pg_database\n"
    5126             :                          "                   WHERE datname = current_database())");
    5127             : 
    5128         462 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    5129             : 
    5130         462 :     ntups = PQntuples(res);
    5131             : 
    5132             :     /*
    5133             :      * Get subscription fields. We don't include subskiplsn in the dump as
    5134             :      * after restoring the dump this value may no longer be relevant.
    5135             :      */
    5136         462 :     i_tableoid = PQfnumber(res, "tableoid");
    5137         462 :     i_oid = PQfnumber(res, "oid");
    5138         462 :     i_subname = PQfnumber(res, "subname");
    5139         462 :     i_subowner = PQfnumber(res, "subowner");
    5140         462 :     i_subenabled = PQfnumber(res, "subenabled");
    5141         462 :     i_subbinary = PQfnumber(res, "subbinary");
    5142         462 :     i_substream = PQfnumber(res, "substream");
    5143         462 :     i_subtwophasestate = PQfnumber(res, "subtwophasestate");
    5144         462 :     i_subdisableonerr = PQfnumber(res, "subdisableonerr");
    5145         462 :     i_subpasswordrequired = PQfnumber(res, "subpasswordrequired");
    5146         462 :     i_subrunasowner = PQfnumber(res, "subrunasowner");
    5147         462 :     i_subfailover = PQfnumber(res, "subfailover");
    5148         462 :     i_subretaindeadtuples = PQfnumber(res, "subretaindeadtuples");
    5149         462 :     i_subconninfo = PQfnumber(res, "subconninfo");
    5150         462 :     i_subslotname = PQfnumber(res, "subslotname");
    5151         462 :     i_subsynccommit = PQfnumber(res, "subsynccommit");
    5152         462 :     i_subpublications = PQfnumber(res, "subpublications");
    5153         462 :     i_suborigin = PQfnumber(res, "suborigin");
    5154         462 :     i_suboriginremotelsn = PQfnumber(res, "suboriginremotelsn");
    5155             : 
    5156         462 :     subinfo = pg_malloc(ntups * sizeof(SubscriptionInfo));
    5157             : 
    5158         748 :     for (i = 0; i < ntups; i++)
    5159             :     {
    5160         286 :         subinfo[i].dobj.objType = DO_SUBSCRIPTION;
    5161         286 :         subinfo[i].dobj.catId.tableoid =
    5162         286 :             atooid(PQgetvalue(res, i, i_tableoid));
    5163         286 :         subinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    5164         286 :         AssignDumpId(&subinfo[i].dobj);
    5165         286 :         subinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_subname));
    5166         286 :         subinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_subowner));
    5167             : 
    5168         286 :         subinfo[i].subenabled =
    5169         286 :             (strcmp(PQgetvalue(res, i, i_subenabled), "t") == 0);
    5170         286 :         subinfo[i].subbinary =
    5171         286 :             (strcmp(PQgetvalue(res, i, i_subbinary), "t") == 0);
    5172         286 :         subinfo[i].substream = *(PQgetvalue(res, i, i_substream));
    5173         286 :         subinfo[i].subtwophasestate = *(PQgetvalue(res, i, i_subtwophasestate));
    5174         286 :         subinfo[i].subdisableonerr =
    5175         286 :             (strcmp(PQgetvalue(res, i, i_subdisableonerr), "t") == 0);
    5176         286 :         subinfo[i].subpasswordrequired =
    5177         286 :             (strcmp(PQgetvalue(res, i, i_subpasswordrequired), "t") == 0);
    5178         286 :         subinfo[i].subrunasowner =
    5179         286 :             (strcmp(PQgetvalue(res, i, i_subrunasowner), "t") == 0);
    5180         286 :         subinfo[i].subfailover =
    5181         286 :             (strcmp(PQgetvalue(res, i, i_subfailover), "t") == 0);
    5182         286 :         subinfo[i].subretaindeadtuples =
    5183         286 :             (strcmp(PQgetvalue(res, i, i_subretaindeadtuples), "t") == 0);
    5184         572 :         subinfo[i].subconninfo =
    5185         286 :             pg_strdup(PQgetvalue(res, i, i_subconninfo));
    5186         286 :         if (PQgetisnull(res, i, i_subslotname))
    5187           0 :             subinfo[i].subslotname = NULL;
    5188             :         else
    5189         286 :             subinfo[i].subslotname =
    5190         286 :                 pg_strdup(PQgetvalue(res, i, i_subslotname));
    5191         572 :         subinfo[i].subsynccommit =
    5192         286 :             pg_strdup(PQgetvalue(res, i, i_subsynccommit));
    5193         572 :         subinfo[i].subpublications =
    5194         286 :             pg_strdup(PQgetvalue(res, i, i_subpublications));
    5195         286 :         subinfo[i].suborigin = pg_strdup(PQgetvalue(res, i, i_suborigin));
    5196         286 :         if (PQgetisnull(res, i, i_suboriginremotelsn))
    5197         284 :             subinfo[i].suboriginremotelsn = NULL;
    5198             :         else
    5199           2 :             subinfo[i].suboriginremotelsn =
    5200           2 :                 pg_strdup(PQgetvalue(res, i, i_suboriginremotelsn));
    5201             : 
    5202             :         /* Decide whether we want to dump it */
    5203         286 :         selectDumpableObject(&(subinfo[i].dobj), fout);
    5204             :     }
    5205         462 :     PQclear(res);
    5206             : 
    5207         462 :     destroyPQExpBuffer(query);
    5208             : }
    5209             : 
    5210             : /*
    5211             :  * getSubscriptionTables
    5212             :  *    Get information about subscription membership for dumpable tables. This
    5213             :  *    will be used only in binary-upgrade mode for PG17 or later versions.
    5214             :  */
    5215             : void
    5216         468 : getSubscriptionTables(Archive *fout)
    5217             : {
    5218         468 :     DumpOptions *dopt = fout->dopt;
    5219         468 :     SubscriptionInfo *subinfo = NULL;
    5220             :     SubRelInfo *subrinfo;
    5221             :     PGresult   *res;
    5222             :     int         i_srsubid;
    5223             :     int         i_srrelid;
    5224             :     int         i_srsubstate;
    5225             :     int         i_srsublsn;
    5226             :     int         ntups;
    5227         468 :     Oid         last_srsubid = InvalidOid;
    5228             : 
    5229         468 :     if (dopt->no_subscriptions || !dopt->binary_upgrade ||
    5230          62 :         fout->remoteVersion < 170000)
    5231         406 :         return;
    5232             : 
    5233          62 :     res = ExecuteSqlQuery(fout,
    5234             :                           "SELECT srsubid, srrelid, srsubstate, srsublsn "
    5235             :                           "FROM pg_catalog.pg_subscription_rel "
    5236             :                           "ORDER BY srsubid",
    5237             :                           PGRES_TUPLES_OK);
    5238          62 :     ntups = PQntuples(res);
    5239          62 :     if (ntups == 0)
    5240          60 :         goto cleanup;
    5241             : 
    5242             :     /* Get pg_subscription_rel attributes */
    5243           2 :     i_srsubid = PQfnumber(res, "srsubid");
    5244           2 :     i_srrelid = PQfnumber(res, "srrelid");
    5245           2 :     i_srsubstate = PQfnumber(res, "srsubstate");
    5246           2 :     i_srsublsn = PQfnumber(res, "srsublsn");
    5247             : 
    5248           2 :     subrinfo = pg_malloc(ntups * sizeof(SubRelInfo));
    5249           6 :     for (int i = 0; i < ntups; i++)
    5250             :     {
    5251           4 :         Oid         cur_srsubid = atooid(PQgetvalue(res, i, i_srsubid));
    5252           4 :         Oid         relid = atooid(PQgetvalue(res, i, i_srrelid));
    5253             :         TableInfo  *tblinfo;
    5254             : 
    5255             :         /*
    5256             :          * If we switched to a new subscription, check if the subscription
    5257             :          * exists.
    5258             :          */
    5259           4 :         if (cur_srsubid != last_srsubid)
    5260             :         {
    5261           4 :             subinfo = findSubscriptionByOid(cur_srsubid);
    5262           4 :             if (subinfo == NULL)
    5263           0 :                 pg_fatal("subscription with OID %u does not exist", cur_srsubid);
    5264             : 
    5265           4 :             last_srsubid = cur_srsubid;
    5266             :         }
    5267             : 
    5268           4 :         tblinfo = findTableByOid(relid);
    5269           4 :         if (tblinfo == NULL)
    5270           0 :             pg_fatal("failed sanity check, table with OID %u not found",
    5271             :                      relid);
    5272             : 
    5273             :         /* OK, make a DumpableObject for this relationship */
    5274           4 :         subrinfo[i].dobj.objType = DO_SUBSCRIPTION_REL;
    5275           4 :         subrinfo[i].dobj.catId.tableoid = relid;
    5276           4 :         subrinfo[i].dobj.catId.oid = cur_srsubid;
    5277           4 :         AssignDumpId(&subrinfo[i].dobj);
    5278           4 :         subrinfo[i].dobj.name = pg_strdup(subinfo->dobj.name);
    5279           4 :         subrinfo[i].tblinfo = tblinfo;
    5280           4 :         subrinfo[i].srsubstate = PQgetvalue(res, i, i_srsubstate)[0];
    5281           4 :         if (PQgetisnull(res, i, i_srsublsn))
    5282           2 :             subrinfo[i].srsublsn = NULL;
    5283             :         else
    5284           2 :             subrinfo[i].srsublsn = pg_strdup(PQgetvalue(res, i, i_srsublsn));
    5285             : 
    5286           4 :         subrinfo[i].subinfo = subinfo;
    5287             : 
    5288             :         /* Decide whether we want to dump it */
    5289           4 :         selectDumpableObject(&(subrinfo[i].dobj), fout);
    5290             :     }
    5291             : 
    5292           2 : cleanup:
    5293          62 :     PQclear(res);
    5294             : }
    5295             : 
    5296             : /*
    5297             :  * dumpSubscriptionTable
    5298             :  *    Dump the definition of the given subscription table mapping. This will be
    5299             :  *    used only in binary-upgrade mode for PG17 or later versions.
    5300             :  */
    5301             : static void
    5302           4 : dumpSubscriptionTable(Archive *fout, const SubRelInfo *subrinfo)
    5303             : {
    5304           4 :     DumpOptions *dopt = fout->dopt;
    5305           4 :     SubscriptionInfo *subinfo = subrinfo->subinfo;
    5306             :     PQExpBuffer query;
    5307             :     char       *tag;
    5308             : 
    5309             :     /* Do nothing if not dumping schema */
    5310           4 :     if (!dopt->dumpSchema)
    5311           0 :         return;
    5312             : 
    5313             :     Assert(fout->dopt->binary_upgrade && fout->remoteVersion >= 170000);
    5314             : 
    5315           4 :     tag = psprintf("%s %s", subinfo->dobj.name, subrinfo->dobj.name);
    5316             : 
    5317           4 :     query = createPQExpBuffer();
    5318             : 
    5319           4 :     if (subinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
    5320             :     {
    5321             :         /*
    5322             :          * binary_upgrade_add_sub_rel_state will add the subscription relation
    5323             :          * to pg_subscription_rel table. This will be used only in
    5324             :          * binary-upgrade mode.
    5325             :          */
    5326           4 :         appendPQExpBufferStr(query,
    5327             :                              "\n-- For binary upgrade, must preserve the subscriber table.\n");
    5328           4 :         appendPQExpBufferStr(query,
    5329             :                              "SELECT pg_catalog.binary_upgrade_add_sub_rel_state(");
    5330           4 :         appendStringLiteralAH(query, subrinfo->dobj.name, fout);
    5331           4 :         appendPQExpBuffer(query,
    5332             :                           ", %u, '%c'",
    5333           4 :                           subrinfo->tblinfo->dobj.catId.oid,
    5334           4 :                           subrinfo->srsubstate);
    5335             : 
    5336           4 :         if (subrinfo->srsublsn && subrinfo->srsublsn[0] != '\0')
    5337           2 :             appendPQExpBuffer(query, ", '%s'", subrinfo->srsublsn);
    5338             :         else
    5339           2 :             appendPQExpBufferStr(query, ", NULL");
    5340             : 
    5341           4 :         appendPQExpBufferStr(query, ");\n");
    5342             :     }
    5343             : 
    5344             :     /*
    5345             :      * There is no point in creating a drop query as the drop is done by table
    5346             :      * drop.  (If you think to change this, see also _printTocEntry().)
    5347             :      * Although this object doesn't really have ownership as such, set the
    5348             :      * owner field anyway to ensure that the command is run by the correct
    5349             :      * role at restore time.
    5350             :      */
    5351           4 :     if (subrinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
    5352           4 :         ArchiveEntry(fout, subrinfo->dobj.catId, subrinfo->dobj.dumpId,
    5353           4 :                      ARCHIVE_OPTS(.tag = tag,
    5354             :                                   .namespace = subrinfo->tblinfo->dobj.namespace->dobj.name,
    5355             :                                   .owner = subinfo->rolname,
    5356             :                                   .description = "SUBSCRIPTION TABLE",
    5357             :                                   .section = SECTION_POST_DATA,
    5358             :                                   .createStmt = query->data));
    5359             : 
    5360             :     /* These objects can't currently have comments or seclabels */
    5361             : 
    5362           4 :     free(tag);
    5363           4 :     destroyPQExpBuffer(query);
    5364             : }
    5365             : 
    5366             : /*
    5367             :  * dumpSubscription
    5368             :  *    dump the definition of the given subscription
    5369             :  */
    5370             : static void
    5371         250 : dumpSubscription(Archive *fout, const SubscriptionInfo *subinfo)
    5372             : {
    5373         250 :     DumpOptions *dopt = fout->dopt;
    5374             :     PQExpBuffer delq;
    5375             :     PQExpBuffer query;
    5376             :     PQExpBuffer publications;
    5377             :     char       *qsubname;
    5378         250 :     char      **pubnames = NULL;
    5379         250 :     int         npubnames = 0;
    5380             :     int         i;
    5381             : 
    5382             :     /* Do nothing if not dumping schema */
    5383         250 :     if (!dopt->dumpSchema)
    5384          36 :         return;
    5385             : 
    5386         214 :     delq = createPQExpBuffer();
    5387         214 :     query = createPQExpBuffer();
    5388             : 
    5389         214 :     qsubname = pg_strdup(fmtId(subinfo->dobj.name));
    5390             : 
    5391         214 :     appendPQExpBuffer(delq, "DROP SUBSCRIPTION %s;\n",
    5392             :                       qsubname);
    5393             : 
    5394         214 :     appendPQExpBuffer(query, "CREATE SUBSCRIPTION %s CONNECTION ",
    5395             :                       qsubname);
    5396         214 :     appendStringLiteralAH(query, subinfo->subconninfo, fout);
    5397             : 
    5398             :     /* Build list of quoted publications and append them to query. */
    5399         214 :     if (!parsePGArray(subinfo->subpublications, &pubnames, &npubnames))
    5400           0 :         pg_fatal("could not parse %s array", "subpublications");
    5401             : 
    5402         214 :     publications = createPQExpBuffer();
    5403         428 :     for (i = 0; i < npubnames; i++)
    5404             :     {
    5405         214 :         if (i > 0)
    5406           0 :             appendPQExpBufferStr(publications, ", ");
    5407             : 
    5408         214 :         appendPQExpBufferStr(publications, fmtId(pubnames[i]));
    5409             :     }
    5410             : 
    5411         214 :     appendPQExpBuffer(query, " PUBLICATION %s WITH (connect = false, slot_name = ", publications->data);
    5412         214 :     if (subinfo->subslotname)
    5413         214 :         appendStringLiteralAH(query, subinfo->subslotname, fout);
    5414             :     else
    5415           0 :         appendPQExpBufferStr(query, "NONE");
    5416             : 
    5417         214 :     if (subinfo->subbinary)
    5418           0 :         appendPQExpBufferStr(query, ", binary = true");
    5419             : 
    5420         214 :     if (subinfo->substream == LOGICALREP_STREAM_ON)
    5421          70 :         appendPQExpBufferStr(query, ", streaming = on");
    5422         144 :     else if (subinfo->substream == LOGICALREP_STREAM_PARALLEL)
    5423          74 :         appendPQExpBufferStr(query, ", streaming = parallel");
    5424             :     else
    5425          70 :         appendPQExpBufferStr(query, ", streaming = off");
    5426             : 
    5427         214 :     if (subinfo->subtwophasestate != LOGICALREP_TWOPHASE_STATE_DISABLED)
    5428           0 :         appendPQExpBufferStr(query, ", two_phase = on");
    5429             : 
    5430         214 :     if (subinfo->subdisableonerr)
    5431           0 :         appendPQExpBufferStr(query, ", disable_on_error = true");
    5432             : 
    5433         214 :     if (!subinfo->subpasswordrequired)
    5434           0 :         appendPQExpBufferStr(query, ", password_required = false");
    5435             : 
    5436         214 :     if (subinfo->subrunasowner)
    5437           0 :         appendPQExpBufferStr(query, ", run_as_owner = true");
    5438             : 
    5439         214 :     if (subinfo->subfailover)
    5440           2 :         appendPQExpBufferStr(query, ", failover = true");
    5441             : 
    5442         214 :     if (subinfo->subretaindeadtuples)
    5443           2 :         appendPQExpBufferStr(query, ", retain_dead_tuples = true");
    5444             : 
    5445         214 :     if (strcmp(subinfo->subsynccommit, "off") != 0)
    5446           0 :         appendPQExpBuffer(query, ", synchronous_commit = %s", fmtId(subinfo->subsynccommit));
    5447             : 
    5448         214 :     if (pg_strcasecmp(subinfo->suborigin, LOGICALREP_ORIGIN_ANY) != 0)
    5449          70 :         appendPQExpBuffer(query, ", origin = %s", subinfo->suborigin);
    5450             : 
    5451         214 :     appendPQExpBufferStr(query, ");\n");
    5452             : 
    5453             :     /*
    5454             :      * In binary-upgrade mode, we allow the replication to continue after the
    5455             :      * upgrade.
    5456             :      */
    5457         214 :     if (dopt->binary_upgrade && fout->remoteVersion >= 170000)
    5458             :     {
    5459          10 :         if (subinfo->suboriginremotelsn)
    5460             :         {
    5461             :             /*
    5462             :              * Preserve the remote_lsn for the subscriber's replication
    5463             :              * origin. This value is required to start the replication from
    5464             :              * the position before the upgrade. This value will be stale if
    5465             :              * the publisher gets upgraded before the subscriber node.
    5466             :              * However, this shouldn't be a problem as the upgrade of the
    5467             :              * publisher ensures that all the transactions were replicated
    5468             :              * before upgrading it.
    5469             :              */
    5470           2 :             appendPQExpBufferStr(query,
    5471             :                                  "\n-- For binary upgrade, must preserve the remote_lsn for the subscriber's replication origin.\n");
    5472           2 :             appendPQExpBufferStr(query,
    5473             :                                  "SELECT pg_catalog.binary_upgrade_replorigin_advance(");
    5474           2 :             appendStringLiteralAH(query, subinfo->dobj.name, fout);
    5475           2 :             appendPQExpBuffer(query, ", '%s');\n", subinfo->suboriginremotelsn);
    5476             :         }
    5477             : 
    5478          10 :         if (subinfo->subenabled)
    5479             :         {
    5480             :             /*
    5481             :              * Enable the subscription to allow the replication to continue
    5482             :              * after the upgrade.
    5483             :              */
    5484           2 :             appendPQExpBufferStr(query,
    5485             :                                  "\n-- For binary upgrade, must preserve the subscriber's running state.\n");
    5486           2 :             appendPQExpBuffer(query, "ALTER SUBSCRIPTION %s ENABLE;\n", qsubname);
    5487             :         }
    5488             :     }
    5489             : 
    5490         214 :     if (subinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
    5491         214 :         ArchiveEntry(fout, subinfo->dobj.catId, subinfo->dobj.dumpId,
    5492         214 :                      ARCHIVE_OPTS(.tag = subinfo->dobj.name,
    5493             :                                   .owner = subinfo->rolname,
    5494             :                                   .description = "SUBSCRIPTION",
    5495             :                                   .section = SECTION_POST_DATA,
    5496             :                                   .createStmt = query->data,
    5497             :                                   .dropStmt = delq->data));
    5498             : 
    5499         214 :     if (subinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
    5500          70 :         dumpComment(fout, "SUBSCRIPTION", qsubname,
    5501          70 :                     NULL, subinfo->rolname,
    5502          70 :                     subinfo->dobj.catId, 0, subinfo->dobj.dumpId);
    5503             : 
    5504         214 :     if (subinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
    5505           0 :         dumpSecLabel(fout, "SUBSCRIPTION", qsubname,
    5506           0 :                      NULL, subinfo->rolname,
    5507           0 :                      subinfo->dobj.catId, 0, subinfo->dobj.dumpId);
    5508             : 
    5509         214 :     destroyPQExpBuffer(publications);
    5510         214 :     free(pubnames);
    5511             : 
    5512         214 :     destroyPQExpBuffer(delq);
    5513         214 :     destroyPQExpBuffer(query);
    5514         214 :     free(qsubname);
    5515             : }
    5516             : 
    5517             : /*
    5518             :  * Given a "create query", append as many ALTER ... DEPENDS ON EXTENSION as
    5519             :  * the object needs.
    5520             :  */
    5521             : static void
    5522       14266 : append_depends_on_extension(Archive *fout,
    5523             :                             PQExpBuffer create,
    5524             :                             const DumpableObject *dobj,
    5525             :                             const char *catalog,
    5526             :                             const char *keyword,
    5527             :                             const char *objname)
    5528             : {
    5529       14266 :     if (dobj->depends_on_ext)
    5530             :     {
    5531             :         char       *nm;
    5532             :         PGresult   *res;
    5533             :         PQExpBuffer query;
    5534             :         int         ntups;
    5535             :         int         i_extname;
    5536             :         int         i;
    5537             : 
    5538             :         /* dodge fmtId() non-reentrancy */
    5539          84 :         nm = pg_strdup(objname);
    5540             : 
    5541          84 :         query = createPQExpBuffer();
    5542          84 :         appendPQExpBuffer(query,
    5543             :                           "SELECT e.extname "
    5544             :                           "FROM pg_catalog.pg_depend d, pg_catalog.pg_extension e "
    5545             :                           "WHERE d.refobjid = e.oid AND classid = '%s'::pg_catalog.regclass "
    5546             :                           "AND objid = '%u'::pg_catalog.oid AND deptype = 'x' "
    5547             :                           "AND refclassid = 'pg_catalog.pg_extension'::pg_catalog.regclass",
    5548             :                           catalog,
    5549          84 :                           dobj->catId.oid);
    5550          84 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    5551          84 :         ntups = PQntuples(res);
    5552          84 :         i_extname = PQfnumber(res, "extname");
    5553         168 :         for (i = 0; i < ntups; i++)
    5554             :         {
    5555          84 :             appendPQExpBuffer(create, "\nALTER %s %s DEPENDS ON EXTENSION %s;",
    5556             :                               keyword, nm,
    5557          84 :                               fmtId(PQgetvalue(res, i, i_extname)));
    5558             :         }
    5559             : 
    5560          84 :         PQclear(res);
    5561          84 :         destroyPQExpBuffer(query);
    5562          84 :         pg_free(nm);
    5563             :     }
    5564       14266 : }
    5565             : 
    5566             : static Oid
    5567           0 : get_next_possible_free_pg_type_oid(Archive *fout, PQExpBuffer upgrade_query)
    5568             : {
    5569             :     /*
    5570             :      * If the old version didn't assign an array type, but the new version
    5571             :      * does, we must select an unused type OID to assign.  This currently only
    5572             :      * happens for domains, when upgrading pre-v11 to v11 and up.
    5573             :      *
    5574             :      * Note: local state here is kind of ugly, but we must have some, since we
    5575             :      * mustn't choose the same unused OID more than once.
    5576             :      */
    5577             :     static Oid  next_possible_free_oid = FirstNormalObjectId;
    5578             :     PGresult   *res;
    5579             :     bool        is_dup;
    5580             : 
    5581             :     do
    5582             :     {
    5583           0 :         ++next_possible_free_oid;
    5584           0 :         printfPQExpBuffer(upgrade_query,
    5585             :                           "SELECT EXISTS(SELECT 1 "
    5586             :                           "FROM pg_catalog.pg_type "
    5587             :                           "WHERE oid = '%u'::pg_catalog.oid);",
    5588             :                           next_possible_free_oid);
    5589           0 :         res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data);
    5590           0 :         is_dup = (PQgetvalue(res, 0, 0)[0] == 't');
    5591           0 :         PQclear(res);
    5592           0 :     } while (is_dup);
    5593             : 
    5594           0 :     return next_possible_free_oid;
    5595             : }
    5596             : 
    5597             : static void
    5598        1852 : binary_upgrade_set_type_oids_by_type_oid(Archive *fout,
    5599             :                                          PQExpBuffer upgrade_buffer,
    5600             :                                          Oid pg_type_oid,
    5601             :                                          bool force_array_type,
    5602             :                                          bool include_multirange_type)
    5603             : {
    5604        1852 :     PQExpBuffer upgrade_query = createPQExpBuffer();
    5605             :     PGresult   *res;
    5606             :     Oid         pg_type_array_oid;
    5607             :     Oid         pg_type_multirange_oid;
    5608             :     Oid         pg_type_multirange_array_oid;
    5609             :     TypeInfo   *tinfo;
    5610             : 
    5611        1852 :     appendPQExpBufferStr(upgrade_buffer, "\n-- For binary upgrade, must preserve pg_type oid\n");
    5612        1852 :     appendPQExpBuffer(upgrade_buffer,
    5613             :                       "SELECT pg_catalog.binary_upgrade_set_next_pg_type_oid('%u'::pg_catalog.oid);\n\n",
    5614             :                       pg_type_oid);
    5615             : 
    5616        1852 :     tinfo = findTypeByOid(pg_type_oid);
    5617        1852 :     if (tinfo)
    5618        1852 :         pg_type_array_oid = tinfo->typarray;
    5619             :     else
    5620           0 :         pg_type_array_oid = InvalidOid;
    5621             : 
    5622        1852 :     if (!OidIsValid(pg_type_array_oid) && force_array_type)
    5623           0 :         pg_type_array_oid = get_next_possible_free_pg_type_oid(fout, upgrade_query);
    5624             : 
    5625        1852 :     if (OidIsValid(pg_type_array_oid))
    5626             :     {
    5627        1848 :         appendPQExpBufferStr(upgrade_buffer,
    5628             :                              "\n-- For binary upgrade, must preserve pg_type array oid\n");
    5629        1848 :         appendPQExpBuffer(upgrade_buffer,
    5630             :                           "SELECT pg_catalog.binary_upgrade_set_next_array_pg_type_oid('%u'::pg_catalog.oid);\n\n",
    5631             :                           pg_type_array_oid);
    5632             :     }
    5633             : 
    5634             :     /*
    5635             :      * Pre-set the multirange type oid and its own array type oid.
    5636             :      */
    5637        1852 :     if (include_multirange_type)
    5638             :     {
    5639          16 :         if (fout->remoteVersion >= 140000)
    5640             :         {
    5641          16 :             printfPQExpBuffer(upgrade_query,
    5642             :                               "SELECT t.oid, t.typarray "
    5643             :                               "FROM pg_catalog.pg_type t "
    5644             :                               "JOIN pg_catalog.pg_range r "
    5645             :                               "ON t.oid = r.rngmultitypid "
    5646             :                               "WHERE r.rngtypid = '%u'::pg_catalog.oid;",
    5647             :                               pg_type_oid);
    5648             : 
    5649          16 :             res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data);
    5650             : 
    5651          16 :             pg_type_multirange_oid = atooid(PQgetvalue(res, 0, PQfnumber(res, "oid")));
    5652          16 :             pg_type_multirange_array_oid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typarray")));
    5653             : 
    5654          16 :             PQclear(res);
    5655             :         }
    5656             :         else
    5657             :         {
    5658           0 :             pg_type_multirange_oid = get_next_possible_free_pg_type_oid(fout, upgrade_query);
    5659           0 :             pg_type_multirange_array_oid = get_next_possible_free_pg_type_oid(fout, upgrade_query);
    5660             :         }
    5661             : 
    5662          16 :         appendPQExpBufferStr(upgrade_buffer,
    5663             :                              "\n-- For binary upgrade, must preserve multirange pg_type oid\n");
    5664          16 :         appendPQExpBuffer(upgrade_buffer,
    5665             :                           "SELECT pg_catalog.binary_upgrade_set_next_multirange_pg_type_oid('%u'::pg_catalog.oid);\n\n",
    5666             :                           pg_type_multirange_oid);
    5667          16 :         appendPQExpBufferStr(upgrade_buffer,
    5668             :                              "\n-- For binary upgrade, must preserve multirange pg_type array oid\n");
    5669          16 :         appendPQExpBuffer(upgrade_buffer,
    5670             :                           "SELECT pg_catalog.binary_upgrade_set_next_multirange_array_pg_type_oid('%u'::pg_catalog.oid);\n\n",
    5671             :                           pg_type_multirange_array_oid);
    5672             :     }
    5673             : 
    5674        1852 :     destroyPQExpBuffer(upgrade_query);
    5675        1852 : }
    5676             : 
    5677             : static void
    5678        1704 : binary_upgrade_set_type_oids_by_rel(Archive *fout,
    5679             :                                     PQExpBuffer upgrade_buffer,
    5680             :                                     const TableInfo *tbinfo)
    5681             : {
    5682        1704 :     Oid         pg_type_oid = tbinfo->reltype;
    5683             : 
    5684        1704 :     if (OidIsValid(pg_type_oid))
    5685        1704 :         binary_upgrade_set_type_oids_by_type_oid(fout, upgrade_buffer,
    5686             :                                                  pg_type_oid, false, false);
    5687        1704 : }
    5688             : 
    5689             : /*
    5690             :  * bsearch() comparator for BinaryUpgradeClassOidItem
    5691             :  */
    5692             : static int
    5693       24448 : BinaryUpgradeClassOidItemCmp(const void *p1, const void *p2)
    5694             : {
    5695       24448 :     BinaryUpgradeClassOidItem v1 = *((const BinaryUpgradeClassOidItem *) p1);
    5696       24448 :     BinaryUpgradeClassOidItem v2 = *((const BinaryUpgradeClassOidItem *) p2);
    5697             : 
    5698       24448 :     return pg_cmp_u32(v1.oid, v2.oid);
    5699             : }
    5700             : 
    5701             : /*
    5702             :  * collectBinaryUpgradeClassOids
    5703             :  *
    5704             :  * Construct a table of pg_class information required for
    5705             :  * binary_upgrade_set_pg_class_oids().  The table is sorted by OID for speed in
    5706             :  * lookup.
    5707             :  */
    5708             : static void
    5709          62 : collectBinaryUpgradeClassOids(Archive *fout)
    5710             : {
    5711             :     PGresult   *res;
    5712             :     const char *query;
    5713             : 
    5714          62 :     query = "SELECT c.oid, c.relkind, c.relfilenode, c.reltoastrelid, "
    5715             :         "ct.relfilenode, i.indexrelid, cti.relfilenode "
    5716             :         "FROM pg_catalog.pg_class c LEFT JOIN pg_catalog.pg_index i "
    5717             :         "ON (c.reltoastrelid = i.indrelid AND i.indisvalid) "
    5718             :         "LEFT JOIN pg_catalog.pg_class ct ON (c.reltoastrelid = ct.oid) "
    5719             :         "LEFT JOIN pg_catalog.pg_class AS cti ON (i.indexrelid = cti.oid) "
    5720             :         "ORDER BY c.oid;";
    5721             : 
    5722          62 :     res = ExecuteSqlQuery(fout, query, PGRES_TUPLES_OK);
    5723             : 
    5724          62 :     nbinaryUpgradeClassOids = PQntuples(res);
    5725          62 :     binaryUpgradeClassOids = (BinaryUpgradeClassOidItem *)
    5726          62 :         pg_malloc(nbinaryUpgradeClassOids * sizeof(BinaryUpgradeClassOidItem));
    5727             : 
    5728       29450 :     for (int i = 0; i < nbinaryUpgradeClassOids; i++)
    5729             :     {
    5730       29388 :         binaryUpgradeClassOids[i].oid = atooid(PQgetvalue(res, i, 0));
    5731       29388 :         binaryUpgradeClassOids[i].relkind = *PQgetvalue(res, i, 1);
    5732       29388 :         binaryUpgradeClassOids[i].relfilenumber = atooid(PQgetvalue(res, i, 2));
    5733       29388 :         binaryUpgradeClassOids[i].toast_oid = atooid(PQgetvalue(res, i, 3));
    5734       29388 :         binaryUpgradeClassOids[i].toast_relfilenumber = atooid(PQgetvalue(res, i, 4));
    5735       29388 :         binaryUpgradeClassOids[i].toast_index_oid = atooid(PQgetvalue(res, i, 5));
    5736       29388 :         binaryUpgradeClassOids[i].toast_index_relfilenumber = atooid(PQgetvalue(res, i, 6));
    5737             :     }
    5738             : 
    5739          62 :     PQclear(res);
    5740          62 : }
    5741             : 
    5742             : static void
    5743        2476 : binary_upgrade_set_pg_class_oids(Archive *fout,
    5744             :                                  PQExpBuffer upgrade_buffer, Oid pg_class_oid)
    5745             : {
    5746        2476 :     BinaryUpgradeClassOidItem key = {0};
    5747             :     BinaryUpgradeClassOidItem *entry;
    5748             : 
    5749             :     Assert(binaryUpgradeClassOids);
    5750             : 
    5751             :     /*
    5752             :      * Preserve the OID and relfilenumber of the table, table's index, table's
    5753             :      * toast table and toast table's index if any.
    5754             :      *
    5755             :      * One complexity is that the current table definition might not require
    5756             :      * the creation of a TOAST table, but the old database might have a TOAST
    5757             :      * table that was created earlier, before some wide columns were dropped.
    5758             :      * By setting the TOAST oid we force creation of the TOAST heap and index
    5759             :      * by the new backend, so we can copy the files during binary upgrade
    5760             :      * without worrying about this case.
    5761             :      */
    5762        2476 :     key.oid = pg_class_oid;
    5763        2476 :     entry = bsearch(&key, binaryUpgradeClassOids, nbinaryUpgradeClassOids,
    5764             :                     sizeof(BinaryUpgradeClassOidItem),
    5765             :                     BinaryUpgradeClassOidItemCmp);
    5766             : 
    5767        2476 :     appendPQExpBufferStr(upgrade_buffer,
    5768             :                          "\n-- For binary upgrade, must preserve pg_class oids and relfilenodes\n");
    5769             : 
    5770        2476 :     if (entry->relkind != RELKIND_INDEX &&
    5771        1922 :         entry->relkind != RELKIND_PARTITIONED_INDEX)
    5772             :     {
    5773        1872 :         appendPQExpBuffer(upgrade_buffer,
    5774             :                           "SELECT pg_catalog.binary_upgrade_set_next_heap_pg_class_oid('%u'::pg_catalog.oid);\n",
    5775             :                           pg_class_oid);
    5776             : 
    5777             :         /*
    5778             :          * Not every relation has storage. Also, in a pre-v12 database,
    5779             :          * partitioned tables have a relfilenumber, which should not be
    5780             :          * preserved when upgrading.
    5781             :          */
    5782        1872 :         if (RelFileNumberIsValid(entry->relfilenumber) &&
    5783        1550 :             entry->relkind != RELKIND_PARTITIONED_TABLE)
    5784        1550 :             appendPQExpBuffer(upgrade_buffer,
    5785             :                               "SELECT pg_catalog.binary_upgrade_set_next_heap_relfilenode('%u'::pg_catalog.oid);\n",
    5786             :                               entry->relfilenumber);
    5787             : 
    5788             :         /*
    5789             :          * In a pre-v12 database, partitioned tables might be marked as having
    5790             :          * toast tables, but we should ignore them if so.
    5791             :          */
    5792        1872 :         if (OidIsValid(entry->toast_oid) &&
    5793         560 :             entry->relkind != RELKIND_PARTITIONED_TABLE)
    5794             :         {
    5795         560 :             appendPQExpBuffer(upgrade_buffer,
    5796             :                               "SELECT pg_catalog.binary_upgrade_set_next_toast_pg_class_oid('%u'::pg_catalog.oid);\n",
    5797             :                               entry->toast_oid);
    5798         560 :             appendPQExpBuffer(upgrade_buffer,
    5799             :                               "SELECT pg_catalog.binary_upgrade_set_next_toast_relfilenode('%u'::pg_catalog.oid);\n",
    5800             :                               entry->toast_relfilenumber);
    5801             : 
    5802             :             /* every toast table has an index */
    5803         560 :             appendPQExpBuffer(upgrade_buffer,
    5804             :                               "SELECT pg_catalog.binary_upgrade_set_next_index_pg_class_oid('%u'::pg_catalog.oid);\n",
    5805             :                               entry->toast_index_oid);
    5806         560 :             appendPQExpBuffer(upgrade_buffer,
    5807             :                               "SELECT pg_catalog.binary_upgrade_set_next_index_relfilenode('%u'::pg_catalog.oid);\n",
    5808             :                               entry->toast_index_relfilenumber);
    5809             :         }
    5810             :     }
    5811             :     else
    5812             :     {
    5813             :         /* Preserve the OID and relfilenumber of the index */
    5814         604 :         appendPQExpBuffer(upgrade_buffer,
    5815             :                           "SELECT pg_catalog.binary_upgrade_set_next_index_pg_class_oid('%u'::pg_catalog.oid);\n",
    5816             :                           pg_class_oid);
    5817         604 :         appendPQExpBuffer(upgrade_buffer,
    5818             :                           "SELECT pg_catalog.binary_upgrade_set_next_index_relfilenode('%u'::pg_catalog.oid);\n",
    5819             :                           entry->relfilenumber);
    5820             :     }
    5821             : 
    5822        2476 :     appendPQExpBufferChar(upgrade_buffer, '\n');
    5823        2476 : }
    5824             : 
    5825             : /*
    5826             :  * If the DumpableObject is a member of an extension, add a suitable
    5827             :  * ALTER EXTENSION ADD command to the creation commands in upgrade_buffer.
    5828             :  *
    5829             :  * For somewhat historical reasons, objname should already be quoted,
    5830             :  * but not objnamespace (if any).
    5831             :  */
    5832             : static void
    5833        2940 : binary_upgrade_extension_member(PQExpBuffer upgrade_buffer,
    5834             :                                 const DumpableObject *dobj,
    5835             :                                 const char *objtype,
    5836             :                                 const char *objname,
    5837             :                                 const char *objnamespace)
    5838             : {
    5839        2940 :     DumpableObject *extobj = NULL;
    5840             :     int         i;
    5841             : 
    5842        2940 :     if (!dobj->ext_member)
    5843        2908 :         return;
    5844             : 
    5845             :     /*
    5846             :      * Find the parent extension.  We could avoid this search if we wanted to
    5847             :      * add a link field to DumpableObject, but the space costs of that would
    5848             :      * be considerable.  We assume that member objects could only have a
    5849             :      * direct dependency on their own extension, not any others.
    5850             :      */
    5851          32 :     for (i = 0; i < dobj->nDeps; i++)
    5852             :     {
    5853          32 :         extobj = findObjectByDumpId(dobj->dependencies[i]);
    5854          32 :         if (extobj && extobj->objType == DO_EXTENSION)
    5855          32 :             break;
    5856           0 :         extobj = NULL;
    5857             :     }
    5858          32 :     if (extobj == NULL)
    5859           0 :         pg_fatal("could not find parent extension for %s %s",
    5860             :                  objtype, objname);
    5861             : 
    5862          32 :     appendPQExpBufferStr(upgrade_buffer,
    5863             :                          "\n-- For binary upgrade, handle extension membership the hard way\n");
    5864          32 :     appendPQExpBuffer(upgrade_buffer, "ALTER EXTENSION %s ADD %s ",
    5865          32 :                       fmtId(extobj->name),
    5866             :                       objtype);
    5867          32 :     if (objnamespace && *objnamespace)
    5868          26 :         appendPQExpBuffer(upgrade_buffer, "%s.", fmtId(objnamespace));
    5869          32 :     appendPQExpBuffer(upgrade_buffer, "%s;\n", objname);
    5870             : }
    5871             : 
    5872             : /*
    5873             :  * getNamespaces:
    5874             :  *    get information about all namespaces in the system catalogs
    5875             :  */
    5876             : void
    5877         470 : getNamespaces(Archive *fout)
    5878             : {
    5879             :     PGresult   *res;
    5880             :     int         ntups;
    5881             :     int         i;
    5882             :     PQExpBuffer query;
    5883             :     NamespaceInfo *nsinfo;
    5884             :     int         i_tableoid;
    5885             :     int         i_oid;
    5886             :     int         i_nspname;
    5887             :     int         i_nspowner;
    5888             :     int         i_nspacl;
    5889             :     int         i_acldefault;
    5890             : 
    5891         470 :     query = createPQExpBuffer();
    5892             : 
    5893             :     /*
    5894             :      * we fetch all namespaces including system ones, so that every object we
    5895             :      * read in can be linked to a containing namespace.
    5896             :      */
    5897         470 :     appendPQExpBufferStr(query, "SELECT n.tableoid, n.oid, n.nspname, "
    5898             :                          "n.nspowner, "
    5899             :                          "n.nspacl, "
    5900             :                          "acldefault('n', n.nspowner) AS acldefault "
    5901             :                          "FROM pg_namespace n");
    5902             : 
    5903         470 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    5904             : 
    5905         470 :     ntups = PQntuples(res);
    5906             : 
    5907         470 :     nsinfo = (NamespaceInfo *) pg_malloc(ntups * sizeof(NamespaceInfo));
    5908             : 
    5909         470 :     i_tableoid = PQfnumber(res, "tableoid");
    5910         470 :     i_oid = PQfnumber(res, "oid");
    5911         470 :     i_nspname = PQfnumber(res, "nspname");
    5912         470 :     i_nspowner = PQfnumber(res, "nspowner");
    5913         470 :     i_nspacl = PQfnumber(res, "nspacl");
    5914         470 :     i_acldefault = PQfnumber(res, "acldefault");
    5915             : 
    5916        4362 :     for (i = 0; i < ntups; i++)
    5917             :     {
    5918             :         const char *nspowner;
    5919             : 
    5920        3892 :         nsinfo[i].dobj.objType = DO_NAMESPACE;
    5921        3892 :         nsinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    5922        3892 :         nsinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    5923        3892 :         AssignDumpId(&nsinfo[i].dobj);
    5924        3892 :         nsinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_nspname));
    5925        3892 :         nsinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_nspacl));
    5926        3892 :         nsinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
    5927        3892 :         nsinfo[i].dacl.privtype = 0;
    5928        3892 :         nsinfo[i].dacl.initprivs = NULL;
    5929        3892 :         nspowner = PQgetvalue(res, i, i_nspowner);
    5930        3892 :         nsinfo[i].nspowner = atooid(nspowner);
    5931        3892 :         nsinfo[i].rolname = getRoleName(nspowner);
    5932             : 
    5933             :         /* Decide whether to dump this namespace */
    5934        3892 :         selectDumpableNamespace(&nsinfo[i], fout);
    5935             : 
    5936             :         /* Mark whether namespace has an ACL */
    5937        3892 :         if (!PQgetisnull(res, i, i_nspacl))
    5938        1572 :             nsinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
    5939             : 
    5940             :         /*
    5941             :          * We ignore any pg_init_privs.initprivs entry for the public schema
    5942             :          * and assume a predetermined default, for several reasons.  First,
    5943             :          * dropping and recreating the schema removes its pg_init_privs entry,
    5944             :          * but an empty destination database starts with this ACL nonetheless.
    5945             :          * Second, we support dump/reload of public schema ownership changes.
    5946             :          * ALTER SCHEMA OWNER filters nspacl through aclnewowner(), but
    5947             :          * initprivs continues to reflect the initial owner.  Hence,
    5948             :          * synthesize the value that nspacl will have after the restore's
    5949             :          * ALTER SCHEMA OWNER.  Third, this makes the destination database
    5950             :          * match the source's ACL, even if the latter was an initdb-default
    5951             :          * ACL, which changed in v15.  An upgrade pulls in changes to most
    5952             :          * system object ACLs that the DBA had not customized.  We've made the
    5953             :          * public schema depart from that, because changing its ACL so easily
    5954             :          * breaks applications.
    5955             :          */
    5956        3892 :         if (strcmp(nsinfo[i].dobj.name, "public") == 0)
    5957             :         {
    5958         462 :             PQExpBuffer aclarray = createPQExpBuffer();
    5959         462 :             PQExpBuffer aclitem = createPQExpBuffer();
    5960             : 
    5961             :             /* Standard ACL as of v15 is {owner=UC/owner,=U/owner} */
    5962         462 :             appendPQExpBufferChar(aclarray, '{');
    5963         462 :             quoteAclUserName(aclitem, nsinfo[i].rolname);
    5964         462 :             appendPQExpBufferStr(aclitem, "=UC/");
    5965         462 :             quoteAclUserName(aclitem, nsinfo[i].rolname);
    5966         462 :             appendPGArray(aclarray, aclitem->data);
    5967         462 :             resetPQExpBuffer(aclitem);
    5968         462 :             appendPQExpBufferStr(aclitem, "=U/");
    5969         462 :             quoteAclUserName(aclitem, nsinfo[i].rolname);
    5970         462 :             appendPGArray(aclarray, aclitem->data);
    5971         462 :             appendPQExpBufferChar(aclarray, '}');
    5972             : 
    5973         462 :             nsinfo[i].dacl.privtype = 'i';
    5974         462 :             nsinfo[i].dacl.initprivs = pstrdup(aclarray->data);
    5975         462 :             nsinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
    5976             : 
    5977         462 :             destroyPQExpBuffer(aclarray);
    5978         462 :             destroyPQExpBuffer(aclitem);
    5979             :         }
    5980             :     }
    5981             : 
    5982         470 :     PQclear(res);
    5983         470 :     destroyPQExpBuffer(query);
    5984         470 : }
    5985             : 
    5986             : /*
    5987             :  * findNamespace:
    5988             :  *      given a namespace OID, look up the info read by getNamespaces
    5989             :  */
    5990             : static NamespaceInfo *
    5991     1478026 : findNamespace(Oid nsoid)
    5992             : {
    5993             :     NamespaceInfo *nsinfo;
    5994             : 
    5995     1478026 :     nsinfo = findNamespaceByOid(nsoid);
    5996     1478026 :     if (nsinfo == NULL)
    5997           0 :         pg_fatal("schema with OID %u does not exist", nsoid);
    5998     1478026 :     return nsinfo;
    5999             : }
    6000             : 
    6001             : /*
    6002             :  * getExtensions:
    6003             :  *    read all extensions in the system catalogs and return them in the
    6004             :  * ExtensionInfo* structure
    6005             :  *
    6006             :  *  numExtensions is set to the number of extensions read in
    6007             :  */
    6008             : ExtensionInfo *
    6009         470 : getExtensions(Archive *fout, int *numExtensions)
    6010             : {
    6011         470 :     DumpOptions *dopt = fout->dopt;
    6012             :     PGresult   *res;
    6013             :     int         ntups;
    6014             :     int         i;
    6015             :     PQExpBuffer query;
    6016         470 :     ExtensionInfo *extinfo = NULL;
    6017             :     int         i_tableoid;
    6018             :     int         i_oid;
    6019             :     int         i_extname;
    6020             :     int         i_nspname;
    6021             :     int         i_extrelocatable;
    6022             :     int         i_extversion;
    6023             :     int         i_extconfig;
    6024             :     int         i_extcondition;
    6025             : 
    6026         470 :     query = createPQExpBuffer();
    6027             : 
    6028         470 :     appendPQExpBufferStr(query, "SELECT x.tableoid, x.oid, "
    6029             :                          "x.extname, n.nspname, x.extrelocatable, x.extversion, x.extconfig, x.extcondition "
    6030             :                          "FROM pg_extension x "
    6031             :                          "JOIN pg_namespace n ON n.oid = x.extnamespace");
    6032             : 
    6033         470 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    6034             : 
    6035         470 :     ntups = PQntuples(res);
    6036         470 :     if (ntups == 0)
    6037           0 :         goto cleanup;
    6038             : 
    6039         470 :     extinfo = (ExtensionInfo *) pg_malloc(ntups * sizeof(ExtensionInfo));
    6040             : 
    6041         470 :     i_tableoid = PQfnumber(res, "tableoid");
    6042         470 :     i_oid = PQfnumber(res, "oid");
    6043         470 :     i_extname = PQfnumber(res, "extname");
    6044         470 :     i_nspname = PQfnumber(res, "nspname");
    6045         470 :     i_extrelocatable = PQfnumber(res, "extrelocatable");
    6046         470 :     i_extversion = PQfnumber(res, "extversion");
    6047         470 :     i_extconfig = PQfnumber(res, "extconfig");
    6048         470 :     i_extcondition = PQfnumber(res, "extcondition");
    6049             : 
    6050         990 :     for (i = 0; i < ntups; i++)
    6051             :     {
    6052         520 :         extinfo[i].dobj.objType = DO_EXTENSION;
    6053         520 :         extinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    6054         520 :         extinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    6055         520 :         AssignDumpId(&extinfo[i].dobj);
    6056         520 :         extinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_extname));
    6057         520 :         extinfo[i].namespace = pg_strdup(PQgetvalue(res, i, i_nspname));
    6058         520 :         extinfo[i].relocatable = *(PQgetvalue(res, i, i_extrelocatable)) == 't';
    6059         520 :         extinfo[i].extversion = pg_strdup(PQgetvalue(res, i, i_extversion));
    6060         520 :         extinfo[i].extconfig = pg_strdup(PQgetvalue(res, i, i_extconfig));
    6061         520 :         extinfo[i].extcondition = pg_strdup(PQgetvalue(res, i, i_extcondition));
    6062             : 
    6063             :         /* Decide whether we want to dump it */
    6064         520 :         selectDumpableExtension(&(extinfo[i]), dopt);
    6065             :     }
    6066             : 
    6067         470 : cleanup:
    6068         470 :     PQclear(res);
    6069         470 :     destroyPQExpBuffer(query);
    6070             : 
    6071         470 :     *numExtensions = ntups;
    6072             : 
    6073         470 :     return extinfo;
    6074             : }
    6075             : 
    6076             : /*
    6077             :  * getTypes:
    6078             :  *    get information about all types in the system catalogs
    6079             :  *
    6080             :  * NB: this must run after getFuncs() because we assume we can do
    6081             :  * findFuncByOid().
    6082             :  */
    6083             : void
    6084         468 : getTypes(Archive *fout)
    6085             : {
    6086             :     PGresult   *res;
    6087             :     int         ntups;
    6088             :     int         i;
    6089         468 :     PQExpBuffer query = createPQExpBuffer();
    6090             :     TypeInfo   *tyinfo;
    6091             :     ShellTypeInfo *stinfo;
    6092             :     int         i_tableoid;
    6093             :     int         i_oid;
    6094             :     int         i_typname;
    6095             :     int         i_typnamespace;
    6096             :     int         i_typacl;
    6097             :     int         i_acldefault;
    6098             :     int         i_typowner;
    6099             :     int         i_typelem;
    6100             :     int         i_typrelid;
    6101             :     int         i_typrelkind;
    6102             :     int         i_typtype;
    6103             :     int         i_typisdefined;
    6104             :     int         i_isarray;
    6105             :     int         i_typarray;
    6106             : 
    6107             :     /*
    6108             :      * we include even the built-in types because those may be used as array
    6109             :      * elements by user-defined types
    6110             :      *
    6111             :      * we filter out the built-in types when we dump out the types
    6112             :      *
    6113             :      * same approach for undefined (shell) types and array types
    6114             :      *
    6115             :      * Note: as of 8.3 we can reliably detect whether a type is an
    6116             :      * auto-generated array type by checking the element type's typarray.
    6117             :      * (Before that the test is capable of generating false positives.) We
    6118             :      * still check for name beginning with '_', though, so as to avoid the
    6119             :      * cost of the subselect probe for all standard types.  This would have to
    6120             :      * be revisited if the backend ever allows renaming of array types.
    6121             :      */
    6122         468 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, typname, "
    6123             :                          "typnamespace, typacl, "
    6124             :                          "acldefault('T', typowner) AS acldefault, "
    6125             :                          "typowner, "
    6126             :                          "typelem, typrelid, typarray, "
    6127             :                          "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
    6128             :                          "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
    6129             :                          "typtype, typisdefined, "
    6130             :                          "typname[0] = '_' AND typelem != 0 AND "
    6131             :                          "(SELECT typarray FROM pg_type te WHERE oid = pg_type.typelem) = oid AS isarray "
    6132             :                          "FROM pg_type");
    6133             : 
    6134         468 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    6135             : 
    6136         468 :     ntups = PQntuples(res);
    6137             : 
    6138         468 :     tyinfo = (TypeInfo *) pg_malloc(ntups * sizeof(TypeInfo));
    6139             : 
    6140         468 :     i_tableoid = PQfnumber(res, "tableoid");
    6141         468 :     i_oid = PQfnumber(res, "oid");
    6142         468 :     i_typname = PQfnumber(res, "typname");
    6143         468 :     i_typnamespace = PQfnumber(res, "typnamespace");
    6144         468 :     i_typacl = PQfnumber(res, "typacl");
    6145         468 :     i_acldefault = PQfnumber(res, "acldefault");
    6146         468 :     i_typowner = PQfnumber(res, "typowner");
    6147         468 :     i_typelem = PQfnumber(res, "typelem");
    6148         468 :     i_typrelid = PQfnumber(res, "typrelid");
    6149         468 :     i_typrelkind = PQfnumber(res, "typrelkind");
    6150         468 :     i_typtype = PQfnumber(res, "typtype");
    6151         468 :     i_typisdefined = PQfnumber(res, "typisdefined");
    6152         468 :     i_isarray = PQfnumber(res, "isarray");
    6153         468 :     i_typarray = PQfnumber(res, "typarray");
    6154             : 
    6155      340362 :     for (i = 0; i < ntups; i++)
    6156             :     {
    6157      339894 :         tyinfo[i].dobj.objType = DO_TYPE;
    6158      339894 :         tyinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    6159      339894 :         tyinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    6160      339894 :         AssignDumpId(&tyinfo[i].dobj);
    6161      339894 :         tyinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_typname));
    6162      679788 :         tyinfo[i].dobj.namespace =
    6163      339894 :             findNamespace(atooid(PQgetvalue(res, i, i_typnamespace)));
    6164      339894 :         tyinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_typacl));
    6165      339894 :         tyinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
    6166      339894 :         tyinfo[i].dacl.privtype = 0;
    6167      339894 :         tyinfo[i].dacl.initprivs = NULL;
    6168      339894 :         tyinfo[i].ftypname = NULL;  /* may get filled later */
    6169      339894 :         tyinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_typowner));
    6170      339894 :         tyinfo[i].typelem = atooid(PQgetvalue(res, i, i_typelem));
    6171      339894 :         tyinfo[i].typrelid = atooid(PQgetvalue(res, i, i_typrelid));
    6172      339894 :         tyinfo[i].typrelkind = *PQgetvalue(res, i, i_typrelkind);
    6173      339894 :         tyinfo[i].typtype = *PQgetvalue(res, i, i_typtype);
    6174      339894 :         tyinfo[i].shellType = NULL;
    6175             : 
    6176      339894 :         if (strcmp(PQgetvalue(res, i, i_typisdefined), "t") == 0)
    6177      339776 :             tyinfo[i].isDefined = true;
    6178             :         else
    6179         118 :             tyinfo[i].isDefined = false;
    6180             : 
    6181      339894 :         if (strcmp(PQgetvalue(res, i, i_isarray), "t") == 0)
    6182      163102 :             tyinfo[i].isArray = true;
    6183             :         else
    6184      176792 :             tyinfo[i].isArray = false;
    6185             : 
    6186      339894 :         tyinfo[i].typarray = atooid(PQgetvalue(res, i, i_typarray));
    6187             : 
    6188      339894 :         if (tyinfo[i].typtype == TYPTYPE_MULTIRANGE)
    6189        3124 :             tyinfo[i].isMultirange = true;
    6190             :         else
    6191      336770 :             tyinfo[i].isMultirange = false;
    6192             : 
    6193             :         /* Decide whether we want to dump it */
    6194      339894 :         selectDumpableType(&tyinfo[i], fout);
    6195             : 
    6196             :         /* Mark whether type has an ACL */
    6197      339894 :         if (!PQgetisnull(res, i, i_typacl))
    6198         442 :             tyinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
    6199             : 
    6200             :         /*
    6201             :          * If it's a domain, fetch info about its constraints, if any
    6202             :          */
    6203      339894 :         tyinfo[i].nDomChecks = 0;
    6204      339894 :         tyinfo[i].domChecks = NULL;
    6205      339894 :         tyinfo[i].notnull = NULL;
    6206      339894 :         if ((tyinfo[i].dobj.dump & DUMP_COMPONENT_DEFINITION) &&
    6207       41044 :             tyinfo[i].typtype == TYPTYPE_DOMAIN)
    6208         468 :             getDomainConstraints(fout, &(tyinfo[i]));
    6209             : 
    6210             :         /*
    6211             :          * If it's a base type, make a DumpableObject representing a shell
    6212             :          * definition of the type.  We will need to dump that ahead of the I/O
    6213             :          * functions for the type.  Similarly, range types need a shell
    6214             :          * definition in case they have a canonicalize function.
    6215             :          *
    6216             :          * Note: the shell type doesn't have a catId.  You might think it
    6217             :          * should copy the base type's catId, but then it might capture the
    6218             :          * pg_depend entries for the type, which we don't want.
    6219             :          */
    6220      339894 :         if ((tyinfo[i].dobj.dump & DUMP_COMPONENT_DEFINITION) &&
    6221       41044 :             (tyinfo[i].typtype == TYPTYPE_BASE ||
    6222       20052 :              tyinfo[i].typtype == TYPTYPE_RANGE))
    6223             :         {
    6224       21292 :             stinfo = (ShellTypeInfo *) pg_malloc(sizeof(ShellTypeInfo));
    6225       21292 :             stinfo->dobj.objType = DO_SHELL_TYPE;
    6226       21292 :             stinfo->dobj.catId = nilCatalogId;
    6227       21292 :             AssignDumpId(&stinfo->dobj);
    6228       21292 :             stinfo->dobj.name = pg_strdup(tyinfo[i].dobj.name);
    6229       21292 :             stinfo->dobj.namespace = tyinfo[i].dobj.namespace;
    6230       21292 :             stinfo->baseType = &(tyinfo[i]);
    6231       21292 :             tyinfo[i].shellType = stinfo;
    6232             : 
    6233             :             /*
    6234             :              * Initially mark the shell type as not to be dumped.  We'll only
    6235             :              * dump it if the I/O or canonicalize functions need to be dumped;
    6236             :              * this is taken care of while sorting dependencies.
    6237             :              */
    6238       21292 :             stinfo->dobj.dump = DUMP_COMPONENT_NONE;
    6239             :         }
    6240             :     }
    6241             : 
    6242         468 :     PQclear(res);
    6243             : 
    6244         468 :     destroyPQExpBuffer(query);
    6245         468 : }
    6246             : 
    6247             : /*
    6248             :  * getOperators:
    6249             :  *    get information about all operators in the system catalogs
    6250             :  */
    6251             : void
    6252         468 : getOperators(Archive *fout)
    6253             : {
    6254             :     PGresult   *res;
    6255             :     int         ntups;
    6256             :     int         i;
    6257         468 :     PQExpBuffer query = createPQExpBuffer();
    6258             :     OprInfo    *oprinfo;
    6259             :     int         i_tableoid;
    6260             :     int         i_oid;
    6261             :     int         i_oprname;
    6262             :     int         i_oprnamespace;
    6263             :     int         i_oprowner;
    6264             :     int         i_oprkind;
    6265             :     int         i_oprcode;
    6266             : 
    6267             :     /*
    6268             :      * find all operators, including builtin operators; we filter out
    6269             :      * system-defined operators at dump-out time.
    6270             :      */
    6271             : 
    6272         468 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, oprname, "
    6273             :                          "oprnamespace, "
    6274             :                          "oprowner, "
    6275             :                          "oprkind, "
    6276             :                          "oprcode::oid AS oprcode "
    6277             :                          "FROM pg_operator");
    6278             : 
    6279         468 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    6280             : 
    6281         468 :     ntups = PQntuples(res);
    6282             : 
    6283         468 :     oprinfo = (OprInfo *) pg_malloc(ntups * sizeof(OprInfo));
    6284             : 
    6285         468 :     i_tableoid = PQfnumber(res, "tableoid");
    6286         468 :     i_oid = PQfnumber(res, "oid");
    6287         468 :     i_oprname = PQfnumber(res, "oprname");
    6288         468 :     i_oprnamespace = PQfnumber(res, "oprnamespace");
    6289         468 :     i_oprowner = PQfnumber(res, "oprowner");
    6290         468 :     i_oprkind = PQfnumber(res, "oprkind");
    6291         468 :     i_oprcode = PQfnumber(res, "oprcode");
    6292             : 
    6293      374774 :     for (i = 0; i < ntups; i++)
    6294             :     {
    6295      374306 :         oprinfo[i].dobj.objType = DO_OPERATOR;
    6296      374306 :         oprinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    6297      374306 :         oprinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    6298      374306 :         AssignDumpId(&oprinfo[i].dobj);
    6299      374306 :         oprinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_oprname));
    6300      748612 :         oprinfo[i].dobj.namespace =
    6301      374306 :             findNamespace(atooid(PQgetvalue(res, i, i_oprnamespace)));
    6302      374306 :         oprinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_oprowner));
    6303      374306 :         oprinfo[i].oprkind = (PQgetvalue(res, i, i_oprkind))[0];
    6304      374306 :         oprinfo[i].oprcode = atooid(PQgetvalue(res, i, i_oprcode));
    6305             : 
    6306             :         /* Decide whether we want to dump it */
    6307      374306 :         selectDumpableObject(&(oprinfo[i].dobj), fout);
    6308             :     }
    6309             : 
    6310         468 :     PQclear(res);
    6311             : 
    6312         468 :     destroyPQExpBuffer(query);
    6313         468 : }
    6314             : 
    6315             : /*
    6316             :  * getCollations:
    6317             :  *    get information about all collations in the system catalogs
    6318             :  */
    6319             : void
    6320         468 : getCollations(Archive *fout)
    6321             : {
    6322             :     PGresult   *res;
    6323             :     int         ntups;
    6324             :     int         i;
    6325             :     PQExpBuffer query;
    6326             :     CollInfo   *collinfo;
    6327             :     int         i_tableoid;
    6328             :     int         i_oid;
    6329             :     int         i_collname;
    6330             :     int         i_collnamespace;
    6331             :     int         i_collowner;
    6332             : 
    6333         468 :     query = createPQExpBuffer();
    6334             : 
    6335             :     /*
    6336             :      * find all collations, including builtin collations; we filter out
    6337             :      * system-defined collations at dump-out time.
    6338             :      */
    6339             : 
    6340         468 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, collname, "
    6341             :                          "collnamespace, "
    6342             :                          "collowner "
    6343             :                          "FROM pg_collation");
    6344             : 
    6345         468 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    6346             : 
    6347         468 :     ntups = PQntuples(res);
    6348             : 
    6349         468 :     collinfo = (CollInfo *) pg_malloc(ntups * sizeof(CollInfo));
    6350             : 
    6351         468 :     i_tableoid = PQfnumber(res, "tableoid");
    6352         468 :     i_oid = PQfnumber(res, "oid");
    6353         468 :     i_collname = PQfnumber(res, "collname");
    6354         468 :     i_collnamespace = PQfnumber(res, "collnamespace");
    6355         468 :     i_collowner = PQfnumber(res, "collowner");
    6356             : 
    6357      382612 :     for (i = 0; i < ntups; i++)
    6358             :     {
    6359      382144 :         collinfo[i].dobj.objType = DO_COLLATION;
    6360      382144 :         collinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    6361      382144 :         collinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    6362      382144 :         AssignDumpId(&collinfo[i].dobj);
    6363      382144 :         collinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_collname));
    6364      764288 :         collinfo[i].dobj.namespace =
    6365      382144 :             findNamespace(atooid(PQgetvalue(res, i, i_collnamespace)));
    6366      382144 :         collinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_collowner));
    6367             : 
    6368             :         /* Decide whether we want to dump it */
    6369      382144 :         selectDumpableObject(&(collinfo[i].dobj), fout);
    6370             :     }
    6371             : 
    6372         468 :     PQclear(res);
    6373             : 
    6374         468 :     destroyPQExpBuffer(query);
    6375         468 : }
    6376             : 
    6377             : /*
    6378             :  * getConversions:
    6379             :  *    get information about all conversions in the system catalogs
    6380             :  */
    6381             : void
    6382         468 : getConversions(Archive *fout)
    6383             : {
    6384             :     PGresult   *res;
    6385             :     int         ntups;
    6386             :     int         i;
    6387             :     PQExpBuffer query;
    6388             :     ConvInfo   *convinfo;
    6389             :     int         i_tableoid;
    6390             :     int         i_oid;
    6391             :     int         i_conname;
    6392             :     int         i_connamespace;
    6393             :     int         i_conowner;
    6394             : 
    6395         468 :     query = createPQExpBuffer();
    6396             : 
    6397             :     /*
    6398             :      * find all conversions, including builtin conversions; we filter out
    6399             :      * system-defined conversions at dump-out time.
    6400             :      */
    6401             : 
    6402         468 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, conname, "
    6403             :                          "connamespace, "
    6404             :                          "conowner "
    6405             :                          "FROM pg_conversion");
    6406             : 
    6407         468 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    6408             : 
    6409         468 :     ntups = PQntuples(res);
    6410             : 
    6411         468 :     convinfo = (ConvInfo *) pg_malloc(ntups * sizeof(ConvInfo));
    6412             : 
    6413         468 :     i_tableoid = PQfnumber(res, "tableoid");
    6414         468 :     i_oid = PQfnumber(res, "oid");
    6415         468 :     i_conname = PQfnumber(res, "conname");
    6416         468 :     i_connamespace = PQfnumber(res, "connamespace");
    6417         468 :     i_conowner = PQfnumber(res, "conowner");
    6418             : 
    6419       60470 :     for (i = 0; i < ntups; i++)
    6420             :     {
    6421       60002 :         convinfo[i].dobj.objType = DO_CONVERSION;
    6422       60002 :         convinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    6423       60002 :         convinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    6424       60002 :         AssignDumpId(&convinfo[i].dobj);
    6425       60002 :         convinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_conname));
    6426      120004 :         convinfo[i].dobj.namespace =
    6427       60002 :             findNamespace(atooid(PQgetvalue(res, i, i_connamespace)));
    6428       60002 :         convinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_conowner));
    6429             : 
    6430             :         /* Decide whether we want to dump it */
    6431       60002 :         selectDumpableObject(&(convinfo[i].dobj), fout);
    6432             :     }
    6433             : 
    6434         468 :     PQclear(res);
    6435             : 
    6436         468 :     destroyPQExpBuffer(query);
    6437         468 : }
    6438             : 
    6439             : /*
    6440             :  * getAccessMethods:
    6441             :  *    get information about all user-defined access methods
    6442             :  */
    6443             : void
    6444         468 : getAccessMethods(Archive *fout)
    6445             : {
    6446             :     PGresult   *res;
    6447             :     int         ntups;
    6448             :     int         i;
    6449             :     PQExpBuffer query;
    6450             :     AccessMethodInfo *aminfo;
    6451             :     int         i_tableoid;
    6452             :     int         i_oid;
    6453             :     int         i_amname;
    6454             :     int         i_amhandler;
    6455             :     int         i_amtype;
    6456             : 
    6457             :     /* Before 9.6, there are no user-defined access methods */
    6458         468 :     if (fout->remoteVersion < 90600)
    6459           0 :         return;
    6460             : 
    6461         468 :     query = createPQExpBuffer();
    6462             : 
    6463             :     /* Select all access methods from pg_am table */
    6464         468 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, amname, amtype, "
    6465             :                          "amhandler::pg_catalog.regproc AS amhandler "
    6466             :                          "FROM pg_am");
    6467             : 
    6468         468 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    6469             : 
    6470         468 :     ntups = PQntuples(res);
    6471             : 
    6472         468 :     aminfo = (AccessMethodInfo *) pg_malloc(ntups * sizeof(AccessMethodInfo));
    6473             : 
    6474         468 :     i_tableoid = PQfnumber(res, "tableoid");
    6475         468 :     i_oid = PQfnumber(res, "oid");
    6476         468 :     i_amname = PQfnumber(res, "amname");
    6477         468 :     i_amhandler = PQfnumber(res, "amhandler");
    6478         468 :     i_amtype = PQfnumber(res, "amtype");
    6479             : 
    6480        4010 :     for (i = 0; i < ntups; i++)
    6481             :     {
    6482        3542 :         aminfo[i].dobj.objType = DO_ACCESS_METHOD;
    6483        3542 :         aminfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    6484        3542 :         aminfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    6485        3542 :         AssignDumpId(&aminfo[i].dobj);
    6486        3542 :         aminfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_amname));
    6487        3542 :         aminfo[i].dobj.namespace = NULL;
    6488        3542 :         aminfo[i].amhandler = pg_strdup(PQgetvalue(res, i, i_amhandler));
    6489        3542 :         aminfo[i].amtype = *(PQgetvalue(res, i, i_amtype));
    6490             : 
    6491             :         /* Decide whether we want to dump it */
    6492        3542 :         selectDumpableAccessMethod(&(aminfo[i]), fout);
    6493             :     }
    6494             : 
    6495         468 :     PQclear(res);
    6496             : 
    6497         468 :     destroyPQExpBuffer(query);
    6498             : }
    6499             : 
    6500             : 
    6501             : /*
    6502             :  * getOpclasses:
    6503             :  *    get information about all opclasses in the system catalogs
    6504             :  */
    6505             : void
    6506         468 : getOpclasses(Archive *fout)
    6507             : {
    6508             :     PGresult   *res;
    6509             :     int         ntups;
    6510             :     int         i;
    6511         468 :     PQExpBuffer query = createPQExpBuffer();
    6512             :     OpclassInfo *opcinfo;
    6513             :     int         i_tableoid;
    6514             :     int         i_oid;
    6515             :     int         i_opcname;
    6516             :     int         i_opcnamespace;
    6517             :     int         i_opcowner;
    6518             : 
    6519             :     /*
    6520             :      * find all opclasses, including builtin opclasses; we filter out
    6521             :      * system-defined opclasses at dump-out time.
    6522             :      */
    6523             : 
    6524         468 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, opcname, "
    6525             :                          "opcnamespace, "
    6526             :                          "opcowner "
    6527             :                          "FROM pg_opclass");
    6528             : 
    6529         468 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    6530             : 
    6531         468 :     ntups = PQntuples(res);
    6532             : 
    6533         468 :     opcinfo = (OpclassInfo *) pg_malloc(ntups * sizeof(OpclassInfo));
    6534             : 
    6535         468 :     i_tableoid = PQfnumber(res, "tableoid");
    6536         468 :     i_oid = PQfnumber(res, "oid");
    6537         468 :     i_opcname = PQfnumber(res, "opcname");
    6538         468 :     i_opcnamespace = PQfnumber(res, "opcnamespace");
    6539         468 :     i_opcowner = PQfnumber(res, "opcowner");
    6540             : 
    6541       83658 :     for (i = 0; i < ntups; i++)
    6542             :     {
    6543       83190 :         opcinfo[i].dobj.objType = DO_OPCLASS;
    6544       83190 :         opcinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    6545       83190 :         opcinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    6546       83190 :         AssignDumpId(&opcinfo[i].dobj);
    6547       83190 :         opcinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_opcname));
    6548      166380 :         opcinfo[i].dobj.namespace =
    6549       83190 :             findNamespace(atooid(PQgetvalue(res, i, i_opcnamespace)));
    6550       83190 :         opcinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_opcowner));
    6551             : 
    6552             :         /* Decide whether we want to dump it */
    6553       83190 :         selectDumpableObject(&(opcinfo[i].dobj), fout);
    6554             :     }
    6555             : 
    6556         468 :     PQclear(res);
    6557             : 
    6558         468 :     destroyPQExpBuffer(query);
    6559         468 : }
    6560             : 
    6561             : /*
    6562             :  * getOpfamilies:
    6563             :  *    get information about all opfamilies in the system catalogs
    6564             :  */
    6565             : void
    6566         468 : getOpfamilies(Archive *fout)
    6567             : {
    6568             :     PGresult   *res;
    6569             :     int         ntups;
    6570             :     int         i;
    6571             :     PQExpBuffer query;
    6572             :     OpfamilyInfo *opfinfo;
    6573             :     int         i_tableoid;
    6574             :     int         i_oid;
    6575             :     int         i_opfname;
    6576             :     int         i_opfnamespace;
    6577             :     int         i_opfowner;
    6578             : 
    6579         468 :     query = createPQExpBuffer();
    6580             : 
    6581             :     /*
    6582             :      * find all opfamilies, including builtin opfamilies; we filter out
    6583             :      * system-defined opfamilies at dump-out time.
    6584             :      */
    6585             : 
    6586         468 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, opfname, "
    6587             :                          "opfnamespace, "
    6588             :                          "opfowner "
    6589             :                          "FROM pg_opfamily");
    6590             : 
    6591         468 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    6592             : 
    6593         468 :     ntups = PQntuples(res);
    6594             : 
    6595         468 :     opfinfo = (OpfamilyInfo *) pg_malloc(ntups * sizeof(OpfamilyInfo));
    6596             : 
    6597         468 :     i_tableoid = PQfnumber(res, "tableoid");
    6598         468 :     i_oid = PQfnumber(res, "oid");
    6599         468 :     i_opfname = PQfnumber(res, "opfname");
    6600         468 :     i_opfnamespace = PQfnumber(res, "opfnamespace");
    6601         468 :     i_opfowner = PQfnumber(res, "opfowner");
    6602             : 
    6603       69132 :     for (i = 0; i < ntups; i++)
    6604             :     {
    6605       68664 :         opfinfo[i].dobj.objType = DO_OPFAMILY;
    6606       68664 :         opfinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    6607       68664 :         opfinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    6608       68664 :         AssignDumpId(&opfinfo[i].dobj);
    6609       68664 :         opfinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_opfname));
    6610      137328 :         opfinfo[i].dobj.namespace =
    6611       68664 :             findNamespace(atooid(PQgetvalue(res, i, i_opfnamespace)));
    6612       68664 :         opfinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_opfowner));
    6613             : 
    6614             :         /* Decide whether we want to dump it */
    6615       68664 :         selectDumpableObject(&(opfinfo[i].dobj), fout);
    6616             :     }
    6617             : 
    6618         468 :     PQclear(res);
    6619             : 
    6620         468 :     destroyPQExpBuffer(query);
    6621         468 : }
    6622             : 
    6623             : /*
    6624             :  * getAggregates:
    6625             :  *    get information about all user-defined aggregates in the system catalogs
    6626             :  */
    6627             : void
    6628         468 : getAggregates(Archive *fout)
    6629             : {
    6630         468 :     DumpOptions *dopt = fout->dopt;
    6631             :     PGresult   *res;
    6632             :     int         ntups;
    6633             :     int         i;
    6634         468 :     PQExpBuffer query = createPQExpBuffer();
    6635             :     AggInfo    *agginfo;
    6636             :     int         i_tableoid;
    6637             :     int         i_oid;
    6638             :     int         i_aggname;
    6639             :     int         i_aggnamespace;
    6640             :     int         i_pronargs;
    6641             :     int         i_proargtypes;
    6642             :     int         i_proowner;
    6643             :     int         i_aggacl;
    6644             :     int         i_acldefault;
    6645             : 
    6646             :     /*
    6647             :      * Find all interesting aggregates.  See comment in getFuncs() for the
    6648             :      * rationale behind the filtering logic.
    6649             :      */
    6650         468 :     if (fout->remoteVersion >= 90600)
    6651             :     {
    6652             :         const char *agg_check;
    6653             : 
    6654         936 :         agg_check = (fout->remoteVersion >= 110000 ? "p.prokind = 'a'"
    6655         468 :                      : "p.proisagg");
    6656             : 
    6657         468 :         appendPQExpBuffer(query, "SELECT p.tableoid, p.oid, "
    6658             :                           "p.proname AS aggname, "
    6659             :                           "p.pronamespace AS aggnamespace, "
    6660             :                           "p.pronargs, p.proargtypes, "
    6661             :                           "p.proowner, "
    6662             :                           "p.proacl AS aggacl, "
    6663             :                           "acldefault('f', p.proowner) AS acldefault "
    6664             :                           "FROM pg_proc p "
    6665             :                           "LEFT JOIN pg_init_privs pip ON "
    6666             :                           "(p.oid = pip.objoid "
    6667             :                           "AND pip.classoid = 'pg_proc'::regclass "
    6668             :                           "AND pip.objsubid = 0) "
    6669             :                           "WHERE %s AND ("
    6670             :                           "p.pronamespace != "
    6671             :                           "(SELECT oid FROM pg_namespace "
    6672             :                           "WHERE nspname = 'pg_catalog') OR "
    6673             :                           "p.proacl IS DISTINCT FROM pip.initprivs",
    6674             :                           agg_check);
    6675         468 :         if (dopt->binary_upgrade)
    6676          62 :             appendPQExpBufferStr(query,
    6677             :                                  " OR EXISTS(SELECT 1 FROM pg_depend WHERE "
    6678             :                                  "classid = 'pg_proc'::regclass AND "
    6679             :                                  "objid = p.oid AND "
    6680             :                                  "refclassid = 'pg_extension'::regclass AND "
    6681             :                                  "deptype = 'e')");
    6682         468 :         appendPQExpBufferChar(query, ')');
    6683             :     }
    6684             :     else
    6685             :     {
    6686           0 :         appendPQExpBufferStr(query, "SELECT tableoid, oid, proname AS aggname, "
    6687             :                              "pronamespace AS aggnamespace, "
    6688             :                              "pronargs, proargtypes, "
    6689             :                              "proowner, "
    6690             :                              "proacl AS aggacl, "
    6691             :                              "acldefault('f', proowner) AS acldefault "
    6692             :                              "FROM pg_proc p "
    6693             :                              "WHERE proisagg AND ("
    6694             :                              "pronamespace != "
    6695             :                              "(SELECT oid FROM pg_namespace "
    6696             :                              "WHERE nspname = 'pg_catalog')");
    6697           0 :         if (dopt->binary_upgrade)
    6698           0 :             appendPQExpBufferStr(query,
    6699             :                                  " OR EXISTS(SELECT 1 FROM pg_depend WHERE "
    6700             :                                  "classid = 'pg_proc'::regclass AND "
    6701             :                                  "objid = p.oid AND "
    6702             :                                  "refclassid = 'pg_extension'::regclass AND "
    6703             :                                  "deptype = 'e')");
    6704           0 :         appendPQExpBufferChar(query, ')');
    6705             :     }
    6706             : 
    6707         468 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    6708             : 
    6709         468 :     ntups = PQntuples(res);
    6710             : 
    6711         468 :     agginfo = (AggInfo *) pg_malloc(ntups * sizeof(AggInfo));
    6712             : 
    6713         468 :     i_tableoid = PQfnumber(res, "tableoid");
    6714         468 :     i_oid = PQfnumber(res, "oid");
    6715         468 :     i_aggname = PQfnumber(res, "aggname");
    6716         468 :     i_aggnamespace = PQfnumber(res, "aggnamespace");
    6717         468 :     i_pronargs = PQfnumber(res, "pronargs");
    6718         468 :     i_proargtypes = PQfnumber(res, "proargtypes");
    6719         468 :     i_proowner = PQfnumber(res, "proowner");
    6720         468 :     i_aggacl = PQfnumber(res, "aggacl");
    6721         468 :     i_acldefault = PQfnumber(res, "acldefault");
    6722             : 
    6723        1556 :     for (i = 0; i < ntups; i++)
    6724             :     {
    6725        1088 :         agginfo[i].aggfn.dobj.objType = DO_AGG;
    6726        1088 :         agginfo[i].aggfn.dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    6727        1088 :         agginfo[i].aggfn.dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    6728        1088 :         AssignDumpId(&agginfo[i].aggfn.dobj);
    6729        1088 :         agginfo[i].aggfn.dobj.name = pg_strdup(PQgetvalue(res, i, i_aggname));
    6730        2176 :         agginfo[i].aggfn.dobj.namespace =
    6731        1088 :             findNamespace(atooid(PQgetvalue(res, i, i_aggnamespace)));
    6732        1088 :         agginfo[i].aggfn.dacl.acl = pg_strdup(PQgetvalue(res, i, i_aggacl));
    6733        1088 :         agginfo[i].aggfn.dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
    6734        1088 :         agginfo[i].aggfn.dacl.privtype = 0;
    6735        1088 :         agginfo[i].aggfn.dacl.initprivs = NULL;
    6736        1088 :         agginfo[i].aggfn.rolname = getRoleName(PQgetvalue(res, i, i_proowner));
    6737        1088 :         agginfo[i].aggfn.lang = InvalidOid; /* not currently interesting */
    6738        1088 :         agginfo[i].aggfn.prorettype = InvalidOid;   /* not saved */
    6739        1088 :         agginfo[i].aggfn.nargs = atoi(PQgetvalue(res, i, i_pronargs));
    6740        1088 :         if (agginfo[i].aggfn.nargs == 0)
    6741         160 :             agginfo[i].aggfn.argtypes = NULL;
    6742             :         else
    6743             :         {
    6744         928 :             agginfo[i].aggfn.argtypes = (Oid *) pg_malloc(agginfo[i].aggfn.nargs * sizeof(Oid));
    6745         928 :             parseOidArray(PQgetvalue(res, i, i_proargtypes),
    6746         928 :                           agginfo[i].aggfn.argtypes,
    6747         928 :                           agginfo[i].aggfn.nargs);
    6748             :         }
    6749        1088 :         agginfo[i].aggfn.postponed_def = false; /* might get set during sort */
    6750             : 
    6751             :         /* Decide whether we want to dump it */
    6752        1088 :         selectDumpableObject(&(agginfo[i].aggfn.dobj), fout);
    6753             : 
    6754             :         /* Mark whether aggregate has an ACL */
    6755        1088 :         if (!PQgetisnull(res, i, i_aggacl))
    6756          50 :             agginfo[i].aggfn.dobj.components |= DUMP_COMPONENT_ACL;
    6757             :     }
    6758             : 
    6759         468 :     PQclear(res);
    6760             : 
    6761         468 :     destroyPQExpBuffer(query);
    6762         468 : }
    6763             : 
    6764             : /*
    6765             :  * getFuncs:
    6766             :  *    get information about all user-defined functions in the system catalogs
    6767             :  */
    6768             : void
    6769         468 : getFuncs(Archive *fout)
    6770             : {
    6771         468 :     DumpOptions *dopt = fout->dopt;
    6772             :     PGresult   *res;
    6773             :     int         ntups;
    6774             :     int         i;
    6775         468 :     PQExpBuffer query = createPQExpBuffer();
    6776             :     FuncInfo   *finfo;
    6777             :     int         i_tableoid;
    6778             :     int         i_oid;
    6779             :     int         i_proname;
    6780             :     int         i_pronamespace;
    6781             :     int         i_proowner;
    6782             :     int         i_prolang;
    6783             :     int         i_pronargs;
    6784             :     int         i_proargtypes;
    6785             :     int         i_prorettype;
    6786             :     int         i_proacl;
    6787             :     int         i_acldefault;
    6788             : 
    6789             :     /*
    6790             :      * Find all interesting functions.  This is a bit complicated:
    6791             :      *
    6792             :      * 1. Always exclude aggregates; those are handled elsewhere.
    6793             :      *
    6794             :      * 2. Always exclude functions that are internally dependent on something
    6795             :      * else, since presumably those will be created as a result of creating
    6796             :      * the something else.  This currently acts only to suppress constructor
    6797             :      * functions for range types.  Note this is OK only because the
    6798             :      * constructors don't have any dependencies the range type doesn't have;
    6799             :      * otherwise we might not get creation ordering correct.
    6800             :      *
    6801             :      * 3. Otherwise, we normally exclude functions in pg_catalog.  However, if
    6802             :      * they're members of extensions and we are in binary-upgrade mode then
    6803             :      * include them, since we want to dump extension members individually in
    6804             :      * that mode.  Also, if they are used by casts or transforms then we need
    6805             :      * to gather the information about them, though they won't be dumped if
    6806             :      * they are built-in.  Also, in 9.6 and up, include functions in
    6807             :      * pg_catalog if they have an ACL different from what's shown in
    6808             :      * pg_init_privs (so we have to join to pg_init_privs; annoying).
    6809             :      */
    6810         468 :     if (fout->remoteVersion >= 90600)
    6811             :     {
    6812             :         const char *not_agg_check;
    6813             : 
    6814         936 :         not_agg_check = (fout->remoteVersion >= 110000 ? "p.prokind <> 'a'"
    6815         468 :                          : "NOT p.proisagg");
    6816             : 
    6817         468 :         appendPQExpBuffer(query,
    6818             :                           "SELECT p.tableoid, p.oid, p.proname, p.prolang, "
    6819             :                           "p.pronargs, p.proargtypes, p.prorettype, "
    6820             :                           "p.proacl, "
    6821             :                           "acldefault('f', p.proowner) AS acldefault, "
    6822             :                           "p.pronamespace, "
    6823             :                           "p.proowner "
    6824             :                           "FROM pg_proc p "
    6825             :                           "LEFT JOIN pg_init_privs pip ON "
    6826             :                           "(p.oid = pip.objoid "
    6827             :                           "AND pip.classoid = 'pg_proc'::regclass "
    6828             :                           "AND pip.objsubid = 0) "
    6829             :                           "WHERE %s"
    6830             :                           "\n  AND NOT EXISTS (SELECT 1 FROM pg_depend "
    6831             :                           "WHERE classid = 'pg_proc'::regclass AND "
    6832             :                           "objid = p.oid AND deptype = 'i')"
    6833             :                           "\n  AND ("
    6834             :                           "\n  pronamespace != "
    6835             :                           "(SELECT oid FROM pg_namespace "
    6836             :                           "WHERE nspname = 'pg_catalog')"
    6837             :                           "\n  OR EXISTS (SELECT 1 FROM pg_cast"
    6838             :                           "\n  WHERE pg_cast.oid > %u "
    6839             :                           "\n  AND p.oid = pg_cast.castfunc)"
    6840             :                           "\n  OR EXISTS (SELECT 1 FROM pg_transform"
    6841             :                           "\n  WHERE pg_transform.oid > %u AND "
    6842             :                           "\n  (p.oid = pg_transform.trffromsql"
    6843             :                           "\n  OR p.oid = pg_transform.trftosql))",
    6844             :                           not_agg_check,
    6845             :                           g_last_builtin_oid,
    6846             :                           g_last_builtin_oid);
    6847         468 :         if (dopt->binary_upgrade)
    6848          62 :             appendPQExpBufferStr(query,
    6849             :                                  "\n  OR EXISTS(SELECT 1 FROM pg_depend WHERE "
    6850             :                                  "classid = 'pg_proc'::regclass AND "
    6851             :                                  "objid = p.oid AND "
    6852             :                                  "refclassid = 'pg_extension'::regclass AND "
    6853             :                                  "deptype = 'e')");
    6854         468 :         appendPQExpBufferStr(query,
    6855             :                              "\n  OR p.proacl IS DISTINCT FROM pip.initprivs");
    6856         468 :         appendPQExpBufferChar(query, ')');
    6857             :     }
    6858             :     else
    6859             :     {
    6860           0 :         appendPQExpBuffer(query,
    6861             :                           "SELECT tableoid, oid, proname, prolang, "
    6862             :                           "pronargs, proargtypes, prorettype, proacl, "
    6863             :                           "acldefault('f', proowner) AS acldefault, "
    6864             :                           "pronamespace, "
    6865             :                           "proowner "
    6866             :                           "FROM pg_proc p "
    6867             :                           "WHERE NOT proisagg"
    6868             :                           "\n  AND NOT EXISTS (SELECT 1 FROM pg_depend "
    6869             :                           "WHERE classid = 'pg_proc'::regclass AND "
    6870             :                           "objid = p.oid AND deptype = 'i')"
    6871             :                           "\n  AND ("
    6872             :                           "\n  pronamespace != "
    6873             :                           "(SELECT oid FROM pg_namespace "
    6874             :                           "WHERE nspname = 'pg_catalog')"
    6875             :                           "\n  OR EXISTS (SELECT 1 FROM pg_cast"
    6876             :                           "\n  WHERE pg_cast.oid > '%u'::oid"
    6877             :                           "\n  AND p.oid = pg_cast.castfunc)",
    6878             :                           g_last_builtin_oid);
    6879             : 
    6880           0 :         if (fout->remoteVersion >= 90500)
    6881           0 :             appendPQExpBuffer(query,
    6882             :                               "\n  OR EXISTS (SELECT 1 FROM pg_transform"
    6883             :                               "\n  WHERE pg_transform.oid > '%u'::oid"
    6884             :                               "\n  AND (p.oid = pg_transform.trffromsql"
    6885             :                               "\n  OR p.oid = pg_transform.trftosql))",
    6886             :                               g_last_builtin_oid);
    6887             : 
    6888           0 :         if (dopt->binary_upgrade)
    6889           0 :             appendPQExpBufferStr(query,
    6890             :                                  "\n  OR EXISTS(SELECT 1 FROM pg_depend WHERE "
    6891             :                                  "classid = 'pg_proc'::regclass AND "
    6892             :                                  "objid = p.oid AND "
    6893             :                                  "refclassid = 'pg_extension'::regclass AND "
    6894             :                                  "deptype = 'e')");
    6895           0 :         appendPQExpBufferChar(query, ')');
    6896             :     }
    6897             : 
    6898         468 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    6899             : 
    6900         468 :     ntups = PQntuples(res);
    6901             : 
    6902         468 :     finfo = (FuncInfo *) pg_malloc0(ntups * sizeof(FuncInfo));
    6903             : 
    6904         468 :     i_tableoid = PQfnumber(res, "tableoid");
    6905         468 :     i_oid = PQfnumber(res, "oid");
    6906         468 :     i_proname = PQfnumber(res, "proname");
    6907         468 :     i_pronamespace = PQfnumber(res, "pronamespace");
    6908         468 :     i_proowner = PQfnumber(res, "proowner");
    6909         468 :     i_prolang = PQfnumber(res, "prolang");
    6910         468 :     i_pronargs = PQfnumber(res, "pronargs");
    6911         468 :     i_proargtypes = PQfnumber(res, "proargtypes");
    6912         468 :     i_prorettype = PQfnumber(res, "prorettype");
    6913         468 :     i_proacl = PQfnumber(res, "proacl");
    6914         468 :     i_acldefault = PQfnumber(res, "acldefault");
    6915             : 
    6916       12766 :     for (i = 0; i < ntups; i++)
    6917             :     {
    6918       12298 :         finfo[i].dobj.objType = DO_FUNC;
    6919       12298 :         finfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    6920       12298 :         finfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    6921       12298 :         AssignDumpId(&finfo[i].dobj);
    6922       12298 :         finfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_proname));
    6923       24596 :         finfo[i].dobj.namespace =
    6924       12298 :             findNamespace(atooid(PQgetvalue(res, i, i_pronamespace)));
    6925       12298 :         finfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_proacl));
    6926       12298 :         finfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
    6927       12298 :         finfo[i].dacl.privtype = 0;
    6928       12298 :         finfo[i].dacl.initprivs = NULL;
    6929       12298 :         finfo[i].rolname = getRoleName(PQgetvalue(res, i, i_proowner));
    6930       12298 :         finfo[i].lang = atooid(PQgetvalue(res, i, i_prolang));
    6931       12298 :         finfo[i].prorettype = atooid(PQgetvalue(res, i, i_prorettype));
    6932       12298 :         finfo[i].nargs = atoi(PQgetvalue(res, i, i_pronargs));
    6933       12298 :         if (finfo[i].nargs == 0)
    6934        2768 :             finfo[i].argtypes = NULL;
    6935             :         else
    6936             :         {
    6937        9530 :             finfo[i].argtypes = (Oid *) pg_malloc(finfo[i].nargs * sizeof(Oid));
    6938        9530 :             parseOidArray(PQgetvalue(res, i, i_proargtypes),
    6939        9530 :                           finfo[i].argtypes, finfo[i].nargs);
    6940             :         }
    6941       12298 :         finfo[i].postponed_def = false; /* might get set during sort */
    6942             : 
    6943             :         /* Decide whether we want to dump it */
    6944       12298 :         selectDumpableObject(&(finfo[i].dobj), fout);
    6945             : 
    6946             :         /* Mark whether function has an ACL */
    6947       12298 :         if (!PQgetisnull(res, i, i_proacl))
    6948         310 :             finfo[i].dobj.components |= DUMP_COMPONENT_ACL;
    6949             :     }
    6950             : 
    6951         468 :     PQclear(res);
    6952             : 
    6953         468 :     destroyPQExpBuffer(query);
    6954         468 : }
    6955             : 
    6956             : /*
    6957             :  * getRelationStatistics
    6958             :  *    register the statistics object as a dependent of the relation.
    6959             :  *
    6960             :  * reltuples is passed as a string to avoid complexities in converting from/to
    6961             :  * floating point.
    6962             :  */
    6963             : static RelStatsInfo *
    6964       26484 : getRelationStatistics(Archive *fout, DumpableObject *rel, int32 relpages,
    6965             :                       char *reltuples, int32 relallvisible,
    6966             :                       int32 relallfrozen, char relkind,
    6967             :                       char **indAttNames, int nindAttNames)
    6968             : {
    6969       26484 :     if (!fout->dopt->dumpStatistics)
    6970       18918 :         return NULL;
    6971             : 
    6972        7566 :     if ((relkind == RELKIND_RELATION) ||
    6973        3278 :         (relkind == RELKIND_PARTITIONED_TABLE) ||
    6974        2002 :         (relkind == RELKIND_INDEX) ||
    6975        1314 :         (relkind == RELKIND_PARTITIONED_INDEX) ||
    6976         578 :         (relkind == RELKIND_MATVIEW ||
    6977             :          relkind == RELKIND_FOREIGN_TABLE))
    6978             :     {
    6979        7060 :         RelStatsInfo *info = pg_malloc0(sizeof(RelStatsInfo));
    6980        7060 :         DumpableObject *dobj = &info->dobj;
    6981             : 
    6982        7060 :         dobj->objType = DO_REL_STATS;
    6983        7060 :         dobj->catId.tableoid = 0;
    6984        7060 :         dobj->catId.oid = 0;
    6985        7060 :         AssignDumpId(dobj);
    6986        7060 :         dobj->dependencies = (DumpId *) pg_malloc(sizeof(DumpId));
    6987        7060 :         dobj->dependencies[0] = rel->dumpId;
    6988        7060 :         dobj->nDeps = 1;
    6989        7060 :         dobj->allocDeps = 1;
    6990        7060 :         dobj->components |= DUMP_COMPONENT_STATISTICS;
    6991        7060 :         dobj->name = pg_strdup(rel->name);
    6992        7060 :         dobj->namespace = rel->namespace;
    6993        7060 :         info->relpages = relpages;
    6994        7060 :         info->reltuples = pstrdup(reltuples);
    6995        7060 :         info->relallvisible = relallvisible;
    6996        7060 :         info->relallfrozen = relallfrozen;
    6997        7060 :         info->relkind = relkind;
    6998        7060 :         info->indAttNames = indAttNames;
    6999        7060 :         info->nindAttNames = nindAttNames;
    7000             : 
    7001             :         /*
    7002             :          * Ordinarily, stats go in SECTION_DATA for tables and
    7003             :          * SECTION_POST_DATA for indexes.
    7004             :          *
    7005             :          * However, the section may be updated later for materialized view
    7006             :          * stats. REFRESH MATERIALIZED VIEW replaces the storage and resets
    7007             :          * the stats, so the stats must be restored after the data. Also, the
    7008             :          * materialized view definition may be postponed to SECTION_POST_DATA
    7009             :          * (see repairMatViewBoundaryMultiLoop()).
    7010             :          */
    7011        7060 :         switch (info->relkind)
    7012             :         {
    7013        5096 :             case RELKIND_RELATION:
    7014             :             case RELKIND_PARTITIONED_TABLE:
    7015             :             case RELKIND_MATVIEW:
    7016             :             case RELKIND_FOREIGN_TABLE:
    7017        5096 :                 info->section = SECTION_DATA;
    7018        5096 :                 break;
    7019        1964 :             case RELKIND_INDEX:
    7020             :             case RELKIND_PARTITIONED_INDEX:
    7021        1964 :                 info->section = SECTION_POST_DATA;
    7022        1964 :                 break;
    7023           0 :             default:
    7024           0 :                 pg_fatal("cannot dump statistics for relation kind \"%c\"",
    7025             :                          info->relkind);
    7026             :         }
    7027             : 
    7028        7060 :         return info;
    7029             :     }
    7030         506 :     return NULL;
    7031             : }
    7032             : 
    7033             : /*
    7034             :  * getTables
    7035             :  *    read all the tables (no indexes) in the system catalogs,
    7036             :  *    and return them as an array of TableInfo structures
    7037             :  *
    7038             :  * *numTables is set to the number of tables read in
    7039             :  */
    7040             : TableInfo *
    7041         470 : getTables(Archive *fout, int *numTables)
    7042             : {
    7043         470 :     DumpOptions *dopt = fout->dopt;
    7044             :     PGresult   *res;
    7045             :     int         ntups;
    7046             :     int         i;
    7047         470 :     PQExpBuffer query = createPQExpBuffer();
    7048             :     TableInfo  *tblinfo;
    7049             :     int         i_reltableoid;
    7050             :     int         i_reloid;
    7051             :     int         i_relname;
    7052             :     int         i_relnamespace;
    7053             :     int         i_relkind;
    7054             :     int         i_reltype;
    7055             :     int         i_relowner;
    7056             :     int         i_relchecks;
    7057             :     int         i_relhasindex;
    7058             :     int         i_relhasrules;
    7059             :     int         i_relpages;
    7060             :     int         i_reltuples;
    7061             :     int         i_relallvisible;
    7062             :     int         i_relallfrozen;
    7063             :     int         i_toastpages;
    7064             :     int         i_owning_tab;
    7065             :     int         i_owning_col;
    7066             :     int         i_reltablespace;
    7067             :     int         i_relhasoids;
    7068             :     int         i_relhastriggers;
    7069             :     int         i_relpersistence;
    7070             :     int         i_relispopulated;
    7071             :     int         i_relreplident;
    7072             :     int         i_relrowsec;
    7073             :     int         i_relforcerowsec;
    7074             :     int         i_relfrozenxid;
    7075             :     int         i_toastfrozenxid;
    7076             :     int         i_toastoid;
    7077             :     int         i_relminmxid;
    7078             :     int         i_toastminmxid;
    7079             :     int         i_reloptions;
    7080             :     int         i_checkoption;
    7081             :     int         i_toastreloptions;
    7082             :     int         i_reloftype;
    7083             :     int         i_foreignserver;
    7084             :     int         i_amname;
    7085             :     int         i_is_identity_sequence;
    7086             :     int         i_relacl;
    7087             :     int         i_acldefault;
    7088             :     int         i_ispartition;
    7089             : 
    7090             :     /*
    7091             :      * Find all the tables and table-like objects.
    7092             :      *
    7093             :      * We must fetch all tables in this phase because otherwise we cannot
    7094             :      * correctly identify inherited columns, owned sequences, etc.
    7095             :      *
    7096             :      * We include system catalogs, so that we can work if a user table is
    7097             :      * defined to inherit from a system catalog (pretty weird, but...)
    7098             :      *
    7099             :      * Note: in this phase we should collect only a minimal amount of
    7100             :      * information about each table, basically just enough to decide if it is
    7101             :      * interesting.  In particular, since we do not yet have lock on any user
    7102             :      * table, we MUST NOT invoke any server-side data collection functions
    7103             :      * (for instance, pg_get_partkeydef()).  Those are likely to fail or give
    7104             :      * wrong answers if any concurrent DDL is happening.
    7105             :      */
    7106             : 
    7107         470 :     appendPQExpBufferStr(query,
    7108             :                          "SELECT c.tableoid, c.oid, c.relname, "
    7109             :                          "c.relnamespace, c.relkind, c.reltype, "
    7110             :                          "c.relowner, "
    7111             :                          "c.relchecks, "
    7112             :                          "c.relhasindex, c.relhasrules, c.relpages, "
    7113             :                          "c.reltuples, c.relallvisible, ");
    7114             : 
    7115         470 :     if (fout->remoteVersion >= 180000)
    7116         470 :         appendPQExpBufferStr(query, "c.relallfrozen, ");
    7117             :     else
    7118           0 :         appendPQExpBufferStr(query, "0 AS relallfrozen, ");
    7119             : 
    7120         470 :     appendPQExpBufferStr(query,
    7121             :                          "c.relhastriggers, c.relpersistence, "
    7122             :                          "c.reloftype, "
    7123             :                          "c.relacl, "
    7124             :                          "acldefault(CASE WHEN c.relkind = " CppAsString2(RELKIND_SEQUENCE)
    7125             :                          " THEN 's'::\"char\" ELSE 'r'::\"char\" END, c.relowner) AS acldefault, "
    7126             :                          "CASE WHEN c.relkind = " CppAsString2(RELKIND_FOREIGN_TABLE) " THEN "
    7127             :                          "(SELECT ftserver FROM pg_catalog.pg_foreign_table WHERE ftrelid = c.oid) "
    7128             :                          "ELSE 0 END AS foreignserver, "
    7129             :                          "c.relfrozenxid, tc.relfrozenxid AS tfrozenxid, "
    7130             :                          "tc.oid AS toid, "
    7131             :                          "tc.relpages AS toastpages, "
    7132             :                          "tc.reloptions AS toast_reloptions, "
    7133             :                          "d.refobjid AS owning_tab, "
    7134             :                          "d.refobjsubid AS owning_col, "
    7135             :                          "tsp.spcname AS reltablespace, ");
    7136             : 
    7137         470 :     if (fout->remoteVersion >= 120000)
    7138         470 :         appendPQExpBufferStr(query,
    7139             :                              "false AS relhasoids, ");
    7140             :     else
    7141           0 :         appendPQExpBufferStr(query,
    7142             :                              "c.relhasoids, ");
    7143             : 
    7144         470 :     if (fout->remoteVersion >= 90300)
    7145         470 :         appendPQExpBufferStr(query,
    7146             :                              "c.relispopulated, ");
    7147             :     else
    7148           0 :         appendPQExpBufferStr(query,
    7149             :                              "'t' as relispopulated, ");
    7150             : 
    7151         470 :     if (fout->remoteVersion >= 90400)
    7152         470 :         appendPQExpBufferStr(query,
    7153             :                              "c.relreplident, ");
    7154             :     else
    7155           0 :         appendPQExpBufferStr(query,
    7156             :                              "'d' AS relreplident, ");
    7157             : 
    7158         470 :     if (fout->remoteVersion >= 90500)
    7159         470 :         appendPQExpBufferStr(query,
    7160             :                              "c.relrowsecurity, c.relforcerowsecurity, ");
    7161             :     else
    7162           0 :         appendPQExpBufferStr(query,
    7163             :                              "false AS relrowsecurity, "
    7164             :                              "false AS relforcerowsecurity, ");
    7165             : 
    7166         470 :     if (fout->remoteVersion >= 90300)
    7167         470 :         appendPQExpBufferStr(query,
    7168             :                              "c.relminmxid, tc.relminmxid AS tminmxid, ");
    7169             :     else
    7170           0 :         appendPQExpBufferStr(query,
    7171             :                              "0 AS relminmxid, 0 AS tminmxid, ");
    7172             : 
    7173         470 :     if (fout->remoteVersion >= 90300)
    7174         470 :         appendPQExpBufferStr(query,
    7175             :                              "array_remove(array_remove(c.reloptions,'check_option=local'),'check_option=cascaded') AS reloptions, "
    7176             :                              "CASE WHEN 'check_option=local' = ANY (c.reloptions) THEN 'LOCAL'::text "
    7177             :                              "WHEN 'check_option=cascaded' = ANY (c.reloptions) THEN 'CASCADED'::text ELSE NULL END AS checkoption, ");
    7178             :     else
    7179           0 :         appendPQExpBufferStr(query,
    7180             :                              "c.reloptions, NULL AS checkoption, ");
    7181             : 
    7182         470 :     if (fout->remoteVersion >= 90600)
    7183         470 :         appendPQExpBufferStr(query,
    7184             :                              "am.amname, ");
    7185             :     else
    7186           0 :         appendPQExpBufferStr(query,
    7187             :                              "NULL AS amname, ");
    7188             : 
    7189         470 :     if (fout->remoteVersion >= 90600)
    7190         470 :         appendPQExpBufferStr(query,
    7191             :                              "(d.deptype = 'i') IS TRUE AS is_identity_sequence, ");
    7192             :     else
    7193           0 :         appendPQExpBufferStr(query,
    7194             :                              "false AS is_identity_sequence, ");
    7195             : 
    7196         470 :     if (fout->remoteVersion >= 100000)
    7197         470 :         appendPQExpBufferStr(query,
    7198             :                              "c.relispartition AS ispartition ");
    7199             :     else
    7200           0 :         appendPQExpBufferStr(query,
    7201             :                              "false AS ispartition ");
    7202             : 
    7203             :     /*
    7204             :      * Left join to pg_depend to pick up dependency info linking sequences to
    7205             :      * their owning column, if any (note this dependency is AUTO except for
    7206             :      * identity sequences, where it's INTERNAL). Also join to pg_tablespace to
    7207             :      * collect the spcname.
    7208             :      */
    7209         470 :     appendPQExpBufferStr(query,
    7210             :                          "\nFROM pg_class c\n"
    7211             :                          "LEFT JOIN pg_depend d ON "
    7212             :                          "(c.relkind = " CppAsString2(RELKIND_SEQUENCE) " AND "
    7213             :                          "d.classid = 'pg_class'::regclass AND d.objid = c.oid AND "
    7214             :                          "d.objsubid = 0 AND "
    7215             :                          "d.refclassid = 'pg_class'::regclass AND d.deptype IN ('a', 'i'))\n"
    7216             :                          "LEFT JOIN pg_tablespace tsp ON (tsp.oid = c.reltablespace)\n");
    7217             : 
    7218             :     /*
    7219             :      * In 9.6 and up, left join to pg_am to pick up the amname.
    7220             :      */
    7221         470 :     if (fout->remoteVersion >= 90600)
    7222         470 :         appendPQExpBufferStr(query,
    7223             :                              "LEFT JOIN pg_am am ON (c.relam = am.oid)\n");
    7224             : 
    7225             :     /*
    7226             :      * We purposefully ignore toast OIDs for partitioned tables; the reason is
    7227             :      * that versions 10 and 11 have them, but later versions do not, so
    7228             :      * emitting them causes the upgrade to fail.
    7229             :      */
    7230         470 :     appendPQExpBufferStr(query,
    7231             :                          "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid"
    7232             :                          " AND tc.relkind = " CppAsString2(RELKIND_TOASTVALUE)
    7233             :                          " AND c.relkind <> " CppAsString2(RELKIND_PARTITIONED_TABLE) ")\n");
    7234             : 
    7235             :     /*
    7236             :      * Restrict to interesting relkinds (in particular, not indexes).  Not all
    7237             :      * relkinds are possible in older servers, but it's not worth the trouble
    7238             :      * to emit a version-dependent list.
    7239             :      *
    7240             :      * Composite-type table entries won't be dumped as such, but we have to
    7241             :      * make a DumpableObject for them so that we can track dependencies of the
    7242             :      * composite type (pg_depend entries for columns of the composite type
    7243             :      * link to the pg_class entry not the pg_type entry).
    7244             :      */
    7245         470 :     appendPQExpBufferStr(query,
    7246             :                          "WHERE c.relkind IN ("
    7247             :                          CppAsString2(RELKIND_RELATION) ", "
    7248             :                          CppAsString2(RELKIND_SEQUENCE) ", "
    7249             :                          CppAsString2(RELKIND_VIEW) ", "
    7250             :                          CppAsString2(RELKIND_COMPOSITE_TYPE) ", "
    7251             :                          CppAsString2(RELKIND_MATVIEW) ", "
    7252             :                          CppAsString2(RELKIND_FOREIGN_TABLE) ", "
    7253             :                          CppAsString2(RELKIND_PARTITIONED_TABLE) ")\n"
    7254             :                          "ORDER BY c.oid");
    7255             : 
    7256         470 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    7257             : 
    7258         470 :     ntups = PQntuples(res);
    7259             : 
    7260         470 :     *numTables = ntups;
    7261             : 
    7262             :     /*
    7263             :      * Extract data from result and lock dumpable tables.  We do the locking
    7264             :      * before anything else, to minimize the window wherein a table could
    7265             :      * disappear under us.
    7266             :      *
    7267             :      * Note that we have to save info about all tables here, even when dumping
    7268             :      * only one, because we don't yet know which tables might be inheritance
    7269             :      * ancestors of the target table.
    7270             :      */
    7271         470 :     tblinfo = (TableInfo *) pg_malloc0(ntups * sizeof(TableInfo));
    7272             : 
    7273         470 :     i_reltableoid = PQfnumber(res, "tableoid");
    7274         470 :     i_reloid = PQfnumber(res, "oid");
    7275         470 :     i_relname = PQfnumber(res, "relname");
    7276         470 :     i_relnamespace = PQfnumber(res, "relnamespace");
    7277         470 :     i_relkind = PQfnumber(res, "relkind");
    7278         470 :     i_reltype = PQfnumber(res, "reltype");
    7279         470 :     i_relowner = PQfnumber(res, "relowner");
    7280         470 :     i_relchecks = PQfnumber(res, "relchecks");
    7281         470 :     i_relhasindex = PQfnumber(res, "relhasindex");
    7282         470 :     i_relhasrules = PQfnumber(res, "relhasrules");
    7283         470 :     i_relpages = PQfnumber(res, "relpages");
    7284         470 :     i_reltuples = PQfnumber(res, "reltuples");
    7285         470 :     i_relallvisible = PQfnumber(res, "relallvisible");
    7286         470 :     i_relallfrozen = PQfnumber(res, "relallfrozen");
    7287         470 :     i_toastpages = PQfnumber(res, "toastpages");
    7288         470 :     i_owning_tab = PQfnumber(res, "owning_tab");
    7289         470 :     i_owning_col = PQfnumber(res, "owning_col");
    7290         470 :     i_reltablespace = PQfnumber(res, "reltablespace");
    7291         470 :     i_relhasoids = PQfnumber(res, "relhasoids");
    7292         470 :     i_relhastriggers = PQfnumber(res, "relhastriggers");
    7293         470 :     i_relpersistence = PQfnumber(res, "relpersistence");
    7294         470 :     i_relispopulated = PQfnumber(res, "relispopulated");
    7295         470 :     i_relreplident = PQfnumber(res, "relreplident");
    7296         470 :     i_relrowsec = PQfnumber(res, "relrowsecurity");
    7297         470 :     i_relforcerowsec = PQfnumber(res, "relforcerowsecurity");
    7298         470 :     i_relfrozenxid = PQfnumber(res, "relfrozenxid");
    7299         470 :     i_toastfrozenxid = PQfnumber(res, "tfrozenxid");
    7300         470 :     i_toastoid = PQfnumber(res, "toid");
    7301         470 :     i_relminmxid = PQfnumber(res, "relminmxid");
    7302         470 :     i_toastminmxid = PQfnumber(res, "tminmxid");
    7303         470 :     i_reloptions = PQfnumber(res, "reloptions");
    7304         470 :     i_checkoption = PQfnumber(res, "checkoption");
    7305         470 :     i_toastreloptions = PQfnumber(res, "toast_reloptions");
    7306         470 :     i_reloftype = PQfnumber(res, "reloftype");
    7307         470 :     i_foreignserver = PQfnumber(res, "foreignserver");
    7308         470 :     i_amname = PQfnumber(res, "amname");
    7309         470 :     i_is_identity_sequence = PQfnumber(res, "is_identity_sequence");
    7310         470 :     i_relacl = PQfnumber(res, "relacl");
    7311         470 :     i_acldefault = PQfnumber(res, "acldefault");
    7312         470 :     i_ispartition = PQfnumber(res, "ispartition");
    7313             : 
    7314         470 :     if (dopt->lockWaitTimeout)
    7315             :     {
    7316             :         /*
    7317             :          * Arrange to fail instead of waiting forever for a table lock.
    7318             :          *
    7319             :          * NB: this coding assumes that the only queries issued within the
    7320             :          * following loop are LOCK TABLEs; else the timeout may be undesirably
    7321             :          * applied to other things too.
    7322             :          */
    7323           4 :         resetPQExpBuffer(query);
    7324           4 :         appendPQExpBufferStr(query, "SET statement_timeout = ");
    7325           4 :         appendStringLiteralConn(query, dopt->lockWaitTimeout, GetConnection(fout));
    7326           4 :         ExecuteSqlStatement(fout, query->data);
    7327             :     }
    7328             : 
    7329         470 :     resetPQExpBuffer(query);
    7330             : 
    7331      124800 :     for (i = 0; i < ntups; i++)
    7332             :     {
    7333      124330 :         int32       relallvisible = atoi(PQgetvalue(res, i, i_relallvisible));
    7334      124330 :         int32       relallfrozen = atoi(PQgetvalue(res, i, i_relallfrozen));
    7335             : 
    7336      124330 :         tblinfo[i].dobj.objType = DO_TABLE;
    7337      124330 :         tblinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_reltableoid));
    7338      124330 :         tblinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_reloid));
    7339      124330 :         AssignDumpId(&tblinfo[i].dobj);
    7340      124330 :         tblinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_relname));
    7341      248660 :         tblinfo[i].dobj.namespace =
    7342      124330 :             findNamespace(atooid(PQgetvalue(res, i, i_relnamespace)));
    7343      124330 :         tblinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_relacl));
    7344      124330 :         tblinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
    7345      124330 :         tblinfo[i].dacl.privtype = 0;
    7346      124330 :         tblinfo[i].dacl.initprivs = NULL;
    7347      124330 :         tblinfo[i].relkind = *(PQgetvalue(res, i, i_relkind));
    7348      124330 :         tblinfo[i].reltype = atooid(PQgetvalue(res, i, i_reltype));
    7349      124330 :         tblinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_relowner));
    7350      124330 :         tblinfo[i].ncheck = atoi(PQgetvalue(res, i, i_relchecks));
    7351      124330 :         tblinfo[i].hasindex = (strcmp(PQgetvalue(res, i, i_relhasindex), "t") == 0);
    7352      124330 :         tblinfo[i].hasrules = (strcmp(PQgetvalue(res, i, i_relhasrules), "t") == 0);
    7353      124330 :         tblinfo[i].relpages = atoi(PQgetvalue(res, i, i_relpages));
    7354      124330 :         if (PQgetisnull(res, i, i_toastpages))
    7355       99272 :             tblinfo[i].toastpages = 0;
    7356             :         else
    7357       25058 :             tblinfo[i].toastpages = atoi(PQgetvalue(res, i, i_toastpages));
    7358      124330 :         if (PQgetisnull(res, i, i_owning_tab))
    7359             :         {
    7360      123260 :             tblinfo[i].owning_tab = InvalidOid;
    7361      123260 :             tblinfo[i].owning_col = 0;
    7362             :         }
    7363             :         else
    7364             :         {
    7365        1070 :             tblinfo[i].owning_tab = atooid(PQgetvalue(res, i, i_owning_tab));
    7366        1070 :             tblinfo[i].owning_col = atoi(PQgetvalue(res, i, i_owning_col));
    7367             :         }
    7368      124330 :         tblinfo[i].reltablespace = pg_strdup(PQgetvalue(res, i, i_reltablespace));
    7369      124330 :         tblinfo[i].hasoids = (strcmp(PQgetvalue(res, i, i_relhasoids), "t") == 0);
    7370      124330 :         tblinfo[i].hastriggers = (strcmp(PQgetvalue(res, i, i_relhastriggers), "t") == 0);
    7371      124330 :         tblinfo[i].relpersistence = *(PQgetvalue(res, i, i_relpersistence));
    7372      124330 :         tblinfo[i].relispopulated = (strcmp(PQgetvalue(res, i, i_relispopulated), "t") == 0);
    7373      124330 :         tblinfo[i].relreplident = *(PQgetvalue(res, i, i_relreplident));
    7374      124330 :         tblinfo[i].rowsec = (strcmp(PQgetvalue(res, i, i_relrowsec), "t") == 0);
    7375      124330 :         tblinfo[i].forcerowsec = (strcmp(PQgetvalue(res, i, i_relforcerowsec), "t") == 0);
    7376      124330 :         tblinfo[i].frozenxid = atooid(PQgetvalue(res, i, i_relfrozenxid));
    7377      124330 :         tblinfo[i].toast_frozenxid = atooid(PQgetvalue(res, i, i_toastfrozenxid));
    7378      124330 :         tblinfo[i].toast_oid = atooid(PQgetvalue(res, i, i_toastoid));
    7379      124330 :         tblinfo[i].minmxid = atooid(PQgetvalue(res, i, i_relminmxid));
    7380      124330 :         tblinfo[i].toast_minmxid = atooid(PQgetvalue(res, i, i_toastminmxid));
    7381      124330 :         tblinfo[i].reloptions = pg_strdup(PQgetvalue(res, i, i_reloptions));
    7382      124330 :         if (PQgetisnull(res, i, i_checkoption))
    7383      124230 :             tblinfo[i].checkoption = NULL;
    7384             :         else
    7385         100 :             tblinfo[i].checkoption = pg_strdup(PQgetvalue(res, i, i_checkoption));
    7386      124330 :         tblinfo[i].toast_reloptions = pg_strdup(PQgetvalue(res, i, i_toastreloptions));
    7387      124330 :         tblinfo[i].reloftype = atooid(PQgetvalue(res, i, i_reloftype));
    7388      124330 :         tblinfo[i].foreign_server = atooid(PQgetvalue(res, i, i_foreignserver));
    7389      124330 :         if (PQgetisnull(res, i, i_amname))
    7390       73904 :             tblinfo[i].amname = NULL;
    7391             :         else
    7392       50426 :             tblinfo[i].amname = pg_strdup(PQgetvalue(res, i, i_amname));
    7393      124330 :         tblinfo[i].is_identity_sequence = (strcmp(PQgetvalue(res, i, i_is_identity_sequence), "t") == 0);
    7394      124330 :         tblinfo[i].ispartition = (strcmp(PQgetvalue(res, i, i_ispartition), "t") == 0);
    7395             : 
    7396             :         /* other fields were zeroed above */
    7397             : 
    7398             :         /*
    7399             :          * Decide whether we want to dump this table.
    7400             :          */
    7401      124330 :         if (tblinfo[i].relkind == RELKIND_COMPOSITE_TYPE)
    7402         470 :             tblinfo[i].dobj.dump = DUMP_COMPONENT_NONE;
    7403             :         else
    7404      123860 :             selectDumpableTable(&tblinfo[i], fout);
    7405             : 
    7406             :         /*
    7407             :          * Now, consider the table "interesting" if we need to dump its
    7408             :          * definition, data or its statistics.  Later on, we'll skip a lot of
    7409             :          * data collection for uninteresting tables.
    7410             :          *
    7411             :          * Note: the "interesting" flag will also be set by flagInhTables for
    7412             :          * parents of interesting tables, so that we collect necessary
    7413             :          * inheritance info even when the parents are not themselves being
    7414             :          * dumped.  This is the main reason why we need an "interesting" flag
    7415             :          * that's separate from the components-to-dump bitmask.
    7416             :          */
    7417      124330 :         tblinfo[i].interesting = (tblinfo[i].dobj.dump &
    7418             :                                   (DUMP_COMPONENT_DEFINITION |
    7419             :                                    DUMP_COMPONENT_DATA |
    7420      124330 :                                    DUMP_COMPONENT_STATISTICS)) != 0;
    7421             : 
    7422      124330 :         tblinfo[i].dummy_view = false;  /* might get set during sort */
    7423      124330 :         tblinfo[i].postponed_def = false;   /* might get set during sort */
    7424             : 
    7425             :         /* Tables have data */
    7426      124330 :         tblinfo[i].dobj.components |= DUMP_COMPONENT_DATA;
    7427             : 
    7428             :         /* Mark whether table has an ACL */
    7429      124330 :         if (!PQgetisnull(res, i, i_relacl))
    7430       98556 :             tblinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
    7431      124330 :         tblinfo[i].hascolumnACLs = false;   /* may get set later */
    7432             : 
    7433             :         /* Add statistics */
    7434      124330 :         if (tblinfo[i].interesting)
    7435             :         {
    7436             :             RelStatsInfo *stats;
    7437             : 
    7438       38960 :             stats = getRelationStatistics(fout, &tblinfo[i].dobj,
    7439       19480 :                                           tblinfo[i].relpages,
    7440             :                                           PQgetvalue(res, i, i_reltuples),
    7441             :                                           relallvisible, relallfrozen,
    7442       19480 :                                           tblinfo[i].relkind, NULL, 0);
    7443       19480 :             if (tblinfo[i].relkind == RELKIND_MATVIEW)
    7444         988 :                 tblinfo[i].stats = stats;
    7445             :         }
    7446             : 
    7447             :         /*
    7448             :          * Read-lock target tables to make sure they aren't DROPPED or altered
    7449             :          * in schema before we get around to dumping them.
    7450             :          *
    7451             :          * Note that we don't explicitly lock parents of the target tables; we
    7452             :          * assume our lock on the child is enough to prevent schema
    7453             :          * alterations to parent tables.
    7454             :          *
    7455             :          * NOTE: it'd be kinda nice to lock other relations too, not only
    7456             :          * plain or partitioned tables, but the backend doesn't presently
    7457             :          * allow that.
    7458             :          *
    7459             :          * We only need to lock the table for certain components; see
    7460             :          * pg_dump.h
    7461             :          */
    7462      124330 :         if ((tblinfo[i].dobj.dump & DUMP_COMPONENTS_REQUIRING_LOCK) &&
    7463       19480 :             (tblinfo[i].relkind == RELKIND_RELATION ||
    7464        5272 :              tblinfo[i].relkind == RELKIND_PARTITIONED_TABLE))
    7465             :         {
    7466             :             /*
    7467             :              * Tables are locked in batches.  When dumping from a remote
    7468             :              * server this can save a significant amount of time by reducing
    7469             :              * the number of round trips.
    7470             :              */
    7471       15866 :             if (query->len == 0)
    7472         316 :                 appendPQExpBuffer(query, "LOCK TABLE %s",
    7473         316 :                                   fmtQualifiedDumpable(&tblinfo[i]));
    7474             :             else
    7475             :             {
    7476       15550 :                 appendPQExpBuffer(query, ", %s",
    7477       15550 :                                   fmtQualifiedDumpable(&tblinfo[i]));
    7478             : 
    7479             :                 /* Arbitrarily end a batch when query length reaches 100K. */
    7480       15550 :                 if (query->len >= 100000)
    7481             :                 {
    7482             :                     /* Lock another batch of tables. */
    7483           0 :                     appendPQExpBufferStr(query, " IN ACCESS SHARE MODE");
    7484           0 :                     ExecuteSqlStatement(fout, query->data);
    7485           0 :                     resetPQExpBuffer(query);
    7486             :                 }
    7487             :             }
    7488             :         }
    7489             :     }
    7490             : 
    7491         470 :     if (query->len != 0)
    7492             :     {
    7493             :         /* Lock the tables in the last batch. */
    7494         316 :         appendPQExpBufferStr(query, " IN ACCESS SHARE MODE");
    7495         316 :         ExecuteSqlStatement(fout, query->data);
    7496             :     }
    7497             : 
    7498         468 :     if (dopt->lockWaitTimeout)
    7499             :     {
    7500           4 :         ExecuteSqlStatement(fout, "SET statement_timeout = 0");
    7501             :     }
    7502             : 
    7503         468 :     PQclear(res);
    7504             : 
    7505         468 :     destroyPQExpBuffer(query);
    7506             : 
    7507         468 :     return tblinfo;
    7508             : }
    7509             : 
    7510             : /*
    7511             :  * getOwnedSeqs
    7512             :  *    identify owned sequences and mark them as dumpable if owning table is
    7513             :  *
    7514             :  * We used to do this in getTables(), but it's better to do it after the
    7515             :  * index used by findTableByOid() has been set up.
    7516             :  */
    7517             : void
    7518         468 : getOwnedSeqs(Archive *fout, TableInfo tblinfo[], int numTables)
    7519             : {
    7520             :     int         i;
    7521             : 
    7522             :     /*
    7523             :      * Force sequences that are "owned" by table columns to be dumped whenever
    7524             :      * their owning table is being dumped.
    7525             :      */
    7526      124260 :     for (i = 0; i < numTables; i++)
    7527             :     {
    7528      123792 :         TableInfo  *seqinfo = &tblinfo[i];
    7529             :         TableInfo  *owning_tab;
    7530             : 
    7531      123792 :         if (!OidIsValid(seqinfo->owning_tab))
    7532      122728 :             continue;           /* not an owned sequence */
    7533             : 
    7534        1064 :         owning_tab = findTableByOid(seqinfo->owning_tab);
    7535        1064 :         if (owning_tab == NULL)
    7536           0 :             pg_fatal("failed sanity check, parent table with OID %u of sequence with OID %u not found",
    7537             :                      seqinfo->owning_tab, seqinfo->dobj.catId.oid);
    7538             : 
    7539             :         /*
    7540             :          * For an identity sequence, dump exactly the same components for the
    7541             :          * sequence as for the owning table.  This is important because we
    7542             :          * treat the identity sequence as an integral part of the table.  For
    7543             :          * example, there is not any DDL command that allows creation of such
    7544             :          * a sequence independently of the table.
    7545             :          *
    7546             :          * For other owned sequences such as serial sequences, we need to dump
    7547             :          * the components that are being dumped for the table and any
    7548             :          * components that the sequence is explicitly marked with.
    7549             :          *
    7550             :          * We can't simply use the set of components which are being dumped
    7551             :          * for the table as the table might be in an extension (and only the
    7552             :          * non-extension components, eg: ACLs if changed, security labels, and
    7553             :          * policies, are being dumped) while the sequence is not (and
    7554             :          * therefore the definition and other components should also be
    7555             :          * dumped).
    7556             :          *
    7557             :          * If the sequence is part of the extension then it should be properly
    7558             :          * marked by checkExtensionMembership() and this will be a no-op as
    7559             :          * the table will be equivalently marked.
    7560             :          */
    7561        1064 :         if (seqinfo->is_identity_sequence)
    7562         538 :             seqinfo->dobj.dump = owning_tab->dobj.dump;
    7563             :         else
    7564         526 :             seqinfo->dobj.dump |= owning_tab->dobj.dump;
    7565             : 
    7566             :         /* Make sure that necessary data is available if we're dumping it */
    7567        1064 :         if (seqinfo->dobj.dump != DUMP_COMPONENT_NONE)
    7568             :         {
    7569         872 :             seqinfo->interesting = true;
    7570         872 :             owning_tab->interesting = true;
    7571             :         }
    7572             :     }
    7573         468 : }
    7574             : 
    7575             : /*
    7576             :  * getInherits
    7577             :  *    read all the inheritance information
    7578             :  * from the system catalogs return them in the InhInfo* structure
    7579             :  *
    7580             :  * numInherits is set to the number of pairs read in
    7581             :  */
    7582             : InhInfo *
    7583         468 : getInherits(Archive *fout, int *numInherits)
    7584             : {
    7585             :     PGresult   *res;
    7586             :     int         ntups;
    7587             :     int         i;
    7588         468 :     PQExpBuffer query = createPQExpBuffer();
    7589             :     InhInfo    *inhinfo;
    7590             : 
    7591             :     int         i_inhrelid;
    7592             :     int         i_inhparent;
    7593             : 
    7594             :     /* find all the inheritance information */
    7595         468 :     appendPQExpBufferStr(query, "SELECT inhrelid, inhparent FROM pg_inherits");
    7596             : 
    7597         468 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    7598             : 
    7599         468 :     ntups = PQntuples(res);
    7600             : 
    7601         468 :     *numInherits = ntups;
    7602             : 
    7603         468 :     inhinfo = (InhInfo *) pg_malloc(ntups * sizeof(InhInfo));
    7604             : 
    7605         468 :     i_inhrelid = PQfnumber(res, "inhrelid");
    7606         468 :     i_inhparent = PQfnumber(res, "inhparent");
    7607             : 
    7608        9106 :     for (i = 0; i < ntups; i++)
    7609             :     {
    7610        8638 :         inhinfo[i].inhrelid = atooid(PQgetvalue(res, i, i_inhrelid));
    7611        8638 :         inhinfo[i].inhparent = atooid(PQgetvalue(res, i, i_inhparent));
    7612             :     }
    7613             : 
    7614         468 :     PQclear(res);
    7615             : 
    7616         468 :     destroyPQExpBuffer(query);
    7617             : 
    7618         468 :     return inhinfo;
    7619             : }
    7620             : 
    7621             : /*
    7622             :  * getPartitioningInfo
    7623             :  *    get information about partitioning
    7624             :  *
    7625             :  * For the most part, we only collect partitioning info about tables we
    7626             :  * intend to dump.  However, this function has to consider all partitioned
    7627             :  * tables in the database, because we need to know about parents of partitions
    7628             :  * we are going to dump even if the parents themselves won't be dumped.
    7629             :  *
    7630             :  * Specifically, what we need to know is whether each partitioned table
    7631             :  * has an "unsafe" partitioning scheme that requires us to force
    7632             :  * load-via-partition-root mode for its children.  Currently the only case
    7633             :  * for which we force that is hash partitioning on enum columns, since the
    7634             :  * hash codes depend on enum value OIDs which won't be replicated across
    7635             :  * dump-and-reload.  There are other cases in which load-via-partition-root
    7636             :  * might be necessary, but we expect users to cope with them.
    7637             :  */
    7638             : void
    7639         468 : getPartitioningInfo(Archive *fout)
    7640             : {
    7641             :     PQExpBuffer query;
    7642             :     PGresult   *res;
    7643             :     int         ntups;
    7644             : 
    7645             :     /* hash partitioning didn't exist before v11 */
    7646         468 :     if (fout->remoteVersion < 110000)
    7647           0 :         return;
    7648             :     /* needn't bother if not dumping data */
    7649         468 :     if (!fout->dopt->dumpData)
    7650          72 :         return;
    7651             : 
    7652         396 :     query = createPQExpBuffer();
    7653             : 
    7654             :     /*
    7655             :      * Unsafe partitioning schemes are exactly those for which hash enum_ops
    7656             :      * appears among the partition opclasses.  We needn't check partstrat.
    7657             :      *
    7658             :      * Note that this query may well retrieve info about tables we aren't
    7659             :      * going to dump and hence have no lock on.  That's okay since we need not
    7660             :      * invoke any unsafe server-side functions.
    7661             :      */
    7662         396 :     appendPQExpBufferStr(query,
    7663             :                          "SELECT partrelid FROM pg_partitioned_table WHERE\n"
    7664             :                          "(SELECT c.oid FROM pg_opclass c JOIN pg_am a "
    7665             :                          "ON c.opcmethod = a.oid\n"
    7666             :                          "WHERE opcname = 'enum_ops' "
    7667             :                          "AND opcnamespace = 'pg_catalog'::regnamespace "
    7668             :                          "AND amname = 'hash') = ANY(partclass)");
    7669             : 
    7670         396 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    7671             : 
    7672         396 :     ntups = PQntuples(res);
    7673             : 
    7674         400 :     for (int i = 0; i < ntups; i++)
    7675             :     {
    7676           4 :         Oid         tabrelid = atooid(PQgetvalue(res, i, 0));
    7677             :         TableInfo  *tbinfo;
    7678             : 
    7679           4 :         tbinfo = findTableByOid(tabrelid);
    7680           4 :         if (tbinfo == NULL)
    7681           0 :             pg_fatal("failed sanity check, table OID %u appearing in pg_partitioned_table not found",
    7682             :                      tabrelid);
    7683           4 :         tbinfo->unsafe_partitions = true;
    7684             :     }
    7685             : 
    7686         396 :     PQclear(res);
    7687             : 
    7688         396 :     destroyPQExpBuffer(query);
    7689             : }
    7690             : 
    7691             : /*
    7692             :  * getIndexes
    7693             :  *    get information about every index on a dumpable table
    7694             :  *
    7695             :  * Note: index data is not returned directly to the caller, but it
    7696             :  * does get entered into the DumpableObject tables.
    7697             :  */
    7698             : void
    7699         468 : getIndexes(Archive *fout, TableInfo tblinfo[], int numTables)
    7700             : {
    7701         468 :     PQExpBuffer query = createPQExpBuffer();
    7702         468 :     PQExpBuffer tbloids = createPQExpBuffer();
    7703             :     PGresult   *res;
    7704             :     int         ntups;
    7705             :     int         curtblindx;
    7706             :     IndxInfo   *indxinfo;
    7707             :     int         i_tableoid,
    7708             :                 i_oid,
    7709             :                 i_indrelid,
    7710             :                 i_indexname,
    7711             :                 i_relpages,
    7712             :                 i_reltuples,
    7713             :                 i_relallvisible,
    7714             :                 i_relallfrozen,
    7715             :                 i_parentidx,
    7716             :                 i_indexdef,
    7717             :                 i_indnkeyatts,
    7718             :                 i_indnatts,
    7719             :                 i_indkey,
    7720             :                 i_indisclustered,
    7721             :                 i_indisreplident,
    7722             :                 i_indnullsnotdistinct,
    7723             :                 i_contype,
    7724             :                 i_conname,
    7725             :                 i_condeferrable,
    7726             :                 i_condeferred,
    7727             :                 i_conperiod,
    7728             :                 i_contableoid,
    7729             :                 i_conoid,
    7730             :                 i_condef,
    7731             :                 i_indattnames,
    7732             :                 i_tablespace,
    7733             :                 i_indreloptions,
    7734             :                 i_indstatcols,
    7735             :                 i_indstatvals;
    7736             : 
    7737             :     /*
    7738             :      * We want to perform just one query against pg_index.  However, we
    7739             :      * mustn't try to select every row of the catalog and then sort it out on
    7740             :      * the client side, because some of the server-side functions we need
    7741             :      * would be unsafe to apply to tables we don't have lock on.  Hence, we
    7742             :      * build an array of the OIDs of tables we care about (and now have lock
    7743             :      * on!), and use a WHERE clause to constrain which rows are selected.
    7744             :      */
    7745         468 :     appendPQExpBufferChar(tbloids, '{');
    7746      124260 :     for (int i = 0; i < numTables; i++)
    7747             :     {
    7748      123792 :         TableInfo  *tbinfo = &tblinfo[i];
    7749             : 
    7750      123792 :         if (!tbinfo->hasindex)
    7751       87526 :             continue;
    7752             : 
    7753             :         /*
    7754             :          * We can ignore indexes of uninteresting tables.
    7755             :          */
    7756       36266 :         if (!tbinfo->interesting)
    7757       30722 :             continue;
    7758             : 
    7759             :         /* OK, we need info for this table */
    7760        5544 :         if (tbloids->len > 1) /* do we have more than the '{'? */
    7761        5374 :             appendPQExpBufferChar(tbloids, ',');
    7762        5544 :         appendPQExpBuffer(tbloids, "%u", tbinfo->dobj.catId.oid);
    7763             :     }
    7764         468 :     appendPQExpBufferChar(tbloids, '}');
    7765             : 
    7766         468 :     appendPQExpBufferStr(query,
    7767             :                          "SELECT t.tableoid, t.oid, i.indrelid, "
    7768             :                          "t.relname AS indexname, "
    7769             :                          "t.relpages, t.reltuples, t.relallvisible, ");
    7770             : 
    7771         468 :     if (fout->remoteVersion >= 180000)
    7772         468 :         appendPQExpBufferStr(query, "t.relallfrozen, ");
    7773             :     else
    7774           0 :         appendPQExpBufferStr(query, "0 AS relallfrozen, ");
    7775             : 
    7776         468 :     appendPQExpBufferStr(query,
    7777             :                          "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
    7778             :                          "i.indkey, i.indisclustered, "
    7779             :                          "c.contype, c.conname, "
    7780             :                          "c.condeferrable, c.condeferred, "
    7781             :                          "c.tableoid AS contableoid, "
    7782             :                          "c.oid AS conoid, "
    7783             :                          "pg_catalog.pg_get_constraintdef(c.oid, false) AS condef, "
    7784             :                          "CASE WHEN i.indexprs IS NOT NULL THEN "
    7785             :                          "(SELECT pg_catalog.array_agg(attname ORDER BY attnum)"
    7786             :                          "  FROM pg_catalog.pg_attribute "
    7787             :                          "  WHERE attrelid = i.indexrelid) "
    7788             :                          "ELSE NULL END AS indattnames, "
    7789             :                          "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
    7790             :                          "t.reloptions AS indreloptions, ");
    7791             : 
    7792             : 
    7793         468 :     if (fout->remoteVersion >= 90400)
    7794         468 :         appendPQExpBufferStr(query,
    7795             :                              "i.indisreplident, ");
    7796             :     else
    7797           0 :         appendPQExpBufferStr(query,
    7798             :                              "false AS indisreplident, ");
    7799             : 
    7800         468 :     if (fout->remoteVersion >= 110000)
    7801         468 :         appendPQExpBufferStr(query,
    7802             :                              "inh.inhparent AS parentidx, "
    7803             :                              "i.indnkeyatts AS indnkeyatts, "
    7804             :                              "i.indnatts AS indnatts, "
    7805             :                              "(SELECT pg_catalog.array_agg(attnum ORDER BY attnum) "
    7806             :                              "  FROM pg_catalog.pg_attribute "
    7807             :                              "  WHERE attrelid = i.indexrelid AND "
    7808             :                              "    attstattarget >= 0) AS indstatcols, "
    7809             :                              "(SELECT pg_catalog.array_agg(attstattarget ORDER BY attnum) "
    7810             :                              "  FROM pg_catalog.pg_attribute "
    7811             :                              "  WHERE attrelid = i.indexrelid AND "
    7812             :                              "    attstattarget >= 0) AS indstatvals, ");
    7813             :     else
    7814           0 :         appendPQExpBufferStr(query,
    7815             :                              "0 AS parentidx, "
    7816             :                              "i.indnatts AS indnkeyatts, "
    7817             :                              "i.indnatts AS indnatts, "
    7818             :                              "'' AS indstatcols, "
    7819             :                              "'' AS indstatvals, ");
    7820             : 
    7821         468 :     if (fout->remoteVersion >= 150000)
    7822         468 :         appendPQExpBufferStr(query,
    7823             :                              "i.indnullsnotdistinct, ");
    7824             :     else
    7825           0 :         appendPQExpBufferStr(query,
    7826             :                              "false AS indnullsnotdistinct, ");
    7827             : 
    7828         468 :     if (fout->remoteVersion >= 180000)
    7829         468 :         appendPQExpBufferStr(query,
    7830             :                              "c.conperiod ");
    7831             :     else
    7832           0 :         appendPQExpBufferStr(query,
    7833             :                              "NULL AS conperiod ");
    7834             : 
    7835             :     /*
    7836             :      * The point of the messy-looking outer join is to find a constraint that
    7837             :      * is related by an internal dependency link to the index. If we find one,
    7838             :      * create a CONSTRAINT entry linked to the INDEX entry.  We assume an
    7839             :      * index won't have more than one internal dependency.
    7840             :      *
    7841             :      * Note: the check on conrelid is redundant, but useful because that
    7842             :      * column is indexed while conindid is not.
    7843             :      */
    7844         468 :     if (fout->remoteVersion >= 110000)
    7845             :     {
    7846         468 :         appendPQExpBuffer(query,
    7847             :                           "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
    7848             :                           "JOIN pg_catalog.pg_index i ON (src.tbloid = i.indrelid) "
    7849             :                           "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
    7850             :                           "JOIN pg_catalog.pg_class t2 ON (t2.oid = i.indrelid) "
    7851             :                           "LEFT JOIN pg_catalog.pg_constraint c "
    7852             :                           "ON (i.indrelid = c.conrelid AND "
    7853             :                           "i.indexrelid = c.conindid AND "
    7854             :                           "c.contype IN ('p','u','x')) "
    7855             :                           "LEFT JOIN pg_catalog.pg_inherits inh "
    7856             :                           "ON (inh.inhrelid = indexrelid) "
    7857             :                           "WHERE (i.indisvalid OR t2.relkind = 'p') "
    7858             :                           "AND i.indisready "
    7859             :                           "ORDER BY i.indrelid, indexname",
    7860             :                           tbloids->data);
    7861             :     }
    7862             :     else
    7863             :     {
    7864             :         /*
    7865             :          * the test on indisready is necessary in 9.2, and harmless in
    7866             :          * earlier/later versions
    7867             :          */
    7868           0 :         appendPQExpBuffer(query,
    7869             :                           "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
    7870             :                           "JOIN pg_catalog.pg_index i ON (src.tbloid = i.indrelid) "
    7871             :                           "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
    7872             :                           "LEFT JOIN pg_catalog.pg_constraint c "
    7873             :                           "ON (i.indrelid = c.conrelid AND "
    7874             :                           "i.indexrelid = c.conindid AND "
    7875             :                           "c.contype IN ('p','u','x')) "
    7876             :                           "WHERE i.indisvalid AND i.indisready "
    7877             :                           "ORDER BY i.indrelid, indexname",
    7878             :                           tbloids->data);
    7879             :     }
    7880             : 
    7881         468 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    7882             : 
    7883         468 :     ntups = PQntuples(res);
    7884             : 
    7885         468 :     i_tableoid = PQfnumber(res, "tableoid");
    7886         468 :     i_oid = PQfnumber(res, "oid");
    7887         468 :     i_indrelid = PQfnumber(res, "indrelid");
    7888         468 :     i_indexname = PQfnumber(res, "indexname");
    7889         468 :     i_relpages = PQfnumber(res, "relpages");
    7890         468 :     i_reltuples = PQfnumber(res, "reltuples");
    7891         468 :     i_relallvisible = PQfnumber(res, "relallvisible");
    7892         468 :     i_relallfrozen = PQfnumber(res, "relallfrozen");
    7893         468 :     i_parentidx = PQfnumber(res, "parentidx");
    7894         468 :     i_indexdef = PQfnumber(res, "indexdef");
    7895         468 :     i_indnkeyatts = PQfnumber(res, "indnkeyatts");
    7896         468 :     i_indnatts = PQfnumber(res, "indnatts");
    7897         468 :     i_indkey = PQfnumber(res, "indkey");
    7898         468 :     i_indisclustered = PQfnumber(res, "indisclustered");
    7899         468 :     i_indisreplident = PQfnumber(res, "indisreplident");
    7900         468 :     i_indnullsnotdistinct = PQfnumber(res, "indnullsnotdistinct");
    7901         468 :     i_contype = PQfnumber(res, "contype");
    7902         468 :     i_conname = PQfnumber(res, "conname");
    7903         468 :     i_condeferrable = PQfnumber(res, "condeferrable");
    7904         468 :     i_condeferred = PQfnumber(res, "condeferred");
    7905         468 :     i_conperiod = PQfnumber(res, "conperiod");
    7906         468 :     i_contableoid = PQfnumber(res, "contableoid");
    7907         468 :     i_conoid = PQfnumber(res, "conoid");
    7908         468 :     i_condef = PQfnumber(res, "condef");
    7909         468 :     i_indattnames = PQfnumber(res, "indattnames");
    7910         468 :     i_tablespace = PQfnumber(res, "tablespace");
    7911         468 :     i_indreloptions = PQfnumber(res, "indreloptions");
    7912         468 :     i_indstatcols = PQfnumber(res, "indstatcols");
    7913         468 :     i_indstatvals = PQfnumber(res, "indstatvals");
    7914             : 
    7915         468 :     indxinfo = (IndxInfo *) pg_malloc(ntups * sizeof(IndxInfo));
    7916             : 
    7917             :     /*
    7918             :      * Outer loop iterates once per table, not once per row.  Incrementing of
    7919             :      * j is handled by the inner loop.
    7920             :      */
    7921         468 :     curtblindx = -1;
    7922        5956 :     for (int j = 0; j < ntups;)
    7923             :     {
    7924        5488 :         Oid         indrelid = atooid(PQgetvalue(res, j, i_indrelid));
    7925        5488 :         TableInfo  *tbinfo = NULL;
    7926        5488 :         char      **indAttNames = NULL;
    7927        5488 :         int         nindAttNames = 0;
    7928             :         int         numinds;
    7929             : 
    7930             :         /* Count rows for this table */
    7931        7004 :         for (numinds = 1; numinds < ntups - j; numinds++)
    7932        6834 :             if (atooid(PQgetvalue(res, j + numinds, i_indrelid)) != indrelid)
    7933        5318 :                 break;
    7934             : 
    7935             :         /*
    7936             :          * Locate the associated TableInfo; we rely on tblinfo[] being in OID
    7937             :          * order.
    7938             :          */
    7939       54514 :         while (++curtblindx < numTables)
    7940             :         {
    7941       54514 :             tbinfo = &tblinfo[curtblindx];
    7942       54514 :             if (tbinfo->dobj.catId.oid == indrelid)
    7943        5488 :                 break;
    7944             :         }
    7945        5488 :         if (curtblindx >= numTables)
    7946           0 :             pg_fatal("unrecognized table OID %u", indrelid);
    7947             :         /* cross-check that we only got requested tables */
    7948        5488 :         if (!tbinfo->hasindex ||
    7949        5488 :             !tbinfo->interesting)
    7950           0 :             pg_fatal("unexpected index data for table \"%s\"",
    7951             :                      tbinfo->dobj.name);
    7952             : 
    7953             :         /* Save data for this table */
    7954        5488 :         tbinfo->indexes = indxinfo + j;
    7955        5488 :         tbinfo->numIndexes = numinds;
    7956             : 
    7957       12492 :         for (int c = 0; c < numinds; c++, j++)
    7958             :         {
    7959             :             char        contype;
    7960             :             char        indexkind;
    7961             :             RelStatsInfo *relstats;
    7962        7004 :             int32       relpages = atoi(PQgetvalue(res, j, i_relpages));
    7963        7004 :             int32       relallvisible = atoi(PQgetvalue(res, j, i_relallvisible));
    7964        7004 :             int32       relallfrozen = atoi(PQgetvalue(res, j, i_relallfrozen));
    7965             : 
    7966        7004 :             indxinfo[j].dobj.objType = DO_INDEX;
    7967        7004 :             indxinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
    7968        7004 :             indxinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
    7969        7004 :             AssignDumpId(&indxinfo[j].dobj);
    7970        7004 :             indxinfo[j].dobj.dump = tbinfo->dobj.dump;
    7971        7004 :             indxinfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_indexname));
    7972        7004 :             indxinfo[j].dobj.namespace = tbinfo->dobj.namespace;
    7973        7004 :             indxinfo[j].indextable = tbinfo;
    7974        7004 :             indxinfo[j].indexdef = pg_strdup(PQgetvalue(res, j, i_indexdef));
    7975        7004 :             indxinfo[j].indnkeyattrs = atoi(PQgetvalue(res, j, i_indnkeyatts));
    7976        7004 :             indxinfo[j].indnattrs = atoi(PQgetvalue(res, j, i_indnatts));
    7977        7004 :             indxinfo[j].tablespace = pg_strdup(PQgetvalue(res, j, i_tablespace));
    7978        7004 :             indxinfo[j].indreloptions = pg_strdup(PQgetvalue(res, j, i_indreloptions));
    7979        7004 :             indxinfo[j].indstatcols = pg_strdup(PQgetvalue(res, j, i_indstatcols));
    7980        7004 :             indxinfo[j].indstatvals = pg_strdup(PQgetvalue(res, j, i_indstatvals));
    7981        7004 :             indxinfo[j].indkeys = (Oid *) pg_malloc(indxinfo[j].indnattrs * sizeof(Oid));
    7982        7004 :             parseOidArray(PQgetvalue(res, j, i_indkey),
    7983        7004 :                           indxinfo[j].indkeys, indxinfo[j].indnattrs);
    7984        7004 :             indxinfo[j].indisclustered = (PQgetvalue(res, j, i_indisclustered)[0] == 't');
    7985        7004 :             indxinfo[j].indisreplident = (PQgetvalue(res, j, i_indisreplident)[0] == 't');
    7986        7004 :             indxinfo[j].indnullsnotdistinct = (PQgetvalue(res, j, i_indnullsnotdistinct)[0] == 't');
    7987        7004 :             indxinfo[j].parentidx = atooid(PQgetvalue(res, j, i_parentidx));
    7988        7004 :             indxinfo[j].partattaches = (SimplePtrList)
    7989             :             {
    7990             :                 NULL, NULL
    7991             :             };
    7992             : 
    7993        7004 :             if (indxinfo[j].parentidx == 0)
    7994        5524 :                 indexkind = RELKIND_INDEX;
    7995             :             else
    7996        1480 :                 indexkind = RELKIND_PARTITIONED_INDEX;
    7997             : 
    7998        7004 :             if (!PQgetisnull(res, j, i_indattnames))
    7999             :             {
    8000         392 :                 if (!parsePGArray(PQgetvalue(res, j, i_indattnames),
    8001             :                                   &indAttNames, &nindAttNames))
    8002           0 :                     pg_fatal("could not parse %s array", "indattnames");
    8003             :             }
    8004             : 
    8005        7004 :             relstats = getRelationStatistics(fout, &indxinfo[j].dobj, relpages,
    8006             :                                              PQgetvalue(res, j, i_reltuples),
    8007             :                                              relallvisible, relallfrozen, indexkind,
    8008             :                                              indAttNames, nindAttNames);
    8009             : 
    8010        7004 :             contype = *(PQgetvalue(res, j, i_contype));
    8011        7004 :             if (contype == 'p' || contype == 'u' || contype == 'x')
    8012        3896 :             {
    8013             :                 /*
    8014             :                  * If we found a constraint matching the index, create an
    8015             :                  * entry for it.
    8016             :                  */
    8017             :                 ConstraintInfo *constrinfo;
    8018             : 
    8019        3896 :                 constrinfo = (ConstraintInfo *) pg_malloc(sizeof(ConstraintInfo));
    8020        3896 :                 constrinfo->dobj.objType = DO_CONSTRAINT;
    8021        3896 :                 constrinfo->dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_contableoid));
    8022        3896 :                 constrinfo->dobj.catId.oid = atooid(PQgetvalue(res, j, i_conoid));
    8023        3896 :                 AssignDumpId(&constrinfo->dobj);
    8024        3896 :                 constrinfo->dobj.dump = tbinfo->dobj.dump;
    8025        3896 :                 constrinfo->dobj.name = pg_strdup(PQgetvalue(res, j, i_conname));
    8026        3896 :                 constrinfo->dobj.namespace = tbinfo->dobj.namespace;
    8027        3896 :                 constrinfo->contable = tbinfo;
    8028        3896 :                 constrinfo->condomain = NULL;
    8029        3896 :                 constrinfo->contype = contype;
    8030        3896 :                 if (contype == 'x')
    8031          32 :                     constrinfo->condef = pg_strdup(PQgetvalue(res, j, i_condef));
    8032             :                 else
    8033        3864 :                     constrinfo->condef = NULL;
    8034        3896 :                 constrinfo->confrelid = InvalidOid;
    8035        3896 :                 constrinfo->conindex = indxinfo[j].dobj.dumpId;
    8036        3896 :                 constrinfo->condeferrable = *(PQgetvalue(res, j, i_condeferrable)) == 't';
    8037        3896 :                 constrinfo->condeferred = *(PQgetvalue(res, j, i_condeferred)) == 't';
    8038        3896 :                 constrinfo->conperiod = *(PQgetvalue(res, j, i_conperiod)) == 't';
    8039        3896 :                 constrinfo->conislocal = true;
    8040        3896 :                 constrinfo->separate = true;
    8041             : 
    8042        3896 :                 indxinfo[j].indexconstraint = constrinfo->dobj.dumpId;
    8043        3896 :                 if (relstats != NULL)
    8044        1148 :                     addObjectDependency(&relstats->dobj, constrinfo->dobj.dumpId);
    8045             :             }
    8046             :             else
    8047             :             {
    8048             :                 /* Plain secondary index */
    8049        3108 :                 indxinfo[j].indexconstraint = 0;
    8050             :             }
    8051             :         }
    8052             :     }
    8053             : 
    8054         468 :     PQclear(res);
    8055             : 
    8056         468 :     destroyPQExpBuffer(query);
    8057         468 :     destroyPQExpBuffer(tbloids);
    8058         468 : }
    8059             : 
    8060             : /*
    8061             :  * getExtendedStatistics
    8062             :  *    get information about extended-statistics objects.
    8063             :  *
    8064             :  * Note: extended statistics data is not returned directly to the caller, but
    8065             :  * it does get entered into the DumpableObject tables.
    8066             :  */
    8067             : void
    8068         468 : getExtendedStatistics(Archive *fout)
    8069             : {
    8070             :     PQExpBuffer query;
    8071             :     PGresult   *res;
    8072             :     StatsExtInfo *statsextinfo;
    8073             :     int         ntups;
    8074             :     int         i_tableoid;
    8075             :     int         i_oid;
    8076             :     int         i_stxname;
    8077             :     int         i_stxnamespace;
    8078             :     int         i_stxowner;
    8079             :     int         i_stxrelid;
    8080             :     int         i_stattarget;
    8081             :     int         i;
    8082             : 
    8083             :     /* Extended statistics were new in v10 */
    8084         468 :     if (fout->remoteVersion < 100000)
    8085           0 :         return;
    8086             : 
    8087         468 :     query = createPQExpBuffer();
    8088             : 
    8089         468 :     if (fout->remoteVersion < 130000)
    8090           0 :         appendPQExpBufferStr(query, "SELECT tableoid, oid, stxname, "
    8091             :                              "stxnamespace, stxowner, stxrelid, NULL AS stxstattarget "
    8092             :                              "FROM pg_catalog.pg_statistic_ext");
    8093             :     else
    8094         468 :         appendPQExpBufferStr(query, "SELECT tableoid, oid, stxname, "
    8095             :                              "stxnamespace, stxowner, stxrelid, stxstattarget "
    8096             :                              "FROM pg_catalog.pg_statistic_ext");
    8097             : 
    8098         468 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    8099             : 
    8100         468 :     ntups = PQntuples(res);
    8101             : 
    8102         468 :     i_tableoid = PQfnumber(res, "tableoid");
    8103         468 :     i_oid = PQfnumber(res, "oid");
    8104         468 :     i_stxname = PQfnumber(res, "stxname");
    8105         468 :     i_stxnamespace = PQfnumber(res, "stxnamespace");
    8106         468 :     i_stxowner = PQfnumber(res, "stxowner");
    8107         468 :     i_stxrelid = PQfnumber(res, "stxrelid");
    8108         468 :     i_stattarget = PQfnumber(res, "stxstattarget");
    8109             : 
    8110         468 :     statsextinfo = (StatsExtInfo *) pg_malloc(ntups * sizeof(StatsExtInfo));
    8111             : 
    8112         842 :     for (i = 0; i < ntups; i++)
    8113             :     {
    8114         374 :         statsextinfo[i].dobj.objType = DO_STATSEXT;
    8115         374 :         statsextinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    8116         374 :         statsextinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    8117         374 :         AssignDumpId(&statsextinfo[i].dobj);
    8118         374 :         statsextinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_stxname));
    8119         748 :         statsextinfo[i].dobj.namespace =
    8120         374 :             findNamespace(atooid(PQgetvalue(res, i, i_stxnamespace)));
    8121         374 :         statsextinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_stxowner));
    8122         748 :         statsextinfo[i].stattable =
    8123         374 :             findTableByOid(atooid(PQgetvalue(res, i, i_stxrelid)));
    8124         374 :         if (PQgetisnull(res, i, i_stattarget))
    8125         276 :             statsextinfo[i].stattarget = -1;
    8126             :         else
    8127          98 :             statsextinfo[i].stattarget = atoi(PQgetvalue(res, i, i_stattarget));
    8128             : 
    8129             :         /* Decide whether we want to dump it */
    8130         374 :         selectDumpableStatisticsObject(&(statsextinfo[i]), fout);
    8131             :     }
    8132             : 
    8133         468 :     PQclear(res);
    8134         468 :     destroyPQExpBuffer(query);
    8135             : }
    8136             : 
    8137             : /*
    8138             :  * getConstraints
    8139             :  *
    8140             :  * Get info about constraints on dumpable tables.
    8141             :  *
    8142             :  * Currently handles foreign keys only.
    8143             :  * Unique and primary key constraints are handled with indexes,
    8144             :  * while check constraints are processed in getTableAttrs().
    8145             :  */
    8146             : void
    8147         468 : getConstraints(Archive *fout, TableInfo tblinfo[], int numTables)
    8148             : {
    8149         468 :     PQExpBuffer query = createPQExpBuffer();
    8150         468 :     PQExpBuffer tbloids = createPQExpBuffer();
    8151             :     PGresult   *res;
    8152             :     int         ntups;
    8153             :     int         curtblindx;
    8154         468 :     TableInfo  *tbinfo = NULL;
    8155             :     ConstraintInfo *constrinfo;
    8156             :     int         i_contableoid,
    8157             :                 i_conoid,
    8158             :                 i_conrelid,
    8159             :                 i_conname,
    8160             :                 i_confrelid,
    8161             :                 i_conindid,
    8162             :                 i_condef;
    8163             : 
    8164             :     /*
    8165             :      * We want to perform just one query against pg_constraint.  However, we
    8166             :      * mustn't try to select every row of the catalog and then sort it out on
    8167             :      * the client side, because some of the server-side functions we need
    8168             :      * would be unsafe to apply to tables we don't have lock on.  Hence, we
    8169             :      * build an array of the OIDs of tables we care about (and now have lock
    8170             :      * on!), and use a WHERE clause to constrain which rows are selected.
    8171             :      */
    8172         468 :     appendPQExpBufferChar(tbloids, '{');
    8173      124260 :     for (int i = 0; i < numTables; i++)
    8174             :     {
    8175      123792 :         TableInfo  *tinfo = &tblinfo[i];
    8176             : 
    8177      123792 :         if (!(tinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
    8178      104414 :             continue;
    8179             : 
    8180             :         /* OK, we need info for this table */
    8181       19378 :         if (tbloids->len > 1) /* do we have more than the '{'? */
    8182       19060 :             appendPQExpBufferChar(tbloids, ',');
    8183       19378 :         appendPQExpBuffer(tbloids, "%u", tinfo->dobj.catId.oid);
    8184             :     }
    8185         468 :     appendPQExpBufferChar(tbloids, '}');
    8186             : 
    8187         468 :     appendPQExpBufferStr(query,
    8188             :                          "SELECT c.tableoid, c.oid, "
    8189             :                          "conrelid, conname, confrelid, ");
    8190         468 :     if (fout->remoteVersion >= 110000)
    8191         468 :         appendPQExpBufferStr(query, "conindid, ");
    8192             :     else
    8193           0 :         appendPQExpBufferStr(query, "0 AS conindid, ");
    8194         468 :     appendPQExpBuffer(query,
    8195             :                       "pg_catalog.pg_get_constraintdef(c.oid) AS condef\n"
    8196             :                       "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
    8197             :                       "JOIN pg_catalog.pg_constraint c ON (src.tbloid = c.conrelid)\n"
    8198             :                       "WHERE contype = 'f' ",
    8199             :                       tbloids->data);
    8200         468 :     if (fout->remoteVersion >= 110000)
    8201         468 :         appendPQExpBufferStr(query,
    8202             :                              "AND conparentid = 0 ");
    8203         468 :     appendPQExpBufferStr(query,
    8204             :                          "ORDER BY conrelid, conname");
    8205             : 
    8206         468 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    8207             : 
    8208         468 :     ntups = PQntuples(res);
    8209             : 
    8210         468 :     i_contableoid = PQfnumber(res, "tableoid");
    8211         468 :     i_conoid = PQfnumber(res, "oid");
    8212         468 :     i_conrelid = PQfnumber(res, "conrelid");
    8213         468 :     i_conname = PQfnumber(res, "conname");
    8214         468 :     i_confrelid = PQfnumber(res, "confrelid");
    8215         468 :     i_conindid = PQfnumber(res, "conindid");
    8216         468 :     i_condef = PQfnumber(res, "condef");
    8217             : 
    8218         468 :     constrinfo = (ConstraintInfo *) pg_malloc(ntups * sizeof(ConstraintInfo));
    8219             : 
    8220         468 :     curtblindx = -1;
    8221         940 :     for (int j = 0; j < ntups; j++)
    8222             :     {
    8223         472 :         Oid         conrelid = atooid(PQgetvalue(res, j, i_conrelid));
    8224             :         TableInfo  *reftable;
    8225             : 
    8226             :         /*
    8227             :          * Locate the associated TableInfo; we rely on tblinfo[] being in OID
    8228             :          * order.
    8229             :          */
    8230         472 :         if (tbinfo == NULL || tbinfo->dobj.catId.oid != conrelid)
    8231             :         {
    8232       34350 :             while (++curtblindx < numTables)
    8233             :             {
    8234       34350 :                 tbinfo = &tblinfo[curtblindx];
    8235       34350 :                 if (tbinfo->dobj.catId.oid == conrelid)
    8236         440 :                     break;
    8237             :             }
    8238         440 :             if (curtblindx >= numTables)
    8239           0 :                 pg_fatal("unrecognized table OID %u", conrelid);
    8240             :         }
    8241             : 
    8242         472 :         constrinfo[j].dobj.objType = DO_FK_CONSTRAINT;
    8243         472 :         constrinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_contableoid));
    8244         472 :         constrinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_conoid));
    8245         472 :         AssignDumpId(&constrinfo[j].dobj);
    8246         472 :         constrinfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_conname));
    8247         472 :         constrinfo[j].dobj.namespace = tbinfo->dobj.namespace;
    8248         472 :         constrinfo[j].contable = tbinfo;
    8249         472 :         constrinfo[j].condomain = NULL;
    8250         472 :         constrinfo[j].contype = 'f';
    8251         472 :         constrinfo[j].condef = pg_strdup(PQgetvalue(res, j, i_condef));
    8252         472 :         constrinfo[j].confrelid = atooid(PQgetvalue(res, j, i_confrelid));
    8253         472 :         constrinfo[j].conindex = 0;
    8254         472 :         constrinfo[j].condeferrable = false;
    8255         472 :         constrinfo[j].condeferred = false;
    8256         472 :         constrinfo[j].conislocal = true;
    8257         472 :         constrinfo[j].separate = true;
    8258             : 
    8259             :         /*
    8260             :          * Restoring an FK that points to a partitioned table requires that
    8261             :          * all partition indexes have been attached beforehand. Ensure that
    8262             :          * happens by making the constraint depend on each index partition
    8263             :          * attach object.
    8264             :          */
    8265         472 :         reftable = findTableByOid(constrinfo[j].confrelid);
    8266         472 :         if (reftable && reftable->relkind == RELKIND_PARTITIONED_TABLE)
    8267             :         {
    8268          64 :             Oid         indexOid = atooid(PQgetvalue(res, j, i_conindid));
    8269             : 
    8270          64 :             if (indexOid != InvalidOid)
    8271             :             {
    8272          64 :                 for (int k = 0; k < reftable->numIndexes; k++)
    8273             :                 {
    8274             :                     IndxInfo   *refidx;
    8275             : 
    8276             :                     /* not our index? */
    8277          64 :                     if (reftable->indexes[k].dobj.catId.oid != indexOid)
    8278           0 :                         continue;
    8279             : 
    8280          64 :                     refidx = &reftable->indexes[k];
    8281          64 :                     addConstrChildIdxDeps(&constrinfo[j].dobj, refidx);
    8282          64 :                     break;
    8283             :                 }
    8284             :             }
    8285             :         }
    8286             :     }
    8287             : 
    8288         468 :     PQclear(res);
    8289             : 
    8290         468 :     destroyPQExpBuffer(query);
    8291         468 :     destroyPQExpBuffer(tbloids);
    8292         468 : }
    8293             : 
    8294             : /*
    8295             :  * addConstrChildIdxDeps
    8296             :  *
    8297             :  * Recursive subroutine for getConstraints
    8298             :  *
    8299             :  * Given an object representing a foreign key constraint and an index on the
    8300             :  * partitioned table it references, mark the constraint object as dependent
    8301             :  * on the DO_INDEX_ATTACH object of each index partition, recursively
    8302             :  * drilling down to their partitions if any.  This ensures that the FK is not
    8303             :  * restored until the index is fully marked valid.
    8304             :  */
    8305             : static void
    8306         144 : addConstrChildIdxDeps(DumpableObject *dobj, const IndxInfo *refidx)
    8307             : {
    8308             :     SimplePtrListCell *cell;
    8309             : 
    8310             :     Assert(dobj->objType == DO_FK_CONSTRAINT);
    8311             : 
    8312         496 :     for (cell = refidx->partattaches.head; cell; cell = cell->next)
    8313             :     {
    8314         352 :         IndexAttachInfo *attach = (IndexAttachInfo *) cell->ptr;
    8315             : 
    8316         352 :         addObjectDependency(dobj, attach->dobj.dumpId);
    8317             : 
    8318         352 :         if (attach->partitionIdx->partattaches.head != NULL)
    8319          80 :             addConstrChildIdxDeps(dobj, attach->partitionIdx);
    8320             :     }
    8321         144 : }
    8322             : 
    8323             : /*
    8324             :  * getDomainConstraints
    8325             :  *
    8326             :  * Get info about constraints on a domain.
    8327             :  */
    8328             : static void
    8329         468 : getDomainConstraints(Archive *fout, TypeInfo *tyinfo)
    8330             : {
    8331             :     ConstraintInfo *constrinfo;
    8332         468 :     PQExpBuffer query = createPQExpBuffer();
    8333             :     PGresult   *res;
    8334             :     int         i_tableoid,
    8335             :                 i_oid,
    8336             :                 i_conname,
    8337             :                 i_consrc,
    8338             :                 i_convalidated,
    8339             :                 i_contype;
    8340             :     int         ntups;
    8341             : 
    8342         468 :     if (!fout->is_prepared[PREPQUERY_GETDOMAINCONSTRAINTS])
    8343             :     {
    8344             :         /*
    8345             :          * Set up query for constraint-specific details.  For servers 17 and
    8346             :          * up, domains have constraints of type 'n' as well as 'c', otherwise
    8347             :          * just the latter.
    8348             :          */
    8349         100 :         appendPQExpBuffer(query,
    8350             :                           "PREPARE getDomainConstraints(pg_catalog.oid) AS\n"
    8351             :                           "SELECT tableoid, oid, conname, "
    8352             :                           "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
    8353             :                           "convalidated, contype "
    8354             :                           "FROM pg_catalog.pg_constraint "
    8355             :                           "WHERE contypid = $1 AND contype IN (%s) "
    8356             :                           "ORDER BY conname",
    8357         100 :                           fout->remoteVersion < 170000 ? "'c'" : "'c', 'n'");
    8358             : 
    8359         100 :         ExecuteSqlStatement(fout, query->data);
    8360             : 
    8361         100 :         fout->is_prepared[PREPQUERY_GETDOMAINCONSTRAINTS] = true;
    8362             :     }
    8363             : 
    8364         468 :     printfPQExpBuffer(query,
    8365             :                       "EXECUTE getDomainConstraints('%u')",
    8366             :                       tyinfo->dobj.catId.oid);
    8367             : 
    8368         468 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    8369             : 
    8370         468 :     ntups = PQntuples(res);
    8371             : 
    8372         468 :     i_tableoid = PQfnumber(res, "tableoid");
    8373         468 :     i_oid = PQfnumber(res, "oid");
    8374         468 :     i_conname = PQfnumber(res, "conname");
    8375         468 :     i_consrc = PQfnumber(res, "consrc");
    8376         468 :     i_convalidated = PQfnumber(res, "convalidated");
    8377         468 :     i_contype = PQfnumber(res, "contype");
    8378             : 
    8379         468 :     constrinfo = (ConstraintInfo *) pg_malloc(ntups * sizeof(ConstraintInfo));
    8380         468 :     tyinfo->domChecks = constrinfo;
    8381             : 
    8382             :     /* 'i' tracks result rows; 'j' counts CHECK constraints */
    8383         924 :     for (int i = 0, j = 0; i < ntups; i++)
    8384             :     {
    8385         456 :         bool        validated = PQgetvalue(res, i, i_convalidated)[0] == 't';
    8386         456 :         char        contype = (PQgetvalue(res, i, i_contype))[0];
    8387             :         ConstraintInfo *constraint;
    8388             : 
    8389         456 :         if (contype == CONSTRAINT_CHECK)
    8390             :         {
    8391         324 :             constraint = &constrinfo[j++];
    8392         324 :             tyinfo->nDomChecks++;
    8393             :         }
    8394             :         else
    8395             :         {
    8396             :             Assert(contype == CONSTRAINT_NOTNULL);
    8397             :             Assert(tyinfo->notnull == NULL);
    8398             :             /* use last item in array for the not-null constraint */
    8399         132 :             tyinfo->notnull = &(constrinfo[ntups - 1]);
    8400         132 :             constraint = tyinfo->notnull;
    8401             :         }
    8402             : 
    8403         456 :         constraint->dobj.objType = DO_CONSTRAINT;
    8404         456 :         constraint->dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    8405         456 :         constraint->dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    8406         456 :         AssignDumpId(&(constraint->dobj));
    8407         456 :         constraint->dobj.name = pg_strdup(PQgetvalue(res, i, i_conname));
    8408         456 :         constraint->dobj.namespace = tyinfo->dobj.namespace;
    8409         456 :         constraint->contable = NULL;
    8410         456 :         constraint->condomain = tyinfo;
    8411         456 :         constraint->contype = contype;
    8412         456 :         constraint->condef = pg_strdup(PQgetvalue(res, i, i_consrc));
    8413         456 :         constraint->confrelid = InvalidOid;
    8414         456 :         constraint->conindex = 0;
    8415         456 :         constraint->condeferrable = false;
    8416         456 :         constraint->condeferred = false;
    8417         456 :         constraint->conislocal = true;
    8418             : 
    8419         456 :         constraint->separate = !validated;
    8420             : 
    8421             :         /*
    8422             :          * Make the domain depend on the constraint, ensuring it won't be
    8423             :          * output till any constraint dependencies are OK.  If the constraint
    8424             :          * has not been validated, it's going to be dumped after the domain
    8425             :          * anyway, so this doesn't matter.
    8426             :          */
    8427         456 :         if (validated)
    8428         440 :             addObjectDependency(&tyinfo->dobj, constraint->dobj.dumpId);
    8429             :     }
    8430             : 
    8431         468 :     PQclear(res);
    8432             : 
    8433         468 :     destroyPQExpBuffer(query);
    8434         468 : }
    8435             : 
    8436             : /*
    8437             :  * getRules
    8438             :  *    get basic information about every rule in the system
    8439             :  */
    8440             : void
    8441         468 : getRules(Archive *fout)
    8442             : {
    8443             :     PGresult   *res;
    8444             :     int         ntups;
    8445             :     int         i;
    8446         468 :     PQExpBuffer query = createPQExpBuffer();
    8447             :     RuleInfo   *ruleinfo;
    8448             :     int         i_tableoid;
    8449             :     int         i_oid;
    8450             :     int         i_rulename;
    8451             :     int         i_ruletable;
    8452             :     int         i_ev_type;
    8453             :     int         i_is_instead;
    8454             :     int         i_ev_enabled;
    8455             : 
    8456         468 :     appendPQExpBufferStr(query, "SELECT "
    8457             :                          "tableoid, oid, rulename, "
    8458             :                          "ev_class AS ruletable, ev_type, is_instead, "
    8459             :                          "ev_enabled "
    8460             :                          "FROM pg_rewrite "
    8461             :                          "ORDER BY oid");
    8462             : 
    8463         468 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    8464             : 
    8465         468 :     ntups = PQntuples(res);
    8466             : 
    8467         468 :     ruleinfo = (RuleInfo *) pg_malloc(ntups * sizeof(RuleInfo));
    8468             : 
    8469         468 :     i_tableoid = PQfnumber(res, "tableoid");
    8470         468 :     i_oid = PQfnumber(res, "oid");
    8471         468 :     i_rulename = PQfnumber(res, "rulename");
    8472         468 :     i_ruletable = PQfnumber(res, "ruletable");
    8473         468 :     i_ev_type = PQfnumber(res, "ev_type");
    8474         468 :     i_is_instead = PQfnumber(res, "is_instead");
    8475         468 :     i_ev_enabled = PQfnumber(res, "ev_enabled");
    8476             : 
    8477       72770 :     for (i = 0; i < ntups; i++)
    8478             :     {
    8479             :         Oid         ruletableoid;
    8480             : 
    8481       72302 :         ruleinfo[i].dobj.objType = DO_RULE;
    8482       72302 :         ruleinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    8483       72302 :         ruleinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    8484       72302 :         AssignDumpId(&ruleinfo[i].dobj);
    8485       72302 :         ruleinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_rulename));
    8486       72302 :         ruletableoid = atooid(PQgetvalue(res, i, i_ruletable));
    8487       72302 :         ruleinfo[i].ruletable = findTableByOid(ruletableoid);
    8488       72302 :         if (ruleinfo[i].ruletable == NULL)
    8489           0 :             pg_fatal("failed sanity check, parent table with OID %u of pg_rewrite entry with OID %u not found",
    8490             :                      ruletableoid, ruleinfo[i].dobj.catId.oid);
    8491       72302 :         ruleinfo[i].dobj.namespace = ruleinfo[i].ruletable->dobj.namespace;
    8492       72302 :         ruleinfo[i].dobj.dump = ruleinfo[i].ruletable->dobj.dump;
    8493       72302 :         ruleinfo[i].ev_type = *(PQgetvalue(res, i, i_ev_type));
    8494       72302 :         ruleinfo[i].is_instead = *(PQgetvalue(res, i, i_is_instead)) == 't';
    8495       72302 :         ruleinfo[i].ev_enabled = *(PQgetvalue(res, i, i_ev_enabled));
    8496       72302 :         if (ruleinfo[i].ruletable)
    8497             :         {
    8498             :             /*
    8499             :              * If the table is a view or materialized view, force its ON
    8500             :              * SELECT rule to be sorted before the view itself --- this
    8501             :              * ensures that any dependencies for the rule affect the table's
    8502             :              * positioning. Other rules are forced to appear after their
    8503             :              * table.
    8504             :              */
    8505       72302 :             if ((ruleinfo[i].ruletable->relkind == RELKIND_VIEW ||
    8506        1800 :                  ruleinfo[i].ruletable->relkind == RELKIND_MATVIEW) &&
    8507       71642 :                 ruleinfo[i].ev_type == '1' && ruleinfo[i].is_instead)
    8508             :             {
    8509       70586 :                 addObjectDependency(&ruleinfo[i].ruletable->dobj,
    8510       70586 :                                     ruleinfo[i].dobj.dumpId);
    8511             :                 /* We'll merge the rule into CREATE VIEW, if possible */
    8512       70586 :                 ruleinfo[i].separate = false;
    8513             :             }
    8514             :             else
    8515             :             {
    8516        1716 :                 addObjectDependency(&ruleinfo[i].dobj,
    8517        1716 :                                     ruleinfo[i].ruletable->dobj.dumpId);
    8518        1716 :                 ruleinfo[i].separate = true;
    8519             :             }
    8520             :         }
    8521             :         else
    8522           0 :             ruleinfo[i].separate = true;
    8523             :     }
    8524             : 
    8525         468 :     PQclear(res);
    8526             : 
    8527         468 :     destroyPQExpBuffer(query);
    8528         468 : }
    8529             : 
    8530             : /*
    8531             :  * getTriggers
    8532             :  *    get information about every trigger on a dumpable table
    8533             :  *
    8534             :  * Note: trigger data is not returned directly to the caller, but it
    8535             :  * does get entered into the DumpableObject tables.
    8536             :  */
    8537             : void
    8538         468 : getTriggers(Archive *fout, TableInfo tblinfo[], int numTables)
    8539             : {
    8540         468 :     PQExpBuffer query = createPQExpBuffer();
    8541         468 :     PQExpBuffer tbloids = createPQExpBuffer();
    8542             :     PGresult   *res;
    8543             :     int         ntups;
    8544             :     int         curtblindx;
    8545             :     TriggerInfo *tginfo;
    8546             :     int         i_tableoid,
    8547             :                 i_oid,
    8548             :                 i_tgrelid,
    8549             :                 i_tgname,
    8550             :                 i_tgenabled,
    8551             :                 i_tgispartition,
    8552             :                 i_tgdef;
    8553             : 
    8554             :     /*
    8555             :      * We want to perform just one query against pg_trigger.  However, we
    8556             :      * mustn't try to select every row of the catalog and then sort it out on
    8557             :      * the client side, because some of the server-side functions we need
    8558             :      * would be unsafe to apply to tables we don't have lock on.  Hence, we
    8559             :      * build an array of the OIDs of tables we care about (and now have lock
    8560             :      * on!), and use a WHERE clause to constrain which rows are selected.
    8561             :      */
    8562         468 :     appendPQExpBufferChar(tbloids, '{');
    8563      124260 :     for (int i = 0; i < numTables; i++)
    8564             :     {
    8565      123792 :         TableInfo  *tbinfo = &tblinfo[i];
    8566             : 
    8567      123792 :         if (!tbinfo->hastriggers ||
    8568        2898 :             !(tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
    8569      121418 :             continue;
    8570             : 
    8571             :         /* OK, we need info for this table */
    8572        2374 :         if (tbloids->len > 1) /* do we have more than the '{'? */
    8573        2258 :             appendPQExpBufferChar(tbloids, ',');
    8574        2374 :         appendPQExpBuffer(tbloids, "%u", tbinfo->dobj.catId.oid);
    8575             :     }
    8576         468 :     appendPQExpBufferChar(tbloids, '}');
    8577             : 
    8578         468 :     if (fout->remoteVersion >= 150000)
    8579             :     {
    8580             :         /*
    8581             :          * NB: think not to use pretty=true in pg_get_triggerdef.  It could
    8582             :          * result in non-forward-compatible dumps of WHEN clauses due to
    8583             :          * under-parenthesization.
    8584             :          *
    8585             :          * NB: We need to see partition triggers in case the tgenabled flag
    8586             :          * has been changed from the parent.
    8587             :          */
    8588         468 :         appendPQExpBuffer(query,
    8589             :                           "SELECT t.tgrelid, t.tgname, "
    8590             :                           "pg_catalog.pg_get_triggerdef(t.oid, false) AS tgdef, "
    8591             :                           "t.tgenabled, t.tableoid, t.oid, "
    8592             :                           "t.tgparentid <> 0 AS tgispartition\n"
    8593             :                           "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
    8594             :                           "JOIN pg_catalog.pg_trigger t ON (src.tbloid = t.tgrelid) "
    8595             :                           "LEFT JOIN pg_catalog.pg_trigger u ON (u.oid = t.tgparentid) "
    8596             :                           "WHERE ((NOT t.tgisinternal AND t.tgparentid = 0) "
    8597             :                           "OR t.tgenabled != u.tgenabled) "
    8598             :                           "ORDER BY t.tgrelid, t.tgname",
    8599             :                           tbloids->data);
    8600             :     }
    8601           0 :     else if (fout->remoteVersion >= 130000)
    8602             :     {
    8603             :         /*
    8604             :          * NB: think not to use pretty=true in pg_get_triggerdef.  It could
    8605             :          * result in non-forward-compatible dumps of WHEN clauses due to
    8606             :          * under-parenthesization.
    8607             :          *
    8608             :          * NB: We need to see tgisinternal triggers in partitions, in case the
    8609             :          * tgenabled flag has been changed from the parent.
    8610             :          */
    8611           0 :         appendPQExpBuffer(query,
    8612             :                           "SELECT t.tgrelid, t.tgname, "
    8613             :                           "pg_catalog.pg_get_triggerdef(t.oid, false) AS tgdef, "
    8614             :                           "t.tgenabled, t.tableoid, t.oid, t.tgisinternal as tgispartition\n"
    8615             :                           "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
    8616             :                           "JOIN pg_catalog.pg_trigger t ON (src.tbloid = t.tgrelid) "
    8617             :                           "LEFT JOIN pg_catalog.pg_trigger u ON (u.oid = t.tgparentid) "
    8618             :                           "WHERE (NOT t.tgisinternal OR t.tgenabled != u.tgenabled) "
    8619             :                           "ORDER BY t.tgrelid, t.tgname",
    8620             :                           tbloids->data);
    8621             :     }
    8622           0 :     else if (fout->remoteVersion >= 110000)
    8623             :     {
    8624             :         /*
    8625             :          * NB: We need to see tgisinternal triggers in partitions, in case the
    8626             :          * tgenabled flag has been changed from the parent. No tgparentid in
    8627             :          * version 11-12, so we have to match them via pg_depend.
    8628             :          *
    8629             :          * See above about pretty=true in pg_get_triggerdef.
    8630             :          */
    8631           0 :         appendPQExpBuffer(query,
    8632             :                           "SELECT t.tgrelid, t.tgname, "
    8633             :                           "pg_catalog.pg_get_triggerdef(t.oid, false) AS tgdef, "
    8634             :                           "t.tgenabled, t.tableoid, t.oid, t.tgisinternal as tgispartition "
    8635             :                           "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
    8636             :                           "JOIN pg_catalog.pg_trigger t ON (src.tbloid = t.tgrelid) "
    8637             :                           "LEFT JOIN pg_catalog.pg_depend AS d ON "
    8638             :                           " d.classid = 'pg_catalog.pg_trigger'::pg_catalog.regclass AND "
    8639             :                           " d.refclassid = 'pg_catalog.pg_trigger'::pg_catalog.regclass AND "
    8640             :                           " d.objid = t.oid "
    8641             :                           "LEFT JOIN pg_catalog.pg_trigger AS pt ON pt.oid = refobjid "
    8642             :                           "WHERE (NOT t.tgisinternal OR t.tgenabled != pt.tgenabled) "
    8643             :                           "ORDER BY t.tgrelid, t.tgname",
    8644             :                           tbloids->data);
    8645             :     }
    8646             :     else
    8647             :     {
    8648             :         /* See above about pretty=true in pg_get_triggerdef */
    8649           0 :         appendPQExpBuffer(query,
    8650             :                           "SELECT t.tgrelid, t.tgname, "
    8651             :                           "pg_catalog.pg_get_triggerdef(t.oid, false) AS tgdef, "
    8652             :                           "t.tgenabled, false as tgispartition, "
    8653             :                           "t.tableoid, t.oid "
    8654             :                           "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
    8655             :                           "JOIN pg_catalog.pg_trigger t ON (src.tbloid = t.tgrelid) "
    8656             :                           "WHERE NOT tgisinternal "
    8657             :                           "ORDER BY t.tgrelid, t.tgname",
    8658             :                           tbloids->data);
    8659             :     }
    8660             : 
    8661         468 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    8662             : 
    8663         468 :     ntups = PQntuples(res);
    8664             : 
    8665         468 :     i_tableoid = PQfnumber(res, "tableoid");
    8666         468 :     i_oid = PQfnumber(res, "oid");
    8667         468 :     i_tgrelid = PQfnumber(res, "tgrelid");
    8668         468 :     i_tgname = PQfnumber(res, "tgname");
    8669         468 :     i_tgenabled = PQfnumber(res, "tgenabled");
    8670         468 :     i_tgispartition = PQfnumber(res, "tgispartition");
    8671         468 :     i_tgdef = PQfnumber(res, "tgdef");
    8672             : 
    8673         468 :     tginfo = (TriggerInfo *) pg_malloc(ntups * sizeof(TriggerInfo));
    8674             : 
    8675             :     /*
    8676             :      * Outer loop iterates once per table, not once per row.  Incrementing of
    8677             :      * j is handled by the inner loop.
    8678             :      */
    8679         468 :     curtblindx = -1;
    8680        1252 :     for (int j = 0; j < ntups;)
    8681             :     {
    8682         784 :         Oid         tgrelid = atooid(PQgetvalue(res, j, i_tgrelid));
    8683         784 :         TableInfo  *tbinfo = NULL;
    8684             :         int         numtrigs;
    8685             : 
    8686             :         /* Count rows for this table */
    8687        1476 :         for (numtrigs = 1; numtrigs < ntups - j; numtrigs++)
    8688        1360 :             if (atooid(PQgetvalue(res, j + numtrigs, i_tgrelid)) != tgrelid)
    8689         668 :                 break;
    8690             : 
    8691             :         /*
    8692             :          * Locate the associated TableInfo; we rely on tblinfo[] being in OID
    8693             :          * order.
    8694             :          */
    8695       39738 :         while (++curtblindx < numTables)
    8696             :         {
    8697       39738 :             tbinfo = &tblinfo[curtblindx];
    8698       39738 :             if (tbinfo->dobj.catId.oid == tgrelid)
    8699         784 :                 break;
    8700             :         }
    8701         784 :         if (curtblindx >= numTables)
    8702           0 :             pg_fatal("unrecognized table OID %u", tgrelid);
    8703             : 
    8704             :         /* Save data for this table */
    8705         784 :         tbinfo->triggers = tginfo + j;
    8706         784 :         tbinfo->numTriggers = numtrigs;
    8707             : 
    8708        2260 :         for (int c = 0; c < numtrigs; c++, j++)
    8709             :         {
    8710        1476 :             tginfo[j].dobj.objType = DO_TRIGGER;
    8711        1476 :             tginfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
    8712        1476 :             tginfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
    8713        1476 :             AssignDumpId(&tginfo[j].dobj);
    8714        1476 :             tginfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_tgname));
    8715        1476 :             tginfo[j].dobj.namespace = tbinfo->dobj.namespace;
    8716        1476 :             tginfo[j].tgtable = tbinfo;
    8717        1476 :             tginfo[j].tgenabled = *(PQgetvalue(res, j, i_tgenabled));
    8718        1476 :             tginfo[j].tgispartition = *(PQgetvalue(res, j, i_tgispartition)) == 't';
    8719        1476 :             tginfo[j].tgdef = pg_strdup(PQgetvalue(res, j, i_tgdef));
    8720             :         }
    8721             :     }
    8722             : 
    8723         468 :     PQclear(res);
    8724             : 
    8725         468 :     destroyPQExpBuffer(query);
    8726         468 :     destroyPQExpBuffer(tbloids);
    8727         468 : }
    8728             : 
    8729             : /*
    8730             :  * getEventTriggers
    8731             :  *    get information about event triggers
    8732             :  */
    8733             : void
    8734         468 : getEventTriggers(Archive *fout)
    8735             : {
    8736             :     int         i;
    8737             :     PQExpBuffer query;
    8738             :     PGresult   *res;
    8739             :     EventTriggerInfo *evtinfo;
    8740             :     int         i_tableoid,
    8741             :                 i_oid,
    8742             :                 i_evtname,
    8743             :                 i_evtevent,
    8744             :                 i_evtowner,
    8745             :                 i_evttags,
    8746             :                 i_evtfname,
    8747             :                 i_evtenabled;
    8748             :     int         ntups;
    8749             : 
    8750             :     /* Before 9.3, there are no event triggers */
    8751         468 :     if (fout->remoteVersion < 90300)
    8752           0 :         return;
    8753             : 
    8754         468 :     query = createPQExpBuffer();
    8755             : 
    8756         468 :     appendPQExpBufferStr(query,
    8757             :                          "SELECT e.tableoid, e.oid, evtname, evtenabled, "
    8758             :                          "evtevent, evtowner, "
    8759             :                          "array_to_string(array("
    8760             :                          "select quote_literal(x) "
    8761             :                          " from unnest(evttags) as t(x)), ', ') as evttags, "
    8762             :                          "e.evtfoid::regproc as evtfname "
    8763             :                          "FROM pg_event_trigger e "
    8764             :                          "ORDER BY e.oid");
    8765             : 
    8766         468 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    8767             : 
    8768         468 :     ntups = PQntuples(res);
    8769             : 
    8770         468 :     evtinfo = (EventTriggerInfo *) pg_malloc(ntups * sizeof(EventTriggerInfo));
    8771             : 
    8772         468 :     i_tableoid = PQfnumber(res, "tableoid");
    8773         468 :     i_oid = PQfnumber(res, "oid");
    8774         468 :     i_evtname = PQfnumber(res, "evtname");
    8775         468 :     i_evtevent = PQfnumber(res, "evtevent");
    8776         468 :     i_evtowner = PQfnumber(res, "evtowner");
    8777         468 :     i_evttags = PQfnumber(res, "evttags");
    8778         468 :     i_evtfname = PQfnumber(res, "evtfname");
    8779         468 :     i_evtenabled = PQfnumber(res, "evtenabled");
    8780             : 
    8781         586 :     for (i = 0; i < ntups; i++)
    8782             :     {
    8783         118 :         evtinfo[i].dobj.objType = DO_EVENT_TRIGGER;
    8784         118 :         evtinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    8785         118 :         evtinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    8786         118 :         AssignDumpId(&evtinfo[i].dobj);
    8787         118 :         evtinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_evtname));
    8788         118 :         evtinfo[i].evtname = pg_strdup(PQgetvalue(res, i, i_evtname));
    8789         118 :         evtinfo[i].evtevent = pg_strdup(PQgetvalue(res, i, i_evtevent));
    8790         118 :         evtinfo[i].evtowner = getRoleName(PQgetvalue(res, i, i_evtowner));
    8791         118 :         evtinfo[i].evttags = pg_strdup(PQgetvalue(res, i, i_evttags));
    8792         118 :         evtinfo[i].evtfname = pg_strdup(PQgetvalue(res, i, i_evtfname));
    8793         118 :         evtinfo[i].evtenabled = *(PQgetvalue(res, i, i_evtenabled));
    8794             : 
    8795             :         /* Decide whether we want to dump it */
    8796         118 :         selectDumpableObject(&(evtinfo[i].dobj), fout);
    8797             :     }
    8798             : 
    8799         468 :     PQclear(res);
    8800             : 
    8801         468 :     destroyPQExpBuffer(query);
    8802             : }
    8803             : 
    8804             : /*
    8805             :  * getProcLangs
    8806             :  *    get basic information about every procedural language in the system
    8807             :  *
    8808             :  * NB: this must run after getFuncs() because we assume we can do
    8809             :  * findFuncByOid().
    8810             :  */
    8811             : void
    8812         468 : getProcLangs(Archive *fout)
    8813             : {
    8814             :     PGresult   *res;
    8815             :     int         ntups;
    8816             :     int         i;
    8817         468 :     PQExpBuffer query = createPQExpBuffer();
    8818             :     ProcLangInfo *planginfo;
    8819             :     int         i_tableoid;
    8820             :     int         i_oid;
    8821             :     int         i_lanname;
    8822             :     int         i_lanpltrusted;
    8823             :     int         i_lanplcallfoid;
    8824             :     int         i_laninline;
    8825             :     int         i_lanvalidator;
    8826             :     int         i_lanacl;
    8827             :     int         i_acldefault;
    8828             :     int         i_lanowner;
    8829             : 
    8830         468 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, "
    8831             :                          "lanname, lanpltrusted, lanplcallfoid, "
    8832             :                          "laninline, lanvalidator, "
    8833             :                          "lanacl, "
    8834             :                          "acldefault('l', lanowner) AS acldefault, "
    8835             :                          "lanowner "
    8836             :                          "FROM pg_language "
    8837             :                          "WHERE lanispl "
    8838             :                          "ORDER BY oid");
    8839             : 
    8840         468 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    8841             : 
    8842         468 :     ntups = PQntuples(res);
    8843             : 
    8844         468 :     planginfo = (ProcLangInfo *) pg_malloc(ntups * sizeof(ProcLangInfo));
    8845             : 
    8846         468 :     i_tableoid = PQfnumber(res, "tableoid");
    8847         468 :     i_oid = PQfnumber(res, "oid");
    8848         468 :     i_lanname = PQfnumber(res, "lanname");
    8849         468 :     i_lanpltrusted = PQfnumber(res, "lanpltrusted");
    8850         468 :     i_lanplcallfoid = PQfnumber(res, "lanplcallfoid");
    8851         468 :     i_laninline = PQfnumber(res, "laninline");
    8852         468 :     i_lanvalidator = PQfnumber(res, "lanvalidator");
    8853         468 :     i_lanacl = PQfnumber(res, "lanacl");
    8854         468 :     i_acldefault = PQfnumber(res, "acldefault");
    8855         468 :     i_lanowner = PQfnumber(res, "lanowner");
    8856             : 
    8857        1034 :     for (i = 0; i < ntups; i++)
    8858             :     {
    8859         566 :         planginfo[i].dobj.objType = DO_PROCLANG;
    8860         566 :         planginfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    8861         566 :         planginfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    8862         566 :         AssignDumpId(&planginfo[i].dobj);
    8863             : 
    8864         566 :         planginfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_lanname));
    8865         566 :         planginfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_lanacl));
    8866         566 :         planginfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
    8867         566 :         planginfo[i].dacl.privtype = 0;
    8868         566 :         planginfo[i].dacl.initprivs = NULL;
    8869         566 :         planginfo[i].lanpltrusted = *(PQgetvalue(res, i, i_lanpltrusted)) == 't';
    8870         566 :         planginfo[i].lanplcallfoid = atooid(PQgetvalue(res, i, i_lanplcallfoid));
    8871         566 :         planginfo[i].laninline = atooid(PQgetvalue(res, i, i_laninline));
    8872         566 :         planginfo[i].lanvalidator = atooid(PQgetvalue(res, i, i_lanvalidator));
    8873         566 :         planginfo[i].lanowner = getRoleName(PQgetvalue(res, i, i_lanowner));
    8874             : 
    8875             :         /* Decide whether we want to dump it */
    8876         566 :         selectDumpableProcLang(&(planginfo[i]), fout);
    8877             : 
    8878             :         /* Mark whether language has an ACL */
    8879         566 :         if (!PQgetisnull(res, i, i_lanacl))
    8880          98 :             planginfo[i].dobj.components |= DUMP_COMPONENT_ACL;
    8881             :     }
    8882             : 
    8883         468 :     PQclear(res);
    8884             : 
    8885         468 :     destroyPQExpBuffer(query);
    8886         468 : }
    8887             : 
    8888             : /*
    8889             :  * getCasts
    8890             :  *    get basic information about most casts in the system
    8891             :  *
    8892             :  * Skip casts from a range to its multirange, since we'll create those
    8893             :  * automatically.
    8894             :  */
    8895             : void
    8896         468 : getCasts(Archive *fout)
    8897             : {
    8898             :     PGresult   *res;
    8899             :     int         ntups;
    8900             :     int         i;
    8901         468 :     PQExpBuffer query = createPQExpBuffer();
    8902             :     CastInfo   *castinfo;
    8903             :     int         i_tableoid;
    8904             :     int         i_oid;
    8905             :     int         i_castsource;
    8906             :     int         i_casttarget;
    8907             :     int         i_castfunc;
    8908             :     int         i_castcontext;
    8909             :     int         i_castmethod;
    8910             : 
    8911         468 :     if (fout->remoteVersion >= 140000)
    8912             :     {
    8913         468 :         appendPQExpBufferStr(query, "SELECT tableoid, oid, "
    8914             :                              "castsource, casttarget, castfunc, castcontext, "
    8915             :                              "castmethod "
    8916             :                              "FROM pg_cast c "
    8917             :                              "WHERE NOT EXISTS ( "
    8918             :                              "SELECT 1 FROM pg_range r "
    8919             :                              "WHERE c.castsource = r.rngtypid "
    8920             :                              "AND c.casttarget = r.rngmultitypid "
    8921             :                              ") "
    8922             :                              "ORDER BY 3,4");
    8923             :     }
    8924             :     else
    8925             :     {
    8926           0 :         appendPQExpBufferStr(query, "SELECT tableoid, oid, "
    8927             :                              "castsource, casttarget, castfunc, castcontext, "
    8928             :                              "castmethod "
    8929             :                              "FROM pg_cast ORDER BY 3,4");
    8930             :     }
    8931             : 
    8932         468 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    8933             : 
    8934         468 :     ntups = PQntuples(res);
    8935             : 
    8936         468 :     castinfo = (CastInfo *) pg_malloc(ntups * sizeof(CastInfo));
    8937             : 
    8938         468 :     i_tableoid = PQfnumber(res, "tableoid");
    8939         468 :     i_oid = PQfnumber(res, "oid");
    8940         468 :     i_castsource = PQfnumber(res, "castsource");
    8941         468 :     i_casttarget = PQfnumber(res, "casttarget");
    8942         468 :     i_castfunc = PQfnumber(res, "castfunc");
    8943         468 :     i_castcontext = PQfnumber(res, "castcontext");
    8944         468 :     i_castmethod = PQfnumber(res, "castmethod");
    8945             : 
    8946      111134 :     for (i = 0; i < ntups; i++)
    8947             :     {
    8948             :         PQExpBufferData namebuf;
    8949             :         TypeInfo   *sTypeInfo;
    8950             :         TypeInfo   *tTypeInfo;
    8951             : 
    8952      110666 :         castinfo[i].dobj.objType = DO_CAST;
    8953      110666 :         castinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    8954      110666 :         castinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    8955      110666 :         AssignDumpId(&castinfo[i].dobj);
    8956      110666 :         castinfo[i].castsource = atooid(PQgetvalue(res, i, i_castsource));
    8957      110666 :         castinfo[i].casttarget = atooid(PQgetvalue(res, i, i_casttarget));
    8958      110666 :         castinfo[i].castfunc = atooid(PQgetvalue(res, i, i_castfunc));
    8959      110666 :         castinfo[i].castcontext = *(PQgetvalue(res, i, i_castcontext));
    8960      110666 :         castinfo[i].castmethod = *(PQgetvalue(res, i, i_castmethod));
    8961             : 
    8962             :         /*
    8963             :          * Try to name cast as concatenation of typnames.  This is only used
    8964             :          * for purposes of sorting.  If we fail to find either type, the name
    8965             :          * will be an empty string.
    8966             :          */
    8967      110666 :         initPQExpBuffer(&namebuf);
    8968      110666 :         sTypeInfo = findTypeByOid(castinfo[i].castsource);
    8969      110666 :         tTypeInfo = findTypeByOid(castinfo[i].casttarget);
    8970      110666 :         if (sTypeInfo && tTypeInfo)
    8971      110666 :             appendPQExpBuffer(&namebuf, "%s %s",
    8972             :                               sTypeInfo->dobj.name, tTypeInfo->dobj.name);
    8973      110666 :         castinfo[i].dobj.name = namebuf.data;
    8974             : 
    8975             :         /* Decide whether we want to dump it */
    8976      110666 :         selectDumpableCast(&(castinfo[i]), fout);
    8977             :     }
    8978             : 
    8979         468 :     PQclear(res);
    8980             : 
    8981         468 :     destroyPQExpBuffer(query);
    8982         468 : }
    8983             : 
    8984             : static char *
    8985         204 : get_language_name(Archive *fout, Oid langid)
    8986             : {
    8987             :     PQExpBuffer query;
    8988             :     PGresult   *res;
    8989             :     char       *lanname;
    8990             : 
    8991         204 :     query = createPQExpBuffer();
    8992         204 :     appendPQExpBuffer(query, "SELECT lanname FROM pg_language WHERE oid = %u", langid);
    8993         204 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
    8994         204 :     lanname = pg_strdup(fmtId(PQgetvalue(res, 0, 0)));
    8995         204 :     destroyPQExpBuffer(query);
    8996         204 :     PQclear(res);
    8997             : 
    8998         204 :     return lanname;
    8999             : }
    9000             : 
    9001             : /*
    9002             :  * getTransforms
    9003             :  *    get basic information about every transform in the system
    9004             :  */
    9005             : void
    9006         468 : getTransforms(Archive *fout)
    9007             : {
    9008             :     PGresult   *res;
    9009             :     int         ntups;
    9010             :     int         i;
    9011             :     PQExpBuffer query;
    9012             :     TransformInfo *transforminfo;
    9013             :     int         i_tableoid;
    9014             :     int         i_oid;
    9015             :     int         i_trftype;
    9016             :     int         i_trflang;
    9017             :     int         i_trffromsql;
    9018             :     int         i_trftosql;
    9019             : 
    9020             :     /* Transforms didn't exist pre-9.5 */
    9021         468 :     if (fout->remoteVersion < 90500)
    9022           0 :         return;
    9023             : 
    9024         468 :     query = createPQExpBuffer();
    9025             : 
    9026         468 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, "
    9027             :                          "trftype, trflang, trffromsql::oid, trftosql::oid "
    9028             :                          "FROM pg_transform "
    9029             :                          "ORDER BY 3,4");
    9030             : 
    9031         468 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    9032             : 
    9033         468 :     ntups = PQntuples(res);
    9034             : 
    9035         468 :     transforminfo = (TransformInfo *) pg_malloc(ntups * sizeof(TransformInfo));
    9036             : 
    9037         468 :     i_tableoid = PQfnumber(res, "tableoid");
    9038         468 :     i_oid = PQfnumber(res, "oid");
    9039         468 :     i_trftype = PQfnumber(res, "trftype");
    9040         468 :     i_trflang = PQfnumber(res, "trflang");
    9041         468 :     i_trffromsql = PQfnumber(res, "trffromsql");
    9042         468 :     i_trftosql = PQfnumber(res, "trftosql");
    9043             : 
    9044         586 :     for (i = 0; i < ntups; i++)
    9045             :     {
    9046             :         PQExpBufferData namebuf;
    9047             :         TypeInfo   *typeInfo;
    9048             :         char       *lanname;
    9049             : 
    9050         118 :         transforminfo[i].dobj.objType = DO_TRANSFORM;
    9051         118 :         transforminfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    9052         118 :         transforminfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    9053         118 :         AssignDumpId(&transforminfo[i].dobj);
    9054         118 :         transforminfo[i].trftype = atooid(PQgetvalue(res, i, i_trftype));
    9055         118 :         transforminfo[i].trflang = atooid(PQgetvalue(res, i, i_trflang));
    9056         118 :         transforminfo[i].trffromsql = atooid(PQgetvalue(res, i, i_trffromsql));
    9057         118 :         transforminfo[i].trftosql = atooid(PQgetvalue(res, i, i_trftosql));
    9058             : 
    9059             :         /*
    9060             :          * Try to name transform as concatenation of type and language name.
    9061             :          * This is only used for purposes of sorting.  If we fail to find
    9062             :          * either, the name will be an empty string.
    9063             :          */
    9064         118 :         initPQExpBuffer(&namebuf);
    9065         118 :         typeInfo = findTypeByOid(transforminfo[i].trftype);
    9066         118 :         lanname = get_language_name(fout, transforminfo[i].trflang);
    9067         118 :         if (typeInfo && lanname)
    9068         118 :             appendPQExpBuffer(&namebuf, "%s %s",
    9069             :                               typeInfo->dobj.name, lanname);
    9070         118 :         transforminfo[i].dobj.name = namebuf.data;
    9071         118 :         free(lanname);
    9072             : 
    9073             :         /* Decide whether we want to dump it */
    9074         118 :         selectDumpableObject(&(transforminfo[i].dobj), fout);
    9075             :     }
    9076             : 
    9077         468 :     PQclear(res);
    9078             : 
    9079         468 :     destroyPQExpBuffer(query);
    9080             : }
    9081             : 
    9082             : /*
    9083             :  * getTableAttrs -
    9084             :  *    for each interesting table, read info about its attributes
    9085             :  *    (names, types, default values, CHECK constraints, etc)
    9086             :  *
    9087             :  *  modifies tblinfo
    9088             :  */
    9089             : void
    9090         468 : getTableAttrs(Archive *fout, TableInfo *tblinfo, int numTables)
    9091             : {
    9092         468 :     DumpOptions *dopt = fout->dopt;
    9093         468 :     PQExpBuffer q = createPQExpBuffer();
    9094         468 :     PQExpBuffer tbloids = createPQExpBuffer();
    9095         468 :     PQExpBuffer checkoids = createPQExpBuffer();
    9096         468 :     PQExpBuffer invalidnotnulloids = NULL;
    9097             :     PGresult   *res;
    9098             :     int         ntups;
    9099             :     int         curtblindx;
    9100             :     int         i_attrelid;
    9101             :     int         i_attnum;
    9102             :     int         i_attname;
    9103             :     int         i_atttypname;
    9104             :     int         i_attstattarget;
    9105             :     int         i_attstorage;
    9106             :     int         i_typstorage;
    9107             :     int         i_attidentity;
    9108             :     int         i_attgenerated;
    9109             :     int         i_attisdropped;
    9110             :     int         i_attlen;
    9111             :     int         i_attalign;
    9112             :     int         i_attislocal;
    9113             :     int         i_notnull_name;
    9114             :     int         i_notnull_comment;
    9115             :     int         i_notnull_noinherit;
    9116             :     int         i_notnull_islocal;
    9117             :     int         i_notnull_invalidoid;
    9118             :     int         i_attoptions;
    9119             :     int         i_attcollation;
    9120             :     int         i_attcompression;
    9121             :     int         i_attfdwoptions;
    9122             :     int         i_attmissingval;
    9123             :     int         i_atthasdef;
    9124             : 
    9125             :     /*
    9126             :      * We want to perform just one query against pg_attribute, and then just
    9127             :      * one against pg_attrdef (for DEFAULTs) and two against pg_constraint
    9128             :      * (for CHECK constraints and for NOT NULL constraints).  However, we
    9129             :      * mustn't try to select every row of those catalogs and then sort it out
    9130             :      * on the client side, because some of the server-side functions we need
    9131             :      * would be unsafe to apply to tables we don't have lock on.  Hence, we
    9132             :      * build an array of the OIDs of tables we care about (and now have lock
    9133             :      * on!), and use a WHERE clause to constrain which rows are selected.
    9134             :      */
    9135         468 :     appendPQExpBufferChar(tbloids, '{');
    9136         468 :     appendPQExpBufferChar(checkoids, '{');
    9137      124260 :     for (int i = 0; i < numTables; i++)
    9138             :     {
    9139      123792 :         TableInfo  *tbinfo = &tblinfo[i];
    9140             : 
    9141             :         /* Don't bother to collect info for sequences */
    9142      123792 :         if (tbinfo->relkind == RELKIND_SEQUENCE)
    9143        1632 :             continue;
    9144             : 
    9145             :         /*
    9146             :          * Don't bother with uninteresting tables, either.  For binary
    9147             :          * upgrades, this is bypassed for pg_largeobject_metadata and
    9148             :          * pg_shdepend so that the columns names are collected for the
    9149             :          * corresponding COPY commands.  Restoring the data for those catalogs
    9150             :          * is faster than restoring the equivalent set of large object
    9151             :          * commands.  We can only do this for upgrades from v12 and newer; in
    9152             :          * older versions, pg_largeobject_metadata was created WITH OIDS, so
    9153             :          * the OID column is hidden and won't be dumped.
    9154             :          */
    9155      122160 :         if (!tbinfo->interesting &&
    9156      103844 :             !(fout->dopt->binary_upgrade && fout->remoteVersion >= 120000 &&
    9157       13304 :               (tbinfo->dobj.catId.oid == LargeObjectMetadataRelationId ||
    9158       13242 :                tbinfo->dobj.catId.oid == SharedDependRelationId)))
    9159      103720 :             continue;
    9160             : 
    9161             :         /* OK, we need info for this table */
    9162       18440 :         if (tbloids->len > 1) /* do we have more than the '{'? */
    9163       18086 :             appendPQExpBufferChar(tbloids, ',');
    9164       18440 :         appendPQExpBuffer(tbloids, "%u", tbinfo->dobj.catId.oid);
    9165             : 
    9166       18440 :         if (tbinfo->ncheck > 0)
    9167             :         {
    9168             :             /* Also make a list of the ones with check constraints */
    9169        1362 :             if (checkoids->len > 1) /* do we have more than the '{'? */
    9170        1210 :                 appendPQExpBufferChar(checkoids, ',');
    9171        1362 :             appendPQExpBuffer(checkoids, "%u", tbinfo->dobj.catId.oid);
    9172             :         }
    9173             :     }
    9174         468 :     appendPQExpBufferChar(tbloids, '}');
    9175         468 :     appendPQExpBufferChar(checkoids, '}');
    9176             : 
    9177             :     /*
    9178             :      * Find all the user attributes and their types.
    9179             :      *
    9180             :      * Since we only want to dump COLLATE clauses for attributes whose
    9181             :      * collation is different from their type's default, we use a CASE here to
    9182             :      * suppress uninteresting attcollations cheaply.
    9183             :      */
    9184         468 :     appendPQExpBufferStr(q,
    9185             :                          "SELECT\n"
    9186             :                          "a.attrelid,\n"
    9187             :                          "a.attnum,\n"
    9188             :                          "a.attname,\n"
    9189             :                          "a.attstattarget,\n"
    9190             :                          "a.attstorage,\n"
    9191             :                          "t.typstorage,\n"
    9192             :                          "a.atthasdef,\n"
    9193             :                          "a.attisdropped,\n"
    9194             :                          "a.attlen,\n"
    9195             :                          "a.attalign,\n"
    9196             :                          "a.attislocal,\n"
    9197             :                          "pg_catalog.format_type(t.oid, a.atttypmod) AS atttypname,\n"
    9198             :                          "array_to_string(a.attoptions, ', ') AS attoptions,\n"
    9199             :                          "CASE WHEN a.attcollation <> t.typcollation "
    9200             :                          "THEN a.attcollation ELSE 0 END AS attcollation,\n"
    9201             :                          "pg_catalog.array_to_string(ARRAY("
    9202             :                          "SELECT pg_catalog.quote_ident(option_name) || "
    9203             :                          "' ' || pg_catalog.quote_literal(option_value) "
    9204             :                          "FROM pg_catalog.pg_options_to_table(attfdwoptions) "
    9205             :                          "ORDER BY option_name"
    9206             :                          "), E',\n    ') AS attfdwoptions,\n");
    9207             : 
    9208             :     /*
    9209             :      * Find out any NOT NULL markings for each column.  In 18 and up we read
    9210             :      * pg_constraint to obtain the constraint name, and for valid constraints
    9211             :      * also pg_description to obtain its comment.  notnull_noinherit is set
    9212             :      * according to the NO INHERIT property.  For versions prior to 18, we
    9213             :      * store an empty string as the name when a constraint is marked as
    9214             :      * attnotnull (this cues dumpTableSchema to print the NOT NULL clause
    9215             :      * without a name); also, such cases are never NO INHERIT.
    9216             :      *
    9217             :      * For invalid constraints, we need to store their OIDs for processing
    9218             :      * elsewhere, so we bring the pg_constraint.oid value when the constraint
    9219             :      * is invalid, and NULL otherwise.  Their comments are handled not here
    9220             :      * but by collectComments, because they're their own dumpable object.
    9221             :      *
    9222             :      * We track in notnull_islocal whether the constraint was defined directly
    9223             :      * in this table or via an ancestor, for binary upgrade.  flagInhAttrs
    9224             :      * might modify this later; that routine is also in charge of determining
    9225             :      * the correct inhcount.
    9226             :      */
    9227         468 :     if (fout->remoteVersion >= 180000)
    9228         468 :         appendPQExpBufferStr(q,
    9229             :                              "co.conname AS notnull_name,\n"
    9230             :                              "CASE WHEN co.convalidated THEN pt.description"
    9231             :                              " ELSE NULL END AS notnull_comment,\n"
    9232             :                              "CASE WHEN NOT co.convalidated THEN co.oid "
    9233             :                              "ELSE NULL END AS notnull_invalidoid,\n"
    9234             :                              "co.connoinherit AS notnull_noinherit,\n"
    9235             :                              "co.conislocal AS notnull_islocal,\n");
    9236             :     else
    9237           0 :         appendPQExpBufferStr(q,
    9238             :                              "CASE WHEN a.attnotnull THEN '' ELSE NULL END AS notnull_name,\n"
    9239             :                              "NULL AS notnull_comment,\n"
    9240             :                              "NULL AS notnull_invalidoid,\n"
    9241             :                              "false AS notnull_noinherit,\n"
    9242             :                              "a.attislocal AS notnull_islocal,\n");
    9243             : 
    9244         468 :     if (fout->remoteVersion >= 140000)
    9245         468 :         appendPQExpBufferStr(q,
    9246             :                              "a.attcompression AS attcompression,\n");
    9247             :     else
    9248           0 :         appendPQExpBufferStr(q,
    9249             :                              "'' AS attcompression,\n");
    9250             : 
    9251         468 :     if (fout->remoteVersion >= 100000)
    9252         468 :         appendPQExpBufferStr(q,
    9253             :                              "a.attidentity,\n");
    9254             :     else
    9255           0 :         appendPQExpBufferStr(q,
    9256             :                              "'' AS attidentity,\n");
    9257             : 
    9258         468 :     if (fout->remoteVersion >= 110000)
    9259         468 :         appendPQExpBufferStr(q,
    9260             :                              "CASE WHEN a.atthasmissing AND NOT a.attisdropped "
    9261             :                              "THEN a.attmissingval ELSE null END AS attmissingval,\n");
    9262             :     else
    9263           0 :         appendPQExpBufferStr(q,
    9264             :                              "NULL AS attmissingval,\n");
    9265             : 
    9266         468 :     if (fout->remoteVersion >= 120000)
    9267         468 :         appendPQExpBufferStr(q,
    9268             :                              "a.attgenerated\n");
    9269             :     else
    9270           0 :         appendPQExpBufferStr(q,
    9271             :                              "'' AS attgenerated\n");
    9272             : 
    9273             :     /* need left join to pg_type to not fail on dropped columns ... */
    9274         468 :     appendPQExpBuffer(q,
    9275             :                       "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
    9276             :                       "JOIN pg_catalog.pg_attribute a ON (src.tbloid = a.attrelid) "
    9277             :                       "LEFT JOIN pg_catalog.pg_type t "
    9278             :                       "ON (a.atttypid = t.oid)\n",
    9279             :                       tbloids->data);
    9280             : 
    9281             :     /*
    9282             :      * In versions 18 and up, we need pg_constraint for explicit NOT NULL
    9283             :      * entries and pg_description to get their comments.
    9284             :      */
    9285         468 :     if (fout->remoteVersion >= 180000)
    9286         468 :         appendPQExpBufferStr(q,
    9287             :                              " LEFT JOIN pg_catalog.pg_constraint co ON "
    9288             :                              "(a.attrelid = co.conrelid\n"
    9289             :                              "   AND co.contype = 'n' AND "
    9290             :                              "co.conkey = array[a.attnum])\n"
    9291             :                              " LEFT JOIN pg_catalog.pg_description pt ON "
    9292             :                              "(pt.classoid = co.tableoid AND pt.objoid = co.oid)\n");
    9293             : 
    9294         468 :     appendPQExpBufferStr(q,
    9295             :                          "WHERE a.attnum > 0::pg_catalog.int2\n"
    9296             :                          "ORDER BY a.attrelid, a.attnum");
    9297             : 
    9298         468 :     res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
    9299             : 
    9300         468 :     ntups = PQntuples(res);
    9301             : 
    9302         468 :     i_attrelid = PQfnumber(res, "attrelid");
    9303         468 :     i_attnum = PQfnumber(res, "attnum");
    9304         468 :     i_attname = PQfnumber(res, "attname");
    9305         468 :     i_atttypname = PQfnumber(res, "atttypname");
    9306         468 :     i_attstattarget = PQfnumber(res, "attstattarget");
    9307         468 :     i_attstorage = PQfnumber(res, "attstorage");
    9308         468 :     i_typstorage = PQfnumber(res, "typstorage");
    9309         468 :     i_attidentity = PQfnumber(res, "attidentity");
    9310         468 :     i_attgenerated = PQfnumber(res, "attgenerated");
    9311         468 :     i_attisdropped = PQfnumber(res, "attisdropped");
    9312         468 :     i_attlen = PQfnumber(res, "attlen");
    9313         468 :     i_attalign = PQfnumber(res, "attalign");
    9314         468 :     i_attislocal = PQfnumber(res, "attislocal");
    9315         468 :     i_notnull_name = PQfnumber(res, "notnull_name");
    9316         468 :     i_notnull_comment = PQfnumber(res, "notnull_comment");
    9317         468 :     i_notnull_invalidoid = PQfnumber(res, "notnull_invalidoid");
    9318         468 :     i_notnull_noinherit = PQfnumber(res, "notnull_noinherit");
    9319         468 :     i_notnull_islocal = PQfnumber(res, "notnull_islocal");
    9320         468 :     i_attoptions = PQfnumber(res, "attoptions");
    9321         468 :     i_attcollation = PQfnumber(res, "attcollation");
    9322         468 :     i_attcompression = PQfnumber(res, "attcompression");
    9323         468 :     i_attfdwoptions = PQfnumber(res, "attfdwoptions");
    9324         468 :     i_attmissingval = PQfnumber(res, "attmissingval");
    9325         468 :     i_atthasdef = PQfnumber(res, "atthasdef");
    9326             : 
    9327             :     /* Within the next loop, we'll accumulate OIDs of tables with defaults */
    9328         468 :     resetPQExpBuffer(tbloids);
    9329         468 :     appendPQExpBufferChar(tbloids, '{');
    9330             : 
    9331             :     /*
    9332             :      * Outer loop iterates once per table, not once per row.  Incrementing of
    9333             :      * r is handled by the inner loop.
    9334             :      */
    9335         468 :     curtblindx = -1;
    9336       18582 :     for (int r = 0; r < ntups;)
    9337             :     {
    9338       18114 :         Oid         attrelid = atooid(PQgetvalue(res, r, i_attrelid));
    9339       18114 :         TableInfo  *tbinfo = NULL;
    9340             :         int         numatts;
    9341             :         bool        hasdefaults;
    9342             : 
    9343             :         /* Count rows for this table */
    9344       68800 :         for (numatts = 1; numatts < ntups - r; numatts++)
    9345       68452 :             if (atooid(PQgetvalue(res, r + numatts, i_attrelid)) != attrelid)
    9346       17766 :                 break;
    9347             : 
    9348             :         /*
    9349             :          * Locate the associated TableInfo; we rely on tblinfo[] being in OID
    9350             :          * order.
    9351             :          */
    9352       88102 :         while (++curtblindx < numTables)
    9353             :         {
    9354       88102 :             tbinfo = &tblinfo[curtblindx];
    9355       88102 :             if (tbinfo->dobj.catId.oid == attrelid)
    9356       18114 :                 break;
    9357             :         }
    9358       18114 :         if (curtblindx >= numTables)
    9359           0 :             pg_fatal("unrecognized table OID %u", attrelid);
    9360             :         /* cross-check that we only got requested tables */
    9361       18114 :         if (tbinfo->relkind == RELKIND_SEQUENCE ||
    9362       18114 :             (!tbinfo->interesting &&
    9363         124 :              !(fout->dopt->binary_upgrade && fout->remoteVersion >= 120000 &&
    9364         124 :                (tbinfo->dobj.catId.oid == LargeObjectMetadataRelationId ||
    9365          62 :                 tbinfo->dobj.catId.oid == SharedDependRelationId))))
    9366           0 :             pg_fatal("unexpected column data for table \"%s\"",
    9367             :                      tbinfo->dobj.name);
    9368             : 
    9369             :         /* Save data for this table */
    9370       18114 :         tbinfo->numatts = numatts;
    9371       18114 :         tbinfo->attnames = (char **) pg_malloc(numatts * sizeof(char *));
    9372       18114 :         tbinfo->atttypnames = (char **) pg_malloc(numatts * sizeof(char *));
    9373       18114 :         tbinfo->attstattarget = (int *) pg_malloc(numatts * sizeof(int));
    9374       18114 :         tbinfo->attstorage = (char *) pg_malloc(numatts * sizeof(char));
    9375       18114 :         tbinfo->typstorage = (char *) pg_malloc(numatts * sizeof(char));
    9376       18114 :         tbinfo->attidentity = (char *) pg_malloc(numatts * sizeof(char));
    9377       18114 :         tbinfo->attgenerated = (char *) pg_malloc(numatts * sizeof(char));
    9378       18114 :         tbinfo->attisdropped = (bool *) pg_malloc(numatts * sizeof(bool));
    9379       18114 :         tbinfo->attlen = (int *) pg_malloc(numatts * sizeof(int));
    9380       18114 :         tbinfo->attalign = (char *) pg_malloc(numatts * sizeof(char));
    9381       18114 :         tbinfo->attislocal = (bool *) pg_malloc(numatts * sizeof(bool));
    9382       18114 :         tbinfo->attoptions = (char **) pg_malloc(numatts * sizeof(char *));
    9383       18114 :         tbinfo->attcollation = (Oid *) pg_malloc(numatts * sizeof(Oid));
    9384       18114 :         tbinfo->attcompression = (char *) pg_malloc(numatts * sizeof(char));
    9385       18114 :         tbinfo->attfdwoptions = (char **) pg_malloc(numatts * sizeof(char *));
    9386       18114 :         tbinfo->attmissingval = (char **) pg_malloc(numatts * sizeof(char *));
    9387       18114 :         tbinfo->notnull_constrs = (char **) pg_malloc(numatts * sizeof(char *));
    9388       18114 :         tbinfo->notnull_comment = (char **) pg_malloc(numatts * sizeof(char *));
    9389       18114 :         tbinfo->notnull_invalid = (bool *) pg_malloc(numatts * sizeof(bool));
    9390       18114 :         tbinfo->notnull_noinh = (bool *) pg_malloc(numatts * sizeof(bool));
    9391       18114 :         tbinfo->notnull_islocal = (bool *) pg_malloc(numatts * sizeof(bool));
    9392       18114 :         tbinfo->attrdefs = (AttrDefInfo **) pg_malloc(numatts * sizeof(AttrDefInfo *));
    9393       18114 :         hasdefaults = false;
    9394             : 
    9395       86914 :         for (int j = 0; j < numatts; j++, r++)
    9396             :         {
    9397       68800 :             if (j + 1 != atoi(PQgetvalue(res, r, i_attnum)))
    9398           0 :                 pg_fatal("invalid column numbering in table \"%s\"",
    9399             :                          tbinfo->dobj.name);
    9400       68800 :             tbinfo->attnames[j] = pg_strdup(PQgetvalue(res, r, i_attname));
    9401       68800 :             tbinfo->atttypnames[j] = pg_strdup(PQgetvalue(res, r, i_atttypname));
    9402       68800 :             if (PQgetisnull(res, r, i_attstattarget))
    9403       68712 :                 tbinfo->attstattarget[j] = -1;
    9404             :             else
    9405          88 :                 tbinfo->attstattarget[j] = atoi(PQgetvalue(res, r, i_attstattarget));
    9406       68800 :             tbinfo->attstorage[j] = *(PQgetvalue(res, r, i_attstorage));
    9407       68800 :             tbinfo->typstorage[j] = *(PQgetvalue(res, r, i_typstorage));
    9408       68800 :             tbinfo->attidentity[j] = *(PQgetvalue(res, r, i_attidentity));
    9409       68800 :             tbinfo->attgenerated[j] = *(PQgetvalue(res, r, i_attgenerated));
    9410       68800 :             tbinfo->needs_override = tbinfo->needs_override || (tbinfo->attidentity[j] == ATTRIBUTE_IDENTITY_ALWAYS);
    9411       68800 :             tbinfo->attisdropped[j] = (PQgetvalue(res, r, i_attisdropped)[0] == 't');
    9412       68800 :             tbinfo->attlen[j] = atoi(PQgetvalue(res, r, i_attlen));
    9413       68800 :             tbinfo->attalign[j] = *(PQgetvalue(res, r, i_attalign));
    9414       68800 :             tbinfo->attislocal[j] = (PQgetvalue(res, r, i_attislocal)[0] == 't');
    9415             : 
    9416             :             /* Handle not-null constraint name and flags */
    9417       68800 :             determineNotNullFlags(fout, res, r,
    9418             :                                   tbinfo, j,
    9419             :                                   i_notnull_name,
    9420             :                                   i_notnull_comment,
    9421             :                                   i_notnull_invalidoid,
    9422             :                                   i_notnull_noinherit,
    9423             :                                   i_notnull_islocal,
    9424             :                                   &invalidnotnulloids);
    9425             : 
    9426       68800 :             tbinfo->notnull_comment[j] = PQgetisnull(res, r, i_notnull_comment) ?
    9427       68800 :                 NULL : pg_strdup(PQgetvalue(res, r, i_notnull_comment));
    9428       68800 :             tbinfo->attoptions[j] = pg_strdup(PQgetvalue(res, r, i_attoptions));
    9429       68800 :             tbinfo->attcollation[j] = atooid(PQgetvalue(res, r, i_attcollation));
    9430       68800 :             tbinfo->attcompression[j] = *(PQgetvalue(res, r, i_attcompression));
    9431       68800 :             tbinfo->attfdwoptions[j] = pg_strdup(PQgetvalue(res, r, i_attfdwoptions));
    9432       68800 :             tbinfo->attmissingval[j] = pg_strdup(PQgetvalue(res, r, i_attmissingval));
    9433       68800 :             tbinfo->attrdefs[j] = NULL; /* fix below */
    9434       68800 :             if (PQgetvalue(res, r, i_atthasdef)[0] == 't')
    9435        3420 :                 hasdefaults = true;
    9436             :         }
    9437             : 
    9438       18114 :         if (hasdefaults)
    9439             :         {
    9440             :             /* Collect OIDs of interesting tables that have defaults */
    9441        2598 :             if (tbloids->len > 1) /* do we have more than the '{'? */
    9442        2448 :                 appendPQExpBufferChar(tbloids, ',');
    9443        2598 :             appendPQExpBuffer(tbloids, "%u", tbinfo->dobj.catId.oid);
    9444             :         }
    9445             :     }
    9446             : 
    9447             :     /* If invalidnotnulloids has any data, finalize it */
    9448         468 :     if (invalidnotnulloids != NULL)
    9449         100 :         appendPQExpBufferChar(invalidnotnulloids, '}');
    9450             : 
    9451         468 :     PQclear(res);
    9452             : 
    9453             :     /*
    9454             :      * Now get info about column defaults.  This is skipped for a data-only
    9455             :      * dump, as it is only needed for table schemas.
    9456             :      */
    9457         468 :     if (dopt->dumpSchema && tbloids->len > 1)
    9458             :     {
    9459             :         AttrDefInfo *attrdefs;
    9460             :         int         numDefaults;
    9461         134 :         TableInfo  *tbinfo = NULL;
    9462             : 
    9463         134 :         pg_log_info("finding table default expressions");
    9464             : 
    9465         134 :         appendPQExpBufferChar(tbloids, '}');
    9466             : 
    9467         134 :         printfPQExpBuffer(q, "SELECT a.tableoid, a.oid, adrelid, adnum, "
    9468             :                           "pg_catalog.pg_get_expr(adbin, adrelid) AS adsrc\n"
    9469             :                           "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
    9470             :                           "JOIN pg_catalog.pg_attrdef a ON (src.tbloid = a.adrelid)\n"
    9471             :                           "ORDER BY a.adrelid, a.adnum",
    9472             :                           tbloids->data);
    9473             : 
    9474         134 :         res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
    9475             : 
    9476         134 :         numDefaults = PQntuples(res);
    9477         134 :         attrdefs = (AttrDefInfo *) pg_malloc(numDefaults * sizeof(AttrDefInfo));
    9478             : 
    9479         134 :         curtblindx = -1;
    9480        3358 :         for (int j = 0; j < numDefaults; j++)
    9481             :         {
    9482        3224 :             Oid         adtableoid = atooid(PQgetvalue(res, j, 0));
    9483        3224 :             Oid         adoid = atooid(PQgetvalue(res, j, 1));
    9484        3224 :             Oid         adrelid = atooid(PQgetvalue(res, j, 2));
    9485        3224 :             int         adnum = atoi(PQgetvalue(res, j, 3));
    9486        3224 :             char       *adsrc = PQgetvalue(res, j, 4);
    9487             : 
    9488             :             /*
    9489             :              * Locate the associated TableInfo; we rely on tblinfo[] being in
    9490             :              * OID order.
    9491             :              */
    9492        3224 :             if (tbinfo == NULL || tbinfo->dobj.catId.oid != adrelid)
    9493             :             {
    9494       45744 :                 while (++curtblindx < numTables)
    9495             :                 {
    9496       45744 :                     tbinfo = &tblinfo[curtblindx];
    9497       45744 :                     if (tbinfo->dobj.catId.oid == adrelid)
    9498        2462 :                         break;
    9499             :                 }
    9500        2462 :                 if (curtblindx >= numTables)
    9501           0 :                     pg_fatal("unrecognized table OID %u", adrelid);
    9502             :             }
    9503             : 
    9504        3224 :             if (adnum <= 0 || adnum > tbinfo->numatts)
    9505           0 :                 pg_fatal("invalid adnum value %d for table \"%s\"",
    9506             :                          adnum, tbinfo->dobj.name);
    9507             : 
    9508             :             /*
    9509             :              * dropped columns shouldn't have defaults, but just in case,
    9510             :              * ignore 'em
    9511             :              */
    9512        3224 :             if (tbinfo->attisdropped[adnum - 1])
    9513           0 :                 continue;
    9514             : 
    9515        3224 :             attrdefs[j].dobj.objType = DO_ATTRDEF;
    9516        3224 :             attrdefs[j].dobj.catId.tableoid = adtableoid;
    9517        3224 :             attrdefs[j].dobj.catId.oid = adoid;
    9518        3224 :             AssignDumpId(&attrdefs[j].dobj);
    9519        3224 :             attrdefs[j].adtable = tbinfo;
    9520        3224 :             attrdefs[j].adnum = adnum;
    9521        3224 :             attrdefs[j].adef_expr = pg_strdup(adsrc);
    9522             : 
    9523        3224 :             attrdefs[j].dobj.name = pg_strdup(tbinfo->dobj.name);
    9524        3224 :             attrdefs[j].dobj.namespace = tbinfo->dobj.namespace;
    9525             : 
    9526        3224 :             attrdefs[j].dobj.dump = tbinfo->dobj.dump;
    9527             : 
    9528             :             /*
    9529             :              * Figure out whether the default/generation expression should be
    9530             :              * dumped as part of the main CREATE TABLE (or similar) command or
    9531             :              * as a separate ALTER TABLE (or similar) command. The preference
    9532             :              * is to put it into the CREATE command, but in some cases that's
    9533             :              * not possible.
    9534             :              */
    9535        3224 :             if (tbinfo->attgenerated[adnum - 1])
    9536             :             {
    9537             :                 /*
    9538             :                  * Column generation expressions cannot be dumped separately,
    9539             :                  * because there is no syntax for it.  By setting separate to
    9540             :                  * false here we prevent the "default" from being processed as
    9541             :                  * its own dumpable object.  Later, flagInhAttrs() will mark
    9542             :                  * it as not to be dumped at all, if possible (that is, if it
    9543             :                  * can be inherited from a parent).
    9544             :                  */
    9545        1856 :                 attrdefs[j].separate = false;
    9546             :             }
    9547        1368 :             else if (tbinfo->relkind == RELKIND_VIEW)
    9548             :             {
    9549             :                 /*
    9550             :                  * Defaults on a VIEW must always be dumped as separate ALTER
    9551             :                  * TABLE commands.
    9552             :                  */
    9553          72 :                 attrdefs[j].separate = true;
    9554             :             }
    9555        1296 :             else if (!shouldPrintColumn(dopt, tbinfo, adnum - 1))
    9556             :             {
    9557             :                 /* column will be suppressed, print default separately */
    9558          14 :                 attrdefs[j].separate = true;
    9559             :             }
    9560             :             else
    9561             :             {
    9562        1282 :                 attrdefs[j].separate = false;
    9563             :             }
    9564             : 
    9565        3224 :             if (!attrdefs[j].separate)
    9566             :             {
    9567             :                 /*
    9568             :                  * Mark the default as needing to appear before the table, so
    9569             :                  * that any dependencies it has must be emitted before the
    9570             :                  * CREATE TABLE.  If this is not possible, we'll change to
    9571             :                  * "separate" mode while sorting dependencies.
    9572             :                  */
    9573        3138 :                 addObjectDependency(&tbinfo->dobj,
    9574        3138 :                                     attrdefs[j].dobj.dumpId);
    9575             :             }
    9576             : 
    9577        3224 :             tbinfo->attrdefs[adnum - 1] = &attrdefs[j];
    9578             :         }
    9579             : 
    9580         134 :         PQclear(res);
    9581             :     }
    9582             : 
    9583             :     /*
    9584             :      * Get info about NOT NULL NOT VALID constraints.  This is skipped for a
    9585             :      * data-only dump, as it is only needed for table schemas.
    9586             :      */
    9587         468 :     if (dopt->dumpSchema && invalidnotnulloids)
    9588             :     {
    9589             :         ConstraintInfo *constrs;
    9590             :         int         numConstrs;
    9591             :         int         i_tableoid;
    9592             :         int         i_oid;
    9593             :         int         i_conrelid;
    9594             :         int         i_conname;
    9595             :         int         i_consrc;
    9596             :         int         i_conislocal;
    9597             : 
    9598          88 :         pg_log_info("finding invalid not-null constraints");
    9599             : 
    9600          88 :         resetPQExpBuffer(q);
    9601          88 :         appendPQExpBuffer(q,
    9602             :                           "SELECT c.tableoid, c.oid, conrelid, conname, "
    9603             :                           "pg_catalog.pg_get_constraintdef(c.oid) AS consrc, "
    9604             :                           "conislocal, convalidated "
    9605             :                           "FROM unnest('%s'::pg_catalog.oid[]) AS src(conoid)\n"
    9606             :                           "JOIN pg_catalog.pg_constraint c ON (src.conoid = c.oid)\n"
    9607             :                           "ORDER BY c.conrelid, c.conname",
    9608          88 :                           invalidnotnulloids->data);
    9609             : 
    9610          88 :         res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
    9611             : 
    9612          88 :         numConstrs = PQntuples(res);
    9613          88 :         constrs = (ConstraintInfo *) pg_malloc(numConstrs * sizeof(ConstraintInfo));
    9614             : 
    9615          88 :         i_tableoid = PQfnumber(res, "tableoid");
    9616          88 :         i_oid = PQfnumber(res, "oid");
    9617          88 :         i_conrelid = PQfnumber(res, "conrelid");
    9618          88 :         i_conname = PQfnumber(res, "conname");
    9619          88 :         i_consrc = PQfnumber(res, "consrc");
    9620          88 :         i_conislocal = PQfnumber(res, "conislocal");
    9621             : 
    9622             :         /* As above, this loop iterates once per table, not once per row */
    9623          88 :         curtblindx = -1;
    9624         272 :         for (int j = 0; j < numConstrs;)
    9625             :         {
    9626         184 :             Oid         conrelid = atooid(PQgetvalue(res, j, i_conrelid));
    9627         184 :             TableInfo  *tbinfo = NULL;
    9628             :             int         numcons;
    9629             : 
    9630             :             /* Count rows for this table */
    9631         184 :             for (numcons = 1; numcons < numConstrs - j; numcons++)
    9632          96 :                 if (atooid(PQgetvalue(res, j + numcons, i_conrelid)) != conrelid)
    9633          96 :                     break;
    9634             : 
    9635             :             /*
    9636             :              * Locate the associated TableInfo; we rely on tblinfo[] being in
    9637             :              * OID order.
    9638             :              */
    9639       31630 :             while (++curtblindx < numTables)
    9640             :             {
    9641       31630 :                 tbinfo = &tblinfo[curtblindx];
    9642       31630 :                 if (tbinfo->dobj.catId.oid == conrelid)
    9643         184 :                     break;
    9644             :             }
    9645         184 :             if (curtblindx >= numTables)
    9646           0 :                 pg_fatal("unrecognized table OID %u", conrelid);
    9647             : 
    9648         368 :             for (int c = 0; c < numcons; c++, j++)
    9649             :             {
    9650         184 :                 constrs[j].dobj.objType = DO_CONSTRAINT;
    9651         184 :                 constrs[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
    9652         184 :                 constrs[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
    9653         184 :                 AssignDumpId(&constrs[j].dobj);
    9654         184 :                 constrs[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_conname));
    9655         184 :                 constrs[j].dobj.namespace = tbinfo->dobj.namespace;
    9656         184 :                 constrs[j].contable = tbinfo;
    9657         184 :                 constrs[j].condomain = NULL;
    9658         184 :                 constrs[j].contype = 'n';
    9659         184 :                 constrs[j].condef = pg_strdup(PQgetvalue(res, j, i_consrc));
    9660         184 :                 constrs[j].confrelid = InvalidOid;
    9661         184 :                 constrs[j].conindex = 0;
    9662         184 :                 constrs[j].condeferrable = false;
    9663         184 :                 constrs[j].condeferred = false;
    9664         184 :                 constrs[j].conislocal = (PQgetvalue(res, j, i_conislocal)[0] == 't');
    9665             : 
    9666             :                 /*
    9667             :                  * All invalid not-null constraints must be dumped separately,
    9668             :                  * because CREATE TABLE would not create them as invalid, and
    9669             :                  * also because they must be created after potentially
    9670             :                  * violating data has been loaded.
    9671             :                  */
    9672         184 :                 constrs[j].separate = true;
    9673             : 
    9674         184 :                 constrs[j].dobj.dump = tbinfo->dobj.dump;
    9675             :             }
    9676             :         }
    9677          88 :         PQclear(res);
    9678             :     }
    9679             : 
    9680             :     /*
    9681             :      * Get info about table CHECK constraints.  This is skipped for a
    9682             :      * data-only dump, as it is only needed for table schemas.
    9683             :      */
    9684         468 :     if (dopt->dumpSchema && checkoids->len > 2)
    9685             :     {
    9686             :         ConstraintInfo *constrs;
    9687             :         int         numConstrs;
    9688             :         int         i_tableoid;
    9689             :         int         i_oid;
    9690             :         int         i_conrelid;
    9691             :         int         i_conname;
    9692             :         int         i_consrc;
    9693             :         int         i_conislocal;
    9694             :         int         i_convalidated;
    9695             : 
    9696         136 :         pg_log_info("finding table check constraints");
    9697             : 
    9698         136 :         resetPQExpBuffer(q);
    9699         136 :         appendPQExpBuffer(q,
    9700             :                           "SELECT c.tableoid, c.oid, conrelid, conname, "
    9701             :                           "pg_catalog.pg_get_constraintdef(c.oid) AS consrc, "
    9702             :                           "conislocal, convalidated "
    9703             :                           "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
    9704             :                           "JOIN pg_catalog.pg_constraint c ON (src.tbloid = c.conrelid)\n"
    9705             :                           "WHERE contype = 'c' "
    9706             :                           "ORDER BY c.conrelid, c.conname",
    9707             :                           checkoids->data);
    9708             : 
    9709         136 :         res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
    9710             : 
    9711         136 :         numConstrs = PQntuples(res);
    9712         136 :         constrs = (ConstraintInfo *) pg_malloc(numConstrs * sizeof(ConstraintInfo));
    9713             : 
    9714         136 :         i_tableoid = PQfnumber(res, "tableoid");
    9715         136 :         i_oid = PQfnumber(res, "oid");
    9716         136 :         i_conrelid = PQfnumber(res, "conrelid");
    9717         136 :         i_conname = PQfnumber(res, "conname");
    9718         136 :         i_consrc = PQfnumber(res, "consrc");
    9719         136 :         i_conislocal = PQfnumber(res, "conislocal");
    9720         136 :         i_convalidated = PQfnumber(res, "convalidated");
    9721             : 
    9722             :         /* As above, this loop iterates once per table, not once per row */
    9723         136 :         curtblindx = -1;
    9724        1396 :         for (int j = 0; j < numConstrs;)
    9725             :         {
    9726        1260 :             Oid         conrelid = atooid(PQgetvalue(res, j, i_conrelid));
    9727        1260 :             TableInfo  *tbinfo = NULL;
    9728             :             int         numcons;
    9729             : 
    9730             :             /* Count rows for this table */
    9731        1630 :             for (numcons = 1; numcons < numConstrs - j; numcons++)
    9732        1494 :                 if (atooid(PQgetvalue(res, j + numcons, i_conrelid)) != conrelid)
    9733        1124 :                     break;
    9734             : 
    9735             :             /*
    9736             :              * Locate the associated TableInfo; we rely on tblinfo[] being in
    9737             :              * OID order.
    9738             :              */
    9739       43582 :             while (++curtblindx < numTables)
    9740             :             {
    9741       43582 :                 tbinfo = &tblinfo[curtblindx];
    9742       43582 :                 if (tbinfo->dobj.catId.oid == conrelid)
    9743        1260 :                     break;
    9744             :             }
    9745        1260 :             if (curtblindx >= numTables)
    9746           0 :                 pg_fatal("unrecognized table OID %u", conrelid);
    9747             : 
    9748        1260 :             if (numcons != tbinfo->ncheck)
    9749             :             {
    9750           0 :                 pg_log_error(ngettext("expected %d check constraint on table \"%s\" but found %d",
    9751             :                                       "expected %d check constraints on table \"%s\" but found %d",
    9752             :                                       tbinfo->ncheck),
    9753             :                              tbinfo->ncheck, tbinfo->dobj.name, numcons);
    9754           0 :                 pg_log_error_hint("The system catalogs might be corrupted.");
    9755           0 :                 exit_nicely(1);
    9756             :             }
    9757             : 
    9758        1260 :             tbinfo->checkexprs = constrs + j;
    9759             : 
    9760        2890 :             for (int c = 0; c < numcons; c++, j++)
    9761             :             {
    9762        1630 :                 bool        validated = PQgetvalue(res, j, i_convalidated)[0] == 't';
    9763             : 
    9764        1630 :                 constrs[j].dobj.objType = DO_CONSTRAINT;
    9765        1630 :                 constrs[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
    9766        1630 :                 constrs[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
    9767        1630 :                 AssignDumpId(&constrs[j].dobj);
    9768        1630 :                 constrs[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_conname));
    9769        1630 :                 constrs[j].dobj.namespace = tbinfo->dobj.namespace;
    9770        1630 :                 constrs[j].contable = tbinfo;
    9771        1630 :                 constrs[j].condomain = NULL;
    9772        1630 :                 constrs[j].contype = 'c';
    9773        1630 :                 constrs[j].condef = pg_strdup(PQgetvalue(res, j, i_consrc));
    9774        1630 :                 constrs[j].confrelid = InvalidOid;
    9775        1630 :                 constrs[j].conindex = 0;
    9776        1630 :                 constrs[j].condeferrable = false;
    9777        1630 :                 constrs[j].condeferred = false;
    9778        1630 :                 constrs[j].conislocal = (PQgetvalue(res, j, i_conislocal)[0] == 't');
    9779             : 
    9780             :                 /*
    9781             :                  * An unvalidated constraint needs to be dumped separately, so
    9782             :                  * that potentially-violating existing data is loaded before
    9783             :                  * the constraint.
    9784             :                  */
    9785        1630 :                 constrs[j].separate = !validated;
    9786             : 
    9787        1630 :                 constrs[j].dobj.dump = tbinfo->dobj.dump;
    9788             : 
    9789             :                 /*
    9790             :                  * Mark the constraint as needing to appear before the table
    9791             :                  * --- this is so that any other dependencies of the
    9792             :                  * constraint will be emitted before we try to create the
    9793             :                  * table.  If the constraint is to be dumped separately, it
    9794             :                  * will be dumped after data is loaded anyway, so don't do it.
    9795             :                  * (There's an automatic dependency in the opposite direction
    9796             :                  * anyway, so don't need to add one manually here.)
    9797             :                  */
    9798        1630 :                 if (!constrs[j].separate)
    9799        1422 :                     addObjectDependency(&tbinfo->dobj,
    9800        1422 :                                         constrs[j].dobj.dumpId);
    9801             : 
    9802             :                 /*
    9803             :                  * We will detect later whether the constraint must be split
    9804             :                  * out from the table definition.
    9805             :                  */
    9806             :             }
    9807             :         }
    9808             : 
    9809         136 :         PQclear(res);
    9810             :     }
    9811             : 
    9812         468 :     destroyPQExpBuffer(q);
    9813         468 :     destroyPQExpBuffer(tbloids);
    9814         468 :     destroyPQExpBuffer(checkoids);
    9815         468 : }
    9816             : 
    9817             : /*
    9818             :  * Based on the getTableAttrs query's row corresponding to one column, set
    9819             :  * the name and flags to handle a not-null constraint for that column in
    9820             :  * the tbinfo struct.
    9821             :  *
    9822             :  * Result row 'r' is for tbinfo's attribute 'j'.
    9823             :  *
    9824             :  * There are four possibilities:
    9825             :  * 1) the column has no not-null constraints. In that case, ->notnull_constrs
    9826             :  *    (the constraint name) remains NULL.
    9827             :  * 2) The column has a constraint with no name (this is the case when
    9828             :  *    constraints come from pre-18 servers).  In this case, ->notnull_constrs
    9829             :  *    is set to the empty string; dumpTableSchema will print just "NOT NULL".
    9830             :  * 3) The column has an invalid not-null constraint.  This must be treated
    9831             :  *    as a separate object (because it must be created after the table data
    9832             :  *    is loaded).  So we add its OID to invalidnotnulloids for processing
    9833             :  *    elsewhere and do nothing further with it here.  We distinguish this
    9834             :  *    case because the "notnull_invalidoid" column has been set to a non-NULL
    9835             :  *    value, which is the constraint OID.  Valid constraints have a null OID.
    9836             :  * 4) The column has a constraint with a known name; in that case
    9837             :  *    notnull_constrs carries that name and dumpTableSchema will print
    9838             :  *    "CONSTRAINT the_name NOT NULL".  However, if the name is the default
    9839             :  *    (table_column_not_null) and there's no comment on the constraint,
    9840             :  *    there's no need to print that name in the dump, so notnull_constrs
    9841             :  *    is set to the empty string and it behaves as case 2.
    9842             :  *
    9843             :  * In a child table that inherits from a parent already containing NOT NULL
    9844             :  * constraints and the columns in the child don't have their own NOT NULL
    9845             :  * declarations, we suppress printing constraints in the child: the
    9846             :  * constraints are acquired at the point where the child is attached to the
    9847             :  * parent.  This is tracked in ->notnull_islocal; for servers pre-18 this is
    9848             :  * set not here but in flagInhAttrs.  That flag is also used when the
    9849             :  * constraint was validated in a child but all its parent have it as NOT
    9850             :  * VALID.
    9851             :  *
    9852             :  * Any of these constraints might have the NO INHERIT bit.  If so we set
    9853             :  * ->notnull_noinh and NO INHERIT will be printed by dumpTableSchema.
    9854             :  *
    9855             :  * In case 4 above, the name comparison is a bit of a hack; it actually fails
    9856             :  * to do the right thing in all but the trivial case.  However, the downside
    9857             :  * of getting it wrong is simply that the name is printed rather than
    9858             :  * suppressed, so it's not a big deal.
    9859             :  *
    9860             :  * invalidnotnulloids is expected to be given as NULL; if any invalid not-null
    9861             :  * constraints are found, it is initialized and filled with the array of
    9862             :  * OIDs of such constraints, for later processing.
    9863             :  */
    9864             : static void
    9865       68800 : determineNotNullFlags(Archive *fout, PGresult *res, int r,
    9866             :                       TableInfo *tbinfo, int j,
    9867             :                       int i_notnull_name,
    9868             :                       int i_notnull_comment,
    9869             :                       int i_notnull_invalidoid,
    9870             :                       int i_notnull_noinherit,
    9871             :                       int i_notnull_islocal,
    9872             :                       PQExpBuffer *invalidnotnulloids)
    9873             : {
    9874       68800 :     DumpOptions *dopt = fout->dopt;
    9875             : 
    9876             :     /*
    9877             :      * If this not-null constraint is not valid, list its OID in
    9878             :      * invalidnotnulloids and do nothing further.  It'll be processed
    9879             :      * elsewhere later.
    9880             :      *
    9881             :      * Because invalid not-null constraints are rare, we don't want to malloc
    9882             :      * invalidnotnulloids until we're sure we're going it need it, which
    9883             :      * happens here.
    9884             :      */
    9885       68800 :     if (!PQgetisnull(res, r, i_notnull_invalidoid))
    9886             :     {
    9887         196 :         char       *constroid = PQgetvalue(res, r, i_notnull_invalidoid);
    9888             : 
    9889         196 :         if (*invalidnotnulloids == NULL)
    9890             :         {
    9891         100 :             *invalidnotnulloids = createPQExpBuffer();
    9892         100 :             appendPQExpBufferChar(*invalidnotnulloids, '{');
    9893         100 :             appendPQExpBufferStr(*invalidnotnulloids, constroid);
    9894             :         }
    9895             :         else
    9896          96 :             appendPQExpBuffer(*invalidnotnulloids, ",%s", constroid);
    9897             : 
    9898             :         /*
    9899             :          * Track when a parent constraint is invalid for the cases where a
    9900             :          * child constraint has been validated independenly.
    9901             :          */
    9902         196 :         tbinfo->notnull_invalid[j] = true;
    9903             : 
    9904             :         /* nothing else to do */
    9905         196 :         tbinfo->notnull_constrs[j] = NULL;
    9906         196 :         return;
    9907             :     }
    9908             : 
    9909             :     /*
    9910             :      * notnull_noinh is straight from the query result. notnull_islocal also,
    9911             :      * though flagInhAttrs may change that one later.
    9912             :      */
    9913       68604 :     tbinfo->notnull_noinh[j] = PQgetvalue(res, r, i_notnull_noinherit)[0] == 't';
    9914       68604 :     tbinfo->notnull_islocal[j] = PQgetvalue(res, r, i_notnull_islocal)[0] == 't';
    9915       68604 :     tbinfo->notnull_invalid[j] = false;
    9916             : 
    9917             :     /*
    9918             :      * Determine a constraint name to use.  If the column is not marked not-
    9919             :      * null, we set NULL which cues ... to do nothing.  An empty string says
    9920             :      * to print an unnamed NOT NULL, and anything else is a constraint name to
    9921             :      * use.
    9922             :      */
    9923       68604 :     if (fout->remoteVersion < 180000)
    9924             :     {
    9925             :         /*
    9926             :          * < 18 doesn't have not-null names, so an unnamed constraint is
    9927             :          * sufficient.
    9928             :          */
    9929           0 :         if (PQgetisnull(res, r, i_notnull_name))
    9930           0 :             tbinfo->notnull_constrs[j] = NULL;
    9931             :         else
    9932           0 :             tbinfo->notnull_constrs[j] = "";
    9933             :     }
    9934             :     else
    9935             :     {
    9936       68604 :         if (PQgetisnull(res, r, i_notnull_name))
    9937       61638 :             tbinfo->notnull_constrs[j] = NULL;
    9938             :         else
    9939             :         {
    9940             :             /*
    9941             :              * In binary upgrade of inheritance child tables, must have a
    9942             :              * constraint name that we can UPDATE later; same if there's a
    9943             :              * comment on the constraint.
    9944             :              */
    9945        6966 :             if ((dopt->binary_upgrade &&
    9946         642 :                  !tbinfo->ispartition &&
    9947        7452 :                  !tbinfo->notnull_islocal) ||
    9948        6966 :                 !PQgetisnull(res, r, i_notnull_comment))
    9949             :             {
    9950         116 :                 tbinfo->notnull_constrs[j] =
    9951         116 :                     pstrdup(PQgetvalue(res, r, i_notnull_name));
    9952             :             }
    9953             :             else
    9954             :             {
    9955             :                 char       *default_name;
    9956             : 
    9957             :                 /* XXX should match ChooseConstraintName better */
    9958        6850 :                 default_name = psprintf("%s_%s_not_null", tbinfo->dobj.name,
    9959        6850 :                                         tbinfo->attnames[j]);
    9960        6850 :                 if (strcmp(default_name,
    9961        6850 :                            PQgetvalue(res, r, i_notnull_name)) == 0)
    9962        4546 :                     tbinfo->notnull_constrs[j] = "";
    9963             :                 else
    9964             :                 {
    9965        2304 :                     tbinfo->notnull_constrs[j] =
    9966        2304 :                         pstrdup(PQgetvalue(res, r, i_notnull_name));
    9967             :                 }
    9968        6850 :                 free(default_name);
    9969             :             }
    9970             :         }
    9971             :     }
    9972             : }
    9973             : 
    9974             : /*
    9975             :  * Test whether a column should be printed as part of table's CREATE TABLE.
    9976             :  * Column number is zero-based.
    9977             :  *
    9978             :  * Normally this is always true, but it's false for dropped columns, as well
    9979             :  * as those that were inherited without any local definition.  (If we print
    9980             :  * such a column it will mistakenly get pg_attribute.attislocal set to true.)
    9981             :  * For partitions, it's always true, because we want the partitions to be
    9982             :  * created independently and ATTACH PARTITION used afterwards.
    9983             :  *
    9984             :  * In binary_upgrade mode, we must print all columns and fix the attislocal/
    9985             :  * attisdropped state later, so as to keep control of the physical column
    9986             :  * order.
    9987             :  *
    9988             :  * This function exists because there are scattered nonobvious places that
    9989             :  * must be kept in sync with this decision.
    9990             :  */
    9991             : bool
    9992      117436 : shouldPrintColumn(const DumpOptions *dopt, const TableInfo *tbinfo, int colno)
    9993             : {
    9994      117436 :     if (dopt->binary_upgrade)
    9995       12340 :         return true;
    9996      105096 :     if (tbinfo->attisdropped[colno])
    9997        2132 :         return false;
    9998      102964 :     return (tbinfo->attislocal[colno] || tbinfo->ispartition);
    9999             : }
   10000             : 
   10001             : 
   10002             : /*
   10003             :  * getTSParsers:
   10004             :  *    get information about all text search parsers in the system catalogs
   10005             :  */
   10006             : void
   10007         468 : getTSParsers(Archive *fout)
   10008             : {
   10009             :     PGresult   *res;
   10010             :     int         ntups;
   10011             :     int         i;
   10012             :     PQExpBuffer query;
   10013             :     TSParserInfo *prsinfo;
   10014             :     int         i_tableoid;
   10015             :     int         i_oid;
   10016             :     int         i_prsname;
   10017             :     int         i_prsnamespace;
   10018             :     int         i_prsstart;
   10019             :     int         i_prstoken;
   10020             :     int         i_prsend;
   10021             :     int         i_prsheadline;
   10022             :     int         i_prslextype;
   10023             : 
   10024         468 :     query = createPQExpBuffer();
   10025             : 
   10026             :     /*
   10027             :      * find all text search objects, including builtin ones; we filter out
   10028             :      * system-defined objects at dump-out time.
   10029             :      */
   10030             : 
   10031         468 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, prsname, prsnamespace, "
   10032             :                          "prsstart::oid, prstoken::oid, "
   10033             :                          "prsend::oid, prsheadline::oid, prslextype::oid "
   10034             :                          "FROM pg_ts_parser");
   10035             : 
   10036         468 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   10037             : 
   10038         468 :     ntups = PQntuples(res);
   10039             : 
   10040         468 :     prsinfo = (TSParserInfo *) pg_malloc(ntups * sizeof(TSParserInfo));
   10041             : 
   10042         468 :     i_tableoid = PQfnumber(res, "tableoid");
   10043         468 :     i_oid = PQfnumber(res, "oid");
   10044         468 :     i_prsname = PQfnumber(res, "prsname");
   10045         468 :     i_prsnamespace = PQfnumber(res, "prsnamespace");
   10046         468 :     i_prsstart = PQfnumber(res, "prsstart");
   10047         468 :     i_prstoken = PQfnumber(res, "prstoken");
   10048         468 :     i_prsend = PQfnumber(res, "prsend");
   10049         468 :     i_prsheadline = PQfnumber(res, "prsheadline");
   10050         468 :     i_prslextype = PQfnumber(res, "prslextype");
   10051             : 
   10052        1034 :     for (i = 0; i < ntups; i++)
   10053             :     {
   10054         566 :         prsinfo[i].dobj.objType = DO_TSPARSER;
   10055         566 :         prsinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
   10056         566 :         prsinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
   10057         566 :         AssignDumpId(&prsinfo[i].dobj);
   10058         566 :         prsinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_prsname));
   10059        1132 :         prsinfo[i].dobj.namespace =
   10060         566 :             findNamespace(atooid(PQgetvalue(res, i, i_prsnamespace)));
   10061         566 :         prsinfo[i].prsstart = atooid(PQgetvalue(res, i, i_prsstart));
   10062         566 :         prsinfo[i].prstoken = atooid(PQgetvalue(res, i, i_prstoken));
   10063         566 :         prsinfo[i].prsend = atooid(PQgetvalue(res, i, i_prsend));
   10064         566 :         prsinfo[i].prsheadline = atooid(PQgetvalue(res, i, i_prsheadline));
   10065         566 :         prsinfo[i].prslextype = atooid(PQgetvalue(res, i, i_prslextype));
   10066             : 
   10067             :         /* Decide whether we want to dump it */
   10068         566 :         selectDumpableObject(&(prsinfo[i].dobj), fout);
   10069             :     }
   10070             : 
   10071         468 :     PQclear(res);
   10072             : 
   10073         468 :     destroyPQExpBuffer(query);
   10074         468 : }
   10075             : 
   10076             : /*
   10077             :  * getTSDictionaries:
   10078             :  *    get information about all text search dictionaries in the system catalogs
   10079             :  */
   10080             : void
   10081         468 : getTSDictionaries(Archive *fout)
   10082             : {
   10083             :     PGresult   *res;
   10084             :     int         ntups;
   10085             :     int         i;
   10086             :     PQExpBuffer query;
   10087             :     TSDictInfo *dictinfo;
   10088             :     int         i_tableoid;
   10089             :     int         i_oid;
   10090             :     int         i_dictname;
   10091             :     int         i_dictnamespace;
   10092             :     int         i_dictowner;
   10093             :     int         i_dicttemplate;
   10094             :     int         i_dictinitoption;
   10095             : 
   10096         468 :     query = createPQExpBuffer();
   10097             : 
   10098         468 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, dictname, "
   10099             :                          "dictnamespace, dictowner, "
   10100             :                          "dicttemplate, dictinitoption "
   10101             :                          "FROM pg_ts_dict");
   10102             : 
   10103         468 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   10104             : 
   10105         468 :     ntups = PQntuples(res);
   10106             : 
   10107         468 :     dictinfo = (TSDictInfo *) pg_malloc(ntups * sizeof(TSDictInfo));
   10108             : 
   10109         468 :     i_tableoid = PQfnumber(res, "tableoid");
   10110         468 :     i_oid = PQfnumber(res, "oid");
   10111         468 :     i_dictname = PQfnumber(res, "dictname");
   10112         468 :     i_dictnamespace = PQfnumber(res, "dictnamespace");
   10113         468 :     i_dictowner = PQfnumber(res, "dictowner");
   10114         468 :     i_dictinitoption = PQfnumber(res, "dictinitoption");
   10115         468 :     i_dicttemplate = PQfnumber(res, "dicttemplate");
   10116             : 
   10117       14786 :     for (i = 0; i < ntups; i++)
   10118             :     {
   10119       14318 :         dictinfo[i].dobj.objType = DO_TSDICT;
   10120       14318 :         dictinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
   10121       14318 :         dictinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
   10122       14318 :         AssignDumpId(&dictinfo[i].dobj);
   10123       14318 :         dictinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_dictname));
   10124       28636 :         dictinfo[i].dobj.namespace =
   10125       14318 :             findNamespace(atooid(PQgetvalue(res, i, i_dictnamespace)));
   10126       14318 :         dictinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_dictowner));
   10127       14318 :         dictinfo[i].dicttemplate = atooid(PQgetvalue(res, i, i_dicttemplate));
   10128       14318 :         if (PQgetisnull(res, i, i_dictinitoption))
   10129         566 :             dictinfo[i].dictinitoption = NULL;
   10130             :         else
   10131       13752 :             dictinfo[i].dictinitoption = pg_strdup(PQgetvalue(res, i, i_dictinitoption));
   10132             : 
   10133             :         /* Decide whether we want to dump it */
   10134       14318 :         selectDumpableObject(&(dictinfo[i].dobj), fout);
   10135             :     }
   10136             : 
   10137         468 :     PQclear(res);
   10138             : 
   10139         468 :     destroyPQExpBuffer(query);
   10140         468 : }
   10141             : 
   10142             : /*
   10143             :  * getTSTemplates:
   10144             :  *    get information about all text search templates in the system catalogs
   10145             :  */
   10146             : void
   10147         468 : getTSTemplates(Archive *fout)
   10148             : {
   10149             :     PGresult   *res;
   10150             :     int         ntups;
   10151             :     int         i;
   10152             :     PQExpBuffer query;
   10153             :     TSTemplateInfo *tmplinfo;
   10154             :     int         i_tableoid;
   10155             :     int         i_oid;
   10156             :     int         i_tmplname;
   10157             :     int         i_tmplnamespace;
   10158             :     int         i_tmplinit;
   10159             :     int         i_tmpllexize;
   10160             : 
   10161         468 :     query = createPQExpBuffer();
   10162             : 
   10163         468 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, tmplname, "
   10164             :                          "tmplnamespace, tmplinit::oid, tmpllexize::oid "
   10165             :                          "FROM pg_ts_template");
   10166             : 
   10167         468 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   10168             : 
   10169         468 :     ntups = PQntuples(res);
   10170             : 
   10171         468 :     tmplinfo = (TSTemplateInfo *) pg_malloc(ntups * sizeof(TSTemplateInfo));
   10172             : 
   10173         468 :     i_tableoid = PQfnumber(res, "tableoid");
   10174         468 :     i_oid = PQfnumber(res, "oid");
   10175         468 :     i_tmplname = PQfnumber(res, "tmplname");
   10176         468 :     i_tmplnamespace = PQfnumber(res, "tmplnamespace");
   10177         468 :     i_tmplinit = PQfnumber(res, "tmplinit");
   10178         468 :     i_tmpllexize = PQfnumber(res, "tmpllexize");
   10179             : 
   10180        2906 :     for (i = 0; i < ntups; i++)
   10181             :     {
   10182        2438 :         tmplinfo[i].dobj.objType = DO_TSTEMPLATE;
   10183        2438 :         tmplinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
   10184        2438 :         tmplinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
   10185        2438 :         AssignDumpId(&tmplinfo[i].dobj);
   10186        2438 :         tmplinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_tmplname));
   10187        4876 :         tmplinfo[i].dobj.namespace =
   10188        2438 :             findNamespace(atooid(PQgetvalue(res, i, i_tmplnamespace)));
   10189        2438 :         tmplinfo[i].tmplinit = atooid(PQgetvalue(res, i, i_tmplinit));
   10190        2438 :         tmplinfo[i].tmpllexize = atooid(PQgetvalue(res, i, i_tmpllexize));
   10191             : 
   10192             :         /* Decide whether we want to dump it */
   10193        2438 :         selectDumpableObject(&(tmplinfo[i].dobj), fout);
   10194             :     }
   10195             : 
   10196         468 :     PQclear(res);
   10197             : 
   10198         468 :     destroyPQExpBuffer(query);
   10199         468 : }
   10200             : 
   10201             : /*
   10202             :  * getTSConfigurations:
   10203             :  *    get information about all text search configurations
   10204             :  */
   10205             : void
   10206         468 : getTSConfigurations(Archive *fout)
   10207             : {
   10208             :     PGresult   *res;
   10209             :     int         ntups;
   10210             :     int         i;
   10211             :     PQExpBuffer query;
   10212             :     TSConfigInfo *cfginfo;
   10213             :     int         i_tableoid;
   10214             :     int         i_oid;
   10215             :     int         i_cfgname;
   10216             :     int         i_cfgnamespace;
   10217             :     int         i_cfgowner;
   10218             :     int         i_cfgparser;
   10219             : 
   10220         468 :     query = createPQExpBuffer();
   10221             : 
   10222         468 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, cfgname, "
   10223             :                          "cfgnamespace, cfgowner, cfgparser "
   10224             :                          "FROM pg_ts_config");
   10225             : 
   10226         468 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   10227             : 
   10228         468 :     ntups = PQntuples(res);
   10229             : 
   10230         468 :     cfginfo = (TSConfigInfo *) pg_malloc(ntups * sizeof(TSConfigInfo));
   10231             : 
   10232         468 :     i_tableoid = PQfnumber(res, "tableoid");
   10233         468 :     i_oid = PQfnumber(res, "oid");
   10234         468 :     i_cfgname = PQfnumber(res, "cfgname");
   10235         468 :     i_cfgnamespace = PQfnumber(res, "cfgnamespace");
   10236         468 :     i_cfgowner = PQfnumber(res, "cfgowner");
   10237         468 :     i_cfgparser = PQfnumber(res, "cfgparser");
   10238             : 
   10239       14686 :     for (i = 0; i < ntups; i++)
   10240             :     {
   10241       14218 :         cfginfo[i].dobj.objType = DO_TSCONFIG;
   10242       14218 :         cfginfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
   10243       14218 :         cfginfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
   10244       14218 :         AssignDumpId(&cfginfo[i].dobj);
   10245       14218 :         cfginfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_cfgname));
   10246       28436 :         cfginfo[i].dobj.namespace =
   10247       14218 :             findNamespace(atooid(PQgetvalue(res, i, i_cfgnamespace)));
   10248       14218 :         cfginfo[i].rolname = getRoleName(PQgetvalue(res, i, i_cfgowner));
   10249       14218 :         cfginfo[i].cfgparser = atooid(PQgetvalue(res, i, i_cfgparser));
   10250             : 
   10251             :         /* Decide whether we want to dump it */
   10252       14218 :         selectDumpableObject(&(cfginfo[i].dobj), fout);
   10253             :     }
   10254             : 
   10255         468 :     PQclear(res);
   10256             : 
   10257         468 :     destroyPQExpBuffer(query);
   10258         468 : }
   10259             : 
   10260             : /*
   10261             :  * getForeignDataWrappers:
   10262             :  *    get information about all foreign-data wrappers in the system catalogs
   10263             :  */
   10264             : void
   10265         468 : getForeignDataWrappers(Archive *fout)
   10266             : {
   10267             :     PGresult   *res;
   10268             :     int         ntups;
   10269             :     int         i;
   10270             :     PQExpBuffer query;
   10271             :     FdwInfo    *fdwinfo;
   10272             :     int         i_tableoid;
   10273             :     int         i_oid;
   10274             :     int         i_fdwname;
   10275             :     int         i_fdwowner;
   10276             :     int         i_fdwhandler;
   10277             :     int         i_fdwvalidator;
   10278             :     int         i_fdwacl;
   10279             :     int         i_acldefault;
   10280             :     int         i_fdwoptions;
   10281             : 
   10282         468 :     query = createPQExpBuffer();
   10283             : 
   10284         468 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, fdwname, "
   10285             :                          "fdwowner, "
   10286             :                          "fdwhandler::pg_catalog.regproc, "
   10287             :                          "fdwvalidator::pg_catalog.regproc, "
   10288             :                          "fdwacl, "
   10289             :                          "acldefault('F', fdwowner) AS acldefault, "
   10290             :                          "array_to_string(ARRAY("
   10291             :                          "SELECT quote_ident(option_name) || ' ' || "
   10292             :                          "quote_literal(option_value) "
   10293             :                          "FROM pg_options_to_table(fdwoptions) "
   10294             :                          "ORDER BY option_name"
   10295             :                          "), E',\n    ') AS fdwoptions "
   10296             :                          "FROM pg_foreign_data_wrapper");
   10297             : 
   10298         468 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   10299             : 
   10300         468 :     ntups = PQntuples(res);
   10301             : 
   10302         468 :     fdwinfo = (FdwInfo *) pg_malloc(ntups * sizeof(FdwInfo));
   10303             : 
   10304         468 :     i_tableoid = PQfnumber(res, "tableoid");
   10305         468 :     i_oid = PQfnumber(res, "oid");
   10306         468 :     i_fdwname = PQfnumber(res, "fdwname");
   10307         468 :     i_fdwowner = PQfnumber(res, "fdwowner");
   10308         468 :     i_fdwhandler = PQfnumber(res, "fdwhandler");
   10309         468 :     i_fdwvalidator = PQfnumber(res, "fdwvalidator");
   10310         468 :     i_fdwacl = PQfnumber(res, "fdwacl");
   10311         468 :     i_acldefault = PQfnumber(res, "acldefault");
   10312         468 :     i_fdwoptions = PQfnumber(res, "fdwoptions");
   10313             : 
   10314         624 :     for (i = 0; i < ntups; i++)
   10315             :     {
   10316         156 :         fdwinfo[i].dobj.objType = DO_FDW;
   10317         156 :         fdwinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
   10318         156 :         fdwinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
   10319         156 :         AssignDumpId(&fdwinfo[i].dobj);
   10320         156 :         fdwinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_fdwname));
   10321         156 :         fdwinfo[i].dobj.namespace = NULL;
   10322         156 :         fdwinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_fdwacl));
   10323         156 :         fdwinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
   10324         156 :         fdwinfo[i].dacl.privtype = 0;
   10325         156 :         fdwinfo[i].dacl.initprivs = NULL;
   10326         156 :         fdwinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_fdwowner));
   10327         156 :         fdwinfo[i].fdwhandler = pg_strdup(PQgetvalue(res, i, i_fdwhandler));
   10328         156 :         fdwinfo[i].fdwvalidator = pg_strdup(PQgetvalue(res, i, i_fdwvalidator));
   10329         156 :         fdwinfo[i].fdwoptions = pg_strdup(PQgetvalue(res, i, i_fdwoptions));
   10330             : 
   10331             :         /* Decide whether we want to dump it */
   10332         156 :         selectDumpableObject(&(fdwinfo[i].dobj), fout);
   10333             : 
   10334             :         /* Mark whether FDW has an ACL */
   10335         156 :         if (!PQgetisnull(res, i, i_fdwacl))
   10336          98 :             fdwinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
   10337             :     }
   10338             : 
   10339         468 :     PQclear(res);
   10340             : 
   10341         468 :     destroyPQExpBuffer(query);
   10342         468 : }
   10343             : 
   10344             : /*
   10345             :  * getForeignServers:
   10346             :  *    get information about all foreign servers in the system catalogs
   10347             :  */
   10348             : void
   10349         468 : getForeignServers(Archive *fout)
   10350             : {
   10351             :     PGresult   *res;
   10352             :     int         ntups;
   10353             :     int         i;
   10354             :     PQExpBuffer query;
   10355             :     ForeignServerInfo *srvinfo;
   10356             :     int         i_tableoid;
   10357             :     int         i_oid;
   10358             :     int         i_srvname;
   10359             :     int         i_srvowner;
   10360             :     int         i_srvfdw;
   10361             :     int         i_srvtype;
   10362             :     int         i_srvversion;
   10363             :     int         i_srvacl;
   10364             :     int         i_acldefault;
   10365             :     int         i_srvoptions;
   10366             : 
   10367         468 :     query = createPQExpBuffer();
   10368             : 
   10369         468 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, srvname, "
   10370             :                          "srvowner, "
   10371             :                          "srvfdw, srvtype, srvversion, srvacl, "
   10372             :                          "acldefault('S', srvowner) AS acldefault, "
   10373             :                          "array_to_string(ARRAY("
   10374             :                          "SELECT quote_ident(option_name) || ' ' || "
   10375             :                          "quote_literal(option_value) "
   10376             :                          "FROM pg_options_to_table(srvoptions) "
   10377             :                          "ORDER BY option_name"
   10378             :                          "), E',\n    ') AS srvoptions "
   10379             :                          "FROM pg_foreign_server");
   10380             : 
   10381         468 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   10382             : 
   10383         468 :     ntups = PQntuples(res);
   10384             : 
   10385         468 :     srvinfo = (ForeignServerInfo *) pg_malloc(ntups * sizeof(ForeignServerInfo));
   10386             : 
   10387         468 :     i_tableoid = PQfnumber(res, "tableoid");
   10388         468 :     i_oid = PQfnumber(res, "oid");
   10389         468 :     i_srvname = PQfnumber(res, "srvname");
   10390         468 :     i_srvowner = PQfnumber(res, "srvowner");
   10391         468 :     i_srvfdw = PQfnumber(res, "srvfdw");
   10392         468 :     i_srvtype = PQfnumber(res, "srvtype");
   10393         468 :     i_srvversion = PQfnumber(res, "srvversion");
   10394         468 :     i_srvacl = PQfnumber(res, "srvacl");
   10395         468 :     i_acldefault = PQfnumber(res, "acldefault");
   10396         468 :     i_srvoptions = PQfnumber(res, "srvoptions");
   10397             : 
   10398         632 :     for (i = 0; i < ntups; i++)
   10399             :     {
   10400         164 :         srvinfo[i].dobj.objType = DO_FOREIGN_SERVER;
   10401         164 :         srvinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
   10402         164 :         srvinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
   10403         164 :         AssignDumpId(&srvinfo[i].dobj);
   10404         164 :         srvinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_srvname));
   10405         164 :         srvinfo[i].dobj.namespace = NULL;
   10406         164 :         srvinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_srvacl));
   10407         164 :         srvinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
   10408         164 :         srvinfo[i].dacl.privtype = 0;
   10409         164 :         srvinfo[i].dacl.initprivs = NULL;
   10410         164 :         srvinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_srvowner));
   10411         164 :         srvinfo[i].srvfdw = atooid(PQgetvalue(res, i, i_srvfdw));
   10412         164 :         srvinfo[i].srvtype = pg_strdup(PQgetvalue(res, i, i_srvtype));
   10413         164 :         srvinfo[i].srvversion = pg_strdup(PQgetvalue(res, i, i_srvversion));
   10414         164 :         srvinfo[i].srvoptions = pg_strdup(PQgetvalue(res, i, i_srvoptions));
   10415             : 
   10416             :         /* Decide whether we want to dump it */
   10417         164 :         selectDumpableObject(&(srvinfo[i].dobj), fout);
   10418             : 
   10419             :         /* Servers have user mappings */
   10420         164 :         srvinfo[i].dobj.components |= DUMP_COMPONENT_USERMAP;
   10421             : 
   10422             :         /* Mark whether server has an ACL */
   10423         164 :         if (!PQgetisnull(res, i, i_srvacl))
   10424          98 :             srvinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
   10425             :     }
   10426             : 
   10427         468 :     PQclear(res);
   10428             : 
   10429         468 :     destroyPQExpBuffer(query);
   10430         468 : }
   10431             : 
   10432             : /*
   10433             :  * getDefaultACLs:
   10434             :  *    get information about all default ACL information in the system catalogs
   10435             :  */
   10436             : void
   10437         468 : getDefaultACLs(Archive *fout)
   10438             : {
   10439         468 :     DumpOptions *dopt = fout->dopt;
   10440             :     DefaultACLInfo *daclinfo;
   10441             :     PQExpBuffer query;
   10442             :     PGresult   *res;
   10443             :     int         i_oid;
   10444             :     int         i_tableoid;
   10445             :     int         i_defaclrole;
   10446             :     int         i_defaclnamespace;
   10447             :     int         i_defaclobjtype;
   10448             :     int         i_defaclacl;
   10449             :     int         i_acldefault;
   10450             :     int         i,
   10451             :                 ntups;
   10452             : 
   10453         468 :     query = createPQExpBuffer();
   10454             : 
   10455             :     /*
   10456             :      * Global entries (with defaclnamespace=0) replace the hard-wired default
   10457             :      * ACL for their object type.  We should dump them as deltas from the
   10458             :      * default ACL, since that will be used as a starting point for
   10459             :      * interpreting the ALTER DEFAULT PRIVILEGES commands.  On the other hand,
   10460             :      * non-global entries can only add privileges not revoke them.  We must
   10461             :      * dump those as-is (i.e., as deltas from an empty ACL).
   10462             :      *
   10463             :      * We can use defaclobjtype as the object type for acldefault(), except
   10464             :      * for the case of 'S' (DEFACLOBJ_SEQUENCE) which must be converted to
   10465             :      * 's'.
   10466             :      */
   10467         468 :     appendPQExpBufferStr(query,
   10468             :                          "SELECT oid, tableoid, "
   10469             :                          "defaclrole, "
   10470             :                          "defaclnamespace, "
   10471             :                          "defaclobjtype, "
   10472             :                          "defaclacl, "
   10473             :                          "CASE WHEN defaclnamespace = 0 THEN "
   10474             :                          "acldefault(CASE WHEN defaclobjtype = 'S' "
   10475             :                          "THEN 's'::\"char\" ELSE defaclobjtype END, "
   10476             :                          "defaclrole) ELSE '{}' END AS acldefault "
   10477             :                          "FROM pg_default_acl");
   10478             : 
   10479         468 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   10480             : 
   10481         468 :     ntups = PQntuples(res);
   10482             : 
   10483         468 :     daclinfo = (DefaultACLInfo *) pg_malloc(ntups * sizeof(DefaultACLInfo));
   10484             : 
   10485         468 :     i_oid = PQfnumber(res, "oid");
   10486         468 :     i_tableoid = PQfnumber(res, "tableoid");
   10487         468 :     i_defaclrole = PQfnumber(res, "defaclrole");
   10488         468 :     i_defaclnamespace = PQfnumber(res, "defaclnamespace");
   10489         468 :     i_defaclobjtype = PQfnumber(res, "defaclobjtype");
   10490         468 :     i_defaclacl = PQfnumber(res, "defaclacl");
   10491         468 :     i_acldefault = PQfnumber(res, "acldefault");
   10492             : 
   10493         860 :     for (i = 0; i < ntups; i++)
   10494             :     {
   10495         392 :         Oid         nspid = atooid(PQgetvalue(res, i, i_defaclnamespace));
   10496             : 
   10497         392 :         daclinfo[i].dobj.objType = DO_DEFAULT_ACL;
   10498         392 :         daclinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
   10499         392 :         daclinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
   10500         392 :         AssignDumpId(&daclinfo[i].dobj);
   10501             :         /* cheesy ... is it worth coming up with a better object name? */
   10502         392 :         daclinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_defaclobjtype));
   10503             : 
   10504         392 :         if (nspid != InvalidOid)
   10505         196 :             daclinfo[i].dobj.namespace = findNamespace(nspid);
   10506             :         else
   10507         196 :             daclinfo[i].dobj.namespace = NULL;
   10508             : 
   10509         392 :         daclinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_defaclacl));
   10510         392 :         daclinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
   10511         392 :         daclinfo[i].dacl.privtype = 0;
   10512         392 :         daclinfo[i].dacl.initprivs = NULL;
   10513         392 :         daclinfo[i].defaclrole = getRoleName(PQgetvalue(res, i, i_defaclrole));
   10514         392 :         daclinfo[i].defaclobjtype = *(PQgetvalue(res, i, i_defaclobjtype));
   10515             : 
   10516             :         /* Default ACLs are ACLs, of course */
   10517         392 :         daclinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
   10518             : 
   10519             :         /* Decide whether we want to dump it */
   10520         392 :         selectDumpableDefaultACL(&(daclinfo[i]), dopt);
   10521             :     }
   10522             : 
   10523         468 :     PQclear(res);
   10524             : 
   10525         468 :     destroyPQExpBuffer(query);
   10526         468 : }
   10527             : 
   10528             : /*
   10529             :  * getRoleName -- look up the name of a role, given its OID
   10530             :  *
   10531             :  * In current usage, we don't expect failures, so error out for a bad OID.
   10532             :  */
   10533             : static const char *
   10534     1481320 : getRoleName(const char *roleoid_str)
   10535             : {
   10536     1481320 :     Oid         roleoid = atooid(roleoid_str);
   10537             : 
   10538             :     /*
   10539             :      * Do binary search to find the appropriate item.
   10540             :      */
   10541     1481320 :     if (nrolenames > 0)
   10542             :     {
   10543     1481320 :         RoleNameItem *low = &rolenames[0];
   10544     1481320 :         RoleNameItem *high = &rolenames[nrolenames - 1];
   10545             : 
   10546     5925814 :         while (low <= high)
   10547             :         {
   10548     5925814 :             RoleNameItem *middle = low + (high - low) / 2;
   10549             : 
   10550     5925814 :             if (roleoid < middle->roleoid)
   10551     4441462 :                 high = middle - 1;
   10552     1484352 :             else if (roleoid > middle->roleoid)
   10553        3032 :                 low = middle + 1;
   10554             :             else
   10555     1481320 :                 return middle->rolename; /* found a match */
   10556             :         }
   10557             :     }
   10558             : 
   10559           0 :     pg_fatal("role with OID %u does not exist", roleoid);
   10560             :     return NULL;                /* keep compiler quiet */
   10561             : }
   10562             : 
   10563             : /*
   10564             :  * collectRoleNames --
   10565             :  *
   10566             :  * Construct a table of all known roles.
   10567             :  * The table is sorted by OID for speed in lookup.
   10568             :  */
   10569             : static void
   10570         470 : collectRoleNames(Archive *fout)
   10571             : {
   10572             :     PGresult   *res;
   10573             :     const char *query;
   10574             :     int         i;
   10575             : 
   10576         470 :     query = "SELECT oid, rolname FROM pg_catalog.pg_roles ORDER BY 1";
   10577             : 
   10578         470 :     res = ExecuteSqlQuery(fout, query, PGRES_TUPLES_OK);
   10579             : 
   10580         470 :     nrolenames = PQntuples(res);
   10581             : 
   10582         470 :     rolenames = (RoleNameItem *) pg_malloc(nrolenames * sizeof(RoleNameItem));
   10583             : 
   10584       10180 :     for (i = 0; i < nrolenames; i++)
   10585             :     {
   10586        9710 :         rolenames[i].roleoid = atooid(PQgetvalue(res, i, 0));
   10587        9710 :         rolenames[i].rolename = pg_strdup(PQgetvalue(res, i, 1));
   10588             :     }
   10589             : 
   10590         470 :     PQclear(res);
   10591         470 : }
   10592             : 
   10593             : /*
   10594             :  * getAdditionalACLs
   10595             :  *
   10596             :  * We have now created all the DumpableObjects, and collected the ACL data
   10597             :  * that appears in the directly-associated catalog entries.  However, there's
   10598             :  * more ACL-related info to collect.  If any of a table's columns have ACLs,
   10599             :  * we must set the TableInfo's DUMP_COMPONENT_ACL components flag, as well as
   10600             :  * its hascolumnACLs flag (we won't store the ACLs themselves here, though).
   10601             :  * Also, in versions having the pg_init_privs catalog, read that and load the
   10602             :  * information into the relevant DumpableObjects.
   10603             :  */
   10604             : static void
   10605         464 : getAdditionalACLs(Archive *fout)
   10606             : {
   10607         464 :     PQExpBuffer query = createPQExpBuffer();
   10608             :     PGresult   *res;
   10609             :     int         ntups,
   10610             :                 i;
   10611             : 
   10612             :     /* Check for per-column ACLs */
   10613         464 :     appendPQExpBufferStr(query,
   10614             :                          "SELECT DISTINCT attrelid FROM pg_attribute "
   10615             :                          "WHERE attacl IS NOT NULL");
   10616             : 
   10617         464 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   10618             : 
   10619         464 :     ntups = PQntuples(res);
   10620        1304 :     for (i = 0; i < ntups; i++)
   10621             :     {
   10622         840 :         Oid         relid = atooid(PQgetvalue(res, i, 0));
   10623             :         TableInfo  *tblinfo;
   10624             : 
   10625         840 :         tblinfo = findTableByOid(relid);
   10626             :         /* OK to ignore tables we haven't got a DumpableObject for */
   10627         840 :         if (tblinfo)
   10628             :         {
   10629         840 :             tblinfo->dobj.components |= DUMP_COMPONENT_ACL;
   10630         840 :             tblinfo->hascolumnACLs = true;
   10631             :         }
   10632             :     }
   10633         464 :     PQclear(res);
   10634             : 
   10635             :     /* Fetch initial-privileges data */
   10636         464 :     if (fout->remoteVersion >= 90600)
   10637             :     {
   10638         464 :         printfPQExpBuffer(query,
   10639             :                           "SELECT objoid, classoid, objsubid, privtype, initprivs "
   10640             :                           "FROM pg_init_privs");
   10641             : 
   10642         464 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   10643             : 
   10644         464 :         ntups = PQntuples(res);
   10645      108728 :         for (i = 0; i < ntups; i++)
   10646             :         {
   10647      108264 :             Oid         objoid = atooid(PQgetvalue(res, i, 0));
   10648      108264 :             Oid         classoid = atooid(PQgetvalue(res, i, 1));
   10649      108264 :             int         objsubid = atoi(PQgetvalue(res, i, 2));
   10650      108264 :             char        privtype = *(PQgetvalue(res, i, 3));
   10651      108264 :             char       *initprivs = PQgetvalue(res, i, 4);
   10652             :             CatalogId   objId;
   10653             :             DumpableObject *dobj;
   10654             : 
   10655      108264 :             objId.tableoid = classoid;
   10656      108264 :             objId.oid = objoid;
   10657      108264 :             dobj = findObjectByCatalogId(objId);
   10658             :             /* OK to ignore entries we haven't got a DumpableObject for */
   10659      108264 :             if (dobj)
   10660             :             {
   10661             :                 /* Cope with sub-object initprivs */
   10662       77272 :                 if (objsubid != 0)
   10663             :                 {
   10664        8400 :                     if (dobj->objType == DO_TABLE)
   10665             :                     {
   10666             :                         /* For a column initprivs, set the table's ACL flags */
   10667        8400 :                         dobj->components |= DUMP_COMPONENT_ACL;
   10668        8400 :                         ((TableInfo *) dobj)->hascolumnACLs = true;
   10669             :                     }
   10670             :                     else
   10671           0 :                         pg_log_warning("unsupported pg_init_privs entry: %u %u %d",
   10672             :                                        classoid, objoid, objsubid);
   10673        8856 :                     continue;
   10674             :                 }
   10675             : 
   10676             :                 /*
   10677             :                  * We ignore any pg_init_privs.initprivs entry for the public
   10678             :                  * schema, as explained in getNamespaces().
   10679             :                  */
   10680       68872 :                 if (dobj->objType == DO_NAMESPACE &&
   10681         920 :                     strcmp(dobj->name, "public") == 0)
   10682         456 :                     continue;
   10683             : 
   10684             :                 /* Else it had better be of a type we think has ACLs */
   10685       68416 :                 if (dobj->objType == DO_NAMESPACE ||
   10686       67952 :                     dobj->objType == DO_TYPE ||
   10687       67904 :                     dobj->objType == DO_FUNC ||
   10688       67712 :                     dobj->objType == DO_AGG ||
   10689       67664 :                     dobj->objType == DO_TABLE ||
   10690           0 :                     dobj->objType == DO_PROCLANG ||
   10691           0 :                     dobj->objType == DO_FDW ||
   10692           0 :                     dobj->objType == DO_FOREIGN_SERVER)
   10693       68416 :                 {
   10694       68416 :                     DumpableObjectWithAcl *daobj = (DumpableObjectWithAcl *) dobj;
   10695             : 
   10696       68416 :                     daobj->dacl.privtype = privtype;
   10697       68416 :                     daobj->dacl.initprivs = pstrdup(initprivs);
   10698             :                 }
   10699             :                 else
   10700           0 :                     pg_log_warning("unsupported pg_init_privs entry: %u %u %d",
   10701             :                                    classoid, objoid, objsubid);
   10702             :             }
   10703             :         }
   10704         464 :         PQclear(res);
   10705             :     }
   10706             : 
   10707         464 :     destroyPQExpBuffer(query);
   10708         464 : }
   10709             : 
   10710             : /*
   10711             :  * dumpCommentExtended --
   10712             :  *
   10713             :  * This routine is used to dump any comments associated with the
   10714             :  * object handed to this routine. The routine takes the object type
   10715             :  * and object name (ready to print, except for schema decoration), plus
   10716             :  * the namespace and owner of the object (for labeling the ArchiveEntry),
   10717             :  * plus catalog ID and subid which are the lookup key for pg_description,
   10718             :  * plus the dump ID for the object (for setting a dependency).
   10719             :  * If a matching pg_description entry is found, it is dumped.
   10720             :  *
   10721             :  * Note: in some cases, such as comments for triggers and rules, the "type"
   10722             :  * string really looks like, e.g., "TRIGGER name ON".  This is a bit of a hack
   10723             :  * but it doesn't seem worth complicating the API for all callers to make
   10724             :  * it cleaner.
   10725             :  *
   10726             :  * Note: although this routine takes a dumpId for dependency purposes,
   10727             :  * that purpose is just to mark the dependency in the emitted dump file
   10728             :  * for possible future use by pg_restore.  We do NOT use it for determining
   10729             :  * ordering of the comment in the dump file, because this routine is called
   10730             :  * after dependency sorting occurs.  This routine should be called just after
   10731             :  * calling ArchiveEntry() for the specified object.
   10732             :  */
   10733             : static void
   10734       13182 : dumpCommentExtended(Archive *fout, const char *type,
   10735             :                     const char *name, const char *namespace,
   10736             :                     const char *owner, CatalogId catalogId,
   10737             :                     int subid, DumpId dumpId,
   10738             :                     const char *initdb_comment)
   10739             : {
   10740       13182 :     DumpOptions *dopt = fout->dopt;
   10741             :     CommentItem *comments;
   10742             :     int         ncomments;
   10743             : 
   10744             :     /* do nothing, if --no-comments is supplied */
   10745       13182 :     if (dopt->no_comments)
   10746           0 :         return;
   10747             : 
   10748             :     /* Comments are schema not data ... except LO comments are data */
   10749       13182 :     if (strcmp(type, "LARGE OBJECT") != 0)
   10750             :     {
   10751       13060 :         if (!dopt->dumpSchema)
   10752           0 :             return;
   10753             :     }
   10754             :     else
   10755             :     {
   10756             :         /* We do dump LO comments in binary-upgrade mode */
   10757         122 :         if (!dopt->dumpData && !dopt->binary_upgrade)
   10758           0 :             return;
   10759             :     }
   10760             : 
   10761             :     /* Search for comments associated with catalogId, using table */
   10762       13182 :     ncomments = findComments(catalogId.tableoid, catalogId.oid,
   10763             :                              &comments);
   10764             : 
   10765             :     /* Is there one matching the subid? */
   10766       13182 :     while (ncomments > 0)
   10767             :     {
   10768       13086 :         if (comments->objsubid == subid)
   10769       13086 :             break;
   10770           0 :         comments++;
   10771           0 :         ncomments--;
   10772             :     }
   10773             : 
   10774       13182 :     if (initdb_comment != NULL)
   10775             :     {
   10776             :         static CommentItem empty_comment = {.descr = ""};
   10777             : 
   10778             :         /*
   10779             :          * initdb creates this object with a comment.  Skip dumping the
   10780             :          * initdb-provided comment, which would complicate matters for
   10781             :          * non-superuser use of pg_dump.  When the DBA has removed initdb's
   10782             :          * comment, replicate that.
   10783             :          */
   10784         340 :         if (ncomments == 0)
   10785             :         {
   10786           8 :             comments = &empty_comment;
   10787           8 :             ncomments = 1;
   10788             :         }
   10789         332 :         else if (strcmp(comments->descr, initdb_comment) == 0)
   10790         332 :             ncomments = 0;
   10791             :     }
   10792             : 
   10793             :     /* If a comment exists, build COMMENT ON statement */
   10794       13182 :     if (ncomments > 0)
   10795             :     {
   10796       12762 :         PQExpBuffer query = createPQExpBuffer();
   10797       12762 :         PQExpBuffer tag = createPQExpBuffer();
   10798             : 
   10799       12762 :         appendPQExpBuffer(query, "COMMENT ON %s ", type);
   10800       12762 :         if (namespace && *namespace)
   10801       12404 :             appendPQExpBuffer(query, "%s.", fmtId(namespace));
   10802       12762 :         appendPQExpBuffer(query, "%s IS ", name);
   10803       12762 :         appendStringLiteralAH(query, comments->descr, fout);
   10804       12762 :         appendPQExpBufferStr(query, ";\n");
   10805             : 
   10806       12762 :         appendPQExpBuffer(tag, "%s %s", type, name);
   10807             : 
   10808             :         /*
   10809             :          * We mark comments as SECTION_NONE because they really belong in the
   10810             :          * same section as their parent, whether that is pre-data or
   10811             :          * post-data.
   10812             :          */
   10813       12762 :         ArchiveEntry(fout, nilCatalogId, createDumpId(),
   10814       12762 :                      ARCHIVE_OPTS(.tag = tag->data,
   10815             :                                   .namespace = namespace,
   10816             :                                   .owner = owner,
   10817             :                                   .description = "COMMENT",
   10818             :                                   .section = SECTION_NONE,
   10819             :                                   .createStmt = query->data,
   10820             :                                   .deps = &dumpId,
   10821             :                                   .nDeps = 1));
   10822             : 
   10823       12762 :         destroyPQExpBuffer(query);
   10824       12762 :         destroyPQExpBuffer(tag);
   10825             :     }
   10826             : }
   10827             : 
   10828             : /*
   10829             :  * dumpComment --
   10830             :  *
   10831             :  * Typical simplification of the above function.
   10832             :  */
   10833             : static inline void
   10834       12774 : dumpComment(Archive *fout, const char *type,
   10835             :             const char *name, const char *namespace,
   10836             :             const char *owner, CatalogId catalogId,
   10837             :             int subid, DumpId dumpId)
   10838             : {
   10839       12774 :     dumpCommentExtended(fout, type, name, namespace, owner,
   10840             :                         catalogId, subid, dumpId, NULL);
   10841       12774 : }
   10842             : 
   10843             : /*
   10844             :  * appendNamedArgument --
   10845             :  *
   10846             :  * Convenience routine for constructing parameters of the form:
   10847             :  * 'paraname', 'value'::type
   10848             :  */
   10849             : static void
   10850       11290 : appendNamedArgument(PQExpBuffer out, Archive *fout, const char *argname,
   10851             :                     const char *argtype, const char *argval)
   10852             : {
   10853       11290 :     appendPQExpBufferStr(out, ",\n\t");
   10854             : 
   10855       11290 :     appendStringLiteralAH(out, argname, fout);
   10856       11290 :     appendPQExpBufferStr(out, ", ");
   10857             : 
   10858       11290 :     appendStringLiteralAH(out, argval, fout);
   10859       11290 :     appendPQExpBuffer(out, "::%s", argtype);
   10860       11290 : }
   10861             : 
   10862             : /*
   10863             :  * fetchAttributeStats --
   10864             :  *
   10865             :  * Fetch next batch of attribute statistics for dumpRelationStats_dumper().
   10866             :  */
   10867             : static PGresult *
   10868        2242 : fetchAttributeStats(Archive *fout)
   10869             : {
   10870        2242 :     ArchiveHandle *AH = (ArchiveHandle *) fout;
   10871        2242 :     PQExpBuffer nspnames = createPQExpBuffer();
   10872        2242 :     PQExpBuffer relnames = createPQExpBuffer();
   10873        2242 :     int         count = 0;
   10874        2242 :     PGresult   *res = NULL;
   10875             :     static TocEntry *te;
   10876             :     static bool restarted;
   10877        2242 :     int         max_rels = MAX_ATTR_STATS_RELS;
   10878             : 
   10879             :     /*
   10880             :      * Our query for retrieving statistics for multiple relations uses WITH
   10881             :      * ORDINALITY and multi-argument UNNEST(), both of which were introduced
   10882             :      * in v9.4.  For older versions, we resort to gathering statistics for a
   10883             :      * single relation at a time.
   10884             :      */
   10885        2242 :     if (fout->remoteVersion < 90400)
   10886           0 :         max_rels = 1;
   10887             : 
   10888             :     /* If we're just starting, set our TOC pointer. */
   10889        2242 :     if (!te)
   10890         106 :         te = AH->toc->next;
   10891             : 
   10892             :     /*
   10893             :      * We can't easily avoid a second TOC scan for the tar format because it
   10894             :      * writes restore.sql separately, which means we must execute the queries
   10895             :      * twice.  This feels risky, but there is no known reason it should
   10896             :      * generate different output than the first pass.  Even if it does, the
   10897             :      * worst-case scenario is that restore.sql might have different statistics
   10898             :      * data than the archive.
   10899             :      */
   10900        2242 :     if (!restarted && te == AH->toc && AH->format == archTar)
   10901             :     {
   10902           2 :         te = AH->toc->next;
   10903           2 :         restarted = true;
   10904             :     }
   10905             : 
   10906        2242 :     appendPQExpBufferChar(nspnames, '{');
   10907        2242 :     appendPQExpBufferChar(relnames, '{');
   10908             : 
   10909             :     /*
   10910             :      * Scan the TOC for the next set of relevant stats entries.  We assume
   10911             :      * that statistics are dumped in the order they are listed in the TOC.
   10912             :      * This is perhaps not the sturdiest assumption, so we verify it matches
   10913             :      * reality in dumpRelationStats_dumper().
   10914             :      */
   10915       33520 :     for (; te != AH->toc && count < max_rels; te = te->next)
   10916             :     {
   10917       31278 :         if ((te->reqs & REQ_STATS) != 0 &&
   10918        6922 :             strcmp(te->desc, "STATISTICS DATA") == 0)
   10919             :         {
   10920        6922 :             appendPGArray(nspnames, te->namespace);
   10921        6922 :             appendPGArray(relnames, te->tag);
   10922        6922 :             count++;
   10923             :         }
   10924             :     }
   10925             : 
   10926        2242 :     appendPQExpBufferChar(nspnames, '}');
   10927        2242 :     appendPQExpBufferChar(relnames, '}');
   10928             : 
   10929             :     /* Execute the query for the next batch of relations. */
   10930        2242 :     if (count > 0)
   10931             :     {
   10932         200 :         PQExpBuffer query = createPQExpBuffer();
   10933             : 
   10934         200 :         appendPQExpBufferStr(query, "EXECUTE getAttributeStats(");
   10935         200 :         appendStringLiteralAH(query, nspnames->data, fout);
   10936         200 :         appendPQExpBufferStr(query, "::pg_catalog.name[],");
   10937         200 :         appendStringLiteralAH(query, relnames->data, fout);
   10938         200 :         appendPQExpBufferStr(query, "::pg_catalog.name[])");
   10939         200 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   10940         200 :         destroyPQExpBuffer(query);
   10941             :     }
   10942             : 
   10943        2242 :     destroyPQExpBuffer(nspnames);
   10944        2242 :     destroyPQExpBuffer(relnames);
   10945        2242 :     return res;
   10946             : }
   10947             : 
   10948             : /*
   10949             :  * dumpRelationStats_dumper --
   10950             :  *
   10951             :  * Generate command to import stats into the relation on the new database.
   10952             :  * This routine is called by the Archiver when it wants the statistics to be
   10953             :  * dumped.
   10954             :  */
   10955             : static char *
   10956        6922 : dumpRelationStats_dumper(Archive *fout, const void *userArg, const TocEntry *te)
   10957             : {
   10958        6922 :     const RelStatsInfo *rsinfo = (RelStatsInfo *) userArg;
   10959             :     static PGresult *res;
   10960             :     static int  rownum;
   10961             :     PQExpBuffer query;
   10962             :     PQExpBufferData out_data;
   10963        6922 :     PQExpBuffer out = &out_data;
   10964             :     int         i_schemaname;
   10965             :     int         i_tablename;
   10966             :     int         i_attname;
   10967             :     int         i_inherited;
   10968             :     int         i_null_frac;
   10969             :     int         i_avg_width;
   10970             :     int         i_n_distinct;
   10971             :     int         i_most_common_vals;
   10972             :     int         i_most_common_freqs;
   10973             :     int         i_histogram_bounds;
   10974             :     int         i_correlation;
   10975             :     int         i_most_common_elems;
   10976             :     int         i_most_common_elem_freqs;
   10977             :     int         i_elem_count_histogram;
   10978             :     int         i_range_length_histogram;
   10979             :     int         i_range_empty_frac;
   10980             :     int         i_range_bounds_histogram;
   10981             :     static TocEntry *expected_te;
   10982             : 
   10983             :     /*
   10984             :      * fetchAttributeStats() assumes that the statistics are dumped in the
   10985             :      * order they are listed in the TOC.  We verify that here for safety.
   10986             :      */
   10987        6922 :     if (!expected_te)
   10988         106 :         expected_te = ((ArchiveHandle *) fout)->toc;
   10989             : 
   10990        6922 :     expected_te = expected_te->next;
   10991       27518 :     while ((expected_te->reqs & REQ_STATS) == 0 ||
   10992        6922 :            strcmp(expected_te->desc, "STATISTICS DATA") != 0)
   10993       20596 :         expected_te = expected_te->next;
   10994             : 
   10995        6922 :     if (te != expected_te)
   10996           0 :         pg_fatal("statistics dumped out of order (current: %d %s %s, expected: %d %s %s)",
   10997             :                  te->dumpId, te->desc, te->tag,
   10998             :                  expected_te->dumpId, expected_te->desc, expected_te->tag);
   10999             : 
   11000        6922 :     query = createPQExpBuffer();
   11001        6922 :     if (!fout->is_prepared[PREPQUERY_GETATTRIBUTESTATS])
   11002             :     {
   11003         106 :         appendPQExpBufferStr(query,
   11004             :                              "PREPARE getAttributeStats(pg_catalog.name[], pg_catalog.name[]) AS\n"
   11005             :                              "SELECT s.schemaname, s.tablename, s.attname, s.inherited, "
   11006             :                              "s.null_frac, s.avg_width, s.n_distinct, "
   11007             :                              "s.most_common_vals, s.most_common_freqs, "
   11008             :                              "s.histogram_bounds, s.correlation, "
   11009             :                              "s.most_common_elems, s.most_common_elem_freqs, "
   11010             :                              "s.elem_count_histogram, ");
   11011             : 
   11012         106 :         if (fout->remoteVersion >= 170000)
   11013         106 :             appendPQExpBufferStr(query,
   11014             :                                  "s.range_length_histogram, "
   11015             :                                  "s.range_empty_frac, "
   11016             :                                  "s.range_bounds_histogram ");
   11017             :         else
   11018           0 :             appendPQExpBufferStr(query,
   11019             :                                  "NULL AS range_length_histogram,"
   11020             :                                  "NULL AS range_empty_frac,"
   11021             :                                  "NULL AS range_bounds_histogram ");
   11022             : 
   11023             :         /*
   11024             :          * The results must be in the order of the relations supplied in the
   11025             :          * parameters to ensure we remain in sync as we walk through the TOC.
   11026             :          * The redundant filter clause on s.tablename = ANY(...) seems
   11027             :          * sufficient to convince the planner to use
   11028             :          * pg_class_relname_nsp_index, which avoids a full scan of pg_stats.
   11029             :          * This may not work for all versions.
   11030             :          *
   11031             :          * Our query for retrieving statistics for multiple relations uses
   11032             :          * WITH ORDINALITY and multi-argument UNNEST(), both of which were
   11033             :          * introduced in v9.4.  For older versions, we resort to gathering
   11034             :          * statistics for a single relation at a time.
   11035             :          */
   11036         106 :         if (fout->remoteVersion >= 90400)
   11037         106 :             appendPQExpBufferStr(query,
   11038             :                                  "FROM pg_catalog.pg_stats s "
   11039             :                                  "JOIN unnest($1, $2) WITH ORDINALITY AS u (schemaname, tablename, ord) "
   11040             :                                  "ON s.schemaname = u.schemaname "
   11041             :                                  "AND s.tablename = u.tablename "
   11042             :                                  "WHERE s.tablename = ANY($2) "
   11043             :                                  "ORDER BY u.ord, s.attname, s.inherited");
   11044             :         else
   11045           0 :             appendPQExpBufferStr(query,
   11046             :                                  "FROM pg_catalog.pg_stats s "
   11047             :                                  "WHERE s.schemaname = $1[1] "
   11048             :                                  "AND s.tablename = $2[1] "
   11049             :                                  "ORDER BY s.attname, s.inherited");
   11050             : 
   11051         106 :         ExecuteSqlStatement(fout, query->data);
   11052             : 
   11053         106 :         fout->is_prepared[PREPQUERY_GETATTRIBUTESTATS] = true;
   11054         106 :         resetPQExpBuffer(query);
   11055             :     }
   11056             : 
   11057        6922 :     initPQExpBuffer(out);
   11058             : 
   11059             :     /* restore relation stats */
   11060        6922 :     appendPQExpBufferStr(out, "SELECT * FROM pg_catalog.pg_restore_relation_stats(\n");
   11061        6922 :     appendPQExpBuffer(out, "\t'version', '%d'::integer,\n",
   11062             :                       fout->remoteVersion);
   11063        6922 :     appendPQExpBufferStr(out, "\t'schemaname', ");
   11064        6922 :     appendStringLiteralAH(out, rsinfo->dobj.namespace->dobj.name, fout);
   11065        6922 :     appendPQExpBufferStr(out, ",\n");
   11066        6922 :     appendPQExpBufferStr(out, "\t'relname', ");
   11067        6922 :     appendStringLiteralAH(out, rsinfo->dobj.name, fout);
   11068        6922 :     appendPQExpBufferStr(out, ",\n");
   11069        6922 :     appendPQExpBuffer(out, "\t'relpages', '%d'::integer,\n", rsinfo->relpages);
   11070             : 
   11071             :     /*
   11072             :      * Before v14, a reltuples value of 0 was ambiguous: it could either mean
   11073             :      * the relation is empty, or it could mean that it hadn't yet been
   11074             :      * vacuumed or analyzed.  (Newer versions use -1 for the latter case.)
   11075             :      * This ambiguity allegedly can cause the planner to choose inefficient
   11076             :      * plans after restoring to v18 or newer.  To deal with this, let's just
   11077             :      * set reltuples to -1 in that case.
   11078             :      */
   11079        6922 :     if (fout->remoteVersion < 140000 && strcmp("0", rsinfo->reltuples) == 0)
   11080           0 :         appendPQExpBufferStr(out, "\t'reltuples', '-1'::real,\n");
   11081             :     else
   11082        6922 :         appendPQExpBuffer(out, "\t'reltuples', '%s'::real,\n", rsinfo->reltuples);
   11083             : 
   11084        6922 :     appendPQExpBuffer(out, "\t'relallvisible', '%d'::integer",
   11085        6922 :                       rsinfo->relallvisible);
   11086             : 
   11087        6922 :     if (fout->remoteVersion >= 180000)
   11088        6922 :         appendPQExpBuffer(out, ",\n\t'relallfrozen', '%d'::integer", rsinfo->relallfrozen);
   11089             : 
   11090        6922 :     appendPQExpBufferStr(out, "\n);\n");
   11091             : 
   11092             :     /* Fetch the next batch of attribute statistics if needed. */
   11093        6922 :     if (rownum >= PQntuples(res))
   11094             :     {
   11095        2242 :         PQclear(res);
   11096        2242 :         res = fetchAttributeStats(fout);
   11097        2242 :         rownum = 0;
   11098             :     }
   11099             : 
   11100        6922 :     i_schemaname = PQfnumber(res, "schemaname");
   11101        6922 :     i_tablename = PQfnumber(res, "tablename");
   11102        6922 :     i_attname = PQfnumber(res, "attname");
   11103        6922 :     i_inherited = PQfnumber(res, "inherited");
   11104        6922 :     i_null_frac = PQfnumber(res, "null_frac");
   11105        6922 :     i_avg_width = PQfnumber(res, "avg_width");
   11106        6922 :     i_n_distinct = PQfnumber(res, "n_distinct");
   11107        6922 :     i_most_common_vals = PQfnumber(res, "most_common_vals");
   11108        6922 :     i_most_common_freqs = PQfnumber(res, "most_common_freqs");
   11109        6922 :     i_histogram_bounds = PQfnumber(res, "histogram_bounds");
   11110        6922 :     i_correlation = PQfnumber(res, "correlation");
   11111        6922 :     i_most_common_elems = PQfnumber(res, "most_common_elems");
   11112        6922 :     i_most_common_elem_freqs = PQfnumber(res, "most_common_elem_freqs");
   11113        6922 :     i_elem_count_histogram = PQfnumber(res, "elem_count_histogram");
   11114        6922 :     i_range_length_histogram = PQfnumber(res, "range_length_histogram");
   11115        6922 :     i_range_empty_frac = PQfnumber(res, "range_empty_frac");
   11116        6922 :     i_range_bounds_histogram = PQfnumber(res, "range_bounds_histogram");
   11117             : 
   11118             :     /* restore attribute stats */
   11119        8620 :     for (; rownum < PQntuples(res); rownum++)
   11120             :     {
   11121             :         const char *attname;
   11122             : 
   11123             :         /* Stop if the next stat row in our cache isn't for this relation. */
   11124        6378 :         if (strcmp(te->tag, PQgetvalue(res, rownum, i_tablename)) != 0 ||
   11125        1698 :             strcmp(te->namespace, PQgetvalue(res, rownum, i_schemaname)) != 0)
   11126             :             break;
   11127             : 
   11128        1698 :         appendPQExpBufferStr(out, "SELECT * FROM pg_catalog.pg_restore_attribute_stats(\n");
   11129        1698 :         appendPQExpBuffer(out, "\t'version', '%d'::integer,\n",
   11130             :                           fout->remoteVersion);
   11131        1698 :         appendPQExpBufferStr(out, "\t'schemaname', ");
   11132        1698 :         appendStringLiteralAH(out, rsinfo->dobj.namespace->dobj.name, fout);
   11133        1698 :         appendPQExpBufferStr(out, ",\n\t'relname', ");
   11134        1698 :         appendStringLiteralAH(out, rsinfo->dobj.name, fout);
   11135             : 
   11136        1698 :         if (PQgetisnull(res, rownum, i_attname))
   11137           0 :             pg_fatal("unexpected null attname");
   11138        1698 :         attname = PQgetvalue(res, rownum, i_attname);
   11139             : 
   11140             :         /*
   11141             :          * Indexes look up attname in indAttNames to derive attnum, all others
   11142             :          * use attname directly.  We must specify attnum for indexes, since
   11143             :          * their attnames are not necessarily stable across dump/reload.
   11144             :          */
   11145        1698 :         if (rsinfo->nindAttNames == 0)
   11146             :         {
   11147        1616 :             appendPQExpBufferStr(out, ",\n\t'attname', ");
   11148        1616 :             appendStringLiteralAH(out, attname, fout);
   11149             :         }
   11150             :         else
   11151             :         {
   11152          82 :             bool        found = false;
   11153             : 
   11154         152 :             for (int i = 0; i < rsinfo->nindAttNames; i++)
   11155             :             {
   11156         152 :                 if (strcmp(attname, rsinfo->indAttNames[i]) == 0)
   11157             :                 {
   11158          82 :                     appendPQExpBuffer(out, ",\n\t'attnum', '%d'::smallint",
   11159             :                                       i + 1);
   11160          82 :                     found = true;
   11161          82 :                     break;
   11162             :                 }
   11163             :             }
   11164             : 
   11165          82 :             if (!found)
   11166           0 :                 pg_fatal("could not find index attname \"%s\"", attname);
   11167             :         }
   11168             : 
   11169        1698 :         if (!PQgetisnull(res, rownum, i_inherited))
   11170        1698 :             appendNamedArgument(out, fout, "inherited", "boolean",
   11171        1698 :                                 PQgetvalue(res, rownum, i_inherited));
   11172        1698 :         if (!PQgetisnull(res, rownum, i_null_frac))
   11173        1698 :             appendNamedArgument(out, fout, "null_frac", "real",
   11174        1698 :                                 PQgetvalue(res, rownum, i_null_frac));
   11175        1698 :         if (!PQgetisnull(res, rownum, i_avg_width))
   11176        1698 :             appendNamedArgument(out, fout, "avg_width", "integer",
   11177        1698 :                                 PQgetvalue(res, rownum, i_avg_width));
   11178        1698 :         if (!PQgetisnull(res, rownum, i_n_distinct))
   11179        1698 :             appendNamedArgument(out, fout, "n_distinct", "real",
   11180        1698 :                                 PQgetvalue(res, rownum, i_n_distinct));
   11181        1698 :         if (!PQgetisnull(res, rownum, i_most_common_vals))
   11182         874 :             appendNamedArgument(out, fout, "most_common_vals", "text",
   11183         874 :                                 PQgetvalue(res, rownum, i_most_common_vals));
   11184        1698 :         if (!PQgetisnull(res, rownum, i_most_common_freqs))
   11185         874 :             appendNamedArgument(out, fout, "most_common_freqs", "real[]",
   11186         874 :                                 PQgetvalue(res, rownum, i_most_common_freqs));
   11187        1698 :         if (!PQgetisnull(res, rownum, i_histogram_bounds))
   11188        1062 :             appendNamedArgument(out, fout, "histogram_bounds", "text",
   11189        1062 :                                 PQgetvalue(res, rownum, i_histogram_bounds));
   11190        1698 :         if (!PQgetisnull(res, rownum, i_correlation))
   11191        1618 :             appendNamedArgument(out, fout, "correlation", "real",
   11192        1618 :                                 PQgetvalue(res, rownum, i_correlation));
   11193        1698 :         if (!PQgetisnull(res, rownum, i_most_common_elems))
   11194          16 :             appendNamedArgument(out, fout, "most_common_elems", "text",
   11195          16 :                                 PQgetvalue(res, rownum, i_most_common_elems));
   11196        1698 :         if (!PQgetisnull(res, rownum, i_most_common_elem_freqs))
   11197          16 :             appendNamedArgument(out, fout, "most_common_elem_freqs", "real[]",
   11198          16 :                                 PQgetvalue(res, rownum, i_most_common_elem_freqs));
   11199        1698 :         if (!PQgetisnull(res, rownum, i_elem_count_histogram))
   11200          14 :             appendNamedArgument(out, fout, "elem_count_histogram", "real[]",
   11201          14 :                                 PQgetvalue(res, rownum, i_elem_count_histogram));
   11202        1698 :         if (fout->remoteVersion >= 170000)
   11203             :         {
   11204        1698 :             if (!PQgetisnull(res, rownum, i_range_length_histogram))
   11205           8 :                 appendNamedArgument(out, fout, "range_length_histogram", "text",
   11206           8 :                                     PQgetvalue(res, rownum, i_range_length_histogram));
   11207        1698 :             if (!PQgetisnull(res, rownum, i_range_empty_frac))
   11208           8 :                 appendNamedArgument(out, fout, "range_empty_frac", "real",
   11209           8 :                                     PQgetvalue(res, rownum, i_range_empty_frac));
   11210        1698 :             if (!PQgetisnull(res, rownum, i_range_bounds_histogram))
   11211           8 :                 appendNamedArgument(out, fout, "range_bounds_histogram", "text",
   11212           8 :                                     PQgetvalue(res, rownum, i_range_bounds_histogram));
   11213             :         }
   11214        1698 :         appendPQExpBufferStr(out, "\n);\n");
   11215             :     }
   11216             : 
   11217        6922 :     destroyPQExpBuffer(query);
   11218        6922 :     return out->data;
   11219             : }
   11220             : 
   11221             : /*
   11222             :  * dumpRelationStats --
   11223             :  *
   11224             :  * Make an ArchiveEntry for the relation statistics.  The Archiver will take
   11225             :  * care of gathering the statistics and generating the restore commands when
   11226             :  * they are needed.
   11227             :  */
   11228             : static void
   11229        7060 : dumpRelationStats(Archive *fout, const RelStatsInfo *rsinfo)
   11230             : {
   11231        7060 :     const DumpableObject *dobj = &rsinfo->dobj;
   11232             : 
   11233             :     /* nothing to do if we are not dumping statistics */
   11234        7060 :     if (!fout->dopt->dumpStatistics)
   11235           0 :         return;
   11236             : 
   11237        7060 :     ArchiveEntry(fout, nilCatalogId, createDumpId(),
   11238        7060 :                  ARCHIVE_OPTS(.tag = dobj->name,
   11239             :                               .namespace = dobj->namespace->dobj.name,
   11240             :                               .description = "STATISTICS DATA",
   11241             :                               .section = rsinfo->section,
   11242             :                               .defnFn = dumpRelationStats_dumper,
   11243             :                               .defnArg = rsinfo,
   11244             :                               .deps = dobj->dependencies,
   11245             :                               .nDeps = dobj->nDeps));
   11246             : }
   11247             : 
   11248             : /*
   11249             :  * dumpTableComment --
   11250             :  *
   11251             :  * As above, but dump comments for both the specified table (or view)
   11252             :  * and its columns.
   11253             :  */
   11254             : static void
   11255         176 : dumpTableComment(Archive *fout, const TableInfo *tbinfo,
   11256             :                  const char *reltypename)
   11257             : {
   11258         176 :     DumpOptions *dopt = fout->dopt;
   11259             :     CommentItem *comments;
   11260             :     int         ncomments;
   11261             :     PQExpBuffer query;
   11262             :     PQExpBuffer tag;
   11263             : 
   11264             :     /* do nothing, if --no-comments is supplied */
   11265         176 :     if (dopt->no_comments)
   11266           0 :         return;
   11267             : 
   11268             :     /* Comments are SCHEMA not data */
   11269         176 :     if (!dopt->dumpSchema)
   11270           0 :         return;
   11271             : 
   11272             :     /* Search for comments associated with relation, using table */
   11273         176 :     ncomments = findComments(tbinfo->dobj.catId.tableoid,
   11274         176 :                              tbinfo->dobj.catId.oid,
   11275             :                              &comments);
   11276             : 
   11277             :     /* If comments exist, build COMMENT ON statements */
   11278         176 :     if (ncomments <= 0)
   11279           0 :         return;
   11280             : 
   11281         176 :     query = createPQExpBuffer();
   11282         176 :     tag = createPQExpBuffer();
   11283             : 
   11284         496 :     while (ncomments > 0)
   11285             :     {
   11286         320 :         const char *descr = comments->descr;
   11287         320 :         int         objsubid = comments->objsubid;
   11288             : 
   11289         320 :         if (objsubid == 0)
   11290             :         {
   11291          72 :             resetPQExpBuffer(tag);
   11292          72 :             appendPQExpBuffer(tag, "%s %s", reltypename,
   11293          72 :                               fmtId(tbinfo->dobj.name));
   11294             : 
   11295          72 :             resetPQExpBuffer(query);
   11296          72 :             appendPQExpBuffer(query, "COMMENT ON %s %s IS ", reltypename,
   11297          72 :                               fmtQualifiedDumpable(tbinfo));
   11298          72 :             appendStringLiteralAH(query, descr, fout);
   11299          72 :             appendPQExpBufferStr(query, ";\n");
   11300             : 
   11301          72 :             ArchiveEntry(fout, nilCatalogId, createDumpId(),
   11302          72 :                          ARCHIVE_OPTS(.tag = tag->data,
   11303             :                                       .namespace = tbinfo->dobj.namespace->dobj.name,
   11304             :                                       .owner = tbinfo->rolname,
   11305             :                                       .description = "COMMENT",
   11306             :                                       .section = SECTION_NONE,
   11307             :                                       .createStmt = query->data,
   11308             :                                       .deps = &(tbinfo->dobj.dumpId),
   11309             :                                       .nDeps = 1));
   11310             :         }
   11311         248 :         else if (objsubid > 0 && objsubid <= tbinfo->numatts)
   11312             :         {
   11313         248 :             resetPQExpBuffer(tag);
   11314         248 :             appendPQExpBuffer(tag, "COLUMN %s.",
   11315         248 :                               fmtId(tbinfo->dobj.name));
   11316         248 :             appendPQExpBufferStr(tag, fmtId(tbinfo->attnames[objsubid - 1]));
   11317             : 
   11318         248 :             resetPQExpBuffer(query);
   11319         248 :             appendPQExpBuffer(query, "COMMENT ON COLUMN %s.",
   11320         248 :                               fmtQualifiedDumpable(tbinfo));
   11321         248 :             appendPQExpBuffer(query, "%s IS ",
   11322         248 :                               fmtId(tbinfo->attnames[objsubid - 1]));
   11323         248 :             appendStringLiteralAH(query, descr, fout);
   11324         248 :             appendPQExpBufferStr(query, ";\n");
   11325             : 
   11326         248 :             ArchiveEntry(fout, nilCatalogId, createDumpId(),
   11327         248 :                          ARCHIVE_OPTS(.tag = tag->data,
   11328             :                                       .namespace = tbinfo->dobj.namespace->dobj.name,
   11329             :                                       .owner = tbinfo->rolname,
   11330             :                                       .description = "COMMENT",
   11331             :                                       .section = SECTION_NONE,
   11332             :                                       .createStmt = query->data,
   11333             :                                       .deps = &(tbinfo->dobj.dumpId),
   11334             :                                       .nDeps = 1));
   11335             :         }
   11336             : 
   11337         320 :         comments++;
   11338         320 :         ncomments--;
   11339             :     }
   11340             : 
   11341         176 :     destroyPQExpBuffer(query);
   11342         176 :     destroyPQExpBuffer(tag);
   11343             : }
   11344             : 
   11345             : /*
   11346             :  * findComments --
   11347             :  *
   11348             :  * Find the comment(s), if any, associated with the given object.  All the
   11349             :  * objsubid values associated with the given classoid/objoid are found with
   11350             :  * one search.
   11351             :  */
   11352             : static int
   11353       13430 : findComments(Oid classoid, Oid objoid, CommentItem **items)
   11354             : {
   11355       13430 :     CommentItem *middle = NULL;
   11356             :     CommentItem *low;
   11357             :     CommentItem *high;
   11358             :     int         nmatch;
   11359             : 
   11360             :     /*
   11361             :      * Do binary search to find some item matching the object.
   11362             :      */
   11363       13430 :     low = &comments[0];
   11364       13430 :     high = &comments[ncomments - 1];
   11365      133776 :     while (low <= high)
   11366             :     {
   11367      133680 :         middle = low + (high - low) / 2;
   11368             : 
   11369      133680 :         if (classoid < middle->classoid)
   11370       16228 :             high = middle - 1;
   11371      117452 :         else if (classoid > middle->classoid)
   11372       14820 :             low = middle + 1;
   11373      102632 :         else if (objoid < middle->objoid)
   11374       43182 :             high = middle - 1;
   11375       59450 :         else if (objoid > middle->objoid)
   11376       46116 :             low = middle + 1;
   11377             :         else
   11378       13334 :             break;              /* found a match */
   11379             :     }
   11380             : 
   11381       13430 :     if (low > high)              /* no matches */
   11382             :     {
   11383          96 :         *items = NULL;
   11384          96 :         return 0;
   11385             :     }
   11386             : 
   11387             :     /*
   11388             :      * Now determine how many items match the object.  The search loop
   11389             :      * invariant still holds: only items between low and high inclusive could
   11390             :      * match.
   11391             :      */
   11392       13334 :     nmatch = 1;
   11393       13478 :     while (middle > low)
   11394             :     {
   11395        6204 :         if (classoid != middle[-1].classoid ||
   11396        5930 :             objoid != middle[-1].objoid)
   11397             :             break;
   11398         144 :         middle--;
   11399         144 :         nmatch++;
   11400             :     }
   11401             : 
   11402       13334 :     *items = middle;
   11403             : 
   11404       13334 :     middle += nmatch;
   11405       13334 :     while (middle <= high)
   11406             :     {
   11407        7212 :         if (classoid != middle->classoid ||
   11408        6470 :             objoid != middle->objoid)
   11409             :             break;
   11410           0 :         middle++;
   11411           0 :         nmatch++;
   11412             :     }
   11413             : 
   11414       13334 :     return nmatch;
   11415             : }
   11416             : 
   11417             : /*
   11418             :  * collectComments --
   11419             :  *
   11420             :  * Construct a table of all comments available for database objects;
   11421             :  * also set the has-comment component flag for each relevant object.
   11422             :  *
   11423             :  * We used to do per-object queries for the comments, but it's much faster
   11424             :  * to pull them all over at once, and on most databases the memory cost
   11425             :  * isn't high.
   11426             :  *
   11427             :  * The table is sorted by classoid/objid/objsubid for speed in lookup.
   11428             :  */
   11429             : static void
   11430         468 : collectComments(Archive *fout)
   11431             : {
   11432             :     PGresult   *res;
   11433             :     PQExpBuffer query;
   11434             :     int         i_description;
   11435             :     int         i_classoid;
   11436             :     int         i_objoid;
   11437             :     int         i_objsubid;
   11438             :     int         ntups;
   11439             :     int         i;
   11440             :     DumpableObject *dobj;
   11441             : 
   11442         468 :     query = createPQExpBuffer();
   11443             : 
   11444         468 :     appendPQExpBufferStr(query, "SELECT description, classoid, objoid, objsubid "
   11445             :                          "FROM pg_catalog.pg_description "
   11446             :                          "ORDER BY classoid, objoid, objsubid");
   11447             : 
   11448         468 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   11449             : 
   11450             :     /* Construct lookup table containing OIDs in numeric form */
   11451             : 
   11452         468 :     i_description = PQfnumber(res, "description");
   11453         468 :     i_classoid = PQfnumber(res, "classoid");
   11454         468 :     i_objoid = PQfnumber(res, "objoid");
   11455         468 :     i_objsubid = PQfnumber(res, "objsubid");
   11456             : 
   11457         468 :     ntups = PQntuples(res);
   11458             : 
   11459         468 :     comments = (CommentItem *) pg_malloc(ntups * sizeof(CommentItem));
   11460         468 :     ncomments = 0;
   11461         468 :     dobj = NULL;
   11462             : 
   11463     2492852 :     for (i = 0; i < ntups; i++)
   11464             :     {
   11465             :         CatalogId   objId;
   11466             :         int         subid;
   11467             : 
   11468     2492384 :         objId.tableoid = atooid(PQgetvalue(res, i, i_classoid));
   11469     2492384 :         objId.oid = atooid(PQgetvalue(res, i, i_objoid));
   11470     2492384 :         subid = atoi(PQgetvalue(res, i, i_objsubid));
   11471             : 
   11472             :         /* We needn't remember comments that don't match any dumpable object */
   11473     2492384 :         if (dobj == NULL ||
   11474      897686 :             dobj->catId.tableoid != objId.tableoid ||
   11475      892090 :             dobj->catId.oid != objId.oid)
   11476     2492188 :             dobj = findObjectByCatalogId(objId);
   11477     2492384 :         if (dobj == NULL)
   11478     1594246 :             continue;
   11479             : 
   11480             :         /*
   11481             :          * Comments on columns of composite types are linked to the type's
   11482             :          * pg_class entry, but we need to set the DUMP_COMPONENT_COMMENT flag
   11483             :          * in the type's own DumpableObject.
   11484             :          */
   11485      898138 :         if (subid != 0 && dobj->objType == DO_TABLE &&
   11486         432 :             ((TableInfo *) dobj)->relkind == RELKIND_COMPOSITE_TYPE)
   11487          98 :         {
   11488             :             TypeInfo   *cTypeInfo;
   11489             : 
   11490          98 :             cTypeInfo = findTypeByOid(((TableInfo *) dobj)->reltype);
   11491          98 :             if (cTypeInfo)
   11492          98 :                 cTypeInfo->dobj.components |= DUMP_COMPONENT_COMMENT;
   11493             :         }
   11494             :         else
   11495      898040 :             dobj->components |= DUMP_COMPONENT_COMMENT;
   11496             : 
   11497      898138 :         comments[ncomments].descr = pg_strdup(PQgetvalue(res, i, i_description));
   11498      898138 :         comments[ncomments].classoid = objId.tableoid;
   11499      898138 :         comments[ncomments].objoid = objId.oid;
   11500      898138 :         comments[ncomments].objsubid = subid;
   11501      898138 :         ncomments++;
   11502             :     }
   11503             : 
   11504         468 :     PQclear(res);
   11505         468 :     destroyPQExpBuffer(query);
   11506         468 : }
   11507             : 
   11508             : /*
   11509             :  * dumpDumpableObject
   11510             :  *
   11511             :  * This routine and its subsidiaries are responsible for creating
   11512             :  * ArchiveEntries (TOC objects) for each object to be dumped.
   11513             :  */
   11514             : static void
   11515     1740206 : dumpDumpableObject(Archive *fout, DumpableObject *dobj)
   11516             : {
   11517             :     /*
   11518             :      * Clear any dump-request bits for components that don't exist for this
   11519             :      * object.  (This makes it safe to initially use DUMP_COMPONENT_ALL as the
   11520             :      * request for every kind of object.)
   11521             :      */
   11522     1740206 :     dobj->dump &= dobj->components;
   11523             : 
   11524             :     /* Now, short-circuit if there's nothing to be done here. */
   11525     1740206 :     if (dobj->dump == 0)
   11526     1542682 :         return;
   11527             : 
   11528      197524 :     switch (dobj->objType)
   11529             :     {
   11530        1250 :         case DO_NAMESPACE:
   11531        1250 :             dumpNamespace(fout, (const NamespaceInfo *) dobj);
   11532        1250 :             break;
   11533          38 :         case DO_EXTENSION:
   11534          38 :             dumpExtension(fout, (const ExtensionInfo *) dobj);
   11535          38 :             break;
   11536        2170 :         case DO_TYPE:
   11537        2170 :             dumpType(fout, (const TypeInfo *) dobj);
   11538        2170 :             break;
   11539         196 :         case DO_SHELL_TYPE:
   11540         196 :             dumpShellType(fout, (const ShellTypeInfo *) dobj);
   11541         196 :             break;
   11542        5376 :         case DO_FUNC:
   11543        5376 :             dumpFunc(fout, (const FuncInfo *) dobj);
   11544        5376 :             break;
   11545         874 :         case DO_AGG:
   11546         874 :             dumpAgg(fout, (const AggInfo *) dobj);
   11547         874 :             break;
   11548        5098 :         case DO_OPERATOR:
   11549        5098 :             dumpOpr(fout, (const OprInfo *) dobj);
   11550        5098 :             break;
   11551         182 :         case DO_ACCESS_METHOD:
   11552         182 :             dumpAccessMethod(fout, (const AccessMethodInfo *) dobj);
   11553         182 :             break;
   11554        1362 :         case DO_OPCLASS:
   11555        1362 :             dumpOpclass(fout, (const OpclassInfo *) dobj);
   11556        1362 :             break;
   11557        1156 :         case DO_OPFAMILY:
   11558        1156 :             dumpOpfamily(fout, (const OpfamilyInfo *) dobj);
   11559        1156 :             break;
   11560        5108 :         case DO_COLLATION:
   11561        5108 :             dumpCollation(fout, (const CollInfo *) dobj);
   11562        5108 :             break;
   11563         852 :         case DO_CONVERSION:
   11564         852 :             dumpConversion(fout, (const ConvInfo *) dobj);
   11565         852 :             break;
   11566       81182 :         case DO_TABLE:
   11567       81182 :             dumpTable(fout, (const TableInfo *) dobj);
   11568       81182 :             break;
   11569        3900 :         case DO_TABLE_ATTACH:
   11570        3900 :             dumpTableAttach(fout, (const TableAttachInfo *) dobj);
   11571        3900 :             break;
   11572        2916 :         case DO_ATTRDEF:
   11573        2916 :             dumpAttrDef(fout, (const AttrDefInfo *) dobj);
   11574        2916 :             break;
   11575        6986 :         case DO_INDEX:
   11576        6986 :             dumpIndex(fout, (const IndxInfo *) dobj);
   11577        6986 :             break;
   11578        1480 :         case DO_INDEX_ATTACH:
   11579        1480 :             dumpIndexAttach(fout, (const IndexAttachInfo *) dobj);
   11580        1480 :             break;
   11581         314 :         case DO_STATSEXT:
   11582         314 :             dumpStatisticsExt(fout, (const StatsExtInfo *) dobj);
   11583         314 :             break;
   11584         852 :         case DO_REFRESH_MATVIEW:
   11585         852 :             refreshMatViewData(fout, (const TableDataInfo *) dobj);
   11586         852 :             break;
   11587        2990 :         case DO_RULE:
   11588        2990 :             dumpRule(fout, (const RuleInfo *) dobj);
   11589        2990 :             break;
   11590        1476 :         case DO_TRIGGER:
   11591        1476 :             dumpTrigger(fout, (const TriggerInfo *) dobj);
   11592        1476 :             break;
   11593          98 :         case DO_EVENT_TRIGGER:
   11594          98 :             dumpEventTrigger(fout, (const EventTriggerInfo *) dobj);
   11595          98 :             break;
   11596        6078 :         case DO_CONSTRAINT:
   11597        6078 :             dumpConstraint(fout, (const ConstraintInfo *) dobj);
   11598        6078 :             break;
   11599         472 :         case DO_FK_CONSTRAINT:
   11600         472 :             dumpConstraint(fout, (const ConstraintInfo *) dobj);
   11601         472 :             break;
   11602         180 :         case DO_PROCLANG:
   11603         180 :             dumpProcLang(fout, (const ProcLangInfo *) dobj);
   11604         180 :             break;
   11605         178 :         case DO_CAST:
   11606         178 :             dumpCast(fout, (const CastInfo *) dobj);
   11607         178 :             break;
   11608          98 :         case DO_TRANSFORM:
   11609          98 :             dumpTransform(fout, (const TransformInfo *) dobj);
   11610          98 :             break;
   11611        1136 :         case DO_SEQUENCE_SET:
   11612        1136 :             dumpSequenceData(fout, (const TableDataInfo *) dobj);
   11613        1136 :             break;
   11614       12594 :         case DO_TABLE_DATA:
   11615       12594 :             dumpTableData(fout, (const TableDataInfo *) dobj);
   11616       12594 :             break;
   11617       38910 :         case DO_DUMMY_TYPE:
   11618             :             /* table rowtypes and array types are never dumped separately */
   11619       38910 :             break;
   11620          90 :         case DO_TSPARSER:
   11621          90 :             dumpTSParser(fout, (const TSParserInfo *) dobj);
   11622          90 :             break;
   11623         408 :         case DO_TSDICT:
   11624         408 :             dumpTSDictionary(fout, (const TSDictInfo *) dobj);
   11625         408 :             break;
   11626         114 :         case DO_TSTEMPLATE:
   11627         114 :             dumpTSTemplate(fout, (const TSTemplateInfo *) dobj);
   11628         114 :             break;
   11629         328 :         case DO_TSCONFIG:
   11630         328 :             dumpTSConfig(fout, (const TSConfigInfo *) dobj);
   11631         328 :             break;
   11632         118 :         case DO_FDW:
   11633         118 :             dumpForeignDataWrapper(fout, (const FdwInfo *) dobj);
   11634         118 :             break;
   11635         126 :         case DO_FOREIGN_SERVER:
   11636         126 :             dumpForeignServer(fout, (const ForeignServerInfo *) dobj);
   11637         126 :             break;
   11638         332 :         case DO_DEFAULT_ACL:
   11639         332 :             dumpDefaultACL(fout, (const DefaultACLInfo *) dobj);
   11640         332 :             break;
   11641         162 :         case DO_LARGE_OBJECT:
   11642         162 :             dumpLO(fout, (const LoInfo *) dobj);
   11643         162 :             break;
   11644         164 :         case DO_LARGE_OBJECT_DATA:
   11645         164 :             if (dobj->dump & DUMP_COMPONENT_DATA)
   11646             :             {
   11647             :                 LoInfo     *loinfo;
   11648             :                 TocEntry   *te;
   11649             : 
   11650         164 :                 loinfo = (LoInfo *) findObjectByDumpId(dobj->dependencies[0]);
   11651         164 :                 if (loinfo == NULL)
   11652           0 :                     pg_fatal("missing metadata for large objects \"%s\"",
   11653             :                              dobj->name);
   11654             : 
   11655         164 :                 te = ArchiveEntry(fout, dobj->catId, dobj->dumpId,
   11656         164 :                                   ARCHIVE_OPTS(.tag = dobj->name,
   11657             :                                                .owner = loinfo->rolname,
   11658             :                                                .description = "BLOBS",
   11659             :                                                .section = SECTION_DATA,
   11660             :                                                .deps = dobj->dependencies,
   11661             :                                                .nDeps = dobj->nDeps,
   11662             :                                                .dumpFn = dumpLOs,
   11663             :                                                .dumpArg = loinfo));
   11664             : 
   11665             :                 /*
   11666             :                  * Set the TocEntry's dataLength in case we are doing a
   11667             :                  * parallel dump and want to order dump jobs by table size.
   11668             :                  * (We need some size estimate for every TocEntry with a
   11669             :                  * DataDumper function.)  We don't currently have any cheap
   11670             :                  * way to estimate the size of LOs, but fortunately it doesn't
   11671             :                  * matter too much as long as we get large batches of LOs
   11672             :                  * processed reasonably early.  Assume 8K per blob.
   11673             :                  */
   11674         164 :                 te->dataLength = loinfo->numlos * (pgoff_t) 8192;
   11675             :             }
   11676         164 :             break;
   11677         780 :         case DO_POLICY:
   11678         780 :             dumpPolicy(fout, (const PolicyInfo *) dobj);
   11679         780 :             break;
   11680         412 :         case DO_PUBLICATION:
   11681         412 :             dumpPublication(fout, (const PublicationInfo *) dobj);
   11682         412 :             break;
   11683         574 :         case DO_PUBLICATION_REL:
   11684         574 :             dumpPublicationTable(fout, (const PublicationRelInfo *) dobj);
   11685         574 :             break;
   11686         164 :         case DO_PUBLICATION_TABLE_IN_SCHEMA:
   11687         164 :             dumpPublicationNamespace(fout,
   11688             :                                      (const PublicationSchemaInfo *) dobj);
   11689         164 :             break;
   11690         250 :         case DO_SUBSCRIPTION:
   11691         250 :             dumpSubscription(fout, (const SubscriptionInfo *) dobj);
   11692         250 :             break;
   11693           4 :         case DO_SUBSCRIPTION_REL:
   11694           4 :             dumpSubscriptionTable(fout, (const SubRelInfo *) dobj);
   11695           4 :             break;
   11696        7060 :         case DO_REL_STATS:
   11697        7060 :             dumpRelationStats(fout, (const RelStatsInfo *) dobj);
   11698        7060 :             break;
   11699         936 :         case DO_PRE_DATA_BOUNDARY:
   11700             :         case DO_POST_DATA_BOUNDARY:
   11701             :             /* never dumped, nothing to do */
   11702         936 :             break;
   11703             :     }
   11704             : }
   11705             : 
   11706             : /*
   11707             :  * dumpNamespace
   11708             :  *    writes out to fout the queries to recreate a user-defined namespace
   11709             :  */
   11710             : static void
   11711        1250 : dumpNamespace(Archive *fout, const NamespaceInfo *nspinfo)
   11712             : {
   11713        1250 :     DumpOptions *dopt = fout->dopt;
   11714             :     PQExpBuffer q;
   11715             :     PQExpBuffer delq;
   11716             :     char       *qnspname;
   11717             : 
   11718             :     /* Do nothing if not dumping schema */
   11719        1250 :     if (!dopt->dumpSchema)
   11720          56 :         return;
   11721             : 
   11722        1194 :     q = createPQExpBuffer();
   11723        1194 :     delq = createPQExpBuffer();
   11724             : 
   11725        1194 :     qnspname = pg_strdup(fmtId(nspinfo->dobj.name));
   11726             : 
   11727        1194 :     if (nspinfo->create)
   11728             :     {
   11729         796 :         appendPQExpBuffer(delq, "DROP SCHEMA %s;\n", qnspname);
   11730         796 :         appendPQExpBuffer(q, "CREATE SCHEMA %s;\n", qnspname);
   11731             :     }
   11732             :     else
   11733             :     {
   11734             :         /* see selectDumpableNamespace() */
   11735         398 :         appendPQExpBufferStr(delq,
   11736             :                              "-- *not* dropping schema, since initdb creates it\n");
   11737         398 :         appendPQExpBufferStr(q,
   11738             :                              "-- *not* creating schema, since initdb creates it\n");
   11739             :     }
   11740             : 
   11741        1194 :     if (dopt->binary_upgrade)
   11742         156 :         binary_upgrade_extension_member(q, &nspinfo->dobj,
   11743             :                                         "SCHEMA", qnspname, NULL);
   11744             : 
   11745        1194 :     if (nspinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   11746         466 :         ArchiveEntry(fout, nspinfo->dobj.catId, nspinfo->dobj.dumpId,
   11747         466 :                      ARCHIVE_OPTS(.tag = nspinfo->dobj.name,
   11748             :                                   .owner = nspinfo->rolname,
   11749             :                                   .description = "SCHEMA",
   11750             :                                   .section = SECTION_PRE_DATA,
   11751             :                                   .createStmt = q->data,
   11752             :                                   .dropStmt = delq->data));
   11753             : 
   11754             :     /* Dump Schema Comments and Security Labels */
   11755        1194 :     if (nspinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   11756             :     {
   11757         408 :         const char *initdb_comment = NULL;
   11758             : 
   11759         408 :         if (!nspinfo->create && strcmp(qnspname, "public") == 0)
   11760         340 :             initdb_comment = "standard public schema";
   11761         408 :         dumpCommentExtended(fout, "SCHEMA", qnspname,
   11762         408 :                             NULL, nspinfo->rolname,
   11763         408 :                             nspinfo->dobj.catId, 0, nspinfo->dobj.dumpId,
   11764             :                             initdb_comment);
   11765             :     }
   11766             : 
   11767        1194 :     if (nspinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
   11768           0 :         dumpSecLabel(fout, "SCHEMA", qnspname,
   11769           0 :                      NULL, nspinfo->rolname,
   11770           0 :                      nspinfo->dobj.catId, 0, nspinfo->dobj.dumpId);
   11771             : 
   11772        1194 :     if (nspinfo->dobj.dump & DUMP_COMPONENT_ACL)
   11773         936 :         dumpACL(fout, nspinfo->dobj.dumpId, InvalidDumpId, "SCHEMA",
   11774             :                 qnspname, NULL, NULL,
   11775         936 :                 NULL, nspinfo->rolname, &nspinfo->dacl);
   11776             : 
   11777        1194 :     free(qnspname);
   11778             : 
   11779        1194 :     destroyPQExpBuffer(q);
   11780        1194 :     destroyPQExpBuffer(delq);
   11781             : }
   11782             : 
   11783             : /*
   11784             :  * dumpExtension
   11785             :  *    writes out to fout the queries to recreate an extension
   11786             :  */
   11787             : static void
   11788          38 : dumpExtension(Archive *fout, const ExtensionInfo *extinfo)
   11789             : {
   11790          38 :     DumpOptions *dopt = fout->dopt;
   11791             :     PQExpBuffer q;
   11792             :     PQExpBuffer delq;
   11793             :     char       *qextname;
   11794             : 
   11795             :     /* Do nothing if not dumping schema */
   11796          38 :     if (!dopt->dumpSchema)
   11797           2 :         return;
   11798             : 
   11799          36 :     q = createPQExpBuffer();
   11800          36 :     delq = createPQExpBuffer();
   11801             : 
   11802          36 :     qextname = pg_strdup(fmtId(extinfo->dobj.name));
   11803             : 
   11804          36 :     appendPQExpBuffer(delq, "DROP EXTENSION %s;\n", qextname);
   11805             : 
   11806          36 :     if (!dopt->binary_upgrade)
   11807             :     {
   11808             :         /*
   11809             :          * In a regular dump, we simply create the extension, intentionally
   11810             :          * not specifying a version, so that the destination installation's
   11811             :          * default version is used.
   11812             :          *
   11813             :          * Use of IF NOT EXISTS here is unlike our behavior for other object
   11814             :          * types; but there are various scenarios in which it's convenient to
   11815             :          * manually create the desired extension before restoring, so we
   11816             :          * prefer to allow it to exist already.
   11817             :          */
   11818          34 :         appendPQExpBuffer(q, "CREATE EXTENSION IF NOT EXISTS %s WITH SCHEMA %s;\n",
   11819          34 :                           qextname, fmtId(extinfo->namespace));
   11820             :     }
   11821             :     else
   11822             :     {
   11823             :         /*
   11824             :          * In binary-upgrade mode, it's critical to reproduce the state of the
   11825             :          * database exactly, so our procedure is to create an empty extension,
   11826             :          * restore all the contained objects normally, and add them to the
   11827             :          * extension one by one.  This function performs just the first of
   11828             :          * those steps.  binary_upgrade_extension_member() takes care of
   11829             :          * adding member objects as they're created.
   11830             :          */
   11831             :         int         i;
   11832             :         int         n;
   11833             : 
   11834           2 :         appendPQExpBufferStr(q, "-- For binary upgrade, create an empty extension and insert objects into it\n");
   11835             : 
   11836             :         /*
   11837             :          * We unconditionally create the extension, so we must drop it if it
   11838             :          * exists.  This could happen if the user deleted 'plpgsql' and then
   11839             :          * readded it, causing its oid to be greater than g_last_builtin_oid.
   11840             :          */
   11841           2 :         appendPQExpBuffer(q, "DROP EXTENSION IF EXISTS %s;\n", qextname);
   11842             : 
   11843           2 :         appendPQExpBufferStr(q,
   11844             :                              "SELECT pg_catalog.binary_upgrade_create_empty_extension(");
   11845           2 :         appendStringLiteralAH(q, extinfo->dobj.name, fout);
   11846           2 :         appendPQExpBufferStr(q, ", ");
   11847           2 :         appendStringLiteralAH(q, extinfo->namespace, fout);
   11848           2 :         appendPQExpBufferStr(q, ", ");
   11849           2 :         appendPQExpBuffer(q, "%s, ", extinfo->relocatable ? "true" : "false");
   11850           2 :         appendStringLiteralAH(q, extinfo->extversion, fout);
   11851           2 :         appendPQExpBufferStr(q, ", ");
   11852             : 
   11853             :         /*
   11854             :          * Note that we're pushing extconfig (an OID array) back into
   11855             :          * pg_extension exactly as-is.  This is OK because pg_class OIDs are
   11856             :          * preserved in binary upgrade.
   11857             :          */
   11858           2 :         if (strlen(extinfo->extconfig) > 2)
   11859           2 :             appendStringLiteralAH(q, extinfo->extconfig, fout);
   11860             :         else
   11861           0 :             appendPQExpBufferStr(q, "NULL");
   11862           2 :         appendPQExpBufferStr(q, ", ");
   11863           2 :         if (strlen(extinfo->extcondition) > 2)
   11864           2 :             appendStringLiteralAH(q, extinfo->extcondition, fout);
   11865             :         else
   11866           0 :             appendPQExpBufferStr(q, "NULL");
   11867           2 :         appendPQExpBufferStr(q, ", ");
   11868           2 :         appendPQExpBufferStr(q, "ARRAY[");
   11869           2 :         n = 0;
   11870           4 :         for (i = 0; i < extinfo->dobj.nDeps; i++)
   11871             :         {
   11872             :             DumpableObject *extobj;
   11873             : 
   11874           2 :             extobj = findObjectByDumpId(extinfo->dobj.dependencies[i]);
   11875           2 :             if (extobj && extobj->objType == DO_EXTENSION)
   11876             :             {
   11877           0 :                 if (n++ > 0)
   11878           0 :                     appendPQExpBufferChar(q, ',');
   11879           0 :                 appendStringLiteralAH(q, extobj->name, fout);
   11880             :             }
   11881             :         }
   11882           2 :         appendPQExpBufferStr(q, "]::pg_catalog.text[]");
   11883           2 :         appendPQExpBufferStr(q, ");\n");
   11884             :     }
   11885             : 
   11886          36 :     if (extinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   11887          36 :         ArchiveEntry(fout, extinfo->dobj.catId, extinfo->dobj.dumpId,
   11888          36 :                      ARCHIVE_OPTS(.tag = extinfo->dobj.name,
   11889             :                                   .description = "EXTENSION",
   11890             :                                   .section = SECTION_PRE_DATA,
   11891             :                                   .createStmt = q->data,
   11892             :                                   .dropStmt = delq->data));
   11893             : 
   11894             :     /* Dump Extension Comments and Security Labels */
   11895          36 :     if (extinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   11896          36 :         dumpComment(fout, "EXTENSION", qextname,
   11897             :                     NULL, "",
   11898          36 :                     extinfo->dobj.catId, 0, extinfo->dobj.dumpId);
   11899             : 
   11900          36 :     if (extinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
   11901           0 :         dumpSecLabel(fout, "EXTENSION", qextname,
   11902             :                      NULL, "",
   11903           0 :                      extinfo->dobj.catId, 0, extinfo->dobj.dumpId);
   11904             : 
   11905          36 :     free(qextname);
   11906             : 
   11907          36 :     destroyPQExpBuffer(q);
   11908          36 :     destroyPQExpBuffer(delq);
   11909             : }
   11910             : 
   11911             : /*
   11912             :  * dumpType
   11913             :  *    writes out to fout the queries to recreate a user-defined type
   11914             :  */
   11915             : static void
   11916        2170 : dumpType(Archive *fout, const TypeInfo *tyinfo)
   11917             : {
   11918        2170 :     DumpOptions *dopt = fout->dopt;
   11919             : 
   11920             :     /* Do nothing if not dumping schema */
   11921        2170 :     if (!dopt->dumpSchema)
   11922          86 :         return;
   11923             : 
   11924             :     /* Dump out in proper style */
   11925        2084 :     if (tyinfo->typtype == TYPTYPE_BASE)
   11926         610 :         dumpBaseType(fout, tyinfo);
   11927        1474 :     else if (tyinfo->typtype == TYPTYPE_DOMAIN)
   11928         456 :         dumpDomain(fout, tyinfo);
   11929        1018 :     else if (tyinfo->typtype == TYPTYPE_COMPOSITE)
   11930         364 :         dumpCompositeType(fout, tyinfo);
   11931         654 :     else if (tyinfo->typtype == TYPTYPE_ENUM)
   11932         140 :         dumpEnumType(fout, tyinfo);
   11933         514 :     else if (tyinfo->typtype == TYPTYPE_RANGE)
   11934         276 :         dumpRangeType(fout, tyinfo);
   11935         238 :     else if (tyinfo->typtype == TYPTYPE_PSEUDO && !tyinfo->isDefined)
   11936          88 :         dumpUndefinedType(fout, tyinfo);
   11937             :     else
   11938         150 :         pg_log_warning("typtype of data type \"%s\" appears to be invalid",
   11939             :                        tyinfo->dobj.name);
   11940             : }
   11941             : 
   11942             : /*
   11943             :  * dumpEnumType
   11944             :  *    writes out to fout the queries to recreate a user-defined enum type
   11945             :  */
   11946             : static void
   11947         140 : dumpEnumType(Archive *fout, const TypeInfo *tyinfo)
   11948             : {
   11949         140 :     DumpOptions *dopt = fout->dopt;
   11950         140 :     PQExpBuffer q = createPQExpBuffer();
   11951         140 :     PQExpBuffer delq = createPQExpBuffer();
   11952         140 :     PQExpBuffer query = createPQExpBuffer();
   11953             :     PGresult   *res;
   11954             :     int         num,
   11955             :                 i;
   11956             :     Oid         enum_oid;
   11957             :     char       *qtypname;
   11958             :     char       *qualtypname;
   11959             :     char       *label;
   11960             :     int         i_enumlabel;
   11961             :     int         i_oid;
   11962             : 
   11963         140 :     if (!fout->is_prepared[PREPQUERY_DUMPENUMTYPE])
   11964             :     {
   11965             :         /* Set up query for enum-specific details */
   11966          92 :         appendPQExpBufferStr(query,
   11967             :                              "PREPARE dumpEnumType(pg_catalog.oid) AS\n"
   11968             :                              "SELECT oid, enumlabel "
   11969             :                              "FROM pg_catalog.pg_enum "
   11970             :                              "WHERE enumtypid = $1 "
   11971             :                              "ORDER BY enumsortorder");
   11972             : 
   11973          92 :         ExecuteSqlStatement(fout, query->data);
   11974             : 
   11975          92 :         fout->is_prepared[PREPQUERY_DUMPENUMTYPE] = true;
   11976             :     }
   11977             : 
   11978         140 :     printfPQExpBuffer(query,
   11979             :                       "EXECUTE dumpEnumType('%u')",
   11980         140 :                       tyinfo->dobj.catId.oid);
   11981             : 
   11982         140 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   11983             : 
   11984         140 :     num = PQntuples(res);
   11985             : 
   11986         140 :     qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
   11987         140 :     qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
   11988             : 
   11989             :     /*
   11990             :      * CASCADE shouldn't be required here as for normal types since the I/O
   11991             :      * functions are generic and do not get dropped.
   11992             :      */
   11993         140 :     appendPQExpBuffer(delq, "DROP TYPE %s;\n", qualtypname);
   11994             : 
   11995         140 :     if (dopt->binary_upgrade)
   11996          10 :         binary_upgrade_set_type_oids_by_type_oid(fout, q,
   11997          10 :                                                  tyinfo->dobj.catId.oid,
   11998             :                                                  false, false);
   11999             : 
   12000         140 :     appendPQExpBuffer(q, "CREATE TYPE %s AS ENUM (",
   12001             :                       qualtypname);
   12002             : 
   12003         140 :     if (!dopt->binary_upgrade)
   12004             :     {
   12005         130 :         i_enumlabel = PQfnumber(res, "enumlabel");
   12006             : 
   12007             :         /* Labels with server-assigned oids */
   12008        1080 :         for (i = 0; i < num; i++)
   12009             :         {
   12010         950 :             label = PQgetvalue(res, i, i_enumlabel);
   12011         950 :             if (i > 0)
   12012         820 :                 appendPQExpBufferChar(q, ',');
   12013         950 :             appendPQExpBufferStr(q, "\n    ");
   12014         950 :             appendStringLiteralAH(q, label, fout);
   12015             :         }
   12016             :     }
   12017             : 
   12018         140 :     appendPQExpBufferStr(q, "\n);\n");
   12019             : 
   12020         140 :     if (dopt->binary_upgrade)
   12021             :     {
   12022          10 :         i_oid = PQfnumber(res, "oid");
   12023          10 :         i_enumlabel = PQfnumber(res, "enumlabel");
   12024             : 
   12025             :         /* Labels with dump-assigned (preserved) oids */
   12026         116 :         for (i = 0; i < num; i++)
   12027             :         {
   12028         106 :             enum_oid = atooid(PQgetvalue(res, i, i_oid));
   12029         106 :             label = PQgetvalue(res, i, i_enumlabel);
   12030             : 
   12031         106 :             if (i == 0)
   12032          10 :                 appendPQExpBufferStr(q, "\n-- For binary upgrade, must preserve pg_enum oids\n");
   12033         106 :             appendPQExpBuffer(q,
   12034             :                               "SELECT pg_catalog.binary_upgrade_set_next_pg_enum_oid('%u'::pg_catalog.oid);\n",
   12035             :                               enum_oid);
   12036         106 :             appendPQExpBuffer(q, "ALTER TYPE %s ADD VALUE ", qualtypname);
   12037         106 :             appendStringLiteralAH(q, label, fout);
   12038         106 :             appendPQExpBufferStr(q, ";\n\n");
   12039             :         }
   12040             :     }
   12041             : 
   12042         140 :     if (dopt->binary_upgrade)
   12043          10 :         binary_upgrade_extension_member(q, &tyinfo->dobj,
   12044             :                                         "TYPE", qtypname,
   12045          10 :                                         tyinfo->dobj.namespace->dobj.name);
   12046             : 
   12047         140 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   12048         140 :         ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
   12049         140 :                      ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
   12050             :                                   .namespace = tyinfo->dobj.namespace->dobj.name,
   12051             :                                   .owner = tyinfo->rolname,
   12052             :                                   .description = "TYPE",
   12053             :                                   .section = SECTION_PRE_DATA,
   12054             :                                   .createStmt = q->data,
   12055             :                                   .dropStmt = delq->data));
   12056             : 
   12057             :     /* Dump Type Comments and Security Labels */
   12058         140 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   12059          72 :         dumpComment(fout, "TYPE", qtypname,
   12060          72 :                     tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
   12061          72 :                     tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
   12062             : 
   12063         140 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
   12064           0 :         dumpSecLabel(fout, "TYPE", qtypname,
   12065           0 :                      tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
   12066           0 :                      tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
   12067             : 
   12068         140 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
   12069          72 :         dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
   12070             :                 qtypname, NULL,
   12071          72 :                 tyinfo->dobj.namespace->dobj.name,
   12072          72 :                 NULL, tyinfo->rolname, &tyinfo->dacl);
   12073             : 
   12074         140 :     PQclear(res);
   12075         140 :     destroyPQExpBuffer(q);
   12076         140 :     destroyPQExpBuffer(delq);
   12077         140 :     destroyPQExpBuffer(query);
   12078         140 :     free(qtypname);
   12079         140 :     free(qualtypname);
   12080         140 : }
   12081             : 
   12082             : /*
   12083             :  * dumpRangeType
   12084             :  *    writes out to fout the queries to recreate a user-defined range type
   12085             :  */
   12086             : static void
   12087         276 : dumpRangeType(Archive *fout, const TypeInfo *tyinfo)
   12088             : {
   12089         276 :     DumpOptions *dopt = fout->dopt;
   12090         276 :     PQExpBuffer q = createPQExpBuffer();
   12091         276 :     PQExpBuffer delq = createPQExpBuffer();
   12092         276 :     PQExpBuffer query = createPQExpBuffer();
   12093             :     PGresult   *res;
   12094             :     Oid         collationOid;
   12095             :     char       *qtypname;
   12096             :     char       *qualtypname;
   12097             :     char       *procname;
   12098             : 
   12099         276 :     if (!fout->is_prepared[PREPQUERY_DUMPRANGETYPE])
   12100             :     {
   12101             :         /* Set up query for range-specific details */
   12102          94 :         appendPQExpBufferStr(query,
   12103             :                              "PREPARE dumpRangeType(pg_catalog.oid) AS\n");
   12104             : 
   12105          94 :         appendPQExpBufferStr(query,
   12106             :                              "SELECT ");
   12107             : 
   12108          94 :         if (fout->remoteVersion >= 140000)
   12109          94 :             appendPQExpBufferStr(query,
   12110             :                                  "pg_catalog.format_type(rngmultitypid, NULL) AS rngmultitype, ");
   12111             :         else
   12112           0 :             appendPQExpBufferStr(query,
   12113             :                                  "NULL AS rngmultitype, ");
   12114             : 
   12115          94 :         appendPQExpBufferStr(query,
   12116             :                              "pg_catalog.format_type(rngsubtype, NULL) AS rngsubtype, "
   12117             :                              "opc.opcname AS opcname, "
   12118             :                              "(SELECT nspname FROM pg_catalog.pg_namespace nsp "
   12119             :                              "  WHERE nsp.oid = opc.opcnamespace) AS opcnsp, "
   12120             :                              "opc.opcdefault, "
   12121             :                              "CASE WHEN rngcollation = st.typcollation THEN 0 "
   12122             :                              "     ELSE rngcollation END AS collation, "
   12123             :                              "rngcanonical, rngsubdiff "
   12124             :                              "FROM pg_catalog.pg_range r, pg_catalog.pg_type st, "
   12125             :                              "     pg_catalog.pg_opclass opc "
   12126             :                              "WHERE st.oid = rngsubtype AND opc.oid = rngsubopc AND "
   12127             :                              "rngtypid = $1");
   12128             : 
   12129          94 :         ExecuteSqlStatement(fout, query->data);
   12130             : 
   12131          94 :         fout->is_prepared[PREPQUERY_DUMPRANGETYPE] = true;
   12132             :     }
   12133             : 
   12134         276 :     printfPQExpBuffer(query,
   12135             :                       "EXECUTE dumpRangeType('%u')",
   12136         276 :                       tyinfo->dobj.catId.oid);
   12137             : 
   12138         276 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   12139             : 
   12140         276 :     qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
   12141         276 :     qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
   12142             : 
   12143             :     /*
   12144             :      * CASCADE shouldn't be required here as for normal types since the I/O
   12145             :      * functions are generic and do not get dropped.
   12146             :      */
   12147         276 :     appendPQExpBuffer(delq, "DROP TYPE %s;\n", qualtypname);
   12148             : 
   12149         276 :     if (dopt->binary_upgrade)
   12150          16 :         binary_upgrade_set_type_oids_by_type_oid(fout, q,
   12151          16 :                                                  tyinfo->dobj.catId.oid,
   12152             :                                                  false, true);
   12153             : 
   12154         276 :     appendPQExpBuffer(q, "CREATE TYPE %s AS RANGE (",
   12155             :                       qualtypname);
   12156             : 
   12157         276 :     appendPQExpBuffer(q, "\n    subtype = %s",
   12158             :                       PQgetvalue(res, 0, PQfnumber(res, "rngsubtype")));
   12159             : 
   12160         276 :     if (!PQgetisnull(res, 0, PQfnumber(res, "rngmultitype")))
   12161         276 :         appendPQExpBuffer(q, ",\n    multirange_type_name = %s",
   12162             :                           PQgetvalue(res, 0, PQfnumber(res, "rngmultitype")));
   12163             : 
   12164             :     /* print subtype_opclass only if not default for subtype */
   12165         276 :     if (PQgetvalue(res, 0, PQfnumber(res, "opcdefault"))[0] != 't')
   12166             :     {
   12167          72 :         char       *opcname = PQgetvalue(res, 0, PQfnumber(res, "opcname"));
   12168          72 :         char       *nspname = PQgetvalue(res, 0, PQfnumber(res, "opcnsp"));
   12169             : 
   12170          72 :         appendPQExpBuffer(q, ",\n    subtype_opclass = %s.",
   12171             :                           fmtId(nspname));
   12172          72 :         appendPQExpBufferStr(q, fmtId(opcname));
   12173             :     }
   12174             : 
   12175         276 :     collationOid = atooid(PQgetvalue(res, 0, PQfnumber(res, "collation")));
   12176         276 :     if (OidIsValid(collationOid))
   12177             :     {
   12178          88 :         CollInfo   *coll = findCollationByOid(collationOid);
   12179             : 
   12180          88 :         if (coll)
   12181          88 :             appendPQExpBuffer(q, ",\n    collation = %s",
   12182          88 :                               fmtQualifiedDumpable(coll));
   12183             :     }
   12184             : 
   12185         276 :     procname = PQgetvalue(res, 0, PQfnumber(res, "rngcanonical"));
   12186         276 :     if (strcmp(procname, "-") != 0)
   12187          18 :         appendPQExpBuffer(q, ",\n    canonical = %s", procname);
   12188             : 
   12189         276 :     procname = PQgetvalue(res, 0, PQfnumber(res, "rngsubdiff"));
   12190         276 :     if (strcmp(procname, "-") != 0)
   12191          52 :         appendPQExpBuffer(q, ",\n    subtype_diff = %s", procname);
   12192             : 
   12193         276 :     appendPQExpBufferStr(q, "\n);\n");
   12194             : 
   12195         276 :     if (dopt->binary_upgrade)
   12196          16 :         binary_upgrade_extension_member(q, &tyinfo->dobj,
   12197             :                                         "TYPE", qtypname,
   12198          16 :                                         tyinfo->dobj.namespace->dobj.name);
   12199             : 
   12200         276 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   12201         276 :         ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
   12202         276 :                      ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
   12203             :                                   .namespace = tyinfo->dobj.namespace->dobj.name,
   12204             :                                   .owner = tyinfo->rolname,
   12205             :                                   .description = "TYPE",
   12206             :                                   .section = SECTION_PRE_DATA,
   12207             :                                   .createStmt = q->data,
   12208             :                                   .dropStmt = delq->data));
   12209             : 
   12210             :     /* Dump Type Comments and Security Labels */
   12211         276 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   12212         108 :         dumpComment(fout, "TYPE", qtypname,
   12213         108 :                     tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
   12214         108 :                     tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
   12215             : 
   12216         276 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
   12217           0 :         dumpSecLabel(fout, "TYPE", qtypname,
   12218           0 :                      tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
   12219           0 :                      tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
   12220             : 
   12221         276 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
   12222          72 :         dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
   12223             :                 qtypname, NULL,
   12224          72 :                 tyinfo->dobj.namespace->dobj.name,
   12225          72 :                 NULL, tyinfo->rolname, &tyinfo->dacl);
   12226             : 
   12227         276 :     PQclear(res);
   12228         276 :     destroyPQExpBuffer(q);
   12229         276 :     destroyPQExpBuffer(delq);
   12230         276 :     destroyPQExpBuffer(query);
   12231         276 :     free(qtypname);
   12232         276 :     free(qualtypname);
   12233         276 : }
   12234             : 
   12235             : /*
   12236             :  * dumpUndefinedType
   12237             :  *    writes out to fout the queries to recreate a !typisdefined type
   12238             :  *
   12239             :  * This is a shell type, but we use different terminology to distinguish
   12240             :  * this case from where we have to emit a shell type definition to break
   12241             :  * circular dependencies.  An undefined type shouldn't ever have anything
   12242             :  * depending on it.
   12243             :  */
   12244             : static void
   12245          88 : dumpUndefinedType(Archive *fout, const TypeInfo *tyinfo)
   12246             : {
   12247          88 :     DumpOptions *dopt = fout->dopt;
   12248          88 :     PQExpBuffer q = createPQExpBuffer();
   12249          88 :     PQExpBuffer delq = createPQExpBuffer();
   12250             :     char       *qtypname;
   12251             :     char       *qualtypname;
   12252             : 
   12253          88 :     qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
   12254          88 :     qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
   12255             : 
   12256          88 :     appendPQExpBuffer(delq, "DROP TYPE %s;\n", qualtypname);
   12257             : 
   12258          88 :     if (dopt->binary_upgrade)
   12259           4 :         binary_upgrade_set_type_oids_by_type_oid(fout, q,
   12260           4 :                                                  tyinfo->dobj.catId.oid,
   12261             :                                                  false, false);
   12262             : 
   12263          88 :     appendPQExpBuffer(q, "CREATE TYPE %s;\n",
   12264             :                       qualtypname);
   12265             : 
   12266          88 :     if (dopt->binary_upgrade)
   12267           4 :         binary_upgrade_extension_member(q, &tyinfo->dobj,
   12268             :                                         "TYPE", qtypname,
   12269           4 :                                         tyinfo->dobj.namespace->dobj.name);
   12270             : 
   12271          88 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   12272          88 :         ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
   12273          88 :                      ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
   12274             :                                   .namespace = tyinfo->dobj.namespace->dobj.name,
   12275             :                                   .owner = tyinfo->rolname,
   12276             :                                   .description = "TYPE",
   12277             :                                   .section = SECTION_PRE_DATA,
   12278             :                                   .createStmt = q->data,
   12279             :                                   .dropStmt = delq->data));
   12280             : 
   12281             :     /* Dump Type Comments and Security Labels */
   12282          88 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   12283          72 :         dumpComment(fout, "TYPE", qtypname,
   12284          72 :                     tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
   12285          72 :                     tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
   12286             : 
   12287          88 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
   12288           0 :         dumpSecLabel(fout, "TYPE", qtypname,
   12289           0 :                      tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
   12290           0 :                      tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
   12291             : 
   12292          88 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
   12293           0 :         dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
   12294             :                 qtypname, NULL,
   12295           0 :                 tyinfo->dobj.namespace->dobj.name,
   12296           0 :                 NULL, tyinfo->rolname, &tyinfo->dacl);
   12297             : 
   12298          88 :     destroyPQExpBuffer(q);
   12299          88 :     destroyPQExpBuffer(delq);
   12300          88 :     free(qtypname);
   12301          88 :     free(qualtypname);
   12302          88 : }
   12303             : 
   12304             : /*
   12305             :  * dumpBaseType
   12306             :  *    writes out to fout the queries to recreate a user-defined base type
   12307             :  */
   12308             : static void
   12309         610 : dumpBaseType(Archive *fout, const TypeInfo *tyinfo)
   12310             : {
   12311         610 :     DumpOptions *dopt = fout->dopt;
   12312         610 :     PQExpBuffer q = createPQExpBuffer();
   12313         610 :     PQExpBuffer delq = createPQExpBuffer();
   12314         610 :     PQExpBuffer query = createPQExpBuffer();
   12315             :     PGresult   *res;
   12316             :     char       *qtypname;
   12317             :     char       *qualtypname;
   12318             :     char       *typlen;
   12319             :     char       *typinput;
   12320             :     char       *typoutput;
   12321             :     char       *typreceive;
   12322             :     char       *typsend;
   12323             :     char       *typmodin;
   12324             :     char       *typmodout;
   12325             :     char       *typanalyze;
   12326             :     char       *typsubscript;
   12327             :     Oid         typreceiveoid;
   12328             :     Oid         typsendoid;
   12329             :     Oid         typmodinoid;
   12330             :     Oid         typmodoutoid;
   12331             :     Oid         typanalyzeoid;
   12332             :     Oid         typsubscriptoid;
   12333             :     char       *typcategory;
   12334             :     char       *typispreferred;
   12335             :     char       *typdelim;
   12336             :     char       *typbyval;
   12337             :     char       *typalign;
   12338             :     char       *typstorage;
   12339             :     char       *typcollatable;
   12340             :     char       *typdefault;
   12341         610 :     bool        typdefault_is_literal = false;
   12342             : 
   12343         610 :     if (!fout->is_prepared[PREPQUERY_DUMPBASETYPE])
   12344             :     {
   12345             :         /* Set up query for type-specific details */
   12346          94 :         appendPQExpBufferStr(query,
   12347             :                              "PREPARE dumpBaseType(pg_catalog.oid) AS\n"
   12348             :                              "SELECT typlen, "
   12349             :                              "typinput, typoutput, typreceive, typsend, "
   12350             :                              "typreceive::pg_catalog.oid AS typreceiveoid, "
   12351             :                              "typsend::pg_catalog.oid AS typsendoid, "
   12352             :                              "typanalyze, "
   12353             :                              "typanalyze::pg_catalog.oid AS typanalyzeoid, "
   12354             :                              "typdelim, typbyval, typalign, typstorage, "
   12355             :                              "typmodin, typmodout, "
   12356             :                              "typmodin::pg_catalog.oid AS typmodinoid, "
   12357             :                              "typmodout::pg_catalog.oid AS typmodoutoid, "
   12358             :                              "typcategory, typispreferred, "
   12359             :                              "(typcollation <> 0) AS typcollatable, "
   12360             :                              "pg_catalog.pg_get_expr(typdefaultbin, 0) AS typdefaultbin, typdefault, ");
   12361             : 
   12362          94 :         if (fout->remoteVersion >= 140000)
   12363          94 :             appendPQExpBufferStr(query,
   12364             :                                  "typsubscript, "
   12365             :                                  "typsubscript::pg_catalog.oid AS typsubscriptoid ");
   12366             :         else
   12367           0 :             appendPQExpBufferStr(query,
   12368             :                                  "'-' AS typsubscript, 0 AS typsubscriptoid ");
   12369             : 
   12370          94 :         appendPQExpBufferStr(query, "FROM pg_catalog.pg_type "
   12371             :                              "WHERE oid = $1");
   12372             : 
   12373          94 :         ExecuteSqlStatement(fout, query->data);
   12374             : 
   12375          94 :         fout->is_prepared[PREPQUERY_DUMPBASETYPE] = true;
   12376             :     }
   12377             : 
   12378         610 :     printfPQExpBuffer(query,
   12379             :                       "EXECUTE dumpBaseType('%u')",
   12380         610 :                       tyinfo->dobj.catId.oid);
   12381             : 
   12382         610 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   12383             : 
   12384         610 :     typlen = PQgetvalue(res, 0, PQfnumber(res, "typlen"));
   12385         610 :     typinput = PQgetvalue(res, 0, PQfnumber(res, "typinput"));
   12386         610 :     typoutput = PQgetvalue(res, 0, PQfnumber(res, "typoutput"));
   12387         610 :     typreceive = PQgetvalue(res, 0, PQfnumber(res, "typreceive"));
   12388         610 :     typsend = PQgetvalue(res, 0, PQfnumber(res, "typsend"));
   12389         610 :     typmodin = PQgetvalue(res, 0, PQfnumber(res, "typmodin"));
   12390         610 :     typmodout = PQgetvalue(res, 0, PQfnumber(res, "typmodout"));
   12391         610 :     typanalyze = PQgetvalue(res, 0, PQfnumber(res, "typanalyze"));
   12392         610 :     typsubscript = PQgetvalue(res, 0, PQfnumber(res, "typsubscript"));
   12393         610 :     typreceiveoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typreceiveoid")));
   12394         610 :     typsendoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typsendoid")));
   12395         610 :     typmodinoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typmodinoid")));
   12396         610 :     typmodoutoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typmodoutoid")));
   12397         610 :     typanalyzeoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typanalyzeoid")));
   12398         610 :     typsubscriptoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typsubscriptoid")));
   12399         610 :     typcategory = PQgetvalue(res, 0, PQfnumber(res, "typcategory"));
   12400         610 :     typispreferred = PQgetvalue(res, 0, PQfnumber(res, "typispreferred"));
   12401         610 :     typdelim = PQgetvalue(res, 0, PQfnumber(res, "typdelim"));
   12402         610 :     typbyval = PQgetvalue(res, 0, PQfnumber(res, "typbyval"));
   12403         610 :     typalign = PQgetvalue(res, 0, PQfnumber(res, "typalign"));
   12404         610 :     typstorage = PQgetvalue(res, 0, PQfnumber(res, "typstorage"));
   12405         610 :     typcollatable = PQgetvalue(res, 0, PQfnumber(res, "typcollatable"));
   12406         610 :     if (!PQgetisnull(res, 0, PQfnumber(res, "typdefaultbin")))
   12407           0 :         typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefaultbin"));
   12408         610 :     else if (!PQgetisnull(res, 0, PQfnumber(res, "typdefault")))
   12409             :     {
   12410         104 :         typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefault"));
   12411         104 :         typdefault_is_literal = true;   /* it needs quotes */
   12412             :     }
   12413             :     else
   12414         506 :         typdefault = NULL;
   12415             : 
   12416         610 :     qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
   12417         610 :     qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
   12418             : 
   12419             :     /*
   12420             :      * The reason we include CASCADE is that the circular dependency between
   12421             :      * the type and its I/O functions makes it impossible to drop the type any
   12422             :      * other way.
   12423             :      */
   12424         610 :     appendPQExpBuffer(delq, "DROP TYPE %s CASCADE;\n", qualtypname);
   12425             : 
   12426             :     /*
   12427             :      * We might already have a shell type, but setting pg_type_oid is
   12428             :      * harmless, and in any case we'd better set the array type OID.
   12429             :      */
   12430         610 :     if (dopt->binary_upgrade)
   12431          16 :         binary_upgrade_set_type_oids_by_type_oid(fout, q,
   12432          16 :                                                  tyinfo->dobj.catId.oid,
   12433             :                                                  false, false);
   12434             : 
   12435         610 :     appendPQExpBuffer(q,
   12436             :                       "CREATE TYPE %s (\n"
   12437             :                       "    INTERNALLENGTH = %s",
   12438             :                       qualtypname,
   12439         610 :                       (strcmp(typlen, "-1") == 0) ? "variable" : typlen);
   12440             : 
   12441             :     /* regproc result is sufficiently quoted already */
   12442         610 :     appendPQExpBuffer(q, ",\n    INPUT = %s", typinput);
   12443         610 :     appendPQExpBuffer(q, ",\n    OUTPUT = %s", typoutput);
   12444         610 :     if (OidIsValid(typreceiveoid))
   12445         414 :         appendPQExpBuffer(q, ",\n    RECEIVE = %s", typreceive);
   12446         610 :     if (OidIsValid(typsendoid))
   12447         414 :         appendPQExpBuffer(q, ",\n    SEND = %s", typsend);
   12448         610 :     if (OidIsValid(typmodinoid))
   12449          76 :         appendPQExpBuffer(q, ",\n    TYPMOD_IN = %s", typmodin);
   12450         610 :     if (OidIsValid(typmodoutoid))
   12451          76 :         appendPQExpBuffer(q, ",\n    TYPMOD_OUT = %s", typmodout);
   12452         610 :     if (OidIsValid(typanalyzeoid))
   12453           6 :         appendPQExpBuffer(q, ",\n    ANALYZE = %s", typanalyze);
   12454             : 
   12455         610 :     if (strcmp(typcollatable, "t") == 0)
   12456          60 :         appendPQExpBufferStr(q, ",\n    COLLATABLE = true");
   12457             : 
   12458         610 :     if (typdefault != NULL)
   12459             :     {
   12460         104 :         appendPQExpBufferStr(q, ",\n    DEFAULT = ");
   12461         104 :         if (typdefault_is_literal)
   12462         104 :             appendStringLiteralAH(q, typdefault, fout);
   12463             :         else
   12464           0 :             appendPQExpBufferStr(q, typdefault);
   12465             :     }
   12466             : 
   12467         610 :     if (OidIsValid(typsubscriptoid))
   12468          64 :         appendPQExpBuffer(q, ",\n    SUBSCRIPT = %s", typsubscript);
   12469             : 
   12470         610 :     if (OidIsValid(tyinfo->typelem))
   12471          58 :         appendPQExpBuffer(q, ",\n    ELEMENT = %s",
   12472          58 :                           getFormattedTypeName(fout, tyinfo->typelem,
   12473             :                                                zeroIsError));
   12474             : 
   12475         610 :     if (strcmp(typcategory, "U") != 0)
   12476             :     {
   12477         322 :         appendPQExpBufferStr(q, ",\n    CATEGORY = ");
   12478         322 :         appendStringLiteralAH(q, typcategory, fout);
   12479             :     }
   12480             : 
   12481         610 :     if (strcmp(typispreferred, "t") == 0)
   12482          64 :         appendPQExpBufferStr(q, ",\n    PREFERRED = true");
   12483             : 
   12484         610 :     if (typdelim && strcmp(typdelim, ",") != 0)
   12485             :     {
   12486           6 :         appendPQExpBufferStr(q, ",\n    DELIMITER = ");
   12487           6 :         appendStringLiteralAH(q, typdelim, fout);
   12488             :     }
   12489             : 
   12490         610 :     if (*typalign == TYPALIGN_CHAR)
   12491          24 :         appendPQExpBufferStr(q, ",\n    ALIGNMENT = char");
   12492         586 :     else if (*typalign == TYPALIGN_SHORT)
   12493          12 :         appendPQExpBufferStr(q, ",\n    ALIGNMENT = int2");
   12494         574 :     else if (*typalign == TYPALIGN_INT)
   12495         406 :         appendPQExpBufferStr(q, ",\n    ALIGNMENT = int4");
   12496         168 :     else if (*typalign == TYPALIGN_DOUBLE)
   12497         168 :         appendPQExpBufferStr(q, ",\n    ALIGNMENT = double");
   12498             : 
   12499         610 :     if (*typstorage == TYPSTORAGE_PLAIN)
   12500         460 :         appendPQExpBufferStr(q, ",\n    STORAGE = plain");
   12501         150 :     else if (*typstorage == TYPSTORAGE_EXTERNAL)
   12502           0 :         appendPQExpBufferStr(q, ",\n    STORAGE = external");
   12503         150 :     else if (*typstorage == TYPSTORAGE_EXTENDED)
   12504         132 :         appendPQExpBufferStr(q, ",\n    STORAGE = extended");
   12505          18 :     else if (*typstorage == TYPSTORAGE_MAIN)
   12506          18 :         appendPQExpBufferStr(q, ",\n    STORAGE = main");
   12507             : 
   12508         610 :     if (strcmp(typbyval, "t") == 0)
   12509         294 :         appendPQExpBufferStr(q, ",\n    PASSEDBYVALUE");
   12510             : 
   12511         610 :     appendPQExpBufferStr(q, "\n);\n");
   12512             : 
   12513         610 :     if (dopt->binary_upgrade)
   12514          16 :         binary_upgrade_extension_member(q, &tyinfo->dobj,
   12515             :                                         "TYPE", qtypname,
   12516          16 :                                         tyinfo->dobj.namespace->dobj.name);
   12517             : 
   12518         610 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   12519         610 :         ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
   12520         610 :                      ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
   12521             :                                   .namespace = tyinfo->dobj.namespace->dobj.name,
   12522             :                                   .owner = tyinfo->rolname,
   12523             :                                   .description = "TYPE",
   12524             :                                   .section = SECTION_PRE_DATA,
   12525             :                                   .createStmt = q->data,
   12526             :                                   .dropStmt = delq->data));
   12527             : 
   12528             :     /* Dump Type Comments and Security Labels */
   12529         610 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   12530         498 :         dumpComment(fout, "TYPE", qtypname,
   12531         498 :                     tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
   12532         498 :                     tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
   12533             : 
   12534         610 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
   12535           0 :         dumpSecLabel(fout, "TYPE", qtypname,
   12536           0 :                      tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
   12537           0 :                      tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
   12538             : 
   12539         610 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
   12540          72 :         dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
   12541             :                 qtypname, NULL,
   12542          72 :                 tyinfo->dobj.namespace->dobj.name,
   12543          72 :                 NULL, tyinfo->rolname, &tyinfo->dacl);
   12544             : 
   12545         610 :     PQclear(res);
   12546         610 :     destroyPQExpBuffer(q);
   12547         610 :     destroyPQExpBuffer(delq);
   12548         610 :     destroyPQExpBuffer(query);
   12549         610 :     free(qtypname);
   12550         610 :     free(qualtypname);
   12551         610 : }
   12552             : 
   12553             : /*
   12554             :  * dumpDomain
   12555             :  *    writes out to fout the queries to recreate a user-defined domain
   12556             :  */
   12557             : static void
   12558         456 : dumpDomain(Archive *fout, const TypeInfo *tyinfo)
   12559             : {
   12560         456 :     DumpOptions *dopt = fout->dopt;
   12561         456 :     PQExpBuffer q = createPQExpBuffer();
   12562         456 :     PQExpBuffer delq = createPQExpBuffer();
   12563         456 :     PQExpBuffer query = createPQExpBuffer();
   12564             :     PGresult   *res;
   12565             :     int         i;
   12566             :     char       *qtypname;
   12567             :     char       *qualtypname;
   12568             :     char       *typnotnull;
   12569             :     char       *typdefn;
   12570             :     char       *typdefault;
   12571             :     Oid         typcollation;
   12572         456 :     bool        typdefault_is_literal = false;
   12573             : 
   12574         456 :     if (!fout->is_prepared[PREPQUERY_DUMPDOMAIN])
   12575             :     {
   12576             :         /* Set up query for domain-specific details */
   12577          88 :         appendPQExpBufferStr(query,
   12578             :                              "PREPARE dumpDomain(pg_catalog.oid) AS\n");
   12579             : 
   12580          88 :         appendPQExpBufferStr(query, "SELECT t.typnotnull, "
   12581             :                              "pg_catalog.format_type(t.typbasetype, t.typtypmod) AS typdefn, "
   12582             :                              "pg_catalog.pg_get_expr(t.typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, "
   12583             :                              "t.typdefault, "
   12584             :                              "CASE WHEN t.typcollation <> u.typcollation "
   12585             :                              "THEN t.typcollation ELSE 0 END AS typcollation "
   12586             :                              "FROM pg_catalog.pg_type t "
   12587             :                              "LEFT JOIN pg_catalog.pg_type u ON (t.typbasetype = u.oid) "
   12588             :                              "WHERE t.oid = $1");
   12589             : 
   12590          88 :         ExecuteSqlStatement(fout, query->data);
   12591             : 
   12592          88 :         fout->is_prepared[PREPQUERY_DUMPDOMAIN] = true;
   12593             :     }
   12594             : 
   12595         456 :     printfPQExpBuffer(query,
   12596             :                       "EXECUTE dumpDomain('%u')",
   12597         456 :                       tyinfo->dobj.catId.oid);
   12598             : 
   12599         456 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   12600             : 
   12601         456 :     typnotnull = PQgetvalue(res, 0, PQfnumber(res, "typnotnull"));
   12602         456 :     typdefn = PQgetvalue(res, 0, PQfnumber(res, "typdefn"));
   12603         456 :     if (!PQgetisnull(res, 0, PQfnumber(res, "typdefaultbin")))
   12604          88 :         typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefaultbin"));
   12605         368 :     else if (!PQgetisnull(res, 0, PQfnumber(res, "typdefault")))
   12606             :     {
   12607           0 :         typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefault"));
   12608           0 :         typdefault_is_literal = true;   /* it needs quotes */
   12609             :     }
   12610             :     else
   12611         368 :         typdefault = NULL;
   12612         456 :     typcollation = atooid(PQgetvalue(res, 0, PQfnumber(res, "typcollation")));
   12613             : 
   12614         456 :     if (dopt->binary_upgrade)
   12615          50 :         binary_upgrade_set_type_oids_by_type_oid(fout, q,
   12616          50 :                                                  tyinfo->dobj.catId.oid,
   12617             :                                                  true,  /* force array type */
   12618             :                                                  false);    /* force multirange type */
   12619             : 
   12620         456 :     qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
   12621         456 :     qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
   12622             : 
   12623         456 :     appendPQExpBuffer(q,
   12624             :                       "CREATE DOMAIN %s AS %s",
   12625             :                       qualtypname,
   12626             :                       typdefn);
   12627             : 
   12628             :     /* Print collation only if different from base type's collation */
   12629         456 :     if (OidIsValid(typcollation))
   12630             :     {
   12631             :         CollInfo   *coll;
   12632             : 
   12633          72 :         coll = findCollationByOid(typcollation);
   12634          72 :         if (coll)
   12635          72 :             appendPQExpBuffer(q, " COLLATE %s", fmtQualifiedDumpable(coll));
   12636             :     }
   12637             : 
   12638             :     /*
   12639             :      * Print a not-null constraint if there's one.  In servers older than 17
   12640             :      * these don't have names, so just print it unadorned; in newer ones they
   12641             :      * do, but most of the time it's going to be the standard generated one,
   12642             :      * so omit the name in that case also.
   12643             :      */
   12644         456 :     if (typnotnull[0] == 't')
   12645             :     {
   12646         120 :         if (fout->remoteVersion < 170000 || tyinfo->notnull == NULL)
   12647           0 :             appendPQExpBufferStr(q, " NOT NULL");
   12648             :         else
   12649             :         {
   12650         120 :             ConstraintInfo *notnull = tyinfo->notnull;
   12651             : 
   12652         120 :             if (!notnull->separate)
   12653             :             {
   12654             :                 char       *default_name;
   12655             : 
   12656             :                 /* XXX should match ChooseConstraintName better */
   12657         120 :                 default_name = psprintf("%s_not_null", tyinfo->dobj.name);
   12658             : 
   12659         120 :                 if (strcmp(default_name, notnull->dobj.name) == 0)
   12660          48 :                     appendPQExpBufferStr(q, " NOT NULL");
   12661             :                 else
   12662          72 :                     appendPQExpBuffer(q, " CONSTRAINT %s %s",
   12663          72 :                                       fmtId(notnull->dobj.name), notnull->condef);
   12664         120 :                 free(default_name);
   12665             :             }
   12666             :         }
   12667             :     }
   12668             : 
   12669         456 :     if (typdefault != NULL)
   12670             :     {
   12671          88 :         appendPQExpBufferStr(q, " DEFAULT ");
   12672          88 :         if (typdefault_is_literal)
   12673           0 :             appendStringLiteralAH(q, typdefault, fout);
   12674             :         else
   12675          88 :             appendPQExpBufferStr(q, typdefault);
   12676             :     }
   12677             : 
   12678         456 :     PQclear(res);
   12679             : 
   12680             :     /*
   12681             :      * Add any CHECK constraints for the domain
   12682             :      */
   12683         768 :     for (i = 0; i < tyinfo->nDomChecks; i++)
   12684             :     {
   12685         312 :         ConstraintInfo *domcheck = &(tyinfo->domChecks[i]);
   12686             : 
   12687         312 :         if (!domcheck->separate && domcheck->contype == 'c')
   12688         296 :             appendPQExpBuffer(q, "\n\tCONSTRAINT %s %s",
   12689         296 :                               fmtId(domcheck->dobj.name), domcheck->condef);
   12690             :     }
   12691             : 
   12692         456 :     appendPQExpBufferStr(q, ";\n");
   12693             : 
   12694         456 :     appendPQExpBuffer(delq, "DROP DOMAIN %s;\n", qualtypname);
   12695             : 
   12696         456 :     if (dopt->binary_upgrade)
   12697          50 :         binary_upgrade_extension_member(q, &tyinfo->dobj,
   12698             :                                         "DOMAIN", qtypname,
   12699          50 :                                         tyinfo->dobj.namespace->dobj.name);
   12700             : 
   12701         456 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   12702         456 :         ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
   12703         456 :                      ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
   12704             :                                   .namespace = tyinfo->dobj.namespace->dobj.name,
   12705             :                                   .owner = tyinfo->rolname,
   12706             :                                   .description = "DOMAIN",
   12707             :                                   .section = SECTION_PRE_DATA,
   12708             :                                   .createStmt = q->data,
   12709             :                                   .dropStmt = delq->data));
   12710             : 
   12711             :     /* Dump Domain Comments and Security Labels */
   12712         456 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   12713           0 :         dumpComment(fout, "DOMAIN", qtypname,
   12714           0 :                     tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
   12715           0 :                     tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
   12716             : 
   12717         456 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
   12718           0 :         dumpSecLabel(fout, "DOMAIN", qtypname,
   12719           0 :                      tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
   12720           0 :                      tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
   12721             : 
   12722         456 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
   12723          72 :         dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
   12724             :                 qtypname, NULL,
   12725          72 :                 tyinfo->dobj.namespace->dobj.name,
   12726          72 :                 NULL, tyinfo->rolname, &tyinfo->dacl);
   12727             : 
   12728             :     /* Dump any per-constraint comments */
   12729         768 :     for (i = 0; i < tyinfo->nDomChecks; i++)
   12730             :     {
   12731         312 :         ConstraintInfo *domcheck = &(tyinfo->domChecks[i]);
   12732             :         PQExpBuffer conprefix;
   12733             : 
   12734             :         /* but only if the constraint itself was dumped here */
   12735         312 :         if (domcheck->separate)
   12736          16 :             continue;
   12737             : 
   12738         296 :         conprefix = createPQExpBuffer();
   12739         296 :         appendPQExpBuffer(conprefix, "CONSTRAINT %s ON DOMAIN",
   12740         296 :                           fmtId(domcheck->dobj.name));
   12741             : 
   12742         296 :         if (domcheck->dobj.dump & DUMP_COMPONENT_COMMENT)
   12743          72 :             dumpComment(fout, conprefix->data, qtypname,
   12744          72 :                         tyinfo->dobj.namespace->dobj.name,
   12745          72 :                         tyinfo->rolname,
   12746          72 :                         domcheck->dobj.catId, 0, tyinfo->dobj.dumpId);
   12747             : 
   12748         296 :         destroyPQExpBuffer(conprefix);
   12749             :     }
   12750             : 
   12751             :     /*
   12752             :      * And a comment on the not-null constraint, if there's one -- but only if
   12753             :      * the constraint itself was dumped here
   12754             :      */
   12755         456 :     if (tyinfo->notnull != NULL && !tyinfo->notnull->separate)
   12756             :     {
   12757         120 :         PQExpBuffer conprefix = createPQExpBuffer();
   12758             : 
   12759         120 :         appendPQExpBuffer(conprefix, "CONSTRAINT %s ON DOMAIN",
   12760         120 :                           fmtId(tyinfo->notnull->dobj.name));
   12761             : 
   12762         120 :         if (tyinfo->notnull->dobj.dump & DUMP_COMPONENT_COMMENT)
   12763          72 :             dumpComment(fout, conprefix->data, qtypname,
   12764          72 :                         tyinfo->dobj.namespace->dobj.name,
   12765          72 :                         tyinfo->rolname,
   12766          72 :                         tyinfo->notnull->dobj.catId, 0, tyinfo->dobj.dumpId);
   12767         120 :         destroyPQExpBuffer(conprefix);
   12768             :     }
   12769             : 
   12770         456 :     destroyPQExpBuffer(q);
   12771         456 :     destroyPQExpBuffer(delq);
   12772         456 :     destroyPQExpBuffer(query);
   12773         456 :     free(qtypname);
   12774         456 :     free(qualtypname);
   12775         456 : }
   12776             : 
   12777             : /*
   12778             :  * dumpCompositeType
   12779             :  *    writes out to fout the queries to recreate a user-defined stand-alone
   12780             :  *    composite type
   12781             :  */
   12782             : static void
   12783         364 : dumpCompositeType(Archive *fout, const TypeInfo *tyinfo)
   12784             : {
   12785         364 :     DumpOptions *dopt = fout->dopt;
   12786         364 :     PQExpBuffer q = createPQExpBuffer();
   12787         364 :     PQExpBuffer dropped = createPQExpBuffer();
   12788         364 :     PQExpBuffer delq = createPQExpBuffer();
   12789         364 :     PQExpBuffer query = createPQExpBuffer();
   12790             :     PGresult   *res;
   12791             :     char       *qtypname;
   12792             :     char       *qualtypname;
   12793             :     int         ntups;
   12794             :     int         i_attname;
   12795             :     int         i_atttypdefn;
   12796             :     int         i_attlen;
   12797             :     int         i_attalign;
   12798             :     int         i_attisdropped;
   12799             :     int         i_attcollation;
   12800             :     int         i;
   12801             :     int         actual_atts;
   12802             : 
   12803         364 :     if (!fout->is_prepared[PREPQUERY_DUMPCOMPOSITETYPE])
   12804             :     {
   12805             :         /*
   12806             :          * Set up query for type-specific details.
   12807             :          *
   12808             :          * Since we only want to dump COLLATE clauses for attributes whose
   12809             :          * collation is different from their type's default, we use a CASE
   12810             :          * here to suppress uninteresting attcollations cheaply.  atttypid
   12811             :          * will be 0 for dropped columns; collation does not matter for those.
   12812             :          */
   12813         124 :         appendPQExpBufferStr(query,
   12814             :                              "PREPARE dumpCompositeType(pg_catalog.oid) AS\n"
   12815             :                              "SELECT a.attname, a.attnum, "
   12816             :                              "pg_catalog.format_type(a.atttypid, a.atttypmod) AS atttypdefn, "
   12817             :                              "a.attlen, a.attalign, a.attisdropped, "
   12818             :                              "CASE WHEN a.attcollation <> at.typcollation "
   12819             :                              "THEN a.attcollation ELSE 0 END AS attcollation "
   12820             :                              "FROM pg_catalog.pg_type ct "
   12821             :                              "JOIN pg_catalog.pg_attribute a ON a.attrelid = ct.typrelid "
   12822             :                              "LEFT JOIN pg_catalog.pg_type at ON at.oid = a.atttypid "
   12823             :                              "WHERE ct.oid = $1 "
   12824             :                              "ORDER BY a.attnum");
   12825             : 
   12826         124 :         ExecuteSqlStatement(fout, query->data);
   12827             : 
   12828         124 :         fout->is_prepared[PREPQUERY_DUMPCOMPOSITETYPE] = true;
   12829             :     }
   12830             : 
   12831         364 :     printfPQExpBuffer(query,
   12832             :                       "EXECUTE dumpCompositeType('%u')",
   12833         364 :                       tyinfo->dobj.catId.oid);
   12834             : 
   12835         364 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   12836             : 
   12837         364 :     ntups = PQntuples(res);
   12838             : 
   12839         364 :     i_attname = PQfnumber(res, "attname");
   12840         364 :     i_atttypdefn = PQfnumber(res, "atttypdefn");
   12841         364 :     i_attlen = PQfnumber(res, "attlen");
   12842         364 :     i_attalign = PQfnumber(res, "attalign");
   12843         364 :     i_attisdropped = PQfnumber(res, "attisdropped");
   12844         364 :     i_attcollation = PQfnumber(res, "attcollation");
   12845             : 
   12846         364 :     if (dopt->binary_upgrade)
   12847             :     {
   12848          36 :         binary_upgrade_set_type_oids_by_type_oid(fout, q,
   12849          36 :                                                  tyinfo->dobj.catId.oid,
   12850             :                                                  false, false);
   12851          36 :         binary_upgrade_set_pg_class_oids(fout, q, tyinfo->typrelid);
   12852             :     }
   12853             : 
   12854         364 :     qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
   12855         364 :     qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
   12856             : 
   12857         364 :     appendPQExpBuffer(q, "CREATE TYPE %s AS (",
   12858             :                       qualtypname);
   12859             : 
   12860         364 :     actual_atts = 0;
   12861        1180 :     for (i = 0; i < ntups; i++)
   12862             :     {
   12863             :         char       *attname;
   12864             :         char       *atttypdefn;
   12865             :         char       *attlen;
   12866             :         char       *attalign;
   12867             :         bool        attisdropped;
   12868             :         Oid         attcollation;
   12869             : 
   12870         816 :         attname = PQgetvalue(res, i, i_attname);
   12871         816 :         atttypdefn = PQgetvalue(res, i, i_atttypdefn);
   12872         816 :         attlen = PQgetvalue(res, i, i_attlen);
   12873         816 :         attalign = PQgetvalue(res, i, i_attalign);
   12874         816 :         attisdropped = (PQgetvalue(res, i, i_attisdropped)[0] == 't');
   12875         816 :         attcollation = atooid(PQgetvalue(res, i, i_attcollation));
   12876             : 
   12877         816 :         if (attisdropped && !dopt->binary_upgrade)
   12878          24 :             continue;
   12879             : 
   12880             :         /* Format properly if not first attr */
   12881         792 :         if (actual_atts++ > 0)
   12882         428 :             appendPQExpBufferChar(q, ',');
   12883         792 :         appendPQExpBufferStr(q, "\n\t");
   12884             : 
   12885         792 :         if (!attisdropped)
   12886             :         {
   12887         788 :             appendPQExpBuffer(q, "%s %s", fmtId(attname), atttypdefn);
   12888             : 
   12889             :             /* Add collation if not default for the column type */
   12890         788 :             if (OidIsValid(attcollation))
   12891             :             {
   12892             :                 CollInfo   *coll;
   12893             : 
   12894           0 :                 coll = findCollationByOid(attcollation);
   12895           0 :                 if (coll)
   12896           0 :                     appendPQExpBuffer(q, " COLLATE %s",
   12897           0 :                                       fmtQualifiedDumpable(coll));
   12898             :             }
   12899             :         }
   12900             :         else
   12901             :         {
   12902             :             /*
   12903             :              * This is a dropped attribute and we're in binary_upgrade mode.
   12904             :              * Insert a placeholder for it in the CREATE TYPE command, and set
   12905             :              * length and alignment with direct UPDATE to the catalogs
   12906             :              * afterwards. See similar code in dumpTableSchema().
   12907             :              */
   12908           4 :             appendPQExpBuffer(q, "%s INTEGER /* dummy */", fmtId(attname));
   12909             : 
   12910             :             /* stash separately for insertion after the CREATE TYPE */
   12911           4 :             appendPQExpBufferStr(dropped,
   12912             :                                  "\n-- For binary upgrade, recreate dropped column.\n");
   12913           4 :             appendPQExpBuffer(dropped, "UPDATE pg_catalog.pg_attribute\n"
   12914             :                               "SET attlen = %s, "
   12915             :                               "attalign = '%s', attbyval = false\n"
   12916             :                               "WHERE attname = ", attlen, attalign);
   12917           4 :             appendStringLiteralAH(dropped, attname, fout);
   12918           4 :             appendPQExpBufferStr(dropped, "\n  AND attrelid = ");
   12919           4 :             appendStringLiteralAH(dropped, qualtypname, fout);
   12920           4 :             appendPQExpBufferStr(dropped, "::pg_catalog.regclass;\n");
   12921             : 
   12922           4 :             appendPQExpBuffer(dropped, "ALTER TYPE %s ",
   12923             :                               qualtypname);
   12924           4 :             appendPQExpBuffer(dropped, "DROP ATTRIBUTE %s;\n",
   12925             :                               fmtId(attname));
   12926             :         }
   12927             :     }
   12928         364 :     appendPQExpBufferStr(q, "\n);\n");
   12929         364 :     appendPQExpBufferStr(q, dropped->data);
   12930             : 
   12931         364 :     appendPQExpBuffer(delq, "DROP TYPE %s;\n", qualtypname);
   12932             : 
   12933         364 :     if (dopt->binary_upgrade)
   12934          36 :         binary_upgrade_extension_member(q, &tyinfo->dobj,
   12935             :                                         "TYPE", qtypname,
   12936          36 :                                         tyinfo->dobj.namespace->dobj.name);
   12937             : 
   12938         364 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   12939         330 :         ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
   12940         330 :                      ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
   12941             :                                   .namespace = tyinfo->dobj.namespace->dobj.name,
   12942             :                                   .owner = tyinfo->rolname,
   12943             :                                   .description = "TYPE",
   12944             :                                   .section = SECTION_PRE_DATA,
   12945             :                                   .createStmt = q->data,
   12946             :                                   .dropStmt = delq->data));
   12947             : 
   12948             : 
   12949             :     /* Dump Type Comments and Security Labels */
   12950         364 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   12951          72 :         dumpComment(fout, "TYPE", qtypname,
   12952          72 :                     tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
   12953          72 :                     tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
   12954             : 
   12955         364 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
   12956           0 :         dumpSecLabel(fout, "TYPE", qtypname,
   12957           0 :                      tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
   12958           0 :                      tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
   12959             : 
   12960         364 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
   12961          36 :         dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
   12962             :                 qtypname, NULL,
   12963          36 :                 tyinfo->dobj.namespace->dobj.name,
   12964          36 :                 NULL, tyinfo->rolname, &tyinfo->dacl);
   12965             : 
   12966             :     /* Dump any per-column comments */
   12967         364 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   12968          72 :         dumpCompositeTypeColComments(fout, tyinfo, res);
   12969             : 
   12970         364 :     PQclear(res);
   12971         364 :     destroyPQExpBuffer(q);
   12972         364 :     destroyPQExpBuffer(dropped);
   12973         364 :     destroyPQExpBuffer(delq);
   12974         364 :     destroyPQExpBuffer(query);
   12975         364 :     free(qtypname);
   12976         364 :     free(qualtypname);
   12977         364 : }
   12978             : 
   12979             : /*
   12980             :  * dumpCompositeTypeColComments
   12981             :  *    writes out to fout the queries to recreate comments on the columns of
   12982             :  *    a user-defined stand-alone composite type.
   12983             :  *
   12984             :  * The caller has already made a query to collect the names and attnums
   12985             :  * of the type's columns, so we just pass that result into here rather
   12986             :  * than reading them again.
   12987             :  */
   12988             : static void
   12989          72 : dumpCompositeTypeColComments(Archive *fout, const TypeInfo *tyinfo,
   12990             :                              PGresult *res)
   12991             : {
   12992             :     CommentItem *comments;
   12993             :     int         ncomments;
   12994             :     PQExpBuffer query;
   12995             :     PQExpBuffer target;
   12996             :     int         i;
   12997             :     int         ntups;
   12998             :     int         i_attname;
   12999             :     int         i_attnum;
   13000             :     int         i_attisdropped;
   13001             : 
   13002             :     /* do nothing, if --no-comments is supplied */
   13003          72 :     if (fout->dopt->no_comments)
   13004           0 :         return;
   13005             : 
   13006             :     /* Search for comments associated with type's pg_class OID */
   13007          72 :     ncomments = findComments(RelationRelationId, tyinfo->typrelid,
   13008             :                              &comments);
   13009             : 
   13010             :     /* If no comments exist, we're done */
   13011          72 :     if (ncomments <= 0)
   13012           0 :         return;
   13013             : 
   13014             :     /* Build COMMENT ON statements */
   13015          72 :     query = createPQExpBuffer();
   13016          72 :     target = createPQExpBuffer();
   13017             : 
   13018          72 :     ntups = PQntuples(res);
   13019          72 :     i_attnum = PQfnumber(res, "attnum");
   13020          72 :     i_attname = PQfnumber(res, "attname");
   13021          72 :     i_attisdropped = PQfnumber(res, "attisdropped");
   13022         144 :     while (ncomments > 0)
   13023             :     {
   13024             :         const char *attname;
   13025             : 
   13026          72 :         attname = NULL;
   13027          72 :         for (i = 0; i < ntups; i++)
   13028             :         {
   13029          72 :             if (atoi(PQgetvalue(res, i, i_attnum)) == comments->objsubid &&
   13030          72 :                 PQgetvalue(res, i, i_attisdropped)[0] != 't')
   13031             :             {
   13032          72 :                 attname = PQgetvalue(res, i, i_attname);
   13033          72 :                 break;
   13034             :             }
   13035             :         }
   13036          72 :         if (attname)            /* just in case we don't find it */
   13037             :         {
   13038          72 :             const char *descr = comments->descr;
   13039             : 
   13040          72 :             resetPQExpBuffer(target);
   13041          72 :             appendPQExpBuffer(target, "COLUMN %s.",
   13042          72 :                               fmtId(tyinfo->dobj.name));
   13043          72 :             appendPQExpBufferStr(target, fmtId(attname));
   13044             : 
   13045          72 :             resetPQExpBuffer(query);
   13046          72 :             appendPQExpBuffer(query, "COMMENT ON COLUMN %s.",
   13047          72 :                               fmtQualifiedDumpable(tyinfo));
   13048          72 :             appendPQExpBuffer(query, "%s IS ", fmtId(attname));
   13049          72 :             appendStringLiteralAH(query, descr, fout);
   13050          72 :             appendPQExpBufferStr(query, ";\n");
   13051             : 
   13052          72 :             ArchiveEntry(fout, nilCatalogId, createDumpId(),
   13053          72 :                          ARCHIVE_OPTS(.tag = target->data,
   13054             :                                       .namespace = tyinfo->dobj.namespace->dobj.name,
   13055             :                                       .owner = tyinfo->rolname,
   13056             :                                       .description = "COMMENT",
   13057             :                                       .section = SECTION_NONE,
   13058             :                                       .createStmt = query->data,
   13059             :                                       .deps = &(tyinfo->dobj.dumpId),
   13060             :                                       .nDeps = 1));
   13061             :         }
   13062             : 
   13063          72 :         comments++;
   13064          72 :         ncomments--;
   13065             :     }
   13066             : 
   13067          72 :     destroyPQExpBuffer(query);
   13068          72 :     destroyPQExpBuffer(target);
   13069             : }
   13070             : 
   13071             : /*
   13072             :  * dumpShellType
   13073             :  *    writes out to fout the queries to create a shell type
   13074             :  *
   13075             :  * We dump a shell definition in advance of the I/O functions for the type.
   13076             :  */
   13077             : static void
   13078         196 : dumpShellType(Archive *fout, const ShellTypeInfo *stinfo)
   13079             : {
   13080         196 :     DumpOptions *dopt = fout->dopt;
   13081             :     PQExpBuffer q;
   13082             : 
   13083             :     /* Do nothing if not dumping schema */
   13084         196 :     if (!dopt->dumpSchema)
   13085          12 :         return;
   13086             : 
   13087         184 :     q = createPQExpBuffer();
   13088             : 
   13089             :     /*
   13090             :      * Note the lack of a DROP command for the shell type; any required DROP
   13091             :      * is driven off the base type entry, instead.  This interacts with
   13092             :      * _printTocEntry()'s use of the presence of a DROP command to decide
   13093             :      * whether an entry needs an ALTER OWNER command.  We don't want to alter
   13094             :      * the shell type's owner immediately on creation; that should happen only
   13095             :      * after it's filled in, otherwise the backend complains.
   13096             :      */
   13097             : 
   13098         184 :     if (dopt->binary_upgrade)
   13099          16 :         binary_upgrade_set_type_oids_by_type_oid(fout, q,
   13100          16 :                                                  stinfo->baseType->dobj.catId.oid,
   13101             :                                                  false, false);
   13102             : 
   13103         184 :     appendPQExpBuffer(q, "CREATE TYPE %s;\n",
   13104         184 :                       fmtQualifiedDumpable(stinfo));
   13105             : 
   13106         184 :     if (stinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   13107         184 :         ArchiveEntry(fout, stinfo->dobj.catId, stinfo->dobj.dumpId,
   13108         184 :                      ARCHIVE_OPTS(.tag = stinfo->dobj.name,
   13109             :                                   .namespace = stinfo->dobj.namespace->dobj.name,
   13110             :                                   .owner = stinfo->baseType->rolname,
   13111             :                                   .description = "SHELL TYPE",
   13112             :                                   .section = SECTION_PRE_DATA,
   13113             :                                   .createStmt = q->data));
   13114             : 
   13115         184 :     destroyPQExpBuffer(q);
   13116             : }
   13117             : 
   13118             : /*
   13119             :  * dumpProcLang
   13120             :  *        writes out to fout the queries to recreate a user-defined
   13121             :  *        procedural language
   13122             :  */
   13123             : static void
   13124         180 : dumpProcLang(Archive *fout, const ProcLangInfo *plang)
   13125             : {
   13126         180 :     DumpOptions *dopt = fout->dopt;
   13127             :     PQExpBuffer defqry;
   13128             :     PQExpBuffer delqry;
   13129             :     bool        useParams;
   13130             :     char       *qlanname;
   13131             :     FuncInfo   *funcInfo;
   13132         180 :     FuncInfo   *inlineInfo = NULL;
   13133         180 :     FuncInfo   *validatorInfo = NULL;
   13134             : 
   13135             :     /* Do nothing if not dumping schema */
   13136         180 :     if (!dopt->dumpSchema)
   13137          26 :         return;
   13138             : 
   13139             :     /*
   13140             :      * Try to find the support function(s).  It is not an error if we don't
   13141             :      * find them --- if the functions are in the pg_catalog schema, as is
   13142             :      * standard in 8.1 and up, then we won't have loaded them. (In this case
   13143             :      * we will emit a parameterless CREATE LANGUAGE command, which will
   13144             :      * require PL template knowledge in the backend to reload.)
   13145             :      */
   13146             : 
   13147         154 :     funcInfo = findFuncByOid(plang->lanplcallfoid);
   13148         154 :     if (funcInfo != NULL && !funcInfo->dobj.dump)
   13149           4 :         funcInfo = NULL;        /* treat not-dumped same as not-found */
   13150             : 
   13151         154 :     if (OidIsValid(plang->laninline))
   13152             :     {
   13153          84 :         inlineInfo = findFuncByOid(plang->laninline);
   13154          84 :         if (inlineInfo != NULL && !inlineInfo->dobj.dump)
   13155           2 :             inlineInfo = NULL;
   13156             :     }
   13157             : 
   13158         154 :     if (OidIsValid(plang->lanvalidator))
   13159             :     {
   13160          84 :         validatorInfo = findFuncByOid(plang->lanvalidator);
   13161          84 :         if (validatorInfo != NULL && !validatorInfo->dobj.dump)
   13162           2 :             validatorInfo = NULL;
   13163             :     }
   13164             : 
   13165             :     /*
   13166             :      * If the functions are dumpable then emit a complete CREATE LANGUAGE with
   13167             :      * parameters.  Otherwise, we'll write a parameterless command, which will
   13168             :      * be interpreted as CREATE EXTENSION.
   13169             :      */
   13170          68 :     useParams = (funcInfo != NULL &&
   13171         290 :                  (inlineInfo != NULL || !OidIsValid(plang->laninline)) &&
   13172          68 :                  (validatorInfo != NULL || !OidIsValid(plang->lanvalidator)));
   13173             : 
   13174         154 :     defqry = createPQExpBuffer();
   13175         154 :     delqry = createPQExpBuffer();
   13176             : 
   13177         154 :     qlanname = pg_strdup(fmtId(plang->dobj.name));
   13178             : 
   13179         154 :     appendPQExpBuffer(delqry, "DROP PROCEDURAL LANGUAGE %s;\n",
   13180             :                       qlanname);
   13181             : 
   13182         154 :     if (useParams)
   13183             :     {
   13184          68 :         appendPQExpBuffer(defqry, "CREATE %sPROCEDURAL LANGUAGE %s",
   13185          68 :                           plang->lanpltrusted ? "TRUSTED " : "",
   13186             :                           qlanname);
   13187          68 :         appendPQExpBuffer(defqry, " HANDLER %s",
   13188          68 :                           fmtQualifiedDumpable(funcInfo));
   13189          68 :         if (OidIsValid(plang->laninline))
   13190           0 :             appendPQExpBuffer(defqry, " INLINE %s",
   13191           0 :                               fmtQualifiedDumpable(inlineInfo));
   13192          68 :         if (OidIsValid(plang->lanvalidator))
   13193           0 :             appendPQExpBuffer(defqry, " VALIDATOR %s",
   13194           0 :                               fmtQualifiedDumpable(validatorInfo));
   13195             :     }
   13196             :     else
   13197             :     {
   13198             :         /*
   13199             :          * If not dumping parameters, then use CREATE OR REPLACE so that the
   13200             :          * command will not fail if the language is preinstalled in the target
   13201             :          * database.
   13202             :          *
   13203             :          * Modern servers will interpret this as CREATE EXTENSION IF NOT
   13204             :          * EXISTS; perhaps we should emit that instead?  But it might just add
   13205             :          * confusion.
   13206             :          */
   13207          86 :         appendPQExpBuffer(defqry, "CREATE OR REPLACE PROCEDURAL LANGUAGE %s",
   13208             :                           qlanname);
   13209             :     }
   13210         154 :     appendPQExpBufferStr(defqry, ";\n");
   13211             : 
   13212         154 :     if (dopt->binary_upgrade)
   13213           4 :         binary_upgrade_extension_member(defqry, &plang->dobj,
   13214             :                                         "LANGUAGE", qlanname, NULL);
   13215             : 
   13216         154 :     if (plang->dobj.dump & DUMP_COMPONENT_DEFINITION)
   13217          70 :         ArchiveEntry(fout, plang->dobj.catId, plang->dobj.dumpId,
   13218          70 :                      ARCHIVE_OPTS(.tag = plang->dobj.name,
   13219             :                                   .owner = plang->lanowner,
   13220             :                                   .description = "PROCEDURAL LANGUAGE",
   13221             :                                   .section = SECTION_PRE_DATA,
   13222             :                                   .createStmt = defqry->data,
   13223             :                                   .dropStmt = delqry->data,
   13224             :                                   ));
   13225             : 
   13226             :     /* Dump Proc Lang Comments and Security Labels */
   13227         154 :     if (plang->dobj.dump & DUMP_COMPONENT_COMMENT)
   13228           0 :         dumpComment(fout, "LANGUAGE", qlanname,
   13229           0 :                     NULL, plang->lanowner,
   13230           0 :                     plang->dobj.catId, 0, plang->dobj.dumpId);
   13231             : 
   13232         154 :     if (plang->dobj.dump & DUMP_COMPONENT_SECLABEL)
   13233           0 :         dumpSecLabel(fout, "LANGUAGE", qlanname,
   13234           0 :                      NULL, plang->lanowner,
   13235           0 :                      plang->dobj.catId, 0, plang->dobj.dumpId);
   13236             : 
   13237         154 :     if (plang->lanpltrusted && plang->dobj.dump & DUMP_COMPONENT_ACL)
   13238          84 :         dumpACL(fout, plang->dobj.dumpId, InvalidDumpId, "LANGUAGE",
   13239             :                 qlanname, NULL, NULL,
   13240          84 :                 NULL, plang->lanowner, &plang->dacl);
   13241             : 
   13242         154 :     free(qlanname);
   13243             : 
   13244         154 :     destroyPQExpBuffer(defqry);
   13245         154 :     destroyPQExpBuffer(delqry);
   13246             : }
   13247             : 
   13248             : /*
   13249             :  * format_function_arguments: generate function name and argument list
   13250             :  *
   13251             :  * This is used when we can rely on pg_get_function_arguments to format
   13252             :  * the argument list.  Note, however, that pg_get_function_arguments
   13253             :  * does not special-case zero-argument aggregates.
   13254             :  */
   13255             : static char *
   13256       12224 : format_function_arguments(const FuncInfo *finfo, const char *funcargs, bool is_agg)
   13257             : {
   13258             :     PQExpBufferData fn;
   13259             : 
   13260       12224 :     initPQExpBuffer(&fn);
   13261       12224 :     appendPQExpBufferStr(&fn, fmtId(finfo->dobj.name));
   13262       12224 :     if (is_agg && finfo->nargs == 0)
   13263         256 :         appendPQExpBufferStr(&fn, "(*)");
   13264             :     else
   13265       11968 :         appendPQExpBuffer(&fn, "(%s)", funcargs);
   13266       12224 :     return fn.data;
   13267             : }
   13268             : 
   13269             : /*
   13270             :  * format_function_signature: generate function name and argument list
   13271             :  *
   13272             :  * Only a minimal list of input argument types is generated; this is
   13273             :  * sufficient to reference the function, but not to define it.
   13274             :  *
   13275             :  * If honor_quotes is false then the function name is never quoted.
   13276             :  * This is appropriate for use in TOC tags, but not in SQL commands.
   13277             :  */
   13278             : static char *
   13279        6370 : format_function_signature(Archive *fout, const FuncInfo *finfo, bool honor_quotes)
   13280             : {
   13281             :     PQExpBufferData fn;
   13282             :     int         j;
   13283             : 
   13284        6370 :     initPQExpBuffer(&fn);
   13285        6370 :     if (honor_quotes)
   13286        1118 :         appendPQExpBuffer(&fn, "%s(", fmtId(finfo->dobj.name));
   13287             :     else
   13288        5252 :         appendPQExpBuffer(&fn, "%s(", finfo->dobj.name);
   13289       11838 :     for (j = 0; j < finfo->nargs; j++)
   13290             :     {
   13291        5468 :         if (j > 0)
   13292        1348 :             appendPQExpBufferStr(&fn, ", ");
   13293             : 
   13294        5468 :         appendPQExpBufferStr(&fn,
   13295        5468 :                              getFormattedTypeName(fout, finfo->argtypes[j],
   13296             :                                                   zeroIsError));
   13297             :     }
   13298        6370 :     appendPQExpBufferChar(&fn, ')');
   13299        6370 :     return fn.data;
   13300             : }
   13301             : 
   13302             : 
   13303             : /*
   13304             :  * dumpFunc:
   13305             :  *    dump out one function
   13306             :  */
   13307             : static void
   13308        5376 : dumpFunc(Archive *fout, const FuncInfo *finfo)
   13309             : {
   13310        5376 :     DumpOptions *dopt = fout->dopt;
   13311             :     PQExpBuffer query;
   13312             :     PQExpBuffer q;
   13313             :     PQExpBuffer delqry;
   13314             :     PQExpBuffer asPart;
   13315             :     PGresult   *res;
   13316             :     char       *funcsig;        /* identity signature */
   13317        5376 :     char       *funcfullsig = NULL; /* full signature */
   13318             :     char       *funcsig_tag;
   13319             :     char       *qual_funcsig;
   13320             :     char       *proretset;
   13321             :     char       *prosrc;
   13322             :     char       *probin;
   13323             :     char       *prosqlbody;
   13324             :     char       *funcargs;
   13325             :     char       *funciargs;
   13326             :     char       *funcresult;
   13327             :     char       *protrftypes;
   13328             :     char       *prokind;
   13329             :     char       *provolatile;
   13330             :     char       *proisstrict;
   13331             :     char       *prosecdef;
   13332             :     char       *proleakproof;
   13333             :     char       *proconfig;
   13334             :     char       *procost;
   13335             :     char       *prorows;
   13336             :     char       *prosupport;
   13337             :     char       *proparallel;
   13338             :     char       *lanname;
   13339        5376 :     char      **configitems = NULL;
   13340        5376 :     int         nconfigitems = 0;
   13341             :     const char *keyword;
   13342             : 
   13343             :     /* Do nothing if not dumping schema */
   13344        5376 :     if (!dopt->dumpSchema)
   13345         124 :         return;
   13346             : 
   13347        5252 :     query = createPQExpBuffer();
   13348        5252 :     q = createPQExpBuffer();
   13349        5252 :     delqry = createPQExpBuffer();
   13350        5252 :     asPart = createPQExpBuffer();
   13351             : 
   13352        5252 :     if (!fout->is_prepared[PREPQUERY_DUMPFUNC])
   13353             :     {
   13354             :         /* Set up query for function-specific details */
   13355         150 :         appendPQExpBufferStr(query,
   13356             :                              "PREPARE dumpFunc(pg_catalog.oid) AS\n");
   13357             : 
   13358         150 :         appendPQExpBufferStr(query,
   13359             :                              "SELECT\n"
   13360             :                              "proretset,\n"
   13361             :                              "prosrc,\n"
   13362             :                              "probin,\n"
   13363             :                              "provolatile,\n"
   13364             :                              "proisstrict,\n"
   13365             :                              "prosecdef,\n"
   13366             :                              "lanname,\n"
   13367             :                              "proconfig,\n"
   13368             :                              "procost,\n"
   13369             :                              "prorows,\n"
   13370             :                              "pg_catalog.pg_get_function_arguments(p.oid) AS funcargs,\n"
   13371             :                              "pg_catalog.pg_get_function_identity_arguments(p.oid) AS funciargs,\n"
   13372             :                              "pg_catalog.pg_get_function_result(p.oid) AS funcresult,\n"
   13373             :                              "proleakproof,\n");
   13374             : 
   13375         150 :         if (fout->remoteVersion >= 90500)
   13376         150 :             appendPQExpBufferStr(query,
   13377             :                                  "array_to_string(protrftypes, ' ') AS protrftypes,\n");
   13378             :         else
   13379           0 :             appendPQExpBufferStr(query,
   13380             :                                  "NULL AS protrftypes,\n");
   13381             : 
   13382         150 :         if (fout->remoteVersion >= 90600)
   13383         150 :             appendPQExpBufferStr(query,
   13384             :                                  "proparallel,\n");
   13385             :         else
   13386           0 :             appendPQExpBufferStr(query,
   13387             :                                  "'u' AS proparallel,\n");
   13388             : 
   13389         150 :         if (fout->remoteVersion >= 110000)
   13390         150 :             appendPQExpBufferStr(query,
   13391             :                                  "prokind,\n");
   13392             :         else
   13393           0 :             appendPQExpBufferStr(query,
   13394             :                                  "CASE WHEN proiswindow THEN 'w' ELSE 'f' END AS prokind,\n");
   13395             : 
   13396         150 :         if (fout->remoteVersion >= 120000)
   13397         150 :             appendPQExpBufferStr(query,
   13398             :                                  "prosupport,\n");
   13399             :         else
   13400           0 :             appendPQExpBufferStr(query,
   13401             :                                  "'-' AS prosupport,\n");
   13402             : 
   13403         150 :         if (fout->remoteVersion >= 140000)
   13404         150 :             appendPQExpBufferStr(query,
   13405             :                                  "pg_get_function_sqlbody(p.oid) AS prosqlbody\n");
   13406             :         else
   13407           0 :             appendPQExpBufferStr(query,
   13408             :                                  "NULL AS prosqlbody\n");
   13409             : 
   13410         150 :         appendPQExpBufferStr(query,
   13411             :                              "FROM pg_catalog.pg_proc p, pg_catalog.pg_language l\n"
   13412             :                              "WHERE p.oid = $1 "
   13413             :                              "AND l.oid = p.prolang");
   13414             : 
   13415         150 :         ExecuteSqlStatement(fout, query->data);
   13416             : 
   13417         150 :         fout->is_prepared[PREPQUERY_DUMPFUNC] = true;
   13418             :     }
   13419             : 
   13420        5252 :     printfPQExpBuffer(query,
   13421             :                       "EXECUTE dumpFunc('%u')",
   13422        5252 :                       finfo->dobj.catId.oid);
   13423             : 
   13424        5252 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   13425             : 
   13426        5252 :     proretset = PQgetvalue(res, 0, PQfnumber(res, "proretset"));
   13427        5252 :     if (PQgetisnull(res, 0, PQfnumber(res, "prosqlbody")))
   13428             :     {
   13429        5130 :         prosrc = PQgetvalue(res, 0, PQfnumber(res, "prosrc"));
   13430        5130 :         probin = PQgetvalue(res, 0, PQfnumber(res, "probin"));
   13431        5130 :         prosqlbody = NULL;
   13432             :     }
   13433             :     else
   13434             :     {
   13435         122 :         prosrc = NULL;
   13436         122 :         probin = NULL;
   13437         122 :         prosqlbody = PQgetvalue(res, 0, PQfnumber(res, "prosqlbody"));
   13438             :     }
   13439        5252 :     funcargs = PQgetvalue(res, 0, PQfnumber(res, "funcargs"));
   13440        5252 :     funciargs = PQgetvalue(res, 0, PQfnumber(res, "funciargs"));
   13441        5252 :     funcresult = PQgetvalue(res, 0, PQfnumber(res, "funcresult"));
   13442        5252 :     protrftypes = PQgetvalue(res, 0, PQfnumber(res, "protrftypes"));
   13443        5252 :     prokind = PQgetvalue(res, 0, PQfnumber(res, "prokind"));
   13444        5252 :     provolatile = PQgetvalue(res, 0, PQfnumber(res, "provolatile"));
   13445        5252 :     proisstrict = PQgetvalue(res, 0, PQfnumber(res, "proisstrict"));
   13446        5252 :     prosecdef = PQgetvalue(res, 0, PQfnumber(res, "prosecdef"));
   13447        5252 :     proleakproof = PQgetvalue(res, 0, PQfnumber(res, "proleakproof"));
   13448        5252 :     proconfig = PQgetvalue(res, 0, PQfnumber(res, "proconfig"));
   13449        5252 :     procost = PQgetvalue(res, 0, PQfnumber(res, "procost"));
   13450        5252 :     prorows = PQgetvalue(res, 0, PQfnumber(res, "prorows"));
   13451        5252 :     prosupport = PQgetvalue(res, 0, PQfnumber(res, "prosupport"));
   13452        5252 :     proparallel = PQgetvalue(res, 0, PQfnumber(res, "proparallel"));
   13453        5252 :     lanname = PQgetvalue(res, 0, PQfnumber(res, "lanname"));
   13454             : 
   13455             :     /*
   13456             :      * See backend/commands/functioncmds.c for details of how the 'AS' clause
   13457             :      * is used.
   13458             :      */
   13459        5252 :     if (prosqlbody)
   13460             :     {
   13461         122 :         appendPQExpBufferStr(asPart, prosqlbody);
   13462             :     }
   13463        5130 :     else if (probin[0] != '\0')
   13464             :     {
   13465         392 :         appendPQExpBufferStr(asPart, "AS ");
   13466         392 :         appendStringLiteralAH(asPart, probin, fout);
   13467         392 :         if (prosrc[0] != '\0')
   13468             :         {
   13469         392 :             appendPQExpBufferStr(asPart, ", ");
   13470             : 
   13471             :             /*
   13472             :              * where we have bin, use dollar quoting if allowed and src
   13473             :              * contains quote or backslash; else use regular quoting.
   13474             :              */
   13475         392 :             if (dopt->disable_dollar_quoting ||
   13476         392 :                 (strchr(prosrc, '\'') == NULL && strchr(prosrc, '\\') == NULL))
   13477         392 :                 appendStringLiteralAH(asPart, prosrc, fout);
   13478             :             else
   13479           0 :                 appendStringLiteralDQ(asPart, prosrc, NULL);
   13480             :         }
   13481             :     }
   13482             :     else
   13483             :     {
   13484        4738 :         appendPQExpBufferStr(asPart, "AS ");
   13485             :         /* with no bin, dollar quote src unconditionally if allowed */
   13486        4738 :         if (dopt->disable_dollar_quoting)
   13487           0 :             appendStringLiteralAH(asPart, prosrc, fout);
   13488             :         else
   13489        4738 :             appendStringLiteralDQ(asPart, prosrc, NULL);
   13490             :     }
   13491             : 
   13492        5252 :     if (*proconfig)
   13493             :     {
   13494          48 :         if (!parsePGArray(proconfig, &configitems, &nconfigitems))
   13495           0 :             pg_fatal("could not parse %s array", "proconfig");
   13496             :     }
   13497             :     else
   13498             :     {
   13499        5204 :         configitems = NULL;
   13500        5204 :         nconfigitems = 0;
   13501             :     }
   13502             : 
   13503        5252 :     funcfullsig = format_function_arguments(finfo, funcargs, false);
   13504        5252 :     funcsig = format_function_arguments(finfo, funciargs, false);
   13505             : 
   13506        5252 :     funcsig_tag = format_function_signature(fout, finfo, false);
   13507             : 
   13508        5252 :     qual_funcsig = psprintf("%s.%s",
   13509        5252 :                             fmtId(finfo->dobj.namespace->dobj.name),
   13510             :                             funcsig);
   13511             : 
   13512        5252 :     if (prokind[0] == PROKIND_PROCEDURE)
   13513         264 :         keyword = "PROCEDURE";
   13514             :     else
   13515        4988 :         keyword = "FUNCTION"; /* works for window functions too */
   13516             : 
   13517        5252 :     appendPQExpBuffer(delqry, "DROP %s %s;\n",
   13518             :                       keyword, qual_funcsig);
   13519             : 
   13520       10504 :     appendPQExpBuffer(q, "CREATE %s %s.%s",
   13521             :                       keyword,
   13522        5252 :                       fmtId(finfo->dobj.namespace->dobj.name),
   13523             :                       funcfullsig ? funcfullsig :
   13524             :                       funcsig);
   13525             : 
   13526        5252 :     if (prokind[0] == PROKIND_PROCEDURE)
   13527             :          /* no result type to output */ ;
   13528        4988 :     else if (funcresult)
   13529        4988 :         appendPQExpBuffer(q, " RETURNS %s", funcresult);
   13530             :     else
   13531           0 :         appendPQExpBuffer(q, " RETURNS %s%s",
   13532           0 :                           (proretset[0] == 't') ? "SETOF " : "",
   13533           0 :                           getFormattedTypeName(fout, finfo->prorettype,
   13534             :                                                zeroIsError));
   13535             : 
   13536        5252 :     appendPQExpBuffer(q, "\n    LANGUAGE %s", fmtId(lanname));
   13537             : 
   13538        5252 :     if (*protrftypes)
   13539             :     {
   13540           0 :         Oid        *typeids = pg_malloc(FUNC_MAX_ARGS * sizeof(Oid));
   13541             :         int         i;
   13542             : 
   13543           0 :         appendPQExpBufferStr(q, " TRANSFORM ");
   13544           0 :         parseOidArray(protrftypes, typeids, FUNC_MAX_ARGS);
   13545           0 :         for (i = 0; typeids[i]; i++)
   13546             :         {
   13547           0 :             if (i != 0)
   13548           0 :                 appendPQExpBufferStr(q, ", ");
   13549           0 :             appendPQExpBuffer(q, "FOR TYPE %s",
   13550           0 :                               getFormattedTypeName(fout, typeids[i], zeroAsNone));
   13551             :         }
   13552             : 
   13553           0 :         free(typeids);
   13554             :     }
   13555             : 
   13556        5252 :     if (prokind[0] == PROKIND_WINDOW)
   13557          16 :         appendPQExpBufferStr(q, " WINDOW");
   13558             : 
   13559        5252 :     if (provolatile[0] != PROVOLATILE_VOLATILE)
   13560             :     {
   13561        1054 :         if (provolatile[0] == PROVOLATILE_IMMUTABLE)
   13562         988 :             appendPQExpBufferStr(q, " IMMUTABLE");
   13563          66 :         else if (provolatile[0] == PROVOLATILE_STABLE)
   13564          66 :             appendPQExpBufferStr(q, " STABLE");
   13565           0 :         else if (provolatile[0] != PROVOLATILE_VOLATILE)
   13566           0 :             pg_fatal("unrecognized provolatile value for function \"%s\"",
   13567             :                      finfo->dobj.name);
   13568             :     }
   13569             : 
   13570        5252 :     if (proisstrict[0] == 't')
   13571        1030 :         appendPQExpBufferStr(q, " STRICT");
   13572             : 
   13573        5252 :     if (prosecdef[0] == 't')
   13574           0 :         appendPQExpBufferStr(q, " SECURITY DEFINER");
   13575             : 
   13576        5252 :     if (proleakproof[0] == 't')
   13577          32 :         appendPQExpBufferStr(q, " LEAKPROOF");
   13578             : 
   13579             :     /*
   13580             :      * COST and ROWS are emitted only if present and not default, so as not to
   13581             :      * break backwards-compatibility of the dump without need.  Keep this code
   13582             :      * in sync with the defaults in functioncmds.c.
   13583             :      */
   13584        5252 :     if (strcmp(procost, "0") != 0)
   13585             :     {
   13586        5252 :         if (strcmp(lanname, "internal") == 0 || strcmp(lanname, "c") == 0)
   13587             :         {
   13588             :             /* default cost is 1 */
   13589         996 :             if (strcmp(procost, "1") != 0)
   13590           0 :                 appendPQExpBuffer(q, " COST %s", procost);
   13591             :         }
   13592             :         else
   13593             :         {
   13594             :             /* default cost is 100 */
   13595        4256 :             if (strcmp(procost, "100") != 0)
   13596          18 :                 appendPQExpBuffer(q, " COST %s", procost);
   13597             :         }
   13598             :     }
   13599        5252 :     if (proretset[0] == 't' &&
   13600         568 :         strcmp(prorows, "0") != 0 && strcmp(prorows, "1000") != 0)
   13601           0 :         appendPQExpBuffer(q, " ROWS %s", prorows);
   13602             : 
   13603        5252 :     if (strcmp(prosupport, "-") != 0)
   13604             :     {
   13605             :         /* We rely on regprocout to provide quoting and qualification */
   13606         104 :         appendPQExpBuffer(q, " SUPPORT %s", prosupport);
   13607             :     }
   13608             : 
   13609        5252 :     if (proparallel[0] != PROPARALLEL_UNSAFE)
   13610             :     {
   13611         302 :         if (proparallel[0] == PROPARALLEL_SAFE)
   13612         286 :             appendPQExpBufferStr(q, " PARALLEL SAFE");
   13613          16 :         else if (proparallel[0] == PROPARALLEL_RESTRICTED)
   13614          16 :             appendPQExpBufferStr(q, " PARALLEL RESTRICTED");
   13615           0 :         else if (proparallel[0] != PROPARALLEL_UNSAFE)
   13616           0 :             pg_fatal("unrecognized proparallel value for function \"%s\"",
   13617             :                      finfo->dobj.name);
   13618             :     }
   13619             : 
   13620        5364 :     for (int i = 0; i < nconfigitems; i++)
   13621             :     {
   13622             :         /* we feel free to scribble on configitems[] here */
   13623         112 :         char       *configitem = configitems[i];
   13624             :         char       *pos;
   13625             : 
   13626         112 :         pos = strchr(configitem, '=');
   13627         112 :         if (pos == NULL)
   13628           0 :             continue;
   13629         112 :         *pos++ = '\0';
   13630         112 :         appendPQExpBuffer(q, "\n    SET %s TO ", fmtId(configitem));
   13631             : 
   13632             :         /*
   13633             :          * Variables that are marked GUC_LIST_QUOTE were already fully quoted
   13634             :          * by flatten_set_variable_args() before they were put into the
   13635             :          * proconfig array.  However, because the quoting rules used there
   13636             :          * aren't exactly like SQL's, we have to break the list value apart
   13637             :          * and then quote the elements as string literals.  (The elements may
   13638             :          * be double-quoted as-is, but we can't just feed them to the SQL
   13639             :          * parser; it would do the wrong thing with elements that are
   13640             :          * zero-length or longer than NAMEDATALEN.)
   13641             :          *
   13642             :          * Variables that are not so marked should just be emitted as simple
   13643             :          * string literals.  If the variable is not known to
   13644             :          * variable_is_guc_list_quote(), we'll do that; this makes it unsafe
   13645             :          * to use GUC_LIST_QUOTE for extension variables.
   13646             :          */
   13647         112 :         if (variable_is_guc_list_quote(configitem))
   13648             :         {
   13649             :             char      **namelist;
   13650             :             char      **nameptr;
   13651             : 
   13652             :             /* Parse string into list of identifiers */
   13653             :             /* this shouldn't fail really */
   13654          32 :             if (SplitGUCList(pos, ',', &namelist))
   13655             :             {
   13656         112 :                 for (nameptr = namelist; *nameptr; nameptr++)
   13657             :                 {
   13658          80 :                     if (nameptr != namelist)
   13659          48 :                         appendPQExpBufferStr(q, ", ");
   13660          80 :                     appendStringLiteralAH(q, *nameptr, fout);
   13661             :                 }
   13662             :             }
   13663          32 :             pg_free(namelist);
   13664             :         }
   13665             :         else
   13666          80 :             appendStringLiteralAH(q, pos, fout);
   13667             :     }
   13668             : 
   13669        5252 :     appendPQExpBuffer(q, "\n    %s;\n", asPart->data);
   13670             : 
   13671        5252 :     append_depends_on_extension(fout, q, &finfo->dobj,
   13672             :                                 "pg_catalog.pg_proc", keyword,
   13673             :                                 qual_funcsig);
   13674             : 
   13675        5252 :     if (dopt->binary_upgrade)
   13676         576 :         binary_upgrade_extension_member(q, &finfo->dobj,
   13677             :                                         keyword, funcsig,
   13678         576 :                                         finfo->dobj.namespace->dobj.name);
   13679             : 
   13680        5252 :     if (finfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   13681        5044 :         ArchiveEntry(fout, finfo->dobj.catId, finfo->dobj.dumpId,
   13682        5044 :                      ARCHIVE_OPTS(.tag = funcsig_tag,
   13683             :                                   .namespace = finfo->dobj.namespace->dobj.name,
   13684             :                                   .owner = finfo->rolname,
   13685             :                                   .description = keyword,
   13686             :                                   .section = finfo->postponed_def ?
   13687             :                                   SECTION_POST_DATA : SECTION_PRE_DATA,
   13688             :                                   .createStmt = q->data,
   13689             :                                   .dropStmt = delqry->data));
   13690             : 
   13691             :     /* Dump Function Comments and Security Labels */
   13692        5252 :     if (finfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   13693          18 :         dumpComment(fout, keyword, funcsig,
   13694          18 :                     finfo->dobj.namespace->dobj.name, finfo->rolname,
   13695          18 :                     finfo->dobj.catId, 0, finfo->dobj.dumpId);
   13696             : 
   13697        5252 :     if (finfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
   13698           0 :         dumpSecLabel(fout, keyword, funcsig,
   13699           0 :                      finfo->dobj.namespace->dobj.name, finfo->rolname,
   13700           0 :                      finfo->dobj.catId, 0, finfo->dobj.dumpId);
   13701             : 
   13702        5252 :     if (finfo->dobj.dump & DUMP_COMPONENT_ACL)
   13703         230 :         dumpACL(fout, finfo->dobj.dumpId, InvalidDumpId, keyword,
   13704             :                 funcsig, NULL,
   13705         230 :                 finfo->dobj.namespace->dobj.name,
   13706         230 :                 NULL, finfo->rolname, &finfo->dacl);
   13707             : 
   13708        5252 :     PQclear(res);
   13709             : 
   13710        5252 :     destroyPQExpBuffer(query);
   13711        5252 :     destroyPQExpBuffer(q);
   13712        5252 :     destroyPQExpBuffer(delqry);
   13713        5252 :     destroyPQExpBuffer(asPart);
   13714        5252 :     free(funcsig);
   13715        5252 :     free(funcfullsig);
   13716        5252 :     free(funcsig_tag);
   13717        5252 :     free(qual_funcsig);
   13718        5252 :     free(configitems);
   13719             : }
   13720             : 
   13721             : 
   13722             : /*
   13723             :  * Dump a user-defined cast
   13724             :  */
   13725             : static void
   13726         178 : dumpCast(Archive *fout, const CastInfo *cast)
   13727             : {
   13728         178 :     DumpOptions *dopt = fout->dopt;
   13729             :     PQExpBuffer defqry;
   13730             :     PQExpBuffer delqry;
   13731             :     PQExpBuffer labelq;
   13732             :     PQExpBuffer castargs;
   13733         178 :     FuncInfo   *funcInfo = NULL;
   13734             :     const char *sourceType;
   13735             :     const char *targetType;
   13736             : 
   13737             :     /* Do nothing if not dumping schema */
   13738         178 :     if (!dopt->dumpSchema)
   13739          12 :         return;
   13740             : 
   13741             :     /* Cannot dump if we don't have the cast function's info */
   13742         166 :     if (OidIsValid(cast->castfunc))
   13743             :     {
   13744          86 :         funcInfo = findFuncByOid(cast->castfunc);
   13745          86 :         if (funcInfo == NULL)
   13746           0 :             pg_fatal("could not find function definition for function with OID %u",
   13747             :                      cast->castfunc);
   13748             :     }
   13749             : 
   13750         166 :     defqry = createPQExpBuffer();
   13751         166 :     delqry = createPQExpBuffer();
   13752         166 :     labelq = createPQExpBuffer();
   13753         166 :     castargs = createPQExpBuffer();
   13754             : 
   13755         166 :     sourceType = getFormattedTypeName(fout, cast->castsource, zeroAsNone);
   13756         166 :     targetType = getFormattedTypeName(fout, cast->casttarget, zeroAsNone);
   13757         166 :     appendPQExpBuffer(delqry, "DROP CAST (%s AS %s);\n",
   13758             :                       sourceType, targetType);
   13759             : 
   13760         166 :     appendPQExpBuffer(defqry, "CREATE CAST (%s AS %s) ",
   13761             :                       sourceType, targetType);
   13762             : 
   13763         166 :     switch (cast->castmethod)
   13764             :     {
   13765          80 :         case COERCION_METHOD_BINARY:
   13766          80 :             appendPQExpBufferStr(defqry, "WITHOUT FUNCTION");
   13767          80 :             break;
   13768           0 :         case COERCION_METHOD_INOUT:
   13769           0 :             appendPQExpBufferStr(defqry, "WITH INOUT");
   13770           0 :             break;
   13771          86 :         case COERCION_METHOD_FUNCTION:
   13772          86 :             if (funcInfo)
   13773             :             {
   13774          86 :                 char       *fsig = format_function_signature(fout, funcInfo, true);
   13775             : 
   13776             :                 /*
   13777             :                  * Always qualify the function name (format_function_signature
   13778             :                  * won't qualify it).
   13779             :                  */
   13780          86 :                 appendPQExpBuffer(defqry, "WITH FUNCTION %s.%s",
   13781          86 :                                   fmtId(funcInfo->dobj.namespace->dobj.name), fsig);
   13782          86 :                 free(fsig);
   13783             :             }
   13784             :             else
   13785           0 :                 pg_log_warning("bogus value in pg_cast.castfunc or pg_cast.castmethod field");
   13786          86 :             break;
   13787           0 :         default:
   13788           0 :             pg_log_warning("bogus value in pg_cast.castmethod field");
   13789             :     }
   13790             : 
   13791         166 :     if (cast->castcontext == 'a')
   13792          70 :         appendPQExpBufferStr(defqry, " AS ASSIGNMENT");
   13793          96 :     else if (cast->castcontext == 'i')
   13794          32 :         appendPQExpBufferStr(defqry, " AS IMPLICIT");
   13795         166 :     appendPQExpBufferStr(defqry, ";\n");
   13796             : 
   13797         166 :     appendPQExpBuffer(labelq, "CAST (%s AS %s)",
   13798             :                       sourceType, targetType);
   13799             : 
   13800         166 :     appendPQExpBuffer(castargs, "(%s AS %s)",
   13801             :                       sourceType, targetType);
   13802             : 
   13803         166 :     if (dopt->binary_upgrade)
   13804          14 :         binary_upgrade_extension_member(defqry, &cast->dobj,
   13805          14 :                                         "CAST", castargs->data, NULL);
   13806             : 
   13807         166 :     if (cast->dobj.dump & DUMP_COMPONENT_DEFINITION)
   13808         166 :         ArchiveEntry(fout, cast->dobj.catId, cast->dobj.dumpId,
   13809         166 :                      ARCHIVE_OPTS(.tag = labelq->data,
   13810             :                                   .description = "CAST",
   13811             :                                   .section = SECTION_PRE_DATA,
   13812             :                                   .createStmt = defqry->data,
   13813             :                                   .dropStmt = delqry->data));
   13814             : 
   13815             :     /* Dump Cast Comments */
   13816         166 :     if (cast->dobj.dump & DUMP_COMPONENT_COMMENT)
   13817           0 :         dumpComment(fout, "CAST", castargs->data,
   13818             :                     NULL, "",
   13819           0 :                     cast->dobj.catId, 0, cast->dobj.dumpId);
   13820             : 
   13821         166 :     destroyPQExpBuffer(defqry);
   13822         166 :     destroyPQExpBuffer(delqry);
   13823         166 :     destroyPQExpBuffer(labelq);
   13824         166 :     destroyPQExpBuffer(castargs);
   13825             : }
   13826             : 
   13827             : /*
   13828             :  * Dump a transform
   13829             :  */
   13830             : static void
   13831          98 : dumpTransform(Archive *fout, const TransformInfo *transform)
   13832             : {
   13833          98 :     DumpOptions *dopt = fout->dopt;
   13834             :     PQExpBuffer defqry;
   13835             :     PQExpBuffer delqry;
   13836             :     PQExpBuffer labelq;
   13837             :     PQExpBuffer transformargs;
   13838          98 :     FuncInfo   *fromsqlFuncInfo = NULL;
   13839          98 :     FuncInfo   *tosqlFuncInfo = NULL;
   13840             :     char       *lanname;
   13841             :     const char *transformType;
   13842             : 
   13843             :     /* Do nothing if not dumping schema */
   13844          98 :     if (!dopt->dumpSchema)
   13845          12 :         return;
   13846             : 
   13847             :     /* Cannot dump if we don't have the transform functions' info */
   13848          86 :     if (OidIsValid(transform->trffromsql))
   13849             :     {
   13850          86 :         fromsqlFuncInfo = findFuncByOid(transform->trffromsql);
   13851          86 :         if (fromsqlFuncInfo == NULL)
   13852           0 :             pg_fatal("could not find function definition for function with OID %u",
   13853             :                      transform->trffromsql);
   13854             :     }
   13855          86 :     if (OidIsValid(transform->trftosql))
   13856             :     {
   13857          86 :         tosqlFuncInfo = findFuncByOid(transform->trftosql);
   13858          86 :         if (tosqlFuncInfo == NULL)
   13859           0 :             pg_fatal("could not find function definition for function with OID %u",
   13860             :                      transform->trftosql);
   13861             :     }
   13862             : 
   13863          86 :     defqry = createPQExpBuffer();
   13864          86 :     delqry = createPQExpBuffer();
   13865          86 :     labelq = createPQExpBuffer();
   13866          86 :     transformargs = createPQExpBuffer();
   13867             : 
   13868          86 :     lanname = get_language_name(fout, transform->trflang);
   13869          86 :     transformType = getFormattedTypeName(fout, transform->trftype, zeroAsNone);
   13870             : 
   13871          86 :     appendPQExpBuffer(delqry, "DROP TRANSFORM FOR %s LANGUAGE %s;\n",
   13872             :                       transformType, lanname);
   13873             : 
   13874          86 :     appendPQExpBuffer(defqry, "CREATE TRANSFORM FOR %s LANGUAGE %s (",
   13875             :                       transformType, lanname);
   13876             : 
   13877          86 :     if (!transform->trffromsql && !transform->trftosql)
   13878           0 :         pg_log_warning("bogus transform definition, at least one of trffromsql and trftosql should be nonzero");
   13879             : 
   13880          86 :     if (transform->trffromsql)
   13881             :     {
   13882          86 :         if (fromsqlFuncInfo)
   13883             :         {
   13884          86 :             char       *fsig = format_function_signature(fout, fromsqlFuncInfo, true);
   13885             : 
   13886             :             /*
   13887             :              * Always qualify the function name (format_function_signature
   13888             :              * won't qualify it).
   13889             :              */
   13890          86 :             appendPQExpBuffer(defqry, "FROM SQL WITH FUNCTION %s.%s",
   13891          86 :                               fmtId(fromsqlFuncInfo->dobj.namespace->dobj.name), fsig);
   13892          86 :             free(fsig);
   13893             :         }
   13894             :         else
   13895           0 :             pg_log_warning("bogus value in pg_transform.trffromsql field");
   13896             :     }
   13897             : 
   13898          86 :     if (transform->trftosql)
   13899             :     {
   13900          86 :         if (transform->trffromsql)
   13901          86 :             appendPQExpBufferStr(defqry, ", ");
   13902             : 
   13903          86 :         if (tosqlFuncInfo)
   13904             :         {
   13905          86 :             char       *fsig = format_function_signature(fout, tosqlFuncInfo, true);
   13906             : 
   13907             :             /*
   13908             :              * Always qualify the function name (format_function_signature
   13909             :              * won't qualify it).
   13910             :              */
   13911          86 :             appendPQExpBuffer(defqry, "TO SQL WITH FUNCTION %s.%s",
   13912          86 :                               fmtId(tosqlFuncInfo->dobj.namespace->dobj.name), fsig);
   13913          86 :             free(fsig);
   13914             :         }
   13915             :         else
   13916           0 :             pg_log_warning("bogus value in pg_transform.trftosql field");
   13917             :     }
   13918             : 
   13919          86 :     appendPQExpBufferStr(defqry, ");\n");
   13920             : 
   13921          86 :     appendPQExpBuffer(labelq, "TRANSFORM FOR %s LANGUAGE %s",
   13922             :                       transformType, lanname);
   13923             : 
   13924          86 :     appendPQExpBuffer(transformargs, "FOR %s LANGUAGE %s",
   13925             :                       transformType, lanname);
   13926             : 
   13927          86 :     if (dopt->binary_upgrade)
   13928           4 :         binary_upgrade_extension_member(defqry, &transform->dobj,
   13929           4 :                                         "TRANSFORM", transformargs->data, NULL);
   13930             : 
   13931          86 :     if (transform->dobj.dump & DUMP_COMPONENT_DEFINITION)
   13932          86 :         ArchiveEntry(fout, transform->dobj.catId, transform->dobj.dumpId,
   13933          86 :                      ARCHIVE_OPTS(.tag = labelq->data,
   13934             :                                   .description = "TRANSFORM",
   13935             :                                   .section = SECTION_PRE_DATA,
   13936             :                                   .createStmt = defqry->data,
   13937             :                                   .dropStmt = delqry->data,
   13938             :                                   .deps = transform->dobj.dependencies,
   13939             :                                   .nDeps = transform->dobj.nDeps));
   13940             : 
   13941             :     /* Dump Transform Comments */
   13942          86 :     if (transform->dobj.dump & DUMP_COMPONENT_COMMENT)
   13943           0 :         dumpComment(fout, "TRANSFORM", transformargs->data,
   13944             :                     NULL, "",
   13945           0 :                     transform->dobj.catId, 0, transform->dobj.dumpId);
   13946             : 
   13947          86 :     free(lanname);
   13948          86 :     destroyPQExpBuffer(defqry);
   13949          86 :     destroyPQExpBuffer(delqry);
   13950          86 :     destroyPQExpBuffer(labelq);
   13951          86 :     destroyPQExpBuffer(transformargs);
   13952             : }
   13953             : 
   13954             : 
   13955             : /*
   13956             :  * dumpOpr
   13957             :  *    write out a single operator definition
   13958             :  */
   13959             : static void
   13960        5098 : dumpOpr(Archive *fout, const OprInfo *oprinfo)
   13961             : {
   13962        5098 :     DumpOptions *dopt = fout->dopt;
   13963             :     PQExpBuffer query;
   13964             :     PQExpBuffer q;
   13965             :     PQExpBuffer delq;
   13966             :     PQExpBuffer oprid;
   13967             :     PQExpBuffer details;
   13968             :     PGresult   *res;
   13969             :     int         i_oprkind;
   13970             :     int         i_oprcode;
   13971             :     int         i_oprleft;
   13972             :     int         i_oprright;
   13973             :     int         i_oprcom;
   13974             :     int         i_oprnegate;
   13975             :     int         i_oprrest;
   13976             :     int         i_oprjoin;
   13977             :     int         i_oprcanmerge;
   13978             :     int         i_oprcanhash;
   13979             :     char       *oprkind;
   13980             :     char       *oprcode;
   13981             :     char       *oprleft;
   13982             :     char       *oprright;
   13983             :     char       *oprcom;
   13984             :     char       *oprnegate;
   13985             :     char       *oprrest;
   13986             :     char       *oprjoin;
   13987             :     char       *oprcanmerge;
   13988             :     char       *oprcanhash;
   13989             :     char       *oprregproc;
   13990             :     char       *oprref;
   13991             : 
   13992             :     /* Do nothing if not dumping schema */
   13993        5098 :     if (!dopt->dumpSchema)
   13994          12 :         return;
   13995             : 
   13996             :     /*
   13997             :      * some operators are invalid because they were the result of user
   13998             :      * defining operators before commutators exist
   13999             :      */
   14000        5086 :     if (!OidIsValid(oprinfo->oprcode))
   14001          44 :         return;
   14002             : 
   14003        5042 :     query = createPQExpBuffer();
   14004        5042 :     q = createPQExpBuffer();
   14005        5042 :     delq = createPQExpBuffer();
   14006        5042 :     oprid = createPQExpBuffer();
   14007        5042 :     details = createPQExpBuffer();
   14008             : 
   14009        5042 :     if (!fout->is_prepared[PREPQUERY_DUMPOPR])
   14010             :     {
   14011             :         /* Set up query for operator-specific details */
   14012          94 :         appendPQExpBufferStr(query,
   14013             :                              "PREPARE dumpOpr(pg_catalog.oid) AS\n"
   14014             :                              "SELECT oprkind, "
   14015             :                              "oprcode::pg_catalog.regprocedure, "
   14016             :                              "oprleft::pg_catalog.regtype, "
   14017             :                              "oprright::pg_catalog.regtype, "
   14018             :                              "oprcom, "
   14019             :                              "oprnegate, "
   14020             :                              "oprrest::pg_catalog.regprocedure, "
   14021             :                              "oprjoin::pg_catalog.regprocedure, "
   14022             :                              "oprcanmerge, oprcanhash "
   14023             :                              "FROM pg_catalog.pg_operator "
   14024             :                              "WHERE oid = $1");
   14025             : 
   14026          94 :         ExecuteSqlStatement(fout, query->data);
   14027             : 
   14028          94 :         fout->is_prepared[PREPQUERY_DUMPOPR] = true;
   14029             :     }
   14030             : 
   14031        5042 :     printfPQExpBuffer(query,
   14032             :                       "EXECUTE dumpOpr('%u')",
   14033        5042 :                       oprinfo->dobj.catId.oid);
   14034             : 
   14035        5042 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   14036             : 
   14037        5042 :     i_oprkind = PQfnumber(res, "oprkind");
   14038        5042 :     i_oprcode = PQfnumber(res, "oprcode");
   14039        5042 :     i_oprleft = PQfnumber(res, "oprleft");
   14040        5042 :     i_oprright = PQfnumber(res, "oprright");
   14041        5042 :     i_oprcom = PQfnumber(res, "oprcom");
   14042        5042 :     i_oprnegate = PQfnumber(res, "oprnegate");
   14043        5042 :     i_oprrest = PQfnumber(res, "oprrest");
   14044        5042 :     i_oprjoin = PQfnumber(res, "oprjoin");
   14045        5042 :     i_oprcanmerge = PQfnumber(res, "oprcanmerge");
   14046        5042 :     i_oprcanhash = PQfnumber(res, "oprcanhash");
   14047             : 
   14048        5042 :     oprkind = PQgetvalue(res, 0, i_oprkind);
   14049        5042 :     oprcode = PQgetvalue(res, 0, i_oprcode);
   14050        5042 :     oprleft = PQgetvalue(res, 0, i_oprleft);
   14051        5042 :     oprright = PQgetvalue(res, 0, i_oprright);
   14052        5042 :     oprcom = PQgetvalue(res, 0, i_oprcom);
   14053        5042 :     oprnegate = PQgetvalue(res, 0, i_oprnegate);
   14054        5042 :     oprrest = PQgetvalue(res, 0, i_oprrest);
   14055        5042 :     oprjoin = PQgetvalue(res, 0, i_oprjoin);
   14056        5042 :     oprcanmerge = PQgetvalue(res, 0, i_oprcanmerge);
   14057        5042 :     oprcanhash = PQgetvalue(res, 0, i_oprcanhash);
   14058             : 
   14059             :     /* In PG14 upwards postfix operator support does not exist anymore. */
   14060        5042 :     if (strcmp(oprkind, "r") == 0)
   14061           0 :         pg_log_warning("postfix operators are not supported anymore (operator \"%s\")",
   14062             :                        oprcode);
   14063             : 
   14064        5042 :     oprregproc = convertRegProcReference(oprcode);
   14065        5042 :     if (oprregproc)
   14066             :     {
   14067        5042 :         appendPQExpBuffer(details, "    FUNCTION = %s", oprregproc);
   14068        5042 :         free(oprregproc);
   14069             :     }
   14070             : 
   14071        5042 :     appendPQExpBuffer(oprid, "%s (",
   14072        5042 :                       oprinfo->dobj.name);
   14073             : 
   14074             :     /*
   14075             :      * right unary means there's a left arg and left unary means there's a
   14076             :      * right arg.  (Although the "r" case is dead code for PG14 and later,
   14077             :      * continue to support it in case we're dumping from an old server.)
   14078             :      */
   14079        5042 :     if (strcmp(oprkind, "r") == 0 ||
   14080        5042 :         strcmp(oprkind, "b") == 0)
   14081             :     {
   14082        4732 :         appendPQExpBuffer(details, ",\n    LEFTARG = %s", oprleft);
   14083        4732 :         appendPQExpBufferStr(oprid, oprleft);
   14084             :     }
   14085             :     else
   14086         310 :         appendPQExpBufferStr(oprid, "NONE");
   14087             : 
   14088        5042 :     if (strcmp(oprkind, "l") == 0 ||
   14089        4732 :         strcmp(oprkind, "b") == 0)
   14090             :     {
   14091        5042 :         appendPQExpBuffer(details, ",\n    RIGHTARG = %s", oprright);
   14092        5042 :         appendPQExpBuffer(oprid, ", %s)", oprright);
   14093             :     }
   14094             :     else
   14095           0 :         appendPQExpBufferStr(oprid, ", NONE)");
   14096             : 
   14097        5042 :     oprref = getFormattedOperatorName(oprcom);
   14098        5042 :     if (oprref)
   14099             :     {
   14100        3346 :         appendPQExpBuffer(details, ",\n    COMMUTATOR = %s", oprref);
   14101        3346 :         free(oprref);
   14102             :     }
   14103             : 
   14104        5042 :     oprref = getFormattedOperatorName(oprnegate);
   14105        5042 :     if (oprref)
   14106             :     {
   14107        2332 :         appendPQExpBuffer(details, ",\n    NEGATOR = %s", oprref);
   14108        2332 :         free(oprref);
   14109             :     }
   14110             : 
   14111        5042 :     if (strcmp(oprcanmerge, "t") == 0)
   14112         394 :         appendPQExpBufferStr(details, ",\n    MERGES");
   14113             : 
   14114        5042 :     if (strcmp(oprcanhash, "t") == 0)
   14115         276 :         appendPQExpBufferStr(details, ",\n    HASHES");
   14116             : 
   14117        5042 :     oprregproc = convertRegProcReference(oprrest);
   14118        5042 :     if (oprregproc)
   14119             :     {
   14120        3052 :         appendPQExpBuffer(details, ",\n    RESTRICT = %s", oprregproc);
   14121        3052 :         free(oprregproc);
   14122             :     }
   14123             : 
   14124        5042 :     oprregproc = convertRegProcReference(oprjoin);
   14125        5042 :     if (oprregproc)
   14126             :     {
   14127        3052 :         appendPQExpBuffer(details, ",\n    JOIN = %s", oprregproc);
   14128        3052 :         free(oprregproc);
   14129             :     }
   14130             : 
   14131        5042 :     appendPQExpBuffer(delq, "DROP OPERATOR %s.%s;\n",
   14132        5042 :                       fmtId(oprinfo->dobj.namespace->dobj.name),
   14133             :                       oprid->data);
   14134             : 
   14135        5042 :     appendPQExpBuffer(q, "CREATE OPERATOR %s.%s (\n%s\n);\n",
   14136        5042 :                       fmtId(oprinfo->dobj.namespace->dobj.name),
   14137        5042 :                       oprinfo->dobj.name, details->data);
   14138             : 
   14139        5042 :     if (dopt->binary_upgrade)
   14140          24 :         binary_upgrade_extension_member(q, &oprinfo->dobj,
   14141          24 :                                         "OPERATOR", oprid->data,
   14142          24 :                                         oprinfo->dobj.namespace->dobj.name);
   14143             : 
   14144        5042 :     if (oprinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   14145        5042 :         ArchiveEntry(fout, oprinfo->dobj.catId, oprinfo->dobj.dumpId,
   14146        5042 :                      ARCHIVE_OPTS(.tag = oprinfo->dobj.name,
   14147             :                                   .namespace = oprinfo->dobj.namespace->dobj.name,
   14148             :                                   .owner = oprinfo->rolname,
   14149             :                                   .description = "OPERATOR",
   14150             :                                   .section = SECTION_PRE_DATA,
   14151             :                                   .createStmt = q->data,
   14152             :                                   .dropStmt = delq->data));
   14153             : 
   14154             :     /* Dump Operator Comments */
   14155        5042 :     if (oprinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   14156        4794 :         dumpComment(fout, "OPERATOR", oprid->data,
   14157        4794 :                     oprinfo->dobj.namespace->dobj.name, oprinfo->rolname,
   14158        4794 :                     oprinfo->dobj.catId, 0, oprinfo->dobj.dumpId);
   14159             : 
   14160        5042 :     PQclear(res);
   14161             : 
   14162        5042 :     destroyPQExpBuffer(query);
   14163        5042 :     destroyPQExpBuffer(q);
   14164        5042 :     destroyPQExpBuffer(delq);
   14165        5042 :     destroyPQExpBuffer(oprid);
   14166        5042 :     destroyPQExpBuffer(details);
   14167             : }
   14168             : 
   14169             : /*
   14170             :  * Convert a function reference obtained from pg_operator
   14171             :  *
   14172             :  * Returns allocated string of what to print, or NULL if function references
   14173             :  * is InvalidOid. Returned string is expected to be free'd by the caller.
   14174             :  *
   14175             :  * The input is a REGPROCEDURE display; we have to strip the argument-types
   14176             :  * part.
   14177             :  */
   14178             : static char *
   14179       15126 : convertRegProcReference(const char *proc)
   14180             : {
   14181             :     char       *name;
   14182             :     char       *paren;
   14183             :     bool        inquote;
   14184             : 
   14185             :     /* In all cases "-" means a null reference */
   14186       15126 :     if (strcmp(proc, "-") == 0)
   14187        3980 :         return NULL;
   14188             : 
   14189       11146 :     name = pg_strdup(proc);
   14190             :     /* find non-double-quoted left paren */
   14191       11146 :     inquote = false;
   14192      134312 :     for (paren = name; *paren; paren++)
   14193             :     {
   14194      134312 :         if (*paren == '(' && !inquote)
   14195             :         {
   14196       11146 :             *paren = '\0';
   14197       11146 :             break;
   14198             :         }
   14199      123166 :         if (*paren == '"')
   14200         100 :             inquote = !inquote;
   14201             :     }
   14202       11146 :     return name;
   14203             : }
   14204             : 
   14205             : /*
   14206             :  * getFormattedOperatorName - retrieve the operator name for the
   14207             :  * given operator OID (presented in string form).
   14208             :  *
   14209             :  * Returns an allocated string, or NULL if the given OID is invalid.
   14210             :  * Caller is responsible for free'ing result string.
   14211             :  *
   14212             :  * What we produce has the format "OPERATOR(schema.oprname)".  This is only
   14213             :  * useful in commands where the operator's argument types can be inferred from
   14214             :  * context.  We always schema-qualify the name, though.  The predecessor to
   14215             :  * this code tried to skip the schema qualification if possible, but that led
   14216             :  * to wrong results in corner cases, such as if an operator and its negator
   14217             :  * are in different schemas.
   14218             :  */
   14219             : static char *
   14220       10944 : getFormattedOperatorName(const char *oproid)
   14221             : {
   14222             :     OprInfo    *oprInfo;
   14223             : 
   14224             :     /* In all cases "0" means a null reference */
   14225       10944 :     if (strcmp(oproid, "0") == 0)
   14226        5266 :         return NULL;
   14227             : 
   14228        5678 :     oprInfo = findOprByOid(atooid(oproid));
   14229        5678 :     if (oprInfo == NULL)
   14230             :     {
   14231           0 :         pg_log_warning("could not find operator with OID %s",
   14232             :                        oproid);
   14233           0 :         return NULL;
   14234             :     }
   14235             : 
   14236        5678 :     return psprintf("OPERATOR(%s.%s)",
   14237        5678 :                     fmtId(oprInfo->dobj.namespace->dobj.name),
   14238             :                     oprInfo->dobj.name);
   14239             : }
   14240             : 
   14241             : /*
   14242             :  * Convert a function OID obtained from pg_ts_parser or pg_ts_template
   14243             :  *
   14244             :  * It is sufficient to use REGPROC rather than REGPROCEDURE, since the
   14245             :  * argument lists of these functions are predetermined.  Note that the
   14246             :  * caller should ensure we are in the proper schema, because the results
   14247             :  * are search path dependent!
   14248             :  */
   14249             : static char *
   14250         450 : convertTSFunction(Archive *fout, Oid funcOid)
   14251             : {
   14252             :     char       *result;
   14253             :     char        query[128];
   14254             :     PGresult   *res;
   14255             : 
   14256         450 :     snprintf(query, sizeof(query),
   14257             :              "SELECT '%u'::pg_catalog.regproc", funcOid);
   14258         450 :     res = ExecuteSqlQueryForSingleRow(fout, query);
   14259             : 
   14260         450 :     result = pg_strdup(PQgetvalue(res, 0, 0));
   14261             : 
   14262         450 :     PQclear(res);
   14263             : 
   14264         450 :     return result;
   14265             : }
   14266             : 
   14267             : /*
   14268             :  * dumpAccessMethod
   14269             :  *    write out a single access method definition
   14270             :  */
   14271             : static void
   14272         182 : dumpAccessMethod(Archive *fout, const AccessMethodInfo *aminfo)
   14273             : {
   14274         182 :     DumpOptions *dopt = fout->dopt;
   14275             :     PQExpBuffer q;
   14276             :     PQExpBuffer delq;
   14277             :     char       *qamname;
   14278             : 
   14279             :     /* Do nothing if not dumping schema */
   14280         182 :     if (!dopt->dumpSchema)
   14281          24 :         return;
   14282             : 
   14283         158 :     q = createPQExpBuffer();
   14284         158 :     delq = createPQExpBuffer();
   14285             : 
   14286         158 :     qamname = pg_strdup(fmtId(aminfo->dobj.name));
   14287             : 
   14288         158 :     appendPQExpBuffer(q, "CREATE ACCESS METHOD %s ", qamname);
   14289             : 
   14290         158 :     switch (aminfo->amtype)
   14291             :     {
   14292          72 :         case AMTYPE_INDEX:
   14293          72 :             appendPQExpBufferStr(q, "TYPE INDEX ");
   14294          72 :             break;
   14295          86 :         case AMTYPE_TABLE:
   14296          86 :             appendPQExpBufferStr(q, "TYPE TABLE ");
   14297          86 :             break;
   14298           0 :         default:
   14299           0 :             pg_log_warning("invalid type \"%c\" of access method \"%s\"",
   14300             :                            aminfo->amtype, qamname);
   14301           0 :             destroyPQExpBuffer(q);
   14302           0 :             destroyPQExpBuffer(delq);
   14303           0 :             free(qamname);
   14304           0 :             return;
   14305             :     }
   14306             : 
   14307         158 :     appendPQExpBuffer(q, "HANDLER %s;\n", aminfo->amhandler);
   14308             : 
   14309         158 :     appendPQExpBuffer(delq, "DROP ACCESS METHOD %s;\n",
   14310             :                       qamname);
   14311             : 
   14312         158 :     if (dopt->binary_upgrade)
   14313           8 :         binary_upgrade_extension_member(q, &aminfo->dobj,
   14314             :                                         "ACCESS METHOD", qamname, NULL);
   14315             : 
   14316         158 :     if (aminfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   14317         158 :         ArchiveEntry(fout, aminfo->dobj.catId, aminfo->dobj.dumpId,
   14318         158 :                      ARCHIVE_OPTS(.tag = aminfo->dobj.name,
   14319             :                                   .description = "ACCESS METHOD",
   14320             :                                   .section = SECTION_PRE_DATA,
   14321             :                                   .createStmt = q->data,
   14322             :                                   .dropStmt = delq->data));
   14323             : 
   14324             :     /* Dump Access Method Comments */
   14325         158 :     if (aminfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   14326           0 :         dumpComment(fout, "ACCESS METHOD", qamname,
   14327             :                     NULL, "",
   14328           0 :                     aminfo->dobj.catId, 0, aminfo->dobj.dumpId);
   14329             : 
   14330         158 :     destroyPQExpBuffer(q);
   14331         158 :     destroyPQExpBuffer(delq);
   14332         158 :     free(qamname);
   14333             : }
   14334             : 
   14335             : /*
   14336             :  * dumpOpclass
   14337             :  *    write out a single operator class definition
   14338             :  */
   14339             : static void
   14340        1362 : dumpOpclass(Archive *fout, const OpclassInfo *opcinfo)
   14341             : {
   14342        1362 :     DumpOptions *dopt = fout->dopt;
   14343             :     PQExpBuffer query;
   14344             :     PQExpBuffer q;
   14345             :     PQExpBuffer delq;
   14346             :     PQExpBuffer nameusing;
   14347             :     PGresult   *res;
   14348             :     int         ntups;
   14349             :     int         i_opcintype;
   14350             :     int         i_opckeytype;
   14351             :     int         i_opcdefault;
   14352             :     int         i_opcfamily;
   14353             :     int         i_opcfamilyname;
   14354             :     int         i_opcfamilynsp;
   14355             :     int         i_amname;
   14356             :     int         i_amopstrategy;
   14357             :     int         i_amopopr;
   14358             :     int         i_sortfamily;
   14359             :     int         i_sortfamilynsp;
   14360             :     int         i_amprocnum;
   14361             :     int         i_amproc;
   14362             :     int         i_amproclefttype;
   14363             :     int         i_amprocrighttype;
   14364             :     char       *opcintype;
   14365             :     char       *opckeytype;
   14366             :     char       *opcdefault;
   14367             :     char       *opcfamily;
   14368             :     char       *opcfamilyname;
   14369             :     char       *opcfamilynsp;
   14370             :     char       *amname;
   14371             :     char       *amopstrategy;
   14372             :     char       *amopopr;
   14373             :     char       *sortfamily;
   14374             :     char       *sortfamilynsp;
   14375             :     char       *amprocnum;
   14376             :     char       *amproc;
   14377             :     char       *amproclefttype;
   14378             :     char       *amprocrighttype;
   14379             :     bool        needComma;
   14380             :     int         i;
   14381             : 
   14382             :     /* Do nothing if not dumping schema */
   14383        1362 :     if (!dopt->dumpSchema)
   14384          36 :         return;
   14385             : 
   14386        1326 :     query = createPQExpBuffer();
   14387        1326 :     q = createPQExpBuffer();
   14388        1326 :     delq = createPQExpBuffer();
   14389        1326 :     nameusing = createPQExpBuffer();
   14390             : 
   14391             :     /* Get additional fields from the pg_opclass row */
   14392        1326 :     appendPQExpBuffer(query, "SELECT opcintype::pg_catalog.regtype, "
   14393             :                       "opckeytype::pg_catalog.regtype, "
   14394             :                       "opcdefault, opcfamily, "
   14395             :                       "opfname AS opcfamilyname, "
   14396             :                       "nspname AS opcfamilynsp, "
   14397             :                       "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opcmethod) AS amname "
   14398             :                       "FROM pg_catalog.pg_opclass c "
   14399             :                       "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = opcfamily "
   14400             :                       "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
   14401             :                       "WHERE c.oid = '%u'::pg_catalog.oid",
   14402        1326 :                       opcinfo->dobj.catId.oid);
   14403             : 
   14404        1326 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   14405             : 
   14406        1326 :     i_opcintype = PQfnumber(res, "opcintype");
   14407        1326 :     i_opckeytype = PQfnumber(res, "opckeytype");
   14408        1326 :     i_opcdefault = PQfnumber(res, "opcdefault");
   14409        1326 :     i_opcfamily = PQfnumber(res, "opcfamily");
   14410        1326 :     i_opcfamilyname = PQfnumber(res, "opcfamilyname");
   14411        1326 :     i_opcfamilynsp = PQfnumber(res, "opcfamilynsp");
   14412        1326 :     i_amname = PQfnumber(res, "amname");
   14413             : 
   14414             :     /* opcintype may still be needed after we PQclear res */
   14415        1326 :     opcintype = pg_strdup(PQgetvalue(res, 0, i_opcintype));
   14416        1326 :     opckeytype = PQgetvalue(res, 0, i_opckeytype);
   14417        1326 :     opcdefault = PQgetvalue(res, 0, i_opcdefault);
   14418             :     /* opcfamily will still be needed after we PQclear res */
   14419        1326 :     opcfamily = pg_strdup(PQgetvalue(res, 0, i_opcfamily));
   14420        1326 :     opcfamilyname = PQgetvalue(res, 0, i_opcfamilyname);
   14421        1326 :     opcfamilynsp = PQgetvalue(res, 0, i_opcfamilynsp);
   14422             :     /* amname will still be needed after we PQclear res */
   14423        1326 :     amname = pg_strdup(PQgetvalue(res, 0, i_amname));
   14424             : 
   14425        1326 :     appendPQExpBuffer(delq, "DROP OPERATOR CLASS %s",
   14426        1326 :                       fmtQualifiedDumpable(opcinfo));
   14427        1326 :     appendPQExpBuffer(delq, " USING %s;\n",
   14428             :                       fmtId(amname));
   14429             : 
   14430             :     /* Build the fixed portion of the CREATE command */
   14431        1326 :     appendPQExpBuffer(q, "CREATE OPERATOR CLASS %s\n    ",
   14432        1326 :                       fmtQualifiedDumpable(opcinfo));
   14433        1326 :     if (strcmp(opcdefault, "t") == 0)
   14434         714 :         appendPQExpBufferStr(q, "DEFAULT ");
   14435        1326 :     appendPQExpBuffer(q, "FOR TYPE %s USING %s",
   14436             :                       opcintype,
   14437             :                       fmtId(amname));
   14438        1326 :     if (strlen(opcfamilyname) > 0)
   14439             :     {
   14440        1326 :         appendPQExpBufferStr(q, " FAMILY ");
   14441        1326 :         appendPQExpBuffer(q, "%s.", fmtId(opcfamilynsp));
   14442        1326 :         appendPQExpBufferStr(q, fmtId(opcfamilyname));
   14443             :     }
   14444        1326 :     appendPQExpBufferStr(q, " AS\n    ");
   14445             : 
   14446        1326 :     needComma = false;
   14447             : 
   14448        1326 :     if (strcmp(opckeytype, "-") != 0)
   14449             :     {
   14450         504 :         appendPQExpBuffer(q, "STORAGE %s",
   14451             :                           opckeytype);
   14452         504 :         needComma = true;
   14453             :     }
   14454             : 
   14455        1326 :     PQclear(res);
   14456             : 
   14457             :     /*
   14458             :      * Now fetch and print the OPERATOR entries (pg_amop rows).
   14459             :      *
   14460             :      * Print only those opfamily members that are tied to the opclass by
   14461             :      * pg_depend entries.
   14462             :      */
   14463        1326 :     resetPQExpBuffer(query);
   14464        1326 :     appendPQExpBuffer(query, "SELECT amopstrategy, "
   14465             :                       "amopopr::pg_catalog.regoperator, "
   14466             :                       "opfname AS sortfamily, "
   14467             :                       "nspname AS sortfamilynsp "
   14468             :                       "FROM pg_catalog.pg_amop ao JOIN pg_catalog.pg_depend ON "
   14469             :                       "(classid = 'pg_catalog.pg_amop'::pg_catalog.regclass AND objid = ao.oid) "
   14470             :                       "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = amopsortfamily "
   14471             :                       "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
   14472             :                       "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
   14473             :                       "AND refobjid = '%u'::pg_catalog.oid "
   14474             :                       "AND amopfamily = '%s'::pg_catalog.oid "
   14475             :                       "ORDER BY amopstrategy",
   14476        1326 :                       opcinfo->dobj.catId.oid,
   14477             :                       opcfamily);
   14478             : 
   14479        1326 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   14480             : 
   14481        1326 :     ntups = PQntuples(res);
   14482             : 
   14483        1326 :     i_amopstrategy = PQfnumber(res, "amopstrategy");
   14484        1326 :     i_amopopr = PQfnumber(res, "amopopr");
   14485        1326 :     i_sortfamily = PQfnumber(res, "sortfamily");
   14486        1326 :     i_sortfamilynsp = PQfnumber(res, "sortfamilynsp");
   14487             : 
   14488        1790 :     for (i = 0; i < ntups; i++)
   14489             :     {
   14490         464 :         amopstrategy = PQgetvalue(res, i, i_amopstrategy);
   14491         464 :         amopopr = PQgetvalue(res, i, i_amopopr);
   14492         464 :         sortfamily = PQgetvalue(res, i, i_sortfamily);
   14493         464 :         sortfamilynsp = PQgetvalue(res, i, i_sortfamilynsp);
   14494             : 
   14495         464 :         if (needComma)
   14496         288 :             appendPQExpBufferStr(q, " ,\n    ");
   14497             : 
   14498         464 :         appendPQExpBuffer(q, "OPERATOR %s %s",
   14499             :                           amopstrategy, amopopr);
   14500             : 
   14501         464 :         if (strlen(sortfamily) > 0)
   14502             :         {
   14503           0 :             appendPQExpBufferStr(q, " FOR ORDER BY ");
   14504           0 :             appendPQExpBuffer(q, "%s.", fmtId(sortfamilynsp));
   14505           0 :             appendPQExpBufferStr(q, fmtId(sortfamily));
   14506             :         }
   14507             : 
   14508         464 :         needComma = true;
   14509             :     }
   14510             : 
   14511        1326 :     PQclear(res);
   14512             : 
   14513             :     /*
   14514             :      * Now fetch and print the FUNCTION entries (pg_amproc rows).
   14515             :      *
   14516             :      * Print only those opfamily members that are tied to the opclass by
   14517             :      * pg_depend entries.
   14518             :      *
   14519             :      * We print the amproclefttype/amprocrighttype even though in most cases
   14520             :      * the backend could deduce the right values, because of the corner case
   14521             :      * of a btree sort support function for a cross-type comparison.
   14522             :      */
   14523        1326 :     resetPQExpBuffer(query);
   14524             : 
   14525        1326 :     appendPQExpBuffer(query, "SELECT amprocnum, "
   14526             :                       "amproc::pg_catalog.regprocedure, "
   14527             :                       "amproclefttype::pg_catalog.regtype, "
   14528             :                       "amprocrighttype::pg_catalog.regtype "
   14529             :                       "FROM pg_catalog.pg_amproc ap, pg_catalog.pg_depend "
   14530             :                       "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
   14531             :                       "AND refobjid = '%u'::pg_catalog.oid "
   14532             :                       "AND classid = 'pg_catalog.pg_amproc'::pg_catalog.regclass "
   14533             :                       "AND objid = ap.oid "
   14534             :                       "ORDER BY amprocnum",
   14535        1326 :                       opcinfo->dobj.catId.oid);
   14536             : 
   14537        1326 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   14538             : 
   14539        1326 :     ntups = PQntuples(res);
   14540             : 
   14541        1326 :     i_amprocnum = PQfnumber(res, "amprocnum");
   14542        1326 :     i_amproc = PQfnumber(res, "amproc");
   14543        1326 :     i_amproclefttype = PQfnumber(res, "amproclefttype");
   14544        1326 :     i_amprocrighttype = PQfnumber(res, "amprocrighttype");
   14545             : 
   14546        1398 :     for (i = 0; i < ntups; i++)
   14547             :     {
   14548          72 :         amprocnum = PQgetvalue(res, i, i_amprocnum);
   14549          72 :         amproc = PQgetvalue(res, i, i_amproc);
   14550          72 :         amproclefttype = PQgetvalue(res, i, i_amproclefttype);
   14551          72 :         amprocrighttype = PQgetvalue(res, i, i_amprocrighttype);
   14552             : 
   14553          72 :         if (needComma)
   14554          72 :             appendPQExpBufferStr(q, " ,\n    ");
   14555             : 
   14556          72 :         appendPQExpBuffer(q, "FUNCTION %s", amprocnum);
   14557             : 
   14558          72 :         if (*amproclefttype && *amprocrighttype)
   14559          72 :             appendPQExpBuffer(q, " (%s, %s)", amproclefttype, amprocrighttype);
   14560             : 
   14561          72 :         appendPQExpBuffer(q, " %s", amproc);
   14562             : 
   14563          72 :         needComma = true;
   14564             :     }
   14565             : 
   14566        1326 :     PQclear(res);
   14567             : 
   14568             :     /*
   14569             :      * If needComma is still false it means we haven't added anything after
   14570             :      * the AS keyword.  To avoid printing broken SQL, append a dummy STORAGE
   14571             :      * clause with the same datatype.  This isn't sanctioned by the
   14572             :      * documentation, but actually DefineOpClass will treat it as a no-op.
   14573             :      */
   14574        1326 :     if (!needComma)
   14575         646 :         appendPQExpBuffer(q, "STORAGE %s", opcintype);
   14576             : 
   14577        1326 :     appendPQExpBufferStr(q, ";\n");
   14578             : 
   14579        1326 :     appendPQExpBufferStr(nameusing, fmtId(opcinfo->dobj.name));
   14580        1326 :     appendPQExpBuffer(nameusing, " USING %s",
   14581             :                       fmtId(amname));
   14582             : 
   14583        1326 :     if (dopt->binary_upgrade)
   14584          12 :         binary_upgrade_extension_member(q, &opcinfo->dobj,
   14585          12 :                                         "OPERATOR CLASS", nameusing->data,
   14586          12 :                                         opcinfo->dobj.namespace->dobj.name);
   14587             : 
   14588        1326 :     if (opcinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   14589        1326 :         ArchiveEntry(fout, opcinfo->dobj.catId, opcinfo->dobj.dumpId,
   14590        1326 :                      ARCHIVE_OPTS(.tag = opcinfo->dobj.name,
   14591             :                                   .namespace = opcinfo->dobj.namespace->dobj.name,
   14592             :                                   .owner = opcinfo->rolname,
   14593             :                                   .description = "OPERATOR CLASS",
   14594             :                                   .section = SECTION_PRE_DATA,
   14595             :                                   .createStmt = q->data,
   14596             :                                   .dropStmt = delq->data));
   14597             : 
   14598             :     /* Dump Operator Class Comments */
   14599        1326 :     if (opcinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   14600           0 :         dumpComment(fout, "OPERATOR CLASS", nameusing->data,
   14601           0 :                     opcinfo->dobj.namespace->dobj.name, opcinfo->rolname,
   14602           0 :                     opcinfo->dobj.catId, 0, opcinfo->dobj.dumpId);
   14603             : 
   14604        1326 :     free(opcintype);
   14605        1326 :     free(opcfamily);
   14606        1326 :     free(amname);
   14607        1326 :     destroyPQExpBuffer(query);
   14608        1326 :     destroyPQExpBuffer(q);
   14609        1326 :     destroyPQExpBuffer(delq);
   14610        1326 :     destroyPQExpBuffer(nameusing);
   14611             : }
   14612             : 
   14613             : /*
   14614             :  * dumpOpfamily
   14615             :  *    write out a single operator family definition
   14616             :  *
   14617             :  * Note: this also dumps any "loose" operator members that aren't bound to a
   14618             :  * specific opclass within the opfamily.
   14619             :  */
   14620             : static void
   14621        1156 : dumpOpfamily(Archive *fout, const OpfamilyInfo *opfinfo)
   14622             : {
   14623        1156 :     DumpOptions *dopt = fout->dopt;
   14624             :     PQExpBuffer query;
   14625             :     PQExpBuffer q;
   14626             :     PQExpBuffer delq;
   14627             :     PQExpBuffer nameusing;
   14628             :     PGresult   *res;
   14629             :     PGresult   *res_ops;
   14630             :     PGresult   *res_procs;
   14631             :     int         ntups;
   14632             :     int         i_amname;
   14633             :     int         i_amopstrategy;
   14634             :     int         i_amopopr;
   14635             :     int         i_sortfamily;
   14636             :     int         i_sortfamilynsp;
   14637             :     int         i_amprocnum;
   14638             :     int         i_amproc;
   14639             :     int         i_amproclefttype;
   14640             :     int         i_amprocrighttype;
   14641             :     char       *amname;
   14642             :     char       *amopstrategy;
   14643             :     char       *amopopr;
   14644             :     char       *sortfamily;
   14645             :     char       *sortfamilynsp;
   14646             :     char       *amprocnum;
   14647             :     char       *amproc;
   14648             :     char       *amproclefttype;
   14649             :     char       *amprocrighttype;
   14650             :     bool        needComma;
   14651             :     int         i;
   14652             : 
   14653             :     /* Do nothing if not dumping schema */
   14654        1156 :     if (!dopt->dumpSchema)
   14655          24 :         return;
   14656             : 
   14657        1132 :     query = createPQExpBuffer();
   14658        1132 :     q = createPQExpBuffer();
   14659        1132 :     delq = createPQExpBuffer();
   14660        1132 :     nameusing = createPQExpBuffer();
   14661             : 
   14662             :     /*
   14663             :      * Fetch only those opfamily members that are tied directly to the
   14664             :      * opfamily by pg_depend entries.
   14665             :      */
   14666        1132 :     appendPQExpBuffer(query, "SELECT amopstrategy, "
   14667             :                       "amopopr::pg_catalog.regoperator, "
   14668             :                       "opfname AS sortfamily, "
   14669             :                       "nspname AS sortfamilynsp "
   14670             :                       "FROM pg_catalog.pg_amop ao JOIN pg_catalog.pg_depend ON "
   14671             :                       "(classid = 'pg_catalog.pg_amop'::pg_catalog.regclass AND objid = ao.oid) "
   14672             :                       "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = amopsortfamily "
   14673             :                       "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
   14674             :                       "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
   14675             :                       "AND refobjid = '%u'::pg_catalog.oid "
   14676             :                       "AND amopfamily = '%u'::pg_catalog.oid "
   14677             :                       "ORDER BY amopstrategy",
   14678        1132 :                       opfinfo->dobj.catId.oid,
   14679        1132 :                       opfinfo->dobj.catId.oid);
   14680             : 
   14681        1132 :     res_ops = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   14682             : 
   14683        1132 :     resetPQExpBuffer(query);
   14684             : 
   14685        1132 :     appendPQExpBuffer(query, "SELECT amprocnum, "
   14686             :                       "amproc::pg_catalog.regprocedure, "
   14687             :                       "amproclefttype::pg_catalog.regtype, "
   14688             :                       "amprocrighttype::pg_catalog.regtype "
   14689             :                       "FROM pg_catalog.pg_amproc ap, pg_catalog.pg_depend "
   14690             :                       "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
   14691             :                       "AND refobjid = '%u'::pg_catalog.oid "
   14692             :                       "AND classid = 'pg_catalog.pg_amproc'::pg_catalog.regclass "
   14693             :                       "AND objid = ap.oid "
   14694             :                       "ORDER BY amprocnum",
   14695        1132 :                       opfinfo->dobj.catId.oid);
   14696             : 
   14697        1132 :     res_procs = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   14698             : 
   14699             :     /* Get additional fields from the pg_opfamily row */
   14700        1132 :     resetPQExpBuffer(query);
   14701             : 
   14702        1132 :     appendPQExpBuffer(query, "SELECT "
   14703             :                       "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opfmethod) AS amname "
   14704             :                       "FROM pg_catalog.pg_opfamily "
   14705             :                       "WHERE oid = '%u'::pg_catalog.oid",
   14706        1132 :                       opfinfo->dobj.catId.oid);
   14707             : 
   14708        1132 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   14709             : 
   14710        1132 :     i_amname = PQfnumber(res, "amname");
   14711             : 
   14712             :     /* amname will still be needed after we PQclear res */
   14713        1132 :     amname = pg_strdup(PQgetvalue(res, 0, i_amname));
   14714             : 
   14715        1132 :     appendPQExpBuffer(delq, "DROP OPERATOR FAMILY %s",
   14716        1132 :                       fmtQualifiedDumpable(opfinfo));
   14717        1132 :     appendPQExpBuffer(delq, " USING %s;\n",
   14718             :                       fmtId(amname));
   14719             : 
   14720             :     /* Build the fixed portion of the CREATE command */
   14721        1132 :     appendPQExpBuffer(q, "CREATE OPERATOR FAMILY %s",
   14722        1132 :                       fmtQualifiedDumpable(opfinfo));
   14723        1132 :     appendPQExpBuffer(q, " USING %s;\n",
   14724             :                       fmtId(amname));
   14725             : 
   14726        1132 :     PQclear(res);
   14727             : 
   14728             :     /* Do we need an ALTER to add loose members? */
   14729        1132 :     if (PQntuples(res_ops) > 0 || PQntuples(res_procs) > 0)
   14730             :     {
   14731         120 :         appendPQExpBuffer(q, "ALTER OPERATOR FAMILY %s",
   14732         120 :                           fmtQualifiedDumpable(opfinfo));
   14733         120 :         appendPQExpBuffer(q, " USING %s ADD\n    ",
   14734             :                           fmtId(amname));
   14735             : 
   14736         120 :         needComma = false;
   14737             : 
   14738             :         /*
   14739             :          * Now fetch and print the OPERATOR entries (pg_amop rows).
   14740             :          */
   14741         120 :         ntups = PQntuples(res_ops);
   14742             : 
   14743         120 :         i_amopstrategy = PQfnumber(res_ops, "amopstrategy");
   14744         120 :         i_amopopr = PQfnumber(res_ops, "amopopr");
   14745         120 :         i_sortfamily = PQfnumber(res_ops, "sortfamily");
   14746         120 :         i_sortfamilynsp = PQfnumber(res_ops, "sortfamilynsp");
   14747             : 
   14748         480 :         for (i = 0; i < ntups; i++)
   14749             :         {
   14750         360 :             amopstrategy = PQgetvalue(res_ops, i, i_amopstrategy);
   14751         360 :             amopopr = PQgetvalue(res_ops, i, i_amopopr);
   14752         360 :             sortfamily = PQgetvalue(res_ops, i, i_sortfamily);
   14753         360 :             sortfamilynsp = PQgetvalue(res_ops, i, i_sortfamilynsp);
   14754             : 
   14755         360 :             if (needComma)
   14756         288 :                 appendPQExpBufferStr(q, " ,\n    ");
   14757             : 
   14758         360 :             appendPQExpBuffer(q, "OPERATOR %s %s",
   14759             :                               amopstrategy, amopopr);
   14760             : 
   14761         360 :             if (strlen(sortfamily) > 0)
   14762             :             {
   14763           0 :                 appendPQExpBufferStr(q, " FOR ORDER BY ");
   14764           0 :                 appendPQExpBuffer(q, "%s.", fmtId(sortfamilynsp));
   14765           0 :                 appendPQExpBufferStr(q, fmtId(sortfamily));
   14766             :             }
   14767             : 
   14768         360 :             needComma = true;
   14769             :         }
   14770             : 
   14771             :         /*
   14772             :          * Now fetch and print the FUNCTION entries (pg_amproc rows).
   14773             :          */
   14774         120 :         ntups = PQntuples(res_procs);
   14775             : 
   14776         120 :         i_amprocnum = PQfnumber(res_procs, "amprocnum");
   14777         120 :         i_amproc = PQfnumber(res_procs, "amproc");
   14778         120 :         i_amproclefttype = PQfnumber(res_procs, "amproclefttype");
   14779         120 :         i_amprocrighttype = PQfnumber(res_procs, "amprocrighttype");
   14780             : 
   14781         528 :         for (i = 0; i < ntups; i++)
   14782             :         {
   14783         408 :             amprocnum = PQgetvalue(res_procs, i, i_amprocnum);
   14784         408 :             amproc = PQgetvalue(res_procs, i, i_amproc);
   14785         408 :             amproclefttype = PQgetvalue(res_procs, i, i_amproclefttype);
   14786         408 :             amprocrighttype = PQgetvalue(res_procs, i, i_amprocrighttype);
   14787             : 
   14788         408 :             if (needComma)
   14789         360 :                 appendPQExpBufferStr(q, " ,\n    ");
   14790             : 
   14791         408 :             appendPQExpBuffer(q, "FUNCTION %s (%s, %s) %s",
   14792             :                               amprocnum, amproclefttype, amprocrighttype,
   14793             :                               amproc);
   14794             : 
   14795         408 :             needComma = true;
   14796             :         }
   14797             : 
   14798         120 :         appendPQExpBufferStr(q, ";\n");
   14799             :     }
   14800             : 
   14801        1132 :     appendPQExpBufferStr(nameusing, fmtId(opfinfo->dobj.name));
   14802        1132 :     appendPQExpBuffer(nameusing, " USING %s",
   14803             :                       fmtId(amname));
   14804             : 
   14805        1132 :     if (dopt->binary_upgrade)
   14806          18 :         binary_upgrade_extension_member(q, &opfinfo->dobj,
   14807          18 :                                         "OPERATOR FAMILY", nameusing->data,
   14808          18 :                                         opfinfo->dobj.namespace->dobj.name);
   14809             : 
   14810        1132 :     if (opfinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   14811        1132 :         ArchiveEntry(fout, opfinfo->dobj.catId, opfinfo->dobj.dumpId,
   14812        1132 :                      ARCHIVE_OPTS(.tag = opfinfo->dobj.name,
   14813             :                                   .namespace = opfinfo->dobj.namespace->dobj.name,
   14814             :                                   .owner = opfinfo->rolname,
   14815             :                                   .description = "OPERATOR FAMILY",
   14816             :                                   .section = SECTION_PRE_DATA,
   14817             :                                   .createStmt = q->data,
   14818             :                                   .dropStmt = delq->data));
   14819             : 
   14820             :     /* Dump Operator Family Comments */
   14821        1132 :     if (opfinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   14822           0 :         dumpComment(fout, "OPERATOR FAMILY", nameusing->data,
   14823           0 :                     opfinfo->dobj.namespace->dobj.name, opfinfo->rolname,
   14824           0 :                     opfinfo->dobj.catId, 0, opfinfo->dobj.dumpId);
   14825             : 
   14826        1132 :     free(amname);
   14827        1132 :     PQclear(res_ops);
   14828        1132 :     PQclear(res_procs);
   14829        1132 :     destroyPQExpBuffer(query);
   14830        1132 :     destroyPQExpBuffer(q);
   14831        1132 :     destroyPQExpBuffer(delq);
   14832        1132 :     destroyPQExpBuffer(nameusing);
   14833             : }
   14834             : 
   14835             : /*
   14836             :  * dumpCollation
   14837             :  *    write out a single collation definition
   14838             :  */
   14839             : static void
   14840        5108 : dumpCollation(Archive *fout, const CollInfo *collinfo)
   14841             : {
   14842        5108 :     DumpOptions *dopt = fout->dopt;
   14843             :     PQExpBuffer query;
   14844             :     PQExpBuffer q;
   14845             :     PQExpBuffer delq;
   14846             :     char       *qcollname;
   14847             :     PGresult   *res;
   14848             :     int         i_collprovider;
   14849             :     int         i_collisdeterministic;
   14850             :     int         i_collcollate;
   14851             :     int         i_collctype;
   14852             :     int         i_colllocale;
   14853             :     int         i_collicurules;
   14854             :     const char *collprovider;
   14855             :     const char *collcollate;
   14856             :     const char *collctype;
   14857             :     const char *colllocale;
   14858             :     const char *collicurules;
   14859             : 
   14860             :     /* Do nothing if not dumping schema */
   14861        5108 :     if (!dopt->dumpSchema)
   14862          24 :         return;
   14863             : 
   14864        5084 :     query = createPQExpBuffer();
   14865        5084 :     q = createPQExpBuffer();
   14866        5084 :     delq = createPQExpBuffer();
   14867             : 
   14868        5084 :     qcollname = pg_strdup(fmtId(collinfo->dobj.name));
   14869             : 
   14870             :     /* Get collation-specific details */
   14871        5084 :     appendPQExpBufferStr(query, "SELECT ");
   14872             : 
   14873        5084 :     if (fout->remoteVersion >= 100000)
   14874        5084 :         appendPQExpBufferStr(query,
   14875             :                              "collprovider, "
   14876             :                              "collversion, ");
   14877             :     else
   14878           0 :         appendPQExpBufferStr(query,
   14879             :                              "'c' AS collprovider, "
   14880             :                              "NULL AS collversion, ");
   14881             : 
   14882        5084 :     if (fout->remoteVersion >= 120000)
   14883        5084 :         appendPQExpBufferStr(query,
   14884             :                              "collisdeterministic, ");
   14885             :     else
   14886           0 :         appendPQExpBufferStr(query,
   14887             :                              "true AS collisdeterministic, ");
   14888             : 
   14889        5084 :     if (fout->remoteVersion >= 170000)
   14890        5084 :         appendPQExpBufferStr(query,
   14891             :                              "colllocale, ");
   14892           0 :     else if (fout->remoteVersion >= 150000)
   14893           0 :         appendPQExpBufferStr(query,
   14894             :                              "colliculocale AS colllocale, ");
   14895             :     else
   14896           0 :         appendPQExpBufferStr(query,
   14897             :                              "NULL AS colllocale, ");
   14898             : 
   14899        5084 :     if (fout->remoteVersion >= 160000)
   14900        5084 :         appendPQExpBufferStr(query,
   14901             :                              "collicurules, ");
   14902             :     else
   14903           0 :         appendPQExpBufferStr(query,
   14904             :                              "NULL AS collicurules, ");
   14905             : 
   14906        5084 :     appendPQExpBuffer(query,
   14907             :                       "collcollate, "
   14908             :                       "collctype "
   14909             :                       "FROM pg_catalog.pg_collation c "
   14910             :                       "WHERE c.oid = '%u'::pg_catalog.oid",
   14911        5084 :                       collinfo->dobj.catId.oid);
   14912             : 
   14913        5084 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   14914             : 
   14915        5084 :     i_collprovider = PQfnumber(res, "collprovider");
   14916        5084 :     i_collisdeterministic = PQfnumber(res, "collisdeterministic");
   14917        5084 :     i_collcollate = PQfnumber(res, "collcollate");
   14918        5084 :     i_collctype = PQfnumber(res, "collctype");
   14919        5084 :     i_colllocale = PQfnumber(res, "colllocale");
   14920        5084 :     i_collicurules = PQfnumber(res, "collicurules");
   14921             : 
   14922        5084 :     collprovider = PQgetvalue(res, 0, i_collprovider);
   14923             : 
   14924        5084 :     if (!PQgetisnull(res, 0, i_collcollate))
   14925         100 :         collcollate = PQgetvalue(res, 0, i_collcollate);
   14926             :     else
   14927        4984 :         collcollate = NULL;
   14928             : 
   14929        5084 :     if (!PQgetisnull(res, 0, i_collctype))
   14930         100 :         collctype = PQgetvalue(res, 0, i_collctype);
   14931             :     else
   14932        4984 :         collctype = NULL;
   14933             : 
   14934             :     /*
   14935             :      * Before version 15, collcollate and collctype were of type NAME and
   14936             :      * non-nullable. Treat empty strings as NULL for consistency.
   14937             :      */
   14938        5084 :     if (fout->remoteVersion < 150000)
   14939             :     {
   14940           0 :         if (collcollate[0] == '\0')
   14941           0 :             collcollate = NULL;
   14942           0 :         if (collctype[0] == '\0')
   14943           0 :             collctype = NULL;
   14944             :     }
   14945             : 
   14946        5084 :     if (!PQgetisnull(res, 0, i_colllocale))
   14947        4978 :         colllocale = PQgetvalue(res, 0, i_colllocale);
   14948             :     else
   14949         106 :         colllocale = NULL;
   14950             : 
   14951        5084 :     if (!PQgetisnull(res, 0, i_collicurules))
   14952           0 :         collicurules = PQgetvalue(res, 0, i_collicurules);
   14953             :     else
   14954        5084 :         collicurules = NULL;
   14955             : 
   14956        5084 :     appendPQExpBuffer(delq, "DROP COLLATION %s;\n",
   14957        5084 :                       fmtQualifiedDumpable(collinfo));
   14958             : 
   14959        5084 :     appendPQExpBuffer(q, "CREATE COLLATION %s (",
   14960        5084 :                       fmtQualifiedDumpable(collinfo));
   14961             : 
   14962        5084 :     appendPQExpBufferStr(q, "provider = ");
   14963        5084 :     if (collprovider[0] == 'b')
   14964          50 :         appendPQExpBufferStr(q, "builtin");
   14965        5034 :     else if (collprovider[0] == 'c')
   14966         100 :         appendPQExpBufferStr(q, "libc");
   14967        4934 :     else if (collprovider[0] == 'i')
   14968        4928 :         appendPQExpBufferStr(q, "icu");
   14969           6 :     else if (collprovider[0] == 'd')
   14970             :         /* to allow dumping pg_catalog; not accepted on input */
   14971           6 :         appendPQExpBufferStr(q, "default");
   14972             :     else
   14973           0 :         pg_fatal("unrecognized collation provider: %s",
   14974             :                  collprovider);
   14975             : 
   14976        5084 :     if (strcmp(PQgetvalue(res, 0, i_collisdeterministic), "f") == 0)
   14977           0 :         appendPQExpBufferStr(q, ", deterministic = false");
   14978             : 
   14979        5084 :     if (collprovider[0] == 'd')
   14980             :     {
   14981           6 :         if (collcollate || collctype || colllocale || collicurules)
   14982           0 :             pg_log_warning("invalid collation \"%s\"", qcollname);
   14983             : 
   14984             :         /* no locale -- the default collation cannot be reloaded anyway */
   14985             :     }
   14986        5078 :     else if (collprovider[0] == 'b')
   14987             :     {
   14988          50 :         if (collcollate || collctype || !colllocale || collicurules)
   14989           0 :             pg_log_warning("invalid collation \"%s\"", qcollname);
   14990             : 
   14991          50 :         appendPQExpBufferStr(q, ", locale = ");
   14992          50 :         appendStringLiteralAH(q, colllocale ? colllocale : "",
   14993             :                               fout);
   14994             :     }
   14995        5028 :     else if (collprovider[0] == 'i')
   14996             :     {
   14997        4928 :         if (fout->remoteVersion >= 150000)
   14998             :         {
   14999        4928 :             if (collcollate || collctype || !colllocale)
   15000           0 :                 pg_log_warning("invalid collation \"%s\"", qcollname);
   15001             : 
   15002        4928 :             appendPQExpBufferStr(q, ", locale = ");
   15003        4928 :             appendStringLiteralAH(q, colllocale ? colllocale : "",
   15004             :                                   fout);
   15005             :         }
   15006             :         else
   15007             :         {
   15008           0 :             if (!collcollate || !collctype || colllocale ||
   15009           0 :                 strcmp(collcollate, collctype) != 0)
   15010           0 :                 pg_log_warning("invalid collation \"%s\"", qcollname);
   15011             : 
   15012           0 :             appendPQExpBufferStr(q, ", locale = ");
   15013           0 :             appendStringLiteralAH(q, collcollate ? collcollate : "", fout);
   15014             :         }
   15015             : 
   15016        4928 :         if (collicurules)
   15017             :         {
   15018           0 :             appendPQExpBufferStr(q, ", rules = ");
   15019           0 :             appendStringLiteralAH(q, collicurules ? collicurules : "", fout);
   15020             :         }
   15021             :     }
   15022         100 :     else if (collprovider[0] == 'c')
   15023             :     {
   15024         100 :         if (colllocale || collicurules || !collcollate || !collctype)
   15025           0 :             pg_log_warning("invalid collation \"%s\"", qcollname);
   15026             : 
   15027         100 :         if (collcollate && collctype && strcmp(collcollate, collctype) == 0)
   15028             :         {
   15029         100 :             appendPQExpBufferStr(q, ", locale = ");
   15030         100 :             appendStringLiteralAH(q, collcollate ? collcollate : "", fout);
   15031             :         }
   15032             :         else
   15033             :         {
   15034           0 :             appendPQExpBufferStr(q, ", lc_collate = ");
   15035           0 :             appendStringLiteralAH(q, collcollate ? collcollate : "", fout);
   15036           0 :             appendPQExpBufferStr(q, ", lc_ctype = ");
   15037           0 :             appendStringLiteralAH(q, collctype ? collctype : "", fout);
   15038             :         }
   15039             :     }
   15040             :     else
   15041           0 :         pg_fatal("unrecognized collation provider: %s", collprovider);
   15042             : 
   15043             :     /*
   15044             :      * For binary upgrade, carry over the collation version.  For normal
   15045             :      * dump/restore, omit the version, so that it is computed upon restore.
   15046             :      */
   15047        5084 :     if (dopt->binary_upgrade)
   15048             :     {
   15049             :         int         i_collversion;
   15050             : 
   15051          10 :         i_collversion = PQfnumber(res, "collversion");
   15052          10 :         if (!PQgetisnull(res, 0, i_collversion))
   15053             :         {
   15054           8 :             appendPQExpBufferStr(q, ", version = ");
   15055           8 :             appendStringLiteralAH(q,
   15056             :                                   PQgetvalue(res, 0, i_collversion),
   15057             :                                   fout);
   15058             :         }
   15059             :     }
   15060             : 
   15061        5084 :     appendPQExpBufferStr(q, ");\n");
   15062             : 
   15063        5084 :     if (dopt->binary_upgrade)
   15064          10 :         binary_upgrade_extension_member(q, &collinfo->dobj,
   15065             :                                         "COLLATION", qcollname,
   15066          10 :                                         collinfo->dobj.namespace->dobj.name);
   15067             : 
   15068        5084 :     if (collinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   15069        5084 :         ArchiveEntry(fout, collinfo->dobj.catId, collinfo->dobj.dumpId,
   15070        5084 :                      ARCHIVE_OPTS(.tag = collinfo->dobj.name,
   15071             :                                   .namespace = collinfo->dobj.namespace->dobj.name,
   15072             :                                   .owner = collinfo->rolname,
   15073             :                                   .description = "COLLATION",
   15074             :                                   .section = SECTION_PRE_DATA,
   15075             :                                   .createStmt = q->data,
   15076             :                                   .dropStmt = delq->data));
   15077             : 
   15078             :     /* Dump Collation Comments */
   15079        5084 :     if (collinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   15080        4870 :         dumpComment(fout, "COLLATION", qcollname,
   15081        4870 :                     collinfo->dobj.namespace->dobj.name, collinfo->rolname,
   15082        4870 :                     collinfo->dobj.catId, 0, collinfo->dobj.dumpId);
   15083             : 
   15084        5084 :     PQclear(res);
   15085             : 
   15086        5084 :     destroyPQExpBuffer(query);
   15087        5084 :     destroyPQExpBuffer(q);
   15088        5084 :     destroyPQExpBuffer(delq);
   15089        5084 :     free(qcollname);
   15090             : }
   15091             : 
   15092             : /*
   15093             :  * dumpConversion
   15094             :  *    write out a single conversion definition
   15095             :  */
   15096             : static void
   15097         852 : dumpConversion(Archive *fout, const ConvInfo *convinfo)
   15098             : {
   15099         852 :     DumpOptions *dopt = fout->dopt;
   15100             :     PQExpBuffer query;
   15101             :     PQExpBuffer q;
   15102             :     PQExpBuffer delq;
   15103             :     char       *qconvname;
   15104             :     PGresult   *res;
   15105             :     int         i_conforencoding;
   15106             :     int         i_contoencoding;
   15107             :     int         i_conproc;
   15108             :     int         i_condefault;
   15109             :     const char *conforencoding;
   15110             :     const char *contoencoding;
   15111             :     const char *conproc;
   15112             :     bool        condefault;
   15113             : 
   15114             :     /* Do nothing if not dumping schema */
   15115         852 :     if (!dopt->dumpSchema)
   15116          12 :         return;
   15117             : 
   15118         840 :     query = createPQExpBuffer();
   15119         840 :     q = createPQExpBuffer();
   15120         840 :     delq = createPQExpBuffer();
   15121             : 
   15122         840 :     qconvname = pg_strdup(fmtId(convinfo->dobj.name));
   15123             : 
   15124             :     /* Get conversion-specific details */
   15125         840 :     appendPQExpBuffer(query, "SELECT "
   15126             :                       "pg_catalog.pg_encoding_to_char(conforencoding) AS conforencoding, "
   15127             :                       "pg_catalog.pg_encoding_to_char(contoencoding) AS contoencoding, "
   15128             :                       "conproc, condefault "
   15129             :                       "FROM pg_catalog.pg_conversion c "
   15130             :                       "WHERE c.oid = '%u'::pg_catalog.oid",
   15131         840 :                       convinfo->dobj.catId.oid);
   15132             : 
   15133         840 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   15134             : 
   15135         840 :     i_conforencoding = PQfnumber(res, "conforencoding");
   15136         840 :     i_contoencoding = PQfnumber(res, "contoencoding");
   15137         840 :     i_conproc = PQfnumber(res, "conproc");
   15138         840 :     i_condefault = PQfnumber(res, "condefault");
   15139             : 
   15140         840 :     conforencoding = PQgetvalue(res, 0, i_conforencoding);
   15141         840 :     contoencoding = PQgetvalue(res, 0, i_contoencoding);
   15142         840 :     conproc = PQgetvalue(res, 0, i_conproc);
   15143         840 :     condefault = (PQgetvalue(res, 0, i_condefault)[0] == 't');
   15144             : 
   15145         840 :     appendPQExpBuffer(delq, "DROP CONVERSION %s;\n",
   15146         840 :                       fmtQualifiedDumpable(convinfo));
   15147             : 
   15148         840 :     appendPQExpBuffer(q, "CREATE %sCONVERSION %s FOR ",
   15149             :                       (condefault) ? "DEFAULT " : "",
   15150         840 :                       fmtQualifiedDumpable(convinfo));
   15151         840 :     appendStringLiteralAH(q, conforencoding, fout);
   15152         840 :     appendPQExpBufferStr(q, " TO ");
   15153         840 :     appendStringLiteralAH(q, contoencoding, fout);
   15154             :     /* regproc output is already sufficiently quoted */
   15155         840 :     appendPQExpBuffer(q, " FROM %s;\n", conproc);
   15156             : 
   15157         840 :     if (dopt->binary_upgrade)
   15158           2 :         binary_upgrade_extension_member(q, &convinfo->dobj,
   15159             :                                         "CONVERSION", qconvname,
   15160           2 :                                         convinfo->dobj.namespace->dobj.name);
   15161             : 
   15162         840 :     if (convinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   15163         840 :         ArchiveEntry(fout, convinfo->dobj.catId, convinfo->dobj.dumpId,
   15164         840 :                      ARCHIVE_OPTS(.tag = convinfo->dobj.name,
   15165             :                                   .namespace = convinfo->dobj.namespace->dobj.name,
   15166             :                                   .owner = convinfo->rolname,
   15167             :                                   .description = "CONVERSION",
   15168             :                                   .section = SECTION_PRE_DATA,
   15169             :                                   .createStmt = q->data,
   15170             :                                   .dropStmt = delq->data));
   15171             : 
   15172             :     /* Dump Conversion Comments */
   15173         840 :     if (convinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   15174         840 :         dumpComment(fout, "CONVERSION", qconvname,
   15175         840 :                     convinfo->dobj.namespace->dobj.name, convinfo->rolname,
   15176         840 :                     convinfo->dobj.catId, 0, convinfo->dobj.dumpId);
   15177             : 
   15178         840 :     PQclear(res);
   15179             : 
   15180         840 :     destroyPQExpBuffer(query);
   15181         840 :     destroyPQExpBuffer(q);
   15182         840 :     destroyPQExpBuffer(delq);
   15183         840 :     free(qconvname);
   15184             : }
   15185             : 
   15186             : /*
   15187             :  * format_aggregate_signature: generate aggregate name and argument list
   15188             :  *
   15189             :  * The argument type names are qualified if needed.  The aggregate name
   15190             :  * is never qualified.
   15191             :  */
   15192             : static char *
   15193         860 : format_aggregate_signature(const AggInfo *agginfo, Archive *fout, bool honor_quotes)
   15194             : {
   15195             :     PQExpBufferData buf;
   15196             :     int         j;
   15197             : 
   15198         860 :     initPQExpBuffer(&buf);
   15199         860 :     if (honor_quotes)
   15200           0 :         appendPQExpBufferStr(&buf, fmtId(agginfo->aggfn.dobj.name));
   15201             :     else
   15202         860 :         appendPQExpBufferStr(&buf, agginfo->aggfn.dobj.name);
   15203             : 
   15204         860 :     if (agginfo->aggfn.nargs == 0)
   15205         128 :         appendPQExpBufferStr(&buf, "(*)");
   15206             :     else
   15207             :     {
   15208         732 :         appendPQExpBufferChar(&buf, '(');
   15209        1608 :         for (j = 0; j < agginfo->aggfn.nargs; j++)
   15210         876 :             appendPQExpBuffer(&buf, "%s%s",
   15211             :                               (j > 0) ? ", " : "",
   15212             :                               getFormattedTypeName(fout,
   15213         876 :                                                    agginfo->aggfn.argtypes[j],
   15214             :                                                    zeroIsError));
   15215         732 :         appendPQExpBufferChar(&buf, ')');
   15216             :     }
   15217         860 :     return buf.data;
   15218             : }
   15219             : 
   15220             : /*
   15221             :  * dumpAgg
   15222             :  *    write out a single aggregate definition
   15223             :  */
   15224             : static void
   15225         874 : dumpAgg(Archive *fout, const AggInfo *agginfo)
   15226             : {
   15227         874 :     DumpOptions *dopt = fout->dopt;
   15228             :     PQExpBuffer query;
   15229             :     PQExpBuffer q;
   15230             :     PQExpBuffer delq;
   15231             :     PQExpBuffer details;
   15232             :     char       *aggsig;         /* identity signature */
   15233         874 :     char       *aggfullsig = NULL;  /* full signature */
   15234             :     char       *aggsig_tag;
   15235             :     PGresult   *res;
   15236             :     int         i_agginitval;
   15237             :     int         i_aggminitval;
   15238             :     const char *aggtransfn;
   15239             :     const char *aggfinalfn;
   15240             :     const char *aggcombinefn;
   15241             :     const char *aggserialfn;
   15242             :     const char *aggdeserialfn;
   15243             :     const char *aggmtransfn;
   15244             :     const char *aggminvtransfn;
   15245             :     const char *aggmfinalfn;
   15246             :     bool        aggfinalextra;
   15247             :     bool        aggmfinalextra;
   15248             :     char        aggfinalmodify;
   15249             :     char        aggmfinalmodify;
   15250             :     const char *aggsortop;
   15251             :     char       *aggsortconvop;
   15252             :     char        aggkind;
   15253             :     const char *aggtranstype;
   15254             :     const char *aggtransspace;
   15255             :     const char *aggmtranstype;
   15256             :     const char *aggmtransspace;
   15257             :     const char *agginitval;
   15258             :     const char *aggminitval;
   15259             :     const char *proparallel;
   15260             :     char        defaultfinalmodify;
   15261             : 
   15262             :     /* Do nothing if not dumping schema */
   15263         874 :     if (!dopt->dumpSchema)
   15264          14 :         return;
   15265             : 
   15266         860 :     query = createPQExpBuffer();
   15267         860 :     q = createPQExpBuffer();
   15268         860 :     delq = createPQExpBuffer();
   15269         860 :     details = createPQExpBuffer();
   15270             : 
   15271         860 :     if (!fout->is_prepared[PREPQUERY_DUMPAGG])
   15272             :     {
   15273             :         /* Set up query for aggregate-specific details */
   15274         124 :         appendPQExpBufferStr(query,
   15275             :                              "PREPARE dumpAgg(pg_catalog.oid) AS\n");
   15276             : 
   15277         124 :         appendPQExpBufferStr(query,
   15278             :                              "SELECT "
   15279             :                              "aggtransfn,\n"
   15280             :                              "aggfinalfn,\n"
   15281             :                              "aggtranstype::pg_catalog.regtype,\n"
   15282             :                              "agginitval,\n"
   15283             :                              "aggsortop,\n"
   15284             :                              "pg_catalog.pg_get_function_arguments(p.oid) AS funcargs,\n"
   15285             :                              "pg_catalog.pg_get_function_identity_arguments(p.oid) AS funciargs,\n");
   15286             : 
   15287         124 :         if (fout->remoteVersion >= 90400)
   15288         124 :             appendPQExpBufferStr(query,
   15289             :                                  "aggkind,\n"
   15290             :                                  "aggmtransfn,\n"
   15291             :                                  "aggminvtransfn,\n"
   15292             :                                  "aggmfinalfn,\n"
   15293             :                                  "aggmtranstype::pg_catalog.regtype,\n"
   15294             :                                  "aggfinalextra,\n"
   15295             :                                  "aggmfinalextra,\n"
   15296             :                                  "aggtransspace,\n"
   15297             :                                  "aggmtransspace,\n"
   15298             :                                  "aggminitval,\n");
   15299             :         else
   15300           0 :             appendPQExpBufferStr(query,
   15301             :                                  "'n' AS aggkind,\n"
   15302             :                                  "'-' AS aggmtransfn,\n"
   15303             :                                  "'-' AS aggminvtransfn,\n"
   15304             :                                  "'-' AS aggmfinalfn,\n"
   15305             :                                  "0 AS aggmtranstype,\n"
   15306             :                                  "false AS aggfinalextra,\n"
   15307             :                                  "false AS aggmfinalextra,\n"
   15308             :                                  "0 AS aggtransspace,\n"
   15309             :                                  "0 AS aggmtransspace,\n"
   15310             :                                  "NULL AS aggminitval,\n");
   15311             : 
   15312         124 :         if (fout->remoteVersion >= 90600)
   15313         124 :             appendPQExpBufferStr(query,
   15314             :                                  "aggcombinefn,\n"
   15315             :                                  "aggserialfn,\n"
   15316             :                                  "aggdeserialfn,\n"
   15317             :                                  "proparallel,\n");
   15318             :         else
   15319           0 :             appendPQExpBufferStr(query,
   15320             :                                  "'-' AS aggcombinefn,\n"
   15321             :                                  "'-' AS aggserialfn,\n"
   15322             :                                  "'-' AS aggdeserialfn,\n"
   15323             :                                  "'u' AS proparallel,\n");
   15324             : 
   15325         124 :         if (fout->remoteVersion >= 110000)
   15326         124 :             appendPQExpBufferStr(query,
   15327             :                                  "aggfinalmodify,\n"
   15328             :                                  "aggmfinalmodify\n");
   15329             :         else
   15330           0 :             appendPQExpBufferStr(query,
   15331             :                                  "'0' AS aggfinalmodify,\n"
   15332             :                                  "'0' AS aggmfinalmodify\n");
   15333             : 
   15334         124 :         appendPQExpBufferStr(query,
   15335             :                              "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
   15336             :                              "WHERE a.aggfnoid = p.oid "
   15337             :                              "AND p.oid = $1");
   15338             : 
   15339         124 :         ExecuteSqlStatement(fout, query->data);
   15340             : 
   15341         124 :         fout->is_prepared[PREPQUERY_DUMPAGG] = true;
   15342             :     }
   15343             : 
   15344         860 :     printfPQExpBuffer(query,
   15345             :                       "EXECUTE dumpAgg('%u')",
   15346         860 :                       agginfo->aggfn.dobj.catId.oid);
   15347             : 
   15348         860 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   15349             : 
   15350         860 :     i_agginitval = PQfnumber(res, "agginitval");
   15351         860 :     i_aggminitval = PQfnumber(res, "aggminitval");
   15352             : 
   15353         860 :     aggtransfn = PQgetvalue(res, 0, PQfnumber(res, "aggtransfn"));
   15354         860 :     aggfinalfn = PQgetvalue(res, 0, PQfnumber(res, "aggfinalfn"));
   15355         860 :     aggcombinefn = PQgetvalue(res, 0, PQfnumber(res, "aggcombinefn"));
   15356         860 :     aggserialfn = PQgetvalue(res, 0, PQfnumber(res, "aggserialfn"));
   15357         860 :     aggdeserialfn = PQgetvalue(res, 0, PQfnumber(res, "aggdeserialfn"));
   15358         860 :     aggmtransfn = PQgetvalue(res, 0, PQfnumber(res, "aggmtransfn"));
   15359         860 :     aggminvtransfn = PQgetvalue(res, 0, PQfnumber(res, "aggminvtransfn"));
   15360         860 :     aggmfinalfn = PQgetvalue(res, 0, PQfnumber(res, "aggmfinalfn"));
   15361         860 :     aggfinalextra = (PQgetvalue(res, 0, PQfnumber(res, "aggfinalextra"))[0] == 't');
   15362         860 :     aggmfinalextra = (PQgetvalue(res, 0, PQfnumber(res, "aggmfinalextra"))[0] == 't');
   15363         860 :     aggfinalmodify = PQgetvalue(res, 0, PQfnumber(res, "aggfinalmodify"))[0];
   15364         860 :     aggmfinalmodify = PQgetvalue(res, 0, PQfnumber(res, "aggmfinalmodify"))[0];
   15365         860 :     aggsortop = PQgetvalue(res, 0, PQfnumber(res, "aggsortop"));
   15366         860 :     aggkind = PQgetvalue(res, 0, PQfnumber(res, "aggkind"))[0];
   15367         860 :     aggtranstype = PQgetvalue(res, 0, PQfnumber(res, "aggtranstype"));
   15368         860 :     aggtransspace = PQgetvalue(res, 0, PQfnumber(res, "aggtransspace"));
   15369         860 :     aggmtranstype = PQgetvalue(res, 0, PQfnumber(res, "aggmtranstype"));
   15370         860 :     aggmtransspace = PQgetvalue(res, 0, PQfnumber(res, "aggmtransspace"));
   15371         860 :     agginitval = PQgetvalue(res, 0, i_agginitval);
   15372         860 :     aggminitval = PQgetvalue(res, 0, i_aggminitval);
   15373         860 :     proparallel = PQgetvalue(res, 0, PQfnumber(res, "proparallel"));
   15374             : 
   15375             :     {
   15376             :         char       *funcargs;
   15377             :         char       *funciargs;
   15378             : 
   15379         860 :         funcargs = PQgetvalue(res, 0, PQfnumber(res, "funcargs"));
   15380         860 :         funciargs = PQgetvalue(res, 0, PQfnumber(res, "funciargs"));
   15381         860 :         aggfullsig = format_function_arguments(&agginfo->aggfn, funcargs, true);
   15382         860 :         aggsig = format_function_arguments(&agginfo->aggfn, funciargs, true);
   15383             :     }
   15384             : 
   15385         860 :     aggsig_tag = format_aggregate_signature(agginfo, fout, false);
   15386             : 
   15387             :     /* identify default modify flag for aggkind (must match DefineAggregate) */
   15388         860 :     defaultfinalmodify = (aggkind == AGGKIND_NORMAL) ? AGGMODIFY_READ_ONLY : AGGMODIFY_READ_WRITE;
   15389             :     /* replace omitted flags for old versions */
   15390         860 :     if (aggfinalmodify == '0')
   15391           0 :         aggfinalmodify = defaultfinalmodify;
   15392         860 :     if (aggmfinalmodify == '0')
   15393           0 :         aggmfinalmodify = defaultfinalmodify;
   15394             : 
   15395             :     /* regproc and regtype output is already sufficiently quoted */
   15396         860 :     appendPQExpBuffer(details, "    SFUNC = %s,\n    STYPE = %s",
   15397             :                       aggtransfn, aggtranstype);
   15398             : 
   15399         860 :     if (strcmp(aggtransspace, "0") != 0)
   15400             :     {
   15401          16 :         appendPQExpBuffer(details, ",\n    SSPACE = %s",
   15402             :                           aggtransspace);
   15403             :     }
   15404             : 
   15405         860 :     if (!PQgetisnull(res, 0, i_agginitval))
   15406             :     {
   15407         632 :         appendPQExpBufferStr(details, ",\n    INITCOND = ");
   15408         632 :         appendStringLiteralAH(details, agginitval, fout);
   15409             :     }
   15410             : 
   15411         860 :     if (strcmp(aggfinalfn, "-") != 0)
   15412             :     {
   15413         392 :         appendPQExpBuffer(details, ",\n    FINALFUNC = %s",
   15414             :                           aggfinalfn);
   15415         392 :         if (aggfinalextra)
   15416          32 :             appendPQExpBufferStr(details, ",\n    FINALFUNC_EXTRA");
   15417         392 :         if (aggfinalmodify != defaultfinalmodify)
   15418             :         {
   15419          72 :             switch (aggfinalmodify)
   15420             :             {
   15421           0 :                 case AGGMODIFY_READ_ONLY:
   15422           0 :                     appendPQExpBufferStr(details, ",\n    FINALFUNC_MODIFY = READ_ONLY");
   15423           0 :                     break;
   15424          72 :                 case AGGMODIFY_SHAREABLE:
   15425          72 :                     appendPQExpBufferStr(details, ",\n    FINALFUNC_MODIFY = SHAREABLE");
   15426          72 :                     break;
   15427           0 :                 case AGGMODIFY_READ_WRITE:
   15428           0 :                     appendPQExpBufferStr(details, ",\n    FINALFUNC_MODIFY = READ_WRITE");
   15429           0 :                     break;
   15430           0 :                 default:
   15431           0 :                     pg_fatal("unrecognized aggfinalmodify value for aggregate \"%s\"",
   15432             :                              agginfo->aggfn.dobj.name);
   15433             :                     break;
   15434             :             }
   15435             :         }
   15436             :     }
   15437             : 
   15438         860 :     if (strcmp(aggcombinefn, "-") != 0)
   15439           0 :         appendPQExpBuffer(details, ",\n    COMBINEFUNC = %s", aggcombinefn);
   15440             : 
   15441         860 :     if (strcmp(aggserialfn, "-") != 0)
   15442           0 :         appendPQExpBuffer(details, ",\n    SERIALFUNC = %s", aggserialfn);
   15443             : 
   15444         860 :     if (strcmp(aggdeserialfn, "-") != 0)
   15445           0 :         appendPQExpBuffer(details, ",\n    DESERIALFUNC = %s", aggdeserialfn);
   15446             : 
   15447         860 :     if (strcmp(aggmtransfn, "-") != 0)
   15448             :     {
   15449          96 :         appendPQExpBuffer(details, ",\n    MSFUNC = %s,\n    MINVFUNC = %s,\n    MSTYPE = %s",
   15450             :                           aggmtransfn,
   15451             :                           aggminvtransfn,
   15452             :                           aggmtranstype);
   15453             :     }
   15454             : 
   15455         860 :     if (strcmp(aggmtransspace, "0") != 0)
   15456             :     {
   15457           0 :         appendPQExpBuffer(details, ",\n    MSSPACE = %s",
   15458             :                           aggmtransspace);
   15459             :     }
   15460             : 
   15461         860 :     if (!PQgetisnull(res, 0, i_aggminitval))
   15462             :     {
   15463          32 :         appendPQExpBufferStr(details, ",\n    MINITCOND = ");
   15464          32 :         appendStringLiteralAH(details, aggminitval, fout);
   15465             :     }
   15466             : 
   15467         860 :     if (strcmp(aggmfinalfn, "-") != 0)
   15468             :     {
   15469           0 :         appendPQExpBuffer(details, ",\n    MFINALFUNC = %s",
   15470             :                           aggmfinalfn);
   15471           0 :         if (aggmfinalextra)
   15472           0 :             appendPQExpBufferStr(details, ",\n    MFINALFUNC_EXTRA");
   15473           0 :         if (aggmfinalmodify != defaultfinalmodify)
   15474             :         {
   15475           0 :             switch (aggmfinalmodify)
   15476             :             {
   15477           0 :                 case AGGMODIFY_READ_ONLY:
   15478           0 :                     appendPQExpBufferStr(details, ",\n    MFINALFUNC_MODIFY = READ_ONLY");
   15479           0 :                     break;
   15480           0 :                 case AGGMODIFY_SHAREABLE:
   15481           0 :                     appendPQExpBufferStr(details, ",\n    MFINALFUNC_MODIFY = SHAREABLE");
   15482           0 :                     break;
   15483           0 :                 case AGGMODIFY_READ_WRITE:
   15484           0 :                     appendPQExpBufferStr(details, ",\n    MFINALFUNC_MODIFY = READ_WRITE");
   15485           0 :                     break;
   15486           0 :                 default:
   15487           0 :                     pg_fatal("unrecognized aggmfinalmodify value for aggregate \"%s\"",
   15488             :                              agginfo->aggfn.dobj.name);
   15489             :                     break;
   15490             :             }
   15491             :         }
   15492             :     }
   15493             : 
   15494         860 :     aggsortconvop = getFormattedOperatorName(aggsortop);
   15495         860 :     if (aggsortconvop)
   15496             :     {
   15497           0 :         appendPQExpBuffer(details, ",\n    SORTOP = %s",
   15498             :                           aggsortconvop);
   15499           0 :         free(aggsortconvop);
   15500             :     }
   15501             : 
   15502         860 :     if (aggkind == AGGKIND_HYPOTHETICAL)
   15503          16 :         appendPQExpBufferStr(details, ",\n    HYPOTHETICAL");
   15504             : 
   15505         860 :     if (proparallel[0] != PROPARALLEL_UNSAFE)
   15506             :     {
   15507          16 :         if (proparallel[0] == PROPARALLEL_SAFE)
   15508          16 :             appendPQExpBufferStr(details, ",\n    PARALLEL = safe");
   15509           0 :         else if (proparallel[0] == PROPARALLEL_RESTRICTED)
   15510           0 :             appendPQExpBufferStr(details, ",\n    PARALLEL = restricted");
   15511           0 :         else if (proparallel[0] != PROPARALLEL_UNSAFE)
   15512           0 :             pg_fatal("unrecognized proparallel value for function \"%s\"",
   15513             :                      agginfo->aggfn.dobj.name);
   15514             :     }
   15515             : 
   15516         860 :     appendPQExpBuffer(delq, "DROP AGGREGATE %s.%s;\n",
   15517         860 :                       fmtId(agginfo->aggfn.dobj.namespace->dobj.name),
   15518             :                       aggsig);
   15519             : 
   15520        1720 :     appendPQExpBuffer(q, "CREATE AGGREGATE %s.%s (\n%s\n);\n",
   15521         860 :                       fmtId(agginfo->aggfn.dobj.namespace->dobj.name),
   15522             :                       aggfullsig ? aggfullsig : aggsig, details->data);
   15523             : 
   15524         860 :     if (dopt->binary_upgrade)
   15525          98 :         binary_upgrade_extension_member(q, &agginfo->aggfn.dobj,
   15526             :                                         "AGGREGATE", aggsig,
   15527          98 :                                         agginfo->aggfn.dobj.namespace->dobj.name);
   15528             : 
   15529         860 :     if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_DEFINITION)
   15530         826 :         ArchiveEntry(fout, agginfo->aggfn.dobj.catId,
   15531         826 :                      agginfo->aggfn.dobj.dumpId,
   15532         826 :                      ARCHIVE_OPTS(.tag = aggsig_tag,
   15533             :                                   .namespace = agginfo->aggfn.dobj.namespace->dobj.name,
   15534             :                                   .owner = agginfo->aggfn.rolname,
   15535             :                                   .description = "AGGREGATE",
   15536             :                                   .section = SECTION_PRE_DATA,
   15537             :                                   .createStmt = q->data,
   15538             :                                   .dropStmt = delq->data));
   15539             : 
   15540             :     /* Dump Aggregate Comments */
   15541         860 :     if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_COMMENT)
   15542          32 :         dumpComment(fout, "AGGREGATE", aggsig,
   15543          32 :                     agginfo->aggfn.dobj.namespace->dobj.name,
   15544          32 :                     agginfo->aggfn.rolname,
   15545          32 :                     agginfo->aggfn.dobj.catId, 0, agginfo->aggfn.dobj.dumpId);
   15546             : 
   15547         860 :     if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_SECLABEL)
   15548           0 :         dumpSecLabel(fout, "AGGREGATE", aggsig,
   15549           0 :                      agginfo->aggfn.dobj.namespace->dobj.name,
   15550           0 :                      agginfo->aggfn.rolname,
   15551           0 :                      agginfo->aggfn.dobj.catId, 0, agginfo->aggfn.dobj.dumpId);
   15552             : 
   15553             :     /*
   15554             :      * Since there is no GRANT ON AGGREGATE syntax, we have to make the ACL
   15555             :      * command look like a function's GRANT; in particular this affects the
   15556             :      * syntax for zero-argument aggregates and ordered-set aggregates.
   15557             :      */
   15558         860 :     free(aggsig);
   15559             : 
   15560         860 :     aggsig = format_function_signature(fout, &agginfo->aggfn, true);
   15561             : 
   15562         860 :     if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_ACL)
   15563          36 :         dumpACL(fout, agginfo->aggfn.dobj.dumpId, InvalidDumpId,
   15564             :                 "FUNCTION", aggsig, NULL,
   15565          36 :                 agginfo->aggfn.dobj.namespace->dobj.name,
   15566          36 :                 NULL, agginfo->aggfn.rolname, &agginfo->aggfn.dacl);
   15567             : 
   15568         860 :     free(aggsig);
   15569         860 :     free(aggfullsig);
   15570         860 :     free(aggsig_tag);
   15571             : 
   15572         860 :     PQclear(res);
   15573             : 
   15574         860 :     destroyPQExpBuffer(query);
   15575         860 :     destroyPQExpBuffer(q);
   15576         860 :     destroyPQExpBuffer(delq);
   15577         860 :     destroyPQExpBuffer(details);
   15578             : }
   15579             : 
   15580             : /*
   15581             :  * dumpTSParser
   15582             :  *    write out a single text search parser
   15583             :  */
   15584             : static void
   15585          90 : dumpTSParser(Archive *fout, const TSParserInfo *prsinfo)
   15586             : {
   15587          90 :     DumpOptions *dopt = fout->dopt;
   15588             :     PQExpBuffer q;
   15589             :     PQExpBuffer delq;
   15590             :     char       *qprsname;
   15591             : 
   15592             :     /* Do nothing if not dumping schema */
   15593          90 :     if (!dopt->dumpSchema)
   15594          12 :         return;
   15595             : 
   15596          78 :     q = createPQExpBuffer();
   15597          78 :     delq = createPQExpBuffer();
   15598             : 
   15599          78 :     qprsname = pg_strdup(fmtId(prsinfo->dobj.name));
   15600             : 
   15601          78 :     appendPQExpBuffer(q, "CREATE TEXT SEARCH PARSER %s (\n",
   15602          78 :                       fmtQualifiedDumpable(prsinfo));
   15603             : 
   15604          78 :     appendPQExpBuffer(q, "    START = %s,\n",
   15605          78 :                       convertTSFunction(fout, prsinfo->prsstart));
   15606          78 :     appendPQExpBuffer(q, "    GETTOKEN = %s,\n",
   15607          78 :                       convertTSFunction(fout, prsinfo->prstoken));
   15608          78 :     appendPQExpBuffer(q, "    END = %s,\n",
   15609          78 :                       convertTSFunction(fout, prsinfo->prsend));
   15610          78 :     if (prsinfo->prsheadline != InvalidOid)
   15611           6 :         appendPQExpBuffer(q, "    HEADLINE = %s,\n",
   15612           6 :                           convertTSFunction(fout, prsinfo->prsheadline));
   15613          78 :     appendPQExpBuffer(q, "    LEXTYPES = %s );\n",
   15614          78 :                       convertTSFunction(fout, prsinfo->prslextype));
   15615             : 
   15616          78 :     appendPQExpBuffer(delq, "DROP TEXT SEARCH PARSER %s;\n",
   15617          78 :                       fmtQualifiedDumpable(prsinfo));
   15618             : 
   15619          78 :     if (dopt->binary_upgrade)
   15620           2 :         binary_upgrade_extension_member(q, &prsinfo->dobj,
   15621             :                                         "TEXT SEARCH PARSER", qprsname,
   15622           2 :                                         prsinfo->dobj.namespace->dobj.name);
   15623             : 
   15624          78 :     if (prsinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   15625          78 :         ArchiveEntry(fout, prsinfo->dobj.catId, prsinfo->dobj.dumpId,
   15626          78 :                      ARCHIVE_OPTS(.tag = prsinfo->dobj.name,
   15627             :                                   .namespace = prsinfo->dobj.namespace->dobj.name,
   15628             :                                   .description = "TEXT SEARCH PARSER",
   15629             :                                   .section = SECTION_PRE_DATA,
   15630             :                                   .createStmt = q->data,
   15631             :                                   .dropStmt = delq->data));
   15632             : 
   15633             :     /* Dump Parser Comments */
   15634          78 :     if (prsinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   15635          78 :         dumpComment(fout, "TEXT SEARCH PARSER", qprsname,
   15636          78 :                     prsinfo->dobj.namespace->dobj.name, "",
   15637          78 :                     prsinfo->dobj.catId, 0, prsinfo->dobj.dumpId);
   15638             : 
   15639          78 :     destroyPQExpBuffer(q);
   15640          78 :     destroyPQExpBuffer(delq);
   15641          78 :     free(qprsname);
   15642             : }
   15643             : 
   15644             : /*
   15645             :  * dumpTSDictionary
   15646             :  *    write out a single text search dictionary
   15647             :  */
   15648             : static void
   15649         408 : dumpTSDictionary(Archive *fout, const TSDictInfo *dictinfo)
   15650             : {
   15651         408 :     DumpOptions *dopt = fout->dopt;
   15652             :     PQExpBuffer q;
   15653             :     PQExpBuffer delq;
   15654             :     PQExpBuffer query;
   15655             :     char       *qdictname;
   15656             :     PGresult   *res;
   15657             :     char       *nspname;
   15658             :     char       *tmplname;
   15659             : 
   15660             :     /* Do nothing if not dumping schema */
   15661         408 :     if (!dopt->dumpSchema)
   15662          12 :         return;
   15663             : 
   15664         396 :     q = createPQExpBuffer();
   15665         396 :     delq = createPQExpBuffer();
   15666         396 :     query = createPQExpBuffer();
   15667             : 
   15668         396 :     qdictname = pg_strdup(fmtId(dictinfo->dobj.name));
   15669             : 
   15670             :     /* Fetch name and namespace of the dictionary's template */
   15671         396 :     appendPQExpBuffer(query, "SELECT nspname, tmplname "
   15672             :                       "FROM pg_ts_template p, pg_namespace n "
   15673             :                       "WHERE p.oid = '%u' AND n.oid = tmplnamespace",
   15674         396 :                       dictinfo->dicttemplate);
   15675         396 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   15676         396 :     nspname = PQgetvalue(res, 0, 0);
   15677         396 :     tmplname = PQgetvalue(res, 0, 1);
   15678             : 
   15679         396 :     appendPQExpBuffer(q, "CREATE TEXT SEARCH DICTIONARY %s (\n",
   15680         396 :                       fmtQualifiedDumpable(dictinfo));
   15681             : 
   15682         396 :     appendPQExpBufferStr(q, "    TEMPLATE = ");
   15683         396 :     appendPQExpBuffer(q, "%s.", fmtId(nspname));
   15684         396 :     appendPQExpBufferStr(q, fmtId(tmplname));
   15685             : 
   15686         396 :     PQclear(res);
   15687             : 
   15688             :     /* the dictinitoption can be dumped straight into the command */
   15689         396 :     if (dictinfo->dictinitoption)
   15690         318 :         appendPQExpBuffer(q, ",\n    %s", dictinfo->dictinitoption);
   15691             : 
   15692         396 :     appendPQExpBufferStr(q, " );\n");
   15693             : 
   15694         396 :     appendPQExpBuffer(delq, "DROP TEXT SEARCH DICTIONARY %s;\n",
   15695         396 :                       fmtQualifiedDumpable(dictinfo));
   15696             : 
   15697         396 :     if (dopt->binary_upgrade)
   15698          20 :         binary_upgrade_extension_member(q, &dictinfo->dobj,
   15699             :                                         "TEXT SEARCH DICTIONARY", qdictname,
   15700          20 :                                         dictinfo->dobj.namespace->dobj.name);
   15701             : 
   15702         396 :     if (dictinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   15703         396 :         ArchiveEntry(fout, dictinfo->dobj.catId, dictinfo->dobj.dumpId,
   15704         396 :                      ARCHIVE_OPTS(.tag = dictinfo->dobj.name,
   15705             :                                   .namespace = dictinfo->dobj.namespace->dobj.name,
   15706             :                                   .owner = dictinfo->rolname,
   15707             :                                   .description = "TEXT SEARCH DICTIONARY",
   15708             :                                   .section = SECTION_PRE_DATA,
   15709             :                                   .createStmt = q->data,
   15710             :                                   .dropStmt = delq->data));
   15711             : 
   15712             :     /* Dump Dictionary Comments */
   15713         396 :     if (dictinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   15714         252 :         dumpComment(fout, "TEXT SEARCH DICTIONARY", qdictname,
   15715         252 :                     dictinfo->dobj.namespace->dobj.name, dictinfo->rolname,
   15716         252 :                     dictinfo->dobj.catId, 0, dictinfo->dobj.dumpId);
   15717             : 
   15718         396 :     destroyPQExpBuffer(q);
   15719         396 :     destroyPQExpBuffer(delq);
   15720         396 :     destroyPQExpBuffer(query);
   15721         396 :     free(qdictname);
   15722             : }
   15723             : 
   15724             : /*
   15725             :  * dumpTSTemplate
   15726             :  *    write out a single text search template
   15727             :  */
   15728             : static void
   15729         114 : dumpTSTemplate(Archive *fout, const TSTemplateInfo *tmplinfo)
   15730             : {
   15731         114 :     DumpOptions *dopt = fout->dopt;
   15732             :     PQExpBuffer q;
   15733             :     PQExpBuffer delq;
   15734             :     char       *qtmplname;
   15735             : 
   15736             :     /* Do nothing if not dumping schema */
   15737         114 :     if (!dopt->dumpSchema)
   15738          12 :         return;
   15739             : 
   15740         102 :     q = createPQExpBuffer();
   15741         102 :     delq = createPQExpBuffer();
   15742             : 
   15743         102 :     qtmplname = pg_strdup(fmtId(tmplinfo->dobj.name));
   15744             : 
   15745         102 :     appendPQExpBuffer(q, "CREATE TEXT SEARCH TEMPLATE %s (\n",
   15746         102 :                       fmtQualifiedDumpable(tmplinfo));
   15747             : 
   15748         102 :     if (tmplinfo->tmplinit != InvalidOid)
   15749          30 :         appendPQExpBuffer(q, "    INIT = %s,\n",
   15750          30 :                           convertTSFunction(fout, tmplinfo->tmplinit));
   15751         102 :     appendPQExpBuffer(q, "    LEXIZE = %s );\n",
   15752         102 :                       convertTSFunction(fout, tmplinfo->tmpllexize));
   15753             : 
   15754         102 :     appendPQExpBuffer(delq, "DROP TEXT SEARCH TEMPLATE %s;\n",
   15755         102 :                       fmtQualifiedDumpable(tmplinfo));
   15756             : 
   15757         102 :     if (dopt->binary_upgrade)
   15758           2 :         binary_upgrade_extension_member(q, &tmplinfo->dobj,
   15759             :                                         "TEXT SEARCH TEMPLATE", qtmplname,
   15760           2 :                                         tmplinfo->dobj.namespace->dobj.name);
   15761             : 
   15762         102 :     if (tmplinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   15763         102 :         ArchiveEntry(fout, tmplinfo->dobj.catId, tmplinfo->dobj.dumpId,
   15764         102 :                      ARCHIVE_OPTS(.tag = tmplinfo->dobj.name,
   15765             :                                   .namespace = tmplinfo->dobj.namespace->dobj.name,
   15766             :                                   .description = "TEXT SEARCH TEMPLATE",
   15767             :                                   .section = SECTION_PRE_DATA,
   15768             :                                   .createStmt = q->data,
   15769             :                                   .dropStmt = delq->data));
   15770             : 
   15771             :     /* Dump Template Comments */
   15772         102 :     if (tmplinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   15773         102 :         dumpComment(fout, "TEXT SEARCH TEMPLATE", qtmplname,
   15774         102 :                     tmplinfo->dobj.namespace->dobj.name, "",
   15775         102 :                     tmplinfo->dobj.catId, 0, tmplinfo->dobj.dumpId);
   15776             : 
   15777         102 :     destroyPQExpBuffer(q);
   15778         102 :     destroyPQExpBuffer(delq);
   15779         102 :     free(qtmplname);
   15780             : }
   15781             : 
   15782             : /*
   15783             :  * dumpTSConfig
   15784             :  *    write out a single text search configuration
   15785             :  */
   15786             : static void
   15787         328 : dumpTSConfig(Archive *fout, const TSConfigInfo *cfginfo)
   15788             : {
   15789         328 :     DumpOptions *dopt = fout->dopt;
   15790             :     PQExpBuffer q;
   15791             :     PQExpBuffer delq;
   15792             :     PQExpBuffer query;
   15793             :     char       *qcfgname;
   15794             :     PGresult   *res;
   15795             :     char       *nspname;
   15796             :     char       *prsname;
   15797             :     int         ntups,
   15798             :                 i;
   15799             :     int         i_tokenname;
   15800             :     int         i_dictname;
   15801             : 
   15802             :     /* Do nothing if not dumping schema */
   15803         328 :     if (!dopt->dumpSchema)
   15804          12 :         return;
   15805             : 
   15806         316 :     q = createPQExpBuffer();
   15807         316 :     delq = createPQExpBuffer();
   15808         316 :     query = createPQExpBuffer();
   15809             : 
   15810         316 :     qcfgname = pg_strdup(fmtId(cfginfo->dobj.name));
   15811             : 
   15812             :     /* Fetch name and namespace of the config's parser */
   15813         316 :     appendPQExpBuffer(query, "SELECT nspname, prsname "
   15814             :                       "FROM pg_ts_parser p, pg_namespace n "
   15815             :                       "WHERE p.oid = '%u' AND n.oid = prsnamespace",
   15816         316 :                       cfginfo->cfgparser);
   15817         316 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   15818         316 :     nspname = PQgetvalue(res, 0, 0);
   15819         316 :     prsname = PQgetvalue(res, 0, 1);
   15820             : 
   15821         316 :     appendPQExpBuffer(q, "CREATE TEXT SEARCH CONFIGURATION %s (\n",
   15822         316 :                       fmtQualifiedDumpable(cfginfo));
   15823             : 
   15824         316 :     appendPQExpBuffer(q, "    PARSER = %s.", fmtId(nspname));
   15825         316 :     appendPQExpBuffer(q, "%s );\n", fmtId(prsname));
   15826             : 
   15827         316 :     PQclear(res);
   15828             : 
   15829         316 :     resetPQExpBuffer(query);
   15830         316 :     appendPQExpBuffer(query,
   15831             :                       "SELECT\n"
   15832             :                       "  ( SELECT alias FROM pg_catalog.ts_token_type('%u'::pg_catalog.oid) AS t\n"
   15833             :                       "    WHERE t.tokid = m.maptokentype ) AS tokenname,\n"
   15834             :                       "  m.mapdict::pg_catalog.regdictionary AS dictname\n"
   15835             :                       "FROM pg_catalog.pg_ts_config_map AS m\n"
   15836             :                       "WHERE m.mapcfg = '%u'\n"
   15837             :                       "ORDER BY m.mapcfg, m.maptokentype, m.mapseqno",
   15838         316 :                       cfginfo->cfgparser, cfginfo->dobj.catId.oid);
   15839             : 
   15840         316 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   15841         316 :     ntups = PQntuples(res);
   15842             : 
   15843         316 :     i_tokenname = PQfnumber(res, "tokenname");
   15844         316 :     i_dictname = PQfnumber(res, "dictname");
   15845             : 
   15846        6752 :     for (i = 0; i < ntups; i++)
   15847             :     {
   15848        6436 :         char       *tokenname = PQgetvalue(res, i, i_tokenname);
   15849        6436 :         char       *dictname = PQgetvalue(res, i, i_dictname);
   15850             : 
   15851        6436 :         if (i == 0 ||
   15852        6120 :             strcmp(tokenname, PQgetvalue(res, i - 1, i_tokenname)) != 0)
   15853             :         {
   15854             :             /* starting a new token type, so start a new command */
   15855        6004 :             if (i > 0)
   15856        5688 :                 appendPQExpBufferStr(q, ";\n");
   15857        6004 :             appendPQExpBuffer(q, "\nALTER TEXT SEARCH CONFIGURATION %s\n",
   15858        6004 :                               fmtQualifiedDumpable(cfginfo));
   15859             :             /* tokenname needs quoting, dictname does NOT */
   15860        6004 :             appendPQExpBuffer(q, "    ADD MAPPING FOR %s WITH %s",
   15861             :                               fmtId(tokenname), dictname);
   15862             :         }
   15863             :         else
   15864         432 :             appendPQExpBuffer(q, ", %s", dictname);
   15865             :     }
   15866             : 
   15867         316 :     if (ntups > 0)
   15868         316 :         appendPQExpBufferStr(q, ";\n");
   15869             : 
   15870         316 :     PQclear(res);
   15871             : 
   15872         316 :     appendPQExpBuffer(delq, "DROP TEXT SEARCH CONFIGURATION %s;\n",
   15873         316 :                       fmtQualifiedDumpable(cfginfo));
   15874             : 
   15875         316 :     if (dopt->binary_upgrade)
   15876          10 :         binary_upgrade_extension_member(q, &cfginfo->dobj,
   15877             :                                         "TEXT SEARCH CONFIGURATION", qcfgname,
   15878          10 :                                         cfginfo->dobj.namespace->dobj.name);
   15879             : 
   15880         316 :     if (cfginfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   15881         316 :         ArchiveEntry(fout, cfginfo->dobj.catId, cfginfo->dobj.dumpId,
   15882         316 :                      ARCHIVE_OPTS(.tag = cfginfo->dobj.name,
   15883             :                                   .namespace = cfginfo->dobj.namespace->dobj.name,
   15884             :                                   .owner = cfginfo->rolname,
   15885             :                                   .description = "TEXT SEARCH CONFIGURATION",
   15886             :                                   .section = SECTION_PRE_DATA,
   15887             :                                   .createStmt = q->data,
   15888             :                                   .dropStmt = delq->data));
   15889             : 
   15890             :     /* Dump Configuration Comments */
   15891         316 :     if (cfginfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   15892         252 :         dumpComment(fout, "TEXT SEARCH CONFIGURATION", qcfgname,
   15893         252 :                     cfginfo->dobj.namespace->dobj.name, cfginfo->rolname,
   15894         252 :                     cfginfo->dobj.catId, 0, cfginfo->dobj.dumpId);
   15895             : 
   15896         316 :     destroyPQExpBuffer(q);
   15897         316 :     destroyPQExpBuffer(delq);
   15898         316 :     destroyPQExpBuffer(query);
   15899         316 :     free(qcfgname);
   15900             : }
   15901             : 
   15902             : /*
   15903             :  * dumpForeignDataWrapper
   15904             :  *    write out a single foreign-data wrapper definition
   15905             :  */
   15906             : static void
   15907         118 : dumpForeignDataWrapper(Archive *fout, const FdwInfo *fdwinfo)
   15908             : {
   15909         118 :     DumpOptions *dopt = fout->dopt;
   15910             :     PQExpBuffer q;
   15911             :     PQExpBuffer delq;
   15912             :     char       *qfdwname;
   15913             : 
   15914             :     /* Do nothing if not dumping schema */
   15915         118 :     if (!dopt->dumpSchema)
   15916          14 :         return;
   15917             : 
   15918         104 :     q = createPQExpBuffer();
   15919         104 :     delq = createPQExpBuffer();
   15920             : 
   15921         104 :     qfdwname = pg_strdup(fmtId(fdwinfo->dobj.name));
   15922             : 
   15923         104 :     appendPQExpBuffer(q, "CREATE FOREIGN DATA WRAPPER %s",
   15924             :                       qfdwname);
   15925             : 
   15926         104 :     if (strcmp(fdwinfo->fdwhandler, "-") != 0)
   15927           0 :         appendPQExpBuffer(q, " HANDLER %s", fdwinfo->fdwhandler);
   15928             : 
   15929         104 :     if (strcmp(fdwinfo->fdwvalidator, "-") != 0)
   15930           0 :         appendPQExpBuffer(q, " VALIDATOR %s", fdwinfo->fdwvalidator);
   15931             : 
   15932         104 :     if (strlen(fdwinfo->fdwoptions) > 0)
   15933           0 :         appendPQExpBuffer(q, " OPTIONS (\n    %s\n)", fdwinfo->fdwoptions);
   15934             : 
   15935         104 :     appendPQExpBufferStr(q, ";\n");
   15936             : 
   15937         104 :     appendPQExpBuffer(delq, "DROP FOREIGN DATA WRAPPER %s;\n",
   15938             :                       qfdwname);
   15939             : 
   15940         104 :     if (dopt->binary_upgrade)
   15941           4 :         binary_upgrade_extension_member(q, &fdwinfo->dobj,
   15942             :                                         "FOREIGN DATA WRAPPER", qfdwname,
   15943             :                                         NULL);
   15944             : 
   15945         104 :     if (fdwinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   15946         104 :         ArchiveEntry(fout, fdwinfo->dobj.catId, fdwinfo->dobj.dumpId,
   15947         104 :                      ARCHIVE_OPTS(.tag = fdwinfo->dobj.name,
   15948             :                                   .owner = fdwinfo->rolname,
   15949             :                                   .description = "FOREIGN DATA WRAPPER",
   15950             :                                   .section = SECTION_PRE_DATA,
   15951             :                                   .createStmt = q->data,
   15952             :                                   .dropStmt = delq->data));
   15953             : 
   15954             :     /* Dump Foreign Data Wrapper Comments */
   15955         104 :     if (fdwinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   15956           0 :         dumpComment(fout, "FOREIGN DATA WRAPPER", qfdwname,
   15957           0 :                     NULL, fdwinfo->rolname,
   15958           0 :                     fdwinfo->dobj.catId, 0, fdwinfo->dobj.dumpId);
   15959             : 
   15960             :     /* Handle the ACL */
   15961         104 :     if (fdwinfo->dobj.dump & DUMP_COMPONENT_ACL)
   15962          70 :         dumpACL(fout, fdwinfo->dobj.dumpId, InvalidDumpId,
   15963             :                 "FOREIGN DATA WRAPPER", qfdwname, NULL, NULL,
   15964          70 :                 NULL, fdwinfo->rolname, &fdwinfo->dacl);
   15965             : 
   15966         104 :     free(qfdwname);
   15967             : 
   15968         104 :     destroyPQExpBuffer(q);
   15969         104 :     destroyPQExpBuffer(delq);
   15970             : }
   15971             : 
   15972             : /*
   15973             :  * dumpForeignServer
   15974             :  *    write out a foreign server definition
   15975             :  */
   15976             : static void
   15977         126 : dumpForeignServer(Archive *fout, const ForeignServerInfo *srvinfo)
   15978             : {
   15979         126 :     DumpOptions *dopt = fout->dopt;
   15980             :     PQExpBuffer q;
   15981             :     PQExpBuffer delq;
   15982             :     PQExpBuffer query;
   15983             :     PGresult   *res;
   15984             :     char       *qsrvname;
   15985             :     char       *fdwname;
   15986             : 
   15987             :     /* Do nothing if not dumping schema */
   15988         126 :     if (!dopt->dumpSchema)
   15989          18 :         return;
   15990             : 
   15991         108 :     q = createPQExpBuffer();
   15992         108 :     delq = createPQExpBuffer();
   15993         108 :     query = createPQExpBuffer();
   15994             : 
   15995         108 :     qsrvname = pg_strdup(fmtId(srvinfo->dobj.name));
   15996             : 
   15997             :     /* look up the foreign-data wrapper */
   15998         108 :     appendPQExpBuffer(query, "SELECT fdwname "
   15999             :                       "FROM pg_foreign_data_wrapper w "
   16000             :                       "WHERE w.oid = '%u'",
   16001         108 :                       srvinfo->srvfdw);
   16002         108 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   16003         108 :     fdwname = PQgetvalue(res, 0, 0);
   16004             : 
   16005         108 :     appendPQExpBuffer(q, "CREATE SERVER %s", qsrvname);
   16006         108 :     if (srvinfo->srvtype && strlen(srvinfo->srvtype) > 0)
   16007             :     {
   16008           0 :         appendPQExpBufferStr(q, " TYPE ");
   16009           0 :         appendStringLiteralAH(q, srvinfo->srvtype, fout);
   16010             :     }
   16011         108 :     if (srvinfo->srvversion && strlen(srvinfo->srvversion) > 0)
   16012             :     {
   16013           0 :         appendPQExpBufferStr(q, " VERSION ");
   16014           0 :         appendStringLiteralAH(q, srvinfo->srvversion, fout);
   16015             :     }
   16016             : 
   16017         108 :     appendPQExpBufferStr(q, " FOREIGN DATA WRAPPER ");
   16018         108 :     appendPQExpBufferStr(q, fmtId(fdwname));
   16019             : 
   16020         108 :     if (srvinfo->srvoptions && strlen(srvinfo->srvoptions) > 0)
   16021           0 :         appendPQExpBuffer(q, " OPTIONS (\n    %s\n)", srvinfo->srvoptions);
   16022             : 
   16023         108 :     appendPQExpBufferStr(q, ";\n");
   16024             : 
   16025         108 :     appendPQExpBuffer(delq, "DROP SERVER %s;\n",
   16026             :                       qsrvname);
   16027             : 
   16028         108 :     if (dopt->binary_upgrade)
   16029           4 :         binary_upgrade_extension_member(q, &srvinfo->dobj,
   16030             :                                         "SERVER", qsrvname, NULL);
   16031             : 
   16032         108 :     if (srvinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   16033         108 :         ArchiveEntry(fout, srvinfo->dobj.catId, srvinfo->dobj.dumpId,
   16034         108 :                      ARCHIVE_OPTS(.tag = srvinfo->dobj.name,
   16035             :                                   .owner = srvinfo->rolname,
   16036             :                                   .description = "SERVER",
   16037             :                                   .section = SECTION_PRE_DATA,
   16038             :                                   .createStmt = q->data,
   16039             :                                   .dropStmt = delq->data));
   16040             : 
   16041             :     /* Dump Foreign Server Comments */
   16042         108 :     if (srvinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   16043           0 :         dumpComment(fout, "SERVER", qsrvname,
   16044           0 :                     NULL, srvinfo->rolname,
   16045           0 :                     srvinfo->dobj.catId, 0, srvinfo->dobj.dumpId);
   16046             : 
   16047             :     /* Handle the ACL */
   16048         108 :     if (srvinfo->dobj.dump & DUMP_COMPONENT_ACL)
   16049          70 :         dumpACL(fout, srvinfo->dobj.dumpId, InvalidDumpId,
   16050             :                 "FOREIGN SERVER", qsrvname, NULL, NULL,
   16051          70 :                 NULL, srvinfo->rolname, &srvinfo->dacl);
   16052             : 
   16053             :     /* Dump user mappings */
   16054         108 :     if (srvinfo->dobj.dump & DUMP_COMPONENT_USERMAP)
   16055         108 :         dumpUserMappings(fout,
   16056         108 :                          srvinfo->dobj.name, NULL,
   16057         108 :                          srvinfo->rolname,
   16058         108 :                          srvinfo->dobj.catId, srvinfo->dobj.dumpId);
   16059             : 
   16060         108 :     PQclear(res);
   16061             : 
   16062         108 :     free(qsrvname);
   16063             : 
   16064         108 :     destroyPQExpBuffer(q);
   16065         108 :     destroyPQExpBuffer(delq);
   16066         108 :     destroyPQExpBuffer(query);
   16067             : }
   16068             : 
   16069             : /*
   16070             :  * dumpUserMappings
   16071             :  *
   16072             :  * This routine is used to dump any user mappings associated with the
   16073             :  * server handed to this routine. Should be called after ArchiveEntry()
   16074             :  * for the server.
   16075             :  */
   16076             : static void
   16077         108 : dumpUserMappings(Archive *fout,
   16078             :                  const char *servername, const char *namespace,
   16079             :                  const char *owner,
   16080             :                  CatalogId catalogId, DumpId dumpId)
   16081             : {
   16082             :     PQExpBuffer q;
   16083             :     PQExpBuffer delq;
   16084             :     PQExpBuffer query;
   16085             :     PQExpBuffer tag;
   16086             :     PGresult   *res;
   16087             :     int         ntups;
   16088             :     int         i_usename;
   16089             :     int         i_umoptions;
   16090             :     int         i;
   16091             : 
   16092         108 :     q = createPQExpBuffer();
   16093         108 :     tag = createPQExpBuffer();
   16094         108 :     delq = createPQExpBuffer();
   16095         108 :     query = createPQExpBuffer();
   16096             : 
   16097             :     /*
   16098             :      * We read from the publicly accessible view pg_user_mappings, so as not
   16099             :      * to fail if run by a non-superuser.  Note that the view will show
   16100             :      * umoptions as null if the user hasn't got privileges for the associated
   16101             :      * server; this means that pg_dump will dump such a mapping, but with no
   16102             :      * OPTIONS clause.  A possible alternative is to skip such mappings
   16103             :      * altogether, but it's not clear that that's an improvement.
   16104             :      */
   16105         108 :     appendPQExpBuffer(query,
   16106             :                       "SELECT usename, "
   16107             :                       "array_to_string(ARRAY("
   16108             :                       "SELECT quote_ident(option_name) || ' ' || "
   16109             :                       "quote_literal(option_value) "
   16110             :                       "FROM pg_options_to_table(umoptions) "
   16111             :                       "ORDER BY option_name"
   16112             :                       "), E',\n    ') AS umoptions "
   16113             :                       "FROM pg_user_mappings "
   16114             :                       "WHERE srvid = '%u' "
   16115             :                       "ORDER BY usename",
   16116             :                       catalogId.oid);
   16117             : 
   16118         108 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   16119             : 
   16120         108 :     ntups = PQntuples(res);
   16121         108 :     i_usename = PQfnumber(res, "usename");
   16122         108 :     i_umoptions = PQfnumber(res, "umoptions");
   16123             : 
   16124         178 :     for (i = 0; i < ntups; i++)
   16125             :     {
   16126             :         char       *usename;
   16127             :         char       *umoptions;
   16128             : 
   16129          70 :         usename = PQgetvalue(res, i, i_usename);
   16130          70 :         umoptions = PQgetvalue(res, i, i_umoptions);
   16131             : 
   16132          70 :         resetPQExpBuffer(q);
   16133          70 :         appendPQExpBuffer(q, "CREATE USER MAPPING FOR %s", fmtId(usename));
   16134          70 :         appendPQExpBuffer(q, " SERVER %s", fmtId(servername));
   16135             : 
   16136          70 :         if (umoptions && strlen(umoptions) > 0)
   16137           0 :             appendPQExpBuffer(q, " OPTIONS (\n    %s\n)", umoptions);
   16138             : 
   16139          70 :         appendPQExpBufferStr(q, ";\n");
   16140             : 
   16141          70 :         resetPQExpBuffer(delq);
   16142          70 :         appendPQExpBuffer(delq, "DROP USER MAPPING FOR %s", fmtId(usename));
   16143          70 :         appendPQExpBuffer(delq, " SERVER %s;\n", fmtId(servername));
   16144             : 
   16145          70 :         resetPQExpBuffer(tag);
   16146          70 :         appendPQExpBuffer(tag, "USER MAPPING %s SERVER %s",
   16147             :                           usename, servername);
   16148             : 
   16149          70 :         ArchiveEntry(fout, nilCatalogId, createDumpId(),
   16150          70 :                      ARCHIVE_OPTS(.tag = tag->data,
   16151             :                                   .namespace = namespace,
   16152             :                                   .owner = owner,
   16153             :                                   .description = "USER MAPPING",
   16154             :                                   .section = SECTION_PRE_DATA,
   16155             :                                   .createStmt = q->data,
   16156             :                                   .dropStmt = delq->data));
   16157             :     }
   16158             : 
   16159         108 :     PQclear(res);
   16160             : 
   16161         108 :     destroyPQExpBuffer(query);
   16162         108 :     destroyPQExpBuffer(delq);
   16163         108 :     destroyPQExpBuffer(tag);
   16164         108 :     destroyPQExpBuffer(q);
   16165         108 : }
   16166             : 
   16167             : /*
   16168             :  * Write out default privileges information
   16169             :  */
   16170             : static void
   16171         332 : dumpDefaultACL(Archive *fout, const DefaultACLInfo *daclinfo)
   16172             : {
   16173         332 :     DumpOptions *dopt = fout->dopt;
   16174             :     PQExpBuffer q;
   16175             :     PQExpBuffer tag;
   16176             :     const char *type;
   16177             : 
   16178             :     /* Do nothing if not dumping schema, or if we're skipping ACLs */
   16179         332 :     if (!dopt->dumpSchema || dopt->aclsSkip)
   16180          56 :         return;
   16181             : 
   16182         276 :     q = createPQExpBuffer();
   16183         276 :     tag = createPQExpBuffer();
   16184             : 
   16185         276 :     switch (daclinfo->defaclobjtype)
   16186             :     {
   16187         138 :         case DEFACLOBJ_RELATION:
   16188         138 :             type = "TABLES";
   16189         138 :             break;
   16190           0 :         case DEFACLOBJ_SEQUENCE:
   16191           0 :             type = "SEQUENCES";
   16192           0 :             break;
   16193         138 :         case DEFACLOBJ_FUNCTION:
   16194         138 :             type = "FUNCTIONS";
   16195         138 :             break;
   16196           0 :         case DEFACLOBJ_TYPE:
   16197           0 :             type = "TYPES";
   16198           0 :             break;
   16199           0 :         case DEFACLOBJ_NAMESPACE:
   16200           0 :             type = "SCHEMAS";
   16201           0 :             break;
   16202           0 :         case DEFACLOBJ_LARGEOBJECT:
   16203           0 :             type = "LARGE OBJECTS";
   16204           0 :             break;
   16205           0 :         default:
   16206             :             /* shouldn't get here */
   16207           0 :             pg_fatal("unrecognized object type in default privileges: %d",
   16208             :                      (int) daclinfo->defaclobjtype);
   16209             :             type = "";            /* keep compiler quiet */
   16210             :     }
   16211             : 
   16212         276 :     appendPQExpBuffer(tag, "DEFAULT PRIVILEGES FOR %s", type);
   16213             : 
   16214             :     /* build the actual command(s) for this tuple */
   16215         276 :     if (!buildDefaultACLCommands(type,
   16216         276 :                                  daclinfo->dobj.namespace != NULL ?
   16217         140 :                                  daclinfo->dobj.namespace->dobj.name : NULL,
   16218         276 :                                  daclinfo->dacl.acl,
   16219         276 :                                  daclinfo->dacl.acldefault,
   16220         276 :                                  daclinfo->defaclrole,
   16221             :                                  fout->remoteVersion,
   16222             :                                  q))
   16223           0 :         pg_fatal("could not parse default ACL list (%s)",
   16224             :                  daclinfo->dacl.acl);
   16225             : 
   16226         276 :     if (daclinfo->dobj.dump & DUMP_COMPONENT_ACL)
   16227         276 :         ArchiveEntry(fout, daclinfo->dobj.catId, daclinfo->dobj.dumpId,
   16228         276 :                      ARCHIVE_OPTS(.tag = tag->data,
   16229             :                                   .namespace = daclinfo->dobj.namespace ?
   16230             :                                   daclinfo->dobj.namespace->dobj.name : NULL,
   16231             :                                   .owner = daclinfo->defaclrole,
   16232             :                                   .description = "DEFAULT ACL",
   16233             :                                   .section = SECTION_POST_DATA,
   16234             :                                   .createStmt = q->data));
   16235             : 
   16236         276 :     destroyPQExpBuffer(tag);
   16237         276 :     destroyPQExpBuffer(q);
   16238             : }
   16239             : 
   16240             : /*----------
   16241             :  * Write out grant/revoke information
   16242             :  *
   16243             :  * 'objDumpId' is the dump ID of the underlying object.
   16244             :  * 'altDumpId' can be a second dumpId that the ACL entry must also depend on,
   16245             :  *      or InvalidDumpId if there is no need for a second dependency.
   16246             :  * 'type' must be one of
   16247             :  *      TABLE, SEQUENCE, FUNCTION, LANGUAGE, SCHEMA, DATABASE, TABLESPACE,
   16248             :  *      FOREIGN DATA WRAPPER, SERVER, or LARGE OBJECT.
   16249             :  * 'name' is the formatted name of the object.  Must be quoted etc. already.
   16250             :  * 'subname' is the formatted name of the sub-object, if any.  Must be quoted.
   16251             :  *      (Currently we assume that subname is only provided for table columns.)
   16252             :  * 'nspname' is the namespace the object is in (NULL if none).
   16253             :  * 'tag' is the tag to use for the ACL TOC entry; typically, this is NULL
   16254             :  *      to use the default for the object type.
   16255             :  * 'owner' is the owner, NULL if there is no owner (for languages).
   16256             :  * 'dacl' is the DumpableAcl struct for the object.
   16257             :  *
   16258             :  * Returns the dump ID assigned to the ACL TocEntry, or InvalidDumpId if
   16259             :  * no ACL entry was created.
   16260             :  *----------
   16261             :  */
   16262             : static DumpId
   16263       72874 : dumpACL(Archive *fout, DumpId objDumpId, DumpId altDumpId,
   16264             :         const char *type, const char *name, const char *subname,
   16265             :         const char *nspname, const char *tag, const char *owner,
   16266             :         const DumpableAcl *dacl)
   16267             : {
   16268       72874 :     DumpId      aclDumpId = InvalidDumpId;
   16269       72874 :     DumpOptions *dopt = fout->dopt;
   16270       72874 :     const char *acls = dacl->acl;
   16271       72874 :     const char *acldefault = dacl->acldefault;
   16272       72874 :     char        privtype = dacl->privtype;
   16273       72874 :     const char *initprivs = dacl->initprivs;
   16274             :     const char *baseacls;
   16275             :     PQExpBuffer sql;
   16276             : 
   16277             :     /* Do nothing if ACL dump is not enabled */
   16278       72874 :     if (dopt->aclsSkip)
   16279         648 :         return InvalidDumpId;
   16280             : 
   16281             :     /* --data-only skips ACLs *except* large object ACLs */
   16282       72226 :     if (!dopt->dumpSchema && strcmp(type, "LARGE OBJECT") != 0)
   16283           0 :         return InvalidDumpId;
   16284             : 
   16285       72226 :     sql = createPQExpBuffer();
   16286             : 
   16287             :     /*
   16288             :      * In binary upgrade mode, we don't run an extension's script but instead
   16289             :      * dump out the objects independently and then recreate them.  To preserve
   16290             :      * any initial privileges which were set on extension objects, we need to
   16291             :      * compute the set of GRANT and REVOKE commands necessary to get from the
   16292             :      * default privileges of an object to its initial privileges as recorded
   16293             :      * in pg_init_privs.
   16294             :      *
   16295             :      * At restore time, we apply these commands after having called
   16296             :      * binary_upgrade_set_record_init_privs(true).  That tells the backend to
   16297             :      * copy the results into pg_init_privs.  This is how we preserve the
   16298             :      * contents of that catalog across binary upgrades.
   16299             :      */
   16300       72226 :     if (dopt->binary_upgrade && privtype == 'e' &&
   16301          26 :         initprivs && *initprivs != '\0')
   16302             :     {
   16303          26 :         appendPQExpBufferStr(sql, "SELECT pg_catalog.binary_upgrade_set_record_init_privs(true);\n");
   16304          26 :         if (!buildACLCommands(name, subname, nspname, type,
   16305             :                               initprivs, acldefault, owner,
   16306             :                               "", fout->remoteVersion, sql))
   16307           0 :             pg_fatal("could not parse initial ACL list (%s) or default (%s) for object \"%s\" (%s)",
   16308             :                      initprivs, acldefault, name, type);
   16309          26 :         appendPQExpBufferStr(sql, "SELECT pg_catalog.binary_upgrade_set_record_init_privs(false);\n");
   16310             :     }
   16311             : 
   16312             :     /*
   16313             :      * Now figure the GRANT and REVOKE commands needed to get to the object's
   16314             :      * actual current ACL, starting from the initprivs if given, else from the
   16315             :      * object-type-specific default.  Also, while buildACLCommands will assume
   16316             :      * that a NULL/empty acls string means it needn't do anything, what that
   16317             :      * actually represents is the object-type-specific default; so we need to
   16318             :      * substitute the acldefault string to get the right results in that case.
   16319             :      */
   16320       72226 :     if (initprivs && *initprivs != '\0')
   16321             :     {
   16322       68150 :         baseacls = initprivs;
   16323       68150 :         if (acls == NULL || *acls == '\0')
   16324          34 :             acls = acldefault;
   16325             :     }
   16326             :     else
   16327        4076 :         baseacls = acldefault;
   16328             : 
   16329       72226 :     if (!buildACLCommands(name, subname, nspname, type,
   16330             :                           acls, baseacls, owner,
   16331             :                           "", fout->remoteVersion, sql))
   16332           0 :         pg_fatal("could not parse ACL list (%s) or default (%s) for object \"%s\" (%s)",
   16333             :                  acls, baseacls, name, type);
   16334             : 
   16335       72226 :     if (sql->len > 0)
   16336             :     {
   16337        4136 :         PQExpBuffer tagbuf = createPQExpBuffer();
   16338             :         DumpId      aclDeps[2];
   16339        4136 :         int         nDeps = 0;
   16340             : 
   16341        4136 :         if (tag)
   16342           0 :             appendPQExpBufferStr(tagbuf, tag);
   16343        4136 :         else if (subname)
   16344        2368 :             appendPQExpBuffer(tagbuf, "COLUMN %s.%s", name, subname);
   16345             :         else
   16346        1768 :             appendPQExpBuffer(tagbuf, "%s %s", type, name);
   16347             : 
   16348        4136 :         aclDeps[nDeps++] = objDumpId;
   16349        4136 :         if (altDumpId != InvalidDumpId)
   16350        2174 :             aclDeps[nDeps++] = altDumpId;
   16351             : 
   16352        4136 :         aclDumpId = createDumpId();
   16353             : 
   16354        4136 :         ArchiveEntry(fout, nilCatalogId, aclDumpId,
   16355        4136 :                      ARCHIVE_OPTS(.tag = tagbuf->data,
   16356             :                                   .namespace = nspname,
   16357             :                                   .owner = owner,
   16358             :                                   .description = "ACL",
   16359             :                                   .section = SECTION_NONE,
   16360             :                                   .createStmt = sql->data,
   16361             :                                   .deps = aclDeps,
   16362             :                                   .nDeps = nDeps));
   16363             : 
   16364        4136 :         destroyPQExpBuffer(tagbuf);
   16365             :     }
   16366             : 
   16367       72226 :     destroyPQExpBuffer(sql);
   16368             : 
   16369       72226 :     return aclDumpId;
   16370             : }
   16371             : 
   16372             : /*
   16373             :  * dumpSecLabel
   16374             :  *
   16375             :  * This routine is used to dump any security labels associated with the
   16376             :  * object handed to this routine. The routine takes the object type
   16377             :  * and object name (ready to print, except for schema decoration), plus
   16378             :  * the namespace and owner of the object (for labeling the ArchiveEntry),
   16379             :  * plus catalog ID and subid which are the lookup key for pg_seclabel,
   16380             :  * plus the dump ID for the object (for setting a dependency).
   16381             :  * If a matching pg_seclabel entry is found, it is dumped.
   16382             :  *
   16383             :  * Note: although this routine takes a dumpId for dependency purposes,
   16384             :  * that purpose is just to mark the dependency in the emitted dump file
   16385             :  * for possible future use by pg_restore.  We do NOT use it for determining
   16386             :  * ordering of the label in the dump file, because this routine is called
   16387             :  * after dependency sorting occurs.  This routine should be called just after
   16388             :  * calling ArchiveEntry() for the specified object.
   16389             :  */
   16390             : static void
   16391           0 : dumpSecLabel(Archive *fout, const char *type, const char *name,
   16392             :              const char *namespace, const char *owner,
   16393             :              CatalogId catalogId, int subid, DumpId dumpId)
   16394             : {
   16395           0 :     DumpOptions *dopt = fout->dopt;
   16396             :     SecLabelItem *labels;
   16397             :     int         nlabels;
   16398             :     int         i;
   16399             :     PQExpBuffer query;
   16400             : 
   16401             :     /* do nothing, if --no-security-labels is supplied */
   16402           0 :     if (dopt->no_security_labels)
   16403           0 :         return;
   16404             : 
   16405             :     /*
   16406             :      * Security labels are schema not data ... except large object labels are
   16407             :      * data
   16408             :      */
   16409           0 :     if (strcmp(type, "LARGE OBJECT") != 0)
   16410             :     {
   16411           0 :         if (!dopt->dumpSchema)
   16412           0 :             return;
   16413             :     }
   16414             :     else
   16415             :     {
   16416             :         /* We do dump large object security labels in binary-upgrade mode */
   16417           0 :         if (!dopt->dumpData && !dopt->binary_upgrade)
   16418           0 :             return;
   16419             :     }
   16420             : 
   16421             :     /* Search for security labels associated with catalogId, using table */
   16422           0 :     nlabels = findSecLabels(catalogId.tableoid, catalogId.oid, &labels);
   16423             : 
   16424           0 :     query = createPQExpBuffer();
   16425             : 
   16426           0 :     for (i = 0; i < nlabels; i++)
   16427             :     {
   16428             :         /*
   16429             :          * Ignore label entries for which the subid doesn't match.
   16430             :          */
   16431           0 :         if (labels[i].objsubid != subid)
   16432           0 :             continue;
   16433             : 
   16434           0 :         appendPQExpBuffer(query,
   16435             :                           "SECURITY LABEL FOR %s ON %s ",
   16436           0 :                           fmtId(labels[i].provider), type);
   16437           0 :         if (namespace && *namespace)
   16438           0 :             appendPQExpBuffer(query, "%s.", fmtId(namespace));
   16439           0 :         appendPQExpBuffer(query, "%s IS ", name);
   16440           0 :         appendStringLiteralAH(query, labels[i].label, fout);
   16441           0 :         appendPQExpBufferStr(query, ";\n");
   16442             :     }
   16443             : 
   16444           0 :     if (query->len > 0)
   16445             :     {
   16446           0 :         PQExpBuffer tag = createPQExpBuffer();
   16447             : 
   16448           0 :         appendPQExpBuffer(tag, "%s %s", type, name);
   16449           0 :         ArchiveEntry(fout, nilCatalogId, createDumpId(),
   16450           0 :                      ARCHIVE_OPTS(.tag = tag->data,
   16451             :                                   .namespace = namespace,
   16452             :                                   .owner = owner,
   16453             :                                   .description = "SECURITY LABEL",
   16454             :                                   .section = SECTION_NONE,
   16455             :                                   .createStmt = query->data,
   16456             :                                   .deps = &dumpId,
   16457             :                                   .nDeps = 1));
   16458           0 :         destroyPQExpBuffer(tag);
   16459             :     }
   16460             : 
   16461           0 :     destroyPQExpBuffer(query);
   16462             : }
   16463             : 
   16464             : /*
   16465             :  * dumpTableSecLabel
   16466             :  *
   16467             :  * As above, but dump security label for both the specified table (or view)
   16468             :  * and its columns.
   16469             :  */
   16470             : static void
   16471           0 : dumpTableSecLabel(Archive *fout, const TableInfo *tbinfo, const char *reltypename)
   16472             : {
   16473           0 :     DumpOptions *dopt = fout->dopt;
   16474             :     SecLabelItem *labels;
   16475             :     int         nlabels;
   16476             :     int         i;
   16477             :     PQExpBuffer query;
   16478             :     PQExpBuffer target;
   16479             : 
   16480             :     /* do nothing, if --no-security-labels is supplied */
   16481           0 :     if (dopt->no_security_labels)
   16482           0 :         return;
   16483             : 
   16484             :     /* SecLabel are SCHEMA not data */
   16485           0 :     if (!dopt->dumpSchema)
   16486           0 :         return;
   16487             : 
   16488             :     /* Search for comments associated with relation, using table */
   16489           0 :     nlabels = findSecLabels(tbinfo->dobj.catId.tableoid,
   16490           0 :                             tbinfo->dobj.catId.oid,
   16491             :                             &labels);
   16492             : 
   16493             :     /* If security labels exist, build SECURITY LABEL statements */
   16494           0 :     if (nlabels <= 0)
   16495           0 :         return;
   16496             : 
   16497           0 :     query = createPQExpBuffer();
   16498           0 :     target = createPQExpBuffer();
   16499             : 
   16500           0 :     for (i = 0; i < nlabels; i++)
   16501             :     {
   16502             :         const char *colname;
   16503           0 :         const char *provider = labels[i].provider;
   16504           0 :         const char *label = labels[i].label;
   16505           0 :         int         objsubid = labels[i].objsubid;
   16506             : 
   16507           0 :         resetPQExpBuffer(target);
   16508           0 :         if (objsubid == 0)
   16509             :         {
   16510           0 :             appendPQExpBuffer(target, "%s %s", reltypename,
   16511           0 :                               fmtQualifiedDumpable(tbinfo));
   16512             :         }
   16513             :         else
   16514             :         {
   16515           0 :             colname = getAttrName(objsubid, tbinfo);
   16516             :             /* first fmtXXX result must be consumed before calling again */
   16517           0 :             appendPQExpBuffer(target, "COLUMN %s",
   16518           0 :                               fmtQualifiedDumpable(tbinfo));
   16519           0 :             appendPQExpBuffer(target, ".%s", fmtId(colname));
   16520             :         }
   16521           0 :         appendPQExpBuffer(query, "SECURITY LABEL FOR %s ON %s IS ",
   16522             :                           fmtId(provider), target->data);
   16523           0 :         appendStringLiteralAH(query, label, fout);
   16524           0 :         appendPQExpBufferStr(query, ";\n");
   16525             :     }
   16526           0 :     if (query->len > 0)
   16527             :     {
   16528           0 :         resetPQExpBuffer(target);
   16529           0 :         appendPQExpBuffer(target, "%s %s", reltypename,
   16530           0 :                           fmtId(tbinfo->dobj.name));
   16531           0 :         ArchiveEntry(fout, nilCatalogId, createDumpId(),
   16532           0 :                      ARCHIVE_OPTS(.tag = target->data,
   16533             :                                   .namespace = tbinfo->dobj.namespace->dobj.name,
   16534             :                                   .owner = tbinfo->rolname,
   16535             :                                   .description = "SECURITY LABEL",
   16536             :                                   .section = SECTION_NONE,
   16537             :                                   .createStmt = query->data,
   16538             :                                   .deps = &(tbinfo->dobj.dumpId),
   16539             :                                   .nDeps = 1));
   16540             :     }
   16541           0 :     destroyPQExpBuffer(query);
   16542           0 :     destroyPQExpBuffer(target);
   16543             : }
   16544             : 
   16545             : /*
   16546             :  * findSecLabels
   16547             :  *
   16548             :  * Find the security label(s), if any, associated with the given object.
   16549             :  * All the objsubid values associated with the given classoid/objoid are
   16550             :  * found with one search.
   16551             :  */
   16552             : static int
   16553           0 : findSecLabels(Oid classoid, Oid objoid, SecLabelItem **items)
   16554             : {
   16555           0 :     SecLabelItem *middle = NULL;
   16556             :     SecLabelItem *low;
   16557             :     SecLabelItem *high;
   16558             :     int         nmatch;
   16559             : 
   16560           0 :     if (nseclabels <= 0)     /* no labels, so no match is possible */
   16561             :     {
   16562           0 :         *items = NULL;
   16563           0 :         return 0;
   16564             :     }
   16565             : 
   16566             :     /*
   16567             :      * Do binary search to find some item matching the object.
   16568             :      */
   16569           0 :     low = &seclabels[0];
   16570           0 :     high = &seclabels[nseclabels - 1];
   16571           0 :     while (low <= high)
   16572             :     {
   16573           0 :         middle = low + (high - low) / 2;
   16574             : 
   16575           0 :         if (classoid < middle->classoid)
   16576           0 :             high = middle - 1;
   16577           0 :         else if (classoid > middle->classoid)
   16578           0 :             low = middle + 1;
   16579           0 :         else if (objoid < middle->objoid)
   16580           0 :             high = middle - 1;
   16581           0 :         else if (objoid > middle->objoid)
   16582           0 :             low = middle + 1;
   16583             :         else
   16584           0 :             break;              /* found a match */
   16585             :     }
   16586             : 
   16587           0 :     if (low > high)              /* no matches */
   16588             :     {
   16589           0 :         *items = NULL;
   16590           0 :         return 0;
   16591             :     }
   16592             : 
   16593             :     /*
   16594             :      * Now determine how many items match the object.  The search loop
   16595             :      * invariant still holds: only items between low and high inclusive could
   16596             :      * match.
   16597             :      */
   16598           0 :     nmatch = 1;
   16599           0 :     while (middle > low)
   16600             :     {
   16601           0 :         if (classoid != middle[-1].classoid ||
   16602           0 :             objoid != middle[-1].objoid)
   16603             :             break;
   16604           0 :         middle--;
   16605           0 :         nmatch++;
   16606             :     }
   16607             : 
   16608           0 :     *items = middle;
   16609             : 
   16610           0 :     middle += nmatch;
   16611           0 :     while (middle <= high)
   16612             :     {
   16613           0 :         if (classoid != middle->classoid ||
   16614           0 :             objoid != middle->objoid)
   16615             :             break;
   16616           0 :         middle++;
   16617           0 :         nmatch++;
   16618             :     }
   16619             : 
   16620           0 :     return nmatch;
   16621             : }
   16622             : 
   16623             : /*
   16624             :  * collectSecLabels
   16625             :  *
   16626             :  * Construct a table of all security labels available for database objects;
   16627             :  * also set the has-seclabel component flag for each relevant object.
   16628             :  *
   16629             :  * The table is sorted by classoid/objid/objsubid for speed in lookup.
   16630             :  */
   16631             : static void
   16632         468 : collectSecLabels(Archive *fout)
   16633             : {
   16634             :     PGresult   *res;
   16635             :     PQExpBuffer query;
   16636             :     int         i_label;
   16637             :     int         i_provider;
   16638             :     int         i_classoid;
   16639             :     int         i_objoid;
   16640             :     int         i_objsubid;
   16641             :     int         ntups;
   16642             :     int         i;
   16643             :     DumpableObject *dobj;
   16644             : 
   16645         468 :     query = createPQExpBuffer();
   16646             : 
   16647         468 :     appendPQExpBufferStr(query,
   16648             :                          "SELECT label, provider, classoid, objoid, objsubid "
   16649             :                          "FROM pg_catalog.pg_seclabel "
   16650             :                          "ORDER BY classoid, objoid, objsubid");
   16651             : 
   16652         468 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   16653             : 
   16654             :     /* Construct lookup table containing OIDs in numeric form */
   16655         468 :     i_label = PQfnumber(res, "label");
   16656         468 :     i_provider = PQfnumber(res, "provider");
   16657         468 :     i_classoid = PQfnumber(res, "classoid");
   16658         468 :     i_objoid = PQfnumber(res, "objoid");
   16659         468 :     i_objsubid = PQfnumber(res, "objsubid");
   16660             : 
   16661         468 :     ntups = PQntuples(res);
   16662             : 
   16663         468 :     seclabels = (SecLabelItem *) pg_malloc(ntups * sizeof(SecLabelItem));
   16664         468 :     nseclabels = 0;
   16665         468 :     dobj = NULL;
   16666             : 
   16667         468 :     for (i = 0; i < ntups; i++)
   16668             :     {
   16669             :         CatalogId   objId;
   16670             :         int         subid;
   16671             : 
   16672           0 :         objId.tableoid = atooid(PQgetvalue(res, i, i_classoid));
   16673           0 :         objId.oid = atooid(PQgetvalue(res, i, i_objoid));
   16674           0 :         subid = atoi(PQgetvalue(res, i, i_objsubid));
   16675             : 
   16676             :         /* We needn't remember labels that don't match any dumpable object */
   16677           0 :         if (dobj == NULL ||
   16678           0 :             dobj->catId.tableoid != objId.tableoid ||
   16679           0 :             dobj->catId.oid != objId.oid)
   16680           0 :             dobj = findObjectByCatalogId(objId);
   16681           0 :         if (dobj == NULL)
   16682           0 :             continue;
   16683             : 
   16684             :         /*
   16685             :          * Labels on columns of composite types are linked to the type's
   16686             :          * pg_class entry, but we need to set the DUMP_COMPONENT_SECLABEL flag
   16687             :          * in the type's own DumpableObject.
   16688             :          */
   16689           0 :         if (subid != 0 && dobj->objType == DO_TABLE &&
   16690           0 :             ((TableInfo *) dobj)->relkind == RELKIND_COMPOSITE_TYPE)
   16691           0 :         {
   16692             :             TypeInfo   *cTypeInfo;
   16693             : 
   16694           0 :             cTypeInfo = findTypeByOid(((TableInfo *) dobj)->reltype);
   16695           0 :             if (cTypeInfo)
   16696           0 :                 cTypeInfo->dobj.components |= DUMP_COMPONENT_SECLABEL;
   16697             :         }
   16698             :         else
   16699           0 :             dobj->components |= DUMP_COMPONENT_SECLABEL;
   16700             : 
   16701           0 :         seclabels[nseclabels].label = pg_strdup(PQgetvalue(res, i, i_label));
   16702           0 :         seclabels[nseclabels].provider = pg_strdup(PQgetvalue(res, i, i_provider));
   16703           0 :         seclabels[nseclabels].classoid = objId.tableoid;
   16704           0 :         seclabels[nseclabels].objoid = objId.oid;
   16705           0 :         seclabels[nseclabels].objsubid = subid;
   16706           0 :         nseclabels++;
   16707             :     }
   16708             : 
   16709         468 :     PQclear(res);
   16710         468 :     destroyPQExpBuffer(query);
   16711         468 : }
   16712             : 
   16713             : /*
   16714             :  * dumpTable
   16715             :  *    write out to fout the declarations (not data) of a user-defined table
   16716             :  */
   16717             : static void
   16718       81182 : dumpTable(Archive *fout, const TableInfo *tbinfo)
   16719             : {
   16720       81182 :     DumpOptions *dopt = fout->dopt;
   16721       81182 :     DumpId      tableAclDumpId = InvalidDumpId;
   16722             :     char       *namecopy;
   16723             : 
   16724             :     /* Do nothing if not dumping schema */
   16725       81182 :     if (!dopt->dumpSchema)
   16726        3000 :         return;
   16727             : 
   16728       78182 :     if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   16729             :     {
   16730       18716 :         if (tbinfo->relkind == RELKIND_SEQUENCE)
   16731        1106 :             dumpSequence(fout, tbinfo);
   16732             :         else
   16733       17610 :             dumpTableSchema(fout, tbinfo);
   16734             :     }
   16735             : 
   16736             :     /* Handle the ACL here */
   16737       78182 :     namecopy = pg_strdup(fmtId(tbinfo->dobj.name));
   16738       78182 :     if (tbinfo->dobj.dump & DUMP_COMPONENT_ACL)
   16739             :     {
   16740       61040 :         const char *objtype =
   16741       61040 :             (tbinfo->relkind == RELKIND_SEQUENCE) ? "SEQUENCE" : "TABLE";
   16742             : 
   16743             :         tableAclDumpId =
   16744       61040 :             dumpACL(fout, tbinfo->dobj.dumpId, InvalidDumpId,
   16745             :                     objtype, namecopy, NULL,
   16746       61040 :                     tbinfo->dobj.namespace->dobj.name,
   16747       61040 :                     NULL, tbinfo->rolname, &tbinfo->dacl);
   16748             :     }
   16749             : 
   16750             :     /*
   16751             :      * Handle column ACLs, if any.  Note: we pull these with a separate query
   16752             :      * rather than trying to fetch them during getTableAttrs, so that we won't
   16753             :      * miss ACLs on system columns.  Doing it this way also allows us to dump
   16754             :      * ACLs for catalogs that we didn't mark "interesting" back in getTables.
   16755             :      */
   16756       78182 :     if ((tbinfo->dobj.dump & DUMP_COMPONENT_ACL) && tbinfo->hascolumnACLs)
   16757             :     {
   16758         694 :         PQExpBuffer query = createPQExpBuffer();
   16759             :         PGresult   *res;
   16760             :         int         i;
   16761             : 
   16762         694 :         if (!fout->is_prepared[PREPQUERY_GETCOLUMNACLS])
   16763             :         {
   16764             :             /* Set up query for column ACLs */
   16765         416 :             appendPQExpBufferStr(query,
   16766             :                                  "PREPARE getColumnACLs(pg_catalog.oid) AS\n");
   16767             : 
   16768         416 :             if (fout->remoteVersion >= 90600)
   16769             :             {
   16770             :                 /*
   16771             :                  * In principle we should call acldefault('c', relowner) to
   16772             :                  * get the default ACL for a column.  However, we don't
   16773             :                  * currently store the numeric OID of the relowner in
   16774             :                  * TableInfo.  We could convert the owner name using regrole,
   16775             :                  * but that creates a risk of failure due to concurrent role
   16776             :                  * renames.  Given that the default ACL for columns is empty
   16777             :                  * and is likely to stay that way, it's not worth extra cycles
   16778             :                  * and risk to avoid hard-wiring that knowledge here.
   16779             :                  */
   16780         416 :                 appendPQExpBufferStr(query,
   16781             :                                      "SELECT at.attname, "
   16782             :                                      "at.attacl, "
   16783             :                                      "'{}' AS acldefault, "
   16784             :                                      "pip.privtype, pip.initprivs "
   16785             :                                      "FROM pg_catalog.pg_attribute at "
   16786             :                                      "LEFT JOIN pg_catalog.pg_init_privs pip ON "
   16787             :                                      "(at.attrelid = pip.objoid "
   16788             :                                      "AND pip.classoid = 'pg_catalog.pg_class'::pg_catalog.regclass "
   16789             :                                      "AND at.attnum = pip.objsubid) "
   16790             :                                      "WHERE at.attrelid = $1 AND "
   16791             :                                      "NOT at.attisdropped "
   16792             :                                      "AND (at.attacl IS NOT NULL OR pip.initprivs IS NOT NULL) "
   16793             :                                      "ORDER BY at.attnum");
   16794             :             }
   16795             :             else
   16796             :             {
   16797           0 :                 appendPQExpBufferStr(query,
   16798             :                                      "SELECT attname, attacl, '{}' AS acldefault, "
   16799             :                                      "NULL AS privtype, NULL AS initprivs "
   16800             :                                      "FROM pg_catalog.pg_attribute "
   16801             :                                      "WHERE attrelid = $1 AND NOT attisdropped "
   16802             :                                      "AND attacl IS NOT NULL "
   16803             :                                      "ORDER BY attnum");
   16804             :             }
   16805             : 
   16806         416 :             ExecuteSqlStatement(fout, query->data);
   16807             : 
   16808         416 :             fout->is_prepared[PREPQUERY_GETCOLUMNACLS] = true;
   16809             :         }
   16810             : 
   16811         694 :         printfPQExpBuffer(query,
   16812             :                           "EXECUTE getColumnACLs('%u')",
   16813         694 :                           tbinfo->dobj.catId.oid);
   16814             : 
   16815         694 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   16816             : 
   16817       10442 :         for (i = 0; i < PQntuples(res); i++)
   16818             :         {
   16819        9748 :             char       *attname = PQgetvalue(res, i, 0);
   16820        9748 :             char       *attacl = PQgetvalue(res, i, 1);
   16821        9748 :             char       *acldefault = PQgetvalue(res, i, 2);
   16822        9748 :             char        privtype = *(PQgetvalue(res, i, 3));
   16823        9748 :             char       *initprivs = PQgetvalue(res, i, 4);
   16824             :             DumpableAcl coldacl;
   16825             :             char       *attnamecopy;
   16826             : 
   16827        9748 :             coldacl.acl = attacl;
   16828        9748 :             coldacl.acldefault = acldefault;
   16829        9748 :             coldacl.privtype = privtype;
   16830        9748 :             coldacl.initprivs = initprivs;
   16831        9748 :             attnamecopy = pg_strdup(fmtId(attname));
   16832             : 
   16833             :             /*
   16834             :              * Column's GRANT type is always TABLE.  Each column ACL depends
   16835             :              * on the table-level ACL, since we can restore column ACLs in
   16836             :              * parallel but the table-level ACL has to be done first.
   16837             :              */
   16838        9748 :             dumpACL(fout, tbinfo->dobj.dumpId, tableAclDumpId,
   16839             :                     "TABLE", namecopy, attnamecopy,
   16840        9748 :                     tbinfo->dobj.namespace->dobj.name,
   16841        9748 :                     NULL, tbinfo->rolname, &coldacl);
   16842        9748 :             free(attnamecopy);
   16843             :         }
   16844         694 :         PQclear(res);
   16845         694 :         destroyPQExpBuffer(query);
   16846             :     }
   16847             : 
   16848       78182 :     free(namecopy);
   16849             : }
   16850             : 
   16851             : /*
   16852             :  * Create the AS clause for a view or materialized view. The semicolon is
   16853             :  * stripped because a materialized view must add a WITH NO DATA clause.
   16854             :  *
   16855             :  * This returns a new buffer which must be freed by the caller.
   16856             :  */
   16857             : static PQExpBuffer
   16858        2222 : createViewAsClause(Archive *fout, const TableInfo *tbinfo)
   16859             : {
   16860        2222 :     PQExpBuffer query = createPQExpBuffer();
   16861        2222 :     PQExpBuffer result = createPQExpBuffer();
   16862             :     PGresult   *res;
   16863             :     int         len;
   16864             : 
   16865             :     /* Fetch the view definition */
   16866        2222 :     appendPQExpBuffer(query,
   16867             :                       "SELECT pg_catalog.pg_get_viewdef('%u'::pg_catalog.oid) AS viewdef",
   16868        2222 :                       tbinfo->dobj.catId.oid);
   16869             : 
   16870        2222 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   16871             : 
   16872        2222 :     if (PQntuples(res) != 1)
   16873             :     {
   16874           0 :         if (PQntuples(res) < 1)
   16875           0 :             pg_fatal("query to obtain definition of view \"%s\" returned no data",
   16876             :                      tbinfo->dobj.name);
   16877             :         else
   16878           0 :             pg_fatal("query to obtain definition of view \"%s\" returned more than one definition",
   16879             :                      tbinfo->dobj.name);
   16880             :     }
   16881             : 
   16882        2222 :     len = PQgetlength(res, 0, 0);
   16883             : 
   16884        2222 :     if (len == 0)
   16885           0 :         pg_fatal("definition of view \"%s\" appears to be empty (length zero)",
   16886             :                  tbinfo->dobj.name);
   16887             : 
   16888             :     /* Strip off the trailing semicolon so that other things may follow. */
   16889             :     Assert(PQgetvalue(res, 0, 0)[len - 1] == ';');
   16890        2222 :     appendBinaryPQExpBuffer(result, PQgetvalue(res, 0, 0), len - 1);
   16891             : 
   16892        2222 :     PQclear(res);
   16893        2222 :     destroyPQExpBuffer(query);
   16894             : 
   16895        2222 :     return result;
   16896             : }
   16897             : 
   16898             : /*
   16899             :  * Create a dummy AS clause for a view.  This is used when the real view
   16900             :  * definition has to be postponed because of circular dependencies.
   16901             :  * We must duplicate the view's external properties -- column names and types
   16902             :  * (including collation) -- so that it works for subsequent references.
   16903             :  *
   16904             :  * This returns a new buffer which must be freed by the caller.
   16905             :  */
   16906             : static PQExpBuffer
   16907          64 : createDummyViewAsClause(Archive *fout, const TableInfo *tbinfo)
   16908             : {
   16909          64 :     PQExpBuffer result = createPQExpBuffer();
   16910             :     int         j;
   16911             : 
   16912          64 :     appendPQExpBufferStr(result, "SELECT");
   16913             : 
   16914         128 :     for (j = 0; j < tbinfo->numatts; j++)
   16915             :     {
   16916          64 :         if (j > 0)
   16917          32 :             appendPQExpBufferChar(result, ',');
   16918          64 :         appendPQExpBufferStr(result, "\n    ");
   16919             : 
   16920          64 :         appendPQExpBuffer(result, "NULL::%s", tbinfo->atttypnames[j]);
   16921             : 
   16922             :         /*
   16923             :          * Must add collation if not default for the type, because CREATE OR
   16924             :          * REPLACE VIEW won't change it
   16925             :          */
   16926          64 :         if (OidIsValid(tbinfo->attcollation[j]))
   16927             :         {
   16928             :             CollInfo   *coll;
   16929             : 
   16930           0 :             coll = findCollationByOid(tbinfo->attcollation[j]);
   16931           0 :             if (coll)
   16932           0 :                 appendPQExpBuffer(result, " COLLATE %s",
   16933           0 :                                   fmtQualifiedDumpable(coll));
   16934             :         }
   16935             : 
   16936          64 :         appendPQExpBuffer(result, " AS %s", fmtId(tbinfo->attnames[j]));
   16937             :     }
   16938             : 
   16939          64 :     return result;
   16940             : }
   16941             : 
   16942             : /*
   16943             :  * dumpTableSchema
   16944             :  *    write the declaration (not data) of one user-defined table or view
   16945             :  */
   16946             : static void
   16947       17610 : dumpTableSchema(Archive *fout, const TableInfo *tbinfo)
   16948             : {
   16949       17610 :     DumpOptions *dopt = fout->dopt;
   16950       17610 :     PQExpBuffer q = createPQExpBuffer();
   16951       17610 :     PQExpBuffer delq = createPQExpBuffer();
   16952       17610 :     PQExpBuffer extra = createPQExpBuffer();
   16953             :     char       *qrelname;
   16954             :     char       *qualrelname;
   16955             :     int         numParents;
   16956             :     TableInfo **parents;
   16957             :     int         actual_atts;    /* number of attrs in this CREATE statement */
   16958             :     const char *reltypename;
   16959             :     char       *storage;
   16960             :     int         j,
   16961             :                 k;
   16962             : 
   16963             :     /* We had better have loaded per-column details about this table */
   16964             :     Assert(tbinfo->interesting);
   16965             : 
   16966       17610 :     qrelname = pg_strdup(fmtId(tbinfo->dobj.name));
   16967       17610 :     qualrelname = pg_strdup(fmtQualifiedDumpable(tbinfo));
   16968             : 
   16969       17610 :     if (tbinfo->hasoids)
   16970           0 :         pg_log_warning("WITH OIDS is not supported anymore (table \"%s\")",
   16971             :                        qrelname);
   16972             : 
   16973       17610 :     if (dopt->binary_upgrade)
   16974        1704 :         binary_upgrade_set_type_oids_by_rel(fout, q, tbinfo);
   16975             : 
   16976             :     /* Is it a table or a view? */
   16977       17610 :     if (tbinfo->relkind == RELKIND_VIEW)
   16978             :     {
   16979             :         PQExpBuffer result;
   16980             : 
   16981             :         /*
   16982             :          * Note: keep this code in sync with the is_view case in dumpRule()
   16983             :          */
   16984             : 
   16985        1374 :         reltypename = "VIEW";
   16986             : 
   16987        1374 :         appendPQExpBuffer(delq, "DROP VIEW %s;\n", qualrelname);
   16988             : 
   16989        1374 :         if (dopt->binary_upgrade)
   16990         104 :             binary_upgrade_set_pg_class_oids(fout, q,
   16991         104 :                                              tbinfo->dobj.catId.oid);
   16992             : 
   16993        1374 :         appendPQExpBuffer(q, "CREATE VIEW %s", qualrelname);
   16994             : 
   16995        1374 :         if (tbinfo->dummy_view)
   16996          32 :             result = createDummyViewAsClause(fout, tbinfo);
   16997             :         else
   16998             :         {
   16999        1342 :             if (nonemptyReloptions(tbinfo->reloptions))
   17000             :             {
   17001         154 :                 appendPQExpBufferStr(q, " WITH (");
   17002         154 :                 appendReloptionsArrayAH(q, tbinfo->reloptions, "", fout);
   17003         154 :                 appendPQExpBufferChar(q, ')');
   17004             :             }
   17005        1342 :             result = createViewAsClause(fout, tbinfo);
   17006             :         }
   17007        1374 :         appendPQExpBuffer(q, " AS\n%s", result->data);
   17008        1374 :         destroyPQExpBuffer(result);
   17009             : 
   17010        1374 :         if (tbinfo->checkoption != NULL && !tbinfo->dummy_view)
   17011          72 :             appendPQExpBuffer(q, "\n  WITH %s CHECK OPTION", tbinfo->checkoption);
   17012        1374 :         appendPQExpBufferStr(q, ";\n");
   17013             :     }
   17014             :     else
   17015             :     {
   17016       16236 :         char       *partkeydef = NULL;
   17017       16236 :         char       *ftoptions = NULL;
   17018       16236 :         char       *srvname = NULL;
   17019       16236 :         const char *foreign = "";
   17020             : 
   17021             :         /*
   17022             :          * Set reltypename, and collect any relkind-specific data that we
   17023             :          * didn't fetch during getTables().
   17024             :          */
   17025       16236 :         switch (tbinfo->relkind)
   17026             :         {
   17027        1616 :             case RELKIND_PARTITIONED_TABLE:
   17028             :                 {
   17029        1616 :                     PQExpBuffer query = createPQExpBuffer();
   17030             :                     PGresult   *res;
   17031             : 
   17032        1616 :                     reltypename = "TABLE";
   17033             : 
   17034             :                     /* retrieve partition key definition */
   17035        1616 :                     appendPQExpBuffer(query,
   17036             :                                       "SELECT pg_get_partkeydef('%u')",
   17037        1616 :                                       tbinfo->dobj.catId.oid);
   17038        1616 :                     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   17039        1616 :                     partkeydef = pg_strdup(PQgetvalue(res, 0, 0));
   17040        1616 :                     PQclear(res);
   17041        1616 :                     destroyPQExpBuffer(query);
   17042        1616 :                     break;
   17043             :                 }
   17044          76 :             case RELKIND_FOREIGN_TABLE:
   17045             :                 {
   17046          76 :                     PQExpBuffer query = createPQExpBuffer();
   17047             :                     PGresult   *res;
   17048             :                     int         i_srvname;
   17049             :                     int         i_ftoptions;
   17050             : 
   17051          76 :                     reltypename = "FOREIGN TABLE";
   17052             : 
   17053             :                     /* retrieve name of foreign server and generic options */
   17054          76 :                     appendPQExpBuffer(query,
   17055             :                                       "SELECT fs.srvname, "
   17056             :                                       "pg_catalog.array_to_string(ARRAY("
   17057             :                                       "SELECT pg_catalog.quote_ident(option_name) || "
   17058             :                                       "' ' || pg_catalog.quote_literal(option_value) "
   17059             :                                       "FROM pg_catalog.pg_options_to_table(ftoptions) "
   17060             :                                       "ORDER BY option_name"
   17061             :                                       "), E',\n    ') AS ftoptions "
   17062             :                                       "FROM pg_catalog.pg_foreign_table ft "
   17063             :                                       "JOIN pg_catalog.pg_foreign_server fs "
   17064             :                                       "ON (fs.oid = ft.ftserver) "
   17065             :                                       "WHERE ft.ftrelid = '%u'",
   17066          76 :                                       tbinfo->dobj.catId.oid);
   17067          76 :                     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   17068          76 :                     i_srvname = PQfnumber(res, "srvname");
   17069          76 :                     i_ftoptions = PQfnumber(res, "ftoptions");
   17070          76 :                     srvname = pg_strdup(PQgetvalue(res, 0, i_srvname));
   17071          76 :                     ftoptions = pg_strdup(PQgetvalue(res, 0, i_ftoptions));
   17072          76 :                     PQclear(res);
   17073          76 :                     destroyPQExpBuffer(query);
   17074             : 
   17075          76 :                     foreign = "FOREIGN ";
   17076          76 :                     break;
   17077             :                 }
   17078         848 :             case RELKIND_MATVIEW:
   17079         848 :                 reltypename = "MATERIALIZED VIEW";
   17080         848 :                 break;
   17081       13696 :             default:
   17082       13696 :                 reltypename = "TABLE";
   17083       13696 :                 break;
   17084             :         }
   17085             : 
   17086       16236 :         numParents = tbinfo->numParents;
   17087       16236 :         parents = tbinfo->parents;
   17088             : 
   17089       16236 :         appendPQExpBuffer(delq, "DROP %s %s;\n", reltypename, qualrelname);
   17090             : 
   17091       16236 :         if (dopt->binary_upgrade)
   17092        1600 :             binary_upgrade_set_pg_class_oids(fout, q,
   17093        1600 :                                              tbinfo->dobj.catId.oid);
   17094             : 
   17095             :         /*
   17096             :          * PostgreSQL 18 has disabled UNLOGGED for partitioned tables, so
   17097             :          * ignore it when dumping if it was set in this case.
   17098             :          */
   17099       16236 :         appendPQExpBuffer(q, "CREATE %s%s %s",
   17100       16236 :                           (tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED &&
   17101          64 :                            tbinfo->relkind != RELKIND_PARTITIONED_TABLE) ?
   17102             :                           "UNLOGGED " : "",
   17103             :                           reltypename,
   17104             :                           qualrelname);
   17105             : 
   17106             :         /*
   17107             :          * Attach to type, if reloftype; except in case of a binary upgrade,
   17108             :          * we dump the table normally and attach it to the type afterward.
   17109             :          */
   17110       16236 :         if (OidIsValid(tbinfo->reloftype) && !dopt->binary_upgrade)
   17111          84 :             appendPQExpBuffer(q, " OF %s",
   17112          84 :                               getFormattedTypeName(fout, tbinfo->reloftype,
   17113             :                                                    zeroIsError));
   17114             : 
   17115       16236 :         if (tbinfo->relkind != RELKIND_MATVIEW)
   17116             :         {
   17117             :             /* Dump the attributes */
   17118       15388 :             actual_atts = 0;
   17119       73520 :             for (j = 0; j < tbinfo->numatts; j++)
   17120             :             {
   17121             :                 /*
   17122             :                  * Normally, dump if it's locally defined in this table, and
   17123             :                  * not dropped.  But for binary upgrade, we'll dump all the
   17124             :                  * columns, and then fix up the dropped and nonlocal cases
   17125             :                  * below.
   17126             :                  */
   17127       58132 :                 if (shouldPrintColumn(dopt, tbinfo, j))
   17128             :                 {
   17129             :                     bool        print_default;
   17130             :                     bool        print_notnull;
   17131             : 
   17132             :                     /*
   17133             :                      * Default value --- suppress if to be printed separately
   17134             :                      * or not at all.
   17135             :                      */
   17136      113336 :                     print_default = (tbinfo->attrdefs[j] != NULL &&
   17137       58020 :                                      tbinfo->attrdefs[j]->dobj.dump &&
   17138        2830 :                                      !tbinfo->attrdefs[j]->separate);
   17139             : 
   17140             :                     /*
   17141             :                      * Not Null constraint --- print it if it is locally
   17142             :                      * defined, or if binary upgrade.  (In the latter case, we
   17143             :                      * reset conislocal below.)
   17144             :                      */
   17145       61246 :                     print_notnull = (tbinfo->notnull_constrs[j] != NULL &&
   17146        6056 :                                      (tbinfo->notnull_islocal[j] ||
   17147        1640 :                                       dopt->binary_upgrade ||
   17148        1472 :                                       tbinfo->ispartition));
   17149             : 
   17150             :                     /*
   17151             :                      * Skip column if fully defined by reloftype, except in
   17152             :                      * binary upgrade
   17153             :                      */
   17154       55190 :                     if (OidIsValid(tbinfo->reloftype) &&
   17155         160 :                         !print_default && !print_notnull &&
   17156          96 :                         !dopt->binary_upgrade)
   17157          84 :                         continue;
   17158             : 
   17159             :                     /* Format properly if not first attr */
   17160       55106 :                     if (actual_atts == 0)
   17161       14516 :                         appendPQExpBufferStr(q, " (");
   17162             :                     else
   17163       40590 :                         appendPQExpBufferChar(q, ',');
   17164       55106 :                     appendPQExpBufferStr(q, "\n    ");
   17165       55106 :                     actual_atts++;
   17166             : 
   17167             :                     /* Attribute name */
   17168       55106 :                     appendPQExpBufferStr(q, fmtId(tbinfo->attnames[j]));
   17169             : 
   17170       55106 :                     if (tbinfo->attisdropped[j])
   17171             :                     {
   17172             :                         /*
   17173             :                          * ALTER TABLE DROP COLUMN clears
   17174             :                          * pg_attribute.atttypid, so we will not have gotten a
   17175             :                          * valid type name; insert INTEGER as a stopgap. We'll
   17176             :                          * clean things up later.
   17177             :                          */
   17178         168 :                         appendPQExpBufferStr(q, " INTEGER /* dummy */");
   17179             :                         /* and skip to the next column */
   17180         168 :                         continue;
   17181             :                     }
   17182             : 
   17183             :                     /*
   17184             :                      * Attribute type; print it except when creating a typed
   17185             :                      * table ('OF type_name'), but in binary-upgrade mode,
   17186             :                      * print it in that case too.
   17187             :                      */
   17188       54938 :                     if (dopt->binary_upgrade || !OidIsValid(tbinfo->reloftype))
   17189             :                     {
   17190       54882 :                         appendPQExpBuffer(q, " %s",
   17191       54882 :                                           tbinfo->atttypnames[j]);
   17192             :                     }
   17193             : 
   17194       54938 :                     if (print_default)
   17195             :                     {
   17196        2476 :                         if (tbinfo->attgenerated[j] == ATTRIBUTE_GENERATED_STORED)
   17197         788 :                             appendPQExpBuffer(q, " GENERATED ALWAYS AS (%s) STORED",
   17198         788 :                                               tbinfo->attrdefs[j]->adef_expr);
   17199        1688 :                         else if (tbinfo->attgenerated[j] == ATTRIBUTE_GENERATED_VIRTUAL)
   17200         676 :                             appendPQExpBuffer(q, " GENERATED ALWAYS AS (%s)",
   17201         676 :                                               tbinfo->attrdefs[j]->adef_expr);
   17202             :                         else
   17203        1012 :                             appendPQExpBuffer(q, " DEFAULT %s",
   17204        1012 :                                               tbinfo->attrdefs[j]->adef_expr);
   17205             :                     }
   17206             : 
   17207       54938 :                     if (print_notnull)
   17208             :                     {
   17209        5986 :                         if (tbinfo->notnull_constrs[j][0] == '\0')
   17210        4268 :                             appendPQExpBufferStr(q, " NOT NULL");
   17211             :                         else
   17212        1718 :                             appendPQExpBuffer(q, " CONSTRAINT %s NOT NULL",
   17213        1718 :                                               fmtId(tbinfo->notnull_constrs[j]));
   17214             : 
   17215        5986 :                         if (tbinfo->notnull_noinh[j])
   17216           0 :                             appendPQExpBufferStr(q, " NO INHERIT");
   17217             :                     }
   17218             : 
   17219             :                     /* Add collation if not default for the type */
   17220       54938 :                     if (OidIsValid(tbinfo->attcollation[j]))
   17221             :                     {
   17222             :                         CollInfo   *coll;
   17223             : 
   17224         400 :                         coll = findCollationByOid(tbinfo->attcollation[j]);
   17225         400 :                         if (coll)
   17226         400 :                             appendPQExpBuffer(q, " COLLATE %s",
   17227         400 :                                               fmtQualifiedDumpable(coll));
   17228             :                     }
   17229             :                 }
   17230             : 
   17231             :                 /*
   17232             :                  * On the other hand, if we choose not to print a column
   17233             :                  * (likely because it is created by inheritance), but the
   17234             :                  * column has a locally-defined not-null constraint, we need
   17235             :                  * to dump the constraint as a standalone object.
   17236             :                  *
   17237             :                  * This syntax isn't SQL-conforming, but if you wanted
   17238             :                  * standard output you wouldn't be creating non-standard
   17239             :                  * objects to begin with.
   17240             :                  */
   17241       57880 :                 if (!shouldPrintColumn(dopt, tbinfo, j) &&
   17242        2942 :                     !tbinfo->attisdropped[j] &&
   17243        1876 :                     tbinfo->notnull_constrs[j] != NULL &&
   17244         490 :                     tbinfo->notnull_islocal[j])
   17245             :                 {
   17246             :                     /* Format properly if not first attr */
   17247         154 :                     if (actual_atts == 0)
   17248         140 :                         appendPQExpBufferStr(q, " (");
   17249             :                     else
   17250          14 :                         appendPQExpBufferChar(q, ',');
   17251         154 :                     appendPQExpBufferStr(q, "\n    ");
   17252         154 :                     actual_atts++;
   17253             : 
   17254         154 :                     if (tbinfo->notnull_constrs[j][0] == '\0')
   17255          14 :                         appendPQExpBuffer(q, "NOT NULL %s",
   17256          14 :                                           fmtId(tbinfo->attnames[j]));
   17257             :                     else
   17258         280 :                         appendPQExpBuffer(q, "CONSTRAINT %s NOT NULL %s",
   17259         140 :                                           tbinfo->notnull_constrs[j],
   17260         140 :                                           fmtId(tbinfo->attnames[j]));
   17261             :                 }
   17262             :             }
   17263             : 
   17264             :             /*
   17265             :              * Add non-inherited CHECK constraints, if any.
   17266             :              *
   17267             :              * For partitions, we need to include check constraints even if
   17268             :              * they're not defined locally, because the ALTER TABLE ATTACH
   17269             :              * PARTITION that we'll emit later expects the constraint to be
   17270             :              * there.  (No need to fix conislocal: ATTACH PARTITION does that)
   17271             :              */
   17272       16940 :             for (j = 0; j < tbinfo->ncheck; j++)
   17273             :             {
   17274        1552 :                 ConstraintInfo *constr = &(tbinfo->checkexprs[j]);
   17275             : 
   17276        1552 :                 if (constr->separate ||
   17277        1328 :                     (!constr->conislocal && !tbinfo->ispartition))
   17278         312 :                     continue;
   17279             : 
   17280        1240 :                 if (actual_atts == 0)
   17281          56 :                     appendPQExpBufferStr(q, " (\n    ");
   17282             :                 else
   17283        1184 :                     appendPQExpBufferStr(q, ",\n    ");
   17284             : 
   17285        1240 :                 appendPQExpBuffer(q, "CONSTRAINT %s ",
   17286        1240 :                                   fmtId(constr->dobj.name));
   17287        1240 :                 appendPQExpBufferStr(q, constr->condef);
   17288             : 
   17289        1240 :                 actual_atts++;
   17290             :             }
   17291             : 
   17292       15388 :             if (actual_atts)
   17293       14712 :                 appendPQExpBufferStr(q, "\n)");
   17294         676 :             else if (!(OidIsValid(tbinfo->reloftype) && !dopt->binary_upgrade))
   17295             :             {
   17296             :                 /*
   17297             :                  * No attributes? we must have a parenthesized attribute list,
   17298             :                  * even though empty, when not using the OF TYPE syntax.
   17299             :                  */
   17300         634 :                 appendPQExpBufferStr(q, " (\n)");
   17301             :             }
   17302             : 
   17303             :             /*
   17304             :              * Emit the INHERITS clause (not for partitions), except in
   17305             :              * binary-upgrade mode.
   17306             :              */
   17307       15388 :             if (numParents > 0 && !tbinfo->ispartition &&
   17308        1358 :                 !dopt->binary_upgrade)
   17309             :             {
   17310        1232 :                 appendPQExpBufferStr(q, "\nINHERITS (");
   17311        2674 :                 for (k = 0; k < numParents; k++)
   17312             :                 {
   17313        1442 :                     TableInfo  *parentRel = parents[k];
   17314             : 
   17315        1442 :                     if (k > 0)
   17316         210 :                         appendPQExpBufferStr(q, ", ");
   17317        1442 :                     appendPQExpBufferStr(q, fmtQualifiedDumpable(parentRel));
   17318             :                 }
   17319        1232 :                 appendPQExpBufferChar(q, ')');
   17320             :             }
   17321             : 
   17322       15388 :             if (tbinfo->relkind == RELKIND_PARTITIONED_TABLE)
   17323        1616 :                 appendPQExpBuffer(q, "\nPARTITION BY %s", partkeydef);
   17324             : 
   17325       15388 :             if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
   17326          76 :                 appendPQExpBuffer(q, "\nSERVER %s", fmtId(srvname));
   17327             :         }
   17328             : 
   17329       32048 :         if (nonemptyReloptions(tbinfo->reloptions) ||
   17330       15812 :             nonemptyReloptions(tbinfo->toast_reloptions))
   17331             :         {
   17332         424 :             bool        addcomma = false;
   17333             : 
   17334         424 :             appendPQExpBufferStr(q, "\nWITH (");
   17335         424 :             if (nonemptyReloptions(tbinfo->reloptions))
   17336             :             {
   17337         424 :                 addcomma = true;
   17338         424 :                 appendReloptionsArrayAH(q, tbinfo->reloptions, "", fout);
   17339             :             }
   17340         424 :             if (nonemptyReloptions(tbinfo->toast_reloptions))
   17341             :             {
   17342          16 :                 if (addcomma)
   17343          16 :                     appendPQExpBufferStr(q, ", ");
   17344          16 :                 appendReloptionsArrayAH(q, tbinfo->toast_reloptions, "toast.",
   17345             :                                         fout);
   17346             :             }
   17347         424 :             appendPQExpBufferChar(q, ')');
   17348             :         }
   17349             : 
   17350             :         /* Dump generic options if any */
   17351       16236 :         if (ftoptions && ftoptions[0])
   17352          72 :             appendPQExpBuffer(q, "\nOPTIONS (\n    %s\n)", ftoptions);
   17353             : 
   17354             :         /*
   17355             :          * For materialized views, create the AS clause just like a view. At
   17356             :          * this point, we always mark the view as not populated.
   17357             :          */
   17358       16236 :         if (tbinfo->relkind == RELKIND_MATVIEW)
   17359             :         {
   17360             :             PQExpBuffer result;
   17361             : 
   17362         848 :             result = createViewAsClause(fout, tbinfo);
   17363         848 :             appendPQExpBuffer(q, " AS\n%s\n  WITH NO DATA;\n",
   17364             :                               result->data);
   17365         848 :             destroyPQExpBuffer(result);
   17366             :         }
   17367             :         else
   17368       15388 :             appendPQExpBufferStr(q, ";\n");
   17369             : 
   17370             :         /* Materialized views can depend on extensions */
   17371       16236 :         if (tbinfo->relkind == RELKIND_MATVIEW)
   17372         848 :             append_depends_on_extension(fout, q, &tbinfo->dobj,
   17373             :                                         "pg_catalog.pg_class",
   17374             :                                         "MATERIALIZED VIEW",
   17375             :                                         qualrelname);
   17376             : 
   17377             :         /*
   17378             :          * in binary upgrade mode, update the catalog with any missing values
   17379             :          * that might be present.
   17380             :          */
   17381       16236 :         if (dopt->binary_upgrade)
   17382             :         {
   17383        7836 :             for (j = 0; j < tbinfo->numatts; j++)
   17384             :             {
   17385        6236 :                 if (tbinfo->attmissingval[j][0] != '\0')
   17386             :                 {
   17387           4 :                     appendPQExpBufferStr(q, "\n-- set missing value.\n");
   17388           4 :                     appendPQExpBufferStr(q,
   17389             :                                          "SELECT pg_catalog.binary_upgrade_set_missing_value(");
   17390           4 :                     appendStringLiteralAH(q, qualrelname, fout);
   17391           4 :                     appendPQExpBufferStr(q, "::pg_catalog.regclass,");
   17392           4 :                     appendStringLiteralAH(q, tbinfo->attnames[j], fout);
   17393           4 :                     appendPQExpBufferChar(q, ',');
   17394           4 :                     appendStringLiteralAH(q, tbinfo->attmissingval[j], fout);
   17395           4 :                     appendPQExpBufferStr(q, ");\n\n");
   17396             :                 }
   17397             :             }
   17398             :         }
   17399             : 
   17400             :         /*
   17401             :          * To create binary-compatible heap files, we have to ensure the same
   17402             :          * physical column order, including dropped columns, as in the
   17403             :          * original.  Therefore, we create dropped columns above and drop them
   17404             :          * here, also updating their attlen/attalign values so that the
   17405             :          * dropped column can be skipped properly.  (We do not bother with
   17406             :          * restoring the original attbyval setting.)  Also, inheritance
   17407             :          * relationships are set up by doing ALTER TABLE INHERIT rather than
   17408             :          * using an INHERITS clause --- the latter would possibly mess up the
   17409             :          * column order.  That also means we have to take care about setting
   17410             :          * attislocal correctly, plus fix up any inherited CHECK constraints.
   17411             :          * Analogously, we set up typed tables using ALTER TABLE / OF here.
   17412             :          *
   17413             :          * We process foreign and partitioned tables here, even though they
   17414             :          * lack heap storage, because they can participate in inheritance
   17415             :          * relationships and we want this stuff to be consistent across the
   17416             :          * inheritance tree.  We can exclude indexes, toast tables, sequences
   17417             :          * and matviews, even though they have storage, because we don't
   17418             :          * support altering or dropping columns in them, nor can they be part
   17419             :          * of inheritance trees.
   17420             :          */
   17421       16236 :         if (dopt->binary_upgrade &&
   17422        1600 :             (tbinfo->relkind == RELKIND_RELATION ||
   17423         218 :              tbinfo->relkind == RELKIND_FOREIGN_TABLE ||
   17424         216 :              tbinfo->relkind == RELKIND_PARTITIONED_TABLE))
   17425             :         {
   17426             :             bool        firstitem;
   17427             :             bool        firstitem_extra;
   17428             : 
   17429             :             /*
   17430             :              * Drop any dropped columns.  Merge the pg_attribute manipulations
   17431             :              * into a single SQL command, so that we don't cause repeated
   17432             :              * relcache flushes on the target table.  Otherwise we risk O(N^2)
   17433             :              * relcache bloat while dropping N columns.
   17434             :              */
   17435        1564 :             resetPQExpBuffer(extra);
   17436        1564 :             firstitem = true;
   17437        7756 :             for (j = 0; j < tbinfo->numatts; j++)
   17438             :             {
   17439        6192 :                 if (tbinfo->attisdropped[j])
   17440             :                 {
   17441         168 :                     if (firstitem)
   17442             :                     {
   17443          76 :                         appendPQExpBufferStr(q, "\n-- For binary upgrade, recreate dropped columns.\n"
   17444             :                                              "UPDATE pg_catalog.pg_attribute\n"
   17445             :                                              "SET attlen = v.dlen, "
   17446             :                                              "attalign = v.dalign, "
   17447             :                                              "attbyval = false\n"
   17448             :                                              "FROM (VALUES ");
   17449          76 :                         firstitem = false;
   17450             :                     }
   17451             :                     else
   17452          92 :                         appendPQExpBufferStr(q, ",\n             ");
   17453         168 :                     appendPQExpBufferChar(q, '(');
   17454         168 :                     appendStringLiteralAH(q, tbinfo->attnames[j], fout);
   17455         168 :                     appendPQExpBuffer(q, ", %d, '%c')",
   17456         168 :                                       tbinfo->attlen[j],
   17457         168 :                                       tbinfo->attalign[j]);
   17458             :                     /* The ALTER ... DROP COLUMN commands must come after */
   17459         168 :                     appendPQExpBuffer(extra, "ALTER %sTABLE ONLY %s ",
   17460             :                                       foreign, qualrelname);
   17461         168 :                     appendPQExpBuffer(extra, "DROP COLUMN %s;\n",
   17462         168 :                                       fmtId(tbinfo->attnames[j]));
   17463             :                 }
   17464             :             }
   17465        1564 :             if (!firstitem)
   17466             :             {
   17467          76 :                 appendPQExpBufferStr(q, ") v(dname, dlen, dalign)\n"
   17468             :                                      "WHERE attrelid = ");
   17469          76 :                 appendStringLiteralAH(q, qualrelname, fout);
   17470          76 :                 appendPQExpBufferStr(q, "::pg_catalog.regclass\n"
   17471             :                                      "  AND attname = v.dname;\n");
   17472             :                 /* Now we can issue the actual DROP COLUMN commands */
   17473          76 :                 appendBinaryPQExpBuffer(q, extra->data, extra->len);
   17474             :             }
   17475             : 
   17476             :             /*
   17477             :              * Fix up inherited columns.  As above, do the pg_attribute
   17478             :              * manipulations in a single SQL command.
   17479             :              */
   17480        1564 :             firstitem = true;
   17481        7756 :             for (j = 0; j < tbinfo->numatts; j++)
   17482             :             {
   17483        6192 :                 if (!tbinfo->attisdropped[j] &&
   17484        6024 :                     !tbinfo->attislocal[j])
   17485             :                 {
   17486        1202 :                     if (firstitem)
   17487             :                     {
   17488         528 :                         appendPQExpBufferStr(q, "\n-- For binary upgrade, recreate inherited columns.\n");
   17489         528 :                         appendPQExpBufferStr(q, "UPDATE pg_catalog.pg_attribute\n"
   17490             :                                              "SET attislocal = false\n"
   17491             :                                              "WHERE attrelid = ");
   17492         528 :                         appendStringLiteralAH(q, qualrelname, fout);
   17493         528 :                         appendPQExpBufferStr(q, "::pg_catalog.regclass\n"
   17494             :                                              "  AND attname IN (");
   17495         528 :                         firstitem = false;
   17496             :                     }
   17497             :                     else
   17498         674 :                         appendPQExpBufferStr(q, ", ");
   17499        1202 :                     appendStringLiteralAH(q, tbinfo->attnames[j], fout);
   17500             :                 }
   17501             :             }
   17502        1564 :             if (!firstitem)
   17503         528 :                 appendPQExpBufferStr(q, ");\n");
   17504             : 
   17505             :             /*
   17506             :              * Fix up not-null constraints that come from inheritance.  As
   17507             :              * above, do the pg_constraint manipulations in a single SQL
   17508             :              * command.  (Actually, two in special cases, if we're doing an
   17509             :              * upgrade from < 18).
   17510             :              */
   17511        1564 :             firstitem = true;
   17512        1564 :             firstitem_extra = true;
   17513        1564 :             resetPQExpBuffer(extra);
   17514        7756 :             for (j = 0; j < tbinfo->numatts; j++)
   17515             :             {
   17516             :                 /*
   17517             :                  * If a not-null constraint comes from inheritance, reset
   17518             :                  * conislocal.  The inhcount is fixed by ALTER TABLE INHERIT,
   17519             :                  * below.  Special hack: in versions < 18, columns with no
   17520             :                  * local definition need their constraint to be matched by
   17521             :                  * column number in conkeys instead of by constraint name,
   17522             :                  * because the latter is not available.  (We distinguish the
   17523             :                  * case because the constraint name is the empty string.)
   17524             :                  */
   17525        6192 :                 if (tbinfo->notnull_constrs[j] != NULL &&
   17526         580 :                     !tbinfo->notnull_islocal[j])
   17527             :                 {
   17528         168 :                     if (tbinfo->notnull_constrs[j][0] != '\0')
   17529             :                     {
   17530         142 :                         if (firstitem)
   17531             :                         {
   17532         122 :                             appendPQExpBufferStr(q, "UPDATE pg_catalog.pg_constraint\n"
   17533             :                                                  "SET conislocal = false\n"
   17534             :                                                  "WHERE contype = 'n' AND conrelid = ");
   17535         122 :                             appendStringLiteralAH(q, qualrelname, fout);
   17536         122 :                             appendPQExpBufferStr(q, "::pg_catalog.regclass AND\n"
   17537             :                                                  "conname IN (");
   17538         122 :                             firstitem = false;
   17539             :                         }
   17540             :                         else
   17541          20 :                             appendPQExpBufferStr(q, ", ");
   17542         142 :                         appendStringLiteralAH(q, tbinfo->notnull_constrs[j], fout);
   17543             :                     }
   17544             :                     else
   17545             :                     {
   17546          26 :                         if (firstitem_extra)
   17547             :                         {
   17548          26 :                             appendPQExpBufferStr(extra, "UPDATE pg_catalog.pg_constraint\n"
   17549             :                                                  "SET conislocal = false\n"
   17550             :                                                  "WHERE contype = 'n' AND conrelid = ");
   17551          26 :                             appendStringLiteralAH(extra, qualrelname, fout);
   17552          26 :                             appendPQExpBufferStr(extra, "::pg_catalog.regclass AND\n"
   17553             :                                                  "conkey IN (");
   17554          26 :                             firstitem_extra = false;
   17555             :                         }
   17556             :                         else
   17557           0 :                             appendPQExpBufferStr(extra, ", ");
   17558          26 :                         appendPQExpBuffer(extra, "'{%d}'", j + 1);
   17559             :                     }
   17560             :                 }
   17561             :             }
   17562        1564 :             if (!firstitem)
   17563         122 :                 appendPQExpBufferStr(q, ");\n");
   17564        1564 :             if (!firstitem_extra)
   17565          26 :                 appendPQExpBufferStr(extra, ");\n");
   17566             : 
   17567        1564 :             if (extra->len > 0)
   17568          26 :                 appendBinaryPQExpBuffer(q, extra->data, extra->len);
   17569             : 
   17570             :             /*
   17571             :              * Add inherited CHECK constraints, if any.
   17572             :              *
   17573             :              * For partitions, they were already dumped, and conislocal
   17574             :              * doesn't need fixing.
   17575             :              *
   17576             :              * As above, issue only one direct manipulation of pg_constraint.
   17577             :              * Although it is tempting to merge the ALTER ADD CONSTRAINT
   17578             :              * commands into one as well, refrain for now due to concern about
   17579             :              * possible backend memory bloat if there are many such
   17580             :              * constraints.
   17581             :              */
   17582        1564 :             resetPQExpBuffer(extra);
   17583        1564 :             firstitem = true;
   17584        1692 :             for (k = 0; k < tbinfo->ncheck; k++)
   17585             :             {
   17586         128 :                 ConstraintInfo *constr = &(tbinfo->checkexprs[k]);
   17587             : 
   17588         128 :                 if (constr->separate || constr->conislocal || tbinfo->ispartition)
   17589         124 :                     continue;
   17590             : 
   17591           4 :                 if (firstitem)
   17592           4 :                     appendPQExpBufferStr(q, "\n-- For binary upgrade, set up inherited constraints.\n");
   17593           4 :                 appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s ADD CONSTRAINT %s %s;\n",
   17594             :                                   foreign, qualrelname,
   17595           4 :                                   fmtId(constr->dobj.name),
   17596             :                                   constr->condef);
   17597             :                 /* Update pg_constraint after all the ALTER TABLEs */
   17598           4 :                 if (firstitem)
   17599             :                 {
   17600           4 :                     appendPQExpBufferStr(extra, "UPDATE pg_catalog.pg_constraint\n"
   17601             :                                          "SET conislocal = false\n"
   17602             :                                          "WHERE contype = 'c' AND conrelid = ");
   17603           4 :                     appendStringLiteralAH(extra, qualrelname, fout);
   17604           4 :                     appendPQExpBufferStr(extra, "::pg_catalog.regclass\n");
   17605           4 :                     appendPQExpBufferStr(extra, "  AND conname IN (");
   17606           4 :                     firstitem = false;
   17607             :                 }
   17608             :                 else
   17609           0 :                     appendPQExpBufferStr(extra, ", ");
   17610           4 :                 appendStringLiteralAH(extra, constr->dobj.name, fout);
   17611             :             }
   17612        1564 :             if (!firstitem)
   17613             :             {
   17614           4 :                 appendPQExpBufferStr(extra, ");\n");
   17615           4 :                 appendBinaryPQExpBuffer(q, extra->data, extra->len);
   17616             :             }
   17617             : 
   17618        1564 :             if (numParents > 0 && !tbinfo->ispartition)
   17619             :             {
   17620         126 :                 appendPQExpBufferStr(q, "\n-- For binary upgrade, set up inheritance this way.\n");
   17621         274 :                 for (k = 0; k < numParents; k++)
   17622             :                 {
   17623         148 :                     TableInfo  *parentRel = parents[k];
   17624             : 
   17625         148 :                     appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s INHERIT %s;\n", foreign,
   17626             :                                       qualrelname,
   17627         148 :                                       fmtQualifiedDumpable(parentRel));
   17628             :                 }
   17629             :             }
   17630             : 
   17631        1564 :             if (OidIsValid(tbinfo->reloftype))
   17632             :             {
   17633          12 :                 appendPQExpBufferStr(q, "\n-- For binary upgrade, set up typed tables this way.\n");
   17634          12 :                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s OF %s;\n",
   17635             :                                   qualrelname,
   17636          12 :                                   getFormattedTypeName(fout, tbinfo->reloftype,
   17637             :                                                        zeroIsError));
   17638             :             }
   17639             :         }
   17640             : 
   17641             :         /*
   17642             :          * In binary_upgrade mode, arrange to restore the old relfrozenxid and
   17643             :          * relminmxid of all vacuumable relations.  (While vacuum.c processes
   17644             :          * TOAST tables semi-independently, here we see them only as children
   17645             :          * of other relations; so this "if" lacks RELKIND_TOASTVALUE, and the
   17646             :          * child toast table is handled below.)
   17647             :          */
   17648       16236 :         if (dopt->binary_upgrade &&
   17649        1600 :             (tbinfo->relkind == RELKIND_RELATION ||
   17650         218 :              tbinfo->relkind == RELKIND_MATVIEW))
   17651             :         {
   17652        1418 :             appendPQExpBufferStr(q, "\n-- For binary upgrade, set heap's relfrozenxid and relminmxid\n");
   17653        1418 :             appendPQExpBuffer(q, "UPDATE pg_catalog.pg_class\n"
   17654             :                               "SET relfrozenxid = '%u', relminmxid = '%u'\n"
   17655             :                               "WHERE oid = ",
   17656        1418 :                               tbinfo->frozenxid, tbinfo->minmxid);
   17657        1418 :             appendStringLiteralAH(q, qualrelname, fout);
   17658        1418 :             appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
   17659             : 
   17660        1418 :             if (tbinfo->toast_oid)
   17661             :             {
   17662             :                 /*
   17663             :                  * The toast table will have the same OID at restore, so we
   17664             :                  * can safely target it by OID.
   17665             :                  */
   17666         560 :                 appendPQExpBufferStr(q, "\n-- For binary upgrade, set toast's relfrozenxid and relminmxid\n");
   17667         560 :                 appendPQExpBuffer(q, "UPDATE pg_catalog.pg_class\n"
   17668             :                                   "SET relfrozenxid = '%u', relminmxid = '%u'\n"
   17669             :                                   "WHERE oid = '%u';\n",
   17670         560 :                                   tbinfo->toast_frozenxid,
   17671         560 :                                   tbinfo->toast_minmxid, tbinfo->toast_oid);
   17672             :             }
   17673             :         }
   17674             : 
   17675             :         /*
   17676             :          * In binary_upgrade mode, restore matviews' populated status by
   17677             :          * poking pg_class directly.  This is pretty ugly, but we can't use
   17678             :          * REFRESH MATERIALIZED VIEW since it's possible that some underlying
   17679             :          * matview is not populated even though this matview is; in any case,
   17680             :          * we want to transfer the matview's heap storage, not run REFRESH.
   17681             :          */
   17682       16236 :         if (dopt->binary_upgrade && tbinfo->relkind == RELKIND_MATVIEW &&
   17683          36 :             tbinfo->relispopulated)
   17684             :         {
   17685          32 :             appendPQExpBufferStr(q, "\n-- For binary upgrade, mark materialized view as populated\n");
   17686          32 :             appendPQExpBufferStr(q, "UPDATE pg_catalog.pg_class\n"
   17687             :                                  "SET relispopulated = 't'\n"
   17688             :                                  "WHERE oid = ");
   17689          32 :             appendStringLiteralAH(q, qualrelname, fout);
   17690          32 :             appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
   17691             :         }
   17692             : 
   17693             :         /*
   17694             :          * Dump additional per-column properties that we can't handle in the
   17695             :          * main CREATE TABLE command.
   17696             :          */
   17697       75392 :         for (j = 0; j < tbinfo->numatts; j++)
   17698             :         {
   17699             :             /* None of this applies to dropped columns */
   17700       59156 :             if (tbinfo->attisdropped[j])
   17701        1234 :                 continue;
   17702             : 
   17703             :             /*
   17704             :              * Dump per-column statistics information. We only issue an ALTER
   17705             :              * TABLE statement if the attstattarget entry for this column is
   17706             :              * not the default value.
   17707             :              */
   17708       57922 :             if (tbinfo->attstattarget[j] >= 0)
   17709          72 :                 appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s ALTER COLUMN %s SET STATISTICS %d;\n",
   17710             :                                   foreign, qualrelname,
   17711          72 :                                   fmtId(tbinfo->attnames[j]),
   17712          72 :                                   tbinfo->attstattarget[j]);
   17713             : 
   17714             :             /*
   17715             :              * Dump per-column storage information.  The statement is only
   17716             :              * dumped if the storage has been changed from the type's default.
   17717             :              */
   17718       57922 :             if (tbinfo->attstorage[j] != tbinfo->typstorage[j])
   17719             :             {
   17720         192 :                 switch (tbinfo->attstorage[j])
   17721             :                 {
   17722          32 :                     case TYPSTORAGE_PLAIN:
   17723          32 :                         storage = "PLAIN";
   17724          32 :                         break;
   17725          88 :                     case TYPSTORAGE_EXTERNAL:
   17726          88 :                         storage = "EXTERNAL";
   17727          88 :                         break;
   17728           0 :                     case TYPSTORAGE_EXTENDED:
   17729           0 :                         storage = "EXTENDED";
   17730           0 :                         break;
   17731          72 :                     case TYPSTORAGE_MAIN:
   17732          72 :                         storage = "MAIN";
   17733          72 :                         break;
   17734           0 :                     default:
   17735           0 :                         storage = NULL;
   17736             :                 }
   17737             : 
   17738             :                 /*
   17739             :                  * Only dump the statement if it's a storage type we recognize
   17740             :                  */
   17741         192 :                 if (storage != NULL)
   17742         192 :                     appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s ALTER COLUMN %s SET STORAGE %s;\n",
   17743             :                                       foreign, qualrelname,
   17744         192 :                                       fmtId(tbinfo->attnames[j]),
   17745             :                                       storage);
   17746             :             }
   17747             : 
   17748             :             /*
   17749             :              * Dump per-column compression, if it's been set.
   17750             :              */
   17751       57922 :             if (!dopt->no_toast_compression)
   17752             :             {
   17753             :                 const char *cmname;
   17754             : 
   17755       57732 :                 switch (tbinfo->attcompression[j])
   17756             :                 {
   17757         198 :                     case 'p':
   17758         198 :                         cmname = "pglz";
   17759         198 :                         break;
   17760         220 :                     case 'l':
   17761         220 :                         cmname = "lz4";
   17762         220 :                         break;
   17763       57314 :                     default:
   17764       57314 :                         cmname = NULL;
   17765       57314 :                         break;
   17766             :                 }
   17767             : 
   17768       57732 :                 if (cmname != NULL)
   17769         418 :                     appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s ALTER COLUMN %s SET COMPRESSION %s;\n",
   17770             :                                       foreign, qualrelname,
   17771         418 :                                       fmtId(tbinfo->attnames[j]),
   17772             :                                       cmname);
   17773             :             }
   17774             : 
   17775             :             /*
   17776             :              * Dump per-column attributes.
   17777             :              */
   17778       57922 :             if (tbinfo->attoptions[j][0] != '\0')
   17779          72 :                 appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s ALTER COLUMN %s SET (%s);\n",
   17780             :                                   foreign, qualrelname,
   17781          72 :                                   fmtId(tbinfo->attnames[j]),
   17782          72 :                                   tbinfo->attoptions[j]);
   17783             : 
   17784             :             /*
   17785             :              * Dump per-column fdw options.
   17786             :              */
   17787       57922 :             if (tbinfo->relkind == RELKIND_FOREIGN_TABLE &&
   17788          76 :                 tbinfo->attfdwoptions[j][0] != '\0')
   17789          72 :                 appendPQExpBuffer(q,
   17790             :                                   "ALTER FOREIGN TABLE ONLY %s ALTER COLUMN %s OPTIONS (\n"
   17791             :                                   "    %s\n"
   17792             :                                   ");\n",
   17793             :                                   qualrelname,
   17794          72 :                                   fmtId(tbinfo->attnames[j]),
   17795          72 :                                   tbinfo->attfdwoptions[j]);
   17796             :         }                       /* end loop over columns */
   17797             : 
   17798       16236 :         free(partkeydef);
   17799       16236 :         free(ftoptions);
   17800       16236 :         free(srvname);
   17801             :     }
   17802             : 
   17803             :     /*
   17804             :      * dump properties we only have ALTER TABLE syntax for
   17805             :      */
   17806       17610 :     if ((tbinfo->relkind == RELKIND_RELATION ||
   17807        3914 :          tbinfo->relkind == RELKIND_PARTITIONED_TABLE ||
   17808        2298 :          tbinfo->relkind == RELKIND_MATVIEW) &&
   17809       16160 :         tbinfo->relreplident != REPLICA_IDENTITY_DEFAULT)
   17810             :     {
   17811         384 :         if (tbinfo->relreplident == REPLICA_IDENTITY_INDEX)
   17812             :         {
   17813             :             /* nothing to do, will be set when the index is dumped */
   17814             :         }
   17815         384 :         else if (tbinfo->relreplident == REPLICA_IDENTITY_NOTHING)
   17816             :         {
   17817         384 :             appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY NOTHING;\n",
   17818             :                               qualrelname);
   17819             :         }
   17820           0 :         else if (tbinfo->relreplident == REPLICA_IDENTITY_FULL)
   17821             :         {
   17822           0 :             appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY FULL;\n",
   17823             :                               qualrelname);
   17824             :         }
   17825             :     }
   17826             : 
   17827       17610 :     if (tbinfo->forcerowsec)
   17828          16 :         appendPQExpBuffer(q, "\nALTER TABLE ONLY %s FORCE ROW LEVEL SECURITY;\n",
   17829             :                           qualrelname);
   17830             : 
   17831       17610 :     if (dopt->binary_upgrade)
   17832        1704 :         binary_upgrade_extension_member(q, &tbinfo->dobj,
   17833             :                                         reltypename, qrelname,
   17834        1704 :                                         tbinfo->dobj.namespace->dobj.name);
   17835             : 
   17836       17610 :     if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   17837             :     {
   17838       17610 :         char       *tablespace = NULL;
   17839       17610 :         char       *tableam = NULL;
   17840             : 
   17841             :         /*
   17842             :          * _selectTablespace() relies on tablespace-enabled objects in the
   17843             :          * default tablespace to have a tablespace of "" (empty string) versus
   17844             :          * non-tablespace-enabled objects to have a tablespace of NULL.
   17845             :          * getTables() sets tbinfo->reltablespace to "" for the default
   17846             :          * tablespace (not NULL).
   17847             :          */
   17848       17610 :         if (RELKIND_HAS_TABLESPACE(tbinfo->relkind))
   17849       16160 :             tablespace = tbinfo->reltablespace;
   17850             : 
   17851       17610 :         if (RELKIND_HAS_TABLE_AM(tbinfo->relkind) ||
   17852        3066 :             tbinfo->relkind == RELKIND_PARTITIONED_TABLE)
   17853       16160 :             tableam = tbinfo->amname;
   17854             : 
   17855       17610 :         ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
   17856       17610 :                      ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
   17857             :                                   .namespace = tbinfo->dobj.namespace->dobj.name,
   17858             :                                   .tablespace = tablespace,
   17859             :                                   .tableam = tableam,
   17860             :                                   .relkind = tbinfo->relkind,
   17861             :                                   .owner = tbinfo->rolname,
   17862             :                                   .description = reltypename,
   17863             :                                   .section = tbinfo->postponed_def ?
   17864             :                                   SECTION_POST_DATA : SECTION_PRE_DATA,
   17865             :                                   .createStmt = q->data,
   17866             :                                   .dropStmt = delq->data));
   17867             :     }
   17868             : 
   17869             :     /* Dump Table Comments */
   17870       17610 :     if (tbinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   17871         176 :         dumpTableComment(fout, tbinfo, reltypename);
   17872             : 
   17873             :     /* Dump Table Security Labels */
   17874       17610 :     if (tbinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
   17875           0 :         dumpTableSecLabel(fout, tbinfo, reltypename);
   17876             : 
   17877             :     /*
   17878             :      * Dump comments for not-null constraints that aren't to be dumped
   17879             :      * separately (those are processed by collectComments/dumpComment).
   17880             :      */
   17881       17610 :     if (!fout->dopt->no_comments && dopt->dumpSchema &&
   17882       17610 :         fout->remoteVersion >= 180000)
   17883             :     {
   17884       17610 :         PQExpBuffer comment = NULL;
   17885       17610 :         PQExpBuffer tag = NULL;
   17886             : 
   17887       84460 :         for (j = 0; j < tbinfo->numatts; j++)
   17888             :         {
   17889       66850 :             if (tbinfo->notnull_constrs[j] != NULL &&
   17890        6546 :                 tbinfo->notnull_comment[j] != NULL)
   17891             :             {
   17892         104 :                 if (comment == NULL)
   17893             :                 {
   17894         104 :                     comment = createPQExpBuffer();
   17895         104 :                     tag = createPQExpBuffer();
   17896             :                 }
   17897             :                 else
   17898             :                 {
   17899           0 :                     resetPQExpBuffer(comment);
   17900           0 :                     resetPQExpBuffer(tag);
   17901             :                 }
   17902             : 
   17903         104 :                 appendPQExpBuffer(comment, "COMMENT ON CONSTRAINT %s ON %s IS ",
   17904         104 :                                   fmtId(tbinfo->notnull_constrs[j]), qualrelname);
   17905         104 :                 appendStringLiteralAH(comment, tbinfo->notnull_comment[j], fout);
   17906         104 :                 appendPQExpBufferStr(comment, ";\n");
   17907             : 
   17908         104 :                 appendPQExpBuffer(tag, "CONSTRAINT %s ON %s",
   17909         104 :                                   fmtId(tbinfo->notnull_constrs[j]), qrelname);
   17910             : 
   17911         104 :                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
   17912         104 :                              ARCHIVE_OPTS(.tag = tag->data,
   17913             :                                           .namespace = tbinfo->dobj.namespace->dobj.name,
   17914             :                                           .owner = tbinfo->rolname,
   17915             :                                           .description = "COMMENT",
   17916             :                                           .section = SECTION_NONE,
   17917             :                                           .createStmt = comment->data,
   17918             :                                           .deps = &(tbinfo->dobj.dumpId),
   17919             :                                           .nDeps = 1));
   17920             :             }
   17921             :         }
   17922             : 
   17923       17610 :         destroyPQExpBuffer(comment);
   17924       17610 :         destroyPQExpBuffer(tag);
   17925             :     }
   17926             : 
   17927             :     /* Dump comments on inlined table constraints */
   17928       19162 :     for (j = 0; j < tbinfo->ncheck; j++)
   17929             :     {
   17930        1552 :         ConstraintInfo *constr = &(tbinfo->checkexprs[j]);
   17931             : 
   17932        1552 :         if (constr->separate || !constr->conislocal)
   17933         624 :             continue;
   17934             : 
   17935         928 :         if (constr->dobj.dump & DUMP_COMPONENT_COMMENT)
   17936          88 :             dumpTableConstraintComment(fout, constr);
   17937             :     }
   17938             : 
   17939       17610 :     destroyPQExpBuffer(q);
   17940       17610 :     destroyPQExpBuffer(delq);
   17941       17610 :     destroyPQExpBuffer(extra);
   17942       17610 :     free(qrelname);
   17943       17610 :     free(qualrelname);
   17944       17610 : }
   17945             : 
   17946             : /*
   17947             :  * dumpTableAttach
   17948             :  *    write to fout the commands to attach a child partition
   17949             :  *
   17950             :  * Child partitions are always made by creating them separately
   17951             :  * and then using ATTACH PARTITION, rather than using
   17952             :  * CREATE TABLE ... PARTITION OF.  This is important for preserving
   17953             :  * any possible discrepancy in column layout, to allow assigning the
   17954             :  * correct tablespace if different, and so that it's possible to restore
   17955             :  * a partition without restoring its parent.  (You'll get an error from
   17956             :  * the ATTACH PARTITION command, but that can be ignored, or skipped
   17957             :  * using "pg_restore -L" if you prefer.)  The last point motivates
   17958             :  * treating ATTACH PARTITION as a completely separate ArchiveEntry
   17959             :  * rather than emitting it within the child partition's ArchiveEntry.
   17960             :  */
   17961             : static void
   17962        3900 : dumpTableAttach(Archive *fout, const TableAttachInfo *attachinfo)
   17963             : {
   17964        3900 :     DumpOptions *dopt = fout->dopt;
   17965             :     PQExpBuffer q;
   17966             :     PGresult   *res;
   17967             :     char       *partbound;
   17968             : 
   17969             :     /* Do nothing if not dumping schema */
   17970        3900 :     if (!dopt->dumpSchema)
   17971          84 :         return;
   17972             : 
   17973        3816 :     q = createPQExpBuffer();
   17974             : 
   17975        3816 :     if (!fout->is_prepared[PREPQUERY_DUMPTABLEATTACH])
   17976             :     {
   17977             :         /* Set up query for partbound details */
   17978         100 :         appendPQExpBufferStr(q,
   17979             :                              "PREPARE dumpTableAttach(pg_catalog.oid) AS\n");
   17980             : 
   17981         100 :         appendPQExpBufferStr(q,
   17982             :                              "SELECT pg_get_expr(c.relpartbound, c.oid) "
   17983             :                              "FROM pg_class c "
   17984             :                              "WHERE c.oid = $1");
   17985             : 
   17986         100 :         ExecuteSqlStatement(fout, q->data);
   17987             : 
   17988         100 :         fout->is_prepared[PREPQUERY_DUMPTABLEATTACH] = true;
   17989             :     }
   17990             : 
   17991        3816 :     printfPQExpBuffer(q,
   17992             :                       "EXECUTE dumpTableAttach('%u')",
   17993        3816 :                       attachinfo->partitionTbl->dobj.catId.oid);
   17994             : 
   17995        3816 :     res = ExecuteSqlQueryForSingleRow(fout, q->data);
   17996        3816 :     partbound = PQgetvalue(res, 0, 0);
   17997             : 
   17998             :     /* Perform ALTER TABLE on the parent */
   17999        3816 :     printfPQExpBuffer(q,
   18000             :                       "ALTER TABLE ONLY %s ",
   18001        3816 :                       fmtQualifiedDumpable(attachinfo->parentTbl));
   18002        3816 :     appendPQExpBuffer(q,
   18003             :                       "ATTACH PARTITION %s %s;\n",
   18004        3816 :                       fmtQualifiedDumpable(attachinfo->partitionTbl),
   18005             :                       partbound);
   18006             : 
   18007             :     /*
   18008             :      * There is no point in creating a drop query as the drop is done by table
   18009             :      * drop.  (If you think to change this, see also _printTocEntry().)
   18010             :      * Although this object doesn't really have ownership as such, set the
   18011             :      * owner field anyway to ensure that the command is run by the correct
   18012             :      * role at restore time.
   18013             :      */
   18014        3816 :     ArchiveEntry(fout, attachinfo->dobj.catId, attachinfo->dobj.dumpId,
   18015        3816 :                  ARCHIVE_OPTS(.tag = attachinfo->dobj.name,
   18016             :                               .namespace = attachinfo->dobj.namespace->dobj.name,
   18017             :                               .owner = attachinfo->partitionTbl->rolname,
   18018             :                               .description = "TABLE ATTACH",
   18019             :                               .section = SECTION_PRE_DATA,
   18020             :                               .createStmt = q->data));
   18021             : 
   18022        3816 :     PQclear(res);
   18023        3816 :     destroyPQExpBuffer(q);
   18024             : }
   18025             : 
   18026             : /*
   18027             :  * dumpAttrDef --- dump an attribute's default-value declaration
   18028             :  */
   18029             : static void
   18030        2916 : dumpAttrDef(Archive *fout, const AttrDefInfo *adinfo)
   18031             : {
   18032        2916 :     DumpOptions *dopt = fout->dopt;
   18033        2916 :     TableInfo  *tbinfo = adinfo->adtable;
   18034        2916 :     int         adnum = adinfo->adnum;
   18035             :     PQExpBuffer q;
   18036             :     PQExpBuffer delq;
   18037             :     char       *qualrelname;
   18038             :     char       *tag;
   18039             :     char       *foreign;
   18040             : 
   18041             :     /* Do nothing if not dumping schema */
   18042        2916 :     if (!dopt->dumpSchema)
   18043           0 :         return;
   18044             : 
   18045             :     /* Skip if not "separate"; it was dumped in the table's definition */
   18046        2916 :     if (!adinfo->separate)
   18047        2476 :         return;
   18048             : 
   18049         440 :     q = createPQExpBuffer();
   18050         440 :     delq = createPQExpBuffer();
   18051             : 
   18052         440 :     qualrelname = pg_strdup(fmtQualifiedDumpable(tbinfo));
   18053             : 
   18054         440 :     foreign = tbinfo->relkind == RELKIND_FOREIGN_TABLE ? "FOREIGN " : "";
   18055             : 
   18056         440 :     appendPQExpBuffer(q,
   18057             :                       "ALTER %sTABLE ONLY %s ALTER COLUMN %s SET DEFAULT %s;\n",
   18058         440 :                       foreign, qualrelname, fmtId(tbinfo->attnames[adnum - 1]),
   18059         440 :                       adinfo->adef_expr);
   18060             : 
   18061         440 :     appendPQExpBuffer(delq, "ALTER %sTABLE %s ALTER COLUMN %s DROP DEFAULT;\n",
   18062             :                       foreign, qualrelname,
   18063         440 :                       fmtId(tbinfo->attnames[adnum - 1]));
   18064             : 
   18065         440 :     tag = psprintf("%s %s", tbinfo->dobj.name, tbinfo->attnames[adnum - 1]);
   18066             : 
   18067         440 :     if (adinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   18068         440 :         ArchiveEntry(fout, adinfo->dobj.catId, adinfo->dobj.dumpId,
   18069         440 :                      ARCHIVE_OPTS(.tag = tag,
   18070             :                                   .namespace = tbinfo->dobj.namespace->dobj.name,
   18071             :                                   .owner = tbinfo->rolname,
   18072             :                                   .description = "DEFAULT",
   18073             :                                   .section = SECTION_PRE_DATA,
   18074             :                                   .createStmt = q->data,
   18075             :                                   .dropStmt = delq->data));
   18076             : 
   18077         440 :     free(tag);
   18078         440 :     destroyPQExpBuffer(q);
   18079         440 :     destroyPQExpBuffer(delq);
   18080         440 :     free(qualrelname);
   18081             : }
   18082             : 
   18083             : /*
   18084             :  * getAttrName: extract the correct name for an attribute
   18085             :  *
   18086             :  * The array tblInfo->attnames[] only provides names of user attributes;
   18087             :  * if a system attribute number is supplied, we have to fake it.
   18088             :  * We also do a little bit of bounds checking for safety's sake.
   18089             :  */
   18090             : static const char *
   18091        5220 : getAttrName(int attrnum, const TableInfo *tblInfo)
   18092             : {
   18093        5220 :     if (attrnum > 0 && attrnum <= tblInfo->numatts)
   18094        5220 :         return tblInfo->attnames[attrnum - 1];
   18095           0 :     switch (attrnum)
   18096             :     {
   18097           0 :         case SelfItemPointerAttributeNumber:
   18098           0 :             return "ctid";
   18099           0 :         case MinTransactionIdAttributeNumber:
   18100           0 :             return "xmin";
   18101           0 :         case MinCommandIdAttributeNumber:
   18102           0 :             return "cmin";
   18103           0 :         case MaxTransactionIdAttributeNumber:
   18104           0 :             return "xmax";
   18105           0 :         case MaxCommandIdAttributeNumber:
   18106           0 :             return "cmax";
   18107           0 :         case TableOidAttributeNumber:
   18108           0 :             return "tableoid";
   18109             :     }
   18110           0 :     pg_fatal("invalid column number %d for table \"%s\"",
   18111             :              attrnum, tblInfo->dobj.name);
   18112             :     return NULL;                /* keep compiler quiet */
   18113             : }
   18114             : 
   18115             : /*
   18116             :  * dumpIndex
   18117             :  *    write out to fout a user-defined index
   18118             :  */
   18119             : static void
   18120        6986 : dumpIndex(Archive *fout, const IndxInfo *indxinfo)
   18121             : {
   18122        6986 :     DumpOptions *dopt = fout->dopt;
   18123        6986 :     TableInfo  *tbinfo = indxinfo->indextable;
   18124        6986 :     bool        is_constraint = (indxinfo->indexconstraint != 0);
   18125             :     PQExpBuffer q;
   18126             :     PQExpBuffer delq;
   18127             :     char       *qindxname;
   18128             :     char       *qqindxname;
   18129             : 
   18130             :     /* Do nothing if not dumping schema */
   18131        6986 :     if (!dopt->dumpSchema)
   18132         234 :         return;
   18133             : 
   18134        6752 :     q = createPQExpBuffer();
   18135        6752 :     delq = createPQExpBuffer();
   18136             : 
   18137        6752 :     qindxname = pg_strdup(fmtId(indxinfo->dobj.name));
   18138        6752 :     qqindxname = pg_strdup(fmtQualifiedDumpable(indxinfo));
   18139             : 
   18140             :     /*
   18141             :      * If there's an associated constraint, don't dump the index per se, but
   18142             :      * do dump any comment for it.  (This is safe because dependency ordering
   18143             :      * will have ensured the constraint is emitted first.)  Note that the
   18144             :      * emitted comment has to be shown as depending on the constraint, not the
   18145             :      * index, in such cases.
   18146             :      */
   18147        6752 :     if (!is_constraint)
   18148             :     {
   18149        3014 :         char       *indstatcols = indxinfo->indstatcols;
   18150        3014 :         char       *indstatvals = indxinfo->indstatvals;
   18151        3014 :         char      **indstatcolsarray = NULL;
   18152        3014 :         char      **indstatvalsarray = NULL;
   18153        3014 :         int         nstatcols = 0;
   18154        3014 :         int         nstatvals = 0;
   18155             : 
   18156        3014 :         if (dopt->binary_upgrade)
   18157         312 :             binary_upgrade_set_pg_class_oids(fout, q,
   18158         312 :                                              indxinfo->dobj.catId.oid);
   18159             : 
   18160             :         /* Plain secondary index */
   18161        3014 :         appendPQExpBuffer(q, "%s;\n", indxinfo->indexdef);
   18162             : 
   18163             :         /*
   18164             :          * Append ALTER TABLE commands as needed to set properties that we
   18165             :          * only have ALTER TABLE syntax for.  Keep this in sync with the
   18166             :          * similar code in dumpConstraint!
   18167             :          */
   18168             : 
   18169             :         /* If the index is clustered, we need to record that. */
   18170        3014 :         if (indxinfo->indisclustered)
   18171             :         {
   18172           0 :             appendPQExpBuffer(q, "\nALTER TABLE %s CLUSTER",
   18173           0 :                               fmtQualifiedDumpable(tbinfo));
   18174             :             /* index name is not qualified in this syntax */
   18175           0 :             appendPQExpBuffer(q, " ON %s;\n",
   18176             :                               qindxname);
   18177             :         }
   18178             : 
   18179             :         /*
   18180             :          * If the index has any statistics on some of its columns, generate
   18181             :          * the associated ALTER INDEX queries.
   18182             :          */
   18183        3014 :         if (strlen(indstatcols) != 0 || strlen(indstatvals) != 0)
   18184             :         {
   18185             :             int         j;
   18186             : 
   18187          72 :             if (!parsePGArray(indstatcols, &indstatcolsarray, &nstatcols))
   18188           0 :                 pg_fatal("could not parse index statistic columns");
   18189          72 :             if (!parsePGArray(indstatvals, &indstatvalsarray, &nstatvals))
   18190           0 :                 pg_fatal("could not parse index statistic values");
   18191          72 :             if (nstatcols != nstatvals)
   18192           0 :                 pg_fatal("mismatched number of columns and values for index statistics");
   18193             : 
   18194         216 :             for (j = 0; j < nstatcols; j++)
   18195             :             {
   18196         144 :                 appendPQExpBuffer(q, "ALTER INDEX %s ", qqindxname);
   18197             : 
   18198             :                 /*
   18199             :                  * Note that this is a column number, so no quotes should be
   18200             :                  * used.
   18201             :                  */
   18202         144 :                 appendPQExpBuffer(q, "ALTER COLUMN %s ",
   18203         144 :                                   indstatcolsarray[j]);
   18204         144 :                 appendPQExpBuffer(q, "SET STATISTICS %s;\n",
   18205         144 :                                   indstatvalsarray[j]);
   18206             :             }
   18207             :         }
   18208             : 
   18209             :         /* Indexes can depend on extensions */
   18210        3014 :         append_depends_on_extension(fout, q, &indxinfo->dobj,
   18211             :                                     "pg_catalog.pg_class",
   18212             :                                     "INDEX", qqindxname);
   18213             : 
   18214             :         /* If the index defines identity, we need to record that. */
   18215        3014 :         if (indxinfo->indisreplident)
   18216             :         {
   18217           0 :             appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY USING",
   18218           0 :                               fmtQualifiedDumpable(tbinfo));
   18219             :             /* index name is not qualified in this syntax */
   18220           0 :             appendPQExpBuffer(q, " INDEX %s;\n",
   18221             :                               qindxname);
   18222             :         }
   18223             : 
   18224             :         /*
   18225             :          * If this index is a member of a partitioned index, the backend will
   18226             :          * not allow us to drop it separately, so don't try.  It will go away
   18227             :          * automatically when we drop either the index's table or the
   18228             :          * partitioned index.  (If, in a selective restore with --clean, we
   18229             :          * drop neither of those, then this index will not be dropped either.
   18230             :          * But that's fine, and even if you think it's not, the backend won't
   18231             :          * let us do differently.)
   18232             :          */
   18233        3014 :         if (indxinfo->parentidx == 0)
   18234        2558 :             appendPQExpBuffer(delq, "DROP INDEX %s;\n", qqindxname);
   18235             : 
   18236        3014 :         if (indxinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   18237        3014 :             ArchiveEntry(fout, indxinfo->dobj.catId, indxinfo->dobj.dumpId,
   18238        3014 :                          ARCHIVE_OPTS(.tag = indxinfo->dobj.name,
   18239             :                                       .namespace = tbinfo->dobj.namespace->dobj.name,
   18240             :                                       .tablespace = indxinfo->tablespace,
   18241             :                                       .owner = tbinfo->rolname,
   18242             :                                       .description = "INDEX",
   18243             :                                       .section = SECTION_POST_DATA,
   18244             :                                       .createStmt = q->data,
   18245             :                                       .dropStmt = delq->data));
   18246             : 
   18247        3014 :         free(indstatcolsarray);
   18248        3014 :         free(indstatvalsarray);
   18249             :     }
   18250             : 
   18251             :     /* Dump Index Comments */
   18252        6752 :     if (indxinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   18253          48 :         dumpComment(fout, "INDEX", qindxname,
   18254          48 :                     tbinfo->dobj.namespace->dobj.name,
   18255             :                     tbinfo->rolname,
   18256             :                     indxinfo->dobj.catId, 0,
   18257             :                     is_constraint ? indxinfo->indexconstraint :
   18258             :                     indxinfo->dobj.dumpId);
   18259             : 
   18260        6752 :     destroyPQExpBuffer(q);
   18261        6752 :     destroyPQExpBuffer(delq);
   18262        6752 :     free(qindxname);
   18263        6752 :     free(qqindxname);
   18264             : }
   18265             : 
   18266             : /*
   18267             :  * dumpIndexAttach
   18268             :  *    write out to fout a partitioned-index attachment clause
   18269             :  */
   18270             : static void
   18271        1480 : dumpIndexAttach(Archive *fout, const IndexAttachInfo *attachinfo)
   18272             : {
   18273             :     /* Do nothing if not dumping schema */
   18274        1480 :     if (!fout->dopt->dumpSchema)
   18275          96 :         return;
   18276             : 
   18277        1384 :     if (attachinfo->partitionIdx->dobj.dump & DUMP_COMPONENT_DEFINITION)
   18278             :     {
   18279        1384 :         PQExpBuffer q = createPQExpBuffer();
   18280             : 
   18281        1384 :         appendPQExpBuffer(q, "ALTER INDEX %s ",
   18282        1384 :                           fmtQualifiedDumpable(attachinfo->parentIdx));
   18283        1384 :         appendPQExpBuffer(q, "ATTACH PARTITION %s;\n",
   18284        1384 :                           fmtQualifiedDumpable(attachinfo->partitionIdx));
   18285             : 
   18286             :         /*
   18287             :          * There is no need for a dropStmt since the drop is done implicitly
   18288             :          * when we drop either the index's table or the partitioned index.
   18289             :          * Moreover, since there's no ALTER INDEX DETACH PARTITION command,
   18290             :          * there's no way to do it anyway.  (If you think to change this,
   18291             :          * consider also what to do with --if-exists.)
   18292             :          *
   18293             :          * Although this object doesn't really have ownership as such, set the
   18294             :          * owner field anyway to ensure that the command is run by the correct
   18295             :          * role at restore time.
   18296             :          */
   18297        1384 :         ArchiveEntry(fout, attachinfo->dobj.catId, attachinfo->dobj.dumpId,
   18298        1384 :                      ARCHIVE_OPTS(.tag = attachinfo->dobj.name,
   18299             :                                   .namespace = attachinfo->dobj.namespace->dobj.name,
   18300             :                                   .owner = attachinfo->parentIdx->indextable->rolname,
   18301             :                                   .description = "INDEX ATTACH",
   18302             :                                   .section = SECTION_POST_DATA,
   18303             :                                   .createStmt = q->data));
   18304             : 
   18305        1384 :         destroyPQExpBuffer(q);
   18306             :     }
   18307             : }
   18308             : 
   18309             : /*
   18310             :  * dumpStatisticsExt
   18311             :  *    write out to fout an extended statistics object
   18312             :  */
   18313             : static void
   18314         314 : dumpStatisticsExt(Archive *fout, const StatsExtInfo *statsextinfo)
   18315             : {
   18316         314 :     DumpOptions *dopt = fout->dopt;
   18317             :     PQExpBuffer q;
   18318             :     PQExpBuffer delq;
   18319             :     PQExpBuffer query;
   18320             :     char       *qstatsextname;
   18321             :     PGresult   *res;
   18322             :     char       *stxdef;
   18323             : 
   18324             :     /* Do nothing if not dumping schema */
   18325         314 :     if (!dopt->dumpSchema)
   18326          36 :         return;
   18327             : 
   18328         278 :     q = createPQExpBuffer();
   18329         278 :     delq = createPQExpBuffer();
   18330         278 :     query = createPQExpBuffer();
   18331             : 
   18332         278 :     qstatsextname = pg_strdup(fmtId(statsextinfo->dobj.name));
   18333             : 
   18334         278 :     appendPQExpBuffer(query, "SELECT "
   18335             :                       "pg_catalog.pg_get_statisticsobjdef('%u'::pg_catalog.oid)",
   18336         278 :                       statsextinfo->dobj.catId.oid);
   18337             : 
   18338         278 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   18339             : 
   18340         278 :     stxdef = PQgetvalue(res, 0, 0);
   18341             : 
   18342             :     /* Result of pg_get_statisticsobjdef is complete except for semicolon */
   18343         278 :     appendPQExpBuffer(q, "%s;\n", stxdef);
   18344             : 
   18345             :     /*
   18346             :      * We only issue an ALTER STATISTICS statement if the stxstattarget entry
   18347             :      * for this statistics object is not the default value.
   18348             :      */
   18349         278 :     if (statsextinfo->stattarget >= 0)
   18350             :     {
   18351          72 :         appendPQExpBuffer(q, "ALTER STATISTICS %s ",
   18352          72 :                           fmtQualifiedDumpable(statsextinfo));
   18353          72 :         appendPQExpBuffer(q, "SET STATISTICS %d;\n",
   18354          72 :                           statsextinfo->stattarget);
   18355             :     }
   18356             : 
   18357         278 :     appendPQExpBuffer(delq, "DROP STATISTICS %s;\n",
   18358         278 :                       fmtQualifiedDumpable(statsextinfo));
   18359             : 
   18360         278 :     if (statsextinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   18361         278 :         ArchiveEntry(fout, statsextinfo->dobj.catId,
   18362         278 :                      statsextinfo->dobj.dumpId,
   18363         278 :                      ARCHIVE_OPTS(.tag = statsextinfo->dobj.name,
   18364             :                                   .namespace = statsextinfo->dobj.namespace->dobj.name,
   18365             :                                   .owner = statsextinfo->rolname,
   18366             :                                   .description = "STATISTICS",
   18367             :                                   .section = SECTION_POST_DATA,
   18368             :                                   .createStmt = q->data,
   18369             :                                   .dropStmt = delq->data));
   18370             : 
   18371             :     /* Dump Statistics Comments */
   18372         278 :     if (statsextinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   18373           0 :         dumpComment(fout, "STATISTICS", qstatsextname,
   18374           0 :                     statsextinfo->dobj.namespace->dobj.name,
   18375           0 :                     statsextinfo->rolname,
   18376             :                     statsextinfo->dobj.catId, 0,
   18377           0 :                     statsextinfo->dobj.dumpId);
   18378             : 
   18379         278 :     PQclear(res);
   18380         278 :     destroyPQExpBuffer(q);
   18381         278 :     destroyPQExpBuffer(delq);
   18382         278 :     destroyPQExpBuffer(query);
   18383         278 :     free(qstatsextname);
   18384             : }
   18385             : 
   18386             : /*
   18387             :  * dumpConstraint
   18388             :  *    write out to fout a user-defined constraint
   18389             :  */
   18390             : static void
   18391        6550 : dumpConstraint(Archive *fout, const ConstraintInfo *coninfo)
   18392             : {
   18393        6550 :     DumpOptions *dopt = fout->dopt;
   18394        6550 :     TableInfo  *tbinfo = coninfo->contable;
   18395             :     PQExpBuffer q;
   18396             :     PQExpBuffer delq;
   18397        6550 :     char       *tag = NULL;
   18398             :     char       *foreign;
   18399             : 
   18400             :     /* Do nothing if not dumping schema */
   18401        6550 :     if (!dopt->dumpSchema)
   18402         196 :         return;
   18403             : 
   18404        6354 :     q = createPQExpBuffer();
   18405        6354 :     delq = createPQExpBuffer();
   18406             : 
   18407       12276 :     foreign = tbinfo &&
   18408        6354 :         tbinfo->relkind == RELKIND_FOREIGN_TABLE ? "FOREIGN " : "";
   18409             : 
   18410        6354 :     if (coninfo->contype == 'p' ||
   18411        3156 :         coninfo->contype == 'u' ||
   18412        2648 :         coninfo->contype == 'x')
   18413        3738 :     {
   18414             :         /* Index-related constraint */
   18415             :         IndxInfo   *indxinfo;
   18416             :         int         k;
   18417             : 
   18418        3738 :         indxinfo = (IndxInfo *) findObjectByDumpId(coninfo->conindex);
   18419             : 
   18420        3738 :         if (indxinfo == NULL)
   18421           0 :             pg_fatal("missing index for constraint \"%s\"",
   18422             :                      coninfo->dobj.name);
   18423             : 
   18424        3738 :         if (dopt->binary_upgrade)
   18425         292 :             binary_upgrade_set_pg_class_oids(fout, q,
   18426             :                                              indxinfo->dobj.catId.oid);
   18427             : 
   18428        3738 :         appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s\n", foreign,
   18429        3738 :                           fmtQualifiedDumpable(tbinfo));
   18430        3738 :         appendPQExpBuffer(q, "    ADD CONSTRAINT %s ",
   18431        3738 :                           fmtId(coninfo->dobj.name));
   18432             : 
   18433        3738 :         if (coninfo->condef)
   18434             :         {
   18435             :             /* pg_get_constraintdef should have provided everything */
   18436          32 :             appendPQExpBuffer(q, "%s;\n", coninfo->condef);
   18437             :         }
   18438             :         else
   18439             :         {
   18440        3706 :             appendPQExpBufferStr(q,
   18441        3706 :                                  coninfo->contype == 'p' ? "PRIMARY KEY" : "UNIQUE");
   18442             : 
   18443             :             /*
   18444             :              * PRIMARY KEY constraints should not be using NULLS NOT DISTINCT
   18445             :              * indexes. Being able to create this was fixed, but we need to
   18446             :              * make the index distinct in order to be able to restore the
   18447             :              * dump.
   18448             :              */
   18449        3706 :             if (indxinfo->indnullsnotdistinct && coninfo->contype != 'p')
   18450           0 :                 appendPQExpBufferStr(q, " NULLS NOT DISTINCT");
   18451        3706 :             appendPQExpBufferStr(q, " (");
   18452        8798 :             for (k = 0; k < indxinfo->indnkeyattrs; k++)
   18453             :             {
   18454        5092 :                 int         indkey = (int) indxinfo->indkeys[k];
   18455             :                 const char *attname;
   18456             : 
   18457        5092 :                 if (indkey == InvalidAttrNumber)
   18458           0 :                     break;
   18459        5092 :                 attname = getAttrName(indkey, tbinfo);
   18460             : 
   18461        5092 :                 appendPQExpBuffer(q, "%s%s",
   18462             :                                   (k == 0) ? "" : ", ",
   18463             :                                   fmtId(attname));
   18464             :             }
   18465        3706 :             if (coninfo->conperiod)
   18466         272 :                 appendPQExpBufferStr(q, " WITHOUT OVERLAPS");
   18467             : 
   18468        3706 :             if (indxinfo->indnkeyattrs < indxinfo->indnattrs)
   18469          64 :                 appendPQExpBufferStr(q, ") INCLUDE (");
   18470             : 
   18471        3834 :             for (k = indxinfo->indnkeyattrs; k < indxinfo->indnattrs; k++)
   18472             :             {
   18473         128 :                 int         indkey = (int) indxinfo->indkeys[k];
   18474             :                 const char *attname;
   18475             : 
   18476         128 :                 if (indkey == InvalidAttrNumber)
   18477           0 :                     break;
   18478         128 :                 attname = getAttrName(indkey, tbinfo);
   18479             : 
   18480         256 :                 appendPQExpBuffer(q, "%s%s",
   18481         128 :                                   (k == indxinfo->indnkeyattrs) ? "" : ", ",
   18482             :                                   fmtId(attname));
   18483             :             }
   18484             : 
   18485        3706 :             appendPQExpBufferChar(q, ')');
   18486             : 
   18487        3706 :             if (nonemptyReloptions(indxinfo->indreloptions))
   18488             :             {
   18489           0 :                 appendPQExpBufferStr(q, " WITH (");
   18490           0 :                 appendReloptionsArrayAH(q, indxinfo->indreloptions, "", fout);
   18491           0 :                 appendPQExpBufferChar(q, ')');
   18492             :             }
   18493             : 
   18494        3706 :             if (coninfo->condeferrable)
   18495             :             {
   18496          80 :                 appendPQExpBufferStr(q, " DEFERRABLE");
   18497          80 :                 if (coninfo->condeferred)
   18498          48 :                     appendPQExpBufferStr(q, " INITIALLY DEFERRED");
   18499             :             }
   18500             : 
   18501        3706 :             appendPQExpBufferStr(q, ";\n");
   18502             :         }
   18503             : 
   18504             :         /*
   18505             :          * Append ALTER TABLE commands as needed to set properties that we
   18506             :          * only have ALTER TABLE syntax for.  Keep this in sync with the
   18507             :          * similar code in dumpIndex!
   18508             :          */
   18509             : 
   18510             :         /* If the index is clustered, we need to record that. */
   18511        3738 :         if (indxinfo->indisclustered)
   18512             :         {
   18513          72 :             appendPQExpBuffer(q, "\nALTER TABLE %s CLUSTER",
   18514          72 :                               fmtQualifiedDumpable(tbinfo));
   18515             :             /* index name is not qualified in this syntax */
   18516          72 :             appendPQExpBuffer(q, " ON %s;\n",
   18517          72 :                               fmtId(indxinfo->dobj.name));
   18518             :         }
   18519             : 
   18520             :         /* If the index defines identity, we need to record that. */
   18521        3738 :         if (indxinfo->indisreplident)
   18522             :         {
   18523           0 :             appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY USING",
   18524           0 :                               fmtQualifiedDumpable(tbinfo));
   18525             :             /* index name is not qualified in this syntax */
   18526           0 :             appendPQExpBuffer(q, " INDEX %s;\n",
   18527           0 :                               fmtId(indxinfo->dobj.name));
   18528             :         }
   18529             : 
   18530             :         /* Indexes can depend on extensions */
   18531        3738 :         append_depends_on_extension(fout, q, &indxinfo->dobj,
   18532             :                                     "pg_catalog.pg_class", "INDEX",
   18533        3738 :                                     fmtQualifiedDumpable(indxinfo));
   18534             : 
   18535        3738 :         appendPQExpBuffer(delq, "ALTER %sTABLE ONLY %s ", foreign,
   18536        3738 :                           fmtQualifiedDumpable(tbinfo));
   18537        3738 :         appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
   18538        3738 :                           fmtId(coninfo->dobj.name));
   18539             : 
   18540        3738 :         tag = psprintf("%s %s", tbinfo->dobj.name, coninfo->dobj.name);
   18541             : 
   18542        3738 :         if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   18543        3738 :             ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
   18544        3738 :                          ARCHIVE_OPTS(.tag = tag,
   18545             :                                       .namespace = tbinfo->dobj.namespace->dobj.name,
   18546             :                                       .tablespace = indxinfo->tablespace,
   18547             :                                       .owner = tbinfo->rolname,
   18548             :                                       .description = "CONSTRAINT",
   18549             :                                       .section = SECTION_POST_DATA,
   18550             :                                       .createStmt = q->data,
   18551             :                                       .dropStmt = delq->data));
   18552             :     }
   18553        2616 :     else if (coninfo->contype == 'f')
   18554             :     {
   18555             :         char       *only;
   18556             : 
   18557             :         /*
   18558             :          * Foreign keys on partitioned tables are always declared as
   18559             :          * inheriting to partitions; for all other cases, emit them as
   18560             :          * applying ONLY directly to the named table, because that's how they
   18561             :          * work for regular inherited tables.
   18562             :          */
   18563         448 :         only = tbinfo->relkind == RELKIND_PARTITIONED_TABLE ? "" : "ONLY ";
   18564             : 
   18565             :         /*
   18566             :          * XXX Potentially wrap in a 'SET CONSTRAINTS OFF' block so that the
   18567             :          * current table data is not processed
   18568             :          */
   18569         448 :         appendPQExpBuffer(q, "ALTER %sTABLE %s%s\n", foreign,
   18570         448 :                           only, fmtQualifiedDumpable(tbinfo));
   18571         448 :         appendPQExpBuffer(q, "    ADD CONSTRAINT %s %s;\n",
   18572         448 :                           fmtId(coninfo->dobj.name),
   18573         448 :                           coninfo->condef);
   18574             : 
   18575         448 :         appendPQExpBuffer(delq, "ALTER %sTABLE %s%s ", foreign,
   18576         448 :                           only, fmtQualifiedDumpable(tbinfo));
   18577         448 :         appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
   18578         448 :                           fmtId(coninfo->dobj.name));
   18579             : 
   18580         448 :         tag = psprintf("%s %s", tbinfo->dobj.name, coninfo->dobj.name);
   18581             : 
   18582         448 :         if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   18583         448 :             ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
   18584         448 :                          ARCHIVE_OPTS(.tag = tag,
   18585             :                                       .namespace = tbinfo->dobj.namespace->dobj.name,
   18586             :                                       .owner = tbinfo->rolname,
   18587             :                                       .description = "FK CONSTRAINT",
   18588             :                                       .section = SECTION_POST_DATA,
   18589             :                                       .createStmt = q->data,
   18590             :                                       .dropStmt = delq->data));
   18591             :     }
   18592        2168 :     else if ((coninfo->contype == 'c' || coninfo->contype == 'n') && tbinfo)
   18593             :     {
   18594             :         /* CHECK or invalid not-null constraint on a table */
   18595             : 
   18596             :         /* Ignore if not to be dumped separately, or if it was inherited */
   18597        1736 :         if (coninfo->separate && coninfo->conislocal)
   18598             :         {
   18599             :             const char *keyword;
   18600             : 
   18601         312 :             if (coninfo->contype == 'c')
   18602         144 :                 keyword = "CHECK CONSTRAINT";
   18603             :             else
   18604         168 :                 keyword = "CONSTRAINT";
   18605             : 
   18606             :             /* not ONLY since we want it to propagate to children */
   18607         312 :             appendPQExpBuffer(q, "ALTER %sTABLE %s\n", foreign,
   18608         312 :                               fmtQualifiedDumpable(tbinfo));
   18609         312 :             appendPQExpBuffer(q, "    ADD CONSTRAINT %s %s;\n",
   18610         312 :                               fmtId(coninfo->dobj.name),
   18611         312 :                               coninfo->condef);
   18612             : 
   18613         312 :             appendPQExpBuffer(delq, "ALTER %sTABLE %s ", foreign,
   18614         312 :                               fmtQualifiedDumpable(tbinfo));
   18615         312 :             appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
   18616         312 :                               fmtId(coninfo->dobj.name));
   18617             : 
   18618         312 :             tag = psprintf("%s %s", tbinfo->dobj.name, coninfo->dobj.name);
   18619             : 
   18620         312 :             if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   18621         312 :                 ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
   18622         312 :                              ARCHIVE_OPTS(.tag = tag,
   18623             :                                           .namespace = tbinfo->dobj.namespace->dobj.name,
   18624             :                                           .owner = tbinfo->rolname,
   18625             :                                           .description = keyword,
   18626             :                                           .section = SECTION_POST_DATA,
   18627             :                                           .createStmt = q->data,
   18628             :                                           .dropStmt = delq->data));
   18629             :         }
   18630             :     }
   18631         432 :     else if (tbinfo == NULL)
   18632             :     {
   18633             :         /* CHECK, NOT NULL constraint on a domain */
   18634         432 :         TypeInfo   *tyinfo = coninfo->condomain;
   18635             : 
   18636             :         Assert(coninfo->contype == 'c' || coninfo->contype == 'n');
   18637             : 
   18638             :         /* Ignore if not to be dumped separately */
   18639         432 :         if (coninfo->separate)
   18640             :         {
   18641             :             const char *keyword;
   18642             : 
   18643          16 :             if (coninfo->contype == 'c')
   18644          16 :                 keyword = "CHECK CONSTRAINT";
   18645             :             else
   18646           0 :                 keyword = "CONSTRAINT";
   18647             : 
   18648          16 :             appendPQExpBuffer(q, "ALTER DOMAIN %s\n",
   18649          16 :                               fmtQualifiedDumpable(tyinfo));
   18650          16 :             appendPQExpBuffer(q, "    ADD CONSTRAINT %s %s;\n",
   18651          16 :                               fmtId(coninfo->dobj.name),
   18652          16 :                               coninfo->condef);
   18653             : 
   18654          16 :             appendPQExpBuffer(delq, "ALTER DOMAIN %s ",
   18655          16 :                               fmtQualifiedDumpable(tyinfo));
   18656          16 :             appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
   18657          16 :                               fmtId(coninfo->dobj.name));
   18658             : 
   18659          16 :             tag = psprintf("%s %s", tyinfo->dobj.name, coninfo->dobj.name);
   18660             : 
   18661          16 :             if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   18662          16 :                 ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
   18663          16 :                              ARCHIVE_OPTS(.tag = tag,
   18664             :                                           .namespace = tyinfo->dobj.namespace->dobj.name,
   18665             :                                           .owner = tyinfo->rolname,
   18666             :                                           .description = keyword,
   18667             :                                           .section = SECTION_POST_DATA,
   18668             :                                           .createStmt = q->data,
   18669             :                                           .dropStmt = delq->data));
   18670             : 
   18671          16 :             if (coninfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   18672             :             {
   18673          16 :                 PQExpBuffer conprefix = createPQExpBuffer();
   18674          16 :                 char       *qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
   18675             : 
   18676          16 :                 appendPQExpBuffer(conprefix, "CONSTRAINT %s ON DOMAIN",
   18677          16 :                                   fmtId(coninfo->dobj.name));
   18678             : 
   18679          16 :                 dumpComment(fout, conprefix->data, qtypname,
   18680          16 :                             tyinfo->dobj.namespace->dobj.name,
   18681             :                             tyinfo->rolname,
   18682             :                             coninfo->dobj.catId, 0, tyinfo->dobj.dumpId);
   18683          16 :                 destroyPQExpBuffer(conprefix);
   18684          16 :                 free(qtypname);
   18685             :             }
   18686             :         }
   18687             :     }
   18688             :     else
   18689             :     {
   18690           0 :         pg_fatal("unrecognized constraint type: %c",
   18691             :                  coninfo->contype);
   18692             :     }
   18693             : 
   18694             :     /* Dump Constraint Comments --- only works for table constraints */
   18695        6354 :     if (tbinfo && coninfo->separate &&
   18696        4594 :         coninfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   18697         120 :         dumpTableConstraintComment(fout, coninfo);
   18698             : 
   18699        6354 :     free(tag);
   18700        6354 :     destroyPQExpBuffer(q);
   18701        6354 :     destroyPQExpBuffer(delq);
   18702             : }
   18703             : 
   18704             : /*
   18705             :  * dumpTableConstraintComment --- dump a constraint's comment if any
   18706             :  *
   18707             :  * This is split out because we need the function in two different places
   18708             :  * depending on whether the constraint is dumped as part of CREATE TABLE
   18709             :  * or as a separate ALTER command.
   18710             :  */
   18711             : static void
   18712         208 : dumpTableConstraintComment(Archive *fout, const ConstraintInfo *coninfo)
   18713             : {
   18714         208 :     TableInfo  *tbinfo = coninfo->contable;
   18715         208 :     PQExpBuffer conprefix = createPQExpBuffer();
   18716             :     char       *qtabname;
   18717             : 
   18718         208 :     qtabname = pg_strdup(fmtId(tbinfo->dobj.name));
   18719             : 
   18720         208 :     appendPQExpBuffer(conprefix, "CONSTRAINT %s ON",
   18721         208 :                       fmtId(coninfo->dobj.name));
   18722             : 
   18723         208 :     if (coninfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   18724         208 :         dumpComment(fout, conprefix->data, qtabname,
   18725         208 :                     tbinfo->dobj.namespace->dobj.name,
   18726             :                     tbinfo->rolname,
   18727             :                     coninfo->dobj.catId, 0,
   18728         208 :                     coninfo->separate ? coninfo->dobj.dumpId : tbinfo->dobj.dumpId);
   18729             : 
   18730         208 :     destroyPQExpBuffer(conprefix);
   18731         208 :     free(qtabname);
   18732         208 : }
   18733             : 
   18734             : static inline SeqType
   18735        1632 : parse_sequence_type(const char *name)
   18736             : {
   18737        3612 :     for (int i = 0; i < lengthof(SeqTypeNames); i++)
   18738             :     {
   18739        3612 :         if (strcmp(SeqTypeNames[i], name) == 0)
   18740        1632 :             return (SeqType) i;
   18741             :     }
   18742             : 
   18743           0 :     pg_fatal("unrecognized sequence type: %s", name);
   18744             :     return (SeqType) 0;         /* keep compiler quiet */
   18745             : }
   18746             : 
   18747             : /*
   18748             :  * bsearch() comparator for SequenceItem
   18749             :  */
   18750             : static int
   18751        9144 : SequenceItemCmp(const void *p1, const void *p2)
   18752             : {
   18753        9144 :     SequenceItem v1 = *((const SequenceItem *) p1);
   18754        9144 :     SequenceItem v2 = *((const SequenceItem *) p2);
   18755             : 
   18756        9144 :     return pg_cmp_u32(v1.oid, v2.oid);
   18757             : }
   18758             : 
   18759             : /*
   18760             :  * collectSequences
   18761             :  *
   18762             :  * Construct a table of sequence information.  This table is sorted by OID for
   18763             :  * speed in lookup.
   18764             :  */
   18765             : static void
   18766         468 : collectSequences(Archive *fout)
   18767             : {
   18768             :     PGresult   *res;
   18769             :     const char *query;
   18770             : 
   18771             :     /*
   18772             :      * Before Postgres 10, sequence metadata is in the sequence itself.  With
   18773             :      * some extra effort, we might be able to use the sorted table for those
   18774             :      * versions, but for now it seems unlikely to be worth it.
   18775             :      *
   18776             :      * Since version 18, we can gather the sequence data in this query with
   18777             :      * pg_get_sequence_data(), but we only do so for non-schema-only dumps.
   18778             :      */
   18779         468 :     if (fout->remoteVersion < 100000)
   18780           0 :         return;
   18781         468 :     else if (fout->remoteVersion < 180000 ||
   18782         468 :              (!fout->dopt->dumpData && !fout->dopt->sequence_data))
   18783          16 :         query = "SELECT seqrelid, format_type(seqtypid, NULL), "
   18784             :             "seqstart, seqincrement, "
   18785             :             "seqmax, seqmin, "
   18786             :             "seqcache, seqcycle, "
   18787             :             "NULL, 'f' "
   18788             :             "FROM pg_catalog.pg_sequence "
   18789             :             "ORDER BY seqrelid";
   18790             :     else
   18791         452 :         query = "SELECT seqrelid, format_type(seqtypid, NULL), "
   18792             :             "seqstart, seqincrement, "
   18793             :             "seqmax, seqmin, "
   18794             :             "seqcache, seqcycle, "
   18795             :             "last_value, is_called "
   18796             :             "FROM pg_catalog.pg_sequence, "
   18797             :             "pg_get_sequence_data(seqrelid) "
   18798             :             "ORDER BY seqrelid;";
   18799             : 
   18800         468 :     res = ExecuteSqlQuery(fout, query, PGRES_TUPLES_OK);
   18801             : 
   18802         468 :     nsequences = PQntuples(res);
   18803         468 :     sequences = (SequenceItem *) pg_malloc(nsequences * sizeof(SequenceItem));
   18804             : 
   18805        2100 :     for (int i = 0; i < nsequences; i++)
   18806             :     {
   18807        1632 :         sequences[i].oid = atooid(PQgetvalue(res, i, 0));
   18808        1632 :         sequences[i].seqtype = parse_sequence_type(PQgetvalue(res, i, 1));
   18809        1632 :         sequences[i].startv = strtoi64(PQgetvalue(res, i, 2), NULL, 10);
   18810        1632 :         sequences[i].incby = strtoi64(PQgetvalue(res, i, 3), NULL, 10);
   18811        1632 :         sequences[i].maxv = strtoi64(PQgetvalue(res, i, 4), NULL, 10);
   18812        1632 :         sequences[i].minv = strtoi64(PQgetvalue(res, i, 5), NULL, 10);
   18813        1632 :         sequences[i].cache = strtoi64(PQgetvalue(res, i, 6), NULL, 10);
   18814        1632 :         sequences[i].cycled = (strcmp(PQgetvalue(res, i, 7), "t") == 0);
   18815        1632 :         sequences[i].last_value = strtoi64(PQgetvalue(res, i, 8), NULL, 10);
   18816        1632 :         sequences[i].is_called = (strcmp(PQgetvalue(res, i, 9), "t") == 0);
   18817             :     }
   18818             : 
   18819         468 :     PQclear(res);
   18820             : }
   18821             : 
   18822             : /*
   18823             :  * dumpSequence
   18824             :  *    write the declaration (not data) of one user-defined sequence
   18825             :  */
   18826             : static void
   18827        1106 : dumpSequence(Archive *fout, const TableInfo *tbinfo)
   18828             : {
   18829        1106 :     DumpOptions *dopt = fout->dopt;
   18830             :     SequenceItem *seq;
   18831             :     bool        is_ascending;
   18832             :     int64       default_minv,
   18833             :                 default_maxv;
   18834        1106 :     PQExpBuffer query = createPQExpBuffer();
   18835        1106 :     PQExpBuffer delqry = createPQExpBuffer();
   18836             :     char       *qseqname;
   18837        1106 :     TableInfo  *owning_tab = NULL;
   18838             : 
   18839        1106 :     qseqname = pg_strdup(fmtId(tbinfo->dobj.name));
   18840             : 
   18841             :     /*
   18842             :      * For versions >= 10, the sequence information is gathered in a sorted
   18843             :      * table before any calls to dumpSequence().  See collectSequences() for
   18844             :      * more information.
   18845             :      */
   18846        1106 :     if (fout->remoteVersion >= 100000)
   18847             :     {
   18848        1106 :         SequenceItem key = {0};
   18849             : 
   18850             :         Assert(sequences);
   18851             : 
   18852        1106 :         key.oid = tbinfo->dobj.catId.oid;
   18853        1106 :         seq = bsearch(&key, sequences, nsequences,
   18854             :                       sizeof(SequenceItem), SequenceItemCmp);
   18855             :     }
   18856             :     else
   18857             :     {
   18858             :         PGresult   *res;
   18859             : 
   18860             :         /*
   18861             :          * Before PostgreSQL 10, sequence metadata is in the sequence itself.
   18862             :          *
   18863             :          * Note: it might seem that 'bigint' potentially needs to be
   18864             :          * schema-qualified, but actually that's a keyword.
   18865             :          */
   18866           0 :         appendPQExpBuffer(query,
   18867             :                           "SELECT 'bigint' AS sequence_type, "
   18868             :                           "start_value, increment_by, max_value, min_value, "
   18869             :                           "cache_value, is_cycled FROM %s",
   18870           0 :                           fmtQualifiedDumpable(tbinfo));
   18871             : 
   18872           0 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   18873             : 
   18874           0 :         if (PQntuples(res) != 1)
   18875           0 :             pg_fatal(ngettext("query to get data of sequence \"%s\" returned %d row (expected 1)",
   18876             :                               "query to get data of sequence \"%s\" returned %d rows (expected 1)",
   18877             :                               PQntuples(res)),
   18878             :                      tbinfo->dobj.name, PQntuples(res));
   18879             : 
   18880           0 :         seq = pg_malloc0(sizeof(SequenceItem));
   18881           0 :         seq->seqtype = parse_sequence_type(PQgetvalue(res, 0, 0));
   18882           0 :         seq->startv = strtoi64(PQgetvalue(res, 0, 1), NULL, 10);
   18883           0 :         seq->incby = strtoi64(PQgetvalue(res, 0, 2), NULL, 10);
   18884           0 :         seq->maxv = strtoi64(PQgetvalue(res, 0, 3), NULL, 10);
   18885           0 :         seq->minv = strtoi64(PQgetvalue(res, 0, 4), NULL, 10);
   18886           0 :         seq->cache = strtoi64(PQgetvalue(res, 0, 5), NULL, 10);
   18887           0 :         seq->cycled = (strcmp(PQgetvalue(res, 0, 6), "t") == 0);
   18888             : 
   18889           0 :         PQclear(res);
   18890             :     }
   18891             : 
   18892             :     /* Calculate default limits for a sequence of this type */
   18893        1106 :     is_ascending = (seq->incby >= 0);
   18894        1106 :     if (seq->seqtype == SEQTYPE_SMALLINT)
   18895             :     {
   18896          80 :         default_minv = is_ascending ? 1 : PG_INT16_MIN;
   18897          80 :         default_maxv = is_ascending ? PG_INT16_MAX : -1;
   18898             :     }
   18899        1026 :     else if (seq->seqtype == SEQTYPE_INTEGER)
   18900             :     {
   18901         814 :         default_minv = is_ascending ? 1 : PG_INT32_MIN;
   18902         814 :         default_maxv = is_ascending ? PG_INT32_MAX : -1;
   18903             :     }
   18904         212 :     else if (seq->seqtype == SEQTYPE_BIGINT)
   18905             :     {
   18906         212 :         default_minv = is_ascending ? 1 : PG_INT64_MIN;
   18907         212 :         default_maxv = is_ascending ? PG_INT64_MAX : -1;
   18908             :     }
   18909             :     else
   18910             :     {
   18911           0 :         pg_fatal("unrecognized sequence type: %d", seq->seqtype);
   18912             :         default_minv = default_maxv = 0;    /* keep compiler quiet */
   18913             :     }
   18914             : 
   18915             :     /*
   18916             :      * Identity sequences are not to be dropped separately.
   18917             :      */
   18918        1106 :     if (!tbinfo->is_identity_sequence)
   18919             :     {
   18920         682 :         appendPQExpBuffer(delqry, "DROP SEQUENCE %s;\n",
   18921         682 :                           fmtQualifiedDumpable(tbinfo));
   18922             :     }
   18923             : 
   18924        1106 :     resetPQExpBuffer(query);
   18925             : 
   18926        1106 :     if (dopt->binary_upgrade)
   18927             :     {
   18928         132 :         binary_upgrade_set_pg_class_oids(fout, query,
   18929         132 :                                          tbinfo->dobj.catId.oid);
   18930             : 
   18931             :         /*
   18932             :          * In older PG versions a sequence will have a pg_type entry, but v14
   18933             :          * and up don't use that, so don't attempt to preserve the type OID.
   18934             :          */
   18935             :     }
   18936             : 
   18937        1106 :     if (tbinfo->is_identity_sequence)
   18938             :     {
   18939         424 :         owning_tab = findTableByOid(tbinfo->owning_tab);
   18940             : 
   18941         424 :         appendPQExpBuffer(query,
   18942             :                           "ALTER TABLE %s ",
   18943         424 :                           fmtQualifiedDumpable(owning_tab));
   18944         424 :         appendPQExpBuffer(query,
   18945             :                           "ALTER COLUMN %s ADD GENERATED ",
   18946         424 :                           fmtId(owning_tab->attnames[tbinfo->owning_col - 1]));
   18947         424 :         if (owning_tab->attidentity[tbinfo->owning_col - 1] == ATTRIBUTE_IDENTITY_ALWAYS)
   18948         296 :             appendPQExpBufferStr(query, "ALWAYS");
   18949         128 :         else if (owning_tab->attidentity[tbinfo->owning_col - 1] == ATTRIBUTE_IDENTITY_BY_DEFAULT)
   18950         128 :             appendPQExpBufferStr(query, "BY DEFAULT");
   18951         424 :         appendPQExpBuffer(query, " AS IDENTITY (\n    SEQUENCE NAME %s\n",
   18952         424 :                           fmtQualifiedDumpable(tbinfo));
   18953             : 
   18954             :         /*
   18955             :          * Emit persistence option only if it's different from the owning
   18956             :          * table's.  This avoids using this new syntax unnecessarily.
   18957             :          */
   18958         424 :         if (tbinfo->relpersistence != owning_tab->relpersistence)
   18959          32 :             appendPQExpBuffer(query, "    %s\n",
   18960          32 :                               tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED ?
   18961             :                               "UNLOGGED" : "LOGGED");
   18962             :     }
   18963             :     else
   18964             :     {
   18965         682 :         appendPQExpBuffer(query,
   18966             :                           "CREATE %sSEQUENCE %s\n",
   18967         682 :                           tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED ?
   18968             :                           "UNLOGGED " : "",
   18969         682 :                           fmtQualifiedDumpable(tbinfo));
   18970             : 
   18971         682 :         if (seq->seqtype != SEQTYPE_BIGINT)
   18972         518 :             appendPQExpBuffer(query, "    AS %s\n", SeqTypeNames[seq->seqtype]);
   18973             :     }
   18974             : 
   18975        1106 :     appendPQExpBuffer(query, "    START WITH " INT64_FORMAT "\n", seq->startv);
   18976             : 
   18977        1106 :     appendPQExpBuffer(query, "    INCREMENT BY " INT64_FORMAT "\n", seq->incby);
   18978             : 
   18979        1106 :     if (seq->minv != default_minv)
   18980          48 :         appendPQExpBuffer(query, "    MINVALUE " INT64_FORMAT "\n", seq->minv);
   18981             :     else
   18982        1058 :         appendPQExpBufferStr(query, "    NO MINVALUE\n");
   18983             : 
   18984        1106 :     if (seq->maxv != default_maxv)
   18985          48 :         appendPQExpBuffer(query, "    MAXVALUE " INT64_FORMAT "\n", seq->maxv);
   18986             :     else
   18987        1058 :         appendPQExpBufferStr(query, "    NO MAXVALUE\n");
   18988             : 
   18989        1106 :     appendPQExpBuffer(query,
   18990             :                       "    CACHE " INT64_FORMAT "%s",
   18991        1106 :                       seq->cache, (seq->cycled ? "\n    CYCLE" : ""));
   18992             : 
   18993        1106 :     if (tbinfo->is_identity_sequence)
   18994         424 :         appendPQExpBufferStr(query, "\n);\n");
   18995             :     else
   18996         682 :         appendPQExpBufferStr(query, ";\n");
   18997             : 
   18998             :     /* binary_upgrade:  no need to clear TOAST table oid */
   18999             : 
   19000        1106 :     if (dopt->binary_upgrade)
   19001         132 :         binary_upgrade_extension_member(query, &tbinfo->dobj,
   19002             :                                         "SEQUENCE", qseqname,
   19003         132 :                                         tbinfo->dobj.namespace->dobj.name);
   19004             : 
   19005        1106 :     if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   19006        1106 :         ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
   19007        1106 :                      ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
   19008             :                                   .namespace = tbinfo->dobj.namespace->dobj.name,
   19009             :                                   .owner = tbinfo->rolname,
   19010             :                                   .description = "SEQUENCE",
   19011             :                                   .section = SECTION_PRE_DATA,
   19012             :                                   .createStmt = query->data,
   19013             :                                   .dropStmt = delqry->data));
   19014             : 
   19015             :     /*
   19016             :      * If the sequence is owned by a table column, emit the ALTER for it as a
   19017             :      * separate TOC entry immediately following the sequence's own entry. It's
   19018             :      * OK to do this rather than using full sorting logic, because the
   19019             :      * dependency that tells us it's owned will have forced the table to be
   19020             :      * created first.  We can't just include the ALTER in the TOC entry
   19021             :      * because it will fail if we haven't reassigned the sequence owner to
   19022             :      * match the table's owner.
   19023             :      *
   19024             :      * We need not schema-qualify the table reference because both sequence
   19025             :      * and table must be in the same schema.
   19026             :      */
   19027        1106 :     if (OidIsValid(tbinfo->owning_tab) && !tbinfo->is_identity_sequence)
   19028             :     {
   19029         374 :         owning_tab = findTableByOid(tbinfo->owning_tab);
   19030             : 
   19031         374 :         if (owning_tab == NULL)
   19032           0 :             pg_fatal("failed sanity check, parent table with OID %u of sequence with OID %u not found",
   19033             :                      tbinfo->owning_tab, tbinfo->dobj.catId.oid);
   19034             : 
   19035         374 :         if (owning_tab->dobj.dump & DUMP_COMPONENT_DEFINITION)
   19036             :         {
   19037         370 :             resetPQExpBuffer(query);
   19038         370 :             appendPQExpBuffer(query, "ALTER SEQUENCE %s",
   19039         370 :                               fmtQualifiedDumpable(tbinfo));
   19040         370 :             appendPQExpBuffer(query, " OWNED BY %s",
   19041         370 :                               fmtQualifiedDumpable(owning_tab));
   19042         370 :             appendPQExpBuffer(query, ".%s;\n",
   19043         370 :                               fmtId(owning_tab->attnames[tbinfo->owning_col - 1]));
   19044             : 
   19045         370 :             if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   19046         370 :                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
   19047         370 :                              ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
   19048             :                                           .namespace = tbinfo->dobj.namespace->dobj.name,
   19049             :                                           .owner = tbinfo->rolname,
   19050             :                                           .description = "SEQUENCE OWNED BY",
   19051             :                                           .section = SECTION_PRE_DATA,
   19052             :                                           .createStmt = query->data,
   19053             :                                           .deps = &(tbinfo->dobj.dumpId),
   19054             :                                           .nDeps = 1));
   19055             :         }
   19056             :     }
   19057             : 
   19058             :     /* Dump Sequence Comments and Security Labels */
   19059        1106 :     if (tbinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   19060           0 :         dumpComment(fout, "SEQUENCE", qseqname,
   19061           0 :                     tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
   19062           0 :                     tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
   19063             : 
   19064        1106 :     if (tbinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
   19065           0 :         dumpSecLabel(fout, "SEQUENCE", qseqname,
   19066           0 :                      tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
   19067           0 :                      tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
   19068             : 
   19069        1106 :     if (fout->remoteVersion < 100000)
   19070           0 :         pg_free(seq);
   19071        1106 :     destroyPQExpBuffer(query);
   19072        1106 :     destroyPQExpBuffer(delqry);
   19073        1106 :     free(qseqname);
   19074        1106 : }
   19075             : 
   19076             : /*
   19077             :  * dumpSequenceData
   19078             :  *    write the data of one user-defined sequence
   19079             :  */
   19080             : static void
   19081        1136 : dumpSequenceData(Archive *fout, const TableDataInfo *tdinfo)
   19082             : {
   19083        1136 :     TableInfo  *tbinfo = tdinfo->tdtable;
   19084             :     int64       last;
   19085             :     bool        called;
   19086        1136 :     PQExpBuffer query = createPQExpBuffer();
   19087             : 
   19088             :     /*
   19089             :      * For versions >= 18, the sequence information is gathered in the sorted
   19090             :      * array before any calls to dumpSequenceData().  See collectSequences()
   19091             :      * for more information.
   19092             :      *
   19093             :      * For older versions, we have to query the sequence relations
   19094             :      * individually.
   19095             :      */
   19096        1136 :     if (fout->remoteVersion < 180000)
   19097             :     {
   19098             :         PGresult   *res;
   19099             : 
   19100           0 :         appendPQExpBuffer(query,
   19101             :                           "SELECT last_value, is_called FROM %s",
   19102           0 :                           fmtQualifiedDumpable(tbinfo));
   19103             : 
   19104           0 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   19105             : 
   19106           0 :         if (PQntuples(res) != 1)
   19107           0 :             pg_fatal(ngettext("query to get data of sequence \"%s\" returned %d row (expected 1)",
   19108             :                               "query to get data of sequence \"%s\" returned %d rows (expected 1)",
   19109             :                               PQntuples(res)),
   19110             :                      tbinfo->dobj.name, PQntuples(res));
   19111             : 
   19112           0 :         last = strtoi64(PQgetvalue(res, 0, 0), NULL, 10);
   19113           0 :         called = (strcmp(PQgetvalue(res, 0, 1), "t") == 0);
   19114             : 
   19115           0 :         PQclear(res);
   19116             :     }
   19117             :     else
   19118             :     {
   19119        1136 :         SequenceItem key = {0};
   19120             :         SequenceItem *entry;
   19121             : 
   19122             :         Assert(sequences);
   19123             :         Assert(tbinfo->dobj.catId.oid);
   19124             : 
   19125        1136 :         key.oid = tbinfo->dobj.catId.oid;
   19126        1136 :         entry = bsearch(&key, sequences, nsequences,
   19127             :                         sizeof(SequenceItem), SequenceItemCmp);
   19128             : 
   19129        1136 :         last = entry->last_value;
   19130        1136 :         called = entry->is_called;
   19131             :     }
   19132             : 
   19133        1136 :     resetPQExpBuffer(query);
   19134        1136 :     appendPQExpBufferStr(query, "SELECT pg_catalog.setval(");
   19135        1136 :     appendStringLiteralAH(query, fmtQualifiedDumpable(tbinfo), fout);
   19136        1136 :     appendPQExpBuffer(query, ", " INT64_FORMAT ", %s);\n",
   19137             :                       last, (called ? "true" : "false"));
   19138             : 
   19139        1136 :     if (tdinfo->dobj.dump & DUMP_COMPONENT_DATA)
   19140        1136 :         ArchiveEntry(fout, nilCatalogId, createDumpId(),
   19141        1136 :                      ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
   19142             :                                   .namespace = tbinfo->dobj.namespace->dobj.name,
   19143             :                                   .owner = tbinfo->rolname,
   19144             :                                   .description = "SEQUENCE SET",
   19145             :                                   .section = SECTION_DATA,
   19146             :                                   .createStmt = query->data,
   19147             :                                   .deps = &(tbinfo->dobj.dumpId),
   19148             :                                   .nDeps = 1));
   19149             : 
   19150        1136 :     destroyPQExpBuffer(query);
   19151        1136 : }
   19152             : 
   19153             : /*
   19154             :  * dumpTrigger
   19155             :  *    write the declaration of one user-defined table trigger
   19156             :  */
   19157             : static void
   19158        1476 : dumpTrigger(Archive *fout, const TriggerInfo *tginfo)
   19159             : {
   19160        1476 :     DumpOptions *dopt = fout->dopt;
   19161        1476 :     TableInfo  *tbinfo = tginfo->tgtable;
   19162             :     PQExpBuffer query;
   19163             :     PQExpBuffer delqry;
   19164             :     PQExpBuffer trigprefix;
   19165             :     PQExpBuffer trigidentity;
   19166             :     char       *qtabname;
   19167             :     char       *tag;
   19168             : 
   19169             :     /* Do nothing if not dumping schema */
   19170        1476 :     if (!dopt->dumpSchema)
   19171          62 :         return;
   19172             : 
   19173        1414 :     query = createPQExpBuffer();
   19174        1414 :     delqry = createPQExpBuffer();
   19175        1414 :     trigprefix = createPQExpBuffer();
   19176        1414 :     trigidentity = createPQExpBuffer();
   19177             : 
   19178        1414 :     qtabname = pg_strdup(fmtId(tbinfo->dobj.name));
   19179             : 
   19180        1414 :     appendPQExpBuffer(trigidentity, "%s ", fmtId(tginfo->dobj.name));
   19181        1414 :     appendPQExpBuffer(trigidentity, "ON %s", fmtQualifiedDumpable(tbinfo));
   19182             : 
   19183        1414 :     appendPQExpBuffer(query, "%s;\n", tginfo->tgdef);
   19184        1414 :     appendPQExpBuffer(delqry, "DROP TRIGGER %s;\n", trigidentity->data);
   19185             : 
   19186             :     /* Triggers can depend on extensions */
   19187        1414 :     append_depends_on_extension(fout, query, &tginfo->dobj,
   19188             :                                 "pg_catalog.pg_trigger", "TRIGGER",
   19189        1414 :                                 trigidentity->data);
   19190             : 
   19191        1414 :     if (tginfo->tgispartition)
   19192             :     {
   19193             :         Assert(tbinfo->ispartition);
   19194             : 
   19195             :         /*
   19196             :          * Partition triggers only appear here because their 'tgenabled' flag
   19197             :          * differs from its parent's.  The trigger is created already, so
   19198             :          * remove the CREATE and replace it with an ALTER.  (Clear out the
   19199             :          * DROP query too, so that pg_dump --create does not cause errors.)
   19200             :          */
   19201         254 :         resetPQExpBuffer(query);
   19202         254 :         resetPQExpBuffer(delqry);
   19203         254 :         appendPQExpBuffer(query, "\nALTER %sTABLE %s ",
   19204         254 :                           tbinfo->relkind == RELKIND_FOREIGN_TABLE ? "FOREIGN " : "",
   19205         254 :                           fmtQualifiedDumpable(tbinfo));
   19206         254 :         switch (tginfo->tgenabled)
   19207             :         {
   19208          90 :             case 'f':
   19209             :             case 'D':
   19210          90 :                 appendPQExpBufferStr(query, "DISABLE");
   19211          90 :                 break;
   19212           0 :             case 't':
   19213             :             case 'O':
   19214           0 :                 appendPQExpBufferStr(query, "ENABLE");
   19215           0 :                 break;
   19216          74 :             case 'R':
   19217          74 :                 appendPQExpBufferStr(query, "ENABLE REPLICA");
   19218          74 :                 break;
   19219          90 :             case 'A':
   19220          90 :                 appendPQExpBufferStr(query, "ENABLE ALWAYS");
   19221          90 :                 break;
   19222             :         }
   19223         254 :         appendPQExpBuffer(query, " TRIGGER %s;\n",
   19224         254 :                           fmtId(tginfo->dobj.name));
   19225             :     }
   19226        1160 :     else if (tginfo->tgenabled != 't' && tginfo->tgenabled != 'O')
   19227             :     {
   19228           0 :         appendPQExpBuffer(query, "\nALTER %sTABLE %s ",
   19229           0 :                           tbinfo->relkind == RELKIND_FOREIGN_TABLE ? "FOREIGN " : "",
   19230           0 :                           fmtQualifiedDumpable(tbinfo));
   19231           0 :         switch (tginfo->tgenabled)
   19232             :         {
   19233           0 :             case 'D':
   19234             :             case 'f':
   19235           0 :                 appendPQExpBufferStr(query, "DISABLE");
   19236           0 :                 break;
   19237           0 :             case 'A':
   19238           0 :                 appendPQExpBufferStr(query, "ENABLE ALWAYS");
   19239           0 :                 break;
   19240           0 :             case 'R':
   19241           0 :                 appendPQExpBufferStr(query, "ENABLE REPLICA");
   19242           0 :                 break;
   19243           0 :             default:
   19244           0 :                 appendPQExpBufferStr(query, "ENABLE");
   19245           0 :                 break;
   19246             :         }
   19247           0 :         appendPQExpBuffer(query, " TRIGGER %s;\n",
   19248           0 :                           fmtId(tginfo->dobj.name));
   19249             :     }
   19250             : 
   19251        1414 :     appendPQExpBuffer(trigprefix, "TRIGGER %s ON",
   19252        1414 :                       fmtId(tginfo->dobj.name));
   19253             : 
   19254        1414 :     tag = psprintf("%s %s", tbinfo->dobj.name, tginfo->dobj.name);
   19255             : 
   19256        1414 :     if (tginfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   19257        1414 :         ArchiveEntry(fout, tginfo->dobj.catId, tginfo->dobj.dumpId,
   19258        1414 :                      ARCHIVE_OPTS(.tag = tag,
   19259             :                                   .namespace = tbinfo->dobj.namespace->dobj.name,
   19260             :                                   .owner = tbinfo->rolname,
   19261             :                                   .description = "TRIGGER",
   19262             :                                   .section = SECTION_POST_DATA,
   19263             :                                   .createStmt = query->data,
   19264             :                                   .dropStmt = delqry->data));
   19265             : 
   19266        1414 :     if (tginfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   19267           0 :         dumpComment(fout, trigprefix->data, qtabname,
   19268           0 :                     tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
   19269           0 :                     tginfo->dobj.catId, 0, tginfo->dobj.dumpId);
   19270             : 
   19271        1414 :     free(tag);
   19272        1414 :     destroyPQExpBuffer(query);
   19273        1414 :     destroyPQExpBuffer(delqry);
   19274        1414 :     destroyPQExpBuffer(trigprefix);
   19275        1414 :     destroyPQExpBuffer(trigidentity);
   19276        1414 :     free(qtabname);
   19277             : }
   19278             : 
   19279             : /*
   19280             :  * dumpEventTrigger
   19281             :  *    write the declaration of one user-defined event trigger
   19282             :  */
   19283             : static void
   19284          98 : dumpEventTrigger(Archive *fout, const EventTriggerInfo *evtinfo)
   19285             : {
   19286          98 :     DumpOptions *dopt = fout->dopt;
   19287             :     PQExpBuffer query;
   19288             :     PQExpBuffer delqry;
   19289             :     char       *qevtname;
   19290             : 
   19291             :     /* Do nothing if not dumping schema */
   19292          98 :     if (!dopt->dumpSchema)
   19293          12 :         return;
   19294             : 
   19295          86 :     query = createPQExpBuffer();
   19296          86 :     delqry = createPQExpBuffer();
   19297             : 
   19298          86 :     qevtname = pg_strdup(fmtId(evtinfo->dobj.name));
   19299             : 
   19300          86 :     appendPQExpBufferStr(query, "CREATE EVENT TRIGGER ");
   19301          86 :     appendPQExpBufferStr(query, qevtname);
   19302          86 :     appendPQExpBufferStr(query, " ON ");
   19303          86 :     appendPQExpBufferStr(query, fmtId(evtinfo->evtevent));
   19304             : 
   19305          86 :     if (strcmp("", evtinfo->evttags) != 0)
   19306             :     {
   19307          16 :         appendPQExpBufferStr(query, "\n         WHEN TAG IN (");
   19308          16 :         appendPQExpBufferStr(query, evtinfo->evttags);
   19309          16 :         appendPQExpBufferChar(query, ')');
   19310             :     }
   19311             : 
   19312          86 :     appendPQExpBufferStr(query, "\n   EXECUTE FUNCTION ");
   19313          86 :     appendPQExpBufferStr(query, evtinfo->evtfname);
   19314          86 :     appendPQExpBufferStr(query, "();\n");
   19315             : 
   19316          86 :     if (evtinfo->evtenabled != 'O')
   19317             :     {
   19318           0 :         appendPQExpBuffer(query, "\nALTER EVENT TRIGGER %s ",
   19319             :                           qevtname);
   19320           0 :         switch (evtinfo->evtenabled)
   19321             :         {
   19322           0 :             case 'D':
   19323           0 :                 appendPQExpBufferStr(query, "DISABLE");
   19324           0 :                 break;
   19325           0 :             case 'A':
   19326           0 :                 appendPQExpBufferStr(query, "ENABLE ALWAYS");
   19327           0 :                 break;
   19328           0 :             case 'R':
   19329           0 :                 appendPQExpBufferStr(query, "ENABLE REPLICA");
   19330           0 :                 break;
   19331           0 :             default:
   19332           0 :                 appendPQExpBufferStr(query, "ENABLE");
   19333           0 :                 break;
   19334             :         }
   19335           0 :         appendPQExpBufferStr(query, ";\n");
   19336             :     }
   19337             : 
   19338          86 :     appendPQExpBuffer(delqry, "DROP EVENT TRIGGER %s;\n",
   19339             :                       qevtname);
   19340             : 
   19341          86 :     if (dopt->binary_upgrade)
   19342           4 :         binary_upgrade_extension_member(query, &evtinfo->dobj,
   19343             :                                         "EVENT TRIGGER", qevtname, NULL);
   19344             : 
   19345          86 :     if (evtinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   19346          86 :         ArchiveEntry(fout, evtinfo->dobj.catId, evtinfo->dobj.dumpId,
   19347          86 :                      ARCHIVE_OPTS(.tag = evtinfo->dobj.name,
   19348             :                                   .owner = evtinfo->evtowner,
   19349             :                                   .description = "EVENT TRIGGER",
   19350             :                                   .section = SECTION_POST_DATA,
   19351             :                                   .createStmt = query->data,
   19352             :                                   .dropStmt = delqry->data));
   19353             : 
   19354          86 :     if (evtinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   19355           0 :         dumpComment(fout, "EVENT TRIGGER", qevtname,
   19356           0 :                     NULL, evtinfo->evtowner,
   19357           0 :                     evtinfo->dobj.catId, 0, evtinfo->dobj.dumpId);
   19358             : 
   19359          86 :     destroyPQExpBuffer(query);
   19360          86 :     destroyPQExpBuffer(delqry);
   19361          86 :     free(qevtname);
   19362             : }
   19363             : 
   19364             : /*
   19365             :  * dumpRule
   19366             :  *      Dump a rule
   19367             :  */
   19368             : static void
   19369        2990 : dumpRule(Archive *fout, const RuleInfo *rinfo)
   19370             : {
   19371        2990 :     DumpOptions *dopt = fout->dopt;
   19372        2990 :     TableInfo  *tbinfo = rinfo->ruletable;
   19373             :     bool        is_view;
   19374             :     PQExpBuffer query;
   19375             :     PQExpBuffer cmd;
   19376             :     PQExpBuffer delcmd;
   19377             :     PQExpBuffer ruleprefix;
   19378             :     char       *qtabname;
   19379             :     PGresult   *res;
   19380             :     char       *tag;
   19381             : 
   19382             :     /* Do nothing if not dumping schema */
   19383        2990 :     if (!dopt->dumpSchema)
   19384         132 :         return;
   19385             : 
   19386             :     /*
   19387             :      * If it is an ON SELECT rule that is created implicitly by CREATE VIEW,
   19388             :      * we do not want to dump it as a separate object.
   19389             :      */
   19390        2858 :     if (!rinfo->separate)
   19391        2190 :         return;
   19392             : 
   19393             :     /*
   19394             :      * If it's an ON SELECT rule, we want to print it as a view definition,
   19395             :      * instead of a rule.
   19396             :      */
   19397         668 :     is_view = (rinfo->ev_type == '1' && rinfo->is_instead);
   19398             : 
   19399         668 :     query = createPQExpBuffer();
   19400         668 :     cmd = createPQExpBuffer();
   19401         668 :     delcmd = createPQExpBuffer();
   19402         668 :     ruleprefix = createPQExpBuffer();
   19403             : 
   19404         668 :     qtabname = pg_strdup(fmtId(tbinfo->dobj.name));
   19405             : 
   19406         668 :     if (is_view)
   19407             :     {
   19408             :         PQExpBuffer result;
   19409             : 
   19410             :         /*
   19411             :          * We need OR REPLACE here because we'll be replacing a dummy view.
   19412             :          * Otherwise this should look largely like the regular view dump code.
   19413             :          */
   19414          32 :         appendPQExpBuffer(cmd, "CREATE OR REPLACE VIEW %s",
   19415          32 :                           fmtQualifiedDumpable(tbinfo));
   19416          32 :         if (nonemptyReloptions(tbinfo->reloptions))
   19417             :         {
   19418           0 :             appendPQExpBufferStr(cmd, " WITH (");
   19419           0 :             appendReloptionsArrayAH(cmd, tbinfo->reloptions, "", fout);
   19420           0 :             appendPQExpBufferChar(cmd, ')');
   19421             :         }
   19422          32 :         result = createViewAsClause(fout, tbinfo);
   19423          32 :         appendPQExpBuffer(cmd, " AS\n%s", result->data);
   19424          32 :         destroyPQExpBuffer(result);
   19425          32 :         if (tbinfo->checkoption != NULL)
   19426           0 :             appendPQExpBuffer(cmd, "\n  WITH %s CHECK OPTION",
   19427             :                               tbinfo->checkoption);
   19428          32 :         appendPQExpBufferStr(cmd, ";\n");
   19429             :     }
   19430             :     else
   19431             :     {
   19432             :         /* In the rule case, just print pg_get_ruledef's result verbatim */
   19433         636 :         appendPQExpBuffer(query,
   19434             :                           "SELECT pg_catalog.pg_get_ruledef('%u'::pg_catalog.oid)",
   19435         636 :                           rinfo->dobj.catId.oid);
   19436             : 
   19437         636 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   19438             : 
   19439         636 :         if (PQntuples(res) != 1)
   19440           0 :             pg_fatal("query to get rule \"%s\" for table \"%s\" failed: wrong number of rows returned",
   19441             :                      rinfo->dobj.name, tbinfo->dobj.name);
   19442             : 
   19443         636 :         printfPQExpBuffer(cmd, "%s\n", PQgetvalue(res, 0, 0));
   19444             : 
   19445         636 :         PQclear(res);
   19446             :     }
   19447             : 
   19448             :     /*
   19449             :      * Add the command to alter the rules replication firing semantics if it
   19450             :      * differs from the default.
   19451             :      */
   19452         668 :     if (rinfo->ev_enabled != 'O')
   19453             :     {
   19454          48 :         appendPQExpBuffer(cmd, "ALTER TABLE %s ", fmtQualifiedDumpable(tbinfo));
   19455          48 :         switch (rinfo->ev_enabled)
   19456             :         {
   19457           0 :             case 'A':
   19458           0 :                 appendPQExpBuffer(cmd, "ENABLE ALWAYS RULE %s;\n",
   19459           0 :                                   fmtId(rinfo->dobj.name));
   19460           0 :                 break;
   19461           0 :             case 'R':
   19462           0 :                 appendPQExpBuffer(cmd, "ENABLE REPLICA RULE %s;\n",
   19463           0 :                                   fmtId(rinfo->dobj.name));
   19464           0 :                 break;
   19465          48 :             case 'D':
   19466          48 :                 appendPQExpBuffer(cmd, "DISABLE RULE %s;\n",
   19467          48 :                                   fmtId(rinfo->dobj.name));
   19468          48 :                 break;
   19469             :         }
   19470             :     }
   19471             : 
   19472         668 :     if (is_view)
   19473             :     {
   19474             :         /*
   19475             :          * We can't DROP a view's ON SELECT rule.  Instead, use CREATE OR
   19476             :          * REPLACE VIEW to replace the rule with something with minimal
   19477             :          * dependencies.
   19478             :          */
   19479             :         PQExpBuffer result;
   19480             : 
   19481          32 :         appendPQExpBuffer(delcmd, "CREATE OR REPLACE VIEW %s",
   19482          32 :                           fmtQualifiedDumpable(tbinfo));
   19483          32 :         result = createDummyViewAsClause(fout, tbinfo);
   19484          32 :         appendPQExpBuffer(delcmd, " AS\n%s;\n", result->data);
   19485          32 :         destroyPQExpBuffer(result);
   19486             :     }
   19487             :     else
   19488             :     {
   19489         636 :         appendPQExpBuffer(delcmd, "DROP RULE %s ",
   19490         636 :                           fmtId(rinfo->dobj.name));
   19491         636 :         appendPQExpBuffer(delcmd, "ON %s;\n",
   19492         636 :                           fmtQualifiedDumpable(tbinfo));
   19493             :     }
   19494             : 
   19495         668 :     appendPQExpBuffer(ruleprefix, "RULE %s ON",
   19496         668 :                       fmtId(rinfo->dobj.name));
   19497             : 
   19498         668 :     tag = psprintf("%s %s", tbinfo->dobj.name, rinfo->dobj.name);
   19499             : 
   19500         668 :     if (rinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   19501         668 :         ArchiveEntry(fout, rinfo->dobj.catId, rinfo->dobj.dumpId,
   19502         668 :                      ARCHIVE_OPTS(.tag = tag,
   19503             :                                   .namespace = tbinfo->dobj.namespace->dobj.name,
   19504             :                                   .owner = tbinfo->rolname,
   19505             :                                   .description = "RULE",
   19506             :                                   .section = SECTION_POST_DATA,
   19507             :                                   .createStmt = cmd->data,
   19508             :                                   .dropStmt = delcmd->data));
   19509             : 
   19510             :     /* Dump rule comments */
   19511         668 :     if (rinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   19512           0 :         dumpComment(fout, ruleprefix->data, qtabname,
   19513           0 :                     tbinfo->dobj.namespace->dobj.name,
   19514             :                     tbinfo->rolname,
   19515           0 :                     rinfo->dobj.catId, 0, rinfo->dobj.dumpId);
   19516             : 
   19517         668 :     free(tag);
   19518         668 :     destroyPQExpBuffer(query);
   19519         668 :     destroyPQExpBuffer(cmd);
   19520         668 :     destroyPQExpBuffer(delcmd);
   19521         668 :     destroyPQExpBuffer(ruleprefix);
   19522         668 :     free(qtabname);
   19523             : }
   19524             : 
   19525             : /*
   19526             :  * getExtensionMembership --- obtain extension membership data
   19527             :  *
   19528             :  * We need to identify objects that are extension members as soon as they're
   19529             :  * loaded, so that we can correctly determine whether they need to be dumped.
   19530             :  * Generally speaking, extension member objects will get marked as *not* to
   19531             :  * be dumped, as they will be recreated by the single CREATE EXTENSION
   19532             :  * command.  However, in binary upgrade mode we still need to dump the members
   19533             :  * individually.
   19534             :  */
   19535             : void
   19536         470 : getExtensionMembership(Archive *fout, ExtensionInfo extinfo[],
   19537             :                        int numExtensions)
   19538             : {
   19539             :     PQExpBuffer query;
   19540             :     PGresult   *res;
   19541             :     int         ntups,
   19542             :                 i;
   19543             :     int         i_classid,
   19544             :                 i_objid,
   19545             :                 i_refobjid;
   19546             :     ExtensionInfo *ext;
   19547             : 
   19548             :     /* Nothing to do if no extensions */
   19549         470 :     if (numExtensions == 0)
   19550           0 :         return;
   19551             : 
   19552         470 :     query = createPQExpBuffer();
   19553             : 
   19554             :     /* refclassid constraint is redundant but may speed the search */
   19555         470 :     appendPQExpBufferStr(query, "SELECT "
   19556             :                          "classid, objid, refobjid "
   19557             :                          "FROM pg_depend "
   19558             :                          "WHERE refclassid = 'pg_extension'::regclass "
   19559             :                          "AND deptype = 'e' "
   19560             :                          "ORDER BY 3");
   19561             : 
   19562         470 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   19563             : 
   19564         470 :     ntups = PQntuples(res);
   19565             : 
   19566         470 :     i_classid = PQfnumber(res, "classid");
   19567         470 :     i_objid = PQfnumber(res, "objid");
   19568         470 :     i_refobjid = PQfnumber(res, "refobjid");
   19569             : 
   19570             :     /*
   19571             :      * Since we ordered the SELECT by referenced ID, we can expect that
   19572             :      * multiple entries for the same extension will appear together; this
   19573             :      * saves on searches.
   19574             :      */
   19575         470 :     ext = NULL;
   19576             : 
   19577        3550 :     for (i = 0; i < ntups; i++)
   19578             :     {
   19579             :         CatalogId   objId;
   19580             :         Oid         extId;
   19581             : 
   19582        3080 :         objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
   19583        3080 :         objId.oid = atooid(PQgetvalue(res, i, i_objid));
   19584        3080 :         extId = atooid(PQgetvalue(res, i, i_refobjid));
   19585             : 
   19586        3080 :         if (ext == NULL ||
   19587        2610 :             ext->dobj.catId.oid != extId)
   19588         520 :             ext = findExtensionByOid(extId);
   19589             : 
   19590        3080 :         if (ext == NULL)
   19591             :         {
   19592             :             /* shouldn't happen */
   19593           0 :             pg_log_warning("could not find referenced extension %u", extId);
   19594           0 :             continue;
   19595             :         }
   19596             : 
   19597        3080 :         recordExtensionMembership(objId, ext);
   19598             :     }
   19599             : 
   19600         470 :     PQclear(res);
   19601             : 
   19602         470 :     destroyPQExpBuffer(query);
   19603             : }
   19604             : 
   19605             : /*
   19606             :  * processExtensionTables --- deal with extension configuration tables
   19607             :  *
   19608             :  * There are two parts to this process:
   19609             :  *
   19610             :  * 1. Identify and create dump records for extension configuration tables.
   19611             :  *
   19612             :  *    Extensions can mark tables as "configuration", which means that the user
   19613             :  *    is able and expected to modify those tables after the extension has been
   19614             :  *    loaded.  For these tables, we dump out only the data- the structure is
   19615             :  *    expected to be handled at CREATE EXTENSION time, including any indexes or
   19616             :  *    foreign keys, which brings us to-
   19617             :  *
   19618             :  * 2. Record FK dependencies between configuration tables.
   19619             :  *
   19620             :  *    Due to the FKs being created at CREATE EXTENSION time and therefore before
   19621             :  *    the data is loaded, we have to work out what the best order for reloading
   19622             :  *    the data is, to avoid FK violations when the tables are restored.  This is
   19623             :  *    not perfect- we can't handle circular dependencies and if any exist they
   19624             :  *    will cause an invalid dump to be produced (though at least all of the data
   19625             :  *    is included for a user to manually restore).  This is currently documented
   19626             :  *    but perhaps we can provide a better solution in the future.
   19627             :  */
   19628             : void
   19629         468 : processExtensionTables(Archive *fout, ExtensionInfo extinfo[],
   19630             :                        int numExtensions)
   19631             : {
   19632         468 :     DumpOptions *dopt = fout->dopt;
   19633             :     PQExpBuffer query;
   19634             :     PGresult   *res;
   19635             :     int         ntups,
   19636             :                 i;
   19637             :     int         i_conrelid,
   19638             :                 i_confrelid;
   19639             : 
   19640             :     /* Nothing to do if no extensions */
   19641         468 :     if (numExtensions == 0)
   19642           0 :         return;
   19643             : 
   19644             :     /*
   19645             :      * Identify extension configuration tables and create TableDataInfo
   19646             :      * objects for them, ensuring their data will be dumped even though the
   19647             :      * tables themselves won't be.
   19648             :      *
   19649             :      * Note that we create TableDataInfo objects even in schema-only mode, ie,
   19650             :      * user data in a configuration table is treated like schema data. This
   19651             :      * seems appropriate since system data in a config table would get
   19652             :      * reloaded by CREATE EXTENSION.  If the extension is not listed in the
   19653             :      * list of extensions to be included, none of its data is dumped.
   19654             :      */
   19655         986 :     for (i = 0; i < numExtensions; i++)
   19656             :     {
   19657         518 :         ExtensionInfo *curext = &(extinfo[i]);
   19658         518 :         char       *extconfig = curext->extconfig;
   19659         518 :         char       *extcondition = curext->extcondition;
   19660         518 :         char      **extconfigarray = NULL;
   19661         518 :         char      **extconditionarray = NULL;
   19662         518 :         int         nconfigitems = 0;
   19663         518 :         int         nconditionitems = 0;
   19664             : 
   19665             :         /*
   19666             :          * Check if this extension is listed as to include in the dump.  If
   19667             :          * not, any table data associated with it is discarded.
   19668             :          */
   19669         518 :         if (extension_include_oids.head != NULL &&
   19670          16 :             !simple_oid_list_member(&extension_include_oids,
   19671             :                                     curext->dobj.catId.oid))
   19672          12 :             continue;
   19673             : 
   19674             :         /*
   19675             :          * Check if this extension is listed as to exclude in the dump.  If
   19676             :          * yes, any table data associated with it is discarded.
   19677             :          */
   19678         518 :         if (extension_exclude_oids.head != NULL &&
   19679           8 :             simple_oid_list_member(&extension_exclude_oids,
   19680             :                                    curext->dobj.catId.oid))
   19681           4 :             continue;
   19682             : 
   19683         506 :         if (strlen(extconfig) != 0 || strlen(extcondition) != 0)
   19684             :         {
   19685             :             int         j;
   19686             : 
   19687          40 :             if (!parsePGArray(extconfig, &extconfigarray, &nconfigitems))
   19688           0 :                 pg_fatal("could not parse %s array", "extconfig");
   19689          40 :             if (!parsePGArray(extcondition, &extconditionarray, &nconditionitems))
   19690           0 :                 pg_fatal("could not parse %s array", "extcondition");
   19691          40 :             if (nconfigitems != nconditionitems)
   19692           0 :                 pg_fatal("mismatched number of configurations and conditions for extension");
   19693             : 
   19694         120 :             for (j = 0; j < nconfigitems; j++)
   19695             :             {
   19696             :                 TableInfo  *configtbl;
   19697          80 :                 Oid         configtbloid = atooid(extconfigarray[j]);
   19698          80 :                 bool        dumpobj =
   19699          80 :                     curext->dobj.dump & DUMP_COMPONENT_DEFINITION;
   19700             : 
   19701          80 :                 configtbl = findTableByOid(configtbloid);
   19702          80 :                 if (configtbl == NULL)
   19703           0 :                     continue;
   19704             : 
   19705             :                 /*
   19706             :                  * Tables of not-to-be-dumped extensions shouldn't be dumped
   19707             :                  * unless the table or its schema is explicitly included
   19708             :                  */
   19709          80 :                 if (!(curext->dobj.dump & DUMP_COMPONENT_DEFINITION))
   19710             :                 {
   19711             :                     /* check table explicitly requested */
   19712           4 :                     if (table_include_oids.head != NULL &&
   19713           0 :                         simple_oid_list_member(&table_include_oids,
   19714             :                                                configtbloid))
   19715           0 :                         dumpobj = true;
   19716             : 
   19717             :                     /* check table's schema explicitly requested */
   19718           4 :                     if (configtbl->dobj.namespace->dobj.dump &
   19719             :                         DUMP_COMPONENT_DATA)
   19720           4 :                         dumpobj = true;
   19721             :                 }
   19722             : 
   19723             :                 /* check table excluded by an exclusion switch */
   19724          88 :                 if (table_exclude_oids.head != NULL &&
   19725           8 :                     simple_oid_list_member(&table_exclude_oids,
   19726             :                                            configtbloid))
   19727           2 :                     dumpobj = false;
   19728             : 
   19729             :                 /* check schema excluded by an exclusion switch */
   19730          80 :                 if (simple_oid_list_member(&schema_exclude_oids,
   19731          80 :                                            configtbl->dobj.namespace->dobj.catId.oid))
   19732           0 :                     dumpobj = false;
   19733             : 
   19734          80 :                 if (dumpobj)
   19735             :                 {
   19736          78 :                     makeTableDataInfo(dopt, configtbl);
   19737          78 :                     if (configtbl->dataObj != NULL)
   19738             :                     {
   19739          78 :                         if (strlen(extconditionarray[j]) > 0)
   19740           0 :                             configtbl->dataObj->filtercond = pg_strdup(extconditionarray[j]);
   19741             :                     }
   19742             :                 }
   19743             :             }
   19744             :         }
   19745         506 :         if (extconfigarray)
   19746          40 :             free(extconfigarray);
   19747         506 :         if (extconditionarray)
   19748          40 :             free(extconditionarray);
   19749             :     }
   19750             : 
   19751             :     /*
   19752             :      * Now that all the TableDataInfo objects have been created for all the
   19753             :      * extensions, check their FK dependencies and register them to try and
   19754             :      * dump the data out in an order that they can be restored in.
   19755             :      *
   19756             :      * Note that this is not a problem for user tables as their FKs are
   19757             :      * recreated after the data has been loaded.
   19758             :      */
   19759             : 
   19760         468 :     query = createPQExpBuffer();
   19761             : 
   19762         468 :     printfPQExpBuffer(query,
   19763             :                       "SELECT conrelid, confrelid "
   19764             :                       "FROM pg_constraint "
   19765             :                       "JOIN pg_depend ON (objid = confrelid) "
   19766             :                       "WHERE contype = 'f' "
   19767             :                       "AND refclassid = 'pg_extension'::regclass "
   19768             :                       "AND classid = 'pg_class'::regclass;");
   19769             : 
   19770         468 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   19771         468 :     ntups = PQntuples(res);
   19772             : 
   19773         468 :     i_conrelid = PQfnumber(res, "conrelid");
   19774         468 :     i_confrelid = PQfnumber(res, "confrelid");
   19775             : 
   19776             :     /* Now get the dependencies and register them */
   19777         468 :     for (i = 0; i < ntups; i++)
   19778             :     {
   19779             :         Oid         conrelid,
   19780             :                     confrelid;
   19781             :         TableInfo  *reftable,
   19782             :                    *contable;
   19783             : 
   19784           0 :         conrelid = atooid(PQgetvalue(res, i, i_conrelid));
   19785           0 :         confrelid = atooid(PQgetvalue(res, i, i_confrelid));
   19786           0 :         contable = findTableByOid(conrelid);
   19787           0 :         reftable = findTableByOid(confrelid);
   19788             : 
   19789           0 :         if (reftable == NULL ||
   19790           0 :             reftable->dataObj == NULL ||
   19791           0 :             contable == NULL ||
   19792           0 :             contable->dataObj == NULL)
   19793           0 :             continue;
   19794             : 
   19795             :         /*
   19796             :          * Make referencing TABLE_DATA object depend on the referenced table's
   19797             :          * TABLE_DATA object.
   19798             :          */
   19799           0 :         addObjectDependency(&contable->dataObj->dobj,
   19800           0 :                             reftable->dataObj->dobj.dumpId);
   19801             :     }
   19802         468 :     PQclear(res);
   19803         468 :     destroyPQExpBuffer(query);
   19804             : }
   19805             : 
   19806             : /*
   19807             :  * getDependencies --- obtain available dependency data
   19808             :  */
   19809             : static void
   19810         468 : getDependencies(Archive *fout)
   19811             : {
   19812             :     PQExpBuffer query;
   19813             :     PGresult   *res;
   19814             :     int         ntups,
   19815             :                 i;
   19816             :     int         i_classid,
   19817             :                 i_objid,
   19818             :                 i_refclassid,
   19819             :                 i_refobjid,
   19820             :                 i_deptype;
   19821             :     DumpableObject *dobj,
   19822             :                *refdobj;
   19823             : 
   19824         468 :     pg_log_info("reading dependency data");
   19825             : 
   19826         468 :     query = createPQExpBuffer();
   19827             : 
   19828             :     /*
   19829             :      * Messy query to collect the dependency data we need.  Note that we
   19830             :      * ignore the sub-object column, so that dependencies of or on a column
   19831             :      * look the same as dependencies of or on a whole table.
   19832             :      *
   19833             :      * PIN dependencies aren't interesting, and EXTENSION dependencies were
   19834             :      * already processed by getExtensionMembership.
   19835             :      */
   19836         468 :     appendPQExpBufferStr(query, "SELECT "
   19837             :                          "classid, objid, refclassid, refobjid, deptype "
   19838             :                          "FROM pg_depend "
   19839             :                          "WHERE deptype != 'p' AND deptype != 'e'\n");
   19840             : 
   19841             :     /*
   19842             :      * Since we don't treat pg_amop entries as separate DumpableObjects, we
   19843             :      * have to translate their dependencies into dependencies of their parent
   19844             :      * opfamily.  Ignore internal dependencies though, as those will point to
   19845             :      * their parent opclass, which we needn't consider here (and if we did,
   19846             :      * it'd just result in circular dependencies).  Also, "loose" opfamily
   19847             :      * entries will have dependencies on their parent opfamily, which we
   19848             :      * should drop since they'd likewise become useless self-dependencies.
   19849             :      * (But be sure to keep deps on *other* opfamilies; see amopsortfamily.)
   19850             :      */
   19851         468 :     appendPQExpBufferStr(query, "UNION ALL\n"
   19852             :                          "SELECT 'pg_opfamily'::regclass AS classid, amopfamily AS objid, refclassid, refobjid, deptype "
   19853             :                          "FROM pg_depend d, pg_amop o "
   19854             :                          "WHERE deptype NOT IN ('p', 'e', 'i') AND "
   19855             :                          "classid = 'pg_amop'::regclass AND objid = o.oid "
   19856             :                          "AND NOT (refclassid = 'pg_opfamily'::regclass AND amopfamily = refobjid)\n");
   19857             : 
   19858             :     /* Likewise for pg_amproc entries */
   19859         468 :     appendPQExpBufferStr(query, "UNION ALL\n"
   19860             :                          "SELECT 'pg_opfamily'::regclass AS classid, amprocfamily AS objid, refclassid, refobjid, deptype "
   19861             :                          "FROM pg_depend d, pg_amproc p "
   19862             :                          "WHERE deptype NOT IN ('p', 'e', 'i') AND "
   19863             :                          "classid = 'pg_amproc'::regclass AND objid = p.oid "
   19864             :                          "AND NOT (refclassid = 'pg_opfamily'::regclass AND amprocfamily = refobjid)\n");
   19865             : 
   19866             :     /* Sort the output for efficiency below */
   19867         468 :     appendPQExpBufferStr(query, "ORDER BY 1,2");
   19868             : 
   19869         468 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   19870             : 
   19871         468 :     ntups = PQntuples(res);
   19872             : 
   19873         468 :     i_classid = PQfnumber(res, "classid");
   19874         468 :     i_objid = PQfnumber(res, "objid");
   19875         468 :     i_refclassid = PQfnumber(res, "refclassid");
   19876         468 :     i_refobjid = PQfnumber(res, "refobjid");
   19877         468 :     i_deptype = PQfnumber(res, "deptype");
   19878             : 
   19879             :     /*
   19880             :      * Since we ordered the SELECT by referencing ID, we can expect that
   19881             :      * multiple entries for the same object will appear together; this saves
   19882             :      * on searches.
   19883             :      */
   19884         468 :     dobj = NULL;
   19885             : 
   19886     1012934 :     for (i = 0; i < ntups; i++)
   19887             :     {
   19888             :         CatalogId   objId;
   19889             :         CatalogId   refobjId;
   19890             :         char        deptype;
   19891             : 
   19892     1012466 :         objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
   19893     1012466 :         objId.oid = atooid(PQgetvalue(res, i, i_objid));
   19894     1012466 :         refobjId.tableoid = atooid(PQgetvalue(res, i, i_refclassid));
   19895     1012466 :         refobjId.oid = atooid(PQgetvalue(res, i, i_refobjid));
   19896     1012466 :         deptype = *(PQgetvalue(res, i, i_deptype));
   19897             : 
   19898     1012466 :         if (dobj == NULL ||
   19899      950154 :             dobj->catId.tableoid != objId.tableoid ||
   19900      945110 :             dobj->catId.oid != objId.oid)
   19901      444976 :             dobj = findObjectByCatalogId(objId);
   19902             : 
   19903             :         /*
   19904             :          * Failure to find objects mentioned in pg_depend is not unexpected,
   19905             :          * since for example we don't collect info about TOAST tables.
   19906             :          */
   19907     1012466 :         if (dobj == NULL)
   19908             :         {
   19909             : #ifdef NOT_USED
   19910             :             pg_log_warning("no referencing object %u %u",
   19911             :                            objId.tableoid, objId.oid);
   19912             : #endif
   19913       64068 :             continue;
   19914             :         }
   19915             : 
   19916      950622 :         refdobj = findObjectByCatalogId(refobjId);
   19917             : 
   19918      950622 :         if (refdobj == NULL)
   19919             :         {
   19920             : #ifdef NOT_USED
   19921             :             pg_log_warning("no referenced object %u %u",
   19922             :                            refobjId.tableoid, refobjId.oid);
   19923             : #endif
   19924        2224 :             continue;
   19925             :         }
   19926             : 
   19927             :         /*
   19928             :          * For 'x' dependencies, mark the object for later; we still add the
   19929             :          * normal dependency, for possible ordering purposes.  Currently
   19930             :          * pg_dump_sort.c knows to put extensions ahead of all object types
   19931             :          * that could possibly depend on them, but this is safer.
   19932             :          */
   19933      948398 :         if (deptype == 'x')
   19934          88 :             dobj->depends_on_ext = true;
   19935             : 
   19936             :         /*
   19937             :          * Ordinarily, table rowtypes have implicit dependencies on their
   19938             :          * tables.  However, for a composite type the implicit dependency goes
   19939             :          * the other way in pg_depend; which is the right thing for DROP but
   19940             :          * it doesn't produce the dependency ordering we need. So in that one
   19941             :          * case, we reverse the direction of the dependency.
   19942             :          */
   19943      948398 :         if (deptype == 'i' &&
   19944      267160 :             dobj->objType == DO_TABLE &&
   19945        3248 :             refdobj->objType == DO_TYPE)
   19946         468 :             addObjectDependency(refdobj, dobj->dumpId);
   19947             :         else
   19948             :             /* normal case */
   19949      947930 :             addObjectDependency(dobj, refdobj->dumpId);
   19950             :     }
   19951             : 
   19952         468 :     PQclear(res);
   19953             : 
   19954         468 :     destroyPQExpBuffer(query);
   19955         468 : }
   19956             : 
   19957             : 
   19958             : /*
   19959             :  * createBoundaryObjects - create dummy DumpableObjects to represent
   19960             :  * dump section boundaries.
   19961             :  */
   19962             : static DumpableObject *
   19963         468 : createBoundaryObjects(void)
   19964             : {
   19965             :     DumpableObject *dobjs;
   19966             : 
   19967         468 :     dobjs = (DumpableObject *) pg_malloc(2 * sizeof(DumpableObject));
   19968             : 
   19969         468 :     dobjs[0].objType = DO_PRE_DATA_BOUNDARY;
   19970         468 :     dobjs[0].catId = nilCatalogId;
   19971         468 :     AssignDumpId(dobjs + 0);
   19972         468 :     dobjs[0].name = pg_strdup("PRE-DATA BOUNDARY");
   19973             : 
   19974         468 :     dobjs[1].objType = DO_POST_DATA_BOUNDARY;
   19975         468 :     dobjs[1].catId = nilCatalogId;
   19976         468 :     AssignDumpId(dobjs + 1);
   19977         468 :     dobjs[1].name = pg_strdup("POST-DATA BOUNDARY");
   19978             : 
   19979         468 :     return dobjs;
   19980             : }
   19981             : 
   19982             : /*
   19983             :  * addBoundaryDependencies - add dependencies as needed to enforce the dump
   19984             :  * section boundaries.
   19985             :  */
   19986             : static void
   19987         468 : addBoundaryDependencies(DumpableObject **dobjs, int numObjs,
   19988             :                         DumpableObject *boundaryObjs)
   19989             : {
   19990         468 :     DumpableObject *preDataBound = boundaryObjs + 0;
   19991         468 :     DumpableObject *postDataBound = boundaryObjs + 1;
   19992             :     int         i;
   19993             : 
   19994     1740674 :     for (i = 0; i < numObjs; i++)
   19995             :     {
   19996     1740206 :         DumpableObject *dobj = dobjs[i];
   19997             : 
   19998             :         /*
   19999             :          * The classification of object types here must match the SECTION_xxx
   20000             :          * values assigned during subsequent ArchiveEntry calls!
   20001             :          */
   20002     1740206 :         switch (dobj->objType)
   20003             :         {
   20004     1625072 :             case DO_NAMESPACE:
   20005             :             case DO_EXTENSION:
   20006             :             case DO_TYPE:
   20007             :             case DO_SHELL_TYPE:
   20008             :             case DO_FUNC:
   20009             :             case DO_AGG:
   20010             :             case DO_OPERATOR:
   20011             :             case DO_ACCESS_METHOD:
   20012             :             case DO_OPCLASS:
   20013             :             case DO_OPFAMILY:
   20014             :             case DO_COLLATION:
   20015             :             case DO_CONVERSION:
   20016             :             case DO_TABLE:
   20017             :             case DO_TABLE_ATTACH:
   20018             :             case DO_ATTRDEF:
   20019             :             case DO_PROCLANG:
   20020             :             case DO_CAST:
   20021             :             case DO_DUMMY_TYPE:
   20022             :             case DO_TSPARSER:
   20023             :             case DO_TSDICT:
   20024             :             case DO_TSTEMPLATE:
   20025             :             case DO_TSCONFIG:
   20026             :             case DO_FDW:
   20027             :             case DO_FOREIGN_SERVER:
   20028             :             case DO_TRANSFORM:
   20029             :                 /* Pre-data objects: must come before the pre-data boundary */
   20030     1625072 :                 addObjectDependency(preDataBound, dobj->dumpId);
   20031     1625072 :                 break;
   20032       14058 :             case DO_TABLE_DATA:
   20033             :             case DO_SEQUENCE_SET:
   20034             :             case DO_LARGE_OBJECT:
   20035             :             case DO_LARGE_OBJECT_DATA:
   20036             :                 /* Data objects: must come between the boundaries */
   20037       14058 :                 addObjectDependency(dobj, preDataBound->dumpId);
   20038       14058 :                 addObjectDependency(postDataBound, dobj->dumpId);
   20039       14058 :                 break;
   20040       14140 :             case DO_INDEX:
   20041             :             case DO_INDEX_ATTACH:
   20042             :             case DO_STATSEXT:
   20043             :             case DO_REFRESH_MATVIEW:
   20044             :             case DO_TRIGGER:
   20045             :             case DO_EVENT_TRIGGER:
   20046             :             case DO_DEFAULT_ACL:
   20047             :             case DO_POLICY:
   20048             :             case DO_PUBLICATION:
   20049             :             case DO_PUBLICATION_REL:
   20050             :             case DO_PUBLICATION_TABLE_IN_SCHEMA:
   20051             :             case DO_SUBSCRIPTION:
   20052             :             case DO_SUBSCRIPTION_REL:
   20053             :                 /* Post-data objects: must come after the post-data boundary */
   20054       14140 :                 addObjectDependency(dobj, postDataBound->dumpId);
   20055       14140 :                 break;
   20056       72302 :             case DO_RULE:
   20057             :                 /* Rules are post-data, but only if dumped separately */
   20058       72302 :                 if (((RuleInfo *) dobj)->separate)
   20059        1716 :                     addObjectDependency(dobj, postDataBound->dumpId);
   20060       72302 :                 break;
   20061        6638 :             case DO_CONSTRAINT:
   20062             :             case DO_FK_CONSTRAINT:
   20063             :                 /* Constraints are post-data, but only if dumped separately */
   20064        6638 :                 if (((ConstraintInfo *) dobj)->separate)
   20065        4776 :                     addObjectDependency(dobj, postDataBound->dumpId);
   20066        6638 :                 break;
   20067         468 :             case DO_PRE_DATA_BOUNDARY:
   20068             :                 /* nothing to do */
   20069         468 :                 break;
   20070         468 :             case DO_POST_DATA_BOUNDARY:
   20071             :                 /* must come after the pre-data boundary */
   20072         468 :                 addObjectDependency(dobj, preDataBound->dumpId);
   20073         468 :                 break;
   20074        7060 :             case DO_REL_STATS:
   20075             :                 /* stats section varies by parent object type, DATA or POST */
   20076        7060 :                 if (((RelStatsInfo *) dobj)->section == SECTION_DATA)
   20077             :                 {
   20078        4456 :                     addObjectDependency(dobj, preDataBound->dumpId);
   20079        4456 :                     addObjectDependency(postDataBound, dobj->dumpId);
   20080             :                 }
   20081             :                 else
   20082        2604 :                     addObjectDependency(dobj, postDataBound->dumpId);
   20083        7060 :                 break;
   20084             :         }
   20085             :     }
   20086         468 : }
   20087             : 
   20088             : 
   20089             : /*
   20090             :  * BuildArchiveDependencies - create dependency data for archive TOC entries
   20091             :  *
   20092             :  * The raw dependency data obtained by getDependencies() is not terribly
   20093             :  * useful in an archive dump, because in many cases there are dependency
   20094             :  * chains linking through objects that don't appear explicitly in the dump.
   20095             :  * For example, a view will depend on its _RETURN rule while the _RETURN rule
   20096             :  * will depend on other objects --- but the rule will not appear as a separate
   20097             :  * object in the dump.  We need to adjust the view's dependencies to include
   20098             :  * whatever the rule depends on that is included in the dump.
   20099             :  *
   20100             :  * Just to make things more complicated, there are also "special" dependencies
   20101             :  * such as the dependency of a TABLE DATA item on its TABLE, which we must
   20102             :  * not rearrange because pg_restore knows that TABLE DATA only depends on
   20103             :  * its table.  In these cases we must leave the dependencies strictly as-is
   20104             :  * even if they refer to not-to-be-dumped objects.
   20105             :  *
   20106             :  * To handle this, the convention is that "special" dependencies are created
   20107             :  * during ArchiveEntry calls, and an archive TOC item that has any such
   20108             :  * entries will not be touched here.  Otherwise, we recursively search the
   20109             :  * DumpableObject data structures to build the correct dependencies for each
   20110             :  * archive TOC item.
   20111             :  */
   20112             : static void
   20113         206 : BuildArchiveDependencies(Archive *fout)
   20114             : {
   20115         206 :     ArchiveHandle *AH = (ArchiveHandle *) fout;
   20116             :     TocEntry   *te;
   20117             : 
   20118             :     /* Scan all TOC entries in the archive */
   20119       20736 :     for (te = AH->toc->next; te != AH->toc; te = te->next)
   20120             :     {
   20121             :         DumpableObject *dobj;
   20122             :         DumpId     *dependencies;
   20123             :         int         nDeps;
   20124             :         int         allocDeps;
   20125             : 
   20126             :         /* No need to process entries that will not be dumped */
   20127       20530 :         if (te->reqs == 0)
   20128        9208 :             continue;
   20129             :         /* Ignore entries that already have "special" dependencies */
   20130       20524 :         if (te->nDeps > 0)
   20131        7948 :             continue;
   20132             :         /* Otherwise, look up the item's original DumpableObject, if any */
   20133       12576 :         dobj = findObjectByDumpId(te->dumpId);
   20134       12576 :         if (dobj == NULL)
   20135         978 :             continue;
   20136             :         /* No work if it has no dependencies */
   20137       11598 :         if (dobj->nDeps <= 0)
   20138         276 :             continue;
   20139             :         /* Set up work array */
   20140       11322 :         allocDeps = 64;
   20141       11322 :         dependencies = (DumpId *) pg_malloc(allocDeps * sizeof(DumpId));
   20142       11322 :         nDeps = 0;
   20143             :         /* Recursively find all dumpable dependencies */
   20144       11322 :         findDumpableDependencies(AH, dobj,
   20145             :                                  &dependencies, &nDeps, &allocDeps);
   20146             :         /* And save 'em ... */
   20147       11322 :         if (nDeps > 0)
   20148             :         {
   20149        8076 :             dependencies = (DumpId *) pg_realloc(dependencies,
   20150             :                                                  nDeps * sizeof(DumpId));
   20151        8076 :             te->dependencies = dependencies;
   20152        8076 :             te->nDeps = nDeps;
   20153             :         }
   20154             :         else
   20155        3246 :             free(dependencies);
   20156             :     }
   20157         206 : }
   20158             : 
   20159             : /* Recursive search subroutine for BuildArchiveDependencies */
   20160             : static void
   20161       26718 : findDumpableDependencies(ArchiveHandle *AH, const DumpableObject *dobj,
   20162             :                          DumpId **dependencies, int *nDeps, int *allocDeps)
   20163             : {
   20164             :     int         i;
   20165             : 
   20166             :     /*
   20167             :      * Ignore section boundary objects: if we search through them, we'll
   20168             :      * report lots of bogus dependencies.
   20169             :      */
   20170       26718 :     if (dobj->objType == DO_PRE_DATA_BOUNDARY ||
   20171       26684 :         dobj->objType == DO_POST_DATA_BOUNDARY)
   20172        4314 :         return;
   20173             : 
   20174       54764 :     for (i = 0; i < dobj->nDeps; i++)
   20175             :     {
   20176       32360 :         DumpId      depid = dobj->dependencies[i];
   20177             : 
   20178       32360 :         if (TocIDRequired(AH, depid) != 0)
   20179             :         {
   20180             :             /* Object will be dumped, so just reference it as a dependency */
   20181       16964 :             if (*nDeps >= *allocDeps)
   20182             :             {
   20183           0 :                 *allocDeps *= 2;
   20184           0 :                 *dependencies = (DumpId *) pg_realloc(*dependencies,
   20185           0 :                                                       *allocDeps * sizeof(DumpId));
   20186             :             }
   20187       16964 :             (*dependencies)[*nDeps] = depid;
   20188       16964 :             (*nDeps)++;
   20189             :         }
   20190             :         else
   20191             :         {
   20192             :             /*
   20193             :              * Object will not be dumped, so recursively consider its deps. We
   20194             :              * rely on the assumption that sortDumpableObjects already broke
   20195             :              * any dependency loops, else we might recurse infinitely.
   20196             :              */
   20197       15396 :             DumpableObject *otherdobj = findObjectByDumpId(depid);
   20198             : 
   20199       15396 :             if (otherdobj)
   20200       15396 :                 findDumpableDependencies(AH, otherdobj,
   20201             :                                          dependencies, nDeps, allocDeps);
   20202             :         }
   20203             :     }
   20204             : }
   20205             : 
   20206             : 
   20207             : /*
   20208             :  * getFormattedTypeName - retrieve a nicely-formatted type name for the
   20209             :  * given type OID.
   20210             :  *
   20211             :  * This does not guarantee to schema-qualify the output, so it should not
   20212             :  * be used to create the target object name for CREATE or ALTER commands.
   20213             :  *
   20214             :  * Note that the result is cached and must not be freed by the caller.
   20215             :  */
   20216             : static const char *
   20217        6916 : getFormattedTypeName(Archive *fout, Oid oid, OidOptions opts)
   20218             : {
   20219             :     TypeInfo   *typeInfo;
   20220             :     char       *result;
   20221             :     PQExpBuffer query;
   20222             :     PGresult   *res;
   20223             : 
   20224        6916 :     if (oid == 0)
   20225             :     {
   20226           0 :         if ((opts & zeroAsStar) != 0)
   20227           0 :             return "*";
   20228           0 :         else if ((opts & zeroAsNone) != 0)
   20229           0 :             return "NONE";
   20230             :     }
   20231             : 
   20232             :     /* see if we have the result cached in the type's TypeInfo record */
   20233        6916 :     typeInfo = findTypeByOid(oid);
   20234        6916 :     if (typeInfo && typeInfo->ftypname)
   20235        5680 :         return typeInfo->ftypname;
   20236             : 
   20237        1236 :     query = createPQExpBuffer();
   20238        1236 :     appendPQExpBuffer(query, "SELECT pg_catalog.format_type('%u'::pg_catalog.oid, NULL)",
   20239             :                       oid);
   20240             : 
   20241        1236 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   20242             : 
   20243             :     /* result of format_type is already quoted */
   20244        1236 :     result = pg_strdup(PQgetvalue(res, 0, 0));
   20245             : 
   20246        1236 :     PQclear(res);
   20247        1236 :     destroyPQExpBuffer(query);
   20248             : 
   20249             :     /*
   20250             :      * Cache the result for re-use in later requests, if possible.  If we
   20251             :      * don't have a TypeInfo for the type, the string will be leaked once the
   20252             :      * caller is done with it ... but that case really should not happen, so
   20253             :      * leaking if it does seems acceptable.
   20254             :      */
   20255        1236 :     if (typeInfo)
   20256        1236 :         typeInfo->ftypname = result;
   20257             : 
   20258        1236 :     return result;
   20259             : }
   20260             : 
   20261             : /*
   20262             :  * Return a column list clause for the given relation.
   20263             :  *
   20264             :  * Special case: if there are no undropped columns in the relation, return
   20265             :  * "", not an invalid "()" column list.
   20266             :  */
   20267             : static const char *
   20268       24704 : fmtCopyColumnList(const TableInfo *ti, PQExpBuffer buffer)
   20269             : {
   20270       24704 :     int         numatts = ti->numatts;
   20271       24704 :     char      **attnames = ti->attnames;
   20272       24704 :     bool       *attisdropped = ti->attisdropped;
   20273       24704 :     char       *attgenerated = ti->attgenerated;
   20274             :     bool        needComma;
   20275             :     int         i;
   20276             : 
   20277       24704 :     appendPQExpBufferChar(buffer, '(');
   20278       24704 :     needComma = false;
   20279      122556 :     for (i = 0; i < numatts; i++)
   20280             :     {
   20281       97852 :         if (attisdropped[i])
   20282        1744 :             continue;
   20283       96108 :         if (attgenerated[i])
   20284        3216 :             continue;
   20285       92892 :         if (needComma)
   20286       68720 :             appendPQExpBufferStr(buffer, ", ");
   20287       92892 :         appendPQExpBufferStr(buffer, fmtId(attnames[i]));
   20288       92892 :         needComma = true;
   20289             :     }
   20290             : 
   20291       24704 :     if (!needComma)
   20292         532 :         return "";                /* no undropped columns */
   20293             : 
   20294       24172 :     appendPQExpBufferChar(buffer, ')');
   20295       24172 :     return buffer->data;
   20296             : }
   20297             : 
   20298             : /*
   20299             :  * Check if a reloptions array is nonempty.
   20300             :  */
   20301             : static bool
   20302       37976 : nonemptyReloptions(const char *reloptions)
   20303             : {
   20304             :     /* Don't want to print it if it's just "{}" */
   20305       37976 :     return (reloptions != NULL && strlen(reloptions) > 2);
   20306             : }
   20307             : 
   20308             : /*
   20309             :  * Format a reloptions array and append it to the given buffer.
   20310             :  *
   20311             :  * "prefix" is prepended to the option names; typically it's "" or "toast.".
   20312             :  */
   20313             : static void
   20314         594 : appendReloptionsArrayAH(PQExpBuffer buffer, const char *reloptions,
   20315             :                         const char *prefix, Archive *fout)
   20316             : {
   20317             :     bool        res;
   20318             : 
   20319         594 :     res = appendReloptionsArray(buffer, reloptions, prefix, fout->encoding,
   20320         594 :                                 fout->std_strings);
   20321         594 :     if (!res)
   20322           0 :         pg_log_warning("could not parse %s array", "reloptions");
   20323         594 : }
   20324             : 
   20325             : /*
   20326             :  * read_dump_filters - retrieve object identifier patterns from file
   20327             :  *
   20328             :  * Parse the specified filter file for include and exclude patterns, and add
   20329             :  * them to the relevant lists.  If the filename is "-" then filters will be
   20330             :  * read from STDIN rather than a file.
   20331             :  */
   20332             : static void
   20333          52 : read_dump_filters(const char *filename, DumpOptions *dopt)
   20334             : {
   20335             :     FilterStateData fstate;
   20336             :     char       *objname;
   20337             :     FilterCommandType comtype;
   20338             :     FilterObjectType objtype;
   20339             : 
   20340          52 :     filter_init(&fstate, filename, exit_nicely);
   20341             : 
   20342         168 :     while (filter_read_item(&fstate, &objname, &comtype, &objtype))
   20343             :     {
   20344          66 :         if (comtype == FILTER_COMMAND_TYPE_INCLUDE)
   20345             :         {
   20346          34 :             switch (objtype)
   20347             :             {
   20348           0 :                 case FILTER_OBJECT_TYPE_NONE:
   20349           0 :                     break;
   20350           0 :                 case FILTER_OBJECT_TYPE_DATABASE:
   20351             :                 case FILTER_OBJECT_TYPE_FUNCTION:
   20352             :                 case FILTER_OBJECT_TYPE_INDEX:
   20353             :                 case FILTER_OBJECT_TYPE_TABLE_DATA:
   20354             :                 case FILTER_OBJECT_TYPE_TABLE_DATA_AND_CHILDREN:
   20355             :                 case FILTER_OBJECT_TYPE_TRIGGER:
   20356           0 :                     pg_log_filter_error(&fstate, _("%s filter for \"%s\" is not allowed"),
   20357             :                                         "include",
   20358             :                                         filter_object_type_name(objtype));
   20359           0 :                     exit_nicely(1);
   20360             :                     break;      /* unreachable */
   20361             : 
   20362           2 :                 case FILTER_OBJECT_TYPE_EXTENSION:
   20363           2 :                     simple_string_list_append(&extension_include_patterns, objname);
   20364           2 :                     break;
   20365           2 :                 case FILTER_OBJECT_TYPE_FOREIGN_DATA:
   20366           2 :                     simple_string_list_append(&foreign_servers_include_patterns, objname);
   20367           2 :                     break;
   20368           2 :                 case FILTER_OBJECT_TYPE_SCHEMA:
   20369           2 :                     simple_string_list_append(&schema_include_patterns, objname);
   20370           2 :                     dopt->include_everything = false;
   20371           2 :                     break;
   20372          26 :                 case FILTER_OBJECT_TYPE_TABLE:
   20373          26 :                     simple_string_list_append(&table_include_patterns, objname);
   20374          26 :                     dopt->include_everything = false;
   20375          26 :                     break;
   20376           2 :                 case FILTER_OBJECT_TYPE_TABLE_AND_CHILDREN:
   20377           2 :                     simple_string_list_append(&table_include_patterns_and_children,
   20378             :                                               objname);
   20379           2 :                     dopt->include_everything = false;
   20380           2 :                     break;
   20381             :             }
   20382             :         }
   20383          32 :         else if (comtype == FILTER_COMMAND_TYPE_EXCLUDE)
   20384             :         {
   20385          18 :             switch (objtype)
   20386             :             {
   20387           0 :                 case FILTER_OBJECT_TYPE_NONE:
   20388           0 :                     break;
   20389           2 :                 case FILTER_OBJECT_TYPE_DATABASE:
   20390             :                 case FILTER_OBJECT_TYPE_FUNCTION:
   20391             :                 case FILTER_OBJECT_TYPE_INDEX:
   20392             :                 case FILTER_OBJECT_TYPE_TRIGGER:
   20393             :                 case FILTER_OBJECT_TYPE_FOREIGN_DATA:
   20394           2 :                     pg_log_filter_error(&fstate, _("%s filter for \"%s\" is not allowed"),
   20395             :                                         "exclude",
   20396             :                                         filter_object_type_name(objtype));
   20397           2 :                     exit_nicely(1);
   20398             :                     break;
   20399             : 
   20400           2 :                 case FILTER_OBJECT_TYPE_EXTENSION:
   20401           2 :                     simple_string_list_append(&extension_exclude_patterns, objname);
   20402           2 :                     break;
   20403           2 :                 case FILTER_OBJECT_TYPE_TABLE_DATA:
   20404           2 :                     simple_string_list_append(&tabledata_exclude_patterns,
   20405             :                                               objname);
   20406           2 :                     break;
   20407           2 :                 case FILTER_OBJECT_TYPE_TABLE_DATA_AND_CHILDREN:
   20408           2 :                     simple_string_list_append(&tabledata_exclude_patterns_and_children,
   20409             :                                               objname);
   20410           2 :                     break;
   20411           4 :                 case FILTER_OBJECT_TYPE_SCHEMA:
   20412           4 :                     simple_string_list_append(&schema_exclude_patterns, objname);
   20413           4 :                     break;
   20414           4 :                 case FILTER_OBJECT_TYPE_TABLE:
   20415           4 :                     simple_string_list_append(&table_exclude_patterns, objname);
   20416           4 :                     break;
   20417           2 :                 case FILTER_OBJECT_TYPE_TABLE_AND_CHILDREN:
   20418           2 :                     simple_string_list_append(&table_exclude_patterns_and_children,
   20419             :                                               objname);
   20420           2 :                     break;
   20421             :             }
   20422             :         }
   20423             :         else
   20424             :         {
   20425             :             Assert(comtype == FILTER_COMMAND_TYPE_NONE);
   20426             :             Assert(objtype == FILTER_OBJECT_TYPE_NONE);
   20427             :         }
   20428             : 
   20429          64 :         if (objname)
   20430          50 :             free(objname);
   20431             :     }
   20432             : 
   20433          44 :     filter_free(&fstate);
   20434          44 : }

Generated by: LCOV version 1.16