LCOV - code coverage report
Current view: top level - src/bin/pg_dump - pg_dump.c (source / functions) Hit Total Coverage
Test: PostgreSQL 18devel Lines: 7159 7934 90.2 %
Date: 2025-04-01 15:15:16 Functions: 182 186 97.8 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*-------------------------------------------------------------------------
       2             :  *
       3             :  * pg_dump.c
       4             :  *    pg_dump is a utility for dumping out a postgres database
       5             :  *    into a script file.
       6             :  *
       7             :  * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
       8             :  * Portions Copyright (c) 1994, Regents of the University of California
       9             :  *
      10             :  *  pg_dump will read the system catalogs in a database and dump out a
      11             :  *  script that reproduces the schema in terms of SQL that is understood
      12             :  *  by PostgreSQL
      13             :  *
      14             :  *  Note that pg_dump runs in a transaction-snapshot mode transaction,
      15             :  *  so it sees a consistent snapshot of the database including system
      16             :  *  catalogs. However, it relies in part on various specialized backend
      17             :  *  functions like pg_get_indexdef(), and those things tend to look at
      18             :  *  the currently committed state.  So it is possible to get 'cache
      19             :  *  lookup failed' error if someone performs DDL changes while a dump is
      20             :  *  happening. The window for this sort of thing is from the acquisition
      21             :  *  of the transaction snapshot to getSchemaData() (when pg_dump acquires
      22             :  *  AccessShareLock on every table it intends to dump). It isn't very large,
      23             :  *  but it can happen.
      24             :  *
      25             :  *  http://archives.postgresql.org/pgsql-bugs/2010-02/msg00187.php
      26             :  *
      27             :  * IDENTIFICATION
      28             :  *    src/bin/pg_dump/pg_dump.c
      29             :  *
      30             :  *-------------------------------------------------------------------------
      31             :  */
      32             : #include "postgres_fe.h"
      33             : 
      34             : #include <unistd.h>
      35             : #include <ctype.h>
      36             : #include <limits.h>
      37             : #ifdef HAVE_TERMIOS_H
      38             : #include <termios.h>
      39             : #endif
      40             : 
      41             : #include "access/attnum.h"
      42             : #include "access/sysattr.h"
      43             : #include "access/transam.h"
      44             : #include "catalog/pg_aggregate_d.h"
      45             : #include "catalog/pg_am_d.h"
      46             : #include "catalog/pg_attribute_d.h"
      47             : #include "catalog/pg_authid_d.h"
      48             : #include "catalog/pg_cast_d.h"
      49             : #include "catalog/pg_class_d.h"
      50             : #include "catalog/pg_default_acl_d.h"
      51             : #include "catalog/pg_largeobject_d.h"
      52             : #include "catalog/pg_proc_d.h"
      53             : #include "catalog/pg_publication_d.h"
      54             : #include "catalog/pg_subscription_d.h"
      55             : #include "catalog/pg_type_d.h"
      56             : #include "common/connect.h"
      57             : #include "common/int.h"
      58             : #include "common/relpath.h"
      59             : #include "common/shortest_dec.h"
      60             : #include "compress_io.h"
      61             : #include "dumputils.h"
      62             : #include "fe_utils/option_utils.h"
      63             : #include "fe_utils/string_utils.h"
      64             : #include "filter.h"
      65             : #include "getopt_long.h"
      66             : #include "libpq/libpq-fs.h"
      67             : #include "parallel.h"
      68             : #include "pg_backup_db.h"
      69             : #include "pg_backup_utils.h"
      70             : #include "pg_dump.h"
      71             : #include "storage/block.h"
      72             : 
      73             : typedef struct
      74             : {
      75             :     Oid         roleoid;        /* role's OID */
      76             :     const char *rolename;       /* role's name */
      77             : } RoleNameItem;
      78             : 
      79             : typedef struct
      80             : {
      81             :     const char *descr;          /* comment for an object */
      82             :     Oid         classoid;       /* object class (catalog OID) */
      83             :     Oid         objoid;         /* object OID */
      84             :     int         objsubid;       /* subobject (table column #) */
      85             : } CommentItem;
      86             : 
      87             : typedef struct
      88             : {
      89             :     const char *provider;       /* label provider of this security label */
      90             :     const char *label;          /* security label for an object */
      91             :     Oid         classoid;       /* object class (catalog OID) */
      92             :     Oid         objoid;         /* object OID */
      93             :     int         objsubid;       /* subobject (table column #) */
      94             : } SecLabelItem;
      95             : 
      96             : typedef struct
      97             : {
      98             :     Oid         oid;            /* object OID */
      99             :     char        relkind;        /* object kind */
     100             :     RelFileNumber relfilenumber;    /* object filenode */
     101             :     Oid         toast_oid;      /* toast table OID */
     102             :     RelFileNumber toast_relfilenumber;  /* toast table filenode */
     103             :     Oid         toast_index_oid;    /* toast table index OID */
     104             :     RelFileNumber toast_index_relfilenumber;    /* toast table index filenode */
     105             : } BinaryUpgradeClassOidItem;
     106             : 
     107             : /* sequence types */
     108             : typedef enum SeqType
     109             : {
     110             :     SEQTYPE_SMALLINT,
     111             :     SEQTYPE_INTEGER,
     112             :     SEQTYPE_BIGINT,
     113             : } SeqType;
     114             : 
     115             : static const char *const SeqTypeNames[] =
     116             : {
     117             :     [SEQTYPE_SMALLINT] = "smallint",
     118             :     [SEQTYPE_INTEGER] = "integer",
     119             :     [SEQTYPE_BIGINT] = "bigint",
     120             : };
     121             : 
     122             : StaticAssertDecl(lengthof(SeqTypeNames) == (SEQTYPE_BIGINT + 1),
     123             :                  "array length mismatch");
     124             : 
     125             : typedef struct
     126             : {
     127             :     Oid         oid;            /* sequence OID */
     128             :     SeqType     seqtype;        /* data type of sequence */
     129             :     bool        cycled;         /* whether sequence cycles */
     130             :     int64       minv;           /* minimum value */
     131             :     int64       maxv;           /* maximum value */
     132             :     int64       startv;         /* start value */
     133             :     int64       incby;          /* increment value */
     134             :     int64       cache;          /* cache size */
     135             :     int64       last_value;     /* last value of sequence */
     136             :     bool        is_called;      /* whether nextval advances before returning */
     137             : } SequenceItem;
     138             : 
     139             : typedef enum OidOptions
     140             : {
     141             :     zeroIsError = 1,
     142             :     zeroAsStar = 2,
     143             :     zeroAsNone = 4,
     144             : } OidOptions;
     145             : 
     146             : /* global decls */
     147             : static bool dosync = true;      /* Issue fsync() to make dump durable on disk. */
     148             : 
     149             : static Oid  g_last_builtin_oid; /* value of the last builtin oid */
     150             : 
     151             : /* The specified names/patterns should to match at least one entity */
     152             : static int  strict_names = 0;
     153             : 
     154             : static pg_compress_algorithm compression_algorithm = PG_COMPRESSION_NONE;
     155             : 
     156             : /*
     157             :  * Object inclusion/exclusion lists
     158             :  *
     159             :  * The string lists record the patterns given by command-line switches,
     160             :  * which we then convert to lists of OIDs of matching objects.
     161             :  */
     162             : static SimpleStringList schema_include_patterns = {NULL, NULL};
     163             : static SimpleOidList schema_include_oids = {NULL, NULL};
     164             : static SimpleStringList schema_exclude_patterns = {NULL, NULL};
     165             : static SimpleOidList schema_exclude_oids = {NULL, NULL};
     166             : 
     167             : static SimpleStringList table_include_patterns = {NULL, NULL};
     168             : static SimpleStringList table_include_patterns_and_children = {NULL, NULL};
     169             : static SimpleOidList table_include_oids = {NULL, NULL};
     170             : static SimpleStringList table_exclude_patterns = {NULL, NULL};
     171             : static SimpleStringList table_exclude_patterns_and_children = {NULL, NULL};
     172             : static SimpleOidList table_exclude_oids = {NULL, NULL};
     173             : static SimpleStringList tabledata_exclude_patterns = {NULL, NULL};
     174             : static SimpleStringList tabledata_exclude_patterns_and_children = {NULL, NULL};
     175             : static SimpleOidList tabledata_exclude_oids = {NULL, NULL};
     176             : 
     177             : static SimpleStringList foreign_servers_include_patterns = {NULL, NULL};
     178             : static SimpleOidList foreign_servers_include_oids = {NULL, NULL};
     179             : 
     180             : static SimpleStringList extension_include_patterns = {NULL, NULL};
     181             : static SimpleOidList extension_include_oids = {NULL, NULL};
     182             : 
     183             : static SimpleStringList extension_exclude_patterns = {NULL, NULL};
     184             : static SimpleOidList extension_exclude_oids = {NULL, NULL};
     185             : 
     186             : static const CatalogId nilCatalogId = {0, 0};
     187             : 
     188             : /* override for standard extra_float_digits setting */
     189             : static bool have_extra_float_digits = false;
     190             : static int  extra_float_digits;
     191             : 
     192             : /* sorted table of role names */
     193             : static RoleNameItem *rolenames = NULL;
     194             : static int  nrolenames = 0;
     195             : 
     196             : /* sorted table of comments */
     197             : static CommentItem *comments = NULL;
     198             : static int  ncomments = 0;
     199             : 
     200             : /* sorted table of security labels */
     201             : static SecLabelItem *seclabels = NULL;
     202             : static int  nseclabels = 0;
     203             : 
     204             : /* sorted table of pg_class information for binary upgrade */
     205             : static BinaryUpgradeClassOidItem *binaryUpgradeClassOids = NULL;
     206             : static int  nbinaryUpgradeClassOids = 0;
     207             : 
     208             : /* sorted table of sequences */
     209             : static SequenceItem *sequences = NULL;
     210             : static int  nsequences = 0;
     211             : 
     212             : /*
     213             :  * The default number of rows per INSERT when
     214             :  * --inserts is specified without --rows-per-insert
     215             :  */
     216             : #define DUMP_DEFAULT_ROWS_PER_INSERT 1
     217             : 
     218             : /*
     219             :  * Maximum number of large objects to group into a single ArchiveEntry.
     220             :  * At some point we might want to make this user-controllable, but for now
     221             :  * a hard-wired setting will suffice.
     222             :  */
     223             : #define MAX_BLOBS_PER_ARCHIVE_ENTRY 1000
     224             : 
     225             : /*
     226             :  * Macro for producing quoted, schema-qualified name of a dumpable object.
     227             :  */
     228             : #define fmtQualifiedDumpable(obj) \
     229             :     fmtQualifiedId((obj)->dobj.namespace->dobj.name, \
     230             :                    (obj)->dobj.name)
     231             : 
     232             : static void help(const char *progname);
     233             : static void setup_connection(Archive *AH,
     234             :                              const char *dumpencoding, const char *dumpsnapshot,
     235             :                              char *use_role);
     236             : static ArchiveFormat parseArchiveFormat(const char *format, ArchiveMode *mode);
     237             : static void expand_schema_name_patterns(Archive *fout,
     238             :                                         SimpleStringList *patterns,
     239             :                                         SimpleOidList *oids,
     240             :                                         bool strict_names);
     241             : static void expand_extension_name_patterns(Archive *fout,
     242             :                                            SimpleStringList *patterns,
     243             :                                            SimpleOidList *oids,
     244             :                                            bool strict_names);
     245             : static void expand_foreign_server_name_patterns(Archive *fout,
     246             :                                                 SimpleStringList *patterns,
     247             :                                                 SimpleOidList *oids);
     248             : static void expand_table_name_patterns(Archive *fout,
     249             :                                        SimpleStringList *patterns,
     250             :                                        SimpleOidList *oids,
     251             :                                        bool strict_names,
     252             :                                        bool with_child_tables);
     253             : static void prohibit_crossdb_refs(PGconn *conn, const char *dbname,
     254             :                                   const char *pattern);
     255             : 
     256             : static NamespaceInfo *findNamespace(Oid nsoid);
     257             : static void dumpTableData(Archive *fout, const TableDataInfo *tdinfo);
     258             : static void refreshMatViewData(Archive *fout, const TableDataInfo *tdinfo);
     259             : static const char *getRoleName(const char *roleoid_str);
     260             : static void collectRoleNames(Archive *fout);
     261             : static void getAdditionalACLs(Archive *fout);
     262             : static void dumpCommentExtended(Archive *fout, const char *type,
     263             :                                 const char *name, const char *namespace,
     264             :                                 const char *owner, CatalogId catalogId,
     265             :                                 int subid, DumpId dumpId,
     266             :                                 const char *initdb_comment);
     267             : static inline void dumpComment(Archive *fout, const char *type,
     268             :                                const char *name, const char *namespace,
     269             :                                const char *owner, CatalogId catalogId,
     270             :                                int subid, DumpId dumpId);
     271             : static int  findComments(Oid classoid, Oid objoid, CommentItem **items);
     272             : static void collectComments(Archive *fout);
     273             : static void dumpSecLabel(Archive *fout, const char *type, const char *name,
     274             :                          const char *namespace, const char *owner,
     275             :                          CatalogId catalogId, int subid, DumpId dumpId);
     276             : static int  findSecLabels(Oid classoid, Oid objoid, SecLabelItem **items);
     277             : static void collectSecLabels(Archive *fout);
     278             : static void dumpDumpableObject(Archive *fout, DumpableObject *dobj);
     279             : static void dumpNamespace(Archive *fout, const NamespaceInfo *nspinfo);
     280             : static void dumpExtension(Archive *fout, const ExtensionInfo *extinfo);
     281             : static void dumpType(Archive *fout, const TypeInfo *tyinfo);
     282             : static void dumpBaseType(Archive *fout, const TypeInfo *tyinfo);
     283             : static void dumpEnumType(Archive *fout, const TypeInfo *tyinfo);
     284             : static void dumpRangeType(Archive *fout, const TypeInfo *tyinfo);
     285             : static void dumpUndefinedType(Archive *fout, const TypeInfo *tyinfo);
     286             : static void dumpDomain(Archive *fout, const TypeInfo *tyinfo);
     287             : static void dumpCompositeType(Archive *fout, const TypeInfo *tyinfo);
     288             : static void dumpCompositeTypeColComments(Archive *fout, const TypeInfo *tyinfo,
     289             :                                          PGresult *res);
     290             : static void dumpShellType(Archive *fout, const ShellTypeInfo *stinfo);
     291             : static void dumpProcLang(Archive *fout, const ProcLangInfo *plang);
     292             : static void dumpFunc(Archive *fout, const FuncInfo *finfo);
     293             : static void dumpCast(Archive *fout, const CastInfo *cast);
     294             : static void dumpTransform(Archive *fout, const TransformInfo *transform);
     295             : static void dumpOpr(Archive *fout, const OprInfo *oprinfo);
     296             : static void dumpAccessMethod(Archive *fout, const AccessMethodInfo *aminfo);
     297             : static void dumpOpclass(Archive *fout, const OpclassInfo *opcinfo);
     298             : static void dumpOpfamily(Archive *fout, const OpfamilyInfo *opfinfo);
     299             : static void dumpCollation(Archive *fout, const CollInfo *collinfo);
     300             : static void dumpConversion(Archive *fout, const ConvInfo *convinfo);
     301             : static void dumpRule(Archive *fout, const RuleInfo *rinfo);
     302             : static void dumpAgg(Archive *fout, const AggInfo *agginfo);
     303             : static void dumpTrigger(Archive *fout, const TriggerInfo *tginfo);
     304             : static void dumpEventTrigger(Archive *fout, const EventTriggerInfo *evtinfo);
     305             : static void dumpTable(Archive *fout, const TableInfo *tbinfo);
     306             : static void dumpTableSchema(Archive *fout, const TableInfo *tbinfo);
     307             : static void dumpTableAttach(Archive *fout, const TableAttachInfo *attachinfo);
     308             : static void dumpAttrDef(Archive *fout, const AttrDefInfo *adinfo);
     309             : static void collectSequences(Archive *fout);
     310             : static void dumpSequence(Archive *fout, const TableInfo *tbinfo);
     311             : static void dumpSequenceData(Archive *fout, const TableDataInfo *tdinfo);
     312             : static void dumpIndex(Archive *fout, const IndxInfo *indxinfo);
     313             : static void dumpIndexAttach(Archive *fout, const IndexAttachInfo *attachinfo);
     314             : static void dumpStatisticsExt(Archive *fout, const StatsExtInfo *statsextinfo);
     315             : static void dumpConstraint(Archive *fout, const ConstraintInfo *coninfo);
     316             : static void dumpTableConstraintComment(Archive *fout, const ConstraintInfo *coninfo);
     317             : static void dumpTSParser(Archive *fout, const TSParserInfo *prsinfo);
     318             : static void dumpTSDictionary(Archive *fout, const TSDictInfo *dictinfo);
     319             : static void dumpTSTemplate(Archive *fout, const TSTemplateInfo *tmplinfo);
     320             : static void dumpTSConfig(Archive *fout, const TSConfigInfo *cfginfo);
     321             : static void dumpForeignDataWrapper(Archive *fout, const FdwInfo *fdwinfo);
     322             : static void dumpForeignServer(Archive *fout, const ForeignServerInfo *srvinfo);
     323             : static void dumpUserMappings(Archive *fout,
     324             :                              const char *servername, const char *namespace,
     325             :                              const char *owner, CatalogId catalogId, DumpId dumpId);
     326             : static void dumpDefaultACL(Archive *fout, const DefaultACLInfo *daclinfo);
     327             : 
     328             : static DumpId dumpACL(Archive *fout, DumpId objDumpId, DumpId altDumpId,
     329             :                       const char *type, const char *name, const char *subname,
     330             :                       const char *nspname, const char *tag, const char *owner,
     331             :                       const DumpableAcl *dacl);
     332             : 
     333             : static void getDependencies(Archive *fout);
     334             : static void BuildArchiveDependencies(Archive *fout);
     335             : static void findDumpableDependencies(ArchiveHandle *AH, const DumpableObject *dobj,
     336             :                                      DumpId **dependencies, int *nDeps, int *allocDeps);
     337             : 
     338             : static DumpableObject *createBoundaryObjects(void);
     339             : static void addBoundaryDependencies(DumpableObject **dobjs, int numObjs,
     340             :                                     DumpableObject *boundaryObjs);
     341             : 
     342             : static void addConstrChildIdxDeps(DumpableObject *dobj, const IndxInfo *refidx);
     343             : static void getDomainConstraints(Archive *fout, TypeInfo *tyinfo);
     344             : static void getTableData(DumpOptions *dopt, TableInfo *tblinfo, int numTables, char relkind);
     345             : static void makeTableDataInfo(DumpOptions *dopt, TableInfo *tbinfo);
     346             : static void buildMatViewRefreshDependencies(Archive *fout);
     347             : static void getTableDataFKConstraints(void);
     348             : static void determineNotNullFlags(Archive *fout, PGresult *res, int r,
     349             :                                   TableInfo *tbinfo, int j,
     350             :                                   int i_notnull_name, int i_notnull_noinherit,
     351             :                                   int i_notnull_islocal);
     352             : static char *format_function_arguments(const FuncInfo *finfo, const char *funcargs,
     353             :                                        bool is_agg);
     354             : static char *format_function_signature(Archive *fout,
     355             :                                        const FuncInfo *finfo, bool honor_quotes);
     356             : static char *convertRegProcReference(const char *proc);
     357             : static char *getFormattedOperatorName(const char *oproid);
     358             : static char *convertTSFunction(Archive *fout, Oid funcOid);
     359             : static const char *getFormattedTypeName(Archive *fout, Oid oid, OidOptions opts);
     360             : static void getLOs(Archive *fout);
     361             : static void dumpLO(Archive *fout, const LoInfo *loinfo);
     362             : static int  dumpLOs(Archive *fout, const void *arg);
     363             : static void dumpPolicy(Archive *fout, const PolicyInfo *polinfo);
     364             : static void dumpPublication(Archive *fout, const PublicationInfo *pubinfo);
     365             : static void dumpPublicationTable(Archive *fout, const PublicationRelInfo *pubrinfo);
     366             : static void dumpSubscription(Archive *fout, const SubscriptionInfo *subinfo);
     367             : static void dumpSubscriptionTable(Archive *fout, const SubRelInfo *subrinfo);
     368             : static void dumpDatabase(Archive *fout);
     369             : static void dumpDatabaseConfig(Archive *AH, PQExpBuffer outbuf,
     370             :                                const char *dbname, Oid dboid);
     371             : static void dumpEncoding(Archive *AH);
     372             : static void dumpStdStrings(Archive *AH);
     373             : static void dumpSearchPath(Archive *AH);
     374             : static void binary_upgrade_set_type_oids_by_type_oid(Archive *fout,
     375             :                                                      PQExpBuffer upgrade_buffer,
     376             :                                                      Oid pg_type_oid,
     377             :                                                      bool force_array_type,
     378             :                                                      bool include_multirange_type);
     379             : static void binary_upgrade_set_type_oids_by_rel(Archive *fout,
     380             :                                                 PQExpBuffer upgrade_buffer,
     381             :                                                 const TableInfo *tbinfo);
     382             : static void collectBinaryUpgradeClassOids(Archive *fout);
     383             : static void binary_upgrade_set_pg_class_oids(Archive *fout,
     384             :                                              PQExpBuffer upgrade_buffer,
     385             :                                              Oid pg_class_oid);
     386             : static void binary_upgrade_extension_member(PQExpBuffer upgrade_buffer,
     387             :                                             const DumpableObject *dobj,
     388             :                                             const char *objtype,
     389             :                                             const char *objname,
     390             :                                             const char *objnamespace);
     391             : static const char *getAttrName(int attrnum, const TableInfo *tblInfo);
     392             : static const char *fmtCopyColumnList(const TableInfo *ti, PQExpBuffer buffer);
     393             : static bool nonemptyReloptions(const char *reloptions);
     394             : static void appendReloptionsArrayAH(PQExpBuffer buffer, const char *reloptions,
     395             :                                     const char *prefix, Archive *fout);
     396             : static char *get_synchronized_snapshot(Archive *fout);
     397             : static void set_restrict_relation_kind(Archive *AH, const char *value);
     398             : static void setupDumpWorker(Archive *AH);
     399             : static TableInfo *getRootTableInfo(const TableInfo *tbinfo);
     400             : static bool forcePartitionRootLoad(const TableInfo *tbinfo);
     401             : static void read_dump_filters(const char *filename, DumpOptions *dopt);
     402             : 
     403             : 
     404             : int
     405         564 : main(int argc, char **argv)
     406             : {
     407             :     int         c;
     408         564 :     const char *filename = NULL;
     409         564 :     const char *format = "p";
     410             :     TableInfo  *tblinfo;
     411             :     int         numTables;
     412             :     DumpableObject **dobjs;
     413             :     int         numObjs;
     414             :     DumpableObject *boundaryObjs;
     415             :     int         i;
     416             :     int         optindex;
     417             :     RestoreOptions *ropt;
     418             :     Archive    *fout;           /* the script file */
     419         564 :     bool        g_verbose = false;
     420         564 :     const char *dumpencoding = NULL;
     421         564 :     const char *dumpsnapshot = NULL;
     422         564 :     char       *use_role = NULL;
     423         564 :     int         numWorkers = 1;
     424         564 :     int         plainText = 0;
     425         564 :     ArchiveFormat archiveFormat = archUnknown;
     426             :     ArchiveMode archiveMode;
     427         564 :     pg_compress_specification compression_spec = {0};
     428         564 :     char       *compression_detail = NULL;
     429         564 :     char       *compression_algorithm_str = "none";
     430         564 :     char       *error_detail = NULL;
     431         564 :     bool        user_compression_defined = false;
     432         564 :     DataDirSyncMethod sync_method = DATA_DIR_SYNC_METHOD_FSYNC;
     433         564 :     bool        data_only = false;
     434         564 :     bool        schema_only = false;
     435         564 :     bool        statistics_only = false;
     436         564 :     bool        with_data = false;
     437         564 :     bool        with_schema = false;
     438         564 :     bool        with_statistics = false;
     439         564 :     bool        no_data = false;
     440         564 :     bool        no_schema = false;
     441         564 :     bool        no_statistics = false;
     442             : 
     443             :     static DumpOptions dopt;
     444             : 
     445             :     static struct option long_options[] = {
     446             :         {"data-only", no_argument, NULL, 'a'},
     447             :         {"blobs", no_argument, NULL, 'b'},
     448             :         {"large-objects", no_argument, NULL, 'b'},
     449             :         {"no-blobs", no_argument, NULL, 'B'},
     450             :         {"no-large-objects", no_argument, NULL, 'B'},
     451             :         {"clean", no_argument, NULL, 'c'},
     452             :         {"create", no_argument, NULL, 'C'},
     453             :         {"dbname", required_argument, NULL, 'd'},
     454             :         {"extension", required_argument, NULL, 'e'},
     455             :         {"file", required_argument, NULL, 'f'},
     456             :         {"format", required_argument, NULL, 'F'},
     457             :         {"host", required_argument, NULL, 'h'},
     458             :         {"jobs", 1, NULL, 'j'},
     459             :         {"no-reconnect", no_argument, NULL, 'R'},
     460             :         {"no-owner", no_argument, NULL, 'O'},
     461             :         {"port", required_argument, NULL, 'p'},
     462             :         {"schema", required_argument, NULL, 'n'},
     463             :         {"exclude-schema", required_argument, NULL, 'N'},
     464             :         {"schema-only", no_argument, NULL, 's'},
     465             :         {"superuser", required_argument, NULL, 'S'},
     466             :         {"table", required_argument, NULL, 't'},
     467             :         {"exclude-table", required_argument, NULL, 'T'},
     468             :         {"no-password", no_argument, NULL, 'w'},
     469             :         {"password", no_argument, NULL, 'W'},
     470             :         {"username", required_argument, NULL, 'U'},
     471             :         {"verbose", no_argument, NULL, 'v'},
     472             :         {"no-privileges", no_argument, NULL, 'x'},
     473             :         {"no-acl", no_argument, NULL, 'x'},
     474             :         {"compress", required_argument, NULL, 'Z'},
     475             :         {"encoding", required_argument, NULL, 'E'},
     476             :         {"help", no_argument, NULL, '?'},
     477             :         {"version", no_argument, NULL, 'V'},
     478             : 
     479             :         /*
     480             :          * the following options don't have an equivalent short option letter
     481             :          */
     482             :         {"attribute-inserts", no_argument, &dopt.column_inserts, 1},
     483             :         {"binary-upgrade", no_argument, &dopt.binary_upgrade, 1},
     484             :         {"column-inserts", no_argument, &dopt.column_inserts, 1},
     485             :         {"disable-dollar-quoting", no_argument, &dopt.disable_dollar_quoting, 1},
     486             :         {"disable-triggers", no_argument, &dopt.disable_triggers, 1},
     487             :         {"enable-row-security", no_argument, &dopt.enable_row_security, 1},
     488             :         {"exclude-table-data", required_argument, NULL, 4},
     489             :         {"extra-float-digits", required_argument, NULL, 8},
     490             :         {"if-exists", no_argument, &dopt.if_exists, 1},
     491             :         {"inserts", no_argument, NULL, 9},
     492             :         {"lock-wait-timeout", required_argument, NULL, 2},
     493             :         {"no-table-access-method", no_argument, &dopt.outputNoTableAm, 1},
     494             :         {"no-tablespaces", no_argument, &dopt.outputNoTablespaces, 1},
     495             :         {"quote-all-identifiers", no_argument, &quote_all_identifiers, 1},
     496             :         {"load-via-partition-root", no_argument, &dopt.load_via_partition_root, 1},
     497             :         {"role", required_argument, NULL, 3},
     498             :         {"section", required_argument, NULL, 5},
     499             :         {"serializable-deferrable", no_argument, &dopt.serializable_deferrable, 1},
     500             :         {"snapshot", required_argument, NULL, 6},
     501             :         {"statistics-only", no_argument, NULL, 18},
     502             :         {"strict-names", no_argument, &strict_names, 1},
     503             :         {"use-set-session-authorization", no_argument, &dopt.use_setsessauth, 1},
     504             :         {"no-comments", no_argument, &dopt.no_comments, 1},
     505             :         {"no-data", no_argument, NULL, 19},
     506             :         {"no-policies", no_argument, &dopt.no_policies, 1},
     507             :         {"no-publications", no_argument, &dopt.no_publications, 1},
     508             :         {"no-schema", no_argument, NULL, 20},
     509             :         {"no-security-labels", no_argument, &dopt.no_security_labels, 1},
     510             :         {"no-statistics", no_argument, NULL, 21},
     511             :         {"no-subscriptions", no_argument, &dopt.no_subscriptions, 1},
     512             :         {"no-toast-compression", no_argument, &dopt.no_toast_compression, 1},
     513             :         {"no-unlogged-table-data", no_argument, &dopt.no_unlogged_table_data, 1},
     514             :         {"no-sync", no_argument, NULL, 7},
     515             :         {"with-data", no_argument, NULL, 22},
     516             :         {"with-schema", no_argument, NULL, 23},
     517             :         {"with-statistics", no_argument, NULL, 24},
     518             :         {"on-conflict-do-nothing", no_argument, &dopt.do_nothing, 1},
     519             :         {"rows-per-insert", required_argument, NULL, 10},
     520             :         {"include-foreign-data", required_argument, NULL, 11},
     521             :         {"table-and-children", required_argument, NULL, 12},
     522             :         {"exclude-table-and-children", required_argument, NULL, 13},
     523             :         {"exclude-table-data-and-children", required_argument, NULL, 14},
     524             :         {"sync-method", required_argument, NULL, 15},
     525             :         {"filter", required_argument, NULL, 16},
     526             :         {"exclude-extension", required_argument, NULL, 17},
     527             :         {"sequence-data", no_argument, &dopt.sequence_data, 1},
     528             : 
     529             :         {NULL, 0, NULL, 0}
     530             :     };
     531             : 
     532         564 :     pg_logging_init(argv[0]);
     533         564 :     pg_logging_set_level(PG_LOG_WARNING);
     534         564 :     set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_dump"));
     535             : 
     536             :     /*
     537             :      * Initialize what we need for parallel execution, especially for thread
     538             :      * support on Windows.
     539             :      */
     540         564 :     init_parallel_dump_utils();
     541             : 
     542         564 :     progname = get_progname(argv[0]);
     543             : 
     544         564 :     if (argc > 1)
     545             :     {
     546         564 :         if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
     547             :         {
     548           2 :             help(progname);
     549           2 :             exit_nicely(0);
     550             :         }
     551         562 :         if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
     552             :         {
     553         120 :             puts("pg_dump (PostgreSQL) " PG_VERSION);
     554         120 :             exit_nicely(0);
     555             :         }
     556             :     }
     557             : 
     558         442 :     InitDumpOptions(&dopt);
     559             : 
     560        2190 :     while ((c = getopt_long(argc, argv, "abBcCd:e:E:f:F:h:j:n:N:Op:RsS:t:T:U:vwWxXZ:",
     561             :                             long_options, &optindex)) != -1)
     562             :     {
     563        1764 :         switch (c)
     564             :         {
     565          18 :             case 'a':           /* Dump data only */
     566          18 :                 data_only = true;
     567          18 :                 break;
     568             : 
     569           2 :             case 'b':           /* Dump LOs */
     570           2 :                 dopt.outputLOs = true;
     571           2 :                 break;
     572             : 
     573           4 :             case 'B':           /* Don't dump LOs */
     574           4 :                 dopt.dontOutputLOs = true;
     575           4 :                 break;
     576             : 
     577          12 :             case 'c':           /* clean (i.e., drop) schema prior to create */
     578          12 :                 dopt.outputClean = 1;
     579          12 :                 break;
     580             : 
     581          58 :             case 'C':           /* Create DB */
     582          58 :                 dopt.outputCreateDB = 1;
     583          58 :                 break;
     584             : 
     585          10 :             case 'd':           /* database name */
     586          10 :                 dopt.cparams.dbname = pg_strdup(optarg);
     587          10 :                 break;
     588             : 
     589           8 :             case 'e':           /* include extension(s) */
     590           8 :                 simple_string_list_append(&extension_include_patterns, optarg);
     591           8 :                 dopt.include_everything = false;
     592           8 :                 break;
     593             : 
     594           4 :             case 'E':           /* Dump encoding */
     595           4 :                 dumpencoding = pg_strdup(optarg);
     596           4 :                 break;
     597             : 
     598         352 :             case 'f':
     599         352 :                 filename = pg_strdup(optarg);
     600         352 :                 break;
     601             : 
     602         204 :             case 'F':
     603         204 :                 format = pg_strdup(optarg);
     604         204 :                 break;
     605             : 
     606          58 :             case 'h':           /* server host */
     607          58 :                 dopt.cparams.pghost = pg_strdup(optarg);
     608          58 :                 break;
     609             : 
     610          22 :             case 'j':           /* number of dump jobs */
     611          22 :                 if (!option_parse_int(optarg, "-j/--jobs", 1,
     612             :                                       PG_MAX_JOBS,
     613             :                                       &numWorkers))
     614           2 :                     exit_nicely(1);
     615          20 :                 break;
     616             : 
     617          34 :             case 'n':           /* include schema(s) */
     618          34 :                 simple_string_list_append(&schema_include_patterns, optarg);
     619          34 :                 dopt.include_everything = false;
     620          34 :                 break;
     621             : 
     622           2 :             case 'N':           /* exclude schema(s) */
     623           2 :                 simple_string_list_append(&schema_exclude_patterns, optarg);
     624           2 :                 break;
     625             : 
     626           4 :             case 'O':           /* Don't reconnect to match owner */
     627           4 :                 dopt.outputNoOwner = 1;
     628           4 :                 break;
     629             : 
     630         134 :             case 'p':           /* server port */
     631         134 :                 dopt.cparams.pgport = pg_strdup(optarg);
     632         134 :                 break;
     633             : 
     634           4 :             case 'R':
     635             :                 /* no-op, still accepted for backwards compatibility */
     636           4 :                 break;
     637             : 
     638          14 :             case 's':           /* dump schema only */
     639          14 :                 schema_only = true;
     640          14 :                 break;
     641             : 
     642           2 :             case 'S':           /* Username for superuser in plain text output */
     643           2 :                 dopt.outputSuperuser = pg_strdup(optarg);
     644           2 :                 break;
     645             : 
     646          16 :             case 't':           /* include table(s) */
     647          16 :                 simple_string_list_append(&table_include_patterns, optarg);
     648          16 :                 dopt.include_everything = false;
     649          16 :                 break;
     650             : 
     651           8 :             case 'T':           /* exclude table(s) */
     652           8 :                 simple_string_list_append(&table_exclude_patterns, optarg);
     653           8 :                 break;
     654             : 
     655          62 :             case 'U':
     656          62 :                 dopt.cparams.username = pg_strdup(optarg);
     657          62 :                 break;
     658             : 
     659          12 :             case 'v':           /* verbose */
     660          12 :                 g_verbose = true;
     661          12 :                 pg_logging_increase_verbosity();
     662          12 :                 break;
     663             : 
     664           2 :             case 'w':
     665           2 :                 dopt.cparams.promptPassword = TRI_NO;
     666           2 :                 break;
     667             : 
     668           0 :             case 'W':
     669           0 :                 dopt.cparams.promptPassword = TRI_YES;
     670           0 :                 break;
     671             : 
     672           4 :             case 'x':           /* skip ACL dump */
     673           4 :                 dopt.aclsSkip = true;
     674           4 :                 break;
     675             : 
     676          24 :             case 'Z':           /* Compression */
     677          24 :                 parse_compress_options(optarg, &compression_algorithm_str,
     678             :                                        &compression_detail);
     679          24 :                 user_compression_defined = true;
     680          24 :                 break;
     681             : 
     682         226 :             case 0:
     683             :                 /* This covers the long options. */
     684         226 :                 break;
     685             : 
     686           4 :             case 2:             /* lock-wait-timeout */
     687           4 :                 dopt.lockWaitTimeout = pg_strdup(optarg);
     688           4 :                 break;
     689             : 
     690           6 :             case 3:             /* SET ROLE */
     691           6 :                 use_role = pg_strdup(optarg);
     692           6 :                 break;
     693             : 
     694           2 :             case 4:             /* exclude table(s) data */
     695           2 :                 simple_string_list_append(&tabledata_exclude_patterns, optarg);
     696           2 :                 break;
     697             : 
     698          12 :             case 5:             /* section */
     699          12 :                 set_dump_section(optarg, &dopt.dumpSections);
     700          12 :                 break;
     701             : 
     702           0 :             case 6:             /* snapshot */
     703           0 :                 dumpsnapshot = pg_strdup(optarg);
     704           0 :                 break;
     705             : 
     706         268 :             case 7:             /* no-sync */
     707         268 :                 dosync = false;
     708         268 :                 break;
     709             : 
     710           2 :             case 8:
     711           2 :                 have_extra_float_digits = true;
     712           2 :                 if (!option_parse_int(optarg, "--extra-float-digits", -15, 3,
     713             :                                       &extra_float_digits))
     714           2 :                     exit_nicely(1);
     715           0 :                 break;
     716             : 
     717           4 :             case 9:             /* inserts */
     718             : 
     719             :                 /*
     720             :                  * dump_inserts also stores --rows-per-insert, careful not to
     721             :                  * overwrite that.
     722             :                  */
     723           4 :                 if (dopt.dump_inserts == 0)
     724           4 :                     dopt.dump_inserts = DUMP_DEFAULT_ROWS_PER_INSERT;
     725           4 :                 break;
     726             : 
     727           4 :             case 10:            /* rows per insert */
     728           4 :                 if (!option_parse_int(optarg, "--rows-per-insert", 1, INT_MAX,
     729             :                                       &dopt.dump_inserts))
     730           2 :                     exit_nicely(1);
     731           2 :                 break;
     732             : 
     733           8 :             case 11:            /* include foreign data */
     734           8 :                 simple_string_list_append(&foreign_servers_include_patterns,
     735             :                                           optarg);
     736           8 :                 break;
     737             : 
     738           2 :             case 12:            /* include table(s) and their children */
     739           2 :                 simple_string_list_append(&table_include_patterns_and_children,
     740             :                                           optarg);
     741           2 :                 dopt.include_everything = false;
     742           2 :                 break;
     743             : 
     744           2 :             case 13:            /* exclude table(s) and their children */
     745           2 :                 simple_string_list_append(&table_exclude_patterns_and_children,
     746             :                                           optarg);
     747           2 :                 break;
     748             : 
     749           2 :             case 14:            /* exclude data of table(s) and children */
     750           2 :                 simple_string_list_append(&tabledata_exclude_patterns_and_children,
     751             :                                           optarg);
     752           2 :                 break;
     753             : 
     754           0 :             case 15:
     755           0 :                 if (!parse_sync_method(optarg, &sync_method))
     756           0 :                     exit_nicely(1);
     757           0 :                 break;
     758             : 
     759          52 :             case 16:            /* read object filters from file */
     760          52 :                 read_dump_filters(optarg, &dopt);
     761          44 :                 break;
     762             : 
     763           2 :             case 17:            /* exclude extension(s) */
     764           2 :                 simple_string_list_append(&extension_exclude_patterns,
     765             :                                           optarg);
     766           2 :                 break;
     767             : 
     768           8 :             case 18:
     769           8 :                 statistics_only = true;
     770           8 :                 break;
     771             : 
     772          62 :             case 19:
     773          62 :                 no_data = true;
     774          62 :                 break;
     775             : 
     776           4 :             case 20:
     777           4 :                 no_schema = true;
     778           4 :                 break;
     779             : 
     780          16 :             case 21:
     781          16 :                 no_statistics = true;
     782          16 :                 break;
     783             : 
     784           0 :             case 22:
     785           0 :                 with_data = true;
     786           0 :                 break;
     787             : 
     788           0 :             case 23:
     789           0 :                 with_schema = true;
     790           0 :                 break;
     791             : 
     792           2 :             case 24:
     793           2 :                 with_statistics = true;
     794           2 :                 break;
     795             : 
     796           2 :             default:
     797             :                 /* getopt_long already emitted a complaint */
     798           2 :                 pg_log_error_hint("Try \"%s --help\" for more information.", progname);
     799           2 :                 exit_nicely(1);
     800             :         }
     801             :     }
     802             : 
     803             :     /*
     804             :      * Non-option argument specifies database name as long as it wasn't
     805             :      * already specified with -d / --dbname
     806             :      */
     807         426 :     if (optind < argc && dopt.cparams.dbname == NULL)
     808         356 :         dopt.cparams.dbname = argv[optind++];
     809             : 
     810             :     /* Complain if any arguments remain */
     811         426 :     if (optind < argc)
     812             :     {
     813           2 :         pg_log_error("too many command-line arguments (first is \"%s\")",
     814             :                      argv[optind]);
     815           2 :         pg_log_error_hint("Try \"%s --help\" for more information.", progname);
     816           2 :         exit_nicely(1);
     817             :     }
     818             : 
     819             :     /* --column-inserts implies --inserts */
     820         424 :     if (dopt.column_inserts && dopt.dump_inserts == 0)
     821           2 :         dopt.dump_inserts = DUMP_DEFAULT_ROWS_PER_INSERT;
     822             : 
     823             :     /* reject conflicting "-only" options */
     824         424 :     if (data_only && schema_only)
     825           2 :         pg_fatal("options -s/--schema-only and -a/--data-only cannot be used together");
     826         422 :     if (schema_only && statistics_only)
     827           2 :         pg_fatal("options -s/--schema-only and --statistics-only cannot be used together");
     828         420 :     if (data_only && statistics_only)
     829           2 :         pg_fatal("options -a/--data-only and --statistics-only cannot be used together");
     830             : 
     831             :     /* reject conflicting "-only" and "no-" options */
     832         418 :     if (data_only && no_data)
     833           0 :         pg_fatal("options -a/--data-only and --no-data cannot be used together");
     834         418 :     if (schema_only && no_schema)
     835           0 :         pg_fatal("options -s/--schema-only and --no-schema cannot be used together");
     836         418 :     if (statistics_only && no_statistics)
     837           2 :         pg_fatal("options --statistics-only and --no-statistics cannot be used together");
     838             : 
     839             :     /* reject conflicting "with-" and "no-" options */
     840         416 :     if (with_data && no_data)
     841           0 :         pg_fatal("options --with-data and --no-data cannot be used together");
     842         416 :     if (with_schema && no_schema)
     843           0 :         pg_fatal("options --with-schema and --no-schema cannot be used together");
     844         416 :     if (with_statistics && no_statistics)
     845           0 :         pg_fatal("options --with-statistics and --no-statistics cannot be used together");
     846             : 
     847         416 :     if (schema_only && foreign_servers_include_patterns.head != NULL)
     848           2 :         pg_fatal("options -s/--schema-only and --include-foreign-data cannot be used together");
     849             : 
     850         414 :     if (numWorkers > 1 && foreign_servers_include_patterns.head != NULL)
     851           2 :         pg_fatal("option --include-foreign-data is not supported with parallel backup");
     852             : 
     853         412 :     if (data_only && dopt.outputClean)
     854           2 :         pg_fatal("options -c/--clean and -a/--data-only cannot be used together");
     855             : 
     856         410 :     if (dopt.if_exists && !dopt.outputClean)
     857           2 :         pg_fatal("option --if-exists requires option -c/--clean");
     858             : 
     859             :     /*
     860             :      * Set derivative flags. An "-only" option may be overridden by an
     861             :      * explicit "with-" option; e.g. "--schema-only --with-statistics" will
     862             :      * include schema and statistics. Other ambiguous or nonsensical
     863             :      * combinations, e.g. "--schema-only --no-schema", will have already
     864             :      * caused an error in one of the checks above.
     865             :      */
     866         408 :     dopt.dumpData = ((dopt.dumpData && !schema_only && !statistics_only) ||
     867         816 :                      (data_only || with_data)) && !no_data;
     868         408 :     dopt.dumpSchema = ((dopt.dumpSchema && !data_only && !statistics_only) ||
     869         816 :                        (schema_only || with_schema)) && !no_schema;
     870         408 :     dopt.dumpStatistics = ((dopt.dumpStatistics && !schema_only && !data_only) ||
     871         816 :                            (statistics_only || with_statistics)) && !no_statistics;
     872             : 
     873             : 
     874             :     /*
     875             :      * --inserts are already implied above if --column-inserts or
     876             :      * --rows-per-insert were specified.
     877             :      */
     878         408 :     if (dopt.do_nothing && dopt.dump_inserts == 0)
     879           2 :         pg_fatal("option --on-conflict-do-nothing requires option --inserts, --rows-per-insert, or --column-inserts");
     880             : 
     881             :     /* Identify archive format to emit */
     882         406 :     archiveFormat = parseArchiveFormat(format, &archiveMode);
     883             : 
     884             :     /* archiveFormat specific setup */
     885         404 :     if (archiveFormat == archNull)
     886         306 :         plainText = 1;
     887             : 
     888             :     /*
     889             :      * Custom and directory formats are compressed by default with gzip when
     890             :      * available, not the others.  If gzip is not available, no compression is
     891             :      * done by default.
     892             :      */
     893         404 :     if ((archiveFormat == archCustom || archiveFormat == archDirectory) &&
     894          92 :         !user_compression_defined)
     895             :     {
     896             : #ifdef HAVE_LIBZ
     897          82 :         compression_algorithm_str = "gzip";
     898             : #else
     899             :         compression_algorithm_str = "none";
     900             : #endif
     901             :     }
     902             : 
     903             :     /*
     904             :      * Compression options
     905             :      */
     906         404 :     if (!parse_compress_algorithm(compression_algorithm_str,
     907             :                                   &compression_algorithm))
     908           2 :         pg_fatal("unrecognized compression algorithm: \"%s\"",
     909             :                  compression_algorithm_str);
     910             : 
     911         402 :     parse_compress_specification(compression_algorithm, compression_detail,
     912             :                                  &compression_spec);
     913         402 :     error_detail = validate_compress_specification(&compression_spec);
     914         402 :     if (error_detail != NULL)
     915           6 :         pg_fatal("invalid compression specification: %s",
     916             :                  error_detail);
     917             : 
     918         396 :     error_detail = supports_compression(compression_spec);
     919         396 :     if (error_detail != NULL)
     920           0 :         pg_fatal("%s", error_detail);
     921             : 
     922             :     /*
     923             :      * Disable support for zstd workers for now - these are based on
     924             :      * threading, and it's unclear how it interacts with parallel dumps on
     925             :      * platforms where that relies on threads too (e.g. Windows).
     926             :      */
     927         396 :     if (compression_spec.options & PG_COMPRESSION_OPTION_WORKERS)
     928           0 :         pg_log_warning("compression option \"%s\" is not currently supported by pg_dump",
     929             :                        "workers");
     930             : 
     931             :     /*
     932             :      * If emitting an archive format, we always want to emit a DATABASE item,
     933             :      * in case --create is specified at pg_restore time.
     934             :      */
     935         396 :     if (!plainText)
     936          98 :         dopt.outputCreateDB = 1;
     937             : 
     938             :     /* Parallel backup only in the directory archive format so far */
     939         396 :     if (archiveFormat != archDirectory && numWorkers > 1)
     940           2 :         pg_fatal("parallel backup only supported by the directory format");
     941             : 
     942             :     /* Open the output file */
     943         394 :     fout = CreateArchive(filename, archiveFormat, compression_spec,
     944             :                          dosync, archiveMode, setupDumpWorker, sync_method);
     945             : 
     946             :     /* Make dump options accessible right away */
     947         392 :     SetArchiveOptions(fout, &dopt, NULL);
     948             : 
     949             :     /* Register the cleanup hook */
     950         392 :     on_exit_close_archive(fout);
     951             : 
     952             :     /* Let the archiver know how noisy to be */
     953         392 :     fout->verbose = g_verbose;
     954             : 
     955             : 
     956             :     /*
     957             :      * We allow the server to be back to 9.2, and up to any minor release of
     958             :      * our own major version.  (See also version check in pg_dumpall.c.)
     959             :      */
     960         392 :     fout->minRemoteVersion = 90200;
     961         392 :     fout->maxRemoteVersion = (PG_VERSION_NUM / 100) * 100 + 99;
     962             : 
     963         392 :     fout->numWorkers = numWorkers;
     964             : 
     965             :     /*
     966             :      * Open the database using the Archiver, so it knows about it. Errors mean
     967             :      * death.
     968             :      */
     969         392 :     ConnectDatabase(fout, &dopt.cparams, false);
     970         388 :     setup_connection(fout, dumpencoding, dumpsnapshot, use_role);
     971             : 
     972             :     /*
     973             :      * On hot standbys, never try to dump unlogged table data, since it will
     974             :      * just throw an error.
     975             :      */
     976         388 :     if (fout->isStandby)
     977           8 :         dopt.no_unlogged_table_data = true;
     978             : 
     979             :     /*
     980             :      * Find the last built-in OID, if needed (prior to 8.1)
     981             :      *
     982             :      * With 8.1 and above, we can just use FirstNormalObjectId - 1.
     983             :      */
     984         388 :     g_last_builtin_oid = FirstNormalObjectId - 1;
     985             : 
     986         388 :     pg_log_info("last built-in OID is %u", g_last_builtin_oid);
     987             : 
     988             :     /* Expand schema selection patterns into OID lists */
     989         388 :     if (schema_include_patterns.head != NULL)
     990             :     {
     991          36 :         expand_schema_name_patterns(fout, &schema_include_patterns,
     992             :                                     &schema_include_oids,
     993             :                                     strict_names);
     994          24 :         if (schema_include_oids.head == NULL)
     995           2 :             pg_fatal("no matching schemas were found");
     996             :     }
     997         374 :     expand_schema_name_patterns(fout, &schema_exclude_patterns,
     998             :                                 &schema_exclude_oids,
     999             :                                 false);
    1000             :     /* non-matching exclusion patterns aren't an error */
    1001             : 
    1002             :     /* Expand table selection patterns into OID lists */
    1003         374 :     expand_table_name_patterns(fout, &table_include_patterns,
    1004             :                                &table_include_oids,
    1005             :                                strict_names, false);
    1006         364 :     expand_table_name_patterns(fout, &table_include_patterns_and_children,
    1007             :                                &table_include_oids,
    1008             :                                strict_names, true);
    1009         364 :     if ((table_include_patterns.head != NULL ||
    1010         342 :          table_include_patterns_and_children.head != NULL) &&
    1011          26 :         table_include_oids.head == NULL)
    1012           4 :         pg_fatal("no matching tables were found");
    1013             : 
    1014         360 :     expand_table_name_patterns(fout, &table_exclude_patterns,
    1015             :                                &table_exclude_oids,
    1016             :                                false, false);
    1017         360 :     expand_table_name_patterns(fout, &table_exclude_patterns_and_children,
    1018             :                                &table_exclude_oids,
    1019             :                                false, true);
    1020             : 
    1021         360 :     expand_table_name_patterns(fout, &tabledata_exclude_patterns,
    1022             :                                &tabledata_exclude_oids,
    1023             :                                false, false);
    1024         360 :     expand_table_name_patterns(fout, &tabledata_exclude_patterns_and_children,
    1025             :                                &tabledata_exclude_oids,
    1026             :                                false, true);
    1027             : 
    1028         360 :     expand_foreign_server_name_patterns(fout, &foreign_servers_include_patterns,
    1029             :                                         &foreign_servers_include_oids);
    1030             : 
    1031             :     /* non-matching exclusion patterns aren't an error */
    1032             : 
    1033             :     /* Expand extension selection patterns into OID lists */
    1034         358 :     if (extension_include_patterns.head != NULL)
    1035             :     {
    1036          10 :         expand_extension_name_patterns(fout, &extension_include_patterns,
    1037             :                                        &extension_include_oids,
    1038             :                                        strict_names);
    1039          10 :         if (extension_include_oids.head == NULL)
    1040           2 :             pg_fatal("no matching extensions were found");
    1041             :     }
    1042         356 :     expand_extension_name_patterns(fout, &extension_exclude_patterns,
    1043             :                                    &extension_exclude_oids,
    1044             :                                    false);
    1045             :     /* non-matching exclusion patterns aren't an error */
    1046             : 
    1047             :     /*
    1048             :      * Dumping LOs is the default for dumps where an inclusion switch is not
    1049             :      * used (an "include everything" dump).  -B can be used to exclude LOs
    1050             :      * from those dumps.  -b can be used to include LOs even when an inclusion
    1051             :      * switch is used.
    1052             :      *
    1053             :      * -s means "schema only" and LOs are data, not schema, so we never
    1054             :      * include LOs when -s is used.
    1055             :      */
    1056         356 :     if (dopt.include_everything && dopt.dumpData && !dopt.dontOutputLOs)
    1057         234 :         dopt.outputLOs = true;
    1058             : 
    1059             :     /*
    1060             :      * Collect role names so we can map object owner OIDs to names.
    1061             :      */
    1062         356 :     collectRoleNames(fout);
    1063             : 
    1064             :     /*
    1065             :      * Now scan the database and create DumpableObject structs for all the
    1066             :      * objects we intend to dump.
    1067             :      */
    1068         356 :     tblinfo = getSchemaData(fout, &numTables);
    1069             : 
    1070         354 :     if (dopt.dumpData)
    1071             :     {
    1072         282 :         getTableData(&dopt, tblinfo, numTables, 0);
    1073         282 :         buildMatViewRefreshDependencies(fout);
    1074         282 :         if (!dopt.dumpSchema)
    1075          14 :             getTableDataFKConstraints();
    1076             :     }
    1077             : 
    1078         354 :     if (!dopt.dumpData && dopt.sequence_data)
    1079          56 :         getTableData(&dopt, tblinfo, numTables, RELKIND_SEQUENCE);
    1080             : 
    1081             :     /*
    1082             :      * In binary-upgrade mode, we do not have to worry about the actual LO
    1083             :      * data or the associated metadata that resides in the pg_largeobject and
    1084             :      * pg_largeobject_metadata tables, respectively.
    1085             :      *
    1086             :      * However, we do need to collect LO information as there may be comments
    1087             :      * or other information on LOs that we do need to dump out.
    1088             :      */
    1089         354 :     if (dopt.outputLOs || dopt.binary_upgrade)
    1090         296 :         getLOs(fout);
    1091             : 
    1092             :     /*
    1093             :      * Collect dependency data to assist in ordering the objects.
    1094             :      */
    1095         354 :     getDependencies(fout);
    1096             : 
    1097             :     /*
    1098             :      * Collect ACLs, comments, and security labels, if wanted.
    1099             :      */
    1100         354 :     if (!dopt.aclsSkip)
    1101         350 :         getAdditionalACLs(fout);
    1102         354 :     if (!dopt.no_comments)
    1103         354 :         collectComments(fout);
    1104         354 :     if (!dopt.no_security_labels)
    1105         354 :         collectSecLabels(fout);
    1106             : 
    1107             :     /* For binary upgrade mode, collect required pg_class information. */
    1108         354 :     if (dopt.binary_upgrade)
    1109          62 :         collectBinaryUpgradeClassOids(fout);
    1110             : 
    1111             :     /* Collect sequence information. */
    1112         354 :     collectSequences(fout);
    1113             : 
    1114             :     /* Lastly, create dummy objects to represent the section boundaries */
    1115         354 :     boundaryObjs = createBoundaryObjects();
    1116             : 
    1117             :     /* Get pointers to all the known DumpableObjects */
    1118         354 :     getDumpableObjects(&dobjs, &numObjs);
    1119             : 
    1120             :     /*
    1121             :      * Add dummy dependencies to enforce the dump section ordering.
    1122             :      */
    1123         354 :     addBoundaryDependencies(dobjs, numObjs, boundaryObjs);
    1124             : 
    1125             :     /*
    1126             :      * Sort the objects into a safe dump order (no forward references).
    1127             :      *
    1128             :      * We rely on dependency information to help us determine a safe order, so
    1129             :      * the initial sort is mostly for cosmetic purposes: we sort by name to
    1130             :      * ensure that logically identical schemas will dump identically.
    1131             :      */
    1132         354 :     sortDumpableObjectsByTypeName(dobjs, numObjs);
    1133             : 
    1134         354 :     sortDumpableObjects(dobjs, numObjs,
    1135         354 :                         boundaryObjs[0].dumpId, boundaryObjs[1].dumpId);
    1136             : 
    1137             :     /*
    1138             :      * Create archive TOC entries for all the objects to be dumped, in a safe
    1139             :      * order.
    1140             :      */
    1141             : 
    1142             :     /*
    1143             :      * First the special entries for ENCODING, STDSTRINGS, and SEARCHPATH.
    1144             :      */
    1145         354 :     dumpEncoding(fout);
    1146         354 :     dumpStdStrings(fout);
    1147         354 :     dumpSearchPath(fout);
    1148             : 
    1149             :     /* The database items are always next, unless we don't want them at all */
    1150         354 :     if (dopt.outputCreateDB)
    1151         154 :         dumpDatabase(fout);
    1152             : 
    1153             :     /* Now the rearrangeable objects. */
    1154     1305290 :     for (i = 0; i < numObjs; i++)
    1155     1304936 :         dumpDumpableObject(fout, dobjs[i]);
    1156             : 
    1157             :     /*
    1158             :      * Set up options info to ensure we dump what we want.
    1159             :      */
    1160         354 :     ropt = NewRestoreOptions();
    1161         354 :     ropt->filename = filename;
    1162             : 
    1163             :     /* if you change this list, see dumpOptionsFromRestoreOptions */
    1164         354 :     ropt->cparams.dbname = dopt.cparams.dbname ? pg_strdup(dopt.cparams.dbname) : NULL;
    1165         354 :     ropt->cparams.pgport = dopt.cparams.pgport ? pg_strdup(dopt.cparams.pgport) : NULL;
    1166         354 :     ropt->cparams.pghost = dopt.cparams.pghost ? pg_strdup(dopt.cparams.pghost) : NULL;
    1167         354 :     ropt->cparams.username = dopt.cparams.username ? pg_strdup(dopt.cparams.username) : NULL;
    1168         354 :     ropt->cparams.promptPassword = dopt.cparams.promptPassword;
    1169         354 :     ropt->dropSchema = dopt.outputClean;
    1170         354 :     ropt->dumpData = dopt.dumpData;
    1171         354 :     ropt->dumpSchema = dopt.dumpSchema;
    1172         354 :     ropt->dumpStatistics = dopt.dumpStatistics;
    1173         354 :     ropt->if_exists = dopt.if_exists;
    1174         354 :     ropt->column_inserts = dopt.column_inserts;
    1175         354 :     ropt->dumpSections = dopt.dumpSections;
    1176         354 :     ropt->aclsSkip = dopt.aclsSkip;
    1177         354 :     ropt->superuser = dopt.outputSuperuser;
    1178         354 :     ropt->createDB = dopt.outputCreateDB;
    1179         354 :     ropt->noOwner = dopt.outputNoOwner;
    1180         354 :     ropt->noTableAm = dopt.outputNoTableAm;
    1181         354 :     ropt->noTablespace = dopt.outputNoTablespaces;
    1182         354 :     ropt->disable_triggers = dopt.disable_triggers;
    1183         354 :     ropt->use_setsessauth = dopt.use_setsessauth;
    1184         354 :     ropt->disable_dollar_quoting = dopt.disable_dollar_quoting;
    1185         354 :     ropt->dump_inserts = dopt.dump_inserts;
    1186         354 :     ropt->no_comments = dopt.no_comments;
    1187         354 :     ropt->no_policies = dopt.no_policies;
    1188         354 :     ropt->no_publications = dopt.no_publications;
    1189         354 :     ropt->no_security_labels = dopt.no_security_labels;
    1190         354 :     ropt->no_subscriptions = dopt.no_subscriptions;
    1191         354 :     ropt->lockWaitTimeout = dopt.lockWaitTimeout;
    1192         354 :     ropt->include_everything = dopt.include_everything;
    1193         354 :     ropt->enable_row_security = dopt.enable_row_security;
    1194         354 :     ropt->sequence_data = dopt.sequence_data;
    1195         354 :     ropt->binary_upgrade = dopt.binary_upgrade;
    1196             : 
    1197         354 :     ropt->compression_spec = compression_spec;
    1198             : 
    1199         354 :     ropt->suppressDumpWarnings = true;   /* We've already shown them */
    1200             : 
    1201         354 :     SetArchiveOptions(fout, &dopt, ropt);
    1202             : 
    1203             :     /* Mark which entries should be output */
    1204         354 :     ProcessArchiveRestoreOptions(fout);
    1205             : 
    1206             :     /*
    1207             :      * The archive's TOC entries are now marked as to which ones will actually
    1208             :      * be output, so we can set up their dependency lists properly. This isn't
    1209             :      * necessary for plain-text output, though.
    1210             :      */
    1211         354 :     if (!plainText)
    1212          96 :         BuildArchiveDependencies(fout);
    1213             : 
    1214             :     /*
    1215             :      * And finally we can do the actual output.
    1216             :      *
    1217             :      * Note: for non-plain-text output formats, the output file is written
    1218             :      * inside CloseArchive().  This is, um, bizarre; but not worth changing
    1219             :      * right now.
    1220             :      */
    1221         354 :     if (plainText)
    1222         258 :         RestoreArchive(fout);
    1223             : 
    1224         352 :     CloseArchive(fout);
    1225             : 
    1226         352 :     exit_nicely(0);
    1227             : }
    1228             : 
    1229             : 
    1230             : static void
    1231           2 : help(const char *progname)
    1232             : {
    1233           2 :     printf(_("%s dumps a database as a text file or to other formats.\n\n"), progname);
    1234           2 :     printf(_("Usage:\n"));
    1235           2 :     printf(_("  %s [OPTION]... [DBNAME]\n"), progname);
    1236             : 
    1237           2 :     printf(_("\nGeneral options:\n"));
    1238           2 :     printf(_("  -f, --file=FILENAME          output file or directory name\n"));
    1239           2 :     printf(_("  -F, --format=c|d|t|p         output file format (custom, directory, tar,\n"
    1240             :              "                               plain text (default))\n"));
    1241           2 :     printf(_("  -j, --jobs=NUM               use this many parallel jobs to dump\n"));
    1242           2 :     printf(_("  -v, --verbose                verbose mode\n"));
    1243           2 :     printf(_("  -V, --version                output version information, then exit\n"));
    1244           2 :     printf(_("  -Z, --compress=METHOD[:DETAIL]\n"
    1245             :              "                               compress as specified\n"));
    1246           2 :     printf(_("  --lock-wait-timeout=TIMEOUT  fail after waiting TIMEOUT for a table lock\n"));
    1247           2 :     printf(_("  --no-sync                    do not wait for changes to be written safely to disk\n"));
    1248           2 :     printf(_("  --sync-method=METHOD         set method for syncing files to disk\n"));
    1249           2 :     printf(_("  -?, --help                   show this help, then exit\n"));
    1250             : 
    1251           2 :     printf(_("\nOptions controlling the output content:\n"));
    1252           2 :     printf(_("  -a, --data-only              dump only the data, not the schema or statistics\n"));
    1253           2 :     printf(_("  -b, --large-objects          include large objects in dump\n"));
    1254           2 :     printf(_("  --blobs                      (same as --large-objects, deprecated)\n"));
    1255           2 :     printf(_("  -B, --no-large-objects       exclude large objects in dump\n"));
    1256           2 :     printf(_("  --no-blobs                   (same as --no-large-objects, deprecated)\n"));
    1257           2 :     printf(_("  -c, --clean                  clean (drop) database objects before recreating\n"));
    1258           2 :     printf(_("  -C, --create                 include commands to create database in dump\n"));
    1259           2 :     printf(_("  -e, --extension=PATTERN      dump the specified extension(s) only\n"));
    1260           2 :     printf(_("  -E, --encoding=ENCODING      dump the data in encoding ENCODING\n"));
    1261           2 :     printf(_("  -n, --schema=PATTERN         dump the specified schema(s) only\n"));
    1262           2 :     printf(_("  -N, --exclude-schema=PATTERN do NOT dump the specified schema(s)\n"));
    1263           2 :     printf(_("  -O, --no-owner               skip restoration of object ownership in\n"
    1264             :              "                               plain-text format\n"));
    1265           2 :     printf(_("  -s, --schema-only            dump only the schema, no data or statistics\n"));
    1266           2 :     printf(_("  -S, --superuser=NAME         superuser user name to use in plain-text format\n"));
    1267           2 :     printf(_("  -t, --table=PATTERN          dump only the specified table(s)\n"));
    1268           2 :     printf(_("  -T, --exclude-table=PATTERN  do NOT dump the specified table(s)\n"));
    1269           2 :     printf(_("  -x, --no-privileges          do not dump privileges (grant/revoke)\n"));
    1270           2 :     printf(_("  --binary-upgrade             for use by upgrade utilities only\n"));
    1271           2 :     printf(_("  --column-inserts             dump data as INSERT commands with column names\n"));
    1272           2 :     printf(_("  --disable-dollar-quoting     disable dollar quoting, use SQL standard quoting\n"));
    1273           2 :     printf(_("  --disable-triggers           disable triggers during data-only restore\n"));
    1274           2 :     printf(_("  --enable-row-security        enable row security (dump only content user has\n"
    1275             :              "                               access to)\n"));
    1276           2 :     printf(_("  --exclude-extension=PATTERN  do NOT dump the specified extension(s)\n"));
    1277           2 :     printf(_("  --exclude-table-and-children=PATTERN\n"
    1278             :              "                               do NOT dump the specified table(s), including\n"
    1279             :              "                               child and partition tables\n"));
    1280           2 :     printf(_("  --exclude-table-data=PATTERN do NOT dump data for the specified table(s)\n"));
    1281           2 :     printf(_("  --exclude-table-data-and-children=PATTERN\n"
    1282             :              "                               do NOT dump data for the specified table(s),\n"
    1283             :              "                               including child and partition tables\n"));
    1284           2 :     printf(_("  --extra-float-digits=NUM     override default setting for extra_float_digits\n"));
    1285           2 :     printf(_("  --filter=FILENAME            include or exclude objects and data from dump\n"
    1286             :              "                               based on expressions in FILENAME\n"));
    1287           2 :     printf(_("  --if-exists                  use IF EXISTS when dropping objects\n"));
    1288           2 :     printf(_("  --include-foreign-data=PATTERN\n"
    1289             :              "                               include data of foreign tables on foreign\n"
    1290             :              "                               servers matching PATTERN\n"));
    1291           2 :     printf(_("  --inserts                    dump data as INSERT commands, rather than COPY\n"));
    1292           2 :     printf(_("  --load-via-partition-root    load partitions via the root table\n"));
    1293           2 :     printf(_("  --no-comments                do not dump comment commands\n"));
    1294           2 :     printf(_("  --no-data                    do not dump data\n"));
    1295           2 :     printf(_("  --no-policies                do not dump row security policies\n"));
    1296           2 :     printf(_("  --no-publications            do not dump publications\n"));
    1297           2 :     printf(_("  --no-schema                  do not dump schema\n"));
    1298           2 :     printf(_("  --no-security-labels         do not dump security label assignments\n"));
    1299           2 :     printf(_("  --no-statistics              do not dump statistics\n"));
    1300           2 :     printf(_("  --no-subscriptions           do not dump subscriptions\n"));
    1301           2 :     printf(_("  --no-table-access-method     do not dump table access methods\n"));
    1302           2 :     printf(_("  --no-tablespaces             do not dump tablespace assignments\n"));
    1303           2 :     printf(_("  --no-toast-compression       do not dump TOAST compression methods\n"));
    1304           2 :     printf(_("  --no-unlogged-table-data     do not dump unlogged table data\n"));
    1305           2 :     printf(_("  --on-conflict-do-nothing     add ON CONFLICT DO NOTHING to INSERT commands\n"));
    1306           2 :     printf(_("  --quote-all-identifiers      quote all identifiers, even if not key words\n"));
    1307           2 :     printf(_("  --rows-per-insert=NROWS      number of rows per INSERT; implies --inserts\n"));
    1308           2 :     printf(_("  --section=SECTION            dump named section (pre-data, data, or post-data)\n"));
    1309           2 :     printf(_("  --sequence-data              include sequence data in dump\n"));
    1310           2 :     printf(_("  --serializable-deferrable    wait until the dump can run without anomalies\n"));
    1311           2 :     printf(_("  --snapshot=SNAPSHOT          use given snapshot for the dump\n"));
    1312           2 :     printf(_("  --statistics-only            dump only the statistics, not schema or data\n"));
    1313           2 :     printf(_("  --strict-names               require table and/or schema include patterns to\n"
    1314             :              "                               match at least one entity each\n"));
    1315           2 :     printf(_("  --table-and-children=PATTERN dump only the specified table(s), including\n"
    1316             :              "                               child and partition tables\n"));
    1317           2 :     printf(_("  --use-set-session-authorization\n"
    1318             :              "                               use SET SESSION AUTHORIZATION commands instead of\n"
    1319             :              "                               ALTER OWNER commands to set ownership\n"));
    1320           2 :     printf(_("  --with-data                  dump the data\n"));
    1321           2 :     printf(_("  --with-schema                dump the schema\n"));
    1322           2 :     printf(_("  --with-statistics            dump the statistics\n"));
    1323             : 
    1324           2 :     printf(_("\nConnection options:\n"));
    1325           2 :     printf(_("  -d, --dbname=DBNAME      database to dump\n"));
    1326           2 :     printf(_("  -h, --host=HOSTNAME      database server host or socket directory\n"));
    1327           2 :     printf(_("  -p, --port=PORT          database server port number\n"));
    1328           2 :     printf(_("  -U, --username=NAME      connect as specified database user\n"));
    1329           2 :     printf(_("  -w, --no-password        never prompt for password\n"));
    1330           2 :     printf(_("  -W, --password           force password prompt (should happen automatically)\n"));
    1331           2 :     printf(_("  --role=ROLENAME          do SET ROLE before dump\n"));
    1332             : 
    1333           2 :     printf(_("\nIf no database name is supplied, then the PGDATABASE environment\n"
    1334             :              "variable value is used.\n\n"));
    1335           2 :     printf(_("Report bugs to <%s>.\n"), PACKAGE_BUGREPORT);
    1336           2 :     printf(_("%s home page: <%s>\n"), PACKAGE_NAME, PACKAGE_URL);
    1337           2 : }
    1338             : 
    1339             : static void
    1340         420 : setup_connection(Archive *AH, const char *dumpencoding,
    1341             :                  const char *dumpsnapshot, char *use_role)
    1342             : {
    1343         420 :     DumpOptions *dopt = AH->dopt;
    1344         420 :     PGconn     *conn = GetConnection(AH);
    1345             :     const char *std_strings;
    1346             : 
    1347         420 :     PQclear(ExecuteSqlQueryForSingleRow(AH, ALWAYS_SECURE_SEARCH_PATH_SQL));
    1348             : 
    1349             :     /*
    1350             :      * Set the client encoding if requested.
    1351             :      */
    1352         420 :     if (dumpencoding)
    1353             :     {
    1354          36 :         if (PQsetClientEncoding(conn, dumpencoding) < 0)
    1355           0 :             pg_fatal("invalid client encoding \"%s\" specified",
    1356             :                      dumpencoding);
    1357             :     }
    1358             : 
    1359             :     /*
    1360             :      * Get the active encoding and the standard_conforming_strings setting, so
    1361             :      * we know how to escape strings.
    1362             :      */
    1363         420 :     AH->encoding = PQclientEncoding(conn);
    1364         420 :     setFmtEncoding(AH->encoding);
    1365             : 
    1366         420 :     std_strings = PQparameterStatus(conn, "standard_conforming_strings");
    1367         420 :     AH->std_strings = (std_strings && strcmp(std_strings, "on") == 0);
    1368             : 
    1369             :     /*
    1370             :      * Set the role if requested.  In a parallel dump worker, we'll be passed
    1371             :      * use_role == NULL, but AH->use_role is already set (if user specified it
    1372             :      * originally) and we should use that.
    1373             :      */
    1374         420 :     if (!use_role && AH->use_role)
    1375           4 :         use_role = AH->use_role;
    1376             : 
    1377             :     /* Set the role if requested */
    1378         420 :     if (use_role)
    1379             :     {
    1380          10 :         PQExpBuffer query = createPQExpBuffer();
    1381             : 
    1382          10 :         appendPQExpBuffer(query, "SET ROLE %s", fmtId(use_role));
    1383          10 :         ExecuteSqlStatement(AH, query->data);
    1384          10 :         destroyPQExpBuffer(query);
    1385             : 
    1386             :         /* save it for possible later use by parallel workers */
    1387          10 :         if (!AH->use_role)
    1388           6 :             AH->use_role = pg_strdup(use_role);
    1389             :     }
    1390             : 
    1391             :     /* Set the datestyle to ISO to ensure the dump's portability */
    1392         420 :     ExecuteSqlStatement(AH, "SET DATESTYLE = ISO");
    1393             : 
    1394             :     /* Likewise, avoid using sql_standard intervalstyle */
    1395         420 :     ExecuteSqlStatement(AH, "SET INTERVALSTYLE = POSTGRES");
    1396             : 
    1397             :     /*
    1398             :      * Use an explicitly specified extra_float_digits if it has been provided.
    1399             :      * Otherwise, set extra_float_digits so that we can dump float data
    1400             :      * exactly (given correctly implemented float I/O code, anyway).
    1401             :      */
    1402         420 :     if (have_extra_float_digits)
    1403             :     {
    1404           0 :         PQExpBuffer q = createPQExpBuffer();
    1405             : 
    1406           0 :         appendPQExpBuffer(q, "SET extra_float_digits TO %d",
    1407             :                           extra_float_digits);
    1408           0 :         ExecuteSqlStatement(AH, q->data);
    1409           0 :         destroyPQExpBuffer(q);
    1410             :     }
    1411             :     else
    1412         420 :         ExecuteSqlStatement(AH, "SET extra_float_digits TO 3");
    1413             : 
    1414             :     /*
    1415             :      * Disable synchronized scanning, to prevent unpredictable changes in row
    1416             :      * ordering across a dump and reload.
    1417             :      */
    1418         420 :     ExecuteSqlStatement(AH, "SET synchronize_seqscans TO off");
    1419             : 
    1420             :     /*
    1421             :      * Disable timeouts if supported.
    1422             :      */
    1423         420 :     ExecuteSqlStatement(AH, "SET statement_timeout = 0");
    1424         420 :     if (AH->remoteVersion >= 90300)
    1425         420 :         ExecuteSqlStatement(AH, "SET lock_timeout = 0");
    1426         420 :     if (AH->remoteVersion >= 90600)
    1427         420 :         ExecuteSqlStatement(AH, "SET idle_in_transaction_session_timeout = 0");
    1428         420 :     if (AH->remoteVersion >= 170000)
    1429         420 :         ExecuteSqlStatement(AH, "SET transaction_timeout = 0");
    1430             : 
    1431             :     /*
    1432             :      * Quote all identifiers, if requested.
    1433             :      */
    1434         420 :     if (quote_all_identifiers)
    1435          58 :         ExecuteSqlStatement(AH, "SET quote_all_identifiers = true");
    1436             : 
    1437             :     /*
    1438             :      * Adjust row-security mode, if supported.
    1439             :      */
    1440         420 :     if (AH->remoteVersion >= 90500)
    1441             :     {
    1442         420 :         if (dopt->enable_row_security)
    1443           0 :             ExecuteSqlStatement(AH, "SET row_security = on");
    1444             :         else
    1445         420 :             ExecuteSqlStatement(AH, "SET row_security = off");
    1446             :     }
    1447             : 
    1448             :     /*
    1449             :      * For security reasons, we restrict the expansion of non-system views and
    1450             :      * access to foreign tables during the pg_dump process. This restriction
    1451             :      * is adjusted when dumping foreign table data.
    1452             :      */
    1453         420 :     set_restrict_relation_kind(AH, "view, foreign-table");
    1454             : 
    1455             :     /*
    1456             :      * Initialize prepared-query state to "nothing prepared".  We do this here
    1457             :      * so that a parallel dump worker will have its own state.
    1458             :      */
    1459         420 :     AH->is_prepared = (bool *) pg_malloc0(NUM_PREP_QUERIES * sizeof(bool));
    1460             : 
    1461             :     /*
    1462             :      * Start transaction-snapshot mode transaction to dump consistent data.
    1463             :      */
    1464         420 :     ExecuteSqlStatement(AH, "BEGIN");
    1465             : 
    1466             :     /*
    1467             :      * To support the combination of serializable_deferrable with the jobs
    1468             :      * option we use REPEATABLE READ for the worker connections that are
    1469             :      * passed a snapshot.  As long as the snapshot is acquired in a
    1470             :      * SERIALIZABLE, READ ONLY, DEFERRABLE transaction, its use within a
    1471             :      * REPEATABLE READ transaction provides the appropriate integrity
    1472             :      * guarantees.  This is a kluge, but safe for back-patching.
    1473             :      */
    1474         420 :     if (dopt->serializable_deferrable && AH->sync_snapshot_id == NULL)
    1475           0 :         ExecuteSqlStatement(AH,
    1476             :                             "SET TRANSACTION ISOLATION LEVEL "
    1477             :                             "SERIALIZABLE, READ ONLY, DEFERRABLE");
    1478             :     else
    1479         420 :         ExecuteSqlStatement(AH,
    1480             :                             "SET TRANSACTION ISOLATION LEVEL "
    1481             :                             "REPEATABLE READ, READ ONLY");
    1482             : 
    1483             :     /*
    1484             :      * If user specified a snapshot to use, select that.  In a parallel dump
    1485             :      * worker, we'll be passed dumpsnapshot == NULL, but AH->sync_snapshot_id
    1486             :      * is already set (if the server can handle it) and we should use that.
    1487             :      */
    1488         420 :     if (dumpsnapshot)
    1489           0 :         AH->sync_snapshot_id = pg_strdup(dumpsnapshot);
    1490             : 
    1491         420 :     if (AH->sync_snapshot_id)
    1492             :     {
    1493          32 :         PQExpBuffer query = createPQExpBuffer();
    1494             : 
    1495          32 :         appendPQExpBufferStr(query, "SET TRANSACTION SNAPSHOT ");
    1496          32 :         appendStringLiteralConn(query, AH->sync_snapshot_id, conn);
    1497          32 :         ExecuteSqlStatement(AH, query->data);
    1498          32 :         destroyPQExpBuffer(query);
    1499             :     }
    1500         388 :     else if (AH->numWorkers > 1)
    1501             :     {
    1502          16 :         if (AH->isStandby && AH->remoteVersion < 100000)
    1503           0 :             pg_fatal("parallel dumps from standby servers are not supported by this server version");
    1504          16 :         AH->sync_snapshot_id = get_synchronized_snapshot(AH);
    1505             :     }
    1506         420 : }
    1507             : 
    1508             : /* Set up connection for a parallel worker process */
    1509             : static void
    1510          32 : setupDumpWorker(Archive *AH)
    1511             : {
    1512             :     /*
    1513             :      * We want to re-select all the same values the leader connection is
    1514             :      * using.  We'll have inherited directly-usable values in
    1515             :      * AH->sync_snapshot_id and AH->use_role, but we need to translate the
    1516             :      * inherited encoding value back to a string to pass to setup_connection.
    1517             :      */
    1518          32 :     setup_connection(AH,
    1519             :                      pg_encoding_to_char(AH->encoding),
    1520             :                      NULL,
    1521             :                      NULL);
    1522          32 : }
    1523             : 
    1524             : static char *
    1525          16 : get_synchronized_snapshot(Archive *fout)
    1526             : {
    1527          16 :     char       *query = "SELECT pg_catalog.pg_export_snapshot()";
    1528             :     char       *result;
    1529             :     PGresult   *res;
    1530             : 
    1531          16 :     res = ExecuteSqlQueryForSingleRow(fout, query);
    1532          16 :     result = pg_strdup(PQgetvalue(res, 0, 0));
    1533          16 :     PQclear(res);
    1534             : 
    1535          16 :     return result;
    1536             : }
    1537             : 
    1538             : static ArchiveFormat
    1539         406 : parseArchiveFormat(const char *format, ArchiveMode *mode)
    1540             : {
    1541             :     ArchiveFormat archiveFormat;
    1542             : 
    1543         406 :     *mode = archModeWrite;
    1544             : 
    1545         406 :     if (pg_strcasecmp(format, "a") == 0 || pg_strcasecmp(format, "append") == 0)
    1546             :     {
    1547             :         /* This is used by pg_dumpall, and is not documented */
    1548          86 :         archiveFormat = archNull;
    1549          86 :         *mode = archModeAppend;
    1550             :     }
    1551         320 :     else if (pg_strcasecmp(format, "c") == 0)
    1552           0 :         archiveFormat = archCustom;
    1553         320 :     else if (pg_strcasecmp(format, "custom") == 0)
    1554          72 :         archiveFormat = archCustom;
    1555         248 :     else if (pg_strcasecmp(format, "d") == 0)
    1556           0 :         archiveFormat = archDirectory;
    1557         248 :     else if (pg_strcasecmp(format, "directory") == 0)
    1558          20 :         archiveFormat = archDirectory;
    1559         228 :     else if (pg_strcasecmp(format, "p") == 0)
    1560         214 :         archiveFormat = archNull;
    1561          14 :     else if (pg_strcasecmp(format, "plain") == 0)
    1562           6 :         archiveFormat = archNull;
    1563           8 :     else if (pg_strcasecmp(format, "t") == 0)
    1564           0 :         archiveFormat = archTar;
    1565           8 :     else if (pg_strcasecmp(format, "tar") == 0)
    1566           6 :         archiveFormat = archTar;
    1567             :     else
    1568           2 :         pg_fatal("invalid output format \"%s\" specified", format);
    1569         404 :     return archiveFormat;
    1570             : }
    1571             : 
    1572             : /*
    1573             :  * Find the OIDs of all schemas matching the given list of patterns,
    1574             :  * and append them to the given OID list.
    1575             :  */
    1576             : static void
    1577         410 : expand_schema_name_patterns(Archive *fout,
    1578             :                             SimpleStringList *patterns,
    1579             :                             SimpleOidList *oids,
    1580             :                             bool strict_names)
    1581             : {
    1582             :     PQExpBuffer query;
    1583             :     PGresult   *res;
    1584             :     SimpleStringListCell *cell;
    1585             :     int         i;
    1586             : 
    1587         410 :     if (patterns->head == NULL)
    1588         368 :         return;                 /* nothing to do */
    1589             : 
    1590          42 :     query = createPQExpBuffer();
    1591             : 
    1592             :     /*
    1593             :      * The loop below runs multiple SELECTs might sometimes result in
    1594             :      * duplicate entries in the OID list, but we don't care.
    1595             :      */
    1596             : 
    1597          72 :     for (cell = patterns->head; cell; cell = cell->next)
    1598             :     {
    1599             :         PQExpBufferData dbbuf;
    1600             :         int         dotcnt;
    1601             : 
    1602          42 :         appendPQExpBufferStr(query,
    1603             :                              "SELECT oid FROM pg_catalog.pg_namespace n\n");
    1604          42 :         initPQExpBuffer(&dbbuf);
    1605          42 :         processSQLNamePattern(GetConnection(fout), query, cell->val, false,
    1606             :                               false, NULL, "n.nspname", NULL, NULL, &dbbuf,
    1607             :                               &dotcnt);
    1608          42 :         if (dotcnt > 1)
    1609           4 :             pg_fatal("improper qualified name (too many dotted names): %s",
    1610             :                      cell->val);
    1611          38 :         else if (dotcnt == 1)
    1612           6 :             prohibit_crossdb_refs(GetConnection(fout), dbbuf.data, cell->val);
    1613          32 :         termPQExpBuffer(&dbbuf);
    1614             : 
    1615          32 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    1616          32 :         if (strict_names && PQntuples(res) == 0)
    1617           2 :             pg_fatal("no matching schemas were found for pattern \"%s\"", cell->val);
    1618             : 
    1619          58 :         for (i = 0; i < PQntuples(res); i++)
    1620             :         {
    1621          28 :             simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
    1622             :         }
    1623             : 
    1624          30 :         PQclear(res);
    1625          30 :         resetPQExpBuffer(query);
    1626             :     }
    1627             : 
    1628          30 :     destroyPQExpBuffer(query);
    1629             : }
    1630             : 
    1631             : /*
    1632             :  * Find the OIDs of all extensions matching the given list of patterns,
    1633             :  * and append them to the given OID list.
    1634             :  */
    1635             : static void
    1636         366 : expand_extension_name_patterns(Archive *fout,
    1637             :                                SimpleStringList *patterns,
    1638             :                                SimpleOidList *oids,
    1639             :                                bool strict_names)
    1640             : {
    1641             :     PQExpBuffer query;
    1642             :     PGresult   *res;
    1643             :     SimpleStringListCell *cell;
    1644             :     int         i;
    1645             : 
    1646         366 :     if (patterns->head == NULL)
    1647         352 :         return;                 /* nothing to do */
    1648             : 
    1649          14 :     query = createPQExpBuffer();
    1650             : 
    1651             :     /*
    1652             :      * The loop below runs multiple SELECTs might sometimes result in
    1653             :      * duplicate entries in the OID list, but we don't care.
    1654             :      */
    1655          28 :     for (cell = patterns->head; cell; cell = cell->next)
    1656             :     {
    1657             :         int         dotcnt;
    1658             : 
    1659          14 :         appendPQExpBufferStr(query,
    1660             :                              "SELECT oid FROM pg_catalog.pg_extension e\n");
    1661          14 :         processSQLNamePattern(GetConnection(fout), query, cell->val, false,
    1662             :                               false, NULL, "e.extname", NULL, NULL, NULL,
    1663             :                               &dotcnt);
    1664          14 :         if (dotcnt > 0)
    1665           0 :             pg_fatal("improper qualified name (too many dotted names): %s",
    1666             :                      cell->val);
    1667             : 
    1668          14 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    1669          14 :         if (strict_names && PQntuples(res) == 0)
    1670           0 :             pg_fatal("no matching extensions were found for pattern \"%s\"", cell->val);
    1671             : 
    1672          26 :         for (i = 0; i < PQntuples(res); i++)
    1673             :         {
    1674          12 :             simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
    1675             :         }
    1676             : 
    1677          14 :         PQclear(res);
    1678          14 :         resetPQExpBuffer(query);
    1679             :     }
    1680             : 
    1681          14 :     destroyPQExpBuffer(query);
    1682             : }
    1683             : 
    1684             : /*
    1685             :  * Find the OIDs of all foreign servers matching the given list of patterns,
    1686             :  * and append them to the given OID list.
    1687             :  */
    1688             : static void
    1689         360 : expand_foreign_server_name_patterns(Archive *fout,
    1690             :                                     SimpleStringList *patterns,
    1691             :                                     SimpleOidList *oids)
    1692             : {
    1693             :     PQExpBuffer query;
    1694             :     PGresult   *res;
    1695             :     SimpleStringListCell *cell;
    1696             :     int         i;
    1697             : 
    1698         360 :     if (patterns->head == NULL)
    1699         354 :         return;                 /* nothing to do */
    1700             : 
    1701           6 :     query = createPQExpBuffer();
    1702             : 
    1703             :     /*
    1704             :      * The loop below runs multiple SELECTs might sometimes result in
    1705             :      * duplicate entries in the OID list, but we don't care.
    1706             :      */
    1707             : 
    1708          10 :     for (cell = patterns->head; cell; cell = cell->next)
    1709             :     {
    1710             :         int         dotcnt;
    1711             : 
    1712           6 :         appendPQExpBufferStr(query,
    1713             :                              "SELECT oid FROM pg_catalog.pg_foreign_server s\n");
    1714           6 :         processSQLNamePattern(GetConnection(fout), query, cell->val, false,
    1715             :                               false, NULL, "s.srvname", NULL, NULL, NULL,
    1716             :                               &dotcnt);
    1717           6 :         if (dotcnt > 0)
    1718           0 :             pg_fatal("improper qualified name (too many dotted names): %s",
    1719             :                      cell->val);
    1720             : 
    1721           6 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    1722           6 :         if (PQntuples(res) == 0)
    1723           2 :             pg_fatal("no matching foreign servers were found for pattern \"%s\"", cell->val);
    1724             : 
    1725           8 :         for (i = 0; i < PQntuples(res); i++)
    1726           4 :             simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
    1727             : 
    1728           4 :         PQclear(res);
    1729           4 :         resetPQExpBuffer(query);
    1730             :     }
    1731             : 
    1732           4 :     destroyPQExpBuffer(query);
    1733             : }
    1734             : 
    1735             : /*
    1736             :  * Find the OIDs of all tables matching the given list of patterns,
    1737             :  * and append them to the given OID list. See also expand_dbname_patterns()
    1738             :  * in pg_dumpall.c
    1739             :  */
    1740             : static void
    1741        2178 : expand_table_name_patterns(Archive *fout,
    1742             :                            SimpleStringList *patterns, SimpleOidList *oids,
    1743             :                            bool strict_names, bool with_child_tables)
    1744             : {
    1745             :     PQExpBuffer query;
    1746             :     PGresult   *res;
    1747             :     SimpleStringListCell *cell;
    1748             :     int         i;
    1749             : 
    1750        2178 :     if (patterns->head == NULL)
    1751        2120 :         return;                 /* nothing to do */
    1752             : 
    1753          58 :     query = createPQExpBuffer();
    1754             : 
    1755             :     /*
    1756             :      * this might sometimes result in duplicate entries in the OID list, but
    1757             :      * we don't care.
    1758             :      */
    1759             : 
    1760         118 :     for (cell = patterns->head; cell; cell = cell->next)
    1761             :     {
    1762             :         PQExpBufferData dbbuf;
    1763             :         int         dotcnt;
    1764             : 
    1765             :         /*
    1766             :          * Query must remain ABSOLUTELY devoid of unqualified names.  This
    1767             :          * would be unnecessary given a pg_table_is_visible() variant taking a
    1768             :          * search_path argument.
    1769             :          *
    1770             :          * For with_child_tables, we start with the basic query's results and
    1771             :          * recursively search the inheritance tree to add child tables.
    1772             :          */
    1773          70 :         if (with_child_tables)
    1774             :         {
    1775          12 :             appendPQExpBuffer(query, "WITH RECURSIVE partition_tree (relid) AS (\n");
    1776             :         }
    1777             : 
    1778          70 :         appendPQExpBuffer(query,
    1779             :                           "SELECT c.oid"
    1780             :                           "\nFROM pg_catalog.pg_class c"
    1781             :                           "\n     LEFT JOIN pg_catalog.pg_namespace n"
    1782             :                           "\n     ON n.oid OPERATOR(pg_catalog.=) c.relnamespace"
    1783             :                           "\nWHERE c.relkind OPERATOR(pg_catalog.=) ANY"
    1784             :                           "\n    (array['%c', '%c', '%c', '%c', '%c', '%c'])\n",
    1785             :                           RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_VIEW,
    1786             :                           RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE,
    1787             :                           RELKIND_PARTITIONED_TABLE);
    1788          70 :         initPQExpBuffer(&dbbuf);
    1789          70 :         processSQLNamePattern(GetConnection(fout), query, cell->val, true,
    1790             :                               false, "n.nspname", "c.relname", NULL,
    1791             :                               "pg_catalog.pg_table_is_visible(c.oid)", &dbbuf,
    1792             :                               &dotcnt);
    1793          70 :         if (dotcnt > 2)
    1794           2 :             pg_fatal("improper relation name (too many dotted names): %s",
    1795             :                      cell->val);
    1796          68 :         else if (dotcnt == 2)
    1797           4 :             prohibit_crossdb_refs(GetConnection(fout), dbbuf.data, cell->val);
    1798          64 :         termPQExpBuffer(&dbbuf);
    1799             : 
    1800          64 :         if (with_child_tables)
    1801             :         {
    1802          12 :             appendPQExpBuffer(query, "UNION"
    1803             :                               "\nSELECT i.inhrelid"
    1804             :                               "\nFROM partition_tree p"
    1805             :                               "\n     JOIN pg_catalog.pg_inherits i"
    1806             :                               "\n     ON p.relid OPERATOR(pg_catalog.=) i.inhparent"
    1807             :                               "\n)"
    1808             :                               "\nSELECT relid FROM partition_tree");
    1809             :         }
    1810             : 
    1811          64 :         ExecuteSqlStatement(fout, "RESET search_path");
    1812          64 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    1813          64 :         PQclear(ExecuteSqlQueryForSingleRow(fout,
    1814             :                                             ALWAYS_SECURE_SEARCH_PATH_SQL));
    1815          64 :         if (strict_names && PQntuples(res) == 0)
    1816           4 :             pg_fatal("no matching tables were found for pattern \"%s\"", cell->val);
    1817             : 
    1818         148 :         for (i = 0; i < PQntuples(res); i++)
    1819             :         {
    1820          88 :             simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
    1821             :         }
    1822             : 
    1823          60 :         PQclear(res);
    1824          60 :         resetPQExpBuffer(query);
    1825             :     }
    1826             : 
    1827          48 :     destroyPQExpBuffer(query);
    1828             : }
    1829             : 
    1830             : /*
    1831             :  * Verifies that the connected database name matches the given database name,
    1832             :  * and if not, dies with an error about the given pattern.
    1833             :  *
    1834             :  * The 'dbname' argument should be a literal name parsed from 'pattern'.
    1835             :  */
    1836             : static void
    1837          10 : prohibit_crossdb_refs(PGconn *conn, const char *dbname, const char *pattern)
    1838             : {
    1839             :     const char *db;
    1840             : 
    1841          10 :     db = PQdb(conn);
    1842          10 :     if (db == NULL)
    1843           0 :         pg_fatal("You are currently not connected to a database.");
    1844             : 
    1845          10 :     if (strcmp(db, dbname) != 0)
    1846          10 :         pg_fatal("cross-database references are not implemented: %s",
    1847             :                  pattern);
    1848           0 : }
    1849             : 
    1850             : /*
    1851             :  * checkExtensionMembership
    1852             :  *      Determine whether object is an extension member, and if so,
    1853             :  *      record an appropriate dependency and set the object's dump flag.
    1854             :  *
    1855             :  * It's important to call this for each object that could be an extension
    1856             :  * member.  Generally, we integrate this with determining the object's
    1857             :  * to-be-dumped-ness, since extension membership overrides other rules for that.
    1858             :  *
    1859             :  * Returns true if object is an extension member, else false.
    1860             :  */
    1861             : static bool
    1862     1103688 : checkExtensionMembership(DumpableObject *dobj, Archive *fout)
    1863             : {
    1864     1103688 :     ExtensionInfo *ext = findOwningExtension(dobj->catId);
    1865             : 
    1866     1103688 :     if (ext == NULL)
    1867     1102148 :         return false;
    1868             : 
    1869        1540 :     dobj->ext_member = true;
    1870             : 
    1871             :     /* Record dependency so that getDependencies needn't deal with that */
    1872        1540 :     addObjectDependency(dobj, ext->dobj.dumpId);
    1873             : 
    1874             :     /*
    1875             :      * In 9.6 and above, mark the member object to have any non-initial ACLs
    1876             :      * dumped.  (Any initial ACLs will be removed later, using data from
    1877             :      * pg_init_privs, so that we'll dump only the delta from the extension's
    1878             :      * initial setup.)
    1879             :      *
    1880             :      * Prior to 9.6, we do not include any extension member components.
    1881             :      *
    1882             :      * In binary upgrades, we still dump all components of the members
    1883             :      * individually, since the idea is to exactly reproduce the database
    1884             :      * contents rather than replace the extension contents with something
    1885             :      * different.
    1886             :      *
    1887             :      * Note: it might be interesting someday to implement storage and delta
    1888             :      * dumping of extension members' RLS policies and/or security labels.
    1889             :      * However there is a pitfall for RLS policies: trying to dump them
    1890             :      * requires getting a lock on their tables, and the calling user might not
    1891             :      * have privileges for that.  We need no lock to examine a table's ACLs,
    1892             :      * so the current feature doesn't have a problem of that sort.
    1893             :      */
    1894        1540 :     if (fout->dopt->binary_upgrade)
    1895         288 :         dobj->dump = ext->dobj.dump;
    1896             :     else
    1897             :     {
    1898        1252 :         if (fout->remoteVersion < 90600)
    1899           0 :             dobj->dump = DUMP_COMPONENT_NONE;
    1900             :         else
    1901        1252 :             dobj->dump = ext->dobj.dump_contains & (DUMP_COMPONENT_ACL);
    1902             :     }
    1903             : 
    1904        1540 :     return true;
    1905             : }
    1906             : 
    1907             : /*
    1908             :  * selectDumpableNamespace: policy-setting subroutine
    1909             :  *      Mark a namespace as to be dumped or not
    1910             :  */
    1911             : static void
    1912        2716 : selectDumpableNamespace(NamespaceInfo *nsinfo, Archive *fout)
    1913             : {
    1914             :     /*
    1915             :      * DUMP_COMPONENT_DEFINITION typically implies a CREATE SCHEMA statement
    1916             :      * and (for --clean) a DROP SCHEMA statement.  (In the absence of
    1917             :      * DUMP_COMPONENT_DEFINITION, this value is irrelevant.)
    1918             :      */
    1919        2716 :     nsinfo->create = true;
    1920             : 
    1921             :     /*
    1922             :      * If specific tables are being dumped, do not dump any complete
    1923             :      * namespaces. If specific namespaces are being dumped, dump just those
    1924             :      * namespaces. Otherwise, dump all non-system namespaces.
    1925             :      */
    1926        2716 :     if (table_include_oids.head != NULL)
    1927         100 :         nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
    1928        2616 :     else if (schema_include_oids.head != NULL)
    1929         358 :         nsinfo->dobj.dump_contains = nsinfo->dobj.dump =
    1930         358 :             simple_oid_list_member(&schema_include_oids,
    1931             :                                    nsinfo->dobj.catId.oid) ?
    1932         358 :             DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
    1933        2258 :     else if (fout->remoteVersion >= 90600 &&
    1934        2258 :              strcmp(nsinfo->dobj.name, "pg_catalog") == 0)
    1935             :     {
    1936             :         /*
    1937             :          * In 9.6 and above, we dump out any ACLs defined in pg_catalog, if
    1938             :          * they are interesting (and not the original ACLs which were set at
    1939             :          * initdb time, see pg_init_privs).
    1940             :          */
    1941         312 :         nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_ACL;
    1942             :     }
    1943        1946 :     else if (strncmp(nsinfo->dobj.name, "pg_", 3) == 0 ||
    1944         946 :              strcmp(nsinfo->dobj.name, "information_schema") == 0)
    1945             :     {
    1946             :         /* Other system schemas don't get dumped */
    1947        1312 :         nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
    1948             :     }
    1949         634 :     else if (strcmp(nsinfo->dobj.name, "public") == 0)
    1950             :     {
    1951             :         /*
    1952             :          * The public schema is a strange beast that sits in a sort of
    1953             :          * no-mans-land between being a system object and a user object.
    1954             :          * CREATE SCHEMA would fail, so its DUMP_COMPONENT_DEFINITION is just
    1955             :          * a comment and an indication of ownership.  If the owner is the
    1956             :          * default, omit that superfluous DUMP_COMPONENT_DEFINITION.  Before
    1957             :          * v15, the default owner was BOOTSTRAP_SUPERUSERID.
    1958             :          */
    1959         304 :         nsinfo->create = false;
    1960         304 :         nsinfo->dobj.dump = DUMP_COMPONENT_ALL;
    1961         304 :         if (nsinfo->nspowner == ROLE_PG_DATABASE_OWNER)
    1962         212 :             nsinfo->dobj.dump &= ~DUMP_COMPONENT_DEFINITION;
    1963         304 :         nsinfo->dobj.dump_contains = DUMP_COMPONENT_ALL;
    1964             : 
    1965             :         /*
    1966             :          * Also, make like it has a comment even if it doesn't; this is so
    1967             :          * that we'll emit a command to drop the comment, if appropriate.
    1968             :          * (Without this, we'd not call dumpCommentExtended for it.)
    1969             :          */
    1970         304 :         nsinfo->dobj.components |= DUMP_COMPONENT_COMMENT;
    1971             :     }
    1972             :     else
    1973         330 :         nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_ALL;
    1974             : 
    1975             :     /*
    1976             :      * In any case, a namespace can be excluded by an exclusion switch
    1977             :      */
    1978        3684 :     if (nsinfo->dobj.dump_contains &&
    1979         968 :         simple_oid_list_member(&schema_exclude_oids,
    1980             :                                nsinfo->dobj.catId.oid))
    1981           6 :         nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
    1982             : 
    1983             :     /*
    1984             :      * If the schema belongs to an extension, allow extension membership to
    1985             :      * override the dump decision for the schema itself.  However, this does
    1986             :      * not change dump_contains, so this won't change what we do with objects
    1987             :      * within the schema.  (If they belong to the extension, they'll get
    1988             :      * suppressed by it, otherwise not.)
    1989             :      */
    1990        2716 :     (void) checkExtensionMembership(&nsinfo->dobj, fout);
    1991        2716 : }
    1992             : 
    1993             : /*
    1994             :  * selectDumpableTable: policy-setting subroutine
    1995             :  *      Mark a table as to be dumped or not
    1996             :  */
    1997             : static void
    1998       92334 : selectDumpableTable(TableInfo *tbinfo, Archive *fout)
    1999             : {
    2000       92334 :     if (checkExtensionMembership(&tbinfo->dobj, fout))
    2001         450 :         return;                 /* extension membership overrides all else */
    2002             : 
    2003             :     /*
    2004             :      * If specific tables are being dumped, dump just those tables; else, dump
    2005             :      * according to the parent namespace's dump flag.
    2006             :      */
    2007       91884 :     if (table_include_oids.head != NULL)
    2008       10128 :         tbinfo->dobj.dump = simple_oid_list_member(&table_include_oids,
    2009             :                                                    tbinfo->dobj.catId.oid) ?
    2010        5064 :             DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
    2011             :     else
    2012       86820 :         tbinfo->dobj.dump = tbinfo->dobj.namespace->dobj.dump_contains;
    2013             : 
    2014             :     /*
    2015             :      * In any case, a table can be excluded by an exclusion switch
    2016             :      */
    2017      149760 :     if (tbinfo->dobj.dump &&
    2018       57876 :         simple_oid_list_member(&table_exclude_oids,
    2019             :                                tbinfo->dobj.catId.oid))
    2020          24 :         tbinfo->dobj.dump = DUMP_COMPONENT_NONE;
    2021             : }
    2022             : 
    2023             : /*
    2024             :  * selectDumpableType: policy-setting subroutine
    2025             :  *      Mark a type as to be dumped or not
    2026             :  *
    2027             :  * If it's a table's rowtype or an autogenerated array type, we also apply a
    2028             :  * special type code to facilitate sorting into the desired order.  (We don't
    2029             :  * want to consider those to be ordinary types because that would bring tables
    2030             :  * up into the datatype part of the dump order.)  We still set the object's
    2031             :  * dump flag; that's not going to cause the dummy type to be dumped, but we
    2032             :  * need it so that casts involving such types will be dumped correctly -- see
    2033             :  * dumpCast.  This means the flag should be set the same as for the underlying
    2034             :  * object (the table or base type).
    2035             :  */
    2036             : static void
    2037      253526 : selectDumpableType(TypeInfo *tyinfo, Archive *fout)
    2038             : {
    2039             :     /* skip complex types, except for standalone composite types */
    2040      253526 :     if (OidIsValid(tyinfo->typrelid) &&
    2041       90886 :         tyinfo->typrelkind != RELKIND_COMPOSITE_TYPE)
    2042             :     {
    2043       90514 :         TableInfo  *tytable = findTableByOid(tyinfo->typrelid);
    2044             : 
    2045       90514 :         tyinfo->dobj.objType = DO_DUMMY_TYPE;
    2046       90514 :         if (tytable != NULL)
    2047       90514 :             tyinfo->dobj.dump = tytable->dobj.dump;
    2048             :         else
    2049           0 :             tyinfo->dobj.dump = DUMP_COMPONENT_NONE;
    2050       90514 :         return;
    2051             :     }
    2052             : 
    2053             :     /* skip auto-generated array and multirange types */
    2054      163012 :     if (tyinfo->isArray || tyinfo->isMultirange)
    2055             :     {
    2056      123978 :         tyinfo->dobj.objType = DO_DUMMY_TYPE;
    2057             : 
    2058             :         /*
    2059             :          * Fall through to set the dump flag; we assume that the subsequent
    2060             :          * rules will do the same thing as they would for the array's base
    2061             :          * type or multirange's range type.  (We cannot reliably look up the
    2062             :          * base type here, since getTypes may not have processed it yet.)
    2063             :          */
    2064             :     }
    2065             : 
    2066      163012 :     if (checkExtensionMembership(&tyinfo->dobj, fout))
    2067         300 :         return;                 /* extension membership overrides all else */
    2068             : 
    2069             :     /* Dump based on if the contents of the namespace are being dumped */
    2070      162712 :     tyinfo->dobj.dump = tyinfo->dobj.namespace->dobj.dump_contains;
    2071             : }
    2072             : 
    2073             : /*
    2074             :  * selectDumpableDefaultACL: policy-setting subroutine
    2075             :  *      Mark a default ACL as to be dumped or not
    2076             :  *
    2077             :  * For per-schema default ACLs, dump if the schema is to be dumped.
    2078             :  * Otherwise dump if we are dumping "everything".  Note that dumpSchema
    2079             :  * and aclsSkip are checked separately.
    2080             :  */
    2081             : static void
    2082         392 : selectDumpableDefaultACL(DefaultACLInfo *dinfo, DumpOptions *dopt)
    2083             : {
    2084             :     /* Default ACLs can't be extension members */
    2085             : 
    2086         392 :     if (dinfo->dobj.namespace)
    2087             :         /* default ACLs are considered part of the namespace */
    2088         196 :         dinfo->dobj.dump = dinfo->dobj.namespace->dobj.dump_contains;
    2089             :     else
    2090         196 :         dinfo->dobj.dump = dopt->include_everything ?
    2091         196 :             DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
    2092         392 : }
    2093             : 
    2094             : /*
    2095             :  * selectDumpableCast: policy-setting subroutine
    2096             :  *      Mark a cast as to be dumped or not
    2097             :  *
    2098             :  * Casts do not belong to any particular namespace (since they haven't got
    2099             :  * names), nor do they have identifiable owners.  To distinguish user-defined
    2100             :  * casts from built-in ones, we must resort to checking whether the cast's
    2101             :  * OID is in the range reserved for initdb.
    2102             :  */
    2103             : static void
    2104       81248 : selectDumpableCast(CastInfo *cast, Archive *fout)
    2105             : {
    2106       81248 :     if (checkExtensionMembership(&cast->dobj, fout))
    2107           0 :         return;                 /* extension membership overrides all else */
    2108             : 
    2109             :     /*
    2110             :      * This would be DUMP_COMPONENT_ACL for from-initdb casts, but they do not
    2111             :      * support ACLs currently.
    2112             :      */
    2113       81248 :     if (cast->dobj.catId.oid <= (Oid) g_last_builtin_oid)
    2114       81066 :         cast->dobj.dump = DUMP_COMPONENT_NONE;
    2115             :     else
    2116         182 :         cast->dobj.dump = fout->dopt->include_everything ?
    2117         182 :             DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
    2118             : }
    2119             : 
    2120             : /*
    2121             :  * selectDumpableProcLang: policy-setting subroutine
    2122             :  *      Mark a procedural language as to be dumped or not
    2123             :  *
    2124             :  * Procedural languages do not belong to any particular namespace.  To
    2125             :  * identify built-in languages, we must resort to checking whether the
    2126             :  * language's OID is in the range reserved for initdb.
    2127             :  */
    2128             : static void
    2129         452 : selectDumpableProcLang(ProcLangInfo *plang, Archive *fout)
    2130             : {
    2131         452 :     if (checkExtensionMembership(&plang->dobj, fout))
    2132         354 :         return;                 /* extension membership overrides all else */
    2133             : 
    2134             :     /*
    2135             :      * Only include procedural languages when we are dumping everything.
    2136             :      *
    2137             :      * For from-initdb procedural languages, only include ACLs, as we do for
    2138             :      * the pg_catalog namespace.  We need this because procedural languages do
    2139             :      * not live in any namespace.
    2140             :      */
    2141          98 :     if (!fout->dopt->include_everything)
    2142          16 :         plang->dobj.dump = DUMP_COMPONENT_NONE;
    2143             :     else
    2144             :     {
    2145          82 :         if (plang->dobj.catId.oid <= (Oid) g_last_builtin_oid)
    2146           0 :             plang->dobj.dump = fout->remoteVersion < 90600 ?
    2147           0 :                 DUMP_COMPONENT_NONE : DUMP_COMPONENT_ACL;
    2148             :         else
    2149          82 :             plang->dobj.dump = DUMP_COMPONENT_ALL;
    2150             :     }
    2151             : }
    2152             : 
    2153             : /*
    2154             :  * selectDumpableAccessMethod: policy-setting subroutine
    2155             :  *      Mark an access method as to be dumped or not
    2156             :  *
    2157             :  * Access methods do not belong to any particular namespace.  To identify
    2158             :  * built-in access methods, we must resort to checking whether the
    2159             :  * method's OID is in the range reserved for initdb.
    2160             :  */
    2161             : static void
    2162        2738 : selectDumpableAccessMethod(AccessMethodInfo *method, Archive *fout)
    2163             : {
    2164        2738 :     if (checkExtensionMembership(&method->dobj, fout))
    2165          50 :         return;                 /* extension membership overrides all else */
    2166             : 
    2167             :     /*
    2168             :      * This would be DUMP_COMPONENT_ACL for from-initdb access methods, but
    2169             :      * they do not support ACLs currently.
    2170             :      */
    2171        2688 :     if (method->dobj.catId.oid <= (Oid) g_last_builtin_oid)
    2172        2478 :         method->dobj.dump = DUMP_COMPONENT_NONE;
    2173             :     else
    2174         210 :         method->dobj.dump = fout->dopt->include_everything ?
    2175         210 :             DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
    2176             : }
    2177             : 
    2178             : /*
    2179             :  * selectDumpableExtension: policy-setting subroutine
    2180             :  *      Mark an extension as to be dumped or not
    2181             :  *
    2182             :  * Built-in extensions should be skipped except for checking ACLs, since we
    2183             :  * assume those will already be installed in the target database.  We identify
    2184             :  * such extensions by their having OIDs in the range reserved for initdb.
    2185             :  * We dump all user-added extensions by default.  No extensions are dumped
    2186             :  * if include_everything is false (i.e., a --schema or --table switch was
    2187             :  * given), except if --extension specifies a list of extensions to dump.
    2188             :  */
    2189             : static void
    2190         406 : selectDumpableExtension(ExtensionInfo *extinfo, DumpOptions *dopt)
    2191             : {
    2192             :     /*
    2193             :      * Use DUMP_COMPONENT_ACL for built-in extensions, to allow users to
    2194             :      * change permissions on their member objects, if they wish to, and have
    2195             :      * those changes preserved.
    2196             :      */
    2197         406 :     if (extinfo->dobj.catId.oid <= (Oid) g_last_builtin_oid)
    2198         356 :         extinfo->dobj.dump = extinfo->dobj.dump_contains = DUMP_COMPONENT_ACL;
    2199             :     else
    2200             :     {
    2201             :         /* check if there is a list of extensions to dump */
    2202          50 :         if (extension_include_oids.head != NULL)
    2203           8 :             extinfo->dobj.dump = extinfo->dobj.dump_contains =
    2204           8 :                 simple_oid_list_member(&extension_include_oids,
    2205             :                                        extinfo->dobj.catId.oid) ?
    2206           8 :                 DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
    2207             :         else
    2208          42 :             extinfo->dobj.dump = extinfo->dobj.dump_contains =
    2209          42 :                 dopt->include_everything ?
    2210          42 :                 DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
    2211             : 
    2212             :         /* check that the extension is not explicitly excluded */
    2213          92 :         if (extinfo->dobj.dump &&
    2214          42 :             simple_oid_list_member(&extension_exclude_oids,
    2215             :                                    extinfo->dobj.catId.oid))
    2216           4 :             extinfo->dobj.dump = extinfo->dobj.dump_contains = DUMP_COMPONENT_NONE;
    2217             :     }
    2218         406 : }
    2219             : 
    2220             : /*
    2221             :  * selectDumpablePublicationObject: policy-setting subroutine
    2222             :  *      Mark a publication object as to be dumped or not
    2223             :  *
    2224             :  * A publication can have schemas and tables which have schemas, but those are
    2225             :  * ignored in decision making, because publications are only dumped when we are
    2226             :  * dumping everything.
    2227             :  */
    2228             : static void
    2229         882 : selectDumpablePublicationObject(DumpableObject *dobj, Archive *fout)
    2230             : {
    2231         882 :     if (checkExtensionMembership(dobj, fout))
    2232           0 :         return;                 /* extension membership overrides all else */
    2233             : 
    2234         882 :     dobj->dump = fout->dopt->include_everything ?
    2235         882 :         DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
    2236             : }
    2237             : 
    2238             : /*
    2239             :  * selectDumpableStatisticsObject: policy-setting subroutine
    2240             :  *      Mark an extended statistics object as to be dumped or not
    2241             :  *
    2242             :  * We dump an extended statistics object if the schema it's in and the table
    2243             :  * it's for are being dumped.  (This'll need more thought if statistics
    2244             :  * objects ever support cross-table stats.)
    2245             :  */
    2246             : static void
    2247         350 : selectDumpableStatisticsObject(StatsExtInfo *sobj, Archive *fout)
    2248             : {
    2249         350 :     if (checkExtensionMembership(&sobj->dobj, fout))
    2250           0 :         return;                 /* extension membership overrides all else */
    2251             : 
    2252         350 :     sobj->dobj.dump = sobj->dobj.namespace->dobj.dump_contains;
    2253         350 :     if (sobj->stattable == NULL ||
    2254         350 :         !(sobj->stattable->dobj.dump & DUMP_COMPONENT_DEFINITION))
    2255          56 :         sobj->dobj.dump = DUMP_COMPONENT_NONE;
    2256             : }
    2257             : 
    2258             : /*
    2259             :  * selectDumpableObject: policy-setting subroutine
    2260             :  *      Mark a generic dumpable object as to be dumped or not
    2261             :  *
    2262             :  * Use this only for object types without a special-case routine above.
    2263             :  */
    2264             : static void
    2265      759956 : selectDumpableObject(DumpableObject *dobj, Archive *fout)
    2266             : {
    2267      759956 :     if (checkExtensionMembership(dobj, fout))
    2268         336 :         return;                 /* extension membership overrides all else */
    2269             : 
    2270             :     /*
    2271             :      * Default policy is to dump if parent namespace is dumpable, or for
    2272             :      * non-namespace-associated items, dump if we're dumping "everything".
    2273             :      */
    2274      759620 :     if (dobj->namespace)
    2275      758306 :         dobj->dump = dobj->namespace->dobj.dump_contains;
    2276             :     else
    2277        1314 :         dobj->dump = fout->dopt->include_everything ?
    2278        1314 :             DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
    2279             : }
    2280             : 
    2281             : /*
    2282             :  *  Dump a table's contents for loading using the COPY command
    2283             :  *  - this routine is called by the Archiver when it wants the table
    2284             :  *    to be dumped.
    2285             :  */
    2286             : static int
    2287        7632 : dumpTableData_copy(Archive *fout, const void *dcontext)
    2288             : {
    2289        7632 :     TableDataInfo *tdinfo = (TableDataInfo *) dcontext;
    2290        7632 :     TableInfo  *tbinfo = tdinfo->tdtable;
    2291        7632 :     const char *classname = tbinfo->dobj.name;
    2292        7632 :     PQExpBuffer q = createPQExpBuffer();
    2293             : 
    2294             :     /*
    2295             :      * Note: can't use getThreadLocalPQExpBuffer() here, we're calling fmtId
    2296             :      * which uses it already.
    2297             :      */
    2298        7632 :     PQExpBuffer clistBuf = createPQExpBuffer();
    2299        7632 :     PGconn     *conn = GetConnection(fout);
    2300             :     PGresult   *res;
    2301             :     int         ret;
    2302             :     char       *copybuf;
    2303             :     const char *column_list;
    2304             : 
    2305        7632 :     pg_log_info("dumping contents of table \"%s.%s\"",
    2306             :                 tbinfo->dobj.namespace->dobj.name, classname);
    2307             : 
    2308             :     /*
    2309             :      * Specify the column list explicitly so that we have no possibility of
    2310             :      * retrieving data in the wrong column order.  (The default column
    2311             :      * ordering of COPY will not be what we want in certain corner cases
    2312             :      * involving ADD COLUMN and inheritance.)
    2313             :      */
    2314        7632 :     column_list = fmtCopyColumnList(tbinfo, clistBuf);
    2315             : 
    2316             :     /*
    2317             :      * Use COPY (SELECT ...) TO when dumping a foreign table's data, and when
    2318             :      * a filter condition was specified.  For other cases a simple COPY
    2319             :      * suffices.
    2320             :      */
    2321        7632 :     if (tdinfo->filtercond || tbinfo->relkind == RELKIND_FOREIGN_TABLE)
    2322             :     {
    2323             :         /* Temporary allows to access to foreign tables to dump data */
    2324           2 :         if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
    2325           2 :             set_restrict_relation_kind(fout, "view");
    2326             : 
    2327           2 :         appendPQExpBufferStr(q, "COPY (SELECT ");
    2328             :         /* klugery to get rid of parens in column list */
    2329           2 :         if (strlen(column_list) > 2)
    2330             :         {
    2331           2 :             appendPQExpBufferStr(q, column_list + 1);
    2332           2 :             q->data[q->len - 1] = ' ';
    2333             :         }
    2334             :         else
    2335           0 :             appendPQExpBufferStr(q, "* ");
    2336             : 
    2337           4 :         appendPQExpBuffer(q, "FROM %s %s) TO stdout;",
    2338           2 :                           fmtQualifiedDumpable(tbinfo),
    2339           2 :                           tdinfo->filtercond ? tdinfo->filtercond : "");
    2340             :     }
    2341             :     else
    2342             :     {
    2343        7630 :         appendPQExpBuffer(q, "COPY %s %s TO stdout;",
    2344        7630 :                           fmtQualifiedDumpable(tbinfo),
    2345             :                           column_list);
    2346             :     }
    2347        7632 :     res = ExecuteSqlQuery(fout, q->data, PGRES_COPY_OUT);
    2348        7630 :     PQclear(res);
    2349        7630 :     destroyPQExpBuffer(clistBuf);
    2350             : 
    2351             :     for (;;)
    2352             :     {
    2353     3615628 :         ret = PQgetCopyData(conn, &copybuf, 0);
    2354             : 
    2355     3615628 :         if (ret < 0)
    2356        7630 :             break;              /* done or error */
    2357             : 
    2358     3607998 :         if (copybuf)
    2359             :         {
    2360     3607998 :             WriteData(fout, copybuf, ret);
    2361     3607998 :             PQfreemem(copybuf);
    2362             :         }
    2363             : 
    2364             :         /* ----------
    2365             :          * THROTTLE:
    2366             :          *
    2367             :          * There was considerable discussion in late July, 2000 regarding
    2368             :          * slowing down pg_dump when backing up large tables. Users with both
    2369             :          * slow & fast (multi-processor) machines experienced performance
    2370             :          * degradation when doing a backup.
    2371             :          *
    2372             :          * Initial attempts based on sleeping for a number of ms for each ms
    2373             :          * of work were deemed too complex, then a simple 'sleep in each loop'
    2374             :          * implementation was suggested. The latter failed because the loop
    2375             :          * was too tight. Finally, the following was implemented:
    2376             :          *
    2377             :          * If throttle is non-zero, then
    2378             :          *      See how long since the last sleep.
    2379             :          *      Work out how long to sleep (based on ratio).
    2380             :          *      If sleep is more than 100ms, then
    2381             :          *          sleep
    2382             :          *          reset timer
    2383             :          *      EndIf
    2384             :          * EndIf
    2385             :          *
    2386             :          * where the throttle value was the number of ms to sleep per ms of
    2387             :          * work. The calculation was done in each loop.
    2388             :          *
    2389             :          * Most of the hard work is done in the backend, and this solution
    2390             :          * still did not work particularly well: on slow machines, the ratio
    2391             :          * was 50:1, and on medium paced machines, 1:1, and on fast
    2392             :          * multi-processor machines, it had little or no effect, for reasons
    2393             :          * that were unclear.
    2394             :          *
    2395             :          * Further discussion ensued, and the proposal was dropped.
    2396             :          *
    2397             :          * For those people who want this feature, it can be implemented using
    2398             :          * gettimeofday in each loop, calculating the time since last sleep,
    2399             :          * multiplying that by the sleep ratio, then if the result is more
    2400             :          * than a preset 'minimum sleep time' (say 100ms), call the 'select'
    2401             :          * function to sleep for a subsecond period ie.
    2402             :          *
    2403             :          * select(0, NULL, NULL, NULL, &tvi);
    2404             :          *
    2405             :          * This will return after the interval specified in the structure tvi.
    2406             :          * Finally, call gettimeofday again to save the 'last sleep time'.
    2407             :          * ----------
    2408             :          */
    2409             :     }
    2410        7630 :     archprintf(fout, "\\.\n\n\n");
    2411             : 
    2412        7630 :     if (ret == -2)
    2413             :     {
    2414             :         /* copy data transfer failed */
    2415           0 :         pg_log_error("Dumping the contents of table \"%s\" failed: PQgetCopyData() failed.", classname);
    2416           0 :         pg_log_error_detail("Error message from server: %s", PQerrorMessage(conn));
    2417           0 :         pg_log_error_detail("Command was: %s", q->data);
    2418           0 :         exit_nicely(1);
    2419             :     }
    2420             : 
    2421             :     /* Check command status and return to normal libpq state */
    2422        7630 :     res = PQgetResult(conn);
    2423        7630 :     if (PQresultStatus(res) != PGRES_COMMAND_OK)
    2424             :     {
    2425           0 :         pg_log_error("Dumping the contents of table \"%s\" failed: PQgetResult() failed.", classname);
    2426           0 :         pg_log_error_detail("Error message from server: %s", PQerrorMessage(conn));
    2427           0 :         pg_log_error_detail("Command was: %s", q->data);
    2428           0 :         exit_nicely(1);
    2429             :     }
    2430        7630 :     PQclear(res);
    2431             : 
    2432             :     /* Do this to ensure we've pumped libpq back to idle state */
    2433        7630 :     if (PQgetResult(conn) != NULL)
    2434           0 :         pg_log_warning("unexpected extra results during COPY of table \"%s\"",
    2435             :                        classname);
    2436             : 
    2437        7630 :     destroyPQExpBuffer(q);
    2438             : 
    2439             :     /* Revert back the setting */
    2440        7630 :     if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
    2441           0 :         set_restrict_relation_kind(fout, "view, foreign-table");
    2442             : 
    2443        7630 :     return 1;
    2444             : }
    2445             : 
    2446             : /*
    2447             :  * Dump table data using INSERT commands.
    2448             :  *
    2449             :  * Caution: when we restore from an archive file direct to database, the
    2450             :  * INSERT commands emitted by this function have to be parsed by
    2451             :  * pg_backup_db.c's ExecuteSimpleCommands(), which will not handle comments,
    2452             :  * E'' strings, or dollar-quoted strings.  So don't emit anything like that.
    2453             :  */
    2454             : static int
    2455         142 : dumpTableData_insert(Archive *fout, const void *dcontext)
    2456             : {
    2457         142 :     TableDataInfo *tdinfo = (TableDataInfo *) dcontext;
    2458         142 :     TableInfo  *tbinfo = tdinfo->tdtable;
    2459         142 :     DumpOptions *dopt = fout->dopt;
    2460         142 :     PQExpBuffer q = createPQExpBuffer();
    2461         142 :     PQExpBuffer insertStmt = NULL;
    2462             :     char       *attgenerated;
    2463             :     PGresult   *res;
    2464             :     int         nfields,
    2465             :                 i;
    2466         142 :     int         rows_per_statement = dopt->dump_inserts;
    2467         142 :     int         rows_this_statement = 0;
    2468             : 
    2469             :     /* Temporary allows to access to foreign tables to dump data */
    2470         142 :     if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
    2471           0 :         set_restrict_relation_kind(fout, "view");
    2472             : 
    2473             :     /*
    2474             :      * If we're going to emit INSERTs with column names, the most efficient
    2475             :      * way to deal with generated columns is to exclude them entirely.  For
    2476             :      * INSERTs without column names, we have to emit DEFAULT rather than the
    2477             :      * actual column value --- but we can save a few cycles by fetching nulls
    2478             :      * rather than the uninteresting-to-us value.
    2479             :      */
    2480         142 :     attgenerated = (char *) pg_malloc(tbinfo->numatts * sizeof(char));
    2481         142 :     appendPQExpBufferStr(q, "DECLARE _pg_dump_cursor CURSOR FOR SELECT ");
    2482         142 :     nfields = 0;
    2483         466 :     for (i = 0; i < tbinfo->numatts; i++)
    2484             :     {
    2485         324 :         if (tbinfo->attisdropped[i])
    2486           4 :             continue;
    2487         320 :         if (tbinfo->attgenerated[i] && dopt->column_inserts)
    2488          16 :             continue;
    2489         304 :         if (nfields > 0)
    2490         176 :             appendPQExpBufferStr(q, ", ");
    2491         304 :         if (tbinfo->attgenerated[i])
    2492          16 :             appendPQExpBufferStr(q, "NULL");
    2493             :         else
    2494         288 :             appendPQExpBufferStr(q, fmtId(tbinfo->attnames[i]));
    2495         304 :         attgenerated[nfields] = tbinfo->attgenerated[i];
    2496         304 :         nfields++;
    2497             :     }
    2498             :     /* Servers before 9.4 will complain about zero-column SELECT */
    2499         142 :     if (nfields == 0)
    2500          14 :         appendPQExpBufferStr(q, "NULL");
    2501         142 :     appendPQExpBuffer(q, " FROM ONLY %s",
    2502         142 :                       fmtQualifiedDumpable(tbinfo));
    2503         142 :     if (tdinfo->filtercond)
    2504           0 :         appendPQExpBuffer(q, " %s", tdinfo->filtercond);
    2505             : 
    2506         142 :     ExecuteSqlStatement(fout, q->data);
    2507             : 
    2508             :     while (1)
    2509             :     {
    2510         246 :         res = ExecuteSqlQuery(fout, "FETCH 100 FROM _pg_dump_cursor",
    2511             :                               PGRES_TUPLES_OK);
    2512             : 
    2513             :         /* cross-check field count, allowing for dummy NULL if any */
    2514         246 :         if (nfields != PQnfields(res) &&
    2515          20 :             !(nfields == 0 && PQnfields(res) == 1))
    2516           0 :             pg_fatal("wrong number of fields retrieved from table \"%s\"",
    2517             :                      tbinfo->dobj.name);
    2518             : 
    2519             :         /*
    2520             :          * First time through, we build as much of the INSERT statement as
    2521             :          * possible in "insertStmt", which we can then just print for each
    2522             :          * statement. If the table happens to have zero dumpable columns then
    2523             :          * this will be a complete statement, otherwise it will end in
    2524             :          * "VALUES" and be ready to have the row's column values printed.
    2525             :          */
    2526         246 :         if (insertStmt == NULL)
    2527             :         {
    2528             :             TableInfo  *targettab;
    2529             : 
    2530         142 :             insertStmt = createPQExpBuffer();
    2531             : 
    2532             :             /*
    2533             :              * When load-via-partition-root is set or forced, get the root
    2534             :              * table name for the partition table, so that we can reload data
    2535             :              * through the root table.
    2536             :              */
    2537         142 :             if (tbinfo->ispartition &&
    2538          80 :                 (dopt->load_via_partition_root ||
    2539          40 :                  forcePartitionRootLoad(tbinfo)))
    2540           6 :                 targettab = getRootTableInfo(tbinfo);
    2541             :             else
    2542         136 :                 targettab = tbinfo;
    2543             : 
    2544         142 :             appendPQExpBuffer(insertStmt, "INSERT INTO %s ",
    2545         142 :                               fmtQualifiedDumpable(targettab));
    2546             : 
    2547             :             /* corner case for zero-column table */
    2548         142 :             if (nfields == 0)
    2549             :             {
    2550          14 :                 appendPQExpBufferStr(insertStmt, "DEFAULT VALUES;\n");
    2551             :             }
    2552             :             else
    2553             :             {
    2554             :                 /* append the list of column names if required */
    2555         128 :                 if (dopt->column_inserts)
    2556             :                 {
    2557          56 :                     appendPQExpBufferChar(insertStmt, '(');
    2558         182 :                     for (int field = 0; field < nfields; field++)
    2559             :                     {
    2560         126 :                         if (field > 0)
    2561          70 :                             appendPQExpBufferStr(insertStmt, ", ");
    2562         126 :                         appendPQExpBufferStr(insertStmt,
    2563         126 :                                              fmtId(PQfname(res, field)));
    2564             :                     }
    2565          56 :                     appendPQExpBufferStr(insertStmt, ") ");
    2566             :                 }
    2567             : 
    2568         128 :                 if (tbinfo->needs_override)
    2569           4 :                     appendPQExpBufferStr(insertStmt, "OVERRIDING SYSTEM VALUE ");
    2570             : 
    2571         128 :                 appendPQExpBufferStr(insertStmt, "VALUES");
    2572             :             }
    2573             :         }
    2574             : 
    2575        6788 :         for (int tuple = 0; tuple < PQntuples(res); tuple++)
    2576             :         {
    2577             :             /* Write the INSERT if not in the middle of a multi-row INSERT. */
    2578        6542 :             if (rows_this_statement == 0)
    2579        6530 :                 archputs(insertStmt->data, fout);
    2580             : 
    2581             :             /*
    2582             :              * If it is zero-column table then we've already written the
    2583             :              * complete statement, which will mean we've disobeyed
    2584             :              * --rows-per-insert when it's set greater than 1.  We do support
    2585             :              * a way to make this multi-row with: SELECT UNION ALL SELECT
    2586             :              * UNION ALL ... but that's non-standard so we should avoid it
    2587             :              * given that using INSERTs is mostly only ever needed for
    2588             :              * cross-database exports.
    2589             :              */
    2590        6542 :             if (nfields == 0)
    2591          12 :                 continue;
    2592             : 
    2593             :             /* Emit a row heading */
    2594        6530 :             if (rows_per_statement == 1)
    2595        6512 :                 archputs(" (", fout);
    2596          18 :             else if (rows_this_statement > 0)
    2597          12 :                 archputs(",\n\t(", fout);
    2598             :             else
    2599           6 :                 archputs("\n\t(", fout);
    2600             : 
    2601       19698 :             for (int field = 0; field < nfields; field++)
    2602             :             {
    2603       13168 :                 if (field > 0)
    2604        6638 :                     archputs(", ", fout);
    2605       13168 :                 if (attgenerated[field])
    2606             :                 {
    2607           4 :                     archputs("DEFAULT", fout);
    2608           4 :                     continue;
    2609             :                 }
    2610       13164 :                 if (PQgetisnull(res, tuple, field))
    2611             :                 {
    2612         166 :                     archputs("NULL", fout);
    2613         166 :                     continue;
    2614             :                 }
    2615             : 
    2616             :                 /* XXX This code is partially duplicated in ruleutils.c */
    2617       12998 :                 switch (PQftype(res, field))
    2618             :                 {
    2619        8938 :                     case INT2OID:
    2620             :                     case INT4OID:
    2621             :                     case INT8OID:
    2622             :                     case OIDOID:
    2623             :                     case FLOAT4OID:
    2624             :                     case FLOAT8OID:
    2625             :                     case NUMERICOID:
    2626             :                         {
    2627             :                             /*
    2628             :                              * These types are printed without quotes unless
    2629             :                              * they contain values that aren't accepted by the
    2630             :                              * scanner unquoted (e.g., 'NaN').  Note that
    2631             :                              * strtod() and friends might accept NaN, so we
    2632             :                              * can't use that to test.
    2633             :                              *
    2634             :                              * In reality we only need to defend against
    2635             :                              * infinity and NaN, so we need not get too crazy
    2636             :                              * about pattern matching here.
    2637             :                              */
    2638        8938 :                             const char *s = PQgetvalue(res, tuple, field);
    2639             : 
    2640        8938 :                             if (strspn(s, "0123456789 +-eE.") == strlen(s))
    2641        8934 :                                 archputs(s, fout);
    2642             :                             else
    2643           4 :                                 archprintf(fout, "'%s'", s);
    2644             :                         }
    2645        8938 :                         break;
    2646             : 
    2647           4 :                     case BITOID:
    2648             :                     case VARBITOID:
    2649           4 :                         archprintf(fout, "B'%s'",
    2650             :                                    PQgetvalue(res, tuple, field));
    2651           4 :                         break;
    2652             : 
    2653           8 :                     case BOOLOID:
    2654           8 :                         if (strcmp(PQgetvalue(res, tuple, field), "t") == 0)
    2655           4 :                             archputs("true", fout);
    2656             :                         else
    2657           4 :                             archputs("false", fout);
    2658           8 :                         break;
    2659             : 
    2660        4048 :                     default:
    2661             :                         /* All other types are printed as string literals. */
    2662        4048 :                         resetPQExpBuffer(q);
    2663        4048 :                         appendStringLiteralAH(q,
    2664             :                                               PQgetvalue(res, tuple, field),
    2665             :                                               fout);
    2666        4048 :                         archputs(q->data, fout);
    2667        4048 :                         break;
    2668             :                 }
    2669             :             }
    2670             : 
    2671             :             /* Terminate the row ... */
    2672        6530 :             archputs(")", fout);
    2673             : 
    2674             :             /* ... and the statement, if the target no. of rows is reached */
    2675        6530 :             if (++rows_this_statement >= rows_per_statement)
    2676             :             {
    2677        6516 :                 if (dopt->do_nothing)
    2678           0 :                     archputs(" ON CONFLICT DO NOTHING;\n", fout);
    2679             :                 else
    2680        6516 :                     archputs(";\n", fout);
    2681             :                 /* Reset the row counter */
    2682        6516 :                 rows_this_statement = 0;
    2683             :             }
    2684             :         }
    2685             : 
    2686         246 :         if (PQntuples(res) <= 0)
    2687             :         {
    2688         142 :             PQclear(res);
    2689         142 :             break;
    2690             :         }
    2691         104 :         PQclear(res);
    2692             :     }
    2693             : 
    2694             :     /* Terminate any statements that didn't make the row count. */
    2695         142 :     if (rows_this_statement > 0)
    2696             :     {
    2697           2 :         if (dopt->do_nothing)
    2698           0 :             archputs(" ON CONFLICT DO NOTHING;\n", fout);
    2699             :         else
    2700           2 :             archputs(";\n", fout);
    2701             :     }
    2702             : 
    2703         142 :     archputs("\n\n", fout);
    2704             : 
    2705         142 :     ExecuteSqlStatement(fout, "CLOSE _pg_dump_cursor");
    2706             : 
    2707         142 :     destroyPQExpBuffer(q);
    2708         142 :     if (insertStmt != NULL)
    2709         142 :         destroyPQExpBuffer(insertStmt);
    2710         142 :     free(attgenerated);
    2711             : 
    2712             :     /* Revert back the setting */
    2713         142 :     if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
    2714           0 :         set_restrict_relation_kind(fout, "view, foreign-table");
    2715             : 
    2716         142 :     return 1;
    2717             : }
    2718             : 
    2719             : /*
    2720             :  * getRootTableInfo:
    2721             :  *     get the root TableInfo for the given partition table.
    2722             :  */
    2723             : static TableInfo *
    2724          18 : getRootTableInfo(const TableInfo *tbinfo)
    2725             : {
    2726             :     TableInfo  *parentTbinfo;
    2727             : 
    2728             :     Assert(tbinfo->ispartition);
    2729             :     Assert(tbinfo->numParents == 1);
    2730             : 
    2731          18 :     parentTbinfo = tbinfo->parents[0];
    2732          18 :     while (parentTbinfo->ispartition)
    2733             :     {
    2734             :         Assert(parentTbinfo->numParents == 1);
    2735           0 :         parentTbinfo = parentTbinfo->parents[0];
    2736             :     }
    2737             : 
    2738          18 :     return parentTbinfo;
    2739             : }
    2740             : 
    2741             : /*
    2742             :  * forcePartitionRootLoad
    2743             :  *     Check if we must force load_via_partition_root for this partition.
    2744             :  *
    2745             :  * This is required if any level of ancestral partitioned table has an
    2746             :  * unsafe partitioning scheme.
    2747             :  */
    2748             : static bool
    2749        1966 : forcePartitionRootLoad(const TableInfo *tbinfo)
    2750             : {
    2751             :     TableInfo  *parentTbinfo;
    2752             : 
    2753             :     Assert(tbinfo->ispartition);
    2754             :     Assert(tbinfo->numParents == 1);
    2755             : 
    2756        1966 :     parentTbinfo = tbinfo->parents[0];
    2757        1966 :     if (parentTbinfo->unsafe_partitions)
    2758          18 :         return true;
    2759        2380 :     while (parentTbinfo->ispartition)
    2760             :     {
    2761             :         Assert(parentTbinfo->numParents == 1);
    2762         432 :         parentTbinfo = parentTbinfo->parents[0];
    2763         432 :         if (parentTbinfo->unsafe_partitions)
    2764           0 :             return true;
    2765             :     }
    2766             : 
    2767        1948 :     return false;
    2768             : }
    2769             : 
    2770             : /*
    2771             :  * dumpTableData -
    2772             :  *    dump the contents of a single table
    2773             :  *
    2774             :  * Actually, this just makes an ArchiveEntry for the table contents.
    2775             :  */
    2776             : static void
    2777        7914 : dumpTableData(Archive *fout, const TableDataInfo *tdinfo)
    2778             : {
    2779        7914 :     DumpOptions *dopt = fout->dopt;
    2780        7914 :     TableInfo  *tbinfo = tdinfo->tdtable;
    2781        7914 :     PQExpBuffer copyBuf = createPQExpBuffer();
    2782        7914 :     PQExpBuffer clistBuf = createPQExpBuffer();
    2783             :     DataDumperPtr dumpFn;
    2784        7914 :     char       *tdDefn = NULL;
    2785             :     char       *copyStmt;
    2786             :     const char *copyFrom;
    2787             : 
    2788             :     /* We had better have loaded per-column details about this table */
    2789             :     Assert(tbinfo->interesting);
    2790             : 
    2791             :     /*
    2792             :      * When load-via-partition-root is set or forced, get the root table name
    2793             :      * for the partition table, so that we can reload data through the root
    2794             :      * table.  Then construct a comment to be inserted into the TOC entry's
    2795             :      * defn field, so that such cases can be identified reliably.
    2796             :      */
    2797        7914 :     if (tbinfo->ispartition &&
    2798        3852 :         (dopt->load_via_partition_root ||
    2799        1926 :          forcePartitionRootLoad(tbinfo)))
    2800          12 :     {
    2801             :         TableInfo  *parentTbinfo;
    2802             : 
    2803          12 :         parentTbinfo = getRootTableInfo(tbinfo);
    2804          12 :         copyFrom = fmtQualifiedDumpable(parentTbinfo);
    2805          12 :         printfPQExpBuffer(copyBuf, "-- load via partition root %s",
    2806             :                           copyFrom);
    2807          12 :         tdDefn = pg_strdup(copyBuf->data);
    2808             :     }
    2809             :     else
    2810        7902 :         copyFrom = fmtQualifiedDumpable(tbinfo);
    2811             : 
    2812        7914 :     if (dopt->dump_inserts == 0)
    2813             :     {
    2814             :         /* Dump/restore using COPY */
    2815        7772 :         dumpFn = dumpTableData_copy;
    2816             :         /* must use 2 steps here 'cause fmtId is nonreentrant */
    2817        7772 :         printfPQExpBuffer(copyBuf, "COPY %s ",
    2818             :                           copyFrom);
    2819        7772 :         appendPQExpBuffer(copyBuf, "%s FROM stdin;\n",
    2820             :                           fmtCopyColumnList(tbinfo, clistBuf));
    2821        7772 :         copyStmt = copyBuf->data;
    2822             :     }
    2823             :     else
    2824             :     {
    2825             :         /* Restore using INSERT */
    2826         142 :         dumpFn = dumpTableData_insert;
    2827         142 :         copyStmt = NULL;
    2828             :     }
    2829             : 
    2830             :     /*
    2831             :      * Note: although the TableDataInfo is a full DumpableObject, we treat its
    2832             :      * dependency on its table as "special" and pass it to ArchiveEntry now.
    2833             :      * See comments for BuildArchiveDependencies.
    2834             :      */
    2835        7914 :     if (tdinfo->dobj.dump & DUMP_COMPONENT_DATA)
    2836             :     {
    2837             :         TocEntry   *te;
    2838             : 
    2839        7914 :         te = ArchiveEntry(fout, tdinfo->dobj.catId, tdinfo->dobj.dumpId,
    2840        7914 :                           ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
    2841             :                                        .namespace = tbinfo->dobj.namespace->dobj.name,
    2842             :                                        .owner = tbinfo->rolname,
    2843             :                                        .description = "TABLE DATA",
    2844             :                                        .section = SECTION_DATA,
    2845             :                                        .createStmt = tdDefn,
    2846             :                                        .copyStmt = copyStmt,
    2847             :                                        .deps = &(tbinfo->dobj.dumpId),
    2848             :                                        .nDeps = 1,
    2849             :                                        .dumpFn = dumpFn,
    2850             :                                        .dumpArg = tdinfo));
    2851             : 
    2852             :         /*
    2853             :          * Set the TocEntry's dataLength in case we are doing a parallel dump
    2854             :          * and want to order dump jobs by table size.  We choose to measure
    2855             :          * dataLength in table pages (including TOAST pages) during dump, so
    2856             :          * no scaling is needed.
    2857             :          *
    2858             :          * However, relpages is declared as "integer" in pg_class, and hence
    2859             :          * also in TableInfo, but it's really BlockNumber a/k/a unsigned int.
    2860             :          * Cast so that we get the right interpretation of table sizes
    2861             :          * exceeding INT_MAX pages.
    2862             :          */
    2863        7914 :         te->dataLength = (BlockNumber) tbinfo->relpages;
    2864        7914 :         te->dataLength += (BlockNumber) tbinfo->toastpages;
    2865             : 
    2866             :         /*
    2867             :          * If pgoff_t is only 32 bits wide, the above refinement is useless,
    2868             :          * and instead we'd better worry about integer overflow.  Clamp to
    2869             :          * INT_MAX if the correct result exceeds that.
    2870             :          */
    2871             :         if (sizeof(te->dataLength) == 4 &&
    2872             :             (tbinfo->relpages < 0 || tbinfo->toastpages < 0 ||
    2873             :              te->dataLength < 0))
    2874             :             te->dataLength = INT_MAX;
    2875             :     }
    2876             : 
    2877        7914 :     destroyPQExpBuffer(copyBuf);
    2878        7914 :     destroyPQExpBuffer(clistBuf);
    2879        7914 : }
    2880             : 
    2881             : /*
    2882             :  * refreshMatViewData -
    2883             :  *    load or refresh the contents of a single materialized view
    2884             :  *
    2885             :  * Actually, this just makes an ArchiveEntry for the REFRESH MATERIALIZED VIEW
    2886             :  * statement.
    2887             :  */
    2888             : static void
    2889         804 : refreshMatViewData(Archive *fout, const TableDataInfo *tdinfo)
    2890             : {
    2891         804 :     TableInfo  *tbinfo = tdinfo->tdtable;
    2892             :     PQExpBuffer q;
    2893             : 
    2894             :     /* If the materialized view is not flagged as populated, skip this. */
    2895         804 :     if (!tbinfo->relispopulated)
    2896         148 :         return;
    2897             : 
    2898         656 :     q = createPQExpBuffer();
    2899             : 
    2900         656 :     appendPQExpBuffer(q, "REFRESH MATERIALIZED VIEW %s;\n",
    2901         656 :                       fmtQualifiedDumpable(tbinfo));
    2902             : 
    2903         656 :     if (tdinfo->dobj.dump & DUMP_COMPONENT_DATA)
    2904         656 :         ArchiveEntry(fout,
    2905             :                      tdinfo->dobj.catId, /* catalog ID */
    2906             :                      tdinfo->dobj.dumpId,    /* dump ID */
    2907         656 :                      ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
    2908             :                                   .namespace = tbinfo->dobj.namespace->dobj.name,
    2909             :                                   .owner = tbinfo->rolname,
    2910             :                                   .description = "MATERIALIZED VIEW DATA",
    2911             :                                   .section = SECTION_POST_DATA,
    2912             :                                   .createStmt = q->data,
    2913             :                                   .deps = tdinfo->dobj.dependencies,
    2914             :                                   .nDeps = tdinfo->dobj.nDeps));
    2915             : 
    2916         656 :     destroyPQExpBuffer(q);
    2917             : }
    2918             : 
    2919             : /*
    2920             :  * getTableData -
    2921             :  *    set up dumpable objects representing the contents of tables
    2922             :  */
    2923             : static void
    2924         338 : getTableData(DumpOptions *dopt, TableInfo *tblinfo, int numTables, char relkind)
    2925             : {
    2926             :     int         i;
    2927             : 
    2928       88718 :     for (i = 0; i < numTables; i++)
    2929             :     {
    2930       88380 :         if (tblinfo[i].dobj.dump & DUMP_COMPONENT_DATA &&
    2931        1772 :             (!relkind || tblinfo[i].relkind == relkind))
    2932       11430 :             makeTableDataInfo(dopt, &(tblinfo[i]));
    2933             :     }
    2934         338 : }
    2935             : 
    2936             : /*
    2937             :  * Make a dumpable object for the data of this specific table
    2938             :  *
    2939             :  * Note: we make a TableDataInfo if and only if we are going to dump the
    2940             :  * table data; the "dump" field in such objects isn't very interesting.
    2941             :  */
    2942             : static void
    2943       11508 : makeTableDataInfo(DumpOptions *dopt, TableInfo *tbinfo)
    2944             : {
    2945             :     TableDataInfo *tdinfo;
    2946             : 
    2947             :     /*
    2948             :      * Nothing to do if we already decided to dump the table.  This will
    2949             :      * happen for "config" tables.
    2950             :      */
    2951       11508 :     if (tbinfo->dataObj != NULL)
    2952           2 :         return;
    2953             : 
    2954             :     /* Skip VIEWs (no data to dump) */
    2955       11506 :     if (tbinfo->relkind == RELKIND_VIEW)
    2956         942 :         return;
    2957             :     /* Skip FOREIGN TABLEs (no data to dump) unless requested explicitly */
    2958       10564 :     if (tbinfo->relkind == RELKIND_FOREIGN_TABLE &&
    2959          82 :         (foreign_servers_include_oids.head == NULL ||
    2960           8 :          !simple_oid_list_member(&foreign_servers_include_oids,
    2961             :                                  tbinfo->foreign_server)))
    2962          80 :         return;
    2963             :     /* Skip partitioned tables (data in partitions) */
    2964       10484 :     if (tbinfo->relkind == RELKIND_PARTITIONED_TABLE)
    2965         910 :         return;
    2966             : 
    2967             :     /* Don't dump data in unlogged tables, if so requested */
    2968        9574 :     if (tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED &&
    2969          82 :         dopt->no_unlogged_table_data)
    2970          36 :         return;
    2971             : 
    2972             :     /* Check that the data is not explicitly excluded */
    2973        9538 :     if (simple_oid_list_member(&tabledata_exclude_oids,
    2974             :                                tbinfo->dobj.catId.oid))
    2975          16 :         return;
    2976             : 
    2977             :     /* OK, let's dump it */
    2978        9522 :     tdinfo = (TableDataInfo *) pg_malloc(sizeof(TableDataInfo));
    2979             : 
    2980        9522 :     if (tbinfo->relkind == RELKIND_MATVIEW)
    2981         804 :         tdinfo->dobj.objType = DO_REFRESH_MATVIEW;
    2982        8718 :     else if (tbinfo->relkind == RELKIND_SEQUENCE)
    2983         804 :         tdinfo->dobj.objType = DO_SEQUENCE_SET;
    2984             :     else
    2985        7914 :         tdinfo->dobj.objType = DO_TABLE_DATA;
    2986             : 
    2987             :     /*
    2988             :      * Note: use tableoid 0 so that this object won't be mistaken for
    2989             :      * something that pg_depend entries apply to.
    2990             :      */
    2991        9522 :     tdinfo->dobj.catId.tableoid = 0;
    2992        9522 :     tdinfo->dobj.catId.oid = tbinfo->dobj.catId.oid;
    2993        9522 :     AssignDumpId(&tdinfo->dobj);
    2994        9522 :     tdinfo->dobj.name = tbinfo->dobj.name;
    2995        9522 :     tdinfo->dobj.namespace = tbinfo->dobj.namespace;
    2996        9522 :     tdinfo->tdtable = tbinfo;
    2997        9522 :     tdinfo->filtercond = NULL;   /* might get set later */
    2998        9522 :     addObjectDependency(&tdinfo->dobj, tbinfo->dobj.dumpId);
    2999             : 
    3000             :     /* A TableDataInfo contains data, of course */
    3001        9522 :     tdinfo->dobj.components |= DUMP_COMPONENT_DATA;
    3002             : 
    3003        9522 :     tbinfo->dataObj = tdinfo;
    3004             : 
    3005             :     /*
    3006             :      * Materialized view statistics must be restored after the data, because
    3007             :      * REFRESH MATERIALIZED VIEW replaces the storage and resets the stats.
    3008             :      *
    3009             :      * The dependency is added here because the statistics objects are created
    3010             :      * first.
    3011             :      */
    3012        9522 :     if (tbinfo->relkind == RELKIND_MATVIEW && tbinfo->stats != NULL)
    3013             :     {
    3014         692 :         tbinfo->stats->section = SECTION_POST_DATA;
    3015         692 :         addObjectDependency(&tbinfo->stats->dobj, tdinfo->dobj.dumpId);
    3016             :     }
    3017             : 
    3018             :     /* Make sure that we'll collect per-column info for this table. */
    3019        9522 :     tbinfo->interesting = true;
    3020             : }
    3021             : 
    3022             : /*
    3023             :  * The refresh for a materialized view must be dependent on the refresh for
    3024             :  * any materialized view that this one is dependent on.
    3025             :  *
    3026             :  * This must be called after all the objects are created, but before they are
    3027             :  * sorted.
    3028             :  */
    3029             : static void
    3030         282 : buildMatViewRefreshDependencies(Archive *fout)
    3031             : {
    3032             :     PQExpBuffer query;
    3033             :     PGresult   *res;
    3034             :     int         ntups,
    3035             :                 i;
    3036             :     int         i_classid,
    3037             :                 i_objid,
    3038             :                 i_refobjid;
    3039             : 
    3040             :     /* No Mat Views before 9.3. */
    3041         282 :     if (fout->remoteVersion < 90300)
    3042           0 :         return;
    3043             : 
    3044         282 :     query = createPQExpBuffer();
    3045             : 
    3046         282 :     appendPQExpBufferStr(query, "WITH RECURSIVE w AS "
    3047             :                          "( "
    3048             :                          "SELECT d1.objid, d2.refobjid, c2.relkind AS refrelkind "
    3049             :                          "FROM pg_depend d1 "
    3050             :                          "JOIN pg_class c1 ON c1.oid = d1.objid "
    3051             :                          "AND c1.relkind = " CppAsString2(RELKIND_MATVIEW)
    3052             :                          " JOIN pg_rewrite r1 ON r1.ev_class = d1.objid "
    3053             :                          "JOIN pg_depend d2 ON d2.classid = 'pg_rewrite'::regclass "
    3054             :                          "AND d2.objid = r1.oid "
    3055             :                          "AND d2.refobjid <> d1.objid "
    3056             :                          "JOIN pg_class c2 ON c2.oid = d2.refobjid "
    3057             :                          "AND c2.relkind IN (" CppAsString2(RELKIND_MATVIEW) ","
    3058             :                          CppAsString2(RELKIND_VIEW) ") "
    3059             :                          "WHERE d1.classid = 'pg_class'::regclass "
    3060             :                          "UNION "
    3061             :                          "SELECT w.objid, d3.refobjid, c3.relkind "
    3062             :                          "FROM w "
    3063             :                          "JOIN pg_rewrite r3 ON r3.ev_class = w.refobjid "
    3064             :                          "JOIN pg_depend d3 ON d3.classid = 'pg_rewrite'::regclass "
    3065             :                          "AND d3.objid = r3.oid "
    3066             :                          "AND d3.refobjid <> w.refobjid "
    3067             :                          "JOIN pg_class c3 ON c3.oid = d3.refobjid "
    3068             :                          "AND c3.relkind IN (" CppAsString2(RELKIND_MATVIEW) ","
    3069             :                          CppAsString2(RELKIND_VIEW) ") "
    3070             :                          ") "
    3071             :                          "SELECT 'pg_class'::regclass::oid AS classid, objid, refobjid "
    3072             :                          "FROM w "
    3073             :                          "WHERE refrelkind = " CppAsString2(RELKIND_MATVIEW));
    3074             : 
    3075         282 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    3076             : 
    3077         282 :     ntups = PQntuples(res);
    3078             : 
    3079         282 :     i_classid = PQfnumber(res, "classid");
    3080         282 :     i_objid = PQfnumber(res, "objid");
    3081         282 :     i_refobjid = PQfnumber(res, "refobjid");
    3082             : 
    3083         846 :     for (i = 0; i < ntups; i++)
    3084             :     {
    3085             :         CatalogId   objId;
    3086             :         CatalogId   refobjId;
    3087             :         DumpableObject *dobj;
    3088             :         DumpableObject *refdobj;
    3089             :         TableInfo  *tbinfo;
    3090             :         TableInfo  *reftbinfo;
    3091             : 
    3092         564 :         objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
    3093         564 :         objId.oid = atooid(PQgetvalue(res, i, i_objid));
    3094         564 :         refobjId.tableoid = objId.tableoid;
    3095         564 :         refobjId.oid = atooid(PQgetvalue(res, i, i_refobjid));
    3096             : 
    3097         564 :         dobj = findObjectByCatalogId(objId);
    3098         564 :         if (dobj == NULL)
    3099          96 :             continue;
    3100             : 
    3101             :         Assert(dobj->objType == DO_TABLE);
    3102         564 :         tbinfo = (TableInfo *) dobj;
    3103             :         Assert(tbinfo->relkind == RELKIND_MATVIEW);
    3104         564 :         dobj = (DumpableObject *) tbinfo->dataObj;
    3105         564 :         if (dobj == NULL)
    3106          96 :             continue;
    3107             :         Assert(dobj->objType == DO_REFRESH_MATVIEW);
    3108             : 
    3109         468 :         refdobj = findObjectByCatalogId(refobjId);
    3110         468 :         if (refdobj == NULL)
    3111           0 :             continue;
    3112             : 
    3113             :         Assert(refdobj->objType == DO_TABLE);
    3114         468 :         reftbinfo = (TableInfo *) refdobj;
    3115             :         Assert(reftbinfo->relkind == RELKIND_MATVIEW);
    3116         468 :         refdobj = (DumpableObject *) reftbinfo->dataObj;
    3117         468 :         if (refdobj == NULL)
    3118           0 :             continue;
    3119             :         Assert(refdobj->objType == DO_REFRESH_MATVIEW);
    3120             : 
    3121         468 :         addObjectDependency(dobj, refdobj->dumpId);
    3122             : 
    3123         468 :         if (!reftbinfo->relispopulated)
    3124          74 :             tbinfo->relispopulated = false;
    3125             :     }
    3126             : 
    3127         282 :     PQclear(res);
    3128             : 
    3129         282 :     destroyPQExpBuffer(query);
    3130             : }
    3131             : 
    3132             : /*
    3133             :  * getTableDataFKConstraints -
    3134             :  *    add dump-order dependencies reflecting foreign key constraints
    3135             :  *
    3136             :  * This code is executed only in a data-only dump --- in schema+data dumps
    3137             :  * we handle foreign key issues by not creating the FK constraints until
    3138             :  * after the data is loaded.  In a data-only dump, however, we want to
    3139             :  * order the table data objects in such a way that a table's referenced
    3140             :  * tables are restored first.  (In the presence of circular references or
    3141             :  * self-references this may be impossible; we'll detect and complain about
    3142             :  * that during the dependency sorting step.)
    3143             :  */
    3144             : static void
    3145          14 : getTableDataFKConstraints(void)
    3146             : {
    3147             :     DumpableObject **dobjs;
    3148             :     int         numObjs;
    3149             :     int         i;
    3150             : 
    3151             :     /* Search through all the dumpable objects for FK constraints */
    3152          14 :     getDumpableObjects(&dobjs, &numObjs);
    3153       50568 :     for (i = 0; i < numObjs; i++)
    3154             :     {
    3155       50554 :         if (dobjs[i]->objType == DO_FK_CONSTRAINT)
    3156             :         {
    3157          16 :             ConstraintInfo *cinfo = (ConstraintInfo *) dobjs[i];
    3158             :             TableInfo  *ftable;
    3159             : 
    3160             :             /* Not interesting unless both tables are to be dumped */
    3161          16 :             if (cinfo->contable == NULL ||
    3162          16 :                 cinfo->contable->dataObj == NULL)
    3163           8 :                 continue;
    3164           8 :             ftable = findTableByOid(cinfo->confrelid);
    3165           8 :             if (ftable == NULL ||
    3166           8 :                 ftable->dataObj == NULL)
    3167           0 :                 continue;
    3168             : 
    3169             :             /*
    3170             :              * Okay, make referencing table's TABLE_DATA object depend on the
    3171             :              * referenced table's TABLE_DATA object.
    3172             :              */
    3173           8 :             addObjectDependency(&cinfo->contable->dataObj->dobj,
    3174           8 :                                 ftable->dataObj->dobj.dumpId);
    3175             :         }
    3176             :     }
    3177          14 :     free(dobjs);
    3178          14 : }
    3179             : 
    3180             : 
    3181             : /*
    3182             :  * dumpDatabase:
    3183             :  *  dump the database definition
    3184             :  */
    3185             : static void
    3186         154 : dumpDatabase(Archive *fout)
    3187             : {
    3188         154 :     DumpOptions *dopt = fout->dopt;
    3189         154 :     PQExpBuffer dbQry = createPQExpBuffer();
    3190         154 :     PQExpBuffer delQry = createPQExpBuffer();
    3191         154 :     PQExpBuffer creaQry = createPQExpBuffer();
    3192         154 :     PQExpBuffer labelq = createPQExpBuffer();
    3193         154 :     PGconn     *conn = GetConnection(fout);
    3194             :     PGresult   *res;
    3195             :     int         i_tableoid,
    3196             :                 i_oid,
    3197             :                 i_datname,
    3198             :                 i_datdba,
    3199             :                 i_encoding,
    3200             :                 i_datlocprovider,
    3201             :                 i_collate,
    3202             :                 i_ctype,
    3203             :                 i_datlocale,
    3204             :                 i_daticurules,
    3205             :                 i_frozenxid,
    3206             :                 i_minmxid,
    3207             :                 i_datacl,
    3208             :                 i_acldefault,
    3209             :                 i_datistemplate,
    3210             :                 i_datconnlimit,
    3211             :                 i_datcollversion,
    3212             :                 i_tablespace;
    3213             :     CatalogId   dbCatId;
    3214             :     DumpId      dbDumpId;
    3215             :     DumpableAcl dbdacl;
    3216             :     const char *datname,
    3217             :                *dba,
    3218             :                *encoding,
    3219             :                *datlocprovider,
    3220             :                *collate,
    3221             :                *ctype,
    3222             :                *locale,
    3223             :                *icurules,
    3224             :                *datistemplate,
    3225             :                *datconnlimit,
    3226             :                *tablespace;
    3227             :     uint32      frozenxid,
    3228             :                 minmxid;
    3229             :     char       *qdatname;
    3230             : 
    3231         154 :     pg_log_info("saving database definition");
    3232             : 
    3233             :     /*
    3234             :      * Fetch the database-level properties for this database.
    3235             :      */
    3236         154 :     appendPQExpBufferStr(dbQry, "SELECT tableoid, oid, datname, "
    3237             :                          "datdba, "
    3238             :                          "pg_encoding_to_char(encoding) AS encoding, "
    3239             :                          "datcollate, datctype, datfrozenxid, "
    3240             :                          "datacl, acldefault('d', datdba) AS acldefault, "
    3241             :                          "datistemplate, datconnlimit, ");
    3242         154 :     if (fout->remoteVersion >= 90300)
    3243         154 :         appendPQExpBufferStr(dbQry, "datminmxid, ");
    3244             :     else
    3245           0 :         appendPQExpBufferStr(dbQry, "0 AS datminmxid, ");
    3246         154 :     if (fout->remoteVersion >= 170000)
    3247         154 :         appendPQExpBufferStr(dbQry, "datlocprovider, datlocale, datcollversion, ");
    3248           0 :     else if (fout->remoteVersion >= 150000)
    3249           0 :         appendPQExpBufferStr(dbQry, "datlocprovider, daticulocale AS datlocale, datcollversion, ");
    3250             :     else
    3251           0 :         appendPQExpBufferStr(dbQry, "'c' AS datlocprovider, NULL AS datlocale, NULL AS datcollversion, ");
    3252         154 :     if (fout->remoteVersion >= 160000)
    3253         154 :         appendPQExpBufferStr(dbQry, "daticurules, ");
    3254             :     else
    3255           0 :         appendPQExpBufferStr(dbQry, "NULL AS daticurules, ");
    3256         154 :     appendPQExpBufferStr(dbQry,
    3257             :                          "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace, "
    3258             :                          "shobj_description(oid, 'pg_database') AS description "
    3259             :                          "FROM pg_database "
    3260             :                          "WHERE datname = current_database()");
    3261             : 
    3262         154 :     res = ExecuteSqlQueryForSingleRow(fout, dbQry->data);
    3263             : 
    3264         154 :     i_tableoid = PQfnumber(res, "tableoid");
    3265         154 :     i_oid = PQfnumber(res, "oid");
    3266         154 :     i_datname = PQfnumber(res, "datname");
    3267         154 :     i_datdba = PQfnumber(res, "datdba");
    3268         154 :     i_encoding = PQfnumber(res, "encoding");
    3269         154 :     i_datlocprovider = PQfnumber(res, "datlocprovider");
    3270         154 :     i_collate = PQfnumber(res, "datcollate");
    3271         154 :     i_ctype = PQfnumber(res, "datctype");
    3272         154 :     i_datlocale = PQfnumber(res, "datlocale");
    3273         154 :     i_daticurules = PQfnumber(res, "daticurules");
    3274         154 :     i_frozenxid = PQfnumber(res, "datfrozenxid");
    3275         154 :     i_minmxid = PQfnumber(res, "datminmxid");
    3276         154 :     i_datacl = PQfnumber(res, "datacl");
    3277         154 :     i_acldefault = PQfnumber(res, "acldefault");
    3278         154 :     i_datistemplate = PQfnumber(res, "datistemplate");
    3279         154 :     i_datconnlimit = PQfnumber(res, "datconnlimit");
    3280         154 :     i_datcollversion = PQfnumber(res, "datcollversion");
    3281         154 :     i_tablespace = PQfnumber(res, "tablespace");
    3282             : 
    3283         154 :     dbCatId.tableoid = atooid(PQgetvalue(res, 0, i_tableoid));
    3284         154 :     dbCatId.oid = atooid(PQgetvalue(res, 0, i_oid));
    3285         154 :     datname = PQgetvalue(res, 0, i_datname);
    3286         154 :     dba = getRoleName(PQgetvalue(res, 0, i_datdba));
    3287         154 :     encoding = PQgetvalue(res, 0, i_encoding);
    3288         154 :     datlocprovider = PQgetvalue(res, 0, i_datlocprovider);
    3289         154 :     collate = PQgetvalue(res, 0, i_collate);
    3290         154 :     ctype = PQgetvalue(res, 0, i_ctype);
    3291         154 :     if (!PQgetisnull(res, 0, i_datlocale))
    3292          28 :         locale = PQgetvalue(res, 0, i_datlocale);
    3293             :     else
    3294         126 :         locale = NULL;
    3295         154 :     if (!PQgetisnull(res, 0, i_daticurules))
    3296           0 :         icurules = PQgetvalue(res, 0, i_daticurules);
    3297             :     else
    3298         154 :         icurules = NULL;
    3299         154 :     frozenxid = atooid(PQgetvalue(res, 0, i_frozenxid));
    3300         154 :     minmxid = atooid(PQgetvalue(res, 0, i_minmxid));
    3301         154 :     dbdacl.acl = PQgetvalue(res, 0, i_datacl);
    3302         154 :     dbdacl.acldefault = PQgetvalue(res, 0, i_acldefault);
    3303         154 :     datistemplate = PQgetvalue(res, 0, i_datistemplate);
    3304         154 :     datconnlimit = PQgetvalue(res, 0, i_datconnlimit);
    3305         154 :     tablespace = PQgetvalue(res, 0, i_tablespace);
    3306             : 
    3307         154 :     qdatname = pg_strdup(fmtId(datname));
    3308             : 
    3309             :     /*
    3310             :      * Prepare the CREATE DATABASE command.  We must specify OID (if we want
    3311             :      * to preserve that), as well as the encoding, locale, and tablespace
    3312             :      * since those can't be altered later.  Other DB properties are left to
    3313             :      * the DATABASE PROPERTIES entry, so that they can be applied after
    3314             :      * reconnecting to the target DB.
    3315             :      *
    3316             :      * For binary upgrade, we use the FILE_COPY strategy because testing has
    3317             :      * shown it to be faster.  When the server is in binary upgrade mode, it
    3318             :      * will also skip the checkpoints this strategy ordinarily performs.
    3319             :      */
    3320         154 :     if (dopt->binary_upgrade)
    3321             :     {
    3322          60 :         appendPQExpBuffer(creaQry,
    3323             :                           "CREATE DATABASE %s WITH TEMPLATE = template0 "
    3324             :                           "OID = %u STRATEGY = FILE_COPY",
    3325             :                           qdatname, dbCatId.oid);
    3326             :     }
    3327             :     else
    3328             :     {
    3329          94 :         appendPQExpBuffer(creaQry, "CREATE DATABASE %s WITH TEMPLATE = template0",
    3330             :                           qdatname);
    3331             :     }
    3332         154 :     if (strlen(encoding) > 0)
    3333             :     {
    3334         154 :         appendPQExpBufferStr(creaQry, " ENCODING = ");
    3335         154 :         appendStringLiteralAH(creaQry, encoding, fout);
    3336             :     }
    3337             : 
    3338         154 :     appendPQExpBufferStr(creaQry, " LOCALE_PROVIDER = ");
    3339         154 :     if (datlocprovider[0] == 'b')
    3340          28 :         appendPQExpBufferStr(creaQry, "builtin");
    3341         126 :     else if (datlocprovider[0] == 'c')
    3342         126 :         appendPQExpBufferStr(creaQry, "libc");
    3343           0 :     else if (datlocprovider[0] == 'i')
    3344           0 :         appendPQExpBufferStr(creaQry, "icu");
    3345             :     else
    3346           0 :         pg_fatal("unrecognized locale provider: %s",
    3347             :                  datlocprovider);
    3348             : 
    3349         154 :     if (strlen(collate) > 0 && strcmp(collate, ctype) == 0)
    3350             :     {
    3351         154 :         appendPQExpBufferStr(creaQry, " LOCALE = ");
    3352         154 :         appendStringLiteralAH(creaQry, collate, fout);
    3353             :     }
    3354             :     else
    3355             :     {
    3356           0 :         if (strlen(collate) > 0)
    3357             :         {
    3358           0 :             appendPQExpBufferStr(creaQry, " LC_COLLATE = ");
    3359           0 :             appendStringLiteralAH(creaQry, collate, fout);
    3360             :         }
    3361           0 :         if (strlen(ctype) > 0)
    3362             :         {
    3363           0 :             appendPQExpBufferStr(creaQry, " LC_CTYPE = ");
    3364           0 :             appendStringLiteralAH(creaQry, ctype, fout);
    3365             :         }
    3366             :     }
    3367         154 :     if (locale)
    3368             :     {
    3369          28 :         if (datlocprovider[0] == 'b')
    3370          28 :             appendPQExpBufferStr(creaQry, " BUILTIN_LOCALE = ");
    3371             :         else
    3372           0 :             appendPQExpBufferStr(creaQry, " ICU_LOCALE = ");
    3373             : 
    3374          28 :         appendStringLiteralAH(creaQry, locale, fout);
    3375             :     }
    3376             : 
    3377         154 :     if (icurules)
    3378             :     {
    3379           0 :         appendPQExpBufferStr(creaQry, " ICU_RULES = ");
    3380           0 :         appendStringLiteralAH(creaQry, icurules, fout);
    3381             :     }
    3382             : 
    3383             :     /*
    3384             :      * For binary upgrade, carry over the collation version.  For normal
    3385             :      * dump/restore, omit the version, so that it is computed upon restore.
    3386             :      */
    3387         154 :     if (dopt->binary_upgrade)
    3388             :     {
    3389          60 :         if (!PQgetisnull(res, 0, i_datcollversion))
    3390             :         {
    3391          60 :             appendPQExpBufferStr(creaQry, " COLLATION_VERSION = ");
    3392          60 :             appendStringLiteralAH(creaQry,
    3393             :                                   PQgetvalue(res, 0, i_datcollversion),
    3394             :                                   fout);
    3395             :         }
    3396             :     }
    3397             : 
    3398             :     /*
    3399             :      * Note: looking at dopt->outputNoTablespaces here is completely the wrong
    3400             :      * thing; the decision whether to specify a tablespace should be left till
    3401             :      * pg_restore, so that pg_restore --no-tablespaces applies.  Ideally we'd
    3402             :      * label the DATABASE entry with the tablespace and let the normal
    3403             :      * tablespace selection logic work ... but CREATE DATABASE doesn't pay
    3404             :      * attention to default_tablespace, so that won't work.
    3405             :      */
    3406         154 :     if (strlen(tablespace) > 0 && strcmp(tablespace, "pg_default") != 0 &&
    3407           0 :         !dopt->outputNoTablespaces)
    3408           0 :         appendPQExpBuffer(creaQry, " TABLESPACE = %s",
    3409             :                           fmtId(tablespace));
    3410         154 :     appendPQExpBufferStr(creaQry, ";\n");
    3411             : 
    3412         154 :     appendPQExpBuffer(delQry, "DROP DATABASE %s;\n",
    3413             :                       qdatname);
    3414             : 
    3415         154 :     dbDumpId = createDumpId();
    3416             : 
    3417         154 :     ArchiveEntry(fout,
    3418             :                  dbCatId,       /* catalog ID */
    3419             :                  dbDumpId,      /* dump ID */
    3420         154 :                  ARCHIVE_OPTS(.tag = datname,
    3421             :                               .owner = dba,
    3422             :                               .description = "DATABASE",
    3423             :                               .section = SECTION_PRE_DATA,
    3424             :                               .createStmt = creaQry->data,
    3425             :                               .dropStmt = delQry->data));
    3426             : 
    3427             :     /* Compute correct tag for archive entry */
    3428         154 :     appendPQExpBuffer(labelq, "DATABASE %s", qdatname);
    3429             : 
    3430             :     /* Dump DB comment if any */
    3431             :     {
    3432             :         /*
    3433             :          * 8.2 and up keep comments on shared objects in a shared table, so we
    3434             :          * cannot use the dumpComment() code used for other database objects.
    3435             :          * Be careful that the ArchiveEntry parameters match that function.
    3436             :          */
    3437         154 :         char       *comment = PQgetvalue(res, 0, PQfnumber(res, "description"));
    3438             : 
    3439         154 :         if (comment && *comment && !dopt->no_comments)
    3440             :         {
    3441          74 :             resetPQExpBuffer(dbQry);
    3442             : 
    3443             :             /*
    3444             :              * Generates warning when loaded into a differently-named
    3445             :              * database.
    3446             :              */
    3447          74 :             appendPQExpBuffer(dbQry, "COMMENT ON DATABASE %s IS ", qdatname);
    3448          74 :             appendStringLiteralAH(dbQry, comment, fout);
    3449          74 :             appendPQExpBufferStr(dbQry, ";\n");
    3450             : 
    3451          74 :             ArchiveEntry(fout, nilCatalogId, createDumpId(),
    3452          74 :                          ARCHIVE_OPTS(.tag = labelq->data,
    3453             :                                       .owner = dba,
    3454             :                                       .description = "COMMENT",
    3455             :                                       .section = SECTION_NONE,
    3456             :                                       .createStmt = dbQry->data,
    3457             :                                       .deps = &dbDumpId,
    3458             :                                       .nDeps = 1));
    3459             :         }
    3460             :     }
    3461             : 
    3462             :     /* Dump DB security label, if enabled */
    3463         154 :     if (!dopt->no_security_labels)
    3464             :     {
    3465             :         PGresult   *shres;
    3466             :         PQExpBuffer seclabelQry;
    3467             : 
    3468         154 :         seclabelQry = createPQExpBuffer();
    3469             : 
    3470         154 :         buildShSecLabelQuery("pg_database", dbCatId.oid, seclabelQry);
    3471         154 :         shres = ExecuteSqlQuery(fout, seclabelQry->data, PGRES_TUPLES_OK);
    3472         154 :         resetPQExpBuffer(seclabelQry);
    3473         154 :         emitShSecLabels(conn, shres, seclabelQry, "DATABASE", datname);
    3474         154 :         if (seclabelQry->len > 0)
    3475           0 :             ArchiveEntry(fout, nilCatalogId, createDumpId(),
    3476           0 :                          ARCHIVE_OPTS(.tag = labelq->data,
    3477             :                                       .owner = dba,
    3478             :                                       .description = "SECURITY LABEL",
    3479             :                                       .section = SECTION_NONE,
    3480             :                                       .createStmt = seclabelQry->data,
    3481             :                                       .deps = &dbDumpId,
    3482             :                                       .nDeps = 1));
    3483         154 :         destroyPQExpBuffer(seclabelQry);
    3484         154 :         PQclear(shres);
    3485             :     }
    3486             : 
    3487             :     /*
    3488             :      * Dump ACL if any.  Note that we do not support initial privileges
    3489             :      * (pg_init_privs) on databases.
    3490             :      */
    3491         154 :     dbdacl.privtype = 0;
    3492         154 :     dbdacl.initprivs = NULL;
    3493             : 
    3494         154 :     dumpACL(fout, dbDumpId, InvalidDumpId, "DATABASE",
    3495             :             qdatname, NULL, NULL,
    3496             :             NULL, dba, &dbdacl);
    3497             : 
    3498             :     /*
    3499             :      * Now construct a DATABASE PROPERTIES archive entry to restore any
    3500             :      * non-default database-level properties.  (The reason this must be
    3501             :      * separate is that we cannot put any additional commands into the TOC
    3502             :      * entry that has CREATE DATABASE.  pg_restore would execute such a group
    3503             :      * in an implicit transaction block, and the backend won't allow CREATE
    3504             :      * DATABASE in that context.)
    3505             :      */
    3506         154 :     resetPQExpBuffer(creaQry);
    3507         154 :     resetPQExpBuffer(delQry);
    3508             : 
    3509         154 :     if (strlen(datconnlimit) > 0 && strcmp(datconnlimit, "-1") != 0)
    3510           0 :         appendPQExpBuffer(creaQry, "ALTER DATABASE %s CONNECTION LIMIT = %s;\n",
    3511             :                           qdatname, datconnlimit);
    3512             : 
    3513         154 :     if (strcmp(datistemplate, "t") == 0)
    3514             :     {
    3515          20 :         appendPQExpBuffer(creaQry, "ALTER DATABASE %s IS_TEMPLATE = true;\n",
    3516             :                           qdatname);
    3517             : 
    3518             :         /*
    3519             :          * The backend won't accept DROP DATABASE on a template database.  We
    3520             :          * can deal with that by removing the template marking before the DROP
    3521             :          * gets issued.  We'd prefer to use ALTER DATABASE IF EXISTS here, but
    3522             :          * since no such command is currently supported, fake it with a direct
    3523             :          * UPDATE on pg_database.
    3524             :          */
    3525          20 :         appendPQExpBufferStr(delQry, "UPDATE pg_catalog.pg_database "
    3526             :                              "SET datistemplate = false WHERE datname = ");
    3527          20 :         appendStringLiteralAH(delQry, datname, fout);
    3528          20 :         appendPQExpBufferStr(delQry, ";\n");
    3529             :     }
    3530             : 
    3531             :     /*
    3532             :      * We do not restore pg_database.dathasloginevt because it is set
    3533             :      * automatically on login event trigger creation.
    3534             :      */
    3535             : 
    3536             :     /* Add database-specific SET options */
    3537         154 :     dumpDatabaseConfig(fout, creaQry, datname, dbCatId.oid);
    3538             : 
    3539             :     /*
    3540             :      * We stick this binary-upgrade query into the DATABASE PROPERTIES archive
    3541             :      * entry, too, for lack of a better place.
    3542             :      */
    3543         154 :     if (dopt->binary_upgrade)
    3544             :     {
    3545          60 :         appendPQExpBufferStr(creaQry, "\n-- For binary upgrade, set datfrozenxid and datminmxid.\n");
    3546          60 :         appendPQExpBuffer(creaQry, "UPDATE pg_catalog.pg_database\n"
    3547             :                           "SET datfrozenxid = '%u', datminmxid = '%u'\n"
    3548             :                           "WHERE datname = ",
    3549             :                           frozenxid, minmxid);
    3550          60 :         appendStringLiteralAH(creaQry, datname, fout);
    3551          60 :         appendPQExpBufferStr(creaQry, ";\n");
    3552             :     }
    3553             : 
    3554         154 :     if (creaQry->len > 0)
    3555          68 :         ArchiveEntry(fout, nilCatalogId, createDumpId(),
    3556          68 :                      ARCHIVE_OPTS(.tag = datname,
    3557             :                                   .owner = dba,
    3558             :                                   .description = "DATABASE PROPERTIES",
    3559             :                                   .section = SECTION_PRE_DATA,
    3560             :                                   .createStmt = creaQry->data,
    3561             :                                   .dropStmt = delQry->data,
    3562             :                                   .deps = &dbDumpId));
    3563             : 
    3564             :     /*
    3565             :      * pg_largeobject comes from the old system intact, so set its
    3566             :      * relfrozenxids, relminmxids and relfilenode.
    3567             :      */
    3568         154 :     if (dopt->binary_upgrade)
    3569             :     {
    3570             :         PGresult   *lo_res;
    3571          60 :         PQExpBuffer loFrozenQry = createPQExpBuffer();
    3572          60 :         PQExpBuffer loOutQry = createPQExpBuffer();
    3573          60 :         PQExpBuffer loHorizonQry = createPQExpBuffer();
    3574             :         int         ii_relfrozenxid,
    3575             :                     ii_relfilenode,
    3576             :                     ii_oid,
    3577             :                     ii_relminmxid;
    3578             : 
    3579             :         /*
    3580             :          * pg_largeobject
    3581             :          */
    3582          60 :         if (fout->remoteVersion >= 90300)
    3583          60 :             appendPQExpBuffer(loFrozenQry, "SELECT relfrozenxid, relminmxid, relfilenode, oid\n"
    3584             :                               "FROM pg_catalog.pg_class\n"
    3585             :                               "WHERE oid IN (%u, %u);\n",
    3586             :                               LargeObjectRelationId, LargeObjectLOidPNIndexId);
    3587             :         else
    3588           0 :             appendPQExpBuffer(loFrozenQry, "SELECT relfrozenxid, 0 AS relminmxid, relfilenode, oid\n"
    3589             :                               "FROM pg_catalog.pg_class\n"
    3590             :                               "WHERE oid IN (%u, %u);\n",
    3591             :                               LargeObjectRelationId, LargeObjectLOidPNIndexId);
    3592             : 
    3593          60 :         lo_res = ExecuteSqlQuery(fout, loFrozenQry->data, PGRES_TUPLES_OK);
    3594             : 
    3595          60 :         ii_relfrozenxid = PQfnumber(lo_res, "relfrozenxid");
    3596          60 :         ii_relminmxid = PQfnumber(lo_res, "relminmxid");
    3597          60 :         ii_relfilenode = PQfnumber(lo_res, "relfilenode");
    3598          60 :         ii_oid = PQfnumber(lo_res, "oid");
    3599             : 
    3600          60 :         appendPQExpBufferStr(loHorizonQry, "\n-- For binary upgrade, set pg_largeobject relfrozenxid and relminmxid\n");
    3601          60 :         appendPQExpBufferStr(loOutQry, "\n-- For binary upgrade, preserve pg_largeobject and index relfilenodes\n");
    3602         180 :         for (int i = 0; i < PQntuples(lo_res); ++i)
    3603             :         {
    3604             :             Oid         oid;
    3605             :             RelFileNumber relfilenumber;
    3606             : 
    3607         120 :             appendPQExpBuffer(loHorizonQry, "UPDATE pg_catalog.pg_class\n"
    3608             :                               "SET relfrozenxid = '%u', relminmxid = '%u'\n"
    3609             :                               "WHERE oid = %u;\n",
    3610         120 :                               atooid(PQgetvalue(lo_res, i, ii_relfrozenxid)),
    3611         120 :                               atooid(PQgetvalue(lo_res, i, ii_relminmxid)),
    3612         120 :                               atooid(PQgetvalue(lo_res, i, ii_oid)));
    3613             : 
    3614         120 :             oid = atooid(PQgetvalue(lo_res, i, ii_oid));
    3615         120 :             relfilenumber = atooid(PQgetvalue(lo_res, i, ii_relfilenode));
    3616             : 
    3617         120 :             if (oid == LargeObjectRelationId)
    3618          60 :                 appendPQExpBuffer(loOutQry,
    3619             :                                   "SELECT pg_catalog.binary_upgrade_set_next_heap_relfilenode('%u'::pg_catalog.oid);\n",
    3620             :                                   relfilenumber);
    3621          60 :             else if (oid == LargeObjectLOidPNIndexId)
    3622          60 :                 appendPQExpBuffer(loOutQry,
    3623             :                                   "SELECT pg_catalog.binary_upgrade_set_next_index_relfilenode('%u'::pg_catalog.oid);\n",
    3624             :                                   relfilenumber);
    3625             :         }
    3626             : 
    3627          60 :         appendPQExpBufferStr(loOutQry,
    3628             :                              "TRUNCATE pg_catalog.pg_largeobject;\n");
    3629          60 :         appendPQExpBufferStr(loOutQry, loHorizonQry->data);
    3630             : 
    3631          60 :         ArchiveEntry(fout, nilCatalogId, createDumpId(),
    3632          60 :                      ARCHIVE_OPTS(.tag = "pg_largeobject",
    3633             :                                   .description = "pg_largeobject",
    3634             :                                   .section = SECTION_PRE_DATA,
    3635             :                                   .createStmt = loOutQry->data));
    3636             : 
    3637          60 :         PQclear(lo_res);
    3638             : 
    3639          60 :         destroyPQExpBuffer(loFrozenQry);
    3640          60 :         destroyPQExpBuffer(loHorizonQry);
    3641          60 :         destroyPQExpBuffer(loOutQry);
    3642             :     }
    3643             : 
    3644         154 :     PQclear(res);
    3645             : 
    3646         154 :     free(qdatname);
    3647         154 :     destroyPQExpBuffer(dbQry);
    3648         154 :     destroyPQExpBuffer(delQry);
    3649         154 :     destroyPQExpBuffer(creaQry);
    3650         154 :     destroyPQExpBuffer(labelq);
    3651         154 : }
    3652             : 
    3653             : /*
    3654             :  * Collect any database-specific or role-and-database-specific SET options
    3655             :  * for this database, and append them to outbuf.
    3656             :  */
    3657             : static void
    3658         154 : dumpDatabaseConfig(Archive *AH, PQExpBuffer outbuf,
    3659             :                    const char *dbname, Oid dboid)
    3660             : {
    3661         154 :     PGconn     *conn = GetConnection(AH);
    3662         154 :     PQExpBuffer buf = createPQExpBuffer();
    3663             :     PGresult   *res;
    3664             : 
    3665             :     /* First collect database-specific options */
    3666         154 :     printfPQExpBuffer(buf, "SELECT unnest(setconfig) FROM pg_db_role_setting "
    3667             :                       "WHERE setrole = 0 AND setdatabase = '%u'::oid",
    3668             :                       dboid);
    3669             : 
    3670         154 :     res = ExecuteSqlQuery(AH, buf->data, PGRES_TUPLES_OK);
    3671             : 
    3672         214 :     for (int i = 0; i < PQntuples(res); i++)
    3673          60 :         makeAlterConfigCommand(conn, PQgetvalue(res, i, 0),
    3674             :                                "DATABASE", dbname, NULL, NULL,
    3675             :                                outbuf);
    3676             : 
    3677         154 :     PQclear(res);
    3678             : 
    3679             :     /* Now look for role-and-database-specific options */
    3680         154 :     printfPQExpBuffer(buf, "SELECT rolname, unnest(setconfig) "
    3681             :                       "FROM pg_db_role_setting s, pg_roles r "
    3682             :                       "WHERE setrole = r.oid AND setdatabase = '%u'::oid",
    3683             :                       dboid);
    3684             : 
    3685         154 :     res = ExecuteSqlQuery(AH, buf->data, PGRES_TUPLES_OK);
    3686             : 
    3687         154 :     for (int i = 0; i < PQntuples(res); i++)
    3688           0 :         makeAlterConfigCommand(conn, PQgetvalue(res, i, 1),
    3689           0 :                                "ROLE", PQgetvalue(res, i, 0),
    3690             :                                "DATABASE", dbname,
    3691             :                                outbuf);
    3692             : 
    3693         154 :     PQclear(res);
    3694             : 
    3695         154 :     destroyPQExpBuffer(buf);
    3696         154 : }
    3697             : 
    3698             : /*
    3699             :  * dumpEncoding: put the correct encoding into the archive
    3700             :  */
    3701             : static void
    3702         354 : dumpEncoding(Archive *AH)
    3703             : {
    3704         354 :     const char *encname = pg_encoding_to_char(AH->encoding);
    3705         354 :     PQExpBuffer qry = createPQExpBuffer();
    3706             : 
    3707         354 :     pg_log_info("saving encoding = %s", encname);
    3708             : 
    3709         354 :     appendPQExpBufferStr(qry, "SET client_encoding = ");
    3710         354 :     appendStringLiteralAH(qry, encname, AH);
    3711         354 :     appendPQExpBufferStr(qry, ";\n");
    3712             : 
    3713         354 :     ArchiveEntry(AH, nilCatalogId, createDumpId(),
    3714         354 :                  ARCHIVE_OPTS(.tag = "ENCODING",
    3715             :                               .description = "ENCODING",
    3716             :                               .section = SECTION_PRE_DATA,
    3717             :                               .createStmt = qry->data));
    3718             : 
    3719         354 :     destroyPQExpBuffer(qry);
    3720         354 : }
    3721             : 
    3722             : 
    3723             : /*
    3724             :  * dumpStdStrings: put the correct escape string behavior into the archive
    3725             :  */
    3726             : static void
    3727         354 : dumpStdStrings(Archive *AH)
    3728             : {
    3729         354 :     const char *stdstrings = AH->std_strings ? "on" : "off";
    3730         354 :     PQExpBuffer qry = createPQExpBuffer();
    3731             : 
    3732         354 :     pg_log_info("saving \"standard_conforming_strings = %s\"",
    3733             :                 stdstrings);
    3734             : 
    3735         354 :     appendPQExpBuffer(qry, "SET standard_conforming_strings = '%s';\n",
    3736             :                       stdstrings);
    3737             : 
    3738         354 :     ArchiveEntry(AH, nilCatalogId, createDumpId(),
    3739         354 :                  ARCHIVE_OPTS(.tag = "STDSTRINGS",
    3740             :                               .description = "STDSTRINGS",
    3741             :                               .section = SECTION_PRE_DATA,
    3742             :                               .createStmt = qry->data));
    3743             : 
    3744         354 :     destroyPQExpBuffer(qry);
    3745         354 : }
    3746             : 
    3747             : /*
    3748             :  * dumpSearchPath: record the active search_path in the archive
    3749             :  */
    3750             : static void
    3751         354 : dumpSearchPath(Archive *AH)
    3752             : {
    3753         354 :     PQExpBuffer qry = createPQExpBuffer();
    3754         354 :     PQExpBuffer path = createPQExpBuffer();
    3755             :     PGresult   *res;
    3756         354 :     char      **schemanames = NULL;
    3757         354 :     int         nschemanames = 0;
    3758             :     int         i;
    3759             : 
    3760             :     /*
    3761             :      * We use the result of current_schemas(), not the search_path GUC,
    3762             :      * because that might contain wildcards such as "$user", which won't
    3763             :      * necessarily have the same value during restore.  Also, this way avoids
    3764             :      * listing schemas that may appear in search_path but not actually exist,
    3765             :      * which seems like a prudent exclusion.
    3766             :      */
    3767         354 :     res = ExecuteSqlQueryForSingleRow(AH,
    3768             :                                       "SELECT pg_catalog.current_schemas(false)");
    3769             : 
    3770         354 :     if (!parsePGArray(PQgetvalue(res, 0, 0), &schemanames, &nschemanames))
    3771           0 :         pg_fatal("could not parse result of current_schemas()");
    3772             : 
    3773             :     /*
    3774             :      * We use set_config(), not a simple "SET search_path" command, because
    3775             :      * the latter has less-clean behavior if the search path is empty.  While
    3776             :      * that's likely to get fixed at some point, it seems like a good idea to
    3777             :      * be as backwards-compatible as possible in what we put into archives.
    3778             :      */
    3779         354 :     for (i = 0; i < nschemanames; i++)
    3780             :     {
    3781           0 :         if (i > 0)
    3782           0 :             appendPQExpBufferStr(path, ", ");
    3783           0 :         appendPQExpBufferStr(path, fmtId(schemanames[i]));
    3784             :     }
    3785             : 
    3786         354 :     appendPQExpBufferStr(qry, "SELECT pg_catalog.set_config('search_path', ");
    3787         354 :     appendStringLiteralAH(qry, path->data, AH);
    3788         354 :     appendPQExpBufferStr(qry, ", false);\n");
    3789             : 
    3790         354 :     pg_log_info("saving \"search_path = %s\"", path->data);
    3791             : 
    3792         354 :     ArchiveEntry(AH, nilCatalogId, createDumpId(),
    3793         354 :                  ARCHIVE_OPTS(.tag = "SEARCHPATH",
    3794             :                               .description = "SEARCHPATH",
    3795             :                               .section = SECTION_PRE_DATA,
    3796             :                               .createStmt = qry->data));
    3797             : 
    3798             :     /* Also save it in AH->searchpath, in case we're doing plain text dump */
    3799         354 :     AH->searchpath = pg_strdup(qry->data);
    3800             : 
    3801         354 :     free(schemanames);
    3802         354 :     PQclear(res);
    3803         354 :     destroyPQExpBuffer(qry);
    3804         354 :     destroyPQExpBuffer(path);
    3805         354 : }
    3806             : 
    3807             : 
    3808             : /*
    3809             :  * getLOs:
    3810             :  *  Collect schema-level data about large objects
    3811             :  */
    3812             : static void
    3813         296 : getLOs(Archive *fout)
    3814             : {
    3815         296 :     DumpOptions *dopt = fout->dopt;
    3816         296 :     PQExpBuffer loQry = createPQExpBuffer();
    3817             :     PGresult   *res;
    3818             :     int         ntups;
    3819             :     int         i;
    3820             :     int         n;
    3821             :     int         i_oid;
    3822             :     int         i_lomowner;
    3823             :     int         i_lomacl;
    3824             :     int         i_acldefault;
    3825             : 
    3826         296 :     pg_log_info("reading large objects");
    3827             : 
    3828             :     /*
    3829             :      * Fetch LO OIDs and owner/ACL data.  Order the data so that all the blobs
    3830             :      * with the same owner/ACL appear together.
    3831             :      */
    3832         296 :     appendPQExpBufferStr(loQry,
    3833             :                          "SELECT oid, lomowner, lomacl, "
    3834             :                          "acldefault('L', lomowner) AS acldefault "
    3835             :                          "FROM pg_largeobject_metadata "
    3836             :                          "ORDER BY lomowner, lomacl::pg_catalog.text, oid");
    3837             : 
    3838         296 :     res = ExecuteSqlQuery(fout, loQry->data, PGRES_TUPLES_OK);
    3839             : 
    3840         296 :     i_oid = PQfnumber(res, "oid");
    3841         296 :     i_lomowner = PQfnumber(res, "lomowner");
    3842         296 :     i_lomacl = PQfnumber(res, "lomacl");
    3843         296 :     i_acldefault = PQfnumber(res, "acldefault");
    3844             : 
    3845         296 :     ntups = PQntuples(res);
    3846             : 
    3847             :     /*
    3848             :      * Group the blobs into suitably-sized groups that have the same owner and
    3849             :      * ACL setting, and build a metadata and a data DumpableObject for each
    3850             :      * group.  (If we supported initprivs for blobs, we'd have to insist that
    3851             :      * groups also share initprivs settings, since the DumpableObject only has
    3852             :      * room for one.)  i is the index of the first tuple in the current group,
    3853             :      * and n is the number of tuples we include in the group.
    3854             :      */
    3855         454 :     for (i = 0; i < ntups; i += n)
    3856             :     {
    3857         158 :         Oid         thisoid = atooid(PQgetvalue(res, i, i_oid));
    3858         158 :         char       *thisowner = PQgetvalue(res, i, i_lomowner);
    3859         158 :         char       *thisacl = PQgetvalue(res, i, i_lomacl);
    3860             :         LoInfo     *loinfo;
    3861             :         DumpableObject *lodata;
    3862             :         char        namebuf[64];
    3863             : 
    3864             :         /* Scan to find first tuple not to be included in group */
    3865         158 :         n = 1;
    3866         178 :         while (n < MAX_BLOBS_PER_ARCHIVE_ENTRY && i + n < ntups)
    3867             :         {
    3868          94 :             if (strcmp(thisowner, PQgetvalue(res, i + n, i_lomowner)) != 0 ||
    3869          94 :                 strcmp(thisacl, PQgetvalue(res, i + n, i_lomacl)) != 0)
    3870             :                 break;
    3871          20 :             n++;
    3872             :         }
    3873             : 
    3874             :         /* Build the metadata DumpableObject */
    3875         158 :         loinfo = (LoInfo *) pg_malloc(offsetof(LoInfo, looids) + n * sizeof(Oid));
    3876             : 
    3877         158 :         loinfo->dobj.objType = DO_LARGE_OBJECT;
    3878         158 :         loinfo->dobj.catId.tableoid = LargeObjectRelationId;
    3879         158 :         loinfo->dobj.catId.oid = thisoid;
    3880         158 :         AssignDumpId(&loinfo->dobj);
    3881             : 
    3882         158 :         if (n > 1)
    3883          10 :             snprintf(namebuf, sizeof(namebuf), "%u..%u", thisoid,
    3884          10 :                      atooid(PQgetvalue(res, i + n - 1, i_oid)));
    3885             :         else
    3886         148 :             snprintf(namebuf, sizeof(namebuf), "%u", thisoid);
    3887         158 :         loinfo->dobj.name = pg_strdup(namebuf);
    3888         158 :         loinfo->dacl.acl = pg_strdup(thisacl);
    3889         158 :         loinfo->dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
    3890         158 :         loinfo->dacl.privtype = 0;
    3891         158 :         loinfo->dacl.initprivs = NULL;
    3892         158 :         loinfo->rolname = getRoleName(thisowner);
    3893         158 :         loinfo->numlos = n;
    3894         158 :         loinfo->looids[0] = thisoid;
    3895             :         /* Collect OIDs of the remaining blobs in this group */
    3896         178 :         for (int k = 1; k < n; k++)
    3897             :         {
    3898             :             CatalogId   extraID;
    3899             : 
    3900          20 :             loinfo->looids[k] = atooid(PQgetvalue(res, i + k, i_oid));
    3901             : 
    3902             :             /* Make sure we can look up loinfo by any of the blobs' OIDs */
    3903          20 :             extraID.tableoid = LargeObjectRelationId;
    3904          20 :             extraID.oid = loinfo->looids[k];
    3905          20 :             recordAdditionalCatalogID(extraID, &loinfo->dobj);
    3906             :         }
    3907             : 
    3908             :         /* LOs have data */
    3909         158 :         loinfo->dobj.components |= DUMP_COMPONENT_DATA;
    3910             : 
    3911             :         /* Mark whether LO group has a non-empty ACL */
    3912         158 :         if (!PQgetisnull(res, i, i_lomacl))
    3913          74 :             loinfo->dobj.components |= DUMP_COMPONENT_ACL;
    3914             : 
    3915             :         /*
    3916             :          * In binary-upgrade mode for LOs, we do *not* dump out the LO data,
    3917             :          * as it will be copied by pg_upgrade, which simply copies the
    3918             :          * pg_largeobject table. We *do* however dump out anything but the
    3919             :          * data, as pg_upgrade copies just pg_largeobject, but not
    3920             :          * pg_largeobject_metadata, after the dump is restored.
    3921             :          */
    3922         158 :         if (dopt->binary_upgrade)
    3923           6 :             loinfo->dobj.dump &= ~DUMP_COMPONENT_DATA;
    3924             : 
    3925             :         /*
    3926             :          * Create a "BLOBS" data item for the group, too. This is just a
    3927             :          * placeholder for sorting; it carries no data now.
    3928             :          */
    3929         158 :         lodata = (DumpableObject *) pg_malloc(sizeof(DumpableObject));
    3930         158 :         lodata->objType = DO_LARGE_OBJECT_DATA;
    3931         158 :         lodata->catId = nilCatalogId;
    3932         158 :         AssignDumpId(lodata);
    3933         158 :         lodata->name = pg_strdup(namebuf);
    3934         158 :         lodata->components |= DUMP_COMPONENT_DATA;
    3935             :         /* Set up explicit dependency from data to metadata */
    3936         158 :         lodata->dependencies = (DumpId *) pg_malloc(sizeof(DumpId));
    3937         158 :         lodata->dependencies[0] = loinfo->dobj.dumpId;
    3938         158 :         lodata->nDeps = lodata->allocDeps = 1;
    3939             :     }
    3940             : 
    3941         296 :     PQclear(res);
    3942         296 :     destroyPQExpBuffer(loQry);
    3943         296 : }
    3944             : 
    3945             : /*
    3946             :  * dumpLO
    3947             :  *
    3948             :  * dump the definition (metadata) of the given large object group
    3949             :  */
    3950             : static void
    3951         158 : dumpLO(Archive *fout, const LoInfo *loinfo)
    3952             : {
    3953         158 :     PQExpBuffer cquery = createPQExpBuffer();
    3954             : 
    3955             :     /*
    3956             :      * The "definition" is just a newline-separated list of OIDs.  We need to
    3957             :      * put something into the dropStmt too, but it can just be a comment.
    3958             :      */
    3959         336 :     for (int i = 0; i < loinfo->numlos; i++)
    3960         178 :         appendPQExpBuffer(cquery, "%u\n", loinfo->looids[i]);
    3961             : 
    3962         158 :     if (loinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
    3963         158 :         ArchiveEntry(fout, loinfo->dobj.catId, loinfo->dobj.dumpId,
    3964         158 :                      ARCHIVE_OPTS(.tag = loinfo->dobj.name,
    3965             :                                   .owner = loinfo->rolname,
    3966             :                                   .description = "BLOB METADATA",
    3967             :                                   .section = SECTION_DATA,
    3968             :                                   .createStmt = cquery->data,
    3969             :                                   .dropStmt = "-- dummy"));
    3970             : 
    3971             :     /*
    3972             :      * Dump per-blob comments and seclabels if any.  We assume these are rare
    3973             :      * enough that it's okay to generate retail TOC entries for them.
    3974             :      */
    3975         158 :     if (loinfo->dobj.dump & (DUMP_COMPONENT_COMMENT |
    3976             :                              DUMP_COMPONENT_SECLABEL))
    3977             :     {
    3978         188 :         for (int i = 0; i < loinfo->numlos; i++)
    3979             :         {
    3980             :             CatalogId   catId;
    3981             :             char        namebuf[32];
    3982             : 
    3983             :             /* Build identifying info for this blob */
    3984         104 :             catId.tableoid = loinfo->dobj.catId.tableoid;
    3985         104 :             catId.oid = loinfo->looids[i];
    3986         104 :             snprintf(namebuf, sizeof(namebuf), "%u", loinfo->looids[i]);
    3987             : 
    3988         104 :             if (loinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
    3989         104 :                 dumpComment(fout, "LARGE OBJECT", namebuf,
    3990             :                             NULL, loinfo->rolname,
    3991             :                             catId, 0, loinfo->dobj.dumpId);
    3992             : 
    3993         104 :             if (loinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
    3994           0 :                 dumpSecLabel(fout, "LARGE OBJECT", namebuf,
    3995             :                              NULL, loinfo->rolname,
    3996             :                              catId, 0, loinfo->dobj.dumpId);
    3997             :         }
    3998             :     }
    3999             : 
    4000             :     /*
    4001             :      * Dump the ACLs if any (remember that all blobs in the group will have
    4002             :      * the same ACL).  If there's just one blob, dump a simple ACL entry; if
    4003             :      * there's more, make a "LARGE OBJECTS" entry that really contains only
    4004             :      * the ACL for the first blob.  _printTocEntry() will be cued by the tag
    4005             :      * string to emit a mutated version for each blob.
    4006             :      */
    4007         158 :     if (loinfo->dobj.dump & DUMP_COMPONENT_ACL)
    4008             :     {
    4009             :         char        namebuf[32];
    4010             : 
    4011             :         /* Build identifying info for the first blob */
    4012          74 :         snprintf(namebuf, sizeof(namebuf), "%u", loinfo->looids[0]);
    4013             : 
    4014          74 :         if (loinfo->numlos > 1)
    4015             :         {
    4016             :             char        tagbuf[64];
    4017             : 
    4018           0 :             snprintf(tagbuf, sizeof(tagbuf), "LARGE OBJECTS %u..%u",
    4019           0 :                      loinfo->looids[0], loinfo->looids[loinfo->numlos - 1]);
    4020             : 
    4021           0 :             dumpACL(fout, loinfo->dobj.dumpId, InvalidDumpId,
    4022             :                     "LARGE OBJECT", namebuf, NULL, NULL,
    4023             :                     tagbuf, loinfo->rolname, &loinfo->dacl);
    4024             :         }
    4025             :         else
    4026             :         {
    4027          74 :             dumpACL(fout, loinfo->dobj.dumpId, InvalidDumpId,
    4028             :                     "LARGE OBJECT", namebuf, NULL, NULL,
    4029             :                     NULL, loinfo->rolname, &loinfo->dacl);
    4030             :         }
    4031             :     }
    4032             : 
    4033         158 :     destroyPQExpBuffer(cquery);
    4034         158 : }
    4035             : 
    4036             : /*
    4037             :  * dumpLOs:
    4038             :  *  dump the data contents of the large objects in the given group
    4039             :  */
    4040             : static int
    4041         144 : dumpLOs(Archive *fout, const void *arg)
    4042             : {
    4043         144 :     const LoInfo *loinfo = (const LoInfo *) arg;
    4044         144 :     PGconn     *conn = GetConnection(fout);
    4045             :     char        buf[LOBBUFSIZE];
    4046             : 
    4047         144 :     pg_log_info("saving large objects \"%s\"", loinfo->dobj.name);
    4048             : 
    4049         304 :     for (int i = 0; i < loinfo->numlos; i++)
    4050             :     {
    4051         160 :         Oid         loOid = loinfo->looids[i];
    4052             :         int         loFd;
    4053             :         int         cnt;
    4054             : 
    4055             :         /* Open the LO */
    4056         160 :         loFd = lo_open(conn, loOid, INV_READ);
    4057         160 :         if (loFd == -1)
    4058           0 :             pg_fatal("could not open large object %u: %s",
    4059             :                      loOid, PQerrorMessage(conn));
    4060             : 
    4061         160 :         StartLO(fout, loOid);
    4062             : 
    4063             :         /* Now read it in chunks, sending data to archive */
    4064             :         do
    4065             :         {
    4066         244 :             cnt = lo_read(conn, loFd, buf, LOBBUFSIZE);
    4067         244 :             if (cnt < 0)
    4068           0 :                 pg_fatal("error reading large object %u: %s",
    4069             :                          loOid, PQerrorMessage(conn));
    4070             : 
    4071         244 :             WriteData(fout, buf, cnt);
    4072         244 :         } while (cnt > 0);
    4073             : 
    4074         160 :         lo_close(conn, loFd);
    4075             : 
    4076         160 :         EndLO(fout, loOid);
    4077             :     }
    4078             : 
    4079         144 :     return 1;
    4080             : }
    4081             : 
    4082             : /*
    4083             :  * getPolicies
    4084             :  *    get information about all RLS policies on dumpable tables.
    4085             :  */
    4086             : void
    4087         354 : getPolicies(Archive *fout, TableInfo tblinfo[], int numTables)
    4088             : {
    4089         354 :     DumpOptions *dopt = fout->dopt;
    4090             :     PQExpBuffer query;
    4091             :     PQExpBuffer tbloids;
    4092             :     PGresult   *res;
    4093             :     PolicyInfo *polinfo;
    4094             :     int         i_oid;
    4095             :     int         i_tableoid;
    4096             :     int         i_polrelid;
    4097             :     int         i_polname;
    4098             :     int         i_polcmd;
    4099             :     int         i_polpermissive;
    4100             :     int         i_polroles;
    4101             :     int         i_polqual;
    4102             :     int         i_polwithcheck;
    4103             :     int         i,
    4104             :                 j,
    4105             :                 ntups;
    4106             : 
    4107             :     /* No policies before 9.5 */
    4108         354 :     if (fout->remoteVersion < 90500)
    4109           0 :         return;
    4110             : 
    4111             :     /* Skip if --no-policies was specified */
    4112         354 :     if (dopt->no_policies)
    4113           2 :         return;
    4114             : 
    4115         352 :     query = createPQExpBuffer();
    4116         352 :     tbloids = createPQExpBuffer();
    4117             : 
    4118             :     /*
    4119             :      * Identify tables of interest, and check which ones have RLS enabled.
    4120             :      */
    4121         352 :     appendPQExpBufferChar(tbloids, '{');
    4122       92016 :     for (i = 0; i < numTables; i++)
    4123             :     {
    4124       91664 :         TableInfo  *tbinfo = &tblinfo[i];
    4125             : 
    4126             :         /* Ignore row security on tables not to be dumped */
    4127       91664 :         if (!(tbinfo->dobj.dump & DUMP_COMPONENT_POLICY))
    4128       78288 :             continue;
    4129             : 
    4130             :         /* It can't have RLS or policies if it's not a table */
    4131       13376 :         if (tbinfo->relkind != RELKIND_RELATION &&
    4132        3950 :             tbinfo->relkind != RELKIND_PARTITIONED_TABLE)
    4133        2846 :             continue;
    4134             : 
    4135             :         /* Add it to the list of table OIDs to be probed below */
    4136       10530 :         if (tbloids->len > 1) /* do we have more than the '{'? */
    4137       10304 :             appendPQExpBufferChar(tbloids, ',');
    4138       10530 :         appendPQExpBuffer(tbloids, "%u", tbinfo->dobj.catId.oid);
    4139             : 
    4140             :         /* Is RLS enabled?  (That's separate from whether it has policies) */
    4141       10530 :         if (tbinfo->rowsec)
    4142             :         {
    4143         114 :             tbinfo->dobj.components |= DUMP_COMPONENT_POLICY;
    4144             : 
    4145             :             /*
    4146             :              * We represent RLS being enabled on a table by creating a
    4147             :              * PolicyInfo object with null polname.
    4148             :              *
    4149             :              * Note: use tableoid 0 so that this object won't be mistaken for
    4150             :              * something that pg_depend entries apply to.
    4151             :              */
    4152         114 :             polinfo = pg_malloc(sizeof(PolicyInfo));
    4153         114 :             polinfo->dobj.objType = DO_POLICY;
    4154         114 :             polinfo->dobj.catId.tableoid = 0;
    4155         114 :             polinfo->dobj.catId.oid = tbinfo->dobj.catId.oid;
    4156         114 :             AssignDumpId(&polinfo->dobj);
    4157         114 :             polinfo->dobj.namespace = tbinfo->dobj.namespace;
    4158         114 :             polinfo->dobj.name = pg_strdup(tbinfo->dobj.name);
    4159         114 :             polinfo->poltable = tbinfo;
    4160         114 :             polinfo->polname = NULL;
    4161         114 :             polinfo->polcmd = '\0';
    4162         114 :             polinfo->polpermissive = 0;
    4163         114 :             polinfo->polroles = NULL;
    4164         114 :             polinfo->polqual = NULL;
    4165         114 :             polinfo->polwithcheck = NULL;
    4166             :         }
    4167             :     }
    4168         352 :     appendPQExpBufferChar(tbloids, '}');
    4169             : 
    4170             :     /*
    4171             :      * Now, read all RLS policies belonging to the tables of interest, and
    4172             :      * create PolicyInfo objects for them.  (Note that we must filter the
    4173             :      * results server-side not locally, because we dare not apply pg_get_expr
    4174             :      * to tables we don't have lock on.)
    4175             :      */
    4176         352 :     pg_log_info("reading row-level security policies");
    4177             : 
    4178         352 :     printfPQExpBuffer(query,
    4179             :                       "SELECT pol.oid, pol.tableoid, pol.polrelid, pol.polname, pol.polcmd, ");
    4180         352 :     if (fout->remoteVersion >= 100000)
    4181         352 :         appendPQExpBufferStr(query, "pol.polpermissive, ");
    4182             :     else
    4183           0 :         appendPQExpBufferStr(query, "'t' as polpermissive, ");
    4184         352 :     appendPQExpBuffer(query,
    4185             :                       "CASE WHEN pol.polroles = '{0}' THEN NULL ELSE "
    4186             :                       "   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, "
    4187             :                       "pg_catalog.pg_get_expr(pol.polqual, pol.polrelid) AS polqual, "
    4188             :                       "pg_catalog.pg_get_expr(pol.polwithcheck, pol.polrelid) AS polwithcheck "
    4189             :                       "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
    4190             :                       "JOIN pg_catalog.pg_policy pol ON (src.tbloid = pol.polrelid)",
    4191             :                       tbloids->data);
    4192             : 
    4193         352 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    4194             : 
    4195         352 :     ntups = PQntuples(res);
    4196         352 :     if (ntups > 0)
    4197             :     {
    4198          94 :         i_oid = PQfnumber(res, "oid");
    4199          94 :         i_tableoid = PQfnumber(res, "tableoid");
    4200          94 :         i_polrelid = PQfnumber(res, "polrelid");
    4201          94 :         i_polname = PQfnumber(res, "polname");
    4202          94 :         i_polcmd = PQfnumber(res, "polcmd");
    4203          94 :         i_polpermissive = PQfnumber(res, "polpermissive");
    4204          94 :         i_polroles = PQfnumber(res, "polroles");
    4205          94 :         i_polqual = PQfnumber(res, "polqual");
    4206          94 :         i_polwithcheck = PQfnumber(res, "polwithcheck");
    4207             : 
    4208          94 :         polinfo = pg_malloc(ntups * sizeof(PolicyInfo));
    4209             : 
    4210         688 :         for (j = 0; j < ntups; j++)
    4211             :         {
    4212         594 :             Oid         polrelid = atooid(PQgetvalue(res, j, i_polrelid));
    4213         594 :             TableInfo  *tbinfo = findTableByOid(polrelid);
    4214             : 
    4215         594 :             tbinfo->dobj.components |= DUMP_COMPONENT_POLICY;
    4216             : 
    4217         594 :             polinfo[j].dobj.objType = DO_POLICY;
    4218         594 :             polinfo[j].dobj.catId.tableoid =
    4219         594 :                 atooid(PQgetvalue(res, j, i_tableoid));
    4220         594 :             polinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
    4221         594 :             AssignDumpId(&polinfo[j].dobj);
    4222         594 :             polinfo[j].dobj.namespace = tbinfo->dobj.namespace;
    4223         594 :             polinfo[j].poltable = tbinfo;
    4224         594 :             polinfo[j].polname = pg_strdup(PQgetvalue(res, j, i_polname));
    4225         594 :             polinfo[j].dobj.name = pg_strdup(polinfo[j].polname);
    4226             : 
    4227         594 :             polinfo[j].polcmd = *(PQgetvalue(res, j, i_polcmd));
    4228         594 :             polinfo[j].polpermissive = *(PQgetvalue(res, j, i_polpermissive)) == 't';
    4229             : 
    4230         594 :             if (PQgetisnull(res, j, i_polroles))
    4231         258 :                 polinfo[j].polroles = NULL;
    4232             :             else
    4233         336 :                 polinfo[j].polroles = pg_strdup(PQgetvalue(res, j, i_polroles));
    4234             : 
    4235         594 :             if (PQgetisnull(res, j, i_polqual))
    4236          84 :                 polinfo[j].polqual = NULL;
    4237             :             else
    4238         510 :                 polinfo[j].polqual = pg_strdup(PQgetvalue(res, j, i_polqual));
    4239             : 
    4240         594 :             if (PQgetisnull(res, j, i_polwithcheck))
    4241         312 :                 polinfo[j].polwithcheck = NULL;
    4242             :             else
    4243         282 :                 polinfo[j].polwithcheck
    4244         282 :                     = pg_strdup(PQgetvalue(res, j, i_polwithcheck));
    4245             :         }
    4246             :     }
    4247             : 
    4248         352 :     PQclear(res);
    4249             : 
    4250         352 :     destroyPQExpBuffer(query);
    4251         352 :     destroyPQExpBuffer(tbloids);
    4252             : }
    4253             : 
    4254             : /*
    4255             :  * dumpPolicy
    4256             :  *    dump the definition of the given policy
    4257             :  */
    4258             : static void
    4259         708 : dumpPolicy(Archive *fout, const PolicyInfo *polinfo)
    4260             : {
    4261         708 :     DumpOptions *dopt = fout->dopt;
    4262         708 :     TableInfo  *tbinfo = polinfo->poltable;
    4263             :     PQExpBuffer query;
    4264             :     PQExpBuffer delqry;
    4265             :     PQExpBuffer polprefix;
    4266             :     char       *qtabname;
    4267             :     const char *cmd;
    4268             :     char       *tag;
    4269             : 
    4270             :     /* Do nothing if not dumping schema */
    4271         708 :     if (!dopt->dumpSchema)
    4272          98 :         return;
    4273             : 
    4274             :     /*
    4275             :      * If polname is NULL, then this record is just indicating that ROW LEVEL
    4276             :      * SECURITY is enabled for the table. Dump as ALTER TABLE <table> ENABLE
    4277             :      * ROW LEVEL SECURITY.
    4278             :      */
    4279         610 :     if (polinfo->polname == NULL)
    4280             :     {
    4281         100 :         query = createPQExpBuffer();
    4282             : 
    4283         100 :         appendPQExpBuffer(query, "ALTER TABLE %s ENABLE ROW LEVEL SECURITY;",
    4284         100 :                           fmtQualifiedDumpable(tbinfo));
    4285             : 
    4286             :         /*
    4287             :          * We must emit the ROW SECURITY object's dependency on its table
    4288             :          * explicitly, because it will not match anything in pg_depend (unlike
    4289             :          * the case for other PolicyInfo objects).
    4290             :          */
    4291         100 :         if (polinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
    4292         100 :             ArchiveEntry(fout, polinfo->dobj.catId, polinfo->dobj.dumpId,
    4293         100 :                          ARCHIVE_OPTS(.tag = polinfo->dobj.name,
    4294             :                                       .namespace = polinfo->dobj.namespace->dobj.name,
    4295             :                                       .owner = tbinfo->rolname,
    4296             :                                       .description = "ROW SECURITY",
    4297             :                                       .section = SECTION_POST_DATA,
    4298             :                                       .createStmt = query->data,
    4299             :                                       .deps = &(tbinfo->dobj.dumpId),
    4300             :                                       .nDeps = 1));
    4301             : 
    4302         100 :         destroyPQExpBuffer(query);
    4303         100 :         return;
    4304             :     }
    4305             : 
    4306         510 :     if (polinfo->polcmd == '*')
    4307         170 :         cmd = "";
    4308         340 :     else if (polinfo->polcmd == 'r')
    4309          90 :         cmd = " FOR SELECT";
    4310         250 :     else if (polinfo->polcmd == 'a')
    4311          70 :         cmd = " FOR INSERT";
    4312         180 :     else if (polinfo->polcmd == 'w')
    4313          90 :         cmd = " FOR UPDATE";
    4314          90 :     else if (polinfo->polcmd == 'd')
    4315          90 :         cmd = " FOR DELETE";
    4316             :     else
    4317           0 :         pg_fatal("unexpected policy command type: %c",
    4318             :                  polinfo->polcmd);
    4319             : 
    4320         510 :     query = createPQExpBuffer();
    4321         510 :     delqry = createPQExpBuffer();
    4322         510 :     polprefix = createPQExpBuffer();
    4323             : 
    4324         510 :     qtabname = pg_strdup(fmtId(tbinfo->dobj.name));
    4325             : 
    4326         510 :     appendPQExpBuffer(query, "CREATE POLICY %s", fmtId(polinfo->polname));
    4327             : 
    4328         510 :     appendPQExpBuffer(query, " ON %s%s%s", fmtQualifiedDumpable(tbinfo),
    4329         510 :                       !polinfo->polpermissive ? " AS RESTRICTIVE" : "", cmd);
    4330             : 
    4331         510 :     if (polinfo->polroles != NULL)
    4332         280 :         appendPQExpBuffer(query, " TO %s", polinfo->polroles);
    4333             : 
    4334         510 :     if (polinfo->polqual != NULL)
    4335         440 :         appendPQExpBuffer(query, " USING (%s)", polinfo->polqual);
    4336             : 
    4337         510 :     if (polinfo->polwithcheck != NULL)
    4338         240 :         appendPQExpBuffer(query, " WITH CHECK (%s)", polinfo->polwithcheck);
    4339             : 
    4340         510 :     appendPQExpBufferStr(query, ";\n");
    4341             : 
    4342         510 :     appendPQExpBuffer(delqry, "DROP POLICY %s", fmtId(polinfo->polname));
    4343         510 :     appendPQExpBuffer(delqry, " ON %s;\n", fmtQualifiedDumpable(tbinfo));
    4344             : 
    4345         510 :     appendPQExpBuffer(polprefix, "POLICY %s ON",
    4346         510 :                       fmtId(polinfo->polname));
    4347             : 
    4348         510 :     tag = psprintf("%s %s", tbinfo->dobj.name, polinfo->dobj.name);
    4349             : 
    4350         510 :     if (polinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
    4351         510 :         ArchiveEntry(fout, polinfo->dobj.catId, polinfo->dobj.dumpId,
    4352         510 :                      ARCHIVE_OPTS(.tag = tag,
    4353             :                                   .namespace = polinfo->dobj.namespace->dobj.name,
    4354             :                                   .owner = tbinfo->rolname,
    4355             :                                   .description = "POLICY",
    4356             :                                   .section = SECTION_POST_DATA,
    4357             :                                   .createStmt = query->data,
    4358             :                                   .dropStmt = delqry->data));
    4359             : 
    4360         510 :     if (polinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
    4361           0 :         dumpComment(fout, polprefix->data, qtabname,
    4362           0 :                     tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
    4363             :                     polinfo->dobj.catId, 0, polinfo->dobj.dumpId);
    4364             : 
    4365         510 :     free(tag);
    4366         510 :     destroyPQExpBuffer(query);
    4367         510 :     destroyPQExpBuffer(delqry);
    4368         510 :     destroyPQExpBuffer(polprefix);
    4369         510 :     free(qtabname);
    4370             : }
    4371             : 
    4372             : /*
    4373             :  * getPublications
    4374             :  *    get information about publications
    4375             :  */
    4376             : void
    4377         354 : getPublications(Archive *fout)
    4378             : {
    4379         354 :     DumpOptions *dopt = fout->dopt;
    4380             :     PQExpBuffer query;
    4381             :     PGresult   *res;
    4382             :     PublicationInfo *pubinfo;
    4383             :     int         i_tableoid;
    4384             :     int         i_oid;
    4385             :     int         i_pubname;
    4386             :     int         i_pubowner;
    4387             :     int         i_puballtables;
    4388             :     int         i_pubinsert;
    4389             :     int         i_pubupdate;
    4390             :     int         i_pubdelete;
    4391             :     int         i_pubtruncate;
    4392             :     int         i_pubviaroot;
    4393             :     int         i_pubgencols;
    4394             :     int         i,
    4395             :                 ntups;
    4396             : 
    4397         354 :     if (dopt->no_publications || fout->remoteVersion < 100000)
    4398           0 :         return;
    4399             : 
    4400         354 :     query = createPQExpBuffer();
    4401             : 
    4402             :     /* Get the publications. */
    4403         354 :     appendPQExpBufferStr(query, "SELECT p.tableoid, p.oid, p.pubname, "
    4404             :                          "p.pubowner, p.puballtables, p.pubinsert, "
    4405             :                          "p.pubupdate, p.pubdelete, ");
    4406             : 
    4407         354 :     if (fout->remoteVersion >= 110000)
    4408         354 :         appendPQExpBufferStr(query, "p.pubtruncate, ");
    4409             :     else
    4410           0 :         appendPQExpBufferStr(query, "false AS pubtruncate, ");
    4411             : 
    4412         354 :     if (fout->remoteVersion >= 130000)
    4413         354 :         appendPQExpBufferStr(query, "p.pubviaroot, ");
    4414             :     else
    4415           0 :         appendPQExpBufferStr(query, "false AS pubviaroot, ");
    4416             : 
    4417         354 :     if (fout->remoteVersion >= 180000)
    4418         354 :         appendPQExpBufferStr(query, "p.pubgencols ");
    4419             :     else
    4420           0 :         appendPQExpBuffer(query, "'%c' AS pubgencols ", PUBLISH_GENCOLS_NONE);
    4421             : 
    4422         354 :     appendPQExpBufferStr(query, "FROM pg_publication p");
    4423             : 
    4424         354 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    4425             : 
    4426         354 :     ntups = PQntuples(res);
    4427             : 
    4428         354 :     if (ntups == 0)
    4429         254 :         goto cleanup;
    4430             : 
    4431         100 :     i_tableoid = PQfnumber(res, "tableoid");
    4432         100 :     i_oid = PQfnumber(res, "oid");
    4433         100 :     i_pubname = PQfnumber(res, "pubname");
    4434         100 :     i_pubowner = PQfnumber(res, "pubowner");
    4435         100 :     i_puballtables = PQfnumber(res, "puballtables");
    4436         100 :     i_pubinsert = PQfnumber(res, "pubinsert");
    4437         100 :     i_pubupdate = PQfnumber(res, "pubupdate");
    4438         100 :     i_pubdelete = PQfnumber(res, "pubdelete");
    4439         100 :     i_pubtruncate = PQfnumber(res, "pubtruncate");
    4440         100 :     i_pubviaroot = PQfnumber(res, "pubviaroot");
    4441         100 :     i_pubgencols = PQfnumber(res, "pubgencols");
    4442             : 
    4443         100 :     pubinfo = pg_malloc(ntups * sizeof(PublicationInfo));
    4444             : 
    4445         592 :     for (i = 0; i < ntups; i++)
    4446             :     {
    4447         492 :         pubinfo[i].dobj.objType = DO_PUBLICATION;
    4448         492 :         pubinfo[i].dobj.catId.tableoid =
    4449         492 :             atooid(PQgetvalue(res, i, i_tableoid));
    4450         492 :         pubinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    4451         492 :         AssignDumpId(&pubinfo[i].dobj);
    4452         492 :         pubinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_pubname));
    4453         492 :         pubinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_pubowner));
    4454         492 :         pubinfo[i].puballtables =
    4455         492 :             (strcmp(PQgetvalue(res, i, i_puballtables), "t") == 0);
    4456         492 :         pubinfo[i].pubinsert =
    4457         492 :             (strcmp(PQgetvalue(res, i, i_pubinsert), "t") == 0);
    4458         492 :         pubinfo[i].pubupdate =
    4459         492 :             (strcmp(PQgetvalue(res, i, i_pubupdate), "t") == 0);
    4460         492 :         pubinfo[i].pubdelete =
    4461         492 :             (strcmp(PQgetvalue(res, i, i_pubdelete), "t") == 0);
    4462         492 :         pubinfo[i].pubtruncate =
    4463         492 :             (strcmp(PQgetvalue(res, i, i_pubtruncate), "t") == 0);
    4464         492 :         pubinfo[i].pubviaroot =
    4465         492 :             (strcmp(PQgetvalue(res, i, i_pubviaroot), "t") == 0);
    4466         492 :         pubinfo[i].pubgencols_type =
    4467         492 :             *(PQgetvalue(res, i, i_pubgencols));
    4468             : 
    4469             :         /* Decide whether we want to dump it */
    4470         492 :         selectDumpableObject(&(pubinfo[i].dobj), fout);
    4471             :     }
    4472             : 
    4473         100 : cleanup:
    4474         354 :     PQclear(res);
    4475             : 
    4476         354 :     destroyPQExpBuffer(query);
    4477             : }
    4478             : 
    4479             : /*
    4480             :  * dumpPublication
    4481             :  *    dump the definition of the given publication
    4482             :  */
    4483             : static void
    4484         412 : dumpPublication(Archive *fout, const PublicationInfo *pubinfo)
    4485             : {
    4486         412 :     DumpOptions *dopt = fout->dopt;
    4487             :     PQExpBuffer delq;
    4488             :     PQExpBuffer query;
    4489             :     char       *qpubname;
    4490         412 :     bool        first = true;
    4491             : 
    4492             :     /* Do nothing if not dumping schema */
    4493         412 :     if (!dopt->dumpSchema)
    4494          60 :         return;
    4495             : 
    4496         352 :     delq = createPQExpBuffer();
    4497         352 :     query = createPQExpBuffer();
    4498             : 
    4499         352 :     qpubname = pg_strdup(fmtId(pubinfo->dobj.name));
    4500             : 
    4501         352 :     appendPQExpBuffer(delq, "DROP PUBLICATION %s;\n",
    4502             :                       qpubname);
    4503             : 
    4504         352 :     appendPQExpBuffer(query, "CREATE PUBLICATION %s",
    4505             :                       qpubname);
    4506             : 
    4507         352 :     if (pubinfo->puballtables)
    4508          72 :         appendPQExpBufferStr(query, " FOR ALL TABLES");
    4509             : 
    4510         352 :     appendPQExpBufferStr(query, " WITH (publish = '");
    4511         352 :     if (pubinfo->pubinsert)
    4512             :     {
    4513         282 :         appendPQExpBufferStr(query, "insert");
    4514         282 :         first = false;
    4515             :     }
    4516             : 
    4517         352 :     if (pubinfo->pubupdate)
    4518             :     {
    4519         282 :         if (!first)
    4520         282 :             appendPQExpBufferStr(query, ", ");
    4521             : 
    4522         282 :         appendPQExpBufferStr(query, "update");
    4523         282 :         first = false;
    4524             :     }
    4525             : 
    4526         352 :     if (pubinfo->pubdelete)
    4527             :     {
    4528         282 :         if (!first)
    4529         282 :             appendPQExpBufferStr(query, ", ");
    4530             : 
    4531         282 :         appendPQExpBufferStr(query, "delete");
    4532         282 :         first = false;
    4533             :     }
    4534             : 
    4535         352 :     if (pubinfo->pubtruncate)
    4536             :     {
    4537         282 :         if (!first)
    4538         282 :             appendPQExpBufferStr(query, ", ");
    4539             : 
    4540         282 :         appendPQExpBufferStr(query, "truncate");
    4541         282 :         first = false;
    4542             :     }
    4543             : 
    4544         352 :     appendPQExpBufferChar(query, '\'');
    4545             : 
    4546         352 :     if (pubinfo->pubviaroot)
    4547           0 :         appendPQExpBufferStr(query, ", publish_via_partition_root = true");
    4548             : 
    4549         352 :     if (pubinfo->pubgencols_type == PUBLISH_GENCOLS_STORED)
    4550          70 :         appendPQExpBufferStr(query, ", publish_generated_columns = stored");
    4551             : 
    4552         352 :     appendPQExpBufferStr(query, ");\n");
    4553             : 
    4554         352 :     if (pubinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
    4555         352 :         ArchiveEntry(fout, pubinfo->dobj.catId, pubinfo->dobj.dumpId,
    4556         352 :                      ARCHIVE_OPTS(.tag = pubinfo->dobj.name,
    4557             :                                   .owner = pubinfo->rolname,
    4558             :                                   .description = "PUBLICATION",
    4559             :                                   .section = SECTION_POST_DATA,
    4560             :                                   .createStmt = query->data,
    4561             :                                   .dropStmt = delq->data));
    4562             : 
    4563         352 :     if (pubinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
    4564          70 :         dumpComment(fout, "PUBLICATION", qpubname,
    4565             :                     NULL, pubinfo->rolname,
    4566             :                     pubinfo->dobj.catId, 0, pubinfo->dobj.dumpId);
    4567             : 
    4568         352 :     if (pubinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
    4569           0 :         dumpSecLabel(fout, "PUBLICATION", qpubname,
    4570             :                      NULL, pubinfo->rolname,
    4571             :                      pubinfo->dobj.catId, 0, pubinfo->dobj.dumpId);
    4572             : 
    4573         352 :     destroyPQExpBuffer(delq);
    4574         352 :     destroyPQExpBuffer(query);
    4575         352 :     free(qpubname);
    4576             : }
    4577             : 
    4578             : /*
    4579             :  * getPublicationNamespaces
    4580             :  *    get information about publication membership for dumpable schemas.
    4581             :  */
    4582             : void
    4583         354 : getPublicationNamespaces(Archive *fout)
    4584             : {
    4585             :     PQExpBuffer query;
    4586             :     PGresult   *res;
    4587             :     PublicationSchemaInfo *pubsinfo;
    4588         354 :     DumpOptions *dopt = fout->dopt;
    4589             :     int         i_tableoid;
    4590             :     int         i_oid;
    4591             :     int         i_pnpubid;
    4592             :     int         i_pnnspid;
    4593             :     int         i,
    4594             :                 j,
    4595             :                 ntups;
    4596             : 
    4597         354 :     if (dopt->no_publications || fout->remoteVersion < 150000)
    4598           0 :         return;
    4599             : 
    4600         354 :     query = createPQExpBuffer();
    4601             : 
    4602             :     /* Collect all publication membership info. */
    4603         354 :     appendPQExpBufferStr(query,
    4604             :                          "SELECT tableoid, oid, pnpubid, pnnspid "
    4605             :                          "FROM pg_catalog.pg_publication_namespace");
    4606         354 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    4607             : 
    4608         354 :     ntups = PQntuples(res);
    4609             : 
    4610         354 :     i_tableoid = PQfnumber(res, "tableoid");
    4611         354 :     i_oid = PQfnumber(res, "oid");
    4612         354 :     i_pnpubid = PQfnumber(res, "pnpubid");
    4613         354 :     i_pnnspid = PQfnumber(res, "pnnspid");
    4614             : 
    4615             :     /* this allocation may be more than we need */
    4616         354 :     pubsinfo = pg_malloc(ntups * sizeof(PublicationSchemaInfo));
    4617         354 :     j = 0;
    4618             : 
    4619         550 :     for (i = 0; i < ntups; i++)
    4620             :     {
    4621         196 :         Oid         pnpubid = atooid(PQgetvalue(res, i, i_pnpubid));
    4622         196 :         Oid         pnnspid = atooid(PQgetvalue(res, i, i_pnnspid));
    4623             :         PublicationInfo *pubinfo;
    4624             :         NamespaceInfo *nspinfo;
    4625             : 
    4626             :         /*
    4627             :          * Ignore any entries for which we aren't interested in either the
    4628             :          * publication or the rel.
    4629             :          */
    4630         196 :         pubinfo = findPublicationByOid(pnpubid);
    4631         196 :         if (pubinfo == NULL)
    4632           0 :             continue;
    4633         196 :         nspinfo = findNamespaceByOid(pnnspid);
    4634         196 :         if (nspinfo == NULL)
    4635           0 :             continue;
    4636             : 
    4637             :         /* OK, make a DumpableObject for this relationship */
    4638         196 :         pubsinfo[j].dobj.objType = DO_PUBLICATION_TABLE_IN_SCHEMA;
    4639         196 :         pubsinfo[j].dobj.catId.tableoid =
    4640         196 :             atooid(PQgetvalue(res, i, i_tableoid));
    4641         196 :         pubsinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    4642         196 :         AssignDumpId(&pubsinfo[j].dobj);
    4643         196 :         pubsinfo[j].dobj.namespace = nspinfo->dobj.namespace;
    4644         196 :         pubsinfo[j].dobj.name = nspinfo->dobj.name;
    4645         196 :         pubsinfo[j].publication = pubinfo;
    4646         196 :         pubsinfo[j].pubschema = nspinfo;
    4647             : 
    4648             :         /* Decide whether we want to dump it */
    4649         196 :         selectDumpablePublicationObject(&(pubsinfo[j].dobj), fout);
    4650             : 
    4651         196 :         j++;
    4652             :     }
    4653             : 
    4654         354 :     PQclear(res);
    4655         354 :     destroyPQExpBuffer(query);
    4656             : }
    4657             : 
    4658             : /*
    4659             :  * getPublicationTables
    4660             :  *    get information about publication membership for dumpable tables.
    4661             :  */
    4662             : void
    4663         354 : getPublicationTables(Archive *fout, TableInfo tblinfo[], int numTables)
    4664             : {
    4665             :     PQExpBuffer query;
    4666             :     PGresult   *res;
    4667             :     PublicationRelInfo *pubrinfo;
    4668         354 :     DumpOptions *dopt = fout->dopt;
    4669             :     int         i_tableoid;
    4670             :     int         i_oid;
    4671             :     int         i_prpubid;
    4672             :     int         i_prrelid;
    4673             :     int         i_prrelqual;
    4674             :     int         i_prattrs;
    4675             :     int         i,
    4676             :                 j,
    4677             :                 ntups;
    4678             : 
    4679         354 :     if (dopt->no_publications || fout->remoteVersion < 100000)
    4680           0 :         return;
    4681             : 
    4682         354 :     query = createPQExpBuffer();
    4683             : 
    4684             :     /* Collect all publication membership info. */
    4685         354 :     if (fout->remoteVersion >= 150000)
    4686         354 :         appendPQExpBufferStr(query,
    4687             :                              "SELECT tableoid, oid, prpubid, prrelid, "
    4688             :                              "pg_catalog.pg_get_expr(prqual, prrelid) AS prrelqual, "
    4689             :                              "(CASE\n"
    4690             :                              "  WHEN pr.prattrs IS NOT NULL THEN\n"
    4691             :                              "    (SELECT array_agg(attname)\n"
    4692             :                              "       FROM\n"
    4693             :                              "         pg_catalog.generate_series(0, pg_catalog.array_upper(pr.prattrs::pg_catalog.int2[], 1)) s,\n"
    4694             :                              "         pg_catalog.pg_attribute\n"
    4695             :                              "      WHERE attrelid = pr.prrelid AND attnum = prattrs[s])\n"
    4696             :                              "  ELSE NULL END) prattrs "
    4697             :                              "FROM pg_catalog.pg_publication_rel pr");
    4698             :     else
    4699           0 :         appendPQExpBufferStr(query,
    4700             :                              "SELECT tableoid, oid, prpubid, prrelid, "
    4701             :                              "NULL AS prrelqual, NULL AS prattrs "
    4702             :                              "FROM pg_catalog.pg_publication_rel");
    4703         354 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    4704             : 
    4705         354 :     ntups = PQntuples(res);
    4706             : 
    4707         354 :     i_tableoid = PQfnumber(res, "tableoid");
    4708         354 :     i_oid = PQfnumber(res, "oid");
    4709         354 :     i_prpubid = PQfnumber(res, "prpubid");
    4710         354 :     i_prrelid = PQfnumber(res, "prrelid");
    4711         354 :     i_prrelqual = PQfnumber(res, "prrelqual");
    4712         354 :     i_prattrs = PQfnumber(res, "prattrs");
    4713             : 
    4714             :     /* this allocation may be more than we need */
    4715         354 :     pubrinfo = pg_malloc(ntups * sizeof(PublicationRelInfo));
    4716         354 :     j = 0;
    4717             : 
    4718        1040 :     for (i = 0; i < ntups; i++)
    4719             :     {
    4720         686 :         Oid         prpubid = atooid(PQgetvalue(res, i, i_prpubid));
    4721         686 :         Oid         prrelid = atooid(PQgetvalue(res, i, i_prrelid));
    4722             :         PublicationInfo *pubinfo;
    4723             :         TableInfo  *tbinfo;
    4724             : 
    4725             :         /*
    4726             :          * Ignore any entries for which we aren't interested in either the
    4727             :          * publication or the rel.
    4728             :          */
    4729         686 :         pubinfo = findPublicationByOid(prpubid);
    4730         686 :         if (pubinfo == NULL)
    4731           0 :             continue;
    4732         686 :         tbinfo = findTableByOid(prrelid);
    4733         686 :         if (tbinfo == NULL)
    4734           0 :             continue;
    4735             : 
    4736             :         /* OK, make a DumpableObject for this relationship */
    4737         686 :         pubrinfo[j].dobj.objType = DO_PUBLICATION_REL;
    4738         686 :         pubrinfo[j].dobj.catId.tableoid =
    4739         686 :             atooid(PQgetvalue(res, i, i_tableoid));
    4740         686 :         pubrinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    4741         686 :         AssignDumpId(&pubrinfo[j].dobj);
    4742         686 :         pubrinfo[j].dobj.namespace = tbinfo->dobj.namespace;
    4743         686 :         pubrinfo[j].dobj.name = tbinfo->dobj.name;
    4744         686 :         pubrinfo[j].publication = pubinfo;
    4745         686 :         pubrinfo[j].pubtable = tbinfo;
    4746         686 :         if (PQgetisnull(res, i, i_prrelqual))
    4747         392 :             pubrinfo[j].pubrelqual = NULL;
    4748             :         else
    4749         294 :             pubrinfo[j].pubrelqual = pg_strdup(PQgetvalue(res, i, i_prrelqual));
    4750             : 
    4751         686 :         if (!PQgetisnull(res, i, i_prattrs))
    4752             :         {
    4753             :             char      **attnames;
    4754             :             int         nattnames;
    4755             :             PQExpBuffer attribs;
    4756             : 
    4757         196 :             if (!parsePGArray(PQgetvalue(res, i, i_prattrs),
    4758             :                               &attnames, &nattnames))
    4759           0 :                 pg_fatal("could not parse %s array", "prattrs");
    4760         196 :             attribs = createPQExpBuffer();
    4761         588 :             for (int k = 0; k < nattnames; k++)
    4762             :             {
    4763         392 :                 if (k > 0)
    4764         196 :                     appendPQExpBufferStr(attribs, ", ");
    4765             : 
    4766         392 :                 appendPQExpBufferStr(attribs, fmtId(attnames[k]));
    4767             :             }
    4768         196 :             pubrinfo[j].pubrattrs = attribs->data;
    4769         196 :             free(attribs);      /* but not attribs->data */
    4770         196 :             free(attnames);
    4771             :         }
    4772             :         else
    4773         490 :             pubrinfo[j].pubrattrs = NULL;
    4774             : 
    4775             :         /* Decide whether we want to dump it */
    4776         686 :         selectDumpablePublicationObject(&(pubrinfo[j].dobj), fout);
    4777             : 
    4778         686 :         j++;
    4779             :     }
    4780             : 
    4781         354 :     PQclear(res);
    4782         354 :     destroyPQExpBuffer(query);
    4783             : }
    4784             : 
    4785             : /*
    4786             :  * dumpPublicationNamespace
    4787             :  *    dump the definition of the given publication schema mapping.
    4788             :  */
    4789             : static void
    4790         164 : dumpPublicationNamespace(Archive *fout, const PublicationSchemaInfo *pubsinfo)
    4791             : {
    4792         164 :     DumpOptions *dopt = fout->dopt;
    4793         164 :     NamespaceInfo *schemainfo = pubsinfo->pubschema;
    4794         164 :     PublicationInfo *pubinfo = pubsinfo->publication;
    4795             :     PQExpBuffer query;
    4796             :     char       *tag;
    4797             : 
    4798             :     /* Do nothing if not dumping schema */
    4799         164 :     if (!dopt->dumpSchema)
    4800          24 :         return;
    4801             : 
    4802         140 :     tag = psprintf("%s %s", pubinfo->dobj.name, schemainfo->dobj.name);
    4803             : 
    4804         140 :     query = createPQExpBuffer();
    4805             : 
    4806         140 :     appendPQExpBuffer(query, "ALTER PUBLICATION %s ", fmtId(pubinfo->dobj.name));
    4807         140 :     appendPQExpBuffer(query, "ADD TABLES IN SCHEMA %s;\n", fmtId(schemainfo->dobj.name));
    4808             : 
    4809             :     /*
    4810             :      * There is no point in creating drop query as the drop is done by schema
    4811             :      * drop.
    4812             :      */
    4813         140 :     if (pubsinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
    4814         140 :         ArchiveEntry(fout, pubsinfo->dobj.catId, pubsinfo->dobj.dumpId,
    4815         140 :                      ARCHIVE_OPTS(.tag = tag,
    4816             :                                   .namespace = schemainfo->dobj.name,
    4817             :                                   .owner = pubinfo->rolname,
    4818             :                                   .description = "PUBLICATION TABLES IN SCHEMA",
    4819             :                                   .section = SECTION_POST_DATA,
    4820             :                                   .createStmt = query->data));
    4821             : 
    4822             :     /* These objects can't currently have comments or seclabels */
    4823             : 
    4824         140 :     free(tag);
    4825         140 :     destroyPQExpBuffer(query);
    4826             : }
    4827             : 
    4828             : /*
    4829             :  * dumpPublicationTable
    4830             :  *    dump the definition of the given publication table mapping
    4831             :  */
    4832             : static void
    4833         574 : dumpPublicationTable(Archive *fout, const PublicationRelInfo *pubrinfo)
    4834             : {
    4835         574 :     DumpOptions *dopt = fout->dopt;
    4836         574 :     PublicationInfo *pubinfo = pubrinfo->publication;
    4837         574 :     TableInfo  *tbinfo = pubrinfo->pubtable;
    4838             :     PQExpBuffer query;
    4839             :     char       *tag;
    4840             : 
    4841             :     /* Do nothing if not dumping schema */
    4842         574 :     if (!dopt->dumpSchema)
    4843          84 :         return;
    4844             : 
    4845         490 :     tag = psprintf("%s %s", pubinfo->dobj.name, tbinfo->dobj.name);
    4846             : 
    4847         490 :     query = createPQExpBuffer();
    4848             : 
    4849         490 :     appendPQExpBuffer(query, "ALTER PUBLICATION %s ADD TABLE ONLY",
    4850         490 :                       fmtId(pubinfo->dobj.name));
    4851         490 :     appendPQExpBuffer(query, " %s",
    4852         490 :                       fmtQualifiedDumpable(tbinfo));
    4853             : 
    4854         490 :     if (pubrinfo->pubrattrs)
    4855         140 :         appendPQExpBuffer(query, " (%s)", pubrinfo->pubrattrs);
    4856             : 
    4857         490 :     if (pubrinfo->pubrelqual)
    4858             :     {
    4859             :         /*
    4860             :          * It's necessary to add parentheses around the expression because
    4861             :          * pg_get_expr won't supply the parentheses for things like WHERE
    4862             :          * TRUE.
    4863             :          */
    4864         210 :         appendPQExpBuffer(query, " WHERE (%s)", pubrinfo->pubrelqual);
    4865             :     }
    4866         490 :     appendPQExpBufferStr(query, ";\n");
    4867             : 
    4868             :     /*
    4869             :      * There is no point in creating a drop query as the drop is done by table
    4870             :      * drop.  (If you think to change this, see also _printTocEntry().)
    4871             :      * Although this object doesn't really have ownership as such, set the
    4872             :      * owner field anyway to ensure that the command is run by the correct
    4873             :      * role at restore time.
    4874             :      */
    4875         490 :     if (pubrinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
    4876         490 :         ArchiveEntry(fout, pubrinfo->dobj.catId, pubrinfo->dobj.dumpId,
    4877         490 :                      ARCHIVE_OPTS(.tag = tag,
    4878             :                                   .namespace = tbinfo->dobj.namespace->dobj.name,
    4879             :                                   .owner = pubinfo->rolname,
    4880             :                                   .description = "PUBLICATION TABLE",
    4881             :                                   .section = SECTION_POST_DATA,
    4882             :                                   .createStmt = query->data));
    4883             : 
    4884             :     /* These objects can't currently have comments or seclabels */
    4885             : 
    4886         490 :     free(tag);
    4887         490 :     destroyPQExpBuffer(query);
    4888             : }
    4889             : 
    4890             : /*
    4891             :  * Is the currently connected user a superuser?
    4892             :  */
    4893             : static bool
    4894         354 : is_superuser(Archive *fout)
    4895             : {
    4896         354 :     ArchiveHandle *AH = (ArchiveHandle *) fout;
    4897             :     const char *val;
    4898             : 
    4899         354 :     val = PQparameterStatus(AH->connection, "is_superuser");
    4900             : 
    4901         354 :     if (val && strcmp(val, "on") == 0)
    4902         348 :         return true;
    4903             : 
    4904           6 :     return false;
    4905             : }
    4906             : 
    4907             : /*
    4908             :  * Set the given value to restrict_nonsystem_relation_kind value. Since
    4909             :  * restrict_nonsystem_relation_kind is introduced in minor version releases,
    4910             :  * the setting query is effective only where available.
    4911             :  */
    4912             : static void
    4913         422 : set_restrict_relation_kind(Archive *AH, const char *value)
    4914             : {
    4915         422 :     PQExpBuffer query = createPQExpBuffer();
    4916             :     PGresult   *res;
    4917             : 
    4918         422 :     appendPQExpBuffer(query,
    4919             :                       "SELECT set_config(name, '%s', false) "
    4920             :                       "FROM pg_settings "
    4921             :                       "WHERE name = 'restrict_nonsystem_relation_kind'",
    4922             :                       value);
    4923         422 :     res = ExecuteSqlQuery(AH, query->data, PGRES_TUPLES_OK);
    4924             : 
    4925         422 :     PQclear(res);
    4926         422 :     destroyPQExpBuffer(query);
    4927         422 : }
    4928             : 
    4929             : /*
    4930             :  * getSubscriptions
    4931             :  *    get information about subscriptions
    4932             :  */
    4933             : void
    4934         354 : getSubscriptions(Archive *fout)
    4935             : {
    4936         354 :     DumpOptions *dopt = fout->dopt;
    4937             :     PQExpBuffer query;
    4938             :     PGresult   *res;
    4939             :     SubscriptionInfo *subinfo;
    4940             :     int         i_tableoid;
    4941             :     int         i_oid;
    4942             :     int         i_subname;
    4943             :     int         i_subowner;
    4944             :     int         i_subbinary;
    4945             :     int         i_substream;
    4946             :     int         i_subtwophasestate;
    4947             :     int         i_subdisableonerr;
    4948             :     int         i_subpasswordrequired;
    4949             :     int         i_subrunasowner;
    4950             :     int         i_subconninfo;
    4951             :     int         i_subslotname;
    4952             :     int         i_subsynccommit;
    4953             :     int         i_subpublications;
    4954             :     int         i_suborigin;
    4955             :     int         i_suboriginremotelsn;
    4956             :     int         i_subenabled;
    4957             :     int         i_subfailover;
    4958             :     int         i,
    4959             :                 ntups;
    4960             : 
    4961         354 :     if (dopt->no_subscriptions || fout->remoteVersion < 100000)
    4962           0 :         return;
    4963             : 
    4964         354 :     if (!is_superuser(fout))
    4965             :     {
    4966             :         int         n;
    4967             : 
    4968           6 :         res = ExecuteSqlQuery(fout,
    4969             :                               "SELECT count(*) FROM pg_subscription "
    4970             :                               "WHERE subdbid = (SELECT oid FROM pg_database"
    4971             :                               "                 WHERE datname = current_database())",
    4972             :                               PGRES_TUPLES_OK);
    4973           6 :         n = atoi(PQgetvalue(res, 0, 0));
    4974           6 :         if (n > 0)
    4975           4 :             pg_log_warning("subscriptions not dumped because current user is not a superuser");
    4976           6 :         PQclear(res);
    4977           6 :         return;
    4978             :     }
    4979             : 
    4980         348 :     query = createPQExpBuffer();
    4981             : 
    4982             :     /* Get the subscriptions in current database. */
    4983         348 :     appendPQExpBufferStr(query,
    4984             :                          "SELECT s.tableoid, s.oid, s.subname,\n"
    4985             :                          " s.subowner,\n"
    4986             :                          " s.subconninfo, s.subslotname, s.subsynccommit,\n"
    4987             :                          " s.subpublications,\n");
    4988             : 
    4989         348 :     if (fout->remoteVersion >= 140000)
    4990         348 :         appendPQExpBufferStr(query, " s.subbinary,\n");
    4991             :     else
    4992           0 :         appendPQExpBufferStr(query, " false AS subbinary,\n");
    4993             : 
    4994         348 :     if (fout->remoteVersion >= 140000)
    4995         348 :         appendPQExpBufferStr(query, " s.substream,\n");
    4996             :     else
    4997           0 :         appendPQExpBufferStr(query, " 'f' AS substream,\n");
    4998             : 
    4999         348 :     if (fout->remoteVersion >= 150000)
    5000         348 :         appendPQExpBufferStr(query,
    5001             :                              " s.subtwophasestate,\n"
    5002             :                              " s.subdisableonerr,\n");
    5003             :     else
    5004           0 :         appendPQExpBuffer(query,
    5005             :                           " '%c' AS subtwophasestate,\n"
    5006             :                           " false AS subdisableonerr,\n",
    5007             :                           LOGICALREP_TWOPHASE_STATE_DISABLED);
    5008             : 
    5009         348 :     if (fout->remoteVersion >= 160000)
    5010         348 :         appendPQExpBufferStr(query,
    5011             :                              " s.subpasswordrequired,\n"
    5012             :                              " s.subrunasowner,\n"
    5013             :                              " s.suborigin,\n");
    5014             :     else
    5015           0 :         appendPQExpBuffer(query,
    5016             :                           " 't' AS subpasswordrequired,\n"
    5017             :                           " 't' AS subrunasowner,\n"
    5018             :                           " '%s' AS suborigin,\n",
    5019             :                           LOGICALREP_ORIGIN_ANY);
    5020             : 
    5021         348 :     if (dopt->binary_upgrade && fout->remoteVersion >= 170000)
    5022          62 :         appendPQExpBufferStr(query, " o.remote_lsn AS suboriginremotelsn,\n"
    5023             :                              " s.subenabled,\n");
    5024             :     else
    5025         286 :         appendPQExpBufferStr(query, " NULL AS suboriginremotelsn,\n"
    5026             :                              " false AS subenabled,\n");
    5027             : 
    5028         348 :     if (fout->remoteVersion >= 170000)
    5029         348 :         appendPQExpBufferStr(query,
    5030             :                              " s.subfailover\n");
    5031             :     else
    5032           0 :         appendPQExpBuffer(query,
    5033             :                           " false AS subfailover\n");
    5034             : 
    5035         348 :     appendPQExpBufferStr(query,
    5036             :                          "FROM pg_subscription s\n");
    5037             : 
    5038         348 :     if (dopt->binary_upgrade && fout->remoteVersion >= 170000)
    5039          62 :         appendPQExpBufferStr(query,
    5040             :                              "LEFT JOIN pg_catalog.pg_replication_origin_status o \n"
    5041             :                              "    ON o.external_id = 'pg_' || s.oid::text \n");
    5042             : 
    5043         348 :     appendPQExpBufferStr(query,
    5044             :                          "WHERE s.subdbid = (SELECT oid FROM pg_database\n"
    5045             :                          "                   WHERE datname = current_database())");
    5046             : 
    5047         348 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    5048             : 
    5049         348 :     ntups = PQntuples(res);
    5050             : 
    5051             :     /*
    5052             :      * Get subscription fields. We don't include subskiplsn in the dump as
    5053             :      * after restoring the dump this value may no longer be relevant.
    5054             :      */
    5055         348 :     i_tableoid = PQfnumber(res, "tableoid");
    5056         348 :     i_oid = PQfnumber(res, "oid");
    5057         348 :     i_subname = PQfnumber(res, "subname");
    5058         348 :     i_subowner = PQfnumber(res, "subowner");
    5059         348 :     i_subenabled = PQfnumber(res, "subenabled");
    5060         348 :     i_subbinary = PQfnumber(res, "subbinary");
    5061         348 :     i_substream = PQfnumber(res, "substream");
    5062         348 :     i_subtwophasestate = PQfnumber(res, "subtwophasestate");
    5063         348 :     i_subdisableonerr = PQfnumber(res, "subdisableonerr");
    5064         348 :     i_subpasswordrequired = PQfnumber(res, "subpasswordrequired");
    5065         348 :     i_subrunasowner = PQfnumber(res, "subrunasowner");
    5066         348 :     i_subfailover = PQfnumber(res, "subfailover");
    5067         348 :     i_subconninfo = PQfnumber(res, "subconninfo");
    5068         348 :     i_subslotname = PQfnumber(res, "subslotname");
    5069         348 :     i_subsynccommit = PQfnumber(res, "subsynccommit");
    5070         348 :     i_subpublications = PQfnumber(res, "subpublications");
    5071         348 :     i_suborigin = PQfnumber(res, "suborigin");
    5072         348 :     i_suboriginremotelsn = PQfnumber(res, "suboriginremotelsn");
    5073             : 
    5074         348 :     subinfo = pg_malloc(ntups * sizeof(SubscriptionInfo));
    5075             : 
    5076         634 :     for (i = 0; i < ntups; i++)
    5077             :     {
    5078         286 :         subinfo[i].dobj.objType = DO_SUBSCRIPTION;
    5079         286 :         subinfo[i].dobj.catId.tableoid =
    5080         286 :             atooid(PQgetvalue(res, i, i_tableoid));
    5081         286 :         subinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    5082         286 :         AssignDumpId(&subinfo[i].dobj);
    5083         286 :         subinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_subname));
    5084         286 :         subinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_subowner));
    5085             : 
    5086         286 :         subinfo[i].subenabled =
    5087         286 :             (strcmp(PQgetvalue(res, i, i_subenabled), "t") == 0);
    5088         286 :         subinfo[i].subbinary =
    5089         286 :             (strcmp(PQgetvalue(res, i, i_subbinary), "t") == 0);
    5090         286 :         subinfo[i].substream = *(PQgetvalue(res, i, i_substream));
    5091         286 :         subinfo[i].subtwophasestate = *(PQgetvalue(res, i, i_subtwophasestate));
    5092         286 :         subinfo[i].subdisableonerr =
    5093         286 :             (strcmp(PQgetvalue(res, i, i_subdisableonerr), "t") == 0);
    5094         286 :         subinfo[i].subpasswordrequired =
    5095         286 :             (strcmp(PQgetvalue(res, i, i_subpasswordrequired), "t") == 0);
    5096         286 :         subinfo[i].subrunasowner =
    5097         286 :             (strcmp(PQgetvalue(res, i, i_subrunasowner), "t") == 0);
    5098         286 :         subinfo[i].subfailover =
    5099         286 :             (strcmp(PQgetvalue(res, i, i_subfailover), "t") == 0);
    5100         572 :         subinfo[i].subconninfo =
    5101         286 :             pg_strdup(PQgetvalue(res, i, i_subconninfo));
    5102         286 :         if (PQgetisnull(res, i, i_subslotname))
    5103           0 :             subinfo[i].subslotname = NULL;
    5104             :         else
    5105         286 :             subinfo[i].subslotname =
    5106         286 :                 pg_strdup(PQgetvalue(res, i, i_subslotname));
    5107         572 :         subinfo[i].subsynccommit =
    5108         286 :             pg_strdup(PQgetvalue(res, i, i_subsynccommit));
    5109         572 :         subinfo[i].subpublications =
    5110         286 :             pg_strdup(PQgetvalue(res, i, i_subpublications));
    5111         286 :         subinfo[i].suborigin = pg_strdup(PQgetvalue(res, i, i_suborigin));
    5112         286 :         if (PQgetisnull(res, i, i_suboriginremotelsn))
    5113         284 :             subinfo[i].suboriginremotelsn = NULL;
    5114             :         else
    5115           2 :             subinfo[i].suboriginremotelsn =
    5116           2 :                 pg_strdup(PQgetvalue(res, i, i_suboriginremotelsn));
    5117             : 
    5118             :         /* Decide whether we want to dump it */
    5119         286 :         selectDumpableObject(&(subinfo[i].dobj), fout);
    5120             :     }
    5121         348 :     PQclear(res);
    5122             : 
    5123         348 :     destroyPQExpBuffer(query);
    5124             : }
    5125             : 
    5126             : /*
    5127             :  * getSubscriptionTables
    5128             :  *    Get information about subscription membership for dumpable tables. This
    5129             :  *    will be used only in binary-upgrade mode for PG17 or later versions.
    5130             :  */
    5131             : void
    5132         354 : getSubscriptionTables(Archive *fout)
    5133             : {
    5134         354 :     DumpOptions *dopt = fout->dopt;
    5135         354 :     SubscriptionInfo *subinfo = NULL;
    5136             :     SubRelInfo *subrinfo;
    5137             :     PGresult   *res;
    5138             :     int         i_srsubid;
    5139             :     int         i_srrelid;
    5140             :     int         i_srsubstate;
    5141             :     int         i_srsublsn;
    5142             :     int         ntups;
    5143         354 :     Oid         last_srsubid = InvalidOid;
    5144             : 
    5145         354 :     if (dopt->no_subscriptions || !dopt->binary_upgrade ||
    5146          62 :         fout->remoteVersion < 170000)
    5147         292 :         return;
    5148             : 
    5149          62 :     res = ExecuteSqlQuery(fout,
    5150             :                           "SELECT srsubid, srrelid, srsubstate, srsublsn "
    5151             :                           "FROM pg_catalog.pg_subscription_rel "
    5152             :                           "ORDER BY srsubid",
    5153             :                           PGRES_TUPLES_OK);
    5154          62 :     ntups = PQntuples(res);
    5155          62 :     if (ntups == 0)
    5156          60 :         goto cleanup;
    5157             : 
    5158             :     /* Get pg_subscription_rel attributes */
    5159           2 :     i_srsubid = PQfnumber(res, "srsubid");
    5160           2 :     i_srrelid = PQfnumber(res, "srrelid");
    5161           2 :     i_srsubstate = PQfnumber(res, "srsubstate");
    5162           2 :     i_srsublsn = PQfnumber(res, "srsublsn");
    5163             : 
    5164           2 :     subrinfo = pg_malloc(ntups * sizeof(SubRelInfo));
    5165           6 :     for (int i = 0; i < ntups; i++)
    5166             :     {
    5167           4 :         Oid         cur_srsubid = atooid(PQgetvalue(res, i, i_srsubid));
    5168           4 :         Oid         relid = atooid(PQgetvalue(res, i, i_srrelid));
    5169             :         TableInfo  *tblinfo;
    5170             : 
    5171             :         /*
    5172             :          * If we switched to a new subscription, check if the subscription
    5173             :          * exists.
    5174             :          */
    5175           4 :         if (cur_srsubid != last_srsubid)
    5176             :         {
    5177           4 :             subinfo = findSubscriptionByOid(cur_srsubid);
    5178           4 :             if (subinfo == NULL)
    5179           0 :                 pg_fatal("subscription with OID %u does not exist", cur_srsubid);
    5180             : 
    5181           4 :             last_srsubid = cur_srsubid;
    5182             :         }
    5183             : 
    5184           4 :         tblinfo = findTableByOid(relid);
    5185           4 :         if (tblinfo == NULL)
    5186           0 :             pg_fatal("failed sanity check, table with OID %u not found",
    5187             :                      relid);
    5188             : 
    5189             :         /* OK, make a DumpableObject for this relationship */
    5190           4 :         subrinfo[i].dobj.objType = DO_SUBSCRIPTION_REL;
    5191           4 :         subrinfo[i].dobj.catId.tableoid = relid;
    5192           4 :         subrinfo[i].dobj.catId.oid = cur_srsubid;
    5193           4 :         AssignDumpId(&subrinfo[i].dobj);
    5194           4 :         subrinfo[i].dobj.name = pg_strdup(subinfo->dobj.name);
    5195           4 :         subrinfo[i].tblinfo = tblinfo;
    5196           4 :         subrinfo[i].srsubstate = PQgetvalue(res, i, i_srsubstate)[0];
    5197           4 :         if (PQgetisnull(res, i, i_srsublsn))
    5198           2 :             subrinfo[i].srsublsn = NULL;
    5199             :         else
    5200           2 :             subrinfo[i].srsublsn = pg_strdup(PQgetvalue(res, i, i_srsublsn));
    5201             : 
    5202           4 :         subrinfo[i].subinfo = subinfo;
    5203             : 
    5204             :         /* Decide whether we want to dump it */
    5205           4 :         selectDumpableObject(&(subrinfo[i].dobj), fout);
    5206             :     }
    5207             : 
    5208           2 : cleanup:
    5209          62 :     PQclear(res);
    5210             : }
    5211             : 
    5212             : /*
    5213             :  * dumpSubscriptionTable
    5214             :  *    Dump the definition of the given subscription table mapping. This will be
    5215             :  *    used only in binary-upgrade mode for PG17 or later versions.
    5216             :  */
    5217             : static void
    5218           4 : dumpSubscriptionTable(Archive *fout, const SubRelInfo *subrinfo)
    5219             : {
    5220           4 :     DumpOptions *dopt = fout->dopt;
    5221           4 :     SubscriptionInfo *subinfo = subrinfo->subinfo;
    5222             :     PQExpBuffer query;
    5223             :     char       *tag;
    5224             : 
    5225             :     /* Do nothing if not dumping schema */
    5226           4 :     if (!dopt->dumpSchema)
    5227           0 :         return;
    5228             : 
    5229             :     Assert(fout->dopt->binary_upgrade && fout->remoteVersion >= 170000);
    5230             : 
    5231           4 :     tag = psprintf("%s %s", subinfo->dobj.name, subrinfo->dobj.name);
    5232             : 
    5233           4 :     query = createPQExpBuffer();
    5234             : 
    5235           4 :     if (subinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
    5236             :     {
    5237             :         /*
    5238             :          * binary_upgrade_add_sub_rel_state will add the subscription relation
    5239             :          * to pg_subscription_rel table. This will be used only in
    5240             :          * binary-upgrade mode.
    5241             :          */
    5242           4 :         appendPQExpBufferStr(query,
    5243             :                              "\n-- For binary upgrade, must preserve the subscriber table.\n");
    5244           4 :         appendPQExpBufferStr(query,
    5245             :                              "SELECT pg_catalog.binary_upgrade_add_sub_rel_state(");
    5246           4 :         appendStringLiteralAH(query, subrinfo->dobj.name, fout);
    5247           4 :         appendPQExpBuffer(query,
    5248             :                           ", %u, '%c'",
    5249           4 :                           subrinfo->tblinfo->dobj.catId.oid,
    5250           4 :                           subrinfo->srsubstate);
    5251             : 
    5252           4 :         if (subrinfo->srsublsn && subrinfo->srsublsn[0] != '\0')
    5253           2 :             appendPQExpBuffer(query, ", '%s'", subrinfo->srsublsn);
    5254             :         else
    5255           2 :             appendPQExpBuffer(query, ", NULL");
    5256             : 
    5257           4 :         appendPQExpBufferStr(query, ");\n");
    5258             :     }
    5259             : 
    5260             :     /*
    5261             :      * There is no point in creating a drop query as the drop is done by table
    5262             :      * drop.  (If you think to change this, see also _printTocEntry().)
    5263             :      * Although this object doesn't really have ownership as such, set the
    5264             :      * owner field anyway to ensure that the command is run by the correct
    5265             :      * role at restore time.
    5266             :      */
    5267           4 :     if (subrinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
    5268           4 :         ArchiveEntry(fout, subrinfo->dobj.catId, subrinfo->dobj.dumpId,
    5269           4 :                      ARCHIVE_OPTS(.tag = tag,
    5270             :                                   .namespace = subrinfo->tblinfo->dobj.namespace->dobj.name,
    5271             :                                   .owner = subinfo->rolname,
    5272             :                                   .description = "SUBSCRIPTION TABLE",
    5273             :                                   .section = SECTION_POST_DATA,
    5274             :                                   .createStmt = query->data));
    5275             : 
    5276             :     /* These objects can't currently have comments or seclabels */
    5277             : 
    5278           4 :     free(tag);
    5279           4 :     destroyPQExpBuffer(query);
    5280             : }
    5281             : 
    5282             : /*
    5283             :  * dumpSubscription
    5284             :  *    dump the definition of the given subscription
    5285             :  */
    5286             : static void
    5287         250 : dumpSubscription(Archive *fout, const SubscriptionInfo *subinfo)
    5288             : {
    5289         250 :     DumpOptions *dopt = fout->dopt;
    5290             :     PQExpBuffer delq;
    5291             :     PQExpBuffer query;
    5292             :     PQExpBuffer publications;
    5293             :     char       *qsubname;
    5294         250 :     char      **pubnames = NULL;
    5295         250 :     int         npubnames = 0;
    5296             :     int         i;
    5297             : 
    5298             :     /* Do nothing if not dumping schema */
    5299         250 :     if (!dopt->dumpSchema)
    5300          36 :         return;
    5301             : 
    5302         214 :     delq = createPQExpBuffer();
    5303         214 :     query = createPQExpBuffer();
    5304             : 
    5305         214 :     qsubname = pg_strdup(fmtId(subinfo->dobj.name));
    5306             : 
    5307         214 :     appendPQExpBuffer(delq, "DROP SUBSCRIPTION %s;\n",
    5308             :                       qsubname);
    5309             : 
    5310         214 :     appendPQExpBuffer(query, "CREATE SUBSCRIPTION %s CONNECTION ",
    5311             :                       qsubname);
    5312         214 :     appendStringLiteralAH(query, subinfo->subconninfo, fout);
    5313             : 
    5314             :     /* Build list of quoted publications and append them to query. */
    5315         214 :     if (!parsePGArray(subinfo->subpublications, &pubnames, &npubnames))
    5316           0 :         pg_fatal("could not parse %s array", "subpublications");
    5317             : 
    5318         214 :     publications = createPQExpBuffer();
    5319         428 :     for (i = 0; i < npubnames; i++)
    5320             :     {
    5321         214 :         if (i > 0)
    5322           0 :             appendPQExpBufferStr(publications, ", ");
    5323             : 
    5324         214 :         appendPQExpBufferStr(publications, fmtId(pubnames[i]));
    5325             :     }
    5326             : 
    5327         214 :     appendPQExpBuffer(query, " PUBLICATION %s WITH (connect = false, slot_name = ", publications->data);
    5328         214 :     if (subinfo->subslotname)
    5329         214 :         appendStringLiteralAH(query, subinfo->subslotname, fout);
    5330             :     else
    5331           0 :         appendPQExpBufferStr(query, "NONE");
    5332             : 
    5333         214 :     if (subinfo->subbinary)
    5334           0 :         appendPQExpBufferStr(query, ", binary = true");
    5335             : 
    5336         214 :     if (subinfo->substream == LOGICALREP_STREAM_ON)
    5337          70 :         appendPQExpBufferStr(query, ", streaming = on");
    5338         144 :     else if (subinfo->substream == LOGICALREP_STREAM_PARALLEL)
    5339          74 :         appendPQExpBufferStr(query, ", streaming = parallel");
    5340             :     else
    5341          70 :         appendPQExpBufferStr(query, ", streaming = off");
    5342             : 
    5343         214 :     if (subinfo->subtwophasestate != LOGICALREP_TWOPHASE_STATE_DISABLED)
    5344           0 :         appendPQExpBufferStr(query, ", two_phase = on");
    5345             : 
    5346         214 :     if (subinfo->subdisableonerr)
    5347           0 :         appendPQExpBufferStr(query, ", disable_on_error = true");
    5348             : 
    5349         214 :     if (!subinfo->subpasswordrequired)
    5350           0 :         appendPQExpBuffer(query, ", password_required = false");
    5351             : 
    5352         214 :     if (subinfo->subrunasowner)
    5353           0 :         appendPQExpBufferStr(query, ", run_as_owner = true");
    5354             : 
    5355         214 :     if (subinfo->subfailover)
    5356           2 :         appendPQExpBufferStr(query, ", failover = true");
    5357             : 
    5358         214 :     if (strcmp(subinfo->subsynccommit, "off") != 0)
    5359           0 :         appendPQExpBuffer(query, ", synchronous_commit = %s", fmtId(subinfo->subsynccommit));
    5360             : 
    5361         214 :     if (pg_strcasecmp(subinfo->suborigin, LOGICALREP_ORIGIN_ANY) != 0)
    5362          70 :         appendPQExpBuffer(query, ", origin = %s", subinfo->suborigin);
    5363             : 
    5364         214 :     appendPQExpBufferStr(query, ");\n");
    5365             : 
    5366             :     /*
    5367             :      * In binary-upgrade mode, we allow the replication to continue after the
    5368             :      * upgrade.
    5369             :      */
    5370         214 :     if (dopt->binary_upgrade && fout->remoteVersion >= 170000)
    5371             :     {
    5372          10 :         if (subinfo->suboriginremotelsn)
    5373             :         {
    5374             :             /*
    5375             :              * Preserve the remote_lsn for the subscriber's replication
    5376             :              * origin. This value is required to start the replication from
    5377             :              * the position before the upgrade. This value will be stale if
    5378             :              * the publisher gets upgraded before the subscriber node.
    5379             :              * However, this shouldn't be a problem as the upgrade of the
    5380             :              * publisher ensures that all the transactions were replicated
    5381             :              * before upgrading it.
    5382             :              */
    5383           2 :             appendPQExpBufferStr(query,
    5384             :                                  "\n-- For binary upgrade, must preserve the remote_lsn for the subscriber's replication origin.\n");
    5385           2 :             appendPQExpBufferStr(query,
    5386             :                                  "SELECT pg_catalog.binary_upgrade_replorigin_advance(");
    5387           2 :             appendStringLiteralAH(query, subinfo->dobj.name, fout);
    5388           2 :             appendPQExpBuffer(query, ", '%s');\n", subinfo->suboriginremotelsn);
    5389             :         }
    5390             : 
    5391          10 :         if (subinfo->subenabled)
    5392             :         {
    5393             :             /*
    5394             :              * Enable the subscription to allow the replication to continue
    5395             :              * after the upgrade.
    5396             :              */
    5397           2 :             appendPQExpBufferStr(query,
    5398             :                                  "\n-- For binary upgrade, must preserve the subscriber's running state.\n");
    5399           2 :             appendPQExpBuffer(query, "ALTER SUBSCRIPTION %s ENABLE;\n", qsubname);
    5400             :         }
    5401             :     }
    5402             : 
    5403         214 :     if (subinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
    5404         214 :         ArchiveEntry(fout, subinfo->dobj.catId, subinfo->dobj.dumpId,
    5405         214 :                      ARCHIVE_OPTS(.tag = subinfo->dobj.name,
    5406             :                                   .owner = subinfo->rolname,
    5407             :                                   .description = "SUBSCRIPTION",
    5408             :                                   .section = SECTION_POST_DATA,
    5409             :                                   .createStmt = query->data,
    5410             :                                   .dropStmt = delq->data));
    5411             : 
    5412         214 :     if (subinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
    5413          70 :         dumpComment(fout, "SUBSCRIPTION", qsubname,
    5414             :                     NULL, subinfo->rolname,
    5415             :                     subinfo->dobj.catId, 0, subinfo->dobj.dumpId);
    5416             : 
    5417         214 :     if (subinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
    5418           0 :         dumpSecLabel(fout, "SUBSCRIPTION", qsubname,
    5419             :                      NULL, subinfo->rolname,
    5420             :                      subinfo->dobj.catId, 0, subinfo->dobj.dumpId);
    5421             : 
    5422         214 :     destroyPQExpBuffer(publications);
    5423         214 :     free(pubnames);
    5424             : 
    5425         214 :     destroyPQExpBuffer(delq);
    5426         214 :     destroyPQExpBuffer(query);
    5427         214 :     free(qsubname);
    5428             : }
    5429             : 
    5430             : /*
    5431             :  * Given a "create query", append as many ALTER ... DEPENDS ON EXTENSION as
    5432             :  * the object needs.
    5433             :  */
    5434             : static void
    5435       10472 : append_depends_on_extension(Archive *fout,
    5436             :                             PQExpBuffer create,
    5437             :                             const DumpableObject *dobj,
    5438             :                             const char *catalog,
    5439             :                             const char *keyword,
    5440             :                             const char *objname)
    5441             : {
    5442       10472 :     if (dobj->depends_on_ext)
    5443             :     {
    5444             :         char       *nm;
    5445             :         PGresult   *res;
    5446             :         PQExpBuffer query;
    5447             :         int         ntups;
    5448             :         int         i_extname;
    5449             :         int         i;
    5450             : 
    5451             :         /* dodge fmtId() non-reentrancy */
    5452          84 :         nm = pg_strdup(objname);
    5453             : 
    5454          84 :         query = createPQExpBuffer();
    5455          84 :         appendPQExpBuffer(query,
    5456             :                           "SELECT e.extname "
    5457             :                           "FROM pg_catalog.pg_depend d, pg_catalog.pg_extension e "
    5458             :                           "WHERE d.refobjid = e.oid AND classid = '%s'::pg_catalog.regclass "
    5459             :                           "AND objid = '%u'::pg_catalog.oid AND deptype = 'x' "
    5460             :                           "AND refclassid = 'pg_catalog.pg_extension'::pg_catalog.regclass",
    5461             :                           catalog,
    5462             :                           dobj->catId.oid);
    5463          84 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    5464          84 :         ntups = PQntuples(res);
    5465          84 :         i_extname = PQfnumber(res, "extname");
    5466         168 :         for (i = 0; i < ntups; i++)
    5467             :         {
    5468          84 :             appendPQExpBuffer(create, "\nALTER %s %s DEPENDS ON EXTENSION %s;",
    5469             :                               keyword, nm,
    5470          84 :                               fmtId(PQgetvalue(res, i, i_extname)));
    5471             :         }
    5472             : 
    5473          84 :         PQclear(res);
    5474          84 :         destroyPQExpBuffer(query);
    5475          84 :         pg_free(nm);
    5476             :     }
    5477       10472 : }
    5478             : 
    5479             : static Oid
    5480           0 : get_next_possible_free_pg_type_oid(Archive *fout, PQExpBuffer upgrade_query)
    5481             : {
    5482             :     /*
    5483             :      * If the old version didn't assign an array type, but the new version
    5484             :      * does, we must select an unused type OID to assign.  This currently only
    5485             :      * happens for domains, when upgrading pre-v11 to v11 and up.
    5486             :      *
    5487             :      * Note: local state here is kind of ugly, but we must have some, since we
    5488             :      * mustn't choose the same unused OID more than once.
    5489             :      */
    5490             :     static Oid  next_possible_free_oid = FirstNormalObjectId;
    5491             :     PGresult   *res;
    5492             :     bool        is_dup;
    5493             : 
    5494             :     do
    5495             :     {
    5496           0 :         ++next_possible_free_oid;
    5497           0 :         printfPQExpBuffer(upgrade_query,
    5498             :                           "SELECT EXISTS(SELECT 1 "
    5499             :                           "FROM pg_catalog.pg_type "
    5500             :                           "WHERE oid = '%u'::pg_catalog.oid);",
    5501             :                           next_possible_free_oid);
    5502           0 :         res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data);
    5503           0 :         is_dup = (PQgetvalue(res, 0, 0)[0] == 't');
    5504           0 :         PQclear(res);
    5505           0 :     } while (is_dup);
    5506             : 
    5507           0 :     return next_possible_free_oid;
    5508             : }
    5509             : 
    5510             : static void
    5511        1788 : binary_upgrade_set_type_oids_by_type_oid(Archive *fout,
    5512             :                                          PQExpBuffer upgrade_buffer,
    5513             :                                          Oid pg_type_oid,
    5514             :                                          bool force_array_type,
    5515             :                                          bool include_multirange_type)
    5516             : {
    5517        1788 :     PQExpBuffer upgrade_query = createPQExpBuffer();
    5518             :     PGresult   *res;
    5519             :     Oid         pg_type_array_oid;
    5520             :     Oid         pg_type_multirange_oid;
    5521             :     Oid         pg_type_multirange_array_oid;
    5522             :     TypeInfo   *tinfo;
    5523             : 
    5524        1788 :     appendPQExpBufferStr(upgrade_buffer, "\n-- For binary upgrade, must preserve pg_type oid\n");
    5525        1788 :     appendPQExpBuffer(upgrade_buffer,
    5526             :                       "SELECT pg_catalog.binary_upgrade_set_next_pg_type_oid('%u'::pg_catalog.oid);\n\n",
    5527             :                       pg_type_oid);
    5528             : 
    5529        1788 :     tinfo = findTypeByOid(pg_type_oid);
    5530        1788 :     if (tinfo)
    5531        1788 :         pg_type_array_oid = tinfo->typarray;
    5532             :     else
    5533           0 :         pg_type_array_oid = InvalidOid;
    5534             : 
    5535        1788 :     if (!OidIsValid(pg_type_array_oid) && force_array_type)
    5536           0 :         pg_type_array_oid = get_next_possible_free_pg_type_oid(fout, upgrade_query);
    5537             : 
    5538        1788 :     if (OidIsValid(pg_type_array_oid))
    5539             :     {
    5540        1784 :         appendPQExpBufferStr(upgrade_buffer,
    5541             :                              "\n-- For binary upgrade, must preserve pg_type array oid\n");
    5542        1784 :         appendPQExpBuffer(upgrade_buffer,
    5543             :                           "SELECT pg_catalog.binary_upgrade_set_next_array_pg_type_oid('%u'::pg_catalog.oid);\n\n",
    5544             :                           pg_type_array_oid);
    5545             :     }
    5546             : 
    5547             :     /*
    5548             :      * Pre-set the multirange type oid and its own array type oid.
    5549             :      */
    5550        1788 :     if (include_multirange_type)
    5551             :     {
    5552          16 :         if (fout->remoteVersion >= 140000)
    5553             :         {
    5554          16 :             printfPQExpBuffer(upgrade_query,
    5555             :                               "SELECT t.oid, t.typarray "
    5556             :                               "FROM pg_catalog.pg_type t "
    5557             :                               "JOIN pg_catalog.pg_range r "
    5558             :                               "ON t.oid = r.rngmultitypid "
    5559             :                               "WHERE r.rngtypid = '%u'::pg_catalog.oid;",
    5560             :                               pg_type_oid);
    5561             : 
    5562          16 :             res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data);
    5563             : 
    5564          16 :             pg_type_multirange_oid = atooid(PQgetvalue(res, 0, PQfnumber(res, "oid")));
    5565          16 :             pg_type_multirange_array_oid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typarray")));
    5566             : 
    5567          16 :             PQclear(res);
    5568             :         }
    5569             :         else
    5570             :         {
    5571           0 :             pg_type_multirange_oid = get_next_possible_free_pg_type_oid(fout, upgrade_query);
    5572           0 :             pg_type_multirange_array_oid = get_next_possible_free_pg_type_oid(fout, upgrade_query);
    5573             :         }
    5574             : 
    5575          16 :         appendPQExpBufferStr(upgrade_buffer,
    5576             :                              "\n-- For binary upgrade, must preserve multirange pg_type oid\n");
    5577          16 :         appendPQExpBuffer(upgrade_buffer,
    5578             :                           "SELECT pg_catalog.binary_upgrade_set_next_multirange_pg_type_oid('%u'::pg_catalog.oid);\n\n",
    5579             :                           pg_type_multirange_oid);
    5580          16 :         appendPQExpBufferStr(upgrade_buffer,
    5581             :                              "\n-- For binary upgrade, must preserve multirange pg_type array oid\n");
    5582          16 :         appendPQExpBuffer(upgrade_buffer,
    5583             :                           "SELECT pg_catalog.binary_upgrade_set_next_multirange_array_pg_type_oid('%u'::pg_catalog.oid);\n\n",
    5584             :                           pg_type_multirange_array_oid);
    5585             :     }
    5586             : 
    5587        1788 :     destroyPQExpBuffer(upgrade_query);
    5588        1788 : }
    5589             : 
    5590             : static void
    5591        1646 : binary_upgrade_set_type_oids_by_rel(Archive *fout,
    5592             :                                     PQExpBuffer upgrade_buffer,
    5593             :                                     const TableInfo *tbinfo)
    5594             : {
    5595        1646 :     Oid         pg_type_oid = tbinfo->reltype;
    5596             : 
    5597        1646 :     if (OidIsValid(pg_type_oid))
    5598        1646 :         binary_upgrade_set_type_oids_by_type_oid(fout, upgrade_buffer,
    5599             :                                                  pg_type_oid, false, false);
    5600        1646 : }
    5601             : 
    5602             : /*
    5603             :  * bsearch() comparator for BinaryUpgradeClassOidItem
    5604             :  */
    5605             : static int
    5606       23762 : BinaryUpgradeClassOidItemCmp(const void *p1, const void *p2)
    5607             : {
    5608       23762 :     BinaryUpgradeClassOidItem v1 = *((const BinaryUpgradeClassOidItem *) p1);
    5609       23762 :     BinaryUpgradeClassOidItem v2 = *((const BinaryUpgradeClassOidItem *) p2);
    5610             : 
    5611       23762 :     return pg_cmp_u32(v1.oid, v2.oid);
    5612             : }
    5613             : 
    5614             : /*
    5615             :  * collectBinaryUpgradeClassOids
    5616             :  *
    5617             :  * Construct a table of pg_class information required for
    5618             :  * binary_upgrade_set_pg_class_oids().  The table is sorted by OID for speed in
    5619             :  * lookup.
    5620             :  */
    5621             : static void
    5622          62 : collectBinaryUpgradeClassOids(Archive *fout)
    5623             : {
    5624             :     PGresult   *res;
    5625             :     const char *query;
    5626             : 
    5627          62 :     query = "SELECT c.oid, c.relkind, c.relfilenode, c.reltoastrelid, "
    5628             :         "ct.relfilenode, i.indexrelid, cti.relfilenode "
    5629             :         "FROM pg_catalog.pg_class c LEFT JOIN pg_catalog.pg_index i "
    5630             :         "ON (c.reltoastrelid = i.indrelid AND i.indisvalid) "
    5631             :         "LEFT JOIN pg_catalog.pg_class ct ON (c.reltoastrelid = ct.oid) "
    5632             :         "LEFT JOIN pg_catalog.pg_class AS cti ON (i.indexrelid = cti.oid) "
    5633             :         "ORDER BY c.oid;";
    5634             : 
    5635          62 :     res = ExecuteSqlQuery(fout, query, PGRES_TUPLES_OK);
    5636             : 
    5637          62 :     nbinaryUpgradeClassOids = PQntuples(res);
    5638          62 :     binaryUpgradeClassOids = (BinaryUpgradeClassOidItem *)
    5639          62 :         pg_malloc(nbinaryUpgradeClassOids * sizeof(BinaryUpgradeClassOidItem));
    5640             : 
    5641       29306 :     for (int i = 0; i < nbinaryUpgradeClassOids; i++)
    5642             :     {
    5643       29244 :         binaryUpgradeClassOids[i].oid = atooid(PQgetvalue(res, i, 0));
    5644       29244 :         binaryUpgradeClassOids[i].relkind = *PQgetvalue(res, i, 1);
    5645       29244 :         binaryUpgradeClassOids[i].relfilenumber = atooid(PQgetvalue(res, i, 2));
    5646       29244 :         binaryUpgradeClassOids[i].toast_oid = atooid(PQgetvalue(res, i, 3));
    5647       29244 :         binaryUpgradeClassOids[i].toast_relfilenumber = atooid(PQgetvalue(res, i, 4));
    5648       29244 :         binaryUpgradeClassOids[i].toast_index_oid = atooid(PQgetvalue(res, i, 5));
    5649       29244 :         binaryUpgradeClassOids[i].toast_index_relfilenumber = atooid(PQgetvalue(res, i, 6));
    5650             :     }
    5651             : 
    5652          62 :     PQclear(res);
    5653          62 : }
    5654             : 
    5655             : static void
    5656        2410 : binary_upgrade_set_pg_class_oids(Archive *fout,
    5657             :                                  PQExpBuffer upgrade_buffer, Oid pg_class_oid)
    5658             : {
    5659        2410 :     BinaryUpgradeClassOidItem key = {0};
    5660             :     BinaryUpgradeClassOidItem *entry;
    5661             : 
    5662             :     Assert(binaryUpgradeClassOids);
    5663             : 
    5664             :     /*
    5665             :      * Preserve the OID and relfilenumber of the table, table's index, table's
    5666             :      * toast table and toast table's index if any.
    5667             :      *
    5668             :      * One complexity is that the current table definition might not require
    5669             :      * the creation of a TOAST table, but the old database might have a TOAST
    5670             :      * table that was created earlier, before some wide columns were dropped.
    5671             :      * By setting the TOAST oid we force creation of the TOAST heap and index
    5672             :      * by the new backend, so we can copy the files during binary upgrade
    5673             :      * without worrying about this case.
    5674             :      */
    5675        2410 :     key.oid = pg_class_oid;
    5676        2410 :     entry = bsearch(&key, binaryUpgradeClassOids, nbinaryUpgradeClassOids,
    5677             :                     sizeof(BinaryUpgradeClassOidItem),
    5678             :                     BinaryUpgradeClassOidItemCmp);
    5679             : 
    5680        2410 :     appendPQExpBufferStr(upgrade_buffer,
    5681             :                          "\n-- For binary upgrade, must preserve pg_class oids and relfilenodes\n");
    5682             : 
    5683        2410 :     if (entry->relkind != RELKIND_INDEX &&
    5684        1864 :         entry->relkind != RELKIND_PARTITIONED_INDEX)
    5685             :     {
    5686        1814 :         appendPQExpBuffer(upgrade_buffer,
    5687             :                           "SELECT pg_catalog.binary_upgrade_set_next_heap_pg_class_oid('%u'::pg_catalog.oid);\n",
    5688             :                           pg_class_oid);
    5689             : 
    5690             :         /*
    5691             :          * Not every relation has storage. Also, in a pre-v12 database,
    5692             :          * partitioned tables have a relfilenumber, which should not be
    5693             :          * preserved when upgrading.
    5694             :          */
    5695        1814 :         if (RelFileNumberIsValid(entry->relfilenumber) &&
    5696        1498 :             entry->relkind != RELKIND_PARTITIONED_TABLE)
    5697        1498 :             appendPQExpBuffer(upgrade_buffer,
    5698             :                               "SELECT pg_catalog.binary_upgrade_set_next_heap_relfilenode('%u'::pg_catalog.oid);\n",
    5699             :                               entry->relfilenumber);
    5700             : 
    5701             :         /*
    5702             :          * In a pre-v12 database, partitioned tables might be marked as having
    5703             :          * toast tables, but we should ignore them if so.
    5704             :          */
    5705        1814 :         if (OidIsValid(entry->toast_oid) &&
    5706         552 :             entry->relkind != RELKIND_PARTITIONED_TABLE)
    5707             :         {
    5708         552 :             appendPQExpBuffer(upgrade_buffer,
    5709             :                               "SELECT pg_catalog.binary_upgrade_set_next_toast_pg_class_oid('%u'::pg_catalog.oid);\n",
    5710             :                               entry->toast_oid);
    5711         552 :             appendPQExpBuffer(upgrade_buffer,
    5712             :                               "SELECT pg_catalog.binary_upgrade_set_next_toast_relfilenode('%u'::pg_catalog.oid);\n",
    5713             :                               entry->toast_relfilenumber);
    5714             : 
    5715             :             /* every toast table has an index */
    5716         552 :             appendPQExpBuffer(upgrade_buffer,
    5717             :                               "SELECT pg_catalog.binary_upgrade_set_next_index_pg_class_oid('%u'::pg_catalog.oid);\n",
    5718             :                               entry->toast_index_oid);
    5719         552 :             appendPQExpBuffer(upgrade_buffer,
    5720             :                               "SELECT pg_catalog.binary_upgrade_set_next_index_relfilenode('%u'::pg_catalog.oid);\n",
    5721             :                               entry->toast_index_relfilenumber);
    5722             :         }
    5723             :     }
    5724             :     else
    5725             :     {
    5726             :         /* Preserve the OID and relfilenumber of the index */
    5727         596 :         appendPQExpBuffer(upgrade_buffer,
    5728             :                           "SELECT pg_catalog.binary_upgrade_set_next_index_pg_class_oid('%u'::pg_catalog.oid);\n",
    5729             :                           pg_class_oid);
    5730         596 :         appendPQExpBuffer(upgrade_buffer,
    5731             :                           "SELECT pg_catalog.binary_upgrade_set_next_index_relfilenode('%u'::pg_catalog.oid);\n",
    5732             :                           entry->relfilenumber);
    5733             :     }
    5734             : 
    5735        2410 :     appendPQExpBufferChar(upgrade_buffer, '\n');
    5736        2410 : }
    5737             : 
    5738             : /*
    5739             :  * If the DumpableObject is a member of an extension, add a suitable
    5740             :  * ALTER EXTENSION ADD command to the creation commands in upgrade_buffer.
    5741             :  *
    5742             :  * For somewhat historical reasons, objname should already be quoted,
    5743             :  * but not objnamespace (if any).
    5744             :  */
    5745             : static void
    5746        2880 : binary_upgrade_extension_member(PQExpBuffer upgrade_buffer,
    5747             :                                 const DumpableObject *dobj,
    5748             :                                 const char *objtype,
    5749             :                                 const char *objname,
    5750             :                                 const char *objnamespace)
    5751             : {
    5752        2880 :     DumpableObject *extobj = NULL;
    5753             :     int         i;
    5754             : 
    5755        2880 :     if (!dobj->ext_member)
    5756        2848 :         return;
    5757             : 
    5758             :     /*
    5759             :      * Find the parent extension.  We could avoid this search if we wanted to
    5760             :      * add a link field to DumpableObject, but the space costs of that would
    5761             :      * be considerable.  We assume that member objects could only have a
    5762             :      * direct dependency on their own extension, not any others.
    5763             :      */
    5764          32 :     for (i = 0; i < dobj->nDeps; i++)
    5765             :     {
    5766          32 :         extobj = findObjectByDumpId(dobj->dependencies[i]);
    5767          32 :         if (extobj && extobj->objType == DO_EXTENSION)
    5768          32 :             break;
    5769           0 :         extobj = NULL;
    5770             :     }
    5771          32 :     if (extobj == NULL)
    5772           0 :         pg_fatal("could not find parent extension for %s %s",
    5773             :                  objtype, objname);
    5774             : 
    5775          32 :     appendPQExpBufferStr(upgrade_buffer,
    5776             :                          "\n-- For binary upgrade, handle extension membership the hard way\n");
    5777          32 :     appendPQExpBuffer(upgrade_buffer, "ALTER EXTENSION %s ADD %s ",
    5778          32 :                       fmtId(extobj->name),
    5779             :                       objtype);
    5780          32 :     if (objnamespace && *objnamespace)
    5781          26 :         appendPQExpBuffer(upgrade_buffer, "%s.", fmtId(objnamespace));
    5782          32 :     appendPQExpBuffer(upgrade_buffer, "%s;\n", objname);
    5783             : }
    5784             : 
    5785             : /*
    5786             :  * getNamespaces:
    5787             :  *    get information about all namespaces in the system catalogs
    5788             :  */
    5789             : void
    5790         356 : getNamespaces(Archive *fout)
    5791             : {
    5792             :     PGresult   *res;
    5793             :     int         ntups;
    5794             :     int         i;
    5795             :     PQExpBuffer query;
    5796             :     NamespaceInfo *nsinfo;
    5797             :     int         i_tableoid;
    5798             :     int         i_oid;
    5799             :     int         i_nspname;
    5800             :     int         i_nspowner;
    5801             :     int         i_nspacl;
    5802             :     int         i_acldefault;
    5803             : 
    5804         356 :     query = createPQExpBuffer();
    5805             : 
    5806             :     /*
    5807             :      * we fetch all namespaces including system ones, so that every object we
    5808             :      * read in can be linked to a containing namespace.
    5809             :      */
    5810         356 :     appendPQExpBufferStr(query, "SELECT n.tableoid, n.oid, n.nspname, "
    5811             :                          "n.nspowner, "
    5812             :                          "n.nspacl, "
    5813             :                          "acldefault('n', n.nspowner) AS acldefault "
    5814             :                          "FROM pg_namespace n");
    5815             : 
    5816         356 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    5817             : 
    5818         356 :     ntups = PQntuples(res);
    5819             : 
    5820         356 :     nsinfo = (NamespaceInfo *) pg_malloc(ntups * sizeof(NamespaceInfo));
    5821             : 
    5822         356 :     i_tableoid = PQfnumber(res, "tableoid");
    5823         356 :     i_oid = PQfnumber(res, "oid");
    5824         356 :     i_nspname = PQfnumber(res, "nspname");
    5825         356 :     i_nspowner = PQfnumber(res, "nspowner");
    5826         356 :     i_nspacl = PQfnumber(res, "nspacl");
    5827         356 :     i_acldefault = PQfnumber(res, "acldefault");
    5828             : 
    5829        3072 :     for (i = 0; i < ntups; i++)
    5830             :     {
    5831             :         const char *nspowner;
    5832             : 
    5833        2716 :         nsinfo[i].dobj.objType = DO_NAMESPACE;
    5834        2716 :         nsinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    5835        2716 :         nsinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    5836        2716 :         AssignDumpId(&nsinfo[i].dobj);
    5837        2716 :         nsinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_nspname));
    5838        2716 :         nsinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_nspacl));
    5839        2716 :         nsinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
    5840        2716 :         nsinfo[i].dacl.privtype = 0;
    5841        2716 :         nsinfo[i].dacl.initprivs = NULL;
    5842        2716 :         nspowner = PQgetvalue(res, i, i_nspowner);
    5843        2716 :         nsinfo[i].nspowner = atooid(nspowner);
    5844        2716 :         nsinfo[i].rolname = getRoleName(nspowner);
    5845             : 
    5846             :         /* Decide whether to dump this namespace */
    5847        2716 :         selectDumpableNamespace(&nsinfo[i], fout);
    5848             : 
    5849             :         /* Mark whether namespace has an ACL */
    5850        2716 :         if (!PQgetisnull(res, i, i_nspacl))
    5851        1200 :             nsinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
    5852             : 
    5853             :         /*
    5854             :          * We ignore any pg_init_privs.initprivs entry for the public schema
    5855             :          * and assume a predetermined default, for several reasons.  First,
    5856             :          * dropping and recreating the schema removes its pg_init_privs entry,
    5857             :          * but an empty destination database starts with this ACL nonetheless.
    5858             :          * Second, we support dump/reload of public schema ownership changes.
    5859             :          * ALTER SCHEMA OWNER filters nspacl through aclnewowner(), but
    5860             :          * initprivs continues to reflect the initial owner.  Hence,
    5861             :          * synthesize the value that nspacl will have after the restore's
    5862             :          * ALTER SCHEMA OWNER.  Third, this makes the destination database
    5863             :          * match the source's ACL, even if the latter was an initdb-default
    5864             :          * ACL, which changed in v15.  An upgrade pulls in changes to most
    5865             :          * system object ACLs that the DBA had not customized.  We've made the
    5866             :          * public schema depart from that, because changing its ACL so easily
    5867             :          * breaks applications.
    5868             :          */
    5869        2716 :         if (strcmp(nsinfo[i].dobj.name, "public") == 0)
    5870             :         {
    5871         348 :             PQExpBuffer aclarray = createPQExpBuffer();
    5872         348 :             PQExpBuffer aclitem = createPQExpBuffer();
    5873             : 
    5874             :             /* Standard ACL as of v15 is {owner=UC/owner,=U/owner} */
    5875         348 :             appendPQExpBufferChar(aclarray, '{');
    5876         348 :             quoteAclUserName(aclitem, nsinfo[i].rolname);
    5877         348 :             appendPQExpBufferStr(aclitem, "=UC/");
    5878         348 :             quoteAclUserName(aclitem, nsinfo[i].rolname);
    5879         348 :             appendPGArray(aclarray, aclitem->data);
    5880         348 :             resetPQExpBuffer(aclitem);
    5881         348 :             appendPQExpBufferStr(aclitem, "=U/");
    5882         348 :             quoteAclUserName(aclitem, nsinfo[i].rolname);
    5883         348 :             appendPGArray(aclarray, aclitem->data);
    5884         348 :             appendPQExpBufferChar(aclarray, '}');
    5885             : 
    5886         348 :             nsinfo[i].dacl.privtype = 'i';
    5887         348 :             nsinfo[i].dacl.initprivs = pstrdup(aclarray->data);
    5888         348 :             nsinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
    5889             : 
    5890         348 :             destroyPQExpBuffer(aclarray);
    5891         348 :             destroyPQExpBuffer(aclitem);
    5892             :         }
    5893             :     }
    5894             : 
    5895         356 :     PQclear(res);
    5896         356 :     destroyPQExpBuffer(query);
    5897         356 : }
    5898             : 
    5899             : /*
    5900             :  * findNamespace:
    5901             :  *      given a namespace OID, look up the info read by getNamespaces
    5902             :  */
    5903             : static NamespaceInfo *
    5904     1105422 : findNamespace(Oid nsoid)
    5905             : {
    5906             :     NamespaceInfo *nsinfo;
    5907             : 
    5908     1105422 :     nsinfo = findNamespaceByOid(nsoid);
    5909     1105422 :     if (nsinfo == NULL)
    5910           0 :         pg_fatal("schema with OID %u does not exist", nsoid);
    5911     1105422 :     return nsinfo;
    5912             : }
    5913             : 
    5914             : /*
    5915             :  * getExtensions:
    5916             :  *    read all extensions in the system catalogs and return them in the
    5917             :  * ExtensionInfo* structure
    5918             :  *
    5919             :  *  numExtensions is set to the number of extensions read in
    5920             :  */
    5921             : ExtensionInfo *
    5922         356 : getExtensions(Archive *fout, int *numExtensions)
    5923             : {
    5924         356 :     DumpOptions *dopt = fout->dopt;
    5925             :     PGresult   *res;
    5926             :     int         ntups;
    5927             :     int         i;
    5928             :     PQExpBuffer query;
    5929         356 :     ExtensionInfo *extinfo = NULL;
    5930             :     int         i_tableoid;
    5931             :     int         i_oid;
    5932             :     int         i_extname;
    5933             :     int         i_nspname;
    5934             :     int         i_extrelocatable;
    5935             :     int         i_extversion;
    5936             :     int         i_extconfig;
    5937             :     int         i_extcondition;
    5938             : 
    5939         356 :     query = createPQExpBuffer();
    5940             : 
    5941         356 :     appendPQExpBufferStr(query, "SELECT x.tableoid, x.oid, "
    5942             :                          "x.extname, n.nspname, x.extrelocatable, x.extversion, x.extconfig, x.extcondition "
    5943             :                          "FROM pg_extension x "
    5944             :                          "JOIN pg_namespace n ON n.oid = x.extnamespace");
    5945             : 
    5946         356 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    5947             : 
    5948         356 :     ntups = PQntuples(res);
    5949         356 :     if (ntups == 0)
    5950           0 :         goto cleanup;
    5951             : 
    5952         356 :     extinfo = (ExtensionInfo *) pg_malloc(ntups * sizeof(ExtensionInfo));
    5953             : 
    5954         356 :     i_tableoid = PQfnumber(res, "tableoid");
    5955         356 :     i_oid = PQfnumber(res, "oid");
    5956         356 :     i_extname = PQfnumber(res, "extname");
    5957         356 :     i_nspname = PQfnumber(res, "nspname");
    5958         356 :     i_extrelocatable = PQfnumber(res, "extrelocatable");
    5959         356 :     i_extversion = PQfnumber(res, "extversion");
    5960         356 :     i_extconfig = PQfnumber(res, "extconfig");
    5961         356 :     i_extcondition = PQfnumber(res, "extcondition");
    5962             : 
    5963         762 :     for (i = 0; i < ntups; i++)
    5964             :     {
    5965         406 :         extinfo[i].dobj.objType = DO_EXTENSION;
    5966         406 :         extinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    5967         406 :         extinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    5968         406 :         AssignDumpId(&extinfo[i].dobj);
    5969         406 :         extinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_extname));
    5970         406 :         extinfo[i].namespace = pg_strdup(PQgetvalue(res, i, i_nspname));
    5971         406 :         extinfo[i].relocatable = *(PQgetvalue(res, i, i_extrelocatable)) == 't';
    5972         406 :         extinfo[i].extversion = pg_strdup(PQgetvalue(res, i, i_extversion));
    5973         406 :         extinfo[i].extconfig = pg_strdup(PQgetvalue(res, i, i_extconfig));
    5974         406 :         extinfo[i].extcondition = pg_strdup(PQgetvalue(res, i, i_extcondition));
    5975             : 
    5976             :         /* Decide whether we want to dump it */
    5977         406 :         selectDumpableExtension(&(extinfo[i]), dopt);
    5978             :     }
    5979             : 
    5980         356 : cleanup:
    5981         356 :     PQclear(res);
    5982         356 :     destroyPQExpBuffer(query);
    5983             : 
    5984         356 :     *numExtensions = ntups;
    5985             : 
    5986         356 :     return extinfo;
    5987             : }
    5988             : 
    5989             : /*
    5990             :  * getTypes:
    5991             :  *    get information about all types in the system catalogs
    5992             :  *
    5993             :  * NB: this must run after getFuncs() because we assume we can do
    5994             :  * findFuncByOid().
    5995             :  */
    5996             : void
    5997         354 : getTypes(Archive *fout)
    5998             : {
    5999             :     PGresult   *res;
    6000             :     int         ntups;
    6001             :     int         i;
    6002         354 :     PQExpBuffer query = createPQExpBuffer();
    6003             :     TypeInfo   *tyinfo;
    6004             :     ShellTypeInfo *stinfo;
    6005             :     int         i_tableoid;
    6006             :     int         i_oid;
    6007             :     int         i_typname;
    6008             :     int         i_typnamespace;
    6009             :     int         i_typacl;
    6010             :     int         i_acldefault;
    6011             :     int         i_typowner;
    6012             :     int         i_typelem;
    6013             :     int         i_typrelid;
    6014             :     int         i_typrelkind;
    6015             :     int         i_typtype;
    6016             :     int         i_typisdefined;
    6017             :     int         i_isarray;
    6018             :     int         i_typarray;
    6019             : 
    6020             :     /*
    6021             :      * we include even the built-in types because those may be used as array
    6022             :      * elements by user-defined types
    6023             :      *
    6024             :      * we filter out the built-in types when we dump out the types
    6025             :      *
    6026             :      * same approach for undefined (shell) types and array types
    6027             :      *
    6028             :      * Note: as of 8.3 we can reliably detect whether a type is an
    6029             :      * auto-generated array type by checking the element type's typarray.
    6030             :      * (Before that the test is capable of generating false positives.) We
    6031             :      * still check for name beginning with '_', though, so as to avoid the
    6032             :      * cost of the subselect probe for all standard types.  This would have to
    6033             :      * be revisited if the backend ever allows renaming of array types.
    6034             :      */
    6035         354 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, typname, "
    6036             :                          "typnamespace, typacl, "
    6037             :                          "acldefault('T', typowner) AS acldefault, "
    6038             :                          "typowner, "
    6039             :                          "typelem, typrelid, typarray, "
    6040             :                          "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
    6041             :                          "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
    6042             :                          "typtype, typisdefined, "
    6043             :                          "typname[0] = '_' AND typelem != 0 AND "
    6044             :                          "(SELECT typarray FROM pg_type te WHERE oid = pg_type.typelem) = oid AS isarray "
    6045             :                          "FROM pg_type");
    6046             : 
    6047         354 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    6048             : 
    6049         354 :     ntups = PQntuples(res);
    6050             : 
    6051         354 :     tyinfo = (TypeInfo *) pg_malloc(ntups * sizeof(TypeInfo));
    6052             : 
    6053         354 :     i_tableoid = PQfnumber(res, "tableoid");
    6054         354 :     i_oid = PQfnumber(res, "oid");
    6055         354 :     i_typname = PQfnumber(res, "typname");
    6056         354 :     i_typnamespace = PQfnumber(res, "typnamespace");
    6057         354 :     i_typacl = PQfnumber(res, "typacl");
    6058         354 :     i_acldefault = PQfnumber(res, "acldefault");
    6059         354 :     i_typowner = PQfnumber(res, "typowner");
    6060         354 :     i_typelem = PQfnumber(res, "typelem");
    6061         354 :     i_typrelid = PQfnumber(res, "typrelid");
    6062         354 :     i_typrelkind = PQfnumber(res, "typrelkind");
    6063         354 :     i_typtype = PQfnumber(res, "typtype");
    6064         354 :     i_typisdefined = PQfnumber(res, "typisdefined");
    6065         354 :     i_isarray = PQfnumber(res, "isarray");
    6066         354 :     i_typarray = PQfnumber(res, "typarray");
    6067             : 
    6068      253880 :     for (i = 0; i < ntups; i++)
    6069             :     {
    6070      253526 :         tyinfo[i].dobj.objType = DO_TYPE;
    6071      253526 :         tyinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    6072      253526 :         tyinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    6073      253526 :         AssignDumpId(&tyinfo[i].dobj);
    6074      253526 :         tyinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_typname));
    6075      507052 :         tyinfo[i].dobj.namespace =
    6076      253526 :             findNamespace(atooid(PQgetvalue(res, i, i_typnamespace)));
    6077      253526 :         tyinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_typacl));
    6078      253526 :         tyinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
    6079      253526 :         tyinfo[i].dacl.privtype = 0;
    6080      253526 :         tyinfo[i].dacl.initprivs = NULL;
    6081      253526 :         tyinfo[i].ftypname = NULL;  /* may get filled later */
    6082      253526 :         tyinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_typowner));
    6083      253526 :         tyinfo[i].typelem = atooid(PQgetvalue(res, i, i_typelem));
    6084      253526 :         tyinfo[i].typrelid = atooid(PQgetvalue(res, i, i_typrelid));
    6085      253526 :         tyinfo[i].typrelkind = *PQgetvalue(res, i, i_typrelkind);
    6086      253526 :         tyinfo[i].typtype = *PQgetvalue(res, i, i_typtype);
    6087      253526 :         tyinfo[i].shellType = NULL;
    6088             : 
    6089      253526 :         if (strcmp(PQgetvalue(res, i, i_typisdefined), "t") == 0)
    6090      253414 :             tyinfo[i].isDefined = true;
    6091             :         else
    6092         112 :             tyinfo[i].isDefined = false;
    6093             : 
    6094      253526 :         if (strcmp(PQgetvalue(res, i, i_isarray), "t") == 0)
    6095      121574 :             tyinfo[i].isArray = true;
    6096             :         else
    6097      131952 :             tyinfo[i].isArray = false;
    6098             : 
    6099      253526 :         tyinfo[i].typarray = atooid(PQgetvalue(res, i, i_typarray));
    6100             : 
    6101      253526 :         if (tyinfo[i].typtype == TYPTYPE_MULTIRANGE)
    6102        2404 :             tyinfo[i].isMultirange = true;
    6103             :         else
    6104      251122 :             tyinfo[i].isMultirange = false;
    6105             : 
    6106             :         /* Decide whether we want to dump it */
    6107      253526 :         selectDumpableType(&tyinfo[i], fout);
    6108             : 
    6109             :         /* Mark whether type has an ACL */
    6110      253526 :         if (!PQgetisnull(res, i, i_typacl))
    6111         442 :             tyinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
    6112             : 
    6113             :         /*
    6114             :          * If it's a domain, fetch info about its constraints, if any
    6115             :          */
    6116      253526 :         tyinfo[i].nDomChecks = 0;
    6117      253526 :         tyinfo[i].domChecks = NULL;
    6118      253526 :         if ((tyinfo[i].dobj.dump & DUMP_COMPONENT_DEFINITION) &&
    6119       29066 :             tyinfo[i].typtype == TYPTYPE_DOMAIN)
    6120         294 :             getDomainConstraints(fout, &(tyinfo[i]));
    6121             : 
    6122             :         /*
    6123             :          * If it's a base type, make a DumpableObject representing a shell
    6124             :          * definition of the type.  We will need to dump that ahead of the I/O
    6125             :          * functions for the type.  Similarly, range types need a shell
    6126             :          * definition in case they have a canonicalize function.
    6127             :          *
    6128             :          * Note: the shell type doesn't have a catId.  You might think it
    6129             :          * should copy the base type's catId, but then it might capture the
    6130             :          * pg_depend entries for the type, which we don't want.
    6131             :          */
    6132      253526 :         if ((tyinfo[i].dobj.dump & DUMP_COMPONENT_DEFINITION) &&
    6133       29066 :             (tyinfo[i].typtype == TYPTYPE_BASE ||
    6134       14108 :              tyinfo[i].typtype == TYPTYPE_RANGE))
    6135             :         {
    6136       15222 :             stinfo = (ShellTypeInfo *) pg_malloc(sizeof(ShellTypeInfo));
    6137       15222 :             stinfo->dobj.objType = DO_SHELL_TYPE;
    6138       15222 :             stinfo->dobj.catId = nilCatalogId;
    6139       15222 :             AssignDumpId(&stinfo->dobj);
    6140       15222 :             stinfo->dobj.name = pg_strdup(tyinfo[i].dobj.name);
    6141       15222 :             stinfo->dobj.namespace = tyinfo[i].dobj.namespace;
    6142       15222 :             stinfo->baseType = &(tyinfo[i]);
    6143       15222 :             tyinfo[i].shellType = stinfo;
    6144             : 
    6145             :             /*
    6146             :              * Initially mark the shell type as not to be dumped.  We'll only
    6147             :              * dump it if the I/O or canonicalize functions need to be dumped;
    6148             :              * this is taken care of while sorting dependencies.
    6149             :              */
    6150       15222 :             stinfo->dobj.dump = DUMP_COMPONENT_NONE;
    6151             :         }
    6152             :     }
    6153             : 
    6154         354 :     PQclear(res);
    6155             : 
    6156         354 :     destroyPQExpBuffer(query);
    6157         354 : }
    6158             : 
    6159             : /*
    6160             :  * getOperators:
    6161             :  *    get information about all operators in the system catalogs
    6162             :  */
    6163             : void
    6164         354 : getOperators(Archive *fout)
    6165             : {
    6166             :     PGresult   *res;
    6167             :     int         ntups;
    6168             :     int         i;
    6169         354 :     PQExpBuffer query = createPQExpBuffer();
    6170             :     OprInfo    *oprinfo;
    6171             :     int         i_tableoid;
    6172             :     int         i_oid;
    6173             :     int         i_oprname;
    6174             :     int         i_oprnamespace;
    6175             :     int         i_oprowner;
    6176             :     int         i_oprkind;
    6177             :     int         i_oprcode;
    6178             : 
    6179             :     /*
    6180             :      * find all operators, including builtin operators; we filter out
    6181             :      * system-defined operators at dump-out time.
    6182             :      */
    6183             : 
    6184         354 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, oprname, "
    6185             :                          "oprnamespace, "
    6186             :                          "oprowner, "
    6187             :                          "oprkind, "
    6188             :                          "oprcode::oid AS oprcode "
    6189             :                          "FROM pg_operator");
    6190             : 
    6191         354 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    6192             : 
    6193         354 :     ntups = PQntuples(res);
    6194             : 
    6195         354 :     oprinfo = (OprInfo *) pg_malloc(ntups * sizeof(OprInfo));
    6196             : 
    6197         354 :     i_tableoid = PQfnumber(res, "tableoid");
    6198         354 :     i_oid = PQfnumber(res, "oid");
    6199         354 :     i_oprname = PQfnumber(res, "oprname");
    6200         354 :     i_oprnamespace = PQfnumber(res, "oprnamespace");
    6201         354 :     i_oprowner = PQfnumber(res, "oprowner");
    6202         354 :     i_oprkind = PQfnumber(res, "oprkind");
    6203         354 :     i_oprcode = PQfnumber(res, "oprcode");
    6204             : 
    6205      283492 :     for (i = 0; i < ntups; i++)
    6206             :     {
    6207      283138 :         oprinfo[i].dobj.objType = DO_OPERATOR;
    6208      283138 :         oprinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    6209      283138 :         oprinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    6210      283138 :         AssignDumpId(&oprinfo[i].dobj);
    6211      283138 :         oprinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_oprname));
    6212      566276 :         oprinfo[i].dobj.namespace =
    6213      283138 :             findNamespace(atooid(PQgetvalue(res, i, i_oprnamespace)));
    6214      283138 :         oprinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_oprowner));
    6215      283138 :         oprinfo[i].oprkind = (PQgetvalue(res, i, i_oprkind))[0];
    6216      283138 :         oprinfo[i].oprcode = atooid(PQgetvalue(res, i, i_oprcode));
    6217             : 
    6218             :         /* Decide whether we want to dump it */
    6219      283138 :         selectDumpableObject(&(oprinfo[i].dobj), fout);
    6220             :     }
    6221             : 
    6222         354 :     PQclear(res);
    6223             : 
    6224         354 :     destroyPQExpBuffer(query);
    6225         354 : }
    6226             : 
    6227             : /*
    6228             :  * getCollations:
    6229             :  *    get information about all collations in the system catalogs
    6230             :  */
    6231             : void
    6232         354 : getCollations(Archive *fout)
    6233             : {
    6234             :     PGresult   *res;
    6235             :     int         ntups;
    6236             :     int         i;
    6237             :     PQExpBuffer query;
    6238             :     CollInfo   *collinfo;
    6239             :     int         i_tableoid;
    6240             :     int         i_oid;
    6241             :     int         i_collname;
    6242             :     int         i_collnamespace;
    6243             :     int         i_collowner;
    6244             : 
    6245         354 :     query = createPQExpBuffer();
    6246             : 
    6247             :     /*
    6248             :      * find all collations, including builtin collations; we filter out
    6249             :      * system-defined collations at dump-out time.
    6250             :      */
    6251             : 
    6252         354 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, collname, "
    6253             :                          "collnamespace, "
    6254             :                          "collowner "
    6255             :                          "FROM pg_collation");
    6256             : 
    6257         354 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    6258             : 
    6259         354 :     ntups = PQntuples(res);
    6260             : 
    6261         354 :     collinfo = (CollInfo *) pg_malloc(ntups * sizeof(CollInfo));
    6262             : 
    6263         354 :     i_tableoid = PQfnumber(res, "tableoid");
    6264         354 :     i_oid = PQfnumber(res, "oid");
    6265         354 :     i_collname = PQfnumber(res, "collname");
    6266         354 :     i_collnamespace = PQfnumber(res, "collnamespace");
    6267         354 :     i_collowner = PQfnumber(res, "collowner");
    6268             : 
    6269      281314 :     for (i = 0; i < ntups; i++)
    6270             :     {
    6271      280960 :         collinfo[i].dobj.objType = DO_COLLATION;
    6272      280960 :         collinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    6273      280960 :         collinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    6274      280960 :         AssignDumpId(&collinfo[i].dobj);
    6275      280960 :         collinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_collname));
    6276      561920 :         collinfo[i].dobj.namespace =
    6277      280960 :             findNamespace(atooid(PQgetvalue(res, i, i_collnamespace)));
    6278      280960 :         collinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_collowner));
    6279             : 
    6280             :         /* Decide whether we want to dump it */
    6281      280960 :         selectDumpableObject(&(collinfo[i].dobj), fout);
    6282             :     }
    6283             : 
    6284         354 :     PQclear(res);
    6285             : 
    6286         354 :     destroyPQExpBuffer(query);
    6287         354 : }
    6288             : 
    6289             : /*
    6290             :  * getConversions:
    6291             :  *    get information about all conversions in the system catalogs
    6292             :  */
    6293             : void
    6294         354 : getConversions(Archive *fout)
    6295             : {
    6296             :     PGresult   *res;
    6297             :     int         ntups;
    6298             :     int         i;
    6299             :     PQExpBuffer query;
    6300             :     ConvInfo   *convinfo;
    6301             :     int         i_tableoid;
    6302             :     int         i_oid;
    6303             :     int         i_conname;
    6304             :     int         i_connamespace;
    6305             :     int         i_conowner;
    6306             : 
    6307         354 :     query = createPQExpBuffer();
    6308             : 
    6309             :     /*
    6310             :      * find all conversions, including builtin conversions; we filter out
    6311             :      * system-defined conversions at dump-out time.
    6312             :      */
    6313             : 
    6314         354 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, conname, "
    6315             :                          "connamespace, "
    6316             :                          "conowner "
    6317             :                          "FROM pg_conversion");
    6318             : 
    6319         354 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    6320             : 
    6321         354 :     ntups = PQntuples(res);
    6322             : 
    6323         354 :     convinfo = (ConvInfo *) pg_malloc(ntups * sizeof(ConvInfo));
    6324             : 
    6325         354 :     i_tableoid = PQfnumber(res, "tableoid");
    6326         354 :     i_oid = PQfnumber(res, "oid");
    6327         354 :     i_conname = PQfnumber(res, "conname");
    6328         354 :     i_connamespace = PQfnumber(res, "connamespace");
    6329         354 :     i_conowner = PQfnumber(res, "conowner");
    6330             : 
    6331       45764 :     for (i = 0; i < ntups; i++)
    6332             :     {
    6333       45410 :         convinfo[i].dobj.objType = DO_CONVERSION;
    6334       45410 :         convinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    6335       45410 :         convinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    6336       45410 :         AssignDumpId(&convinfo[i].dobj);
    6337       45410 :         convinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_conname));
    6338       90820 :         convinfo[i].dobj.namespace =
    6339       45410 :             findNamespace(atooid(PQgetvalue(res, i, i_connamespace)));
    6340       45410 :         convinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_conowner));
    6341             : 
    6342             :         /* Decide whether we want to dump it */
    6343       45410 :         selectDumpableObject(&(convinfo[i].dobj), fout);
    6344             :     }
    6345             : 
    6346         354 :     PQclear(res);
    6347             : 
    6348         354 :     destroyPQExpBuffer(query);
    6349         354 : }
    6350             : 
    6351             : /*
    6352             :  * getAccessMethods:
    6353             :  *    get information about all user-defined access methods
    6354             :  */
    6355             : void
    6356         354 : getAccessMethods(Archive *fout)
    6357             : {
    6358             :     PGresult   *res;
    6359             :     int         ntups;
    6360             :     int         i;
    6361             :     PQExpBuffer query;
    6362             :     AccessMethodInfo *aminfo;
    6363             :     int         i_tableoid;
    6364             :     int         i_oid;
    6365             :     int         i_amname;
    6366             :     int         i_amhandler;
    6367             :     int         i_amtype;
    6368             : 
    6369             :     /* Before 9.6, there are no user-defined access methods */
    6370         354 :     if (fout->remoteVersion < 90600)
    6371           0 :         return;
    6372             : 
    6373         354 :     query = createPQExpBuffer();
    6374             : 
    6375             :     /* Select all access methods from pg_am table */
    6376         354 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, amname, amtype, "
    6377             :                          "amhandler::pg_catalog.regproc AS amhandler "
    6378             :                          "FROM pg_am");
    6379             : 
    6380         354 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    6381             : 
    6382         354 :     ntups = PQntuples(res);
    6383             : 
    6384         354 :     aminfo = (AccessMethodInfo *) pg_malloc(ntups * sizeof(AccessMethodInfo));
    6385             : 
    6386         354 :     i_tableoid = PQfnumber(res, "tableoid");
    6387         354 :     i_oid = PQfnumber(res, "oid");
    6388         354 :     i_amname = PQfnumber(res, "amname");
    6389         354 :     i_amhandler = PQfnumber(res, "amhandler");
    6390         354 :     i_amtype = PQfnumber(res, "amtype");
    6391             : 
    6392        3092 :     for (i = 0; i < ntups; i++)
    6393             :     {
    6394        2738 :         aminfo[i].dobj.objType = DO_ACCESS_METHOD;
    6395        2738 :         aminfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    6396        2738 :         aminfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    6397        2738 :         AssignDumpId(&aminfo[i].dobj);
    6398        2738 :         aminfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_amname));
    6399        2738 :         aminfo[i].dobj.namespace = NULL;
    6400        2738 :         aminfo[i].amhandler = pg_strdup(PQgetvalue(res, i, i_amhandler));
    6401        2738 :         aminfo[i].amtype = *(PQgetvalue(res, i, i_amtype));
    6402             : 
    6403             :         /* Decide whether we want to dump it */
    6404        2738 :         selectDumpableAccessMethod(&(aminfo[i]), fout);
    6405             :     }
    6406             : 
    6407         354 :     PQclear(res);
    6408             : 
    6409         354 :     destroyPQExpBuffer(query);
    6410             : }
    6411             : 
    6412             : 
    6413             : /*
    6414             :  * getOpclasses:
    6415             :  *    get information about all opclasses in the system catalogs
    6416             :  */
    6417             : void
    6418         354 : getOpclasses(Archive *fout)
    6419             : {
    6420             :     PGresult   *res;
    6421             :     int         ntups;
    6422             :     int         i;
    6423         354 :     PQExpBuffer query = createPQExpBuffer();
    6424             :     OpclassInfo *opcinfo;
    6425             :     int         i_tableoid;
    6426             :     int         i_oid;
    6427             :     int         i_opcname;
    6428             :     int         i_opcnamespace;
    6429             :     int         i_opcowner;
    6430             : 
    6431             :     /*
    6432             :      * find all opclasses, including builtin opclasses; we filter out
    6433             :      * system-defined opclasses at dump-out time.
    6434             :      */
    6435             : 
    6436         354 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, opcname, "
    6437             :                          "opcnamespace, "
    6438             :                          "opcowner "
    6439             :                          "FROM pg_opclass");
    6440             : 
    6441         354 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    6442             : 
    6443         354 :     ntups = PQntuples(res);
    6444             : 
    6445         354 :     opcinfo = (OpclassInfo *) pg_malloc(ntups * sizeof(OpclassInfo));
    6446             : 
    6447         354 :     i_tableoid = PQfnumber(res, "tableoid");
    6448         354 :     i_oid = PQfnumber(res, "oid");
    6449         354 :     i_opcname = PQfnumber(res, "opcname");
    6450         354 :     i_opcnamespace = PQfnumber(res, "opcnamespace");
    6451         354 :     i_opcowner = PQfnumber(res, "opcowner");
    6452             : 
    6453       63348 :     for (i = 0; i < ntups; i++)
    6454             :     {
    6455       62994 :         opcinfo[i].dobj.objType = DO_OPCLASS;
    6456       62994 :         opcinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    6457       62994 :         opcinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    6458       62994 :         AssignDumpId(&opcinfo[i].dobj);
    6459       62994 :         opcinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_opcname));
    6460      125988 :         opcinfo[i].dobj.namespace =
    6461       62994 :             findNamespace(atooid(PQgetvalue(res, i, i_opcnamespace)));
    6462       62994 :         opcinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_opcowner));
    6463             : 
    6464             :         /* Decide whether we want to dump it */
    6465       62994 :         selectDumpableObject(&(opcinfo[i].dobj), fout);
    6466             :     }
    6467             : 
    6468         354 :     PQclear(res);
    6469             : 
    6470         354 :     destroyPQExpBuffer(query);
    6471         354 : }
    6472             : 
    6473             : /*
    6474             :  * getOpfamilies:
    6475             :  *    get information about all opfamilies in the system catalogs
    6476             :  */
    6477             : void
    6478         354 : getOpfamilies(Archive *fout)
    6479             : {
    6480             :     PGresult   *res;
    6481             :     int         ntups;
    6482             :     int         i;
    6483             :     PQExpBuffer query;
    6484             :     OpfamilyInfo *opfinfo;
    6485             :     int         i_tableoid;
    6486             :     int         i_oid;
    6487             :     int         i_opfname;
    6488             :     int         i_opfnamespace;
    6489             :     int         i_opfowner;
    6490             : 
    6491         354 :     query = createPQExpBuffer();
    6492             : 
    6493             :     /*
    6494             :      * find all opfamilies, including builtin opfamilies; we filter out
    6495             :      * system-defined opfamilies at dump-out time.
    6496             :      */
    6497             : 
    6498         354 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, opfname, "
    6499             :                          "opfnamespace, "
    6500             :                          "opfowner "
    6501             :                          "FROM pg_opfamily");
    6502             : 
    6503         354 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    6504             : 
    6505         354 :     ntups = PQntuples(res);
    6506             : 
    6507         354 :     opfinfo = (OpfamilyInfo *) pg_malloc(ntups * sizeof(OpfamilyInfo));
    6508             : 
    6509         354 :     i_tableoid = PQfnumber(res, "tableoid");
    6510         354 :     i_oid = PQfnumber(res, "oid");
    6511         354 :     i_opfname = PQfnumber(res, "opfname");
    6512         354 :     i_opfnamespace = PQfnumber(res, "opfnamespace");
    6513         354 :     i_opfowner = PQfnumber(res, "opfowner");
    6514             : 
    6515       52332 :     for (i = 0; i < ntups; i++)
    6516             :     {
    6517       51978 :         opfinfo[i].dobj.objType = DO_OPFAMILY;
    6518       51978 :         opfinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    6519       51978 :         opfinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    6520       51978 :         AssignDumpId(&opfinfo[i].dobj);
    6521       51978 :         opfinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_opfname));
    6522      103956 :         opfinfo[i].dobj.namespace =
    6523       51978 :             findNamespace(atooid(PQgetvalue(res, i, i_opfnamespace)));
    6524       51978 :         opfinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_opfowner));
    6525             : 
    6526             :         /* Decide whether we want to dump it */
    6527       51978 :         selectDumpableObject(&(opfinfo[i].dobj), fout);
    6528             :     }
    6529             : 
    6530         354 :     PQclear(res);
    6531             : 
    6532         354 :     destroyPQExpBuffer(query);
    6533         354 : }
    6534             : 
    6535             : /*
    6536             :  * getAggregates:
    6537             :  *    get information about all user-defined aggregates in the system catalogs
    6538             :  */
    6539             : void
    6540         354 : getAggregates(Archive *fout)
    6541             : {
    6542         354 :     DumpOptions *dopt = fout->dopt;
    6543             :     PGresult   *res;
    6544             :     int         ntups;
    6545             :     int         i;
    6546         354 :     PQExpBuffer query = createPQExpBuffer();
    6547             :     AggInfo    *agginfo;
    6548             :     int         i_tableoid;
    6549             :     int         i_oid;
    6550             :     int         i_aggname;
    6551             :     int         i_aggnamespace;
    6552             :     int         i_pronargs;
    6553             :     int         i_proargtypes;
    6554             :     int         i_proowner;
    6555             :     int         i_aggacl;
    6556             :     int         i_acldefault;
    6557             : 
    6558             :     /*
    6559             :      * Find all interesting aggregates.  See comment in getFuncs() for the
    6560             :      * rationale behind the filtering logic.
    6561             :      */
    6562         354 :     if (fout->remoteVersion >= 90600)
    6563             :     {
    6564             :         const char *agg_check;
    6565             : 
    6566         708 :         agg_check = (fout->remoteVersion >= 110000 ? "p.prokind = 'a'"
    6567         354 :                      : "p.proisagg");
    6568             : 
    6569         354 :         appendPQExpBuffer(query, "SELECT p.tableoid, p.oid, "
    6570             :                           "p.proname AS aggname, "
    6571             :                           "p.pronamespace AS aggnamespace, "
    6572             :                           "p.pronargs, p.proargtypes, "
    6573             :                           "p.proowner, "
    6574             :                           "p.proacl AS aggacl, "
    6575             :                           "acldefault('f', p.proowner) AS acldefault "
    6576             :                           "FROM pg_proc p "
    6577             :                           "LEFT JOIN pg_init_privs pip ON "
    6578             :                           "(p.oid = pip.objoid "
    6579             :                           "AND pip.classoid = 'pg_proc'::regclass "
    6580             :                           "AND pip.objsubid = 0) "
    6581             :                           "WHERE %s AND ("
    6582             :                           "p.pronamespace != "
    6583             :                           "(SELECT oid FROM pg_namespace "
    6584             :                           "WHERE nspname = 'pg_catalog') OR "
    6585             :                           "p.proacl IS DISTINCT FROM pip.initprivs",
    6586             :                           agg_check);
    6587         354 :         if (dopt->binary_upgrade)
    6588          62 :             appendPQExpBufferStr(query,
    6589             :                                  " OR EXISTS(SELECT 1 FROM pg_depend WHERE "
    6590             :                                  "classid = 'pg_proc'::regclass AND "
    6591             :                                  "objid = p.oid AND "
    6592             :                                  "refclassid = 'pg_extension'::regclass AND "
    6593             :                                  "deptype = 'e')");
    6594         354 :         appendPQExpBufferChar(query, ')');
    6595             :     }
    6596             :     else
    6597             :     {
    6598           0 :         appendPQExpBufferStr(query, "SELECT tableoid, oid, proname AS aggname, "
    6599             :                              "pronamespace AS aggnamespace, "
    6600             :                              "pronargs, proargtypes, "
    6601             :                              "proowner, "
    6602             :                              "proacl AS aggacl, "
    6603             :                              "acldefault('f', proowner) AS acldefault "
    6604             :                              "FROM pg_proc p "
    6605             :                              "WHERE proisagg AND ("
    6606             :                              "pronamespace != "
    6607             :                              "(SELECT oid FROM pg_namespace "
    6608             :                              "WHERE nspname = 'pg_catalog')");
    6609           0 :         if (dopt->binary_upgrade)
    6610           0 :             appendPQExpBufferStr(query,
    6611             :                                  " OR EXISTS(SELECT 1 FROM pg_depend WHERE "
    6612             :                                  "classid = 'pg_proc'::regclass AND "
    6613             :                                  "objid = p.oid AND "
    6614             :                                  "refclassid = 'pg_extension'::regclass AND "
    6615             :                                  "deptype = 'e')");
    6616           0 :         appendPQExpBufferChar(query, ')');
    6617             :     }
    6618             : 
    6619         354 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    6620             : 
    6621         354 :     ntups = PQntuples(res);
    6622             : 
    6623         354 :     agginfo = (AggInfo *) pg_malloc(ntups * sizeof(AggInfo));
    6624             : 
    6625         354 :     i_tableoid = PQfnumber(res, "tableoid");
    6626         354 :     i_oid = PQfnumber(res, "oid");
    6627         354 :     i_aggname = PQfnumber(res, "aggname");
    6628         354 :     i_aggnamespace = PQfnumber(res, "aggnamespace");
    6629         354 :     i_pronargs = PQfnumber(res, "pronargs");
    6630         354 :     i_proargtypes = PQfnumber(res, "proargtypes");
    6631         354 :     i_proowner = PQfnumber(res, "proowner");
    6632         354 :     i_aggacl = PQfnumber(res, "aggacl");
    6633         354 :     i_acldefault = PQfnumber(res, "acldefault");
    6634             : 
    6635        1160 :     for (i = 0; i < ntups; i++)
    6636             :     {
    6637         806 :         agginfo[i].aggfn.dobj.objType = DO_AGG;
    6638         806 :         agginfo[i].aggfn.dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    6639         806 :         agginfo[i].aggfn.dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    6640         806 :         AssignDumpId(&agginfo[i].aggfn.dobj);
    6641         806 :         agginfo[i].aggfn.dobj.name = pg_strdup(PQgetvalue(res, i, i_aggname));
    6642        1612 :         agginfo[i].aggfn.dobj.namespace =
    6643         806 :             findNamespace(atooid(PQgetvalue(res, i, i_aggnamespace)));
    6644         806 :         agginfo[i].aggfn.dacl.acl = pg_strdup(PQgetvalue(res, i, i_aggacl));
    6645         806 :         agginfo[i].aggfn.dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
    6646         806 :         agginfo[i].aggfn.dacl.privtype = 0;
    6647         806 :         agginfo[i].aggfn.dacl.initprivs = NULL;
    6648         806 :         agginfo[i].aggfn.rolname = getRoleName(PQgetvalue(res, i, i_proowner));
    6649         806 :         agginfo[i].aggfn.lang = InvalidOid; /* not currently interesting */
    6650         806 :         agginfo[i].aggfn.prorettype = InvalidOid;   /* not saved */
    6651         806 :         agginfo[i].aggfn.nargs = atoi(PQgetvalue(res, i, i_pronargs));
    6652         806 :         if (agginfo[i].aggfn.nargs == 0)
    6653         112 :             agginfo[i].aggfn.argtypes = NULL;
    6654             :         else
    6655             :         {
    6656         694 :             agginfo[i].aggfn.argtypes = (Oid *) pg_malloc(agginfo[i].aggfn.nargs * sizeof(Oid));
    6657         694 :             parseOidArray(PQgetvalue(res, i, i_proargtypes),
    6658         694 :                           agginfo[i].aggfn.argtypes,
    6659         694 :                           agginfo[i].aggfn.nargs);
    6660             :         }
    6661         806 :         agginfo[i].aggfn.postponed_def = false; /* might get set during sort */
    6662             : 
    6663             :         /* Decide whether we want to dump it */
    6664         806 :         selectDumpableObject(&(agginfo[i].aggfn.dobj), fout);
    6665             : 
    6666             :         /* Mark whether aggregate has an ACL */
    6667         806 :         if (!PQgetisnull(res, i, i_aggacl))
    6668          50 :             agginfo[i].aggfn.dobj.components |= DUMP_COMPONENT_ACL;
    6669             :     }
    6670             : 
    6671         354 :     PQclear(res);
    6672             : 
    6673         354 :     destroyPQExpBuffer(query);
    6674         354 : }
    6675             : 
    6676             : /*
    6677             :  * getFuncs:
    6678             :  *    get information about all user-defined functions in the system catalogs
    6679             :  */
    6680             : void
    6681         354 : getFuncs(Archive *fout)
    6682             : {
    6683         354 :     DumpOptions *dopt = fout->dopt;
    6684             :     PGresult   *res;
    6685             :     int         ntups;
    6686             :     int         i;
    6687         354 :     PQExpBuffer query = createPQExpBuffer();
    6688             :     FuncInfo   *finfo;
    6689             :     int         i_tableoid;
    6690             :     int         i_oid;
    6691             :     int         i_proname;
    6692             :     int         i_pronamespace;
    6693             :     int         i_proowner;
    6694             :     int         i_prolang;
    6695             :     int         i_pronargs;
    6696             :     int         i_proargtypes;
    6697             :     int         i_prorettype;
    6698             :     int         i_proacl;
    6699             :     int         i_acldefault;
    6700             : 
    6701             :     /*
    6702             :      * Find all interesting functions.  This is a bit complicated:
    6703             :      *
    6704             :      * 1. Always exclude aggregates; those are handled elsewhere.
    6705             :      *
    6706             :      * 2. Always exclude functions that are internally dependent on something
    6707             :      * else, since presumably those will be created as a result of creating
    6708             :      * the something else.  This currently acts only to suppress constructor
    6709             :      * functions for range types.  Note this is OK only because the
    6710             :      * constructors don't have any dependencies the range type doesn't have;
    6711             :      * otherwise we might not get creation ordering correct.
    6712             :      *
    6713             :      * 3. Otherwise, we normally exclude functions in pg_catalog.  However, if
    6714             :      * they're members of extensions and we are in binary-upgrade mode then
    6715             :      * include them, since we want to dump extension members individually in
    6716             :      * that mode.  Also, if they are used by casts or transforms then we need
    6717             :      * to gather the information about them, though they won't be dumped if
    6718             :      * they are built-in.  Also, in 9.6 and up, include functions in
    6719             :      * pg_catalog if they have an ACL different from what's shown in
    6720             :      * pg_init_privs (so we have to join to pg_init_privs; annoying).
    6721             :      */
    6722         354 :     if (fout->remoteVersion >= 90600)
    6723             :     {
    6724             :         const char *not_agg_check;
    6725             : 
    6726         708 :         not_agg_check = (fout->remoteVersion >= 110000 ? "p.prokind <> 'a'"
    6727         354 :                          : "NOT p.proisagg");
    6728             : 
    6729         354 :         appendPQExpBuffer(query,
    6730             :                           "SELECT p.tableoid, p.oid, p.proname, p.prolang, "
    6731             :                           "p.pronargs, p.proargtypes, p.prorettype, "
    6732             :                           "p.proacl, "
    6733             :                           "acldefault('f', p.proowner) AS acldefault, "
    6734             :                           "p.pronamespace, "
    6735             :                           "p.proowner "
    6736             :                           "FROM pg_proc p "
    6737             :                           "LEFT JOIN pg_init_privs pip ON "
    6738             :                           "(p.oid = pip.objoid "
    6739             :                           "AND pip.classoid = 'pg_proc'::regclass "
    6740             :                           "AND pip.objsubid = 0) "
    6741             :                           "WHERE %s"
    6742             :                           "\n  AND NOT EXISTS (SELECT 1 FROM pg_depend "
    6743             :                           "WHERE classid = 'pg_proc'::regclass AND "
    6744             :                           "objid = p.oid AND deptype = 'i')"
    6745             :                           "\n  AND ("
    6746             :                           "\n  pronamespace != "
    6747             :                           "(SELECT oid FROM pg_namespace "
    6748             :                           "WHERE nspname = 'pg_catalog')"
    6749             :                           "\n  OR EXISTS (SELECT 1 FROM pg_cast"
    6750             :                           "\n  WHERE pg_cast.oid > %u "
    6751             :                           "\n  AND p.oid = pg_cast.castfunc)"
    6752             :                           "\n  OR EXISTS (SELECT 1 FROM pg_transform"
    6753             :                           "\n  WHERE pg_transform.oid > %u AND "
    6754             :                           "\n  (p.oid = pg_transform.trffromsql"
    6755             :                           "\n  OR p.oid = pg_transform.trftosql))",
    6756             :                           not_agg_check,
    6757             :                           g_last_builtin_oid,
    6758             :                           g_last_builtin_oid);
    6759         354 :         if (dopt->binary_upgrade)
    6760          62 :             appendPQExpBufferStr(query,
    6761             :                                  "\n  OR EXISTS(SELECT 1 FROM pg_depend WHERE "
    6762             :                                  "classid = 'pg_proc'::regclass AND "
    6763             :                                  "objid = p.oid AND "
    6764             :                                  "refclassid = 'pg_extension'::regclass AND "
    6765             :                                  "deptype = 'e')");
    6766         354 :         appendPQExpBufferStr(query,
    6767             :                              "\n  OR p.proacl IS DISTINCT FROM pip.initprivs");
    6768         354 :         appendPQExpBufferChar(query, ')');
    6769             :     }
    6770             :     else
    6771             :     {
    6772           0 :         appendPQExpBuffer(query,
    6773             :                           "SELECT tableoid, oid, proname, prolang, "
    6774             :                           "pronargs, proargtypes, prorettype, proacl, "
    6775             :                           "acldefault('f', proowner) AS acldefault, "
    6776             :                           "pronamespace, "
    6777             :                           "proowner "
    6778             :                           "FROM pg_proc p "
    6779             :                           "WHERE NOT proisagg"
    6780             :                           "\n  AND NOT EXISTS (SELECT 1 FROM pg_depend "
    6781             :                           "WHERE classid = 'pg_proc'::regclass AND "
    6782             :                           "objid = p.oid AND deptype = 'i')"
    6783             :                           "\n  AND ("
    6784             :                           "\n  pronamespace != "
    6785             :                           "(SELECT oid FROM pg_namespace "
    6786             :                           "WHERE nspname = 'pg_catalog')"
    6787             :                           "\n  OR EXISTS (SELECT 1 FROM pg_cast"
    6788             :                           "\n  WHERE pg_cast.oid > '%u'::oid"
    6789             :                           "\n  AND p.oid = pg_cast.castfunc)",
    6790             :                           g_last_builtin_oid);
    6791             : 
    6792           0 :         if (fout->remoteVersion >= 90500)
    6793           0 :             appendPQExpBuffer(query,
    6794             :                               "\n  OR EXISTS (SELECT 1 FROM pg_transform"
    6795             :                               "\n  WHERE pg_transform.oid > '%u'::oid"
    6796             :                               "\n  AND (p.oid = pg_transform.trffromsql"
    6797             :                               "\n  OR p.oid = pg_transform.trftosql))",
    6798             :                               g_last_builtin_oid);
    6799             : 
    6800           0 :         if (dopt->binary_upgrade)
    6801           0 :             appendPQExpBufferStr(query,
    6802             :                                  "\n  OR EXISTS(SELECT 1 FROM pg_depend WHERE "
    6803             :                                  "classid = 'pg_proc'::regclass AND "
    6804             :                                  "objid = p.oid AND "
    6805             :                                  "refclassid = 'pg_extension'::regclass AND "
    6806             :                                  "deptype = 'e')");
    6807           0 :         appendPQExpBufferChar(query, ')');
    6808             :     }
    6809             : 
    6810         354 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    6811             : 
    6812         354 :     ntups = PQntuples(res);
    6813             : 
    6814         354 :     finfo = (FuncInfo *) pg_malloc0(ntups * sizeof(FuncInfo));
    6815             : 
    6816         354 :     i_tableoid = PQfnumber(res, "tableoid");
    6817         354 :     i_oid = PQfnumber(res, "oid");
    6818         354 :     i_proname = PQfnumber(res, "proname");
    6819         354 :     i_pronamespace = PQfnumber(res, "pronamespace");
    6820         354 :     i_proowner = PQfnumber(res, "proowner");
    6821         354 :     i_prolang = PQfnumber(res, "prolang");
    6822         354 :     i_pronargs = PQfnumber(res, "pronargs");
    6823         354 :     i_proargtypes = PQfnumber(res, "proargtypes");
    6824         354 :     i_prorettype = PQfnumber(res, "prorettype");
    6825         354 :     i_proacl = PQfnumber(res, "proacl");
    6826         354 :     i_acldefault = PQfnumber(res, "acldefault");
    6827             : 
    6828        9772 :     for (i = 0; i < ntups; i++)
    6829             :     {
    6830        9418 :         finfo[i].dobj.objType = DO_FUNC;
    6831        9418 :         finfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    6832        9418 :         finfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    6833        9418 :         AssignDumpId(&finfo[i].dobj);
    6834        9418 :         finfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_proname));
    6835       18836 :         finfo[i].dobj.namespace =
    6836        9418 :             findNamespace(atooid(PQgetvalue(res, i, i_pronamespace)));
    6837        9418 :         finfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_proacl));
    6838        9418 :         finfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
    6839        9418 :         finfo[i].dacl.privtype = 0;
    6840        9418 :         finfo[i].dacl.initprivs = NULL;
    6841        9418 :         finfo[i].rolname = getRoleName(PQgetvalue(res, i, i_proowner));
    6842        9418 :         finfo[i].lang = atooid(PQgetvalue(res, i, i_prolang));
    6843        9418 :         finfo[i].prorettype = atooid(PQgetvalue(res, i, i_prorettype));
    6844        9418 :         finfo[i].nargs = atoi(PQgetvalue(res, i, i_pronargs));
    6845        9418 :         if (finfo[i].nargs == 0)
    6846        2210 :             finfo[i].argtypes = NULL;
    6847             :         else
    6848             :         {
    6849        7208 :             finfo[i].argtypes = (Oid *) pg_malloc(finfo[i].nargs * sizeof(Oid));
    6850        7208 :             parseOidArray(PQgetvalue(res, i, i_proargtypes),
    6851        7208 :                           finfo[i].argtypes, finfo[i].nargs);
    6852             :         }
    6853        9418 :         finfo[i].postponed_def = false; /* might get set during sort */
    6854             : 
    6855             :         /* Decide whether we want to dump it */
    6856        9418 :         selectDumpableObject(&(finfo[i].dobj), fout);
    6857             : 
    6858             :         /* Mark whether function has an ACL */
    6859        9418 :         if (!PQgetisnull(res, i, i_proacl))
    6860         296 :             finfo[i].dobj.components |= DUMP_COMPONENT_ACL;
    6861             :     }
    6862             : 
    6863         354 :     PQclear(res);
    6864             : 
    6865         354 :     destroyPQExpBuffer(query);
    6866         354 : }
    6867             : 
    6868             : /*
    6869             :  * getRelationStatistics
    6870             :  *    register the statistics object as a dependent of the relation.
    6871             :  *
    6872             :  * reltuples is passed as a string to avoid complexities in converting from/to
    6873             :  * floating point.
    6874             :  */
    6875             : static RelStatsInfo *
    6876       18844 : getRelationStatistics(Archive *fout, DumpableObject *rel, int32 relpages,
    6877             :                       char *reltuples, int32 relallvisible,
    6878             :                       int32 relallfrozen, char relkind,
    6879             :                       char **indAttNames, int nindAttNames)
    6880             : {
    6881       18844 :     if (!fout->dopt->dumpStatistics)
    6882        5084 :         return NULL;
    6883             : 
    6884       13760 :     if ((relkind == RELKIND_RELATION) ||
    6885        6258 :         (relkind == RELKIND_PARTITIONED_TABLE) ||
    6886        3212 :         (relkind == RELKIND_INDEX) ||
    6887        2292 :         (relkind == RELKIND_PARTITIONED_INDEX) ||
    6888             :         (relkind == RELKIND_MATVIEW))
    6889             :     {
    6890       12276 :         RelStatsInfo *info = pg_malloc0(sizeof(RelStatsInfo));
    6891       12276 :         DumpableObject *dobj = &info->dobj;
    6892             : 
    6893       12276 :         dobj->objType = DO_REL_STATS;
    6894       12276 :         dobj->catId.tableoid = 0;
    6895       12276 :         dobj->catId.oid = 0;
    6896       12276 :         AssignDumpId(dobj);
    6897       12276 :         dobj->dependencies = (DumpId *) pg_malloc(sizeof(DumpId));
    6898       12276 :         dobj->dependencies[0] = rel->dumpId;
    6899       12276 :         dobj->nDeps = 1;
    6900       12276 :         dobj->allocDeps = 1;
    6901       12276 :         dobj->components |= DUMP_COMPONENT_STATISTICS;
    6902       12276 :         dobj->name = pg_strdup(rel->name);
    6903       12276 :         dobj->namespace = rel->namespace;
    6904       12276 :         info->relpages = relpages;
    6905       12276 :         info->reltuples = pstrdup(reltuples);
    6906       12276 :         info->relallvisible = relallvisible;
    6907       12276 :         info->relallfrozen = relallfrozen;
    6908       12276 :         info->relkind = relkind;
    6909       12276 :         info->indAttNames = indAttNames;
    6910       12276 :         info->nindAttNames = nindAttNames;
    6911             : 
    6912             :         /*
    6913             :          * Ordinarily, stats go in SECTION_DATA for tables and
    6914             :          * SECTION_POST_DATA for indexes.
    6915             :          *
    6916             :          * However, the section may be updated later for materialized view
    6917             :          * stats. REFRESH MATERIALIZED VIEW replaces the storage and resets
    6918             :          * the stats, so the stats must be restored after the data. Also, the
    6919             :          * materialized view definition may be postponed to SECTION_POST_DATA
    6920             :          * (see repairMatViewBoundaryMultiLoop()).
    6921             :          */
    6922       12276 :         switch (info->relkind)
    6923             :         {
    6924        8310 :             case RELKIND_RELATION:
    6925             :             case RELKIND_PARTITIONED_TABLE:
    6926             :             case RELKIND_MATVIEW:
    6927        8310 :                 info->section = SECTION_DATA;
    6928        8310 :                 break;
    6929        3966 :             case RELKIND_INDEX:
    6930             :             case RELKIND_PARTITIONED_INDEX:
    6931        3966 :                 info->section = SECTION_POST_DATA;
    6932        3966 :                 break;
    6933           0 :             default:
    6934           0 :                 pg_fatal("cannot dump statistics for relation kind '%c'",
    6935             :                          info->relkind);
    6936             :         }
    6937             : 
    6938       12276 :         return info;
    6939             :     }
    6940        1484 :     return NULL;
    6941             : }
    6942             : 
    6943             : /*
    6944             :  * getTables
    6945             :  *    read all the tables (no indexes) in the system catalogs,
    6946             :  *    and return them as an array of TableInfo structures
    6947             :  *
    6948             :  * *numTables is set to the number of tables read in
    6949             :  */
    6950             : TableInfo *
    6951         356 : getTables(Archive *fout, int *numTables)
    6952             : {
    6953         356 :     DumpOptions *dopt = fout->dopt;
    6954             :     PGresult   *res;
    6955             :     int         ntups;
    6956             :     int         i;
    6957         356 :     PQExpBuffer query = createPQExpBuffer();
    6958             :     TableInfo  *tblinfo;
    6959             :     int         i_reltableoid;
    6960             :     int         i_reloid;
    6961             :     int         i_relname;
    6962             :     int         i_relnamespace;
    6963             :     int         i_relkind;
    6964             :     int         i_reltype;
    6965             :     int         i_relowner;
    6966             :     int         i_relchecks;
    6967             :     int         i_relhasindex;
    6968             :     int         i_relhasrules;
    6969             :     int         i_relpages;
    6970             :     int         i_reltuples;
    6971             :     int         i_relallvisible;
    6972             :     int         i_relallfrozen;
    6973             :     int         i_toastpages;
    6974             :     int         i_owning_tab;
    6975             :     int         i_owning_col;
    6976             :     int         i_reltablespace;
    6977             :     int         i_relhasoids;
    6978             :     int         i_relhastriggers;
    6979             :     int         i_relpersistence;
    6980             :     int         i_relispopulated;
    6981             :     int         i_relreplident;
    6982             :     int         i_relrowsec;
    6983             :     int         i_relforcerowsec;
    6984             :     int         i_relfrozenxid;
    6985             :     int         i_toastfrozenxid;
    6986             :     int         i_toastoid;
    6987             :     int         i_relminmxid;
    6988             :     int         i_toastminmxid;
    6989             :     int         i_reloptions;
    6990             :     int         i_checkoption;
    6991             :     int         i_toastreloptions;
    6992             :     int         i_reloftype;
    6993             :     int         i_foreignserver;
    6994             :     int         i_amname;
    6995             :     int         i_is_identity_sequence;
    6996             :     int         i_relacl;
    6997             :     int         i_acldefault;
    6998             :     int         i_ispartition;
    6999             : 
    7000             :     /*
    7001             :      * Find all the tables and table-like objects.
    7002             :      *
    7003             :      * We must fetch all tables in this phase because otherwise we cannot
    7004             :      * correctly identify inherited columns, owned sequences, etc.
    7005             :      *
    7006             :      * We include system catalogs, so that we can work if a user table is
    7007             :      * defined to inherit from a system catalog (pretty weird, but...)
    7008             :      *
    7009             :      * Note: in this phase we should collect only a minimal amount of
    7010             :      * information about each table, basically just enough to decide if it is
    7011             :      * interesting.  In particular, since we do not yet have lock on any user
    7012             :      * table, we MUST NOT invoke any server-side data collection functions
    7013             :      * (for instance, pg_get_partkeydef()).  Those are likely to fail or give
    7014             :      * wrong answers if any concurrent DDL is happening.
    7015             :      */
    7016             : 
    7017         356 :     appendPQExpBufferStr(query,
    7018             :                          "SELECT c.tableoid, c.oid, c.relname, "
    7019             :                          "c.relnamespace, c.relkind, c.reltype, "
    7020             :                          "c.relowner, "
    7021             :                          "c.relchecks, "
    7022             :                          "c.relhasindex, c.relhasrules, c.relpages, "
    7023             :                          "c.reltuples, c.relallvisible, ");
    7024             : 
    7025         356 :     if (fout->remoteVersion >= 180000)
    7026         356 :         appendPQExpBufferStr(query, "c.relallfrozen, ");
    7027             :     else
    7028           0 :         appendPQExpBufferStr(query, "0 AS relallfrozen, ");
    7029             : 
    7030         356 :     appendPQExpBufferStr(query,
    7031             :                          "c.relhastriggers, c.relpersistence, "
    7032             :                          "c.reloftype, "
    7033             :                          "c.relacl, "
    7034             :                          "acldefault(CASE WHEN c.relkind = " CppAsString2(RELKIND_SEQUENCE)
    7035             :                          " THEN 's'::\"char\" ELSE 'r'::\"char\" END, c.relowner) AS acldefault, "
    7036             :                          "CASE WHEN c.relkind = " CppAsString2(RELKIND_FOREIGN_TABLE) " THEN "
    7037             :                          "(SELECT ftserver FROM pg_catalog.pg_foreign_table WHERE ftrelid = c.oid) "
    7038             :                          "ELSE 0 END AS foreignserver, "
    7039             :                          "c.relfrozenxid, tc.relfrozenxid AS tfrozenxid, "
    7040             :                          "tc.oid AS toid, "
    7041             :                          "tc.relpages AS toastpages, "
    7042             :                          "tc.reloptions AS toast_reloptions, "
    7043             :                          "d.refobjid AS owning_tab, "
    7044             :                          "d.refobjsubid AS owning_col, "
    7045             :                          "tsp.spcname AS reltablespace, ");
    7046             : 
    7047         356 :     if (fout->remoteVersion >= 120000)
    7048         356 :         appendPQExpBufferStr(query,
    7049             :                              "false AS relhasoids, ");
    7050             :     else
    7051           0 :         appendPQExpBufferStr(query,
    7052             :                              "c.relhasoids, ");
    7053             : 
    7054         356 :     if (fout->remoteVersion >= 90300)
    7055         356 :         appendPQExpBufferStr(query,
    7056             :                              "c.relispopulated, ");
    7057             :     else
    7058           0 :         appendPQExpBufferStr(query,
    7059             :                              "'t' as relispopulated, ");
    7060             : 
    7061         356 :     if (fout->remoteVersion >= 90400)
    7062         356 :         appendPQExpBufferStr(query,
    7063             :                              "c.relreplident, ");
    7064             :     else
    7065           0 :         appendPQExpBufferStr(query,
    7066             :                              "'d' AS relreplident, ");
    7067             : 
    7068         356 :     if (fout->remoteVersion >= 90500)
    7069         356 :         appendPQExpBufferStr(query,
    7070             :                              "c.relrowsecurity, c.relforcerowsecurity, ");
    7071             :     else
    7072           0 :         appendPQExpBufferStr(query,
    7073             :                              "false AS relrowsecurity, "
    7074             :                              "false AS relforcerowsecurity, ");
    7075             : 
    7076         356 :     if (fout->remoteVersion >= 90300)
    7077         356 :         appendPQExpBufferStr(query,
    7078             :                              "c.relminmxid, tc.relminmxid AS tminmxid, ");
    7079             :     else
    7080           0 :         appendPQExpBufferStr(query,
    7081             :                              "0 AS relminmxid, 0 AS tminmxid, ");
    7082             : 
    7083         356 :     if (fout->remoteVersion >= 90300)
    7084         356 :         appendPQExpBufferStr(query,
    7085             :                              "array_remove(array_remove(c.reloptions,'check_option=local'),'check_option=cascaded') AS reloptions, "
    7086             :                              "CASE WHEN 'check_option=local' = ANY (c.reloptions) THEN 'LOCAL'::text "
    7087             :                              "WHEN 'check_option=cascaded' = ANY (c.reloptions) THEN 'CASCADED'::text ELSE NULL END AS checkoption, ");
    7088             :     else
    7089           0 :         appendPQExpBufferStr(query,
    7090             :                              "c.reloptions, NULL AS checkoption, ");
    7091             : 
    7092         356 :     if (fout->remoteVersion >= 90600)
    7093         356 :         appendPQExpBufferStr(query,
    7094             :                              "am.amname, ");
    7095             :     else
    7096           0 :         appendPQExpBufferStr(query,
    7097             :                              "NULL AS amname, ");
    7098             : 
    7099         356 :     if (fout->remoteVersion >= 90600)
    7100         356 :         appendPQExpBufferStr(query,
    7101             :                              "(d.deptype = 'i') IS TRUE AS is_identity_sequence, ");
    7102             :     else
    7103           0 :         appendPQExpBufferStr(query,
    7104             :                              "false AS is_identity_sequence, ");
    7105             : 
    7106         356 :     if (fout->remoteVersion >= 100000)
    7107         356 :         appendPQExpBufferStr(query,
    7108             :                              "c.relispartition AS ispartition ");
    7109             :     else
    7110           0 :         appendPQExpBufferStr(query,
    7111             :                              "false AS ispartition ");
    7112             : 
    7113             :     /*
    7114             :      * Left join to pg_depend to pick up dependency info linking sequences to
    7115             :      * their owning column, if any (note this dependency is AUTO except for
    7116             :      * identity sequences, where it's INTERNAL). Also join to pg_tablespace to
    7117             :      * collect the spcname.
    7118             :      */
    7119         356 :     appendPQExpBufferStr(query,
    7120             :                          "\nFROM pg_class c\n"
    7121             :                          "LEFT JOIN pg_depend d ON "
    7122             :                          "(c.relkind = " CppAsString2(RELKIND_SEQUENCE) " AND "
    7123             :                          "d.classid = 'pg_class'::regclass AND d.objid = c.oid AND "
    7124             :                          "d.objsubid = 0 AND "
    7125             :                          "d.refclassid = 'pg_class'::regclass AND d.deptype IN ('a', 'i'))\n"
    7126             :                          "LEFT JOIN pg_tablespace tsp ON (tsp.oid = c.reltablespace)\n");
    7127             : 
    7128             :     /*
    7129             :      * In 9.6 and up, left join to pg_am to pick up the amname.
    7130             :      */
    7131         356 :     if (fout->remoteVersion >= 90600)
    7132         356 :         appendPQExpBufferStr(query,
    7133             :                              "LEFT JOIN pg_am am ON (c.relam = am.oid)\n");
    7134             : 
    7135             :     /*
    7136             :      * We purposefully ignore toast OIDs for partitioned tables; the reason is
    7137             :      * that versions 10 and 11 have them, but later versions do not, so
    7138             :      * emitting them causes the upgrade to fail.
    7139             :      */
    7140         356 :     appendPQExpBufferStr(query,
    7141             :                          "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid"
    7142             :                          " AND tc.relkind = " CppAsString2(RELKIND_TOASTVALUE)
    7143             :                          " AND c.relkind <> " CppAsString2(RELKIND_PARTITIONED_TABLE) ")\n");
    7144             : 
    7145             :     /*
    7146             :      * Restrict to interesting relkinds (in particular, not indexes).  Not all
    7147             :      * relkinds are possible in older servers, but it's not worth the trouble
    7148             :      * to emit a version-dependent list.
    7149             :      *
    7150             :      * Composite-type table entries won't be dumped as such, but we have to
    7151             :      * make a DumpableObject for them so that we can track dependencies of the
    7152             :      * composite type (pg_depend entries for columns of the composite type
    7153             :      * link to the pg_class entry not the pg_type entry).
    7154             :      */
    7155         356 :     appendPQExpBufferStr(query,
    7156             :                          "WHERE c.relkind IN ("
    7157             :                          CppAsString2(RELKIND_RELATION) ", "
    7158             :                          CppAsString2(RELKIND_SEQUENCE) ", "
    7159             :                          CppAsString2(RELKIND_VIEW) ", "
    7160             :                          CppAsString2(RELKIND_COMPOSITE_TYPE) ", "
    7161             :                          CppAsString2(RELKIND_MATVIEW) ", "
    7162             :                          CppAsString2(RELKIND_FOREIGN_TABLE) ", "
    7163             :                          CppAsString2(RELKIND_PARTITIONED_TABLE) ")\n"
    7164             :                          "ORDER BY c.oid");
    7165             : 
    7166         356 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    7167             : 
    7168         356 :     ntups = PQntuples(res);
    7169             : 
    7170         356 :     *numTables = ntups;
    7171             : 
    7172             :     /*
    7173             :      * Extract data from result and lock dumpable tables.  We do the locking
    7174             :      * before anything else, to minimize the window wherein a table could
    7175             :      * disappear under us.
    7176             :      *
    7177             :      * Note that we have to save info about all tables here, even when dumping
    7178             :      * only one, because we don't yet know which tables might be inheritance
    7179             :      * ancestors of the target table.
    7180             :      */
    7181         356 :     tblinfo = (TableInfo *) pg_malloc0(ntups * sizeof(TableInfo));
    7182             : 
    7183         356 :     i_reltableoid = PQfnumber(res, "tableoid");
    7184         356 :     i_reloid = PQfnumber(res, "oid");
    7185         356 :     i_relname = PQfnumber(res, "relname");
    7186         356 :     i_relnamespace = PQfnumber(res, "relnamespace");
    7187         356 :     i_relkind = PQfnumber(res, "relkind");
    7188         356 :     i_reltype = PQfnumber(res, "reltype");
    7189         356 :     i_relowner = PQfnumber(res, "relowner");
    7190         356 :     i_relchecks = PQfnumber(res, "relchecks");
    7191         356 :     i_relhasindex = PQfnumber(res, "relhasindex");
    7192         356 :     i_relhasrules = PQfnumber(res, "relhasrules");
    7193         356 :     i_relpages = PQfnumber(res, "relpages");
    7194         356 :     i_reltuples = PQfnumber(res, "reltuples");
    7195         356 :     i_relallvisible = PQfnumber(res, "relallvisible");
    7196         356 :     i_relallfrozen = PQfnumber(res, "relallfrozen");
    7197         356 :     i_toastpages = PQfnumber(res, "toastpages");
    7198         356 :     i_owning_tab = PQfnumber(res, "owning_tab");
    7199         356 :     i_owning_col = PQfnumber(res, "owning_col");
    7200         356 :     i_reltablespace = PQfnumber(res, "reltablespace");
    7201         356 :     i_relhasoids = PQfnumber(res, "relhasoids");
    7202         356 :     i_relhastriggers = PQfnumber(res, "relhastriggers");
    7203         356 :     i_relpersistence = PQfnumber(res, "relpersistence");
    7204         356 :     i_relispopulated = PQfnumber(res, "relispopulated");
    7205         356 :     i_relreplident = PQfnumber(res, "relreplident");
    7206         356 :     i_relrowsec = PQfnumber(res, "relrowsecurity");
    7207         356 :     i_relforcerowsec = PQfnumber(res, "relforcerowsecurity");
    7208         356 :     i_relfrozenxid = PQfnumber(res, "relfrozenxid");
    7209         356 :     i_toastfrozenxid = PQfnumber(res, "tfrozenxid");
    7210         356 :     i_toastoid = PQfnumber(res, "toid");
    7211         356 :     i_relminmxid = PQfnumber(res, "relminmxid");
    7212         356 :     i_toastminmxid = PQfnumber(res, "tminmxid");
    7213         356 :     i_reloptions = PQfnumber(res, "reloptions");
    7214         356 :     i_checkoption = PQfnumber(res, "checkoption");
    7215         356 :     i_toastreloptions = PQfnumber(res, "toast_reloptions");
    7216         356 :     i_reloftype = PQfnumber(res, "reloftype");
    7217         356 :     i_foreignserver = PQfnumber(res, "foreignserver");
    7218         356 :     i_amname = PQfnumber(res, "amname");
    7219         356 :     i_is_identity_sequence = PQfnumber(res, "is_identity_sequence");
    7220         356 :     i_relacl = PQfnumber(res, "relacl");
    7221         356 :     i_acldefault = PQfnumber(res, "acldefault");
    7222         356 :     i_ispartition = PQfnumber(res, "ispartition");
    7223             : 
    7224         356 :     if (dopt->lockWaitTimeout)
    7225             :     {
    7226             :         /*
    7227             :          * Arrange to fail instead of waiting forever for a table lock.
    7228             :          *
    7229             :          * NB: this coding assumes that the only queries issued within the
    7230             :          * following loop are LOCK TABLEs; else the timeout may be undesirably
    7231             :          * applied to other things too.
    7232             :          */
    7233           4 :         resetPQExpBuffer(query);
    7234           4 :         appendPQExpBufferStr(query, "SET statement_timeout = ");
    7235           4 :         appendStringLiteralConn(query, dopt->lockWaitTimeout, GetConnection(fout));
    7236           4 :         ExecuteSqlStatement(fout, query->data);
    7237             :     }
    7238             : 
    7239         356 :     resetPQExpBuffer(query);
    7240             : 
    7241       93064 :     for (i = 0; i < ntups; i++)
    7242             :     {
    7243       92708 :         int32       relallvisible = atoi(PQgetvalue(res, i, i_relallvisible));
    7244       92708 :         int32       relallfrozen = atoi(PQgetvalue(res, i, i_relallfrozen));
    7245             : 
    7246       92708 :         tblinfo[i].dobj.objType = DO_TABLE;
    7247       92708 :         tblinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_reltableoid));
    7248       92708 :         tblinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_reloid));
    7249       92708 :         AssignDumpId(&tblinfo[i].dobj);
    7250       92708 :         tblinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_relname));
    7251      185416 :         tblinfo[i].dobj.namespace =
    7252       92708 :             findNamespace(atooid(PQgetvalue(res, i, i_relnamespace)));
    7253       92708 :         tblinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_relacl));
    7254       92708 :         tblinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
    7255       92708 :         tblinfo[i].dacl.privtype = 0;
    7256       92708 :         tblinfo[i].dacl.initprivs = NULL;
    7257       92708 :         tblinfo[i].relkind = *(PQgetvalue(res, i, i_relkind));
    7258       92708 :         tblinfo[i].reltype = atooid(PQgetvalue(res, i, i_reltype));
    7259       92708 :         tblinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_relowner));
    7260       92708 :         tblinfo[i].ncheck = atoi(PQgetvalue(res, i, i_relchecks));
    7261       92708 :         tblinfo[i].hasindex = (strcmp(PQgetvalue(res, i, i_relhasindex), "t") == 0);
    7262       92708 :         tblinfo[i].hasrules = (strcmp(PQgetvalue(res, i, i_relhasrules), "t") == 0);
    7263       92708 :         tblinfo[i].relpages = atoi(PQgetvalue(res, i, i_relpages));
    7264       92708 :         if (PQgetisnull(res, i, i_toastpages))
    7265       73470 :             tblinfo[i].toastpages = 0;
    7266             :         else
    7267       19238 :             tblinfo[i].toastpages = atoi(PQgetvalue(res, i, i_toastpages));
    7268       92708 :         if (PQgetisnull(res, i, i_owning_tab))
    7269             :         {
    7270       91854 :             tblinfo[i].owning_tab = InvalidOid;
    7271       91854 :             tblinfo[i].owning_col = 0;
    7272             :         }
    7273             :         else
    7274             :         {
    7275         854 :             tblinfo[i].owning_tab = atooid(PQgetvalue(res, i, i_owning_tab));
    7276         854 :             tblinfo[i].owning_col = atoi(PQgetvalue(res, i, i_owning_col));
    7277             :         }
    7278       92708 :         tblinfo[i].reltablespace = pg_strdup(PQgetvalue(res, i, i_reltablespace));
    7279       92708 :         tblinfo[i].hasoids = (strcmp(PQgetvalue(res, i, i_relhasoids), "t") == 0);
    7280       92708 :         tblinfo[i].hastriggers = (strcmp(PQgetvalue(res, i, i_relhastriggers), "t") == 0);
    7281       92708 :         tblinfo[i].relpersistence = *(PQgetvalue(res, i, i_relpersistence));
    7282       92708 :         tblinfo[i].relispopulated = (strcmp(PQgetvalue(res, i, i_relispopulated), "t") == 0);
    7283       92708 :         tblinfo[i].relreplident = *(PQgetvalue(res, i, i_relreplident));
    7284       92708 :         tblinfo[i].rowsec = (strcmp(PQgetvalue(res, i, i_relrowsec), "t") == 0);
    7285       92708 :         tblinfo[i].forcerowsec = (strcmp(PQgetvalue(res, i, i_relforcerowsec), "t") == 0);
    7286       92708 :         tblinfo[i].frozenxid = atooid(PQgetvalue(res, i, i_relfrozenxid));
    7287       92708 :         tblinfo[i].toast_frozenxid = atooid(PQgetvalue(res, i, i_toastfrozenxid));
    7288       92708 :         tblinfo[i].toast_oid = atooid(PQgetvalue(res, i, i_toastoid));
    7289       92708 :         tblinfo[i].minmxid = atooid(PQgetvalue(res, i, i_relminmxid));
    7290       92708 :         tblinfo[i].toast_minmxid = atooid(PQgetvalue(res, i, i_toastminmxid));
    7291       92708 :         tblinfo[i].reloptions = pg_strdup(PQgetvalue(res, i, i_reloptions));
    7292       92708 :         if (PQgetisnull(res, i, i_checkoption))
    7293       92608 :             tblinfo[i].checkoption = NULL;
    7294             :         else
    7295         100 :             tblinfo[i].checkoption = pg_strdup(PQgetvalue(res, i, i_checkoption));
    7296       92708 :         tblinfo[i].toast_reloptions = pg_strdup(PQgetvalue(res, i, i_toastreloptions));
    7297       92708 :         tblinfo[i].reloftype = atooid(PQgetvalue(res, i, i_reloftype));
    7298       92708 :         tblinfo[i].foreign_server = atooid(PQgetvalue(res, i, i_foreignserver));
    7299       92708 :         if (PQgetisnull(res, i, i_amname))
    7300       54894 :             tblinfo[i].amname = NULL;
    7301             :         else
    7302       37814 :             tblinfo[i].amname = pg_strdup(PQgetvalue(res, i, i_amname));
    7303       92708 :         tblinfo[i].is_identity_sequence = (strcmp(PQgetvalue(res, i, i_is_identity_sequence), "t") == 0);
    7304       92708 :         tblinfo[i].ispartition = (strcmp(PQgetvalue(res, i, i_ispartition), "t") == 0);
    7305             : 
    7306             :         /* other fields were zeroed above */
    7307             : 
    7308             :         /*
    7309             :          * Decide whether we want to dump this table.
    7310             :          */
    7311       92708 :         if (tblinfo[i].relkind == RELKIND_COMPOSITE_TYPE)
    7312         374 :             tblinfo[i].dobj.dump = DUMP_COMPONENT_NONE;
    7313             :         else
    7314       92334 :             selectDumpableTable(&tblinfo[i], fout);
    7315             : 
    7316             :         /*
    7317             :          * Now, consider the table "interesting" if we need to dump its
    7318             :          * definition, data or its statistics.  Later on, we'll skip a lot of
    7319             :          * data collection for uninteresting tables.
    7320             :          *
    7321             :          * Note: the "interesting" flag will also be set by flagInhTables for
    7322             :          * parents of interesting tables, so that we collect necessary
    7323             :          * inheritance info even when the parents are not themselves being
    7324             :          * dumped.  This is the main reason why we need an "interesting" flag
    7325             :          * that's separate from the components-to-dump bitmask.
    7326             :          */
    7327       92708 :         tblinfo[i].interesting = (tblinfo[i].dobj.dump &
    7328             :                                   (DUMP_COMPONENT_DEFINITION |
    7329             :                                    DUMP_COMPONENT_DATA |
    7330       92708 :                                    DUMP_COMPONENT_STATISTICS)) != 0;
    7331             : 
    7332       92708 :         tblinfo[i].dummy_view = false;  /* might get set during sort */
    7333       92708 :         tblinfo[i].postponed_def = false;   /* might get set during sort */
    7334             : 
    7335             :         /* Tables have data */
    7336       92708 :         tblinfo[i].dobj.components |= DUMP_COMPONENT_DATA;
    7337             : 
    7338             :         /* Mark whether table has an ACL */
    7339       92708 :         if (!PQgetisnull(res, i, i_relacl))
    7340       73808 :             tblinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
    7341       92708 :         tblinfo[i].hascolumnACLs = false;   /* may get set later */
    7342             : 
    7343             :         /* Add statistics */
    7344       92708 :         if (tblinfo[i].interesting)
    7345             :         {
    7346             :             RelStatsInfo *stats;
    7347             : 
    7348       27132 :             stats = getRelationStatistics(fout, &tblinfo[i].dobj,
    7349       13566 :                                           tblinfo[i].relpages,
    7350             :                                           PQgetvalue(res, i, i_reltuples),
    7351             :                                           relallvisible, relallfrozen,
    7352       13566 :                                           tblinfo[i].relkind, NULL, 0);
    7353       13566 :             if (tblinfo[i].relkind == RELKIND_MATVIEW)
    7354         940 :                 tblinfo[i].stats = stats;
    7355             :         }
    7356             : 
    7357             :         /*
    7358             :          * Read-lock target tables to make sure they aren't DROPPED or altered
    7359             :          * in schema before we get around to dumping them.
    7360             :          *
    7361             :          * Note that we don't explicitly lock parents of the target tables; we
    7362             :          * assume our lock on the child is enough to prevent schema
    7363             :          * alterations to parent tables.
    7364             :          *
    7365             :          * NOTE: it'd be kinda nice to lock other relations too, not only
    7366             :          * plain or partitioned tables, but the backend doesn't presently
    7367             :          * allow that.
    7368             :          *
    7369             :          * We only need to lock the table for certain components; see
    7370             :          * pg_dump.h
    7371             :          */
    7372       92708 :         if ((tblinfo[i].dobj.dump & DUMP_COMPONENTS_REQUIRING_LOCK) &&
    7373       13566 :             (tblinfo[i].relkind == RELKIND_RELATION ||
    7374        4016 :              tblinfo[i].relkind == RELKIND_PARTITIONED_TABLE))
    7375             :         {
    7376             :             /*
    7377             :              * Tables are locked in batches.  When dumping from a remote
    7378             :              * server this can save a significant amount of time by reducing
    7379             :              * the number of round trips.
    7380             :              */
    7381       10666 :             if (query->len == 0)
    7382         230 :                 appendPQExpBuffer(query, "LOCK TABLE %s",
    7383         230 :                                   fmtQualifiedDumpable(&tblinfo[i]));
    7384             :             else
    7385             :             {
    7386       10436 :                 appendPQExpBuffer(query, ", %s",
    7387       10436 :                                   fmtQualifiedDumpable(&tblinfo[i]));
    7388             : 
    7389             :                 /* Arbitrarily end a batch when query length reaches 100K. */
    7390       10436 :                 if (query->len >= 100000)
    7391             :                 {
    7392             :                     /* Lock another batch of tables. */
    7393           0 :                     appendPQExpBufferStr(query, " IN ACCESS SHARE MODE");
    7394           0 :                     ExecuteSqlStatement(fout, query->data);
    7395           0 :                     resetPQExpBuffer(query);
    7396             :                 }
    7397             :             }
    7398             :         }
    7399             :     }
    7400             : 
    7401         356 :     if (query->len != 0)
    7402             :     {
    7403             :         /* Lock the tables in the last batch. */
    7404         230 :         appendPQExpBufferStr(query, " IN ACCESS SHARE MODE");
    7405         230 :         ExecuteSqlStatement(fout, query->data);
    7406             :     }
    7407             : 
    7408         354 :     if (dopt->lockWaitTimeout)
    7409             :     {
    7410           4 :         ExecuteSqlStatement(fout, "SET statement_timeout = 0");
    7411             :     }
    7412             : 
    7413         354 :     PQclear(res);
    7414             : 
    7415         354 :     destroyPQExpBuffer(query);
    7416             : 
    7417         354 :     return tblinfo;
    7418             : }
    7419             : 
    7420             : /*
    7421             :  * getOwnedSeqs
    7422             :  *    identify owned sequences and mark them as dumpable if owning table is
    7423             :  *
    7424             :  * We used to do this in getTables(), but it's better to do it after the
    7425             :  * index used by findTableByOid() has been set up.
    7426             :  */
    7427             : void
    7428         354 : getOwnedSeqs(Archive *fout, TableInfo tblinfo[], int numTables)
    7429             : {
    7430             :     int         i;
    7431             : 
    7432             :     /*
    7433             :      * Force sequences that are "owned" by table columns to be dumped whenever
    7434             :      * their owning table is being dumped.
    7435             :      */
    7436       92540 :     for (i = 0; i < numTables; i++)
    7437             :     {
    7438       92186 :         TableInfo  *seqinfo = &tblinfo[i];
    7439             :         TableInfo  *owning_tab;
    7440             : 
    7441       92186 :         if (!OidIsValid(seqinfo->owning_tab))
    7442       91338 :             continue;           /* not an owned sequence */
    7443             : 
    7444         848 :         owning_tab = findTableByOid(seqinfo->owning_tab);
    7445         848 :         if (owning_tab == NULL)
    7446           0 :             pg_fatal("failed sanity check, parent table with OID %u of sequence with OID %u not found",
    7447             :                      seqinfo->owning_tab, seqinfo->dobj.catId.oid);
    7448             : 
    7449             :         /*
    7450             :          * For an identity sequence, dump exactly the same components for the
    7451             :          * sequence as for the owning table.  This is important because we
    7452             :          * treat the identity sequence as an integral part of the table.  For
    7453             :          * example, there is not any DDL command that allows creation of such
    7454             :          * a sequence independently of the table.
    7455             :          *
    7456             :          * For other owned sequences such as serial sequences, we need to dump
    7457             :          * the components that are being dumped for the table and any
    7458             :          * components that the sequence is explicitly marked with.
    7459             :          *
    7460             :          * We can't simply use the set of components which are being dumped
    7461             :          * for the table as the table might be in an extension (and only the
    7462             :          * non-extension components, eg: ACLs if changed, security labels, and
    7463             :          * policies, are being dumped) while the sequence is not (and
    7464             :          * therefore the definition and other components should also be
    7465             :          * dumped).
    7466             :          *
    7467             :          * If the sequence is part of the extension then it should be properly
    7468             :          * marked by checkExtensionMembership() and this will be a no-op as
    7469             :          * the table will be equivalently marked.
    7470             :          */
    7471         848 :         if (seqinfo->is_identity_sequence)
    7472         406 :             seqinfo->dobj.dump = owning_tab->dobj.dump;
    7473             :         else
    7474         442 :             seqinfo->dobj.dump |= owning_tab->dobj.dump;
    7475             : 
    7476             :         /* Make sure that necessary data is available if we're dumping it */
    7477         848 :         if (seqinfo->dobj.dump != DUMP_COMPONENT_NONE)
    7478             :         {
    7479         656 :             seqinfo->interesting = true;
    7480         656 :             owning_tab->interesting = true;
    7481             :         }
    7482             :     }
    7483         354 : }
    7484             : 
    7485             : /*
    7486             :  * getInherits
    7487             :  *    read all the inheritance information
    7488             :  * from the system catalogs return them in the InhInfo* structure
    7489             :  *
    7490             :  * numInherits is set to the number of pairs read in
    7491             :  */
    7492             : InhInfo *
    7493         354 : getInherits(Archive *fout, int *numInherits)
    7494             : {
    7495             :     PGresult   *res;
    7496             :     int         ntups;
    7497             :     int         i;
    7498         354 :     PQExpBuffer query = createPQExpBuffer();
    7499             :     InhInfo    *inhinfo;
    7500             : 
    7501             :     int         i_inhrelid;
    7502             :     int         i_inhparent;
    7503             : 
    7504             :     /* find all the inheritance information */
    7505         354 :     appendPQExpBufferStr(query, "SELECT inhrelid, inhparent FROM pg_inherits");
    7506             : 
    7507         354 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    7508             : 
    7509         354 :     ntups = PQntuples(res);
    7510             : 
    7511         354 :     *numInherits = ntups;
    7512             : 
    7513         354 :     inhinfo = (InhInfo *) pg_malloc(ntups * sizeof(InhInfo));
    7514             : 
    7515         354 :     i_inhrelid = PQfnumber(res, "inhrelid");
    7516         354 :     i_inhparent = PQfnumber(res, "inhparent");
    7517             : 
    7518        6526 :     for (i = 0; i < ntups; i++)
    7519             :     {
    7520        6172 :         inhinfo[i].inhrelid = atooid(PQgetvalue(res, i, i_inhrelid));
    7521        6172 :         inhinfo[i].inhparent = atooid(PQgetvalue(res, i, i_inhparent));
    7522             :     }
    7523             : 
    7524         354 :     PQclear(res);
    7525             : 
    7526         354 :     destroyPQExpBuffer(query);
    7527             : 
    7528         354 :     return inhinfo;
    7529             : }
    7530             : 
    7531             : /*
    7532             :  * getPartitioningInfo
    7533             :  *    get information about partitioning
    7534             :  *
    7535             :  * For the most part, we only collect partitioning info about tables we
    7536             :  * intend to dump.  However, this function has to consider all partitioned
    7537             :  * tables in the database, because we need to know about parents of partitions
    7538             :  * we are going to dump even if the parents themselves won't be dumped.
    7539             :  *
    7540             :  * Specifically, what we need to know is whether each partitioned table
    7541             :  * has an "unsafe" partitioning scheme that requires us to force
    7542             :  * load-via-partition-root mode for its children.  Currently the only case
    7543             :  * for which we force that is hash partitioning on enum columns, since the
    7544             :  * hash codes depend on enum value OIDs which won't be replicated across
    7545             :  * dump-and-reload.  There are other cases in which load-via-partition-root
    7546             :  * might be necessary, but we expect users to cope with them.
    7547             :  */
    7548             : void
    7549         354 : getPartitioningInfo(Archive *fout)
    7550             : {
    7551             :     PQExpBuffer query;
    7552             :     PGresult   *res;
    7553             :     int         ntups;
    7554             : 
    7555             :     /* hash partitioning didn't exist before v11 */
    7556         354 :     if (fout->remoteVersion < 110000)
    7557           0 :         return;
    7558             :     /* needn't bother if not dumping data */
    7559         354 :     if (!fout->dopt->dumpData)
    7560          72 :         return;
    7561             : 
    7562         282 :     query = createPQExpBuffer();
    7563             : 
    7564             :     /*
    7565             :      * Unsafe partitioning schemes are exactly those for which hash enum_ops
    7566             :      * appears among the partition opclasses.  We needn't check partstrat.
    7567             :      *
    7568             :      * Note that this query may well retrieve info about tables we aren't
    7569             :      * going to dump and hence have no lock on.  That's okay since we need not
    7570             :      * invoke any unsafe server-side functions.
    7571             :      */
    7572         282 :     appendPQExpBufferStr(query,
    7573             :                          "SELECT partrelid FROM pg_partitioned_table WHERE\n"
    7574             :                          "(SELECT c.oid FROM pg_opclass c JOIN pg_am a "
    7575             :                          "ON c.opcmethod = a.oid\n"
    7576             :                          "WHERE opcname = 'enum_ops' "
    7577             :                          "AND opcnamespace = 'pg_catalog'::regnamespace "
    7578             :                          "AND amname = 'hash') = ANY(partclass)");
    7579             : 
    7580         282 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    7581             : 
    7582         282 :     ntups = PQntuples(res);
    7583             : 
    7584         286 :     for (int i = 0; i < ntups; i++)
    7585             :     {
    7586           4 :         Oid         tabrelid = atooid(PQgetvalue(res, i, 0));
    7587             :         TableInfo  *tbinfo;
    7588             : 
    7589           4 :         tbinfo = findTableByOid(tabrelid);
    7590           4 :         if (tbinfo == NULL)
    7591           0 :             pg_fatal("failed sanity check, table OID %u appearing in pg_partitioned_table not found",
    7592             :                      tabrelid);
    7593           4 :         tbinfo->unsafe_partitions = true;
    7594             :     }
    7595             : 
    7596         282 :     PQclear(res);
    7597             : 
    7598         282 :     destroyPQExpBuffer(query);
    7599             : }
    7600             : 
    7601             : /*
    7602             :  * getIndexes
    7603             :  *    get information about every index on a dumpable table
    7604             :  *
    7605             :  * Note: index data is not returned directly to the caller, but it
    7606             :  * does get entered into the DumpableObject tables.
    7607             :  */
    7608             : void
    7609         354 : getIndexes(Archive *fout, TableInfo tblinfo[], int numTables)
    7610             : {
    7611         354 :     PQExpBuffer query = createPQExpBuffer();
    7612         354 :     PQExpBuffer tbloids = createPQExpBuffer();
    7613             :     PGresult   *res;
    7614             :     int         ntups;
    7615             :     int         curtblindx;
    7616             :     IndxInfo   *indxinfo;
    7617             :     int         i_tableoid,
    7618             :                 i_oid,
    7619             :                 i_indrelid,
    7620             :                 i_indexname,
    7621             :                 i_relpages,
    7622             :                 i_reltuples,
    7623             :                 i_relallvisible,
    7624             :                 i_relallfrozen,
    7625             :                 i_parentidx,
    7626             :                 i_indexdef,
    7627             :                 i_indnkeyatts,
    7628             :                 i_indnatts,
    7629             :                 i_indkey,
    7630             :                 i_indisclustered,
    7631             :                 i_indisreplident,
    7632             :                 i_indnullsnotdistinct,
    7633             :                 i_contype,
    7634             :                 i_conname,
    7635             :                 i_condeferrable,
    7636             :                 i_condeferred,
    7637             :                 i_conperiod,
    7638             :                 i_contableoid,
    7639             :                 i_conoid,
    7640             :                 i_condef,
    7641             :                 i_indattnames,
    7642             :                 i_tablespace,
    7643             :                 i_indreloptions,
    7644             :                 i_indstatcols,
    7645             :                 i_indstatvals;
    7646             : 
    7647             :     /*
    7648             :      * We want to perform just one query against pg_index.  However, we
    7649             :      * mustn't try to select every row of the catalog and then sort it out on
    7650             :      * the client side, because some of the server-side functions we need
    7651             :      * would be unsafe to apply to tables we don't have lock on.  Hence, we
    7652             :      * build an array of the OIDs of tables we care about (and now have lock
    7653             :      * on!), and use a WHERE clause to constrain which rows are selected.
    7654             :      */
    7655         354 :     appendPQExpBufferChar(tbloids, '{');
    7656       92540 :     for (int i = 0; i < numTables; i++)
    7657             :     {
    7658       92186 :         TableInfo  *tbinfo = &tblinfo[i];
    7659             : 
    7660       92186 :         if (!tbinfo->hasindex)
    7661       64718 :             continue;
    7662             : 
    7663             :         /*
    7664             :          * We can ignore indexes of uninteresting tables.
    7665             :          */
    7666       27468 :         if (!tbinfo->interesting)
    7667       23414 :             continue;
    7668             : 
    7669             :         /* OK, we need info for this table */
    7670        4054 :         if (tbloids->len > 1) /* do we have more than the '{'? */
    7671        3890 :             appendPQExpBufferChar(tbloids, ',');
    7672        4054 :         appendPQExpBuffer(tbloids, "%u", tbinfo->dobj.catId.oid);
    7673             :     }
    7674         354 :     appendPQExpBufferChar(tbloids, '}');
    7675             : 
    7676         354 :     appendPQExpBufferStr(query,
    7677             :                          "SELECT t.tableoid, t.oid, i.indrelid, "
    7678             :                          "t.relname AS indexname, "
    7679             :                          "t.relpages, t.reltuples, t.relallvisible, ");
    7680             : 
    7681         354 :     if (fout->remoteVersion >= 180000)
    7682         354 :         appendPQExpBufferStr(query, "t.relallfrozen, ");
    7683             :     else
    7684           0 :         appendPQExpBufferStr(query, "0 AS relallfrozen, ");
    7685             : 
    7686         354 :     appendPQExpBufferStr(query,
    7687             :                          "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
    7688             :                          "i.indkey, i.indisclustered, "
    7689             :                          "c.contype, c.conname, "
    7690             :                          "c.condeferrable, c.condeferred, "
    7691             :                          "c.tableoid AS contableoid, "
    7692             :                          "c.oid AS conoid, "
    7693             :                          "pg_catalog.pg_get_constraintdef(c.oid, false) AS condef, "
    7694             :                          "CASE WHEN i.indexprs IS NOT NULL THEN "
    7695             :                          "(SELECT pg_catalog.array_agg(attname ORDER BY attnum)"
    7696             :                          "  FROM pg_catalog.pg_attribute "
    7697             :                          "  WHERE attrelid = i.indexrelid) "
    7698             :                          "ELSE NULL END AS indattnames, "
    7699             :                          "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
    7700             :                          "t.reloptions AS indreloptions, ");
    7701             : 
    7702             : 
    7703         354 :     if (fout->remoteVersion >= 90400)
    7704         354 :         appendPQExpBufferStr(query,
    7705             :                              "i.indisreplident, ");
    7706             :     else
    7707           0 :         appendPQExpBufferStr(query,
    7708             :                              "false AS indisreplident, ");
    7709             : 
    7710         354 :     if (fout->remoteVersion >= 110000)
    7711         354 :         appendPQExpBufferStr(query,
    7712             :                              "inh.inhparent AS parentidx, "
    7713             :                              "i.indnkeyatts AS indnkeyatts, "
    7714             :                              "i.indnatts AS indnatts, "
    7715             :                              "(SELECT pg_catalog.array_agg(attnum ORDER BY attnum) "
    7716             :                              "  FROM pg_catalog.pg_attribute "
    7717             :                              "  WHERE attrelid = i.indexrelid AND "
    7718             :                              "    attstattarget >= 0) AS indstatcols, "
    7719             :                              "(SELECT pg_catalog.array_agg(attstattarget ORDER BY attnum) "
    7720             :                              "  FROM pg_catalog.pg_attribute "
    7721             :                              "  WHERE attrelid = i.indexrelid AND "
    7722             :                              "    attstattarget >= 0) AS indstatvals, ");
    7723             :     else
    7724           0 :         appendPQExpBufferStr(query,
    7725             :                              "0 AS parentidx, "
    7726             :                              "i.indnatts AS indnkeyatts, "
    7727             :                              "i.indnatts AS indnatts, "
    7728             :                              "'' AS indstatcols, "
    7729             :                              "'' AS indstatvals, ");
    7730             : 
    7731         354 :     if (fout->remoteVersion >= 150000)
    7732         354 :         appendPQExpBufferStr(query,
    7733             :                              "i.indnullsnotdistinct, ");
    7734             :     else
    7735           0 :         appendPQExpBufferStr(query,
    7736             :                              "false AS indnullsnotdistinct, ");
    7737             : 
    7738         354 :     if (fout->remoteVersion >= 180000)
    7739         354 :         appendPQExpBufferStr(query,
    7740             :                              "c.conperiod ");
    7741             :     else
    7742           0 :         appendPQExpBufferStr(query,
    7743             :                              "NULL AS conperiod ");
    7744             : 
    7745             :     /*
    7746             :      * The point of the messy-looking outer join is to find a constraint that
    7747             :      * is related by an internal dependency link to the index. If we find one,
    7748             :      * create a CONSTRAINT entry linked to the INDEX entry.  We assume an
    7749             :      * index won't have more than one internal dependency.
    7750             :      *
    7751             :      * Note: the check on conrelid is redundant, but useful because that
    7752             :      * column is indexed while conindid is not.
    7753             :      */
    7754         354 :     if (fout->remoteVersion >= 110000)
    7755             :     {
    7756         354 :         appendPQExpBuffer(query,
    7757             :                           "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
    7758             :                           "JOIN pg_catalog.pg_index i ON (src.tbloid = i.indrelid) "
    7759             :                           "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
    7760             :                           "JOIN pg_catalog.pg_class t2 ON (t2.oid = i.indrelid) "
    7761             :                           "LEFT JOIN pg_catalog.pg_constraint c "
    7762             :                           "ON (i.indrelid = c.conrelid AND "
    7763             :                           "i.indexrelid = c.conindid AND "
    7764             :                           "c.contype IN ('p','u','x')) "
    7765             :                           "LEFT JOIN pg_catalog.pg_inherits inh "
    7766             :                           "ON (inh.inhrelid = indexrelid) "
    7767             :                           "WHERE (i.indisvalid OR t2.relkind = 'p') "
    7768             :                           "AND i.indisready "
    7769             :                           "ORDER BY i.indrelid, indexname",
    7770             :                           tbloids->data);
    7771             :     }
    7772             :     else
    7773             :     {
    7774             :         /*
    7775             :          * the test on indisready is necessary in 9.2, and harmless in
    7776             :          * earlier/later versions
    7777             :          */
    7778           0 :         appendPQExpBuffer(query,
    7779             :                           "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
    7780             :                           "JOIN pg_catalog.pg_index i ON (src.tbloid = i.indrelid) "
    7781             :                           "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
    7782             :                           "LEFT JOIN pg_catalog.pg_constraint c "
    7783             :                           "ON (i.indrelid = c.conrelid AND "
    7784             :                           "i.indexrelid = c.conindid AND "
    7785             :                           "c.contype IN ('p','u','x')) "
    7786             :                           "WHERE i.indisvalid AND i.indisready "
    7787             :                           "ORDER BY i.indrelid, indexname",
    7788             :                           tbloids->data);
    7789             :     }
    7790             : 
    7791         354 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    7792             : 
    7793         354 :     ntups = PQntuples(res);
    7794             : 
    7795         354 :     i_tableoid = PQfnumber(res, "tableoid");
    7796         354 :     i_oid = PQfnumber(res, "oid");
    7797         354 :     i_indrelid = PQfnumber(res, "indrelid");
    7798         354 :     i_indexname = PQfnumber(res, "indexname");
    7799         354 :     i_relpages = PQfnumber(res, "relpages");
    7800         354 :     i_reltuples = PQfnumber(res, "reltuples");
    7801         354 :     i_relallvisible = PQfnumber(res, "relallvisible");
    7802         354 :     i_relallfrozen = PQfnumber(res, "relallfrozen");
    7803         354 :     i_parentidx = PQfnumber(res, "parentidx");
    7804         354 :     i_indexdef = PQfnumber(res, "indexdef");
    7805         354 :     i_indnkeyatts = PQfnumber(res, "indnkeyatts");
    7806         354 :     i_indnatts = PQfnumber(res, "indnatts");
    7807         354 :     i_indkey = PQfnumber(res, "indkey");
    7808         354 :     i_indisclustered = PQfnumber(res, "indisclustered");
    7809         354 :     i_indisreplident = PQfnumber(res, "indisreplident");
    7810         354 :     i_indnullsnotdistinct = PQfnumber(res, "indnullsnotdistinct");
    7811         354 :     i_contype = PQfnumber(res, "contype");
    7812         354 :     i_conname = PQfnumber(res, "conname");
    7813         354 :     i_condeferrable = PQfnumber(res, "condeferrable");
    7814         354 :     i_condeferred = PQfnumber(res, "condeferred");
    7815         354 :     i_conperiod = PQfnumber(res, "conperiod");
    7816         354 :     i_contableoid = PQfnumber(res, "contableoid");
    7817         354 :     i_conoid = PQfnumber(res, "conoid");
    7818         354 :     i_condef = PQfnumber(res, "condef");
    7819         354 :     i_indattnames = PQfnumber(res, "indattnames");
    7820         354 :     i_tablespace = PQfnumber(res, "tablespace");
    7821         354 :     i_indreloptions = PQfnumber(res, "indreloptions");
    7822         354 :     i_indstatcols = PQfnumber(res, "indstatcols");
    7823         354 :     i_indstatvals = PQfnumber(res, "indstatvals");
    7824             : 
    7825         354 :     indxinfo = (IndxInfo *) pg_malloc(ntups * sizeof(IndxInfo));
    7826             : 
    7827             :     /*
    7828             :      * Outer loop iterates once per table, not once per row.  Incrementing of
    7829             :      * j is handled by the inner loop.
    7830             :      */
    7831         354 :     curtblindx = -1;
    7832        4368 :     for (int j = 0; j < ntups;)
    7833             :     {
    7834        4014 :         Oid         indrelid = atooid(PQgetvalue(res, j, i_indrelid));
    7835        4014 :         TableInfo  *tbinfo = NULL;
    7836        4014 :         char      **indAttNames = NULL;
    7837        4014 :         int         nindAttNames = 0;
    7838             :         int         numinds;
    7839             : 
    7840             :         /* Count rows for this table */
    7841        5278 :         for (numinds = 1; numinds < ntups - j; numinds++)
    7842        5114 :             if (atooid(PQgetvalue(res, j + numinds, i_indrelid)) != indrelid)
    7843        3850 :                 break;
    7844             : 
    7845             :         /*
    7846             :          * Locate the associated TableInfo; we rely on tblinfo[] being in OID
    7847             :          * order.
    7848             :          */
    7849       46952 :         while (++curtblindx < numTables)
    7850             :         {
    7851       46952 :             tbinfo = &tblinfo[curtblindx];
    7852       46952 :             if (tbinfo->dobj.catId.oid == indrelid)
    7853        4014 :                 break;
    7854             :         }
    7855        4014 :         if (curtblindx >= numTables)
    7856           0 :             pg_fatal("unrecognized table OID %u", indrelid);
    7857             :         /* cross-check that we only got requested tables */
    7858        4014 :         if (!tbinfo->hasindex ||
    7859        4014 :             !tbinfo->interesting)
    7860           0 :             pg_fatal("unexpected index data for table \"%s\"",
    7861             :                      tbinfo->dobj.name);
    7862             : 
    7863             :         /* Save data for this table */
    7864        4014 :         tbinfo->indexes = indxinfo + j;
    7865        4014 :         tbinfo->numIndexes = numinds;
    7866             : 
    7867        9292 :         for (int c = 0; c < numinds; c++, j++)
    7868             :         {
    7869             :             char        contype;
    7870             :             char        indexkind;
    7871             :             RelStatsInfo *relstats;
    7872        5278 :             int32       relpages = atoi(PQgetvalue(res, j, i_relpages));
    7873        5278 :             int32       relallvisible = atoi(PQgetvalue(res, j, i_relallvisible));
    7874        5278 :             int32       relallfrozen = atoi(PQgetvalue(res, j, i_relallfrozen));
    7875             : 
    7876        5278 :             indxinfo[j].dobj.objType = DO_INDEX;
    7877        5278 :             indxinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
    7878        5278 :             indxinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
    7879        5278 :             AssignDumpId(&indxinfo[j].dobj);
    7880        5278 :             indxinfo[j].dobj.dump = tbinfo->dobj.dump;
    7881        5278 :             indxinfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_indexname));
    7882        5278 :             indxinfo[j].dobj.namespace = tbinfo->dobj.namespace;
    7883        5278 :             indxinfo[j].indextable = tbinfo;
    7884        5278 :             indxinfo[j].indexdef = pg_strdup(PQgetvalue(res, j, i_indexdef));
    7885        5278 :             indxinfo[j].indnkeyattrs = atoi(PQgetvalue(res, j, i_indnkeyatts));
    7886        5278 :             indxinfo[j].indnattrs = atoi(PQgetvalue(res, j, i_indnatts));
    7887        5278 :             indxinfo[j].tablespace = pg_strdup(PQgetvalue(res, j, i_tablespace));
    7888        5278 :             indxinfo[j].indreloptions = pg_strdup(PQgetvalue(res, j, i_indreloptions));
    7889        5278 :             indxinfo[j].indstatcols = pg_strdup(PQgetvalue(res, j, i_indstatcols));
    7890        5278 :             indxinfo[j].indstatvals = pg_strdup(PQgetvalue(res, j, i_indstatvals));
    7891        5278 :             indxinfo[j].indkeys = (Oid *) pg_malloc(indxinfo[j].indnattrs * sizeof(Oid));
    7892        5278 :             parseOidArray(PQgetvalue(res, j, i_indkey),
    7893        5278 :                           indxinfo[j].indkeys, indxinfo[j].indnattrs);
    7894        5278 :             indxinfo[j].indisclustered = (PQgetvalue(res, j, i_indisclustered)[0] == 't');
    7895        5278 :             indxinfo[j].indisreplident = (PQgetvalue(res, j, i_indisreplident)[0] == 't');
    7896        5278 :             indxinfo[j].indnullsnotdistinct = (PQgetvalue(res, j, i_indnullsnotdistinct)[0] == 't');
    7897        5278 :             indxinfo[j].parentidx = atooid(PQgetvalue(res, j, i_parentidx));
    7898        5278 :             indxinfo[j].partattaches = (SimplePtrList)
    7899             :             {
    7900             :                 NULL, NULL
    7901             :             };
    7902             : 
    7903        5278 :             if (indxinfo[j].parentidx == 0)
    7904        4086 :                 indexkind = RELKIND_INDEX;
    7905             :             else
    7906        1192 :                 indexkind = RELKIND_PARTITIONED_INDEX;
    7907             : 
    7908        5278 :             if (!PQgetisnull(res, j, i_indattnames))
    7909             :             {
    7910         308 :                 if (!parsePGArray(PQgetvalue(res, j, i_indattnames),
    7911             :                                   &indAttNames, &nindAttNames))
    7912           0 :                     pg_fatal("could not parse %s array", "indattnames");
    7913             :             }
    7914             : 
    7915        5278 :             relstats = getRelationStatistics(fout, &indxinfo[j].dobj, relpages,
    7916             :                                              PQgetvalue(res, j, i_reltuples),
    7917             :                                              relallvisible, relallfrozen, indexkind,
    7918             :                                              indAttNames, nindAttNames);
    7919             : 
    7920        5278 :             contype = *(PQgetvalue(res, j, i_contype));
    7921        5278 :             if (contype == 'p' || contype == 'u' || contype == 'x')
    7922        3068 :             {
    7923             :                 /*
    7924             :                  * If we found a constraint matching the index, create an
    7925             :                  * entry for it.
    7926             :                  */
    7927             :                 ConstraintInfo *constrinfo;
    7928             : 
    7929        3068 :                 constrinfo = (ConstraintInfo *) pg_malloc(sizeof(ConstraintInfo));
    7930        3068 :                 constrinfo->dobj.objType = DO_CONSTRAINT;
    7931        3068 :                 constrinfo->dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_contableoid));
    7932        3068 :                 constrinfo->dobj.catId.oid = atooid(PQgetvalue(res, j, i_conoid));
    7933        3068 :                 AssignDumpId(&constrinfo->dobj);
    7934        3068 :                 constrinfo->dobj.dump = tbinfo->dobj.dump;
    7935        3068 :                 constrinfo->dobj.name = pg_strdup(PQgetvalue(res, j, i_conname));
    7936        3068 :                 constrinfo->dobj.namespace = tbinfo->dobj.namespace;
    7937        3068 :                 constrinfo->contable = tbinfo;
    7938        3068 :                 constrinfo->condomain = NULL;
    7939        3068 :                 constrinfo->contype = contype;
    7940        3068 :                 if (contype == 'x')
    7941          20 :                     constrinfo->condef = pg_strdup(PQgetvalue(res, j, i_condef));
    7942             :                 else
    7943        3048 :                     constrinfo->condef = NULL;
    7944        3068 :                 constrinfo->confrelid = InvalidOid;
    7945        3068 :                 constrinfo->conindex = indxinfo[j].dobj.dumpId;
    7946        3068 :                 constrinfo->condeferrable = *(PQgetvalue(res, j, i_condeferrable)) == 't';
    7947        3068 :                 constrinfo->condeferred = *(PQgetvalue(res, j, i_condeferred)) == 't';
    7948        3068 :                 constrinfo->conperiod = *(PQgetvalue(res, j, i_conperiod)) == 't';
    7949        3068 :                 constrinfo->conislocal = true;
    7950        3068 :                 constrinfo->separate = true;
    7951             : 
    7952        3068 :                 indxinfo[j].indexconstraint = constrinfo->dobj.dumpId;
    7953        3068 :                 if (relstats != NULL)
    7954        2420 :                     addObjectDependency(&relstats->dobj, constrinfo->dobj.dumpId);
    7955             :             }
    7956             :             else
    7957             :             {
    7958             :                 /* Plain secondary index */
    7959        2210 :                 indxinfo[j].indexconstraint = 0;
    7960             :             }
    7961             :         }
    7962             :     }
    7963             : 
    7964         354 :     PQclear(res);
    7965             : 
    7966         354 :     destroyPQExpBuffer(query);
    7967         354 :     destroyPQExpBuffer(tbloids);
    7968         354 : }
    7969             : 
    7970             : /*
    7971             :  * getExtendedStatistics
    7972             :  *    get information about extended-statistics objects.
    7973             :  *
    7974             :  * Note: extended statistics data is not returned directly to the caller, but
    7975             :  * it does get entered into the DumpableObject tables.
    7976             :  */
    7977             : void
    7978         354 : getExtendedStatistics(Archive *fout)
    7979             : {
    7980             :     PQExpBuffer query;
    7981             :     PGresult   *res;
    7982             :     StatsExtInfo *statsextinfo;
    7983             :     int         ntups;
    7984             :     int         i_tableoid;
    7985             :     int         i_oid;
    7986             :     int         i_stxname;
    7987             :     int         i_stxnamespace;
    7988             :     int         i_stxowner;
    7989             :     int         i_stxrelid;
    7990             :     int         i_stattarget;
    7991             :     int         i;
    7992             : 
    7993             :     /* Extended statistics were new in v10 */
    7994         354 :     if (fout->remoteVersion < 100000)
    7995           0 :         return;
    7996             : 
    7997         354 :     query = createPQExpBuffer();
    7998             : 
    7999         354 :     if (fout->remoteVersion < 130000)
    8000           0 :         appendPQExpBufferStr(query, "SELECT tableoid, oid, stxname, "
    8001             :                              "stxnamespace, stxowner, stxrelid, NULL AS stxstattarget "
    8002             :                              "FROM pg_catalog.pg_statistic_ext");
    8003             :     else
    8004         354 :         appendPQExpBufferStr(query, "SELECT tableoid, oid, stxname, "
    8005             :                              "stxnamespace, stxowner, stxrelid, stxstattarget "
    8006             :                              "FROM pg_catalog.pg_statistic_ext");
    8007             : 
    8008         354 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    8009             : 
    8010         354 :     ntups = PQntuples(res);
    8011             : 
    8012         354 :     i_tableoid = PQfnumber(res, "tableoid");
    8013         354 :     i_oid = PQfnumber(res, "oid");
    8014         354 :     i_stxname = PQfnumber(res, "stxname");
    8015         354 :     i_stxnamespace = PQfnumber(res, "stxnamespace");
    8016         354 :     i_stxowner = PQfnumber(res, "stxowner");
    8017         354 :     i_stxrelid = PQfnumber(res, "stxrelid");
    8018         354 :     i_stattarget = PQfnumber(res, "stxstattarget");
    8019             : 
    8020         354 :     statsextinfo = (StatsExtInfo *) pg_malloc(ntups * sizeof(StatsExtInfo));
    8021             : 
    8022         704 :     for (i = 0; i < ntups; i++)
    8023             :     {
    8024         350 :         statsextinfo[i].dobj.objType = DO_STATSEXT;
    8025         350 :         statsextinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    8026         350 :         statsextinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    8027         350 :         AssignDumpId(&statsextinfo[i].dobj);
    8028         350 :         statsextinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_stxname));
    8029         700 :         statsextinfo[i].dobj.namespace =
    8030         350 :             findNamespace(atooid(PQgetvalue(res, i, i_stxnamespace)));
    8031         350 :         statsextinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_stxowner));
    8032         700 :         statsextinfo[i].stattable =
    8033         350 :             findTableByOid(atooid(PQgetvalue(res, i, i_stxrelid)));
    8034         350 :         if (PQgetisnull(res, i, i_stattarget))
    8035         252 :             statsextinfo[i].stattarget = -1;
    8036             :         else
    8037          98 :             statsextinfo[i].stattarget = atoi(PQgetvalue(res, i, i_stattarget));
    8038             : 
    8039             :         /* Decide whether we want to dump it */
    8040         350 :         selectDumpableStatisticsObject(&(statsextinfo[i]), fout);
    8041             :     }
    8042             : 
    8043         354 :     PQclear(res);
    8044         354 :     destroyPQExpBuffer(query);
    8045             : }
    8046             : 
    8047             : /*
    8048             :  * getConstraints
    8049             :  *
    8050             :  * Get info about constraints on dumpable tables.
    8051             :  *
    8052             :  * Currently handles foreign keys only.
    8053             :  * Unique and primary key constraints are handled with indexes,
    8054             :  * while check constraints are processed in getTableAttrs().
    8055             :  */
    8056             : void
    8057         354 : getConstraints(Archive *fout, TableInfo tblinfo[], int numTables)
    8058             : {
    8059         354 :     PQExpBuffer query = createPQExpBuffer();
    8060         354 :     PQExpBuffer tbloids = createPQExpBuffer();
    8061             :     PGresult   *res;
    8062             :     int         ntups;
    8063             :     int         curtblindx;
    8064         354 :     TableInfo  *tbinfo = NULL;
    8065             :     ConstraintInfo *constrinfo;
    8066             :     int         i_contableoid,
    8067             :                 i_conoid,
    8068             :                 i_conrelid,
    8069             :                 i_conname,
    8070             :                 i_confrelid,
    8071             :                 i_conindid,
    8072             :                 i_condef;
    8073             : 
    8074             :     /*
    8075             :      * We want to perform just one query against pg_constraint.  However, we
    8076             :      * mustn't try to select every row of the catalog and then sort it out on
    8077             :      * the client side, because some of the server-side functions we need
    8078             :      * would be unsafe to apply to tables we don't have lock on.  Hence, we
    8079             :      * build an array of the OIDs of tables we care about (and now have lock
    8080             :      * on!), and use a WHERE clause to constrain which rows are selected.
    8081             :      */
    8082         354 :     appendPQExpBufferChar(tbloids, '{');
    8083       92540 :     for (int i = 0; i < numTables; i++)
    8084             :     {
    8085       92186 :         TableInfo  *tinfo = &tblinfo[i];
    8086             : 
    8087             :         /*
    8088             :          * For partitioned tables, foreign keys have no triggers so they must
    8089             :          * be included anyway in case some foreign keys are defined.
    8090             :          */
    8091       92186 :         if ((!tinfo->hastriggers &&
    8092       89886 :              tinfo->relkind != RELKIND_PARTITIONED_TABLE) ||
    8093        3292 :             !(tinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
    8094       89684 :             continue;
    8095             : 
    8096             :         /* OK, we need info for this table */
    8097        2502 :         if (tbloids->len > 1) /* do we have more than the '{'? */
    8098        2388 :             appendPQExpBufferChar(tbloids, ',');
    8099        2502 :         appendPQExpBuffer(tbloids, "%u", tinfo->dobj.catId.oid);
    8100             :     }
    8101         354 :     appendPQExpBufferChar(tbloids, '}');
    8102             : 
    8103         354 :     appendPQExpBufferStr(query,
    8104             :                          "SELECT c.tableoid, c.oid, "
    8105             :                          "conrelid, conname, confrelid, ");
    8106         354 :     if (fout->remoteVersion >= 110000)
    8107         354 :         appendPQExpBufferStr(query, "conindid, ");
    8108             :     else
    8109           0 :         appendPQExpBufferStr(query, "0 AS conindid, ");
    8110         354 :     appendPQExpBuffer(query,
    8111             :                       "pg_catalog.pg_get_constraintdef(c.oid) AS condef\n"
    8112             :                       "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
    8113             :                       "JOIN pg_catalog.pg_constraint c ON (src.tbloid = c.conrelid)\n"
    8114             :                       "WHERE contype = 'f' ",
    8115             :                       tbloids->data);
    8116         354 :     if (fout->remoteVersion >= 110000)
    8117         354 :         appendPQExpBufferStr(query,
    8118             :                              "AND conparentid = 0 ");
    8119         354 :     appendPQExpBufferStr(query,
    8120             :                          "ORDER BY conrelid, conname");
    8121             : 
    8122         354 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    8123             : 
    8124         354 :     ntups = PQntuples(res);
    8125             : 
    8126         354 :     i_contableoid = PQfnumber(res, "tableoid");
    8127         354 :     i_conoid = PQfnumber(res, "oid");
    8128         354 :     i_conrelid = PQfnumber(res, "conrelid");
    8129         354 :     i_conname = PQfnumber(res, "conname");
    8130         354 :     i_confrelid = PQfnumber(res, "confrelid");
    8131         354 :     i_conindid = PQfnumber(res, "conindid");
    8132         354 :     i_condef = PQfnumber(res, "condef");
    8133             : 
    8134         354 :     constrinfo = (ConstraintInfo *) pg_malloc(ntups * sizeof(ConstraintInfo));
    8135             : 
    8136         354 :     curtblindx = -1;
    8137         712 :     for (int j = 0; j < ntups; j++)
    8138             :     {
    8139         358 :         Oid         conrelid = atooid(PQgetvalue(res, j, i_conrelid));
    8140             :         TableInfo  *reftable;
    8141             : 
    8142             :         /*
    8143             :          * Locate the associated TableInfo; we rely on tblinfo[] being in OID
    8144             :          * order.
    8145             :          */
    8146         358 :         if (tbinfo == NULL || tbinfo->dobj.catId.oid != conrelid)
    8147             :         {
    8148       28452 :             while (++curtblindx < numTables)
    8149             :             {
    8150       28452 :                 tbinfo = &tblinfo[curtblindx];
    8151       28452 :                 if (tbinfo->dobj.catId.oid == conrelid)
    8152         338 :                     break;
    8153             :             }
    8154         338 :             if (curtblindx >= numTables)
    8155           0 :                 pg_fatal("unrecognized table OID %u", conrelid);
    8156             :         }
    8157             : 
    8158         358 :         constrinfo[j].dobj.objType = DO_FK_CONSTRAINT;
    8159         358 :         constrinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_contableoid));
    8160         358 :         constrinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_conoid));
    8161         358 :         AssignDumpId(&constrinfo[j].dobj);
    8162         358 :         constrinfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_conname));
    8163         358 :         constrinfo[j].dobj.namespace = tbinfo->dobj.namespace;
    8164         358 :         constrinfo[j].contable = tbinfo;
    8165         358 :         constrinfo[j].condomain = NULL;
    8166         358 :         constrinfo[j].contype = 'f';
    8167         358 :         constrinfo[j].condef = pg_strdup(PQgetvalue(res, j, i_condef));
    8168         358 :         constrinfo[j].confrelid = atooid(PQgetvalue(res, j, i_confrelid));
    8169         358 :         constrinfo[j].conindex = 0;
    8170         358 :         constrinfo[j].condeferrable = false;
    8171         358 :         constrinfo[j].condeferred = false;
    8172         358 :         constrinfo[j].conislocal = true;
    8173         358 :         constrinfo[j].separate = true;
    8174             : 
    8175             :         /*
    8176             :          * Restoring an FK that points to a partitioned table requires that
    8177             :          * all partition indexes have been attached beforehand. Ensure that
    8178             :          * happens by making the constraint depend on each index partition
    8179             :          * attach object.
    8180             :          */
    8181         358 :         reftable = findTableByOid(constrinfo[j].confrelid);
    8182         358 :         if (reftable && reftable->relkind == RELKIND_PARTITIONED_TABLE)
    8183             :         {
    8184          40 :             Oid         indexOid = atooid(PQgetvalue(res, j, i_conindid));
    8185             : 
    8186          40 :             if (indexOid != InvalidOid)
    8187             :             {
    8188          40 :                 for (int k = 0; k < reftable->numIndexes; k++)
    8189             :                 {
    8190             :                     IndxInfo   *refidx;
    8191             : 
    8192             :                     /* not our index? */
    8193          40 :                     if (reftable->indexes[k].dobj.catId.oid != indexOid)
    8194           0 :                         continue;
    8195             : 
    8196          40 :                     refidx = &reftable->indexes[k];
    8197          40 :                     addConstrChildIdxDeps(&constrinfo[j].dobj, refidx);
    8198          40 :                     break;
    8199             :                 }
    8200             :             }
    8201             :         }
    8202             :     }
    8203             : 
    8204         354 :     PQclear(res);
    8205             : 
    8206         354 :     destroyPQExpBuffer(query);
    8207         354 :     destroyPQExpBuffer(tbloids);
    8208         354 : }
    8209             : 
    8210             : /*
    8211             :  * addConstrChildIdxDeps
    8212             :  *
    8213             :  * Recursive subroutine for getConstraints
    8214             :  *
    8215             :  * Given an object representing a foreign key constraint and an index on the
    8216             :  * partitioned table it references, mark the constraint object as dependent
    8217             :  * on the DO_INDEX_ATTACH object of each index partition, recursively
    8218             :  * drilling down to their partitions if any.  This ensures that the FK is not
    8219             :  * restored until the index is fully marked valid.
    8220             :  */
    8221             : static void
    8222          90 : addConstrChildIdxDeps(DumpableObject *dobj, const IndxInfo *refidx)
    8223             : {
    8224             :     SimplePtrListCell *cell;
    8225             : 
    8226             :     Assert(dobj->objType == DO_FK_CONSTRAINT);
    8227             : 
    8228         310 :     for (cell = refidx->partattaches.head; cell; cell = cell->next)
    8229             :     {
    8230         220 :         IndexAttachInfo *attach = (IndexAttachInfo *) cell->ptr;
    8231             : 
    8232         220 :         addObjectDependency(dobj, attach->dobj.dumpId);
    8233             : 
    8234         220 :         if (attach->partitionIdx->partattaches.head != NULL)
    8235          50 :             addConstrChildIdxDeps(dobj, attach->partitionIdx);
    8236             :     }
    8237          90 : }
    8238             : 
    8239             : /*
    8240             :  * getDomainConstraints
    8241             :  *
    8242             :  * Get info about constraints on a domain.
    8243             :  */
    8244             : static void
    8245         294 : getDomainConstraints(Archive *fout, TypeInfo *tyinfo)
    8246             : {
    8247             :     int         i;
    8248             :     ConstraintInfo *constrinfo;
    8249         294 :     PQExpBuffer query = createPQExpBuffer();
    8250             :     PGresult   *res;
    8251             :     int         i_tableoid,
    8252             :                 i_oid,
    8253             :                 i_conname,
    8254             :                 i_consrc;
    8255             :     int         ntups;
    8256             : 
    8257         294 :     if (!fout->is_prepared[PREPQUERY_GETDOMAINCONSTRAINTS])
    8258             :     {
    8259             :         /* Set up query for constraint-specific details */
    8260          94 :         appendPQExpBufferStr(query,
    8261             :                              "PREPARE getDomainConstraints(pg_catalog.oid) AS\n"
    8262             :                              "SELECT tableoid, oid, conname, "
    8263             :                              "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
    8264             :                              "convalidated "
    8265             :                              "FROM pg_catalog.pg_constraint "
    8266             :                              "WHERE contypid = $1 AND contype = 'c' "
    8267             :                              "ORDER BY conname");
    8268             : 
    8269          94 :         ExecuteSqlStatement(fout, query->data);
    8270             : 
    8271          94 :         fout->is_prepared[PREPQUERY_GETDOMAINCONSTRAINTS] = true;
    8272             :     }
    8273             : 
    8274         294 :     printfPQExpBuffer(query,
    8275             :                       "EXECUTE getDomainConstraints('%u')",
    8276             :                       tyinfo->dobj.catId.oid);
    8277             : 
    8278         294 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    8279             : 
    8280         294 :     ntups = PQntuples(res);
    8281             : 
    8282         294 :     i_tableoid = PQfnumber(res, "tableoid");
    8283         294 :     i_oid = PQfnumber(res, "oid");
    8284         294 :     i_conname = PQfnumber(res, "conname");
    8285         294 :     i_consrc = PQfnumber(res, "consrc");
    8286             : 
    8287         294 :     constrinfo = (ConstraintInfo *) pg_malloc(ntups * sizeof(ConstraintInfo));
    8288             : 
    8289         294 :     tyinfo->nDomChecks = ntups;
    8290         294 :     tyinfo->domChecks = constrinfo;
    8291             : 
    8292         498 :     for (i = 0; i < ntups; i++)
    8293             :     {
    8294         204 :         bool        validated = PQgetvalue(res, i, 4)[0] == 't';
    8295             : 
    8296         204 :         constrinfo[i].dobj.objType = DO_CONSTRAINT;
    8297         204 :         constrinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    8298         204 :         constrinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    8299         204 :         AssignDumpId(&constrinfo[i].dobj);
    8300         204 :         constrinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_conname));
    8301         204 :         constrinfo[i].dobj.namespace = tyinfo->dobj.namespace;
    8302         204 :         constrinfo[i].contable = NULL;
    8303         204 :         constrinfo[i].condomain = tyinfo;
    8304         204 :         constrinfo[i].contype = 'c';
    8305         204 :         constrinfo[i].condef = pg_strdup(PQgetvalue(res, i, i_consrc));
    8306         204 :         constrinfo[i].confrelid = InvalidOid;
    8307         204 :         constrinfo[i].conindex = 0;
    8308         204 :         constrinfo[i].condeferrable = false;
    8309         204 :         constrinfo[i].condeferred = false;
    8310         204 :         constrinfo[i].conislocal = true;
    8311             : 
    8312         204 :         constrinfo[i].separate = !validated;
    8313             : 
    8314             :         /*
    8315             :          * Make the domain depend on the constraint, ensuring it won't be
    8316             :          * output till any constraint dependencies are OK.  If the constraint
    8317             :          * has not been validated, it's going to be dumped after the domain
    8318             :          * anyway, so this doesn't matter.
    8319             :          */
    8320         204 :         if (validated)
    8321         204 :             addObjectDependency(&tyinfo->dobj,
    8322         204 :                                 constrinfo[i].dobj.dumpId);
    8323             :     }
    8324             : 
    8325         294 :     PQclear(res);
    8326             : 
    8327         294 :     destroyPQExpBuffer(query);
    8328         294 : }
    8329             : 
    8330             : /*
    8331             :  * getRules
    8332             :  *    get basic information about every rule in the system
    8333             :  */
    8334             : void
    8335         354 : getRules(Archive *fout)
    8336             : {
    8337             :     PGresult   *res;
    8338             :     int         ntups;
    8339             :     int         i;
    8340         354 :     PQExpBuffer query = createPQExpBuffer();
    8341             :     RuleInfo   *ruleinfo;
    8342             :     int         i_tableoid;
    8343             :     int         i_oid;
    8344             :     int         i_rulename;
    8345             :     int         i_ruletable;
    8346             :     int         i_ev_type;
    8347             :     int         i_is_instead;
    8348             :     int         i_ev_enabled;
    8349             : 
    8350         354 :     appendPQExpBufferStr(query, "SELECT "
    8351             :                          "tableoid, oid, rulename, "
    8352             :                          "ev_class AS ruletable, ev_type, is_instead, "
    8353             :                          "ev_enabled "
    8354             :                          "FROM pg_rewrite "
    8355             :                          "ORDER BY oid");
    8356             : 
    8357         354 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    8358             : 
    8359         354 :     ntups = PQntuples(res);
    8360             : 
    8361         354 :     ruleinfo = (RuleInfo *) pg_malloc(ntups * sizeof(RuleInfo));
    8362             : 
    8363         354 :     i_tableoid = PQfnumber(res, "tableoid");
    8364         354 :     i_oid = PQfnumber(res, "oid");
    8365         354 :     i_rulename = PQfnumber(res, "rulename");
    8366         354 :     i_ruletable = PQfnumber(res, "ruletable");
    8367         354 :     i_ev_type = PQfnumber(res, "ev_type");
    8368         354 :     i_is_instead = PQfnumber(res, "is_instead");
    8369         354 :     i_ev_enabled = PQfnumber(res, "ev_enabled");
    8370             : 
    8371       54120 :     for (i = 0; i < ntups; i++)
    8372             :     {
    8373             :         Oid         ruletableoid;
    8374             : 
    8375       53766 :         ruleinfo[i].dobj.objType = DO_RULE;
    8376       53766 :         ruleinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    8377       53766 :         ruleinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    8378       53766 :         AssignDumpId(&ruleinfo[i].dobj);
    8379       53766 :         ruleinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_rulename));
    8380       53766 :         ruletableoid = atooid(PQgetvalue(res, i, i_ruletable));
    8381       53766 :         ruleinfo[i].ruletable = findTableByOid(ruletableoid);
    8382       53766 :         if (ruleinfo[i].ruletable == NULL)
    8383           0 :             pg_fatal("failed sanity check, parent table with OID %u of pg_rewrite entry with OID %u not found",
    8384             :                      ruletableoid, ruleinfo[i].dobj.catId.oid);
    8385       53766 :         ruleinfo[i].dobj.namespace = ruleinfo[i].ruletable->dobj.namespace;
    8386       53766 :         ruleinfo[i].dobj.dump = ruleinfo[i].ruletable->dobj.dump;
    8387       53766 :         ruleinfo[i].ev_type = *(PQgetvalue(res, i, i_ev_type));
    8388       53766 :         ruleinfo[i].is_instead = *(PQgetvalue(res, i, i_is_instead)) == 't';
    8389       53766 :         ruleinfo[i].ev_enabled = *(PQgetvalue(res, i, i_ev_enabled));
    8390       53766 :         if (ruleinfo[i].ruletable)
    8391             :         {
    8392             :             /*
    8393             :              * If the table is a view or materialized view, force its ON
    8394             :              * SELECT rule to be sorted before the view itself --- this
    8395             :              * ensures that any dependencies for the rule affect the table's
    8396             :              * positioning. Other rules are forced to appear after their
    8397             :              * table.
    8398             :              */
    8399       53766 :             if ((ruleinfo[i].ruletable->relkind == RELKIND_VIEW ||
    8400        1554 :                  ruleinfo[i].ruletable->relkind == RELKIND_MATVIEW) &&
    8401       53304 :                 ruleinfo[i].ev_type == '1' && ruleinfo[i].is_instead)
    8402             :             {
    8403       52512 :                 addObjectDependency(&ruleinfo[i].ruletable->dobj,
    8404       52512 :                                     ruleinfo[i].dobj.dumpId);
    8405             :                 /* We'll merge the rule into CREATE VIEW, if possible */
    8406       52512 :                 ruleinfo[i].separate = false;
    8407             :             }
    8408             :             else
    8409             :             {
    8410        1254 :                 addObjectDependency(&ruleinfo[i].dobj,
    8411        1254 :                                     ruleinfo[i].ruletable->dobj.dumpId);
    8412        1254 :                 ruleinfo[i].separate = true;
    8413             :             }
    8414             :         }
    8415             :         else
    8416           0 :             ruleinfo[i].separate = true;
    8417             :     }
    8418             : 
    8419         354 :     PQclear(res);
    8420             : 
    8421         354 :     destroyPQExpBuffer(query);
    8422         354 : }
    8423             : 
    8424             : /*
    8425             :  * getTriggers
    8426             :  *    get information about every trigger on a dumpable table
    8427             :  *
    8428             :  * Note: trigger data is not returned directly to the caller, but it
    8429             :  * does get entered into the DumpableObject tables.
    8430             :  */
    8431             : void
    8432         354 : getTriggers(Archive *fout, TableInfo tblinfo[], int numTables)
    8433             : {
    8434         354 :     PQExpBuffer query = createPQExpBuffer();
    8435         354 :     PQExpBuffer tbloids = createPQExpBuffer();
    8436             :     PGresult   *res;
    8437             :     int         ntups;
    8438             :     int         curtblindx;
    8439             :     TriggerInfo *tginfo;
    8440             :     int         i_tableoid,
    8441             :                 i_oid,
    8442             :                 i_tgrelid,
    8443             :                 i_tgname,
    8444             :                 i_tgenabled,
    8445             :                 i_tgispartition,
    8446             :                 i_tgdef;
    8447             : 
    8448             :     /*
    8449             :      * We want to perform just one query against pg_trigger.  However, we
    8450             :      * mustn't try to select every row of the catalog and then sort it out on
    8451             :      * the client side, because some of the server-side functions we need
    8452             :      * would be unsafe to apply to tables we don't have lock on.  Hence, we
    8453             :      * build an array of the OIDs of tables we care about (and now have lock
    8454             :      * on!), and use a WHERE clause to constrain which rows are selected.
    8455             :      */
    8456         354 :     appendPQExpBufferChar(tbloids, '{');
    8457       92540 :     for (int i = 0; i < numTables; i++)
    8458             :     {
    8459       92186 :         TableInfo  *tbinfo = &tblinfo[i];
    8460             : 
    8461       92186 :         if (!tbinfo->hastriggers ||
    8462        2300 :             !(tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
    8463       90410 :             continue;
    8464             : 
    8465             :         /* OK, we need info for this table */
    8466        1776 :         if (tbloids->len > 1) /* do we have more than the '{'? */
    8467        1666 :             appendPQExpBufferChar(tbloids, ',');
    8468        1776 :         appendPQExpBuffer(tbloids, "%u", tbinfo->dobj.catId.oid);
    8469             :     }
    8470         354 :     appendPQExpBufferChar(tbloids, '}');
    8471             : 
    8472         354 :     if (fout->remoteVersion >= 150000)
    8473             :     {
    8474             :         /*
    8475             :          * NB: think not to use pretty=true in pg_get_triggerdef.  It could
    8476             :          * result in non-forward-compatible dumps of WHEN clauses due to
    8477             :          * under-parenthesization.
    8478             :          *
    8479             :          * NB: We need to see partition triggers in case the tgenabled flag
    8480             :          * has been changed from the parent.
    8481             :          */
    8482         354 :         appendPQExpBuffer(query,
    8483             :                           "SELECT t.tgrelid, t.tgname, "
    8484             :                           "pg_catalog.pg_get_triggerdef(t.oid, false) AS tgdef, "
    8485             :                           "t.tgenabled, t.tableoid, t.oid, "
    8486             :                           "t.tgparentid <> 0 AS tgispartition\n"
    8487             :                           "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
    8488             :                           "JOIN pg_catalog.pg_trigger t ON (src.tbloid = t.tgrelid) "
    8489             :                           "LEFT JOIN pg_catalog.pg_trigger u ON (u.oid = t.tgparentid) "
    8490             :                           "WHERE ((NOT t.tgisinternal AND t.tgparentid = 0) "
    8491             :                           "OR t.tgenabled != u.tgenabled) "
    8492             :                           "ORDER BY t.tgrelid, t.tgname",
    8493             :                           tbloids->data);
    8494             :     }
    8495           0 :     else if (fout->remoteVersion >= 130000)
    8496             :     {
    8497             :         /*
    8498             :          * NB: think not to use pretty=true in pg_get_triggerdef.  It could
    8499             :          * result in non-forward-compatible dumps of WHEN clauses due to
    8500             :          * under-parenthesization.
    8501             :          *
    8502             :          * NB: We need to see tgisinternal triggers in partitions, in case the
    8503             :          * tgenabled flag has been changed from the parent.
    8504             :          */
    8505           0 :         appendPQExpBuffer(query,
    8506             :                           "SELECT t.tgrelid, t.tgname, "
    8507             :                           "pg_catalog.pg_get_triggerdef(t.oid, false) AS tgdef, "
    8508             :                           "t.tgenabled, t.tableoid, t.oid, t.tgisinternal as tgispartition\n"
    8509             :                           "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
    8510             :                           "JOIN pg_catalog.pg_trigger t ON (src.tbloid = t.tgrelid) "
    8511             :                           "LEFT JOIN pg_catalog.pg_trigger u ON (u.oid = t.tgparentid) "
    8512             :                           "WHERE (NOT t.tgisinternal OR t.tgenabled != u.tgenabled) "
    8513             :                           "ORDER BY t.tgrelid, t.tgname",
    8514             :                           tbloids->data);
    8515             :     }
    8516           0 :     else if (fout->remoteVersion >= 110000)
    8517             :     {
    8518             :         /*
    8519             :          * NB: We need to see tgisinternal triggers in partitions, in case the
    8520             :          * tgenabled flag has been changed from the parent. No tgparentid in
    8521             :          * version 11-12, so we have to match them via pg_depend.
    8522             :          *
    8523             :          * See above about pretty=true in pg_get_triggerdef.
    8524             :          */
    8525           0 :         appendPQExpBuffer(query,
    8526             :                           "SELECT t.tgrelid, t.tgname, "
    8527             :                           "pg_catalog.pg_get_triggerdef(t.oid, false) AS tgdef, "
    8528             :                           "t.tgenabled, t.tableoid, t.oid, t.tgisinternal as tgispartition "
    8529             :                           "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
    8530             :                           "JOIN pg_catalog.pg_trigger t ON (src.tbloid = t.tgrelid) "
    8531             :                           "LEFT JOIN pg_catalog.pg_depend AS d ON "
    8532             :                           " d.classid = 'pg_catalog.pg_trigger'::pg_catalog.regclass AND "
    8533             :                           " d.refclassid = 'pg_catalog.pg_trigger'::pg_catalog.regclass AND "
    8534             :                           " d.objid = t.oid "
    8535             :                           "LEFT JOIN pg_catalog.pg_trigger AS pt ON pt.oid = refobjid "
    8536             :                           "WHERE (NOT t.tgisinternal OR t.tgenabled != pt.tgenabled) "
    8537             :                           "ORDER BY t.tgrelid, t.tgname",
    8538             :                           tbloids->data);
    8539             :     }
    8540             :     else
    8541             :     {
    8542             :         /* See above about pretty=true in pg_get_triggerdef */
    8543           0 :         appendPQExpBuffer(query,
    8544             :                           "SELECT t.tgrelid, t.tgname, "
    8545             :                           "pg_catalog.pg_get_triggerdef(t.oid, false) AS tgdef, "
    8546             :                           "t.tgenabled, false as tgispartition, "
    8547             :                           "t.tableoid, t.oid "
    8548             :                           "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
    8549             :                           "JOIN pg_catalog.pg_trigger t ON (src.tbloid = t.tgrelid) "
    8550             :                           "WHERE NOT tgisinternal "
    8551             :                           "ORDER BY t.tgrelid, t.tgname",
    8552             :                           tbloids->data);
    8553             :     }
    8554             : 
    8555         354 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    8556             : 
    8557         354 :     ntups = PQntuples(res);
    8558             : 
    8559         354 :     i_tableoid = PQfnumber(res, "tableoid");
    8560         354 :     i_oid = PQfnumber(res, "oid");
    8561         354 :     i_tgrelid = PQfnumber(res, "tgrelid");
    8562         354 :     i_tgname = PQfnumber(res, "tgname");
    8563         354 :     i_tgenabled = PQfnumber(res, "tgenabled");
    8564         354 :     i_tgispartition = PQfnumber(res, "tgispartition");
    8565         354 :     i_tgdef = PQfnumber(res, "tgdef");
    8566             : 
    8567         354 :     tginfo = (TriggerInfo *) pg_malloc(ntups * sizeof(TriggerInfo));
    8568             : 
    8569             :     /*
    8570             :      * Outer loop iterates once per table, not once per row.  Incrementing of
    8571             :      * j is handled by the inner loop.
    8572             :      */
    8573         354 :     curtblindx = -1;
    8574        1006 :     for (int j = 0; j < ntups;)
    8575             :     {
    8576         652 :         Oid         tgrelid = atooid(PQgetvalue(res, j, i_tgrelid));
    8577         652 :         TableInfo  *tbinfo = NULL;
    8578             :         int         numtrigs;
    8579             : 
    8580             :         /* Count rows for this table */
    8581        1086 :         for (numtrigs = 1; numtrigs < ntups - j; numtrigs++)
    8582         976 :             if (atooid(PQgetvalue(res, j + numtrigs, i_tgrelid)) != tgrelid)
    8583         542 :                 break;
    8584             : 
    8585             :         /*
    8586             :          * Locate the associated TableInfo; we rely on tblinfo[] being in OID
    8587             :          * order.
    8588             :          */
    8589       33628 :         while (++curtblindx < numTables)
    8590             :         {
    8591       33628 :             tbinfo = &tblinfo[curtblindx];
    8592       33628 :             if (tbinfo->dobj.catId.oid == tgrelid)
    8593         652 :                 break;
    8594             :         }
    8595         652 :         if (curtblindx >= numTables)
    8596           0 :             pg_fatal("unrecognized table OID %u", tgrelid);
    8597             : 
    8598             :         /* Save data for this table */
    8599         652 :         tbinfo->triggers = tginfo + j;
    8600         652 :         tbinfo->numTriggers = numtrigs;
    8601             : 
    8602        1738 :         for (int c = 0; c < numtrigs; c++, j++)
    8603             :         {
    8604        1086 :             tginfo[j].dobj.objType = DO_TRIGGER;
    8605        1086 :             tginfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
    8606        1086 :             tginfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
    8607        1086 :             AssignDumpId(&tginfo[j].dobj);
    8608        1086 :             tginfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_tgname));
    8609        1086 :             tginfo[j].dobj.namespace = tbinfo->dobj.namespace;
    8610        1086 :             tginfo[j].tgtable = tbinfo;
    8611        1086 :             tginfo[j].tgenabled = *(PQgetvalue(res, j, i_tgenabled));
    8612        1086 :             tginfo[j].tgispartition = *(PQgetvalue(res, j, i_tgispartition)) == 't';
    8613        1086 :             tginfo[j].tgdef = pg_strdup(PQgetvalue(res, j, i_tgdef));
    8614             :         }
    8615             :     }
    8616             : 
    8617         354 :     PQclear(res);
    8618             : 
    8619         354 :     destroyPQExpBuffer(query);
    8620         354 :     destroyPQExpBuffer(tbloids);
    8621         354 : }
    8622             : 
    8623             : /*
    8624             :  * getEventTriggers
    8625             :  *    get information about event triggers
    8626             :  */
    8627             : void
    8628         354 : getEventTriggers(Archive *fout)
    8629             : {
    8630             :     int         i;
    8631             :     PQExpBuffer query;
    8632             :     PGresult   *res;
    8633             :     EventTriggerInfo *evtinfo;
    8634             :     int         i_tableoid,
    8635             :                 i_oid,
    8636             :                 i_evtname,
    8637             :                 i_evtevent,
    8638             :                 i_evtowner,
    8639             :                 i_evttags,
    8640             :                 i_evtfname,
    8641             :                 i_evtenabled;
    8642             :     int         ntups;
    8643             : 
    8644             :     /* Before 9.3, there are no event triggers */
    8645         354 :     if (fout->remoteVersion < 90300)
    8646           0 :         return;
    8647             : 
    8648         354 :     query = createPQExpBuffer();
    8649             : 
    8650         354 :     appendPQExpBufferStr(query,
    8651             :                          "SELECT e.tableoid, e.oid, evtname, evtenabled, "
    8652             :                          "evtevent, evtowner, "
    8653             :                          "array_to_string(array("
    8654             :                          "select quote_literal(x) "
    8655             :                          " from unnest(evttags) as t(x)), ', ') as evttags, "
    8656             :                          "e.evtfoid::regproc as evtfname "
    8657             :                          "FROM pg_event_trigger e "
    8658             :                          "ORDER BY e.oid");
    8659             : 
    8660         354 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    8661             : 
    8662         354 :     ntups = PQntuples(res);
    8663             : 
    8664         354 :     evtinfo = (EventTriggerInfo *) pg_malloc(ntups * sizeof(EventTriggerInfo));
    8665             : 
    8666         354 :     i_tableoid = PQfnumber(res, "tableoid");
    8667         354 :     i_oid = PQfnumber(res, "oid");
    8668         354 :     i_evtname = PQfnumber(res, "evtname");
    8669         354 :     i_evtevent = PQfnumber(res, "evtevent");
    8670         354 :     i_evtowner = PQfnumber(res, "evtowner");
    8671         354 :     i_evttags = PQfnumber(res, "evttags");
    8672         354 :     i_evtfname = PQfnumber(res, "evtfname");
    8673         354 :     i_evtenabled = PQfnumber(res, "evtenabled");
    8674             : 
    8675         466 :     for (i = 0; i < ntups; i++)
    8676             :     {
    8677         112 :         evtinfo[i].dobj.objType = DO_EVENT_TRIGGER;
    8678         112 :         evtinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    8679         112 :         evtinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    8680         112 :         AssignDumpId(&evtinfo[i].dobj);
    8681         112 :         evtinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_evtname));
    8682         112 :         evtinfo[i].evtname = pg_strdup(PQgetvalue(res, i, i_evtname));
    8683         112 :         evtinfo[i].evtevent = pg_strdup(PQgetvalue(res, i, i_evtevent));
    8684         112 :         evtinfo[i].evtowner = getRoleName(PQgetvalue(res, i, i_evtowner));
    8685         112 :         evtinfo[i].evttags = pg_strdup(PQgetvalue(res, i, i_evttags));
    8686         112 :         evtinfo[i].evtfname = pg_strdup(PQgetvalue(res, i, i_evtfname));
    8687         112 :         evtinfo[i].evtenabled = *(PQgetvalue(res, i, i_evtenabled));
    8688             : 
    8689             :         /* Decide whether we want to dump it */
    8690         112 :         selectDumpableObject(&(evtinfo[i].dobj), fout);
    8691             :     }
    8692             : 
    8693         354 :     PQclear(res);
    8694             : 
    8695         354 :     destroyPQExpBuffer(query);
    8696             : }
    8697             : 
    8698             : /*
    8699             :  * getProcLangs
    8700             :  *    get basic information about every procedural language in the system
    8701             :  *
    8702             :  * NB: this must run after getFuncs() because we assume we can do
    8703             :  * findFuncByOid().
    8704             :  */
    8705             : void
    8706         354 : getProcLangs(Archive *fout)
    8707             : {
    8708             :     PGresult   *res;
    8709             :     int         ntups;
    8710             :     int         i;
    8711         354 :     PQExpBuffer query = createPQExpBuffer();
    8712             :     ProcLangInfo *planginfo;
    8713             :     int         i_tableoid;
    8714             :     int         i_oid;
    8715             :     int         i_lanname;
    8716             :     int         i_lanpltrusted;
    8717             :     int         i_lanplcallfoid;
    8718             :     int         i_laninline;
    8719             :     int         i_lanvalidator;
    8720             :     int         i_lanacl;
    8721             :     int         i_acldefault;
    8722             :     int         i_lanowner;
    8723             : 
    8724         354 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, "
    8725             :                          "lanname, lanpltrusted, lanplcallfoid, "
    8726             :                          "laninline, lanvalidator, "
    8727             :                          "lanacl, "
    8728             :                          "acldefault('l', lanowner) AS acldefault, "
    8729             :                          "lanowner "
    8730             :                          "FROM pg_language "
    8731             :                          "WHERE lanispl "
    8732             :                          "ORDER BY oid");
    8733             : 
    8734         354 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    8735             : 
    8736         354 :     ntups = PQntuples(res);
    8737             : 
    8738         354 :     planginfo = (ProcLangInfo *) pg_malloc(ntups * sizeof(ProcLangInfo));
    8739             : 
    8740         354 :     i_tableoid = PQfnumber(res, "tableoid");
    8741         354 :     i_oid = PQfnumber(res, "oid");
    8742         354 :     i_lanname = PQfnumber(res, "lanname");
    8743         354 :     i_lanpltrusted = PQfnumber(res, "lanpltrusted");
    8744         354 :     i_lanplcallfoid = PQfnumber(res, "lanplcallfoid");
    8745         354 :     i_laninline = PQfnumber(res, "laninline");
    8746         354 :     i_lanvalidator = PQfnumber(res, "lanvalidator");
    8747         354 :     i_lanacl = PQfnumber(res, "lanacl");
    8748         354 :     i_acldefault = PQfnumber(res, "acldefault");
    8749         354 :     i_lanowner = PQfnumber(res, "lanowner");
    8750             : 
    8751         806 :     for (i = 0; i < ntups; i++)
    8752             :     {
    8753         452 :         planginfo[i].dobj.objType = DO_PROCLANG;
    8754         452 :         planginfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    8755         452 :         planginfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    8756         452 :         AssignDumpId(&planginfo[i].dobj);
    8757             : 
    8758         452 :         planginfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_lanname));
    8759         452 :         planginfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_lanacl));
    8760         452 :         planginfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
    8761         452 :         planginfo[i].dacl.privtype = 0;
    8762         452 :         planginfo[i].dacl.initprivs = NULL;
    8763         452 :         planginfo[i].lanpltrusted = *(PQgetvalue(res, i, i_lanpltrusted)) == 't';
    8764         452 :         planginfo[i].lanplcallfoid = atooid(PQgetvalue(res, i, i_lanplcallfoid));
    8765         452 :         planginfo[i].laninline = atooid(PQgetvalue(res, i, i_laninline));
    8766         452 :         planginfo[i].lanvalidator = atooid(PQgetvalue(res, i, i_lanvalidator));
    8767         452 :         planginfo[i].lanowner = getRoleName(PQgetvalue(res, i, i_lanowner));
    8768             : 
    8769             :         /* Decide whether we want to dump it */
    8770         452 :         selectDumpableProcLang(&(planginfo[i]), fout);
    8771             : 
    8772             :         /* Mark whether language has an ACL */
    8773         452 :         if (!PQgetisnull(res, i, i_lanacl))
    8774          98 :             planginfo[i].dobj.components |= DUMP_COMPONENT_ACL;
    8775             :     }
    8776             : 
    8777         354 :     PQclear(res);
    8778             : 
    8779         354 :     destroyPQExpBuffer(query);
    8780         354 : }
    8781             : 
    8782             : /*
    8783             :  * getCasts
    8784             :  *    get basic information about most casts in the system
    8785             :  *
    8786             :  * Skip casts from a range to its multirange, since we'll create those
    8787             :  * automatically.
    8788             :  */
    8789             : void
    8790         354 : getCasts(Archive *fout)
    8791             : {
    8792             :     PGresult   *res;
    8793             :     int         ntups;
    8794             :     int         i;
    8795         354 :     PQExpBuffer query = createPQExpBuffer();
    8796             :     CastInfo   *castinfo;
    8797             :     int         i_tableoid;
    8798             :     int         i_oid;
    8799             :     int         i_castsource;
    8800             :     int         i_casttarget;
    8801             :     int         i_castfunc;
    8802             :     int         i_castcontext;
    8803             :     int         i_castmethod;
    8804             : 
    8805         354 :     if (fout->remoteVersion >= 140000)
    8806             :     {
    8807         354 :         appendPQExpBufferStr(query, "SELECT tableoid, oid, "
    8808             :                              "castsource, casttarget, castfunc, castcontext, "
    8809             :                              "castmethod "
    8810             :                              "FROM pg_cast c "
    8811             :                              "WHERE NOT EXISTS ( "
    8812             :                              "SELECT 1 FROM pg_range r "
    8813             :                              "WHERE c.castsource = r.rngtypid "
    8814             :                              "AND c.casttarget = r.rngmultitypid "
    8815             :                              ") "
    8816             :                              "ORDER BY 3,4");
    8817             :     }
    8818             :     else
    8819             :     {
    8820           0 :         appendPQExpBufferStr(query, "SELECT tableoid, oid, "
    8821             :                              "castsource, casttarget, castfunc, castcontext, "
    8822             :                              "castmethod "
    8823             :                              "FROM pg_cast ORDER BY 3,4");
    8824             :     }
    8825             : 
    8826         354 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    8827             : 
    8828         354 :     ntups = PQntuples(res);
    8829             : 
    8830         354 :     castinfo = (CastInfo *) pg_malloc(ntups * sizeof(CastInfo));
    8831             : 
    8832         354 :     i_tableoid = PQfnumber(res, "tableoid");
    8833         354 :     i_oid = PQfnumber(res, "oid");
    8834         354 :     i_castsource = PQfnumber(res, "castsource");
    8835         354 :     i_casttarget = PQfnumber(res, "casttarget");
    8836         354 :     i_castfunc = PQfnumber(res, "castfunc");
    8837         354 :     i_castcontext = PQfnumber(res, "castcontext");
    8838         354 :     i_castmethod = PQfnumber(res, "castmethod");
    8839             : 
    8840       81602 :     for (i = 0; i < ntups; i++)
    8841             :     {
    8842             :         PQExpBufferData namebuf;
    8843             :         TypeInfo   *sTypeInfo;
    8844             :         TypeInfo   *tTypeInfo;
    8845             : 
    8846       81248 :         castinfo[i].dobj.objType = DO_CAST;
    8847       81248 :         castinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    8848       81248 :         castinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    8849       81248 :         AssignDumpId(&castinfo[i].dobj);
    8850       81248 :         castinfo[i].castsource = atooid(PQgetvalue(res, i, i_castsource));
    8851       81248 :         castinfo[i].casttarget = atooid(PQgetvalue(res, i, i_casttarget));
    8852       81248 :         castinfo[i].castfunc = atooid(PQgetvalue(res, i, i_castfunc));
    8853       81248 :         castinfo[i].castcontext = *(PQgetvalue(res, i, i_castcontext));
    8854       81248 :         castinfo[i].castmethod = *(PQgetvalue(res, i, i_castmethod));
    8855             : 
    8856             :         /*
    8857             :          * Try to name cast as concatenation of typnames.  This is only used
    8858             :          * for purposes of sorting.  If we fail to find either type, the name
    8859             :          * will be an empty string.
    8860             :          */
    8861       81248 :         initPQExpBuffer(&namebuf);
    8862       81248 :         sTypeInfo = findTypeByOid(castinfo[i].castsource);
    8863       81248 :         tTypeInfo = findTypeByOid(castinfo[i].casttarget);
    8864       81248 :         if (sTypeInfo && tTypeInfo)
    8865       81248 :             appendPQExpBuffer(&namebuf, "%s %s",
    8866             :                               sTypeInfo->dobj.name, tTypeInfo->dobj.name);
    8867       81248 :         castinfo[i].dobj.name = namebuf.data;
    8868             : 
    8869             :         /* Decide whether we want to dump it */
    8870       81248 :         selectDumpableCast(&(castinfo[i]), fout);
    8871             :     }
    8872             : 
    8873         354 :     PQclear(res);
    8874             : 
    8875         354 :     destroyPQExpBuffer(query);
    8876         354 : }
    8877             : 
    8878             : static char *
    8879         192 : get_language_name(Archive *fout, Oid langid)
    8880             : {
    8881             :     PQExpBuffer query;
    8882             :     PGresult   *res;
    8883             :     char       *lanname;
    8884             : 
    8885         192 :     query = createPQExpBuffer();
    8886         192 :     appendPQExpBuffer(query, "SELECT lanname FROM pg_language WHERE oid = %u", langid);
    8887         192 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
    8888         192 :     lanname = pg_strdup(fmtId(PQgetvalue(res, 0, 0)));
    8889         192 :     destroyPQExpBuffer(query);
    8890         192 :     PQclear(res);
    8891             : 
    8892         192 :     return lanname;
    8893             : }
    8894             : 
    8895             : /*
    8896             :  * getTransforms
    8897             :  *    get basic information about every transform in the system
    8898             :  */
    8899             : void
    8900         354 : getTransforms(Archive *fout)
    8901             : {
    8902             :     PGresult   *res;
    8903             :     int         ntups;
    8904             :     int         i;
    8905             :     PQExpBuffer query;
    8906             :     TransformInfo *transforminfo;
    8907             :     int         i_tableoid;
    8908             :     int         i_oid;
    8909             :     int         i_trftype;
    8910             :     int         i_trflang;
    8911             :     int         i_trffromsql;
    8912             :     int         i_trftosql;
    8913             : 
    8914             :     /* Transforms didn't exist pre-9.5 */
    8915         354 :     if (fout->remoteVersion < 90500)
    8916           0 :         return;
    8917             : 
    8918         354 :     query = createPQExpBuffer();
    8919             : 
    8920         354 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, "
    8921             :                          "trftype, trflang, trffromsql::oid, trftosql::oid "
    8922             :                          "FROM pg_transform "
    8923             :                          "ORDER BY 3,4");
    8924             : 
    8925         354 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    8926             : 
    8927         354 :     ntups = PQntuples(res);
    8928             : 
    8929         354 :     transforminfo = (TransformInfo *) pg_malloc(ntups * sizeof(TransformInfo));
    8930             : 
    8931         354 :     i_tableoid = PQfnumber(res, "tableoid");
    8932         354 :     i_oid = PQfnumber(res, "oid");
    8933         354 :     i_trftype = PQfnumber(res, "trftype");
    8934         354 :     i_trflang = PQfnumber(res, "trflang");
    8935         354 :     i_trffromsql = PQfnumber(res, "trffromsql");
    8936         354 :     i_trftosql = PQfnumber(res, "trftosql");
    8937             : 
    8938         466 :     for (i = 0; i < ntups; i++)
    8939             :     {
    8940             :         PQExpBufferData namebuf;
    8941             :         TypeInfo   *typeInfo;
    8942             :         char       *lanname;
    8943             : 
    8944         112 :         transforminfo[i].dobj.objType = DO_TRANSFORM;
    8945         112 :         transforminfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    8946         112 :         transforminfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    8947         112 :         AssignDumpId(&transforminfo[i].dobj);
    8948         112 :         transforminfo[i].trftype = atooid(PQgetvalue(res, i, i_trftype));
    8949         112 :         transforminfo[i].trflang = atooid(PQgetvalue(res, i, i_trflang));
    8950         112 :         transforminfo[i].trffromsql = atooid(PQgetvalue(res, i, i_trffromsql));
    8951         112 :         transforminfo[i].trftosql = atooid(PQgetvalue(res, i, i_trftosql));
    8952             : 
    8953             :         /*
    8954             :          * Try to name transform as concatenation of type and language name.
    8955             :          * This is only used for purposes of sorting.  If we fail to find
    8956             :          * either, the name will be an empty string.
    8957             :          */
    8958         112 :         initPQExpBuffer(&namebuf);
    8959         112 :         typeInfo = findTypeByOid(transforminfo[i].trftype);
    8960         112 :         lanname = get_language_name(fout, transforminfo[i].trflang);
    8961         112 :         if (typeInfo && lanname)
    8962         112 :             appendPQExpBuffer(&namebuf, "%s %s",
    8963             :                               typeInfo->dobj.name, lanname);
    8964         112 :         transforminfo[i].dobj.name = namebuf.data;
    8965         112 :         free(lanname);
    8966             : 
    8967             :         /* Decide whether we want to dump it */
    8968         112 :         selectDumpableObject(&(transforminfo[i].dobj), fout);
    8969             :     }
    8970             : 
    8971         354 :     PQclear(res);
    8972             : 
    8973         354 :     destroyPQExpBuffer(query);
    8974             : }
    8975             : 
    8976             : /*
    8977             :  * getTableAttrs -
    8978             :  *    for each interesting table, read info about its attributes
    8979             :  *    (names, types, default values, CHECK constraints, etc)
    8980             :  *
    8981             :  *  modifies tblinfo
    8982             :  */
    8983             : void
    8984         354 : getTableAttrs(Archive *fout, TableInfo *tblinfo, int numTables)
    8985             : {
    8986         354 :     DumpOptions *dopt = fout->dopt;
    8987         354 :     PQExpBuffer q = createPQExpBuffer();
    8988         354 :     PQExpBuffer tbloids = createPQExpBuffer();
    8989         354 :     PQExpBuffer checkoids = createPQExpBuffer();
    8990             :     PGresult   *res;
    8991             :     int         ntups;
    8992             :     int         curtblindx;
    8993             :     int         i_attrelid;
    8994             :     int         i_attnum;
    8995             :     int         i_attname;
    8996             :     int         i_atttypname;
    8997             :     int         i_attstattarget;
    8998             :     int         i_attstorage;
    8999             :     int         i_typstorage;
    9000             :     int         i_attidentity;
    9001             :     int         i_attgenerated;
    9002             :     int         i_attisdropped;
    9003             :     int         i_attlen;
    9004             :     int         i_attalign;
    9005             :     int         i_attislocal;
    9006             :     int         i_notnull_name;
    9007             :     int         i_notnull_noinherit;
    9008             :     int         i_notnull_islocal;
    9009             :     int         i_attoptions;
    9010             :     int         i_attcollation;
    9011             :     int         i_attcompression;
    9012             :     int         i_attfdwoptions;
    9013             :     int         i_attmissingval;
    9014             :     int         i_atthasdef;
    9015             : 
    9016             :     /*
    9017             :      * We want to perform just one query against pg_attribute, and then just
    9018             :      * one against pg_attrdef (for DEFAULTs) and two against pg_constraint
    9019             :      * (for CHECK constraints and for NOT NULL constraints).  However, we
    9020             :      * mustn't try to select every row of those catalogs and then sort it out
    9021             :      * on the client side, because some of the server-side functions we need
    9022             :      * would be unsafe to apply to tables we don't have lock on.  Hence, we
    9023             :      * build an array of the OIDs of tables we care about (and now have lock
    9024             :      * on!), and use a WHERE clause to constrain which rows are selected.
    9025             :      */
    9026         354 :     appendPQExpBufferChar(tbloids, '{');
    9027         354 :     appendPQExpBufferChar(checkoids, '{');
    9028       92540 :     for (int i = 0; i < numTables; i++)
    9029             :     {
    9030       92186 :         TableInfo  *tbinfo = &tblinfo[i];
    9031             : 
    9032             :         /* Don't bother to collect info for sequences */
    9033       92186 :         if (tbinfo->relkind == RELKIND_SEQUENCE)
    9034        1300 :             continue;
    9035             : 
    9036             :         /* Don't bother with uninteresting tables, either */
    9037       90886 :         if (!tbinfo->interesting)
    9038       78142 :             continue;
    9039             : 
    9040             :         /* OK, we need info for this table */
    9041       12744 :         if (tbloids->len > 1) /* do we have more than the '{'? */
    9042       12508 :             appendPQExpBufferChar(tbloids, ',');
    9043       12744 :         appendPQExpBuffer(tbloids, "%u", tbinfo->dobj.catId.oid);
    9044             : 
    9045       12744 :         if (tbinfo->ncheck > 0)
    9046             :         {
    9047             :             /* Also make a list of the ones with check constraints */
    9048        1140 :             if (checkoids->len > 1) /* do we have more than the '{'? */
    9049         994 :                 appendPQExpBufferChar(checkoids, ',');
    9050        1140 :             appendPQExpBuffer(checkoids, "%u", tbinfo->dobj.catId.oid);
    9051             :         }
    9052             :     }
    9053         354 :     appendPQExpBufferChar(tbloids, '}');
    9054         354 :     appendPQExpBufferChar(checkoids, '}');
    9055             : 
    9056             :     /*
    9057             :      * Find all the user attributes and their types.
    9058             :      *
    9059             :      * Since we only want to dump COLLATE clauses for attributes whose
    9060             :      * collation is different from their type's default, we use a CASE here to
    9061             :      * suppress uninteresting attcollations cheaply.
    9062             :      */
    9063         354 :     appendPQExpBufferStr(q,
    9064             :                          "SELECT\n"
    9065             :                          "a.attrelid,\n"
    9066             :                          "a.attnum,\n"
    9067             :                          "a.attname,\n"
    9068             :                          "a.attstattarget,\n"
    9069             :                          "a.attstorage,\n"
    9070             :                          "t.typstorage,\n"
    9071             :                          "a.atthasdef,\n"
    9072             :                          "a.attisdropped,\n"
    9073             :                          "a.attlen,\n"
    9074             :                          "a.attalign,\n"
    9075             :                          "a.attislocal,\n"
    9076             :                          "pg_catalog.format_type(t.oid, a.atttypmod) AS atttypname,\n"
    9077             :                          "array_to_string(a.attoptions, ', ') AS attoptions,\n"
    9078             :                          "CASE WHEN a.attcollation <> t.typcollation "
    9079             :                          "THEN a.attcollation ELSE 0 END AS attcollation,\n"
    9080             :                          "pg_catalog.array_to_string(ARRAY("
    9081             :                          "SELECT pg_catalog.quote_ident(option_name) || "
    9082             :                          "' ' || pg_catalog.quote_literal(option_value) "
    9083             :                          "FROM pg_catalog.pg_options_to_table(attfdwoptions) "
    9084             :                          "ORDER BY option_name"
    9085             :                          "), E',\n    ') AS attfdwoptions,\n");
    9086             : 
    9087             :     /*
    9088             :      * Find out any NOT NULL markings for each column.  In 18 and up we read
    9089             :      * pg_constraint to obtain the constraint name.  notnull_noinherit is set
    9090             :      * according to the NO INHERIT property.  For versions prior to 18, we
    9091             :      * store an empty string as the name when a constraint is marked as
    9092             :      * attnotnull (this cues dumpTableSchema to print the NOT NULL clause
    9093             :      * without a name); also, such cases are never NO INHERIT.
    9094             :      *
    9095             :      * We track in notnull_islocal whether the constraint was defined directly
    9096             :      * in this table or via an ancestor, for binary upgrade.  flagInhAttrs
    9097             :      * might modify this later for servers older than 18; it's also in charge
    9098             :      * of determining the correct inhcount.
    9099             :      */
    9100         354 :     if (fout->remoteVersion >= 180000)
    9101         354 :         appendPQExpBufferStr(q,
    9102             :                              "co.conname AS notnull_name,\n"
    9103             :                              "co.connoinherit AS notnull_noinherit,\n"
    9104             :                              "co.conislocal AS notnull_islocal,\n");
    9105             :     else
    9106           0 :         appendPQExpBufferStr(q,
    9107             :                              "CASE WHEN a.attnotnull THEN '' ELSE NULL END AS notnull_name,\n"
    9108             :                              "false AS notnull_noinherit,\n"
    9109             :                              "a.attislocal AS notnull_islocal,\n");
    9110             : 
    9111         354 :     if (fout->remoteVersion >= 140000)
    9112         354 :         appendPQExpBufferStr(q,
    9113             :                              "a.attcompression AS attcompression,\n");
    9114             :     else
    9115           0 :         appendPQExpBufferStr(q,
    9116             :                              "'' AS attcompression,\n");
    9117             : 
    9118         354 :     if (fout->remoteVersion >= 100000)
    9119         354 :         appendPQExpBufferStr(q,
    9120             :                              "a.attidentity,\n");
    9121             :     else
    9122           0 :         appendPQExpBufferStr(q,
    9123             :                              "'' AS attidentity,\n");
    9124             : 
    9125         354 :     if (fout->remoteVersion >= 110000)
    9126         354 :         appendPQExpBufferStr(q,
    9127             :                              "CASE WHEN a.atthasmissing AND NOT a.attisdropped "
    9128             :                              "THEN a.attmissingval ELSE null END AS attmissingval,\n");
    9129             :     else
    9130           0 :         appendPQExpBufferStr(q,
    9131             :                              "NULL AS attmissingval,\n");
    9132             : 
    9133         354 :     if (fout->remoteVersion >= 120000)
    9134         354 :         appendPQExpBufferStr(q,
    9135             :                              "a.attgenerated\n");
    9136             :     else
    9137           0 :         appendPQExpBufferStr(q,
    9138             :                              "'' AS attgenerated\n");
    9139             : 
    9140             :     /* need left join to pg_type to not fail on dropped columns ... */
    9141         354 :     appendPQExpBuffer(q,
    9142             :                       "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
    9143             :                       "JOIN pg_catalog.pg_attribute a ON (src.tbloid = a.attrelid) "
    9144             :                       "LEFT JOIN pg_catalog.pg_type t "
    9145             :                       "ON (a.atttypid = t.oid)\n",
    9146             :                       tbloids->data);
    9147             : 
    9148             :     /*
    9149             :      * In versions 18 and up, we need pg_constraint for explicit NOT NULL
    9150             :      * entries.  Also, we need to know if the NOT NULL for each column is
    9151             :      * backing a primary key.
    9152             :      */
    9153         354 :     if (fout->remoteVersion >= 180000)
    9154         354 :         appendPQExpBufferStr(q,
    9155             :                              " LEFT JOIN pg_catalog.pg_constraint co ON "
    9156             :                              "(a.attrelid = co.conrelid\n"
    9157             :                              "   AND co.contype = 'n' AND "
    9158             :                              "co.conkey = array[a.attnum])\n");
    9159             : 
    9160         354 :     appendPQExpBufferStr(q,
    9161             :                          "WHERE a.attnum > 0::pg_catalog.int2\n"
    9162             :                          "ORDER BY a.attrelid, a.attnum");
    9163             : 
    9164         354 :     res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
    9165             : 
    9166         354 :     ntups = PQntuples(res);
    9167             : 
    9168         354 :     i_attrelid = PQfnumber(res, "attrelid");
    9169         354 :     i_attnum = PQfnumber(res, "attnum");
    9170         354 :     i_attname = PQfnumber(res, "attname");
    9171         354 :     i_atttypname = PQfnumber(res, "atttypname");
    9172         354 :     i_attstattarget = PQfnumber(res, "attstattarget");
    9173         354 :     i_attstorage = PQfnumber(res, "attstorage");
    9174         354 :     i_typstorage = PQfnumber(res, "typstorage");
    9175         354 :     i_attidentity = PQfnumber(res, "attidentity");
    9176         354 :     i_attgenerated = PQfnumber(res, "attgenerated");
    9177         354 :     i_attisdropped = PQfnumber(res, "attisdropped");
    9178         354 :     i_attlen = PQfnumber(res, "attlen");
    9179         354 :     i_attalign = PQfnumber(res, "attalign");
    9180         354 :     i_attislocal = PQfnumber(res, "attislocal");
    9181         354 :     i_notnull_name = PQfnumber(res, "notnull_name");
    9182         354 :     i_notnull_noinherit = PQfnumber(res, "notnull_noinherit");
    9183         354 :     i_notnull_islocal = PQfnumber(res, "notnull_islocal");
    9184         354 :     i_attoptions = PQfnumber(res, "attoptions");
    9185         354 :     i_attcollation = PQfnumber(res, "attcollation");
    9186         354 :     i_attcompression = PQfnumber(res, "attcompression");
    9187         354 :     i_attfdwoptions = PQfnumber(res, "attfdwoptions");
    9188         354 :     i_attmissingval = PQfnumber(res, "attmissingval");
    9189         354 :     i_atthasdef = PQfnumber(res, "atthasdef");
    9190             : 
    9191             :     /* Within the next loop, we'll accumulate OIDs of tables with defaults */
    9192         354 :     resetPQExpBuffer(tbloids);
    9193         354 :     appendPQExpBufferChar(tbloids, '{');
    9194             : 
    9195             :     /*
    9196             :      * Outer loop iterates once per table, not once per row.  Incrementing of
    9197             :      * r is handled by the inner loop.
    9198             :      */
    9199         354 :     curtblindx = -1;
    9200       12798 :     for (int r = 0; r < ntups;)
    9201             :     {
    9202       12444 :         Oid         attrelid = atooid(PQgetvalue(res, r, i_attrelid));
    9203       12444 :         TableInfo  *tbinfo = NULL;
    9204             :         int         numatts;
    9205             :         bool        hasdefaults;
    9206             : 
    9207             :         /* Count rows for this table */
    9208       48128 :         for (numatts = 1; numatts < ntups - r; numatts++)
    9209       47898 :             if (atooid(PQgetvalue(res, r + numatts, i_attrelid)) != attrelid)
    9210       12214 :                 break;
    9211             : 
    9212             :         /*
    9213             :          * Locate the associated TableInfo; we rely on tblinfo[] being in OID
    9214             :          * order.
    9215             :          */
    9216       61810 :         while (++curtblindx < numTables)
    9217             :         {
    9218       61810 :             tbinfo = &tblinfo[curtblindx];
    9219       61810 :             if (tbinfo->dobj.catId.oid == attrelid)
    9220       12444 :                 break;
    9221             :         }
    9222       12444 :         if (curtblindx >= numTables)
    9223           0 :             pg_fatal("unrecognized table OID %u", attrelid);
    9224             :         /* cross-check that we only got requested tables */
    9225       12444 :         if (tbinfo->relkind == RELKIND_SEQUENCE ||
    9226       12444 :             !tbinfo->interesting)
    9227           0 :             pg_fatal("unexpected column data for table \"%s\"",
    9228             :                      tbinfo->dobj.name);
    9229             : 
    9230             :         /* Save data for this table */
    9231       12444 :         tbinfo->numatts = numatts;
    9232       12444 :         tbinfo->attnames = (char **) pg_malloc(numatts * sizeof(char *));
    9233       12444 :         tbinfo->atttypnames = (char **) pg_malloc(numatts * sizeof(char *));
    9234       12444 :         tbinfo->attstattarget = (int *) pg_malloc(numatts * sizeof(int));
    9235       12444 :         tbinfo->attstorage = (char *) pg_malloc(numatts * sizeof(char));
    9236       12444 :         tbinfo->typstorage = (char *) pg_malloc(numatts * sizeof(char));
    9237       12444 :         tbinfo->attidentity = (char *) pg_malloc(numatts * sizeof(char));
    9238       12444 :         tbinfo->attgenerated = (char *) pg_malloc(numatts * sizeof(char));
    9239       12444 :         tbinfo->attisdropped = (bool *) pg_malloc(numatts * sizeof(bool));
    9240       12444 :         tbinfo->attlen = (int *) pg_malloc(numatts * sizeof(int));
    9241       12444 :         tbinfo->attalign = (char *) pg_malloc(numatts * sizeof(char));
    9242       12444 :         tbinfo->attislocal = (bool *) pg_malloc(numatts * sizeof(bool));
    9243       12444 :         tbinfo->attoptions = (char **) pg_malloc(numatts * sizeof(char *));
    9244       12444 :         tbinfo->attcollation = (Oid *) pg_malloc(numatts * sizeof(Oid));
    9245       12444 :         tbinfo->attcompression = (char *) pg_malloc(numatts * sizeof(char));
    9246       12444 :         tbinfo->attfdwoptions = (char **) pg_malloc(numatts * sizeof(char *));
    9247       12444 :         tbinfo->attmissingval = (char **) pg_malloc(numatts * sizeof(char *));
    9248       12444 :         tbinfo->notnull_constrs = (char **) pg_malloc(numatts * sizeof(char *));
    9249       12444 :         tbinfo->notnull_noinh = (bool *) pg_malloc(numatts * sizeof(bool));
    9250       12444 :         tbinfo->notnull_islocal = (bool *) pg_malloc(numatts * sizeof(bool));
    9251       12444 :         tbinfo->attrdefs = (AttrDefInfo **) pg_malloc(numatts * sizeof(AttrDefInfo *));
    9252       12444 :         hasdefaults = false;
    9253             : 
    9254       60572 :         for (int j = 0; j < numatts; j++, r++)
    9255             :         {
    9256       48128 :             if (j + 1 != atoi(PQgetvalue(res, r, i_attnum)))
    9257           0 :                 pg_fatal("invalid column numbering in table \"%s\"",
    9258             :                          tbinfo->dobj.name);
    9259       48128 :             tbinfo->attnames[j] = pg_strdup(PQgetvalue(res, r, i_attname));
    9260       48128 :             tbinfo->atttypnames[j] = pg_strdup(PQgetvalue(res, r, i_atttypname));
    9261       48128 :             if (PQgetisnull(res, r, i_attstattarget))
    9262       48040 :                 tbinfo->attstattarget[j] = -1;
    9263             :             else
    9264          88 :                 tbinfo->attstattarget[j] = atoi(PQgetvalue(res, r, i_attstattarget));
    9265       48128 :             tbinfo->attstorage[j] = *(PQgetvalue(res, r, i_attstorage));
    9266       48128 :             tbinfo->typstorage[j] = *(PQgetvalue(res, r, i_typstorage));
    9267       48128 :             tbinfo->attidentity[j] = *(PQgetvalue(res, r, i_attidentity));
    9268       48128 :             tbinfo->attgenerated[j] = *(PQgetvalue(res, r, i_attgenerated));
    9269       48128 :             tbinfo->needs_override = tbinfo->needs_override || (tbinfo->attidentity[j] == ATTRIBUTE_IDENTITY_ALWAYS);
    9270       48128 :             tbinfo->attisdropped[j] = (PQgetvalue(res, r, i_attisdropped)[0] == 't');
    9271       48128 :             tbinfo->attlen[j] = atoi(PQgetvalue(res, r, i_attlen));
    9272       48128 :             tbinfo->attalign[j] = *(PQgetvalue(res, r, i_attalign));
    9273       48128 :             tbinfo->attislocal[j] = (PQgetvalue(res, r, i_attislocal)[0] == 't');
    9274             : 
    9275             :             /* Handle not-null constraint name and flags */
    9276       48128 :             determineNotNullFlags(fout, res, r,
    9277             :                                   tbinfo, j,
    9278             :                                   i_notnull_name, i_notnull_noinherit,
    9279             :                                   i_notnull_islocal);
    9280             : 
    9281       48128 :             tbinfo->attoptions[j] = pg_strdup(PQgetvalue(res, r, i_attoptions));
    9282       48128 :             tbinfo->attcollation[j] = atooid(PQgetvalue(res, r, i_attcollation));
    9283       48128 :             tbinfo->attcompression[j] = *(PQgetvalue(res, r, i_attcompression));
    9284       48128 :             tbinfo->attfdwoptions[j] = pg_strdup(PQgetvalue(res, r, i_attfdwoptions));
    9285       48128 :             tbinfo->attmissingval[j] = pg_strdup(PQgetvalue(res, r, i_attmissingval));
    9286       48128 :             tbinfo->attrdefs[j] = NULL; /* fix below */
    9287       48128 :             if (PQgetvalue(res, r, i_atthasdef)[0] == 't')
    9288        2644 :                 hasdefaults = true;
    9289             :         }
    9290             : 
    9291       12444 :         if (hasdefaults)
    9292             :         {
    9293             :             /* Collect OIDs of interesting tables that have defaults */
    9294        1972 :             if (tbloids->len > 1) /* do we have more than the '{'? */
    9295        1828 :                 appendPQExpBufferChar(tbloids, ',');
    9296        1972 :             appendPQExpBuffer(tbloids, "%u", tbinfo->dobj.catId.oid);
    9297             :         }
    9298             :     }
    9299             : 
    9300         354 :     PQclear(res);
    9301             : 
    9302             :     /*
    9303             :      * Now get info about column defaults.  This is skipped for a data-only
    9304             :      * dump, as it is only needed for table schemas.
    9305             :      */
    9306         354 :     if (dopt->dumpSchema && tbloids->len > 1)
    9307             :     {
    9308             :         AttrDefInfo *attrdefs;
    9309             :         int         numDefaults;
    9310         128 :         TableInfo  *tbinfo = NULL;
    9311             : 
    9312         128 :         pg_log_info("finding table default expressions");
    9313             : 
    9314         128 :         appendPQExpBufferChar(tbloids, '}');
    9315             : 
    9316         128 :         printfPQExpBuffer(q, "SELECT a.tableoid, a.oid, adrelid, adnum, "
    9317             :                           "pg_catalog.pg_get_expr(adbin, adrelid) AS adsrc\n"
    9318             :                           "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
    9319             :                           "JOIN pg_catalog.pg_attrdef a ON (src.tbloid = a.adrelid)\n"
    9320             :                           "ORDER BY a.adrelid, a.adnum",
    9321             :                           tbloids->data);
    9322             : 
    9323         128 :         res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
    9324             : 
    9325         128 :         numDefaults = PQntuples(res);
    9326         128 :         attrdefs = (AttrDefInfo *) pg_malloc(numDefaults * sizeof(AttrDefInfo));
    9327             : 
    9328         128 :         curtblindx = -1;
    9329        2576 :         for (int j = 0; j < numDefaults; j++)
    9330             :         {
    9331        2448 :             Oid         adtableoid = atooid(PQgetvalue(res, j, 0));
    9332        2448 :             Oid         adoid = atooid(PQgetvalue(res, j, 1));
    9333        2448 :             Oid         adrelid = atooid(PQgetvalue(res, j, 2));
    9334        2448 :             int         adnum = atoi(PQgetvalue(res, j, 3));
    9335        2448 :             char       *adsrc = PQgetvalue(res, j, 4);
    9336             : 
    9337             :             /*
    9338             :              * Locate the associated TableInfo; we rely on tblinfo[] being in
    9339             :              * OID order.
    9340             :              */
    9341        2448 :             if (tbinfo == NULL || tbinfo->dobj.catId.oid != adrelid)
    9342             :             {
    9343       38844 :                 while (++curtblindx < numTables)
    9344             :                 {
    9345       38844 :                     tbinfo = &tblinfo[curtblindx];
    9346       38844 :                     if (tbinfo->dobj.catId.oid == adrelid)
    9347        1836 :                         break;
    9348             :                 }
    9349        1836 :                 if (curtblindx >= numTables)
    9350           0 :                     pg_fatal("unrecognized table OID %u", adrelid);
    9351             :             }
    9352             : 
    9353        2448 :             if (adnum <= 0 || adnum > tbinfo->numatts)
    9354           0 :                 pg_fatal("invalid adnum value %d for table \"%s\"",
    9355             :                          adnum, tbinfo->dobj.name);
    9356             : 
    9357             :             /*
    9358             :              * dropped columns shouldn't have defaults, but just in case,
    9359             :              * ignore 'em
    9360             :              */
    9361        2448 :             if (tbinfo->attisdropped[adnum - 1])
    9362           0 :                 continue;
    9363             : 
    9364        2448 :             attrdefs[j].dobj.objType = DO_ATTRDEF;
    9365        2448 :             attrdefs[j].dobj.catId.tableoid = adtableoid;
    9366        2448 :             attrdefs[j].dobj.catId.oid = adoid;
    9367        2448 :             AssignDumpId(&attrdefs[j].dobj);
    9368        2448 :             attrdefs[j].adtable = tbinfo;
    9369        2448 :             attrdefs[j].adnum = adnum;
    9370        2448 :             attrdefs[j].adef_expr = pg_strdup(adsrc);
    9371             : 
    9372        2448 :             attrdefs[j].dobj.name = pg_strdup(tbinfo->dobj.name);
    9373        2448 :             attrdefs[j].dobj.namespace = tbinfo->dobj.namespace;
    9374             : 
    9375        2448 :             attrdefs[j].dobj.dump = tbinfo->dobj.dump;
    9376             : 
    9377             :             /*
    9378             :              * Figure out whether the default/generation expression should be
    9379             :              * dumped as part of the main CREATE TABLE (or similar) command or
    9380             :              * as a separate ALTER TABLE (or similar) command. The preference
    9381             :              * is to put it into the CREATE command, but in some cases that's
    9382             :              * not possible.
    9383             :              */
    9384        2448 :             if (tbinfo->attgenerated[adnum - 1])
    9385             :             {
    9386             :                 /*
    9387             :                  * Column generation expressions cannot be dumped separately,
    9388             :                  * because there is no syntax for it.  By setting separate to
    9389             :                  * false here we prevent the "default" from being processed as
    9390             :                  * its own dumpable object.  Later, flagInhAttrs() will mark
    9391             :                  * it as not to be dumped at all, if possible (that is, if it
    9392             :                  * can be inherited from a parent).
    9393             :                  */
    9394        1356 :                 attrdefs[j].separate = false;
    9395             :             }
    9396        1092 :             else if (tbinfo->relkind == RELKIND_VIEW)
    9397             :             {
    9398             :                 /*
    9399             :                  * Defaults on a VIEW must always be dumped as separate ALTER
    9400             :                  * TABLE commands.
    9401             :                  */
    9402          72 :                 attrdefs[j].separate = true;
    9403             :             }
    9404        1020 :             else if (!shouldPrintColumn(dopt, tbinfo, adnum - 1))
    9405             :             {
    9406             :                 /* column will be suppressed, print default separately */
    9407           8 :                 attrdefs[j].separate = true;
    9408             :             }
    9409             :             else
    9410             :             {
    9411        1012 :                 attrdefs[j].separate = false;
    9412             :             }
    9413             : 
    9414        2448 :             if (!attrdefs[j].separate)
    9415             :             {
    9416             :                 /*
    9417             :                  * Mark the default as needing to appear before the table, so
    9418             :                  * that any dependencies it has must be emitted before the
    9419             :                  * CREATE TABLE.  If this is not possible, we'll change to
    9420             :                  * "separate" mode while sorting dependencies.
    9421             :                  */
    9422        2368 :                 addObjectDependency(&tbinfo->dobj,
    9423        2368 :                                     attrdefs[j].dobj.dumpId);
    9424             :             }
    9425             : 
    9426        2448 :             tbinfo->attrdefs[adnum - 1] = &attrdefs[j];
    9427             :         }
    9428             : 
    9429         128 :         PQclear(res);
    9430             :     }
    9431             : 
    9432             :     /*
    9433             :      * Get info about table CHECK constraints.  This is skipped for a
    9434             :      * data-only dump, as it is only needed for table schemas.
    9435             :      */
    9436         354 :     if (dopt->dumpSchema && checkoids->len > 2)
    9437             :     {
    9438             :         ConstraintInfo *constrs;
    9439             :         int         numConstrs;
    9440             :         int         i_tableoid;
    9441             :         int         i_oid;
    9442             :         int         i_conrelid;
    9443             :         int         i_conname;
    9444             :         int         i_consrc;
    9445             :         int         i_conislocal;
    9446             :         int         i_convalidated;
    9447             : 
    9448         130 :         pg_log_info("finding table check constraints");
    9449             : 
    9450         130 :         resetPQExpBuffer(q);
    9451         130 :         appendPQExpBuffer(q,
    9452             :                           "SELECT c.tableoid, c.oid, conrelid, conname, "
    9453             :                           "pg_catalog.pg_get_constraintdef(c.oid) AS consrc, "
    9454             :                           "conislocal, convalidated "
    9455             :                           "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
    9456             :                           "JOIN pg_catalog.pg_constraint c ON (src.tbloid = c.conrelid)\n"
    9457             :                           "WHERE contype = 'c' "
    9458             :                           "ORDER BY c.conrelid, c.conname",
    9459             :                           checkoids->data);
    9460             : 
    9461         130 :         res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
    9462             : 
    9463         130 :         numConstrs = PQntuples(res);
    9464         130 :         constrs = (ConstraintInfo *) pg_malloc(numConstrs * sizeof(ConstraintInfo));
    9465             : 
    9466         130 :         i_tableoid = PQfnumber(res, "tableoid");
    9467         130 :         i_oid = PQfnumber(res, "oid");
    9468         130 :         i_conrelid = PQfnumber(res, "conrelid");
    9469         130 :         i_conname = PQfnumber(res, "conname");
    9470         130 :         i_consrc = PQfnumber(res, "consrc");
    9471         130 :         i_conislocal = PQfnumber(res, "conislocal");
    9472         130 :         i_convalidated = PQfnumber(res, "convalidated");
    9473             : 
    9474             :         /* As above, this loop iterates once per table, not once per row */
    9475         130 :         curtblindx = -1;
    9476        1168 :         for (int j = 0; j < numConstrs;)
    9477             :         {
    9478        1038 :             Oid         conrelid = atooid(PQgetvalue(res, j, i_conrelid));
    9479        1038 :             TableInfo  *tbinfo = NULL;
    9480             :             int         numcons;
    9481             : 
    9482             :             /* Count rows for this table */
    9483        1324 :             for (numcons = 1; numcons < numConstrs - j; numcons++)
    9484        1194 :                 if (atooid(PQgetvalue(res, j + numcons, i_conrelid)) != conrelid)
    9485         908 :                     break;
    9486             : 
    9487             :             /*
    9488             :              * Locate the associated TableInfo; we rely on tblinfo[] being in
    9489             :              * OID order.
    9490             :              */
    9491       37528 :             while (++curtblindx < numTables)
    9492             :             {
    9493       37528 :                 tbinfo = &tblinfo[curtblindx];
    9494       37528 :                 if (tbinfo->dobj.catId.oid == conrelid)
    9495        1038 :                     break;
    9496             :             }
    9497        1038 :             if (curtblindx >= numTables)
    9498           0 :                 pg_fatal("unrecognized table OID %u", conrelid);
    9499             : 
    9500        1038 :             if (numcons != tbinfo->ncheck)
    9501             :             {
    9502           0 :                 pg_log_error(ngettext("expected %d check constraint on table \"%s\" but found %d",
    9503             :                                       "expected %d check constraints on table \"%s\" but found %d",
    9504             :                                       tbinfo->ncheck),
    9505             :                              tbinfo->ncheck, tbinfo->dobj.name, numcons);
    9506           0 :                 pg_log_error_hint("The system catalogs might be corrupted.");
    9507           0 :                 exit_nicely(1);
    9508             :             }
    9509             : 
    9510        1038 :             tbinfo->checkexprs = constrs + j;
    9511             : 
    9512        2362 :             for (int c = 0; c < numcons; c++, j++)
    9513             :             {
    9514        1324 :                 bool        validated = PQgetvalue(res, j, i_convalidated)[0] == 't';
    9515             : 
    9516        1324 :                 constrs[j].dobj.objType = DO_CONSTRAINT;
    9517        1324 :                 constrs[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
    9518        1324 :                 constrs[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
    9519        1324 :                 AssignDumpId(&constrs[j].dobj);
    9520        1324 :                 constrs[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_conname));
    9521        1324 :                 constrs[j].dobj.namespace = tbinfo->dobj.namespace;
    9522        1324 :                 constrs[j].contable = tbinfo;
    9523        1324 :                 constrs[j].condomain = NULL;
    9524        1324 :                 constrs[j].contype = 'c';
    9525        1324 :                 constrs[j].condef = pg_strdup(PQgetvalue(res, j, i_consrc));
    9526        1324 :                 constrs[j].confrelid = InvalidOid;
    9527        1324 :                 constrs[j].conindex = 0;
    9528        1324 :                 constrs[j].condeferrable = false;
    9529        1324 :                 constrs[j].condeferred = false;
    9530        1324 :                 constrs[j].conislocal = (PQgetvalue(res, j, i_conislocal)[0] == 't');
    9531             : 
    9532             :                 /*
    9533             :                  * An unvalidated constraint needs to be dumped separately, so
    9534             :                  * that potentially-violating existing data is loaded before
    9535             :                  * the constraint.
    9536             :                  */
    9537        1324 :                 constrs[j].separate = !validated;
    9538             : 
    9539        1324 :                 constrs[j].dobj.dump = tbinfo->dobj.dump;
    9540             : 
    9541             :                 /*
    9542             :                  * Mark the constraint as needing to appear before the table
    9543             :                  * --- this is so that any other dependencies of the
    9544             :                  * constraint will be emitted before we try to create the
    9545             :                  * table.  If the constraint is to be dumped separately, it
    9546             :                  * will be dumped after data is loaded anyway, so don't do it.
    9547             :                  * (There's an automatic dependency in the opposite direction
    9548             :                  * anyway, so don't need to add one manually here.)
    9549             :                  */
    9550        1324 :                 if (!constrs[j].separate)
    9551        1194 :                     addObjectDependency(&tbinfo->dobj,
    9552        1194 :                                         constrs[j].dobj.dumpId);
    9553             : 
    9554             :                 /*
    9555             :                  * We will detect later whether the constraint must be split
    9556             :                  * out from the table definition.
    9557             :                  */
    9558             :             }
    9559             :         }
    9560             : 
    9561         130 :         PQclear(res);
    9562             :     }
    9563             : 
    9564         354 :     destroyPQExpBuffer(q);
    9565         354 :     destroyPQExpBuffer(tbloids);
    9566         354 :     destroyPQExpBuffer(checkoids);
    9567         354 : }
    9568             : 
    9569             : /*
    9570             :  * Based on the getTableAttrs query's row corresponding to one column, set
    9571             :  * the name and flags to handle a not-null constraint for that column in
    9572             :  * the tbinfo struct.
    9573             :  *
    9574             :  * Result row 'r' is for tbinfo's attribute 'j'.
    9575             :  *
    9576             :  * There are three possibilities:
    9577             :  * 1) the column has no not-null constraints. In that case, ->notnull_constrs
    9578             :  *    (the constraint name) remains NULL.
    9579             :  * 2) The column has a constraint with no name (this is the case when
    9580             :  *    constraints come from pre-18 servers).  In this case, ->notnull_constrs
    9581             :  *    is set to the empty string; dumpTableSchema will print just "NOT NULL".
    9582             :  * 3) The column has a constraint with a known name; in that case
    9583             :  *    notnull_constrs carries that name and dumpTableSchema will print
    9584             :  *    "CONSTRAINT the_name NOT NULL".  However, if the name is the default
    9585             :  *    (table_column_not_null), there's no need to print that name in the dump,
    9586             :  *    so notnull_constrs is set to the empty string and it behaves as the case
    9587             :  *    above.
    9588             :  *
    9589             :  * In a child table that inherits from a parent already containing NOT NULL
    9590             :  * constraints and the columns in the child don't have their own NOT NULL
    9591             :  * declarations, we suppress printing constraints in the child: the
    9592             :  * constraints are acquired at the point where the child is attached to the
    9593             :  * parent.  This is tracked in ->notnull_islocal (which is set in flagInhAttrs
    9594             :  * for servers pre-18).
    9595             :  *
    9596             :  * Any of these constraints might have the NO INHERIT bit.  If so we set
    9597             :  * ->notnull_noinh and NO INHERIT will be printed by dumpTableSchema.
    9598             :  *
    9599             :  * In case 3 above, the name comparison is a bit of a hack; it actually fails
    9600             :  * to do the right thing in all but the trivial case.  However, the downside
    9601             :  * of getting it wrong is simply that the name is printed rather than
    9602             :  * suppressed, so it's not a big deal.
    9603             :  */
    9604             : static void
    9605       48128 : determineNotNullFlags(Archive *fout, PGresult *res, int r,
    9606             :                       TableInfo *tbinfo, int j,
    9607             :                       int i_notnull_name, int i_notnull_noinherit,
    9608             :                       int i_notnull_islocal)
    9609             : {
    9610       48128 :     DumpOptions *dopt = fout->dopt;
    9611             : 
    9612             :     /*
    9613             :      * notnull_noinh is straight from the query result. notnull_islocal also,
    9614             :      * though flagInhAttrs may change that one later in versions < 18.
    9615             :      */
    9616       48128 :     tbinfo->notnull_noinh[j] = PQgetvalue(res, r, i_notnull_noinherit)[0] == 't';
    9617       48128 :     tbinfo->notnull_islocal[j] = PQgetvalue(res, r, i_notnull_islocal)[0] == 't';
    9618             : 
    9619             :     /*
    9620             :      * Determine a constraint name to use.  If the column is not marked not-
    9621             :      * null, we set NULL which cues ... to do nothing.  An empty string says
    9622             :      * to print an unnamed NOT NULL, and anything else is a constraint name to
    9623             :      * use.
    9624             :      */
    9625       48128 :     if (fout->remoteVersion < 180000)
    9626             :     {
    9627             :         /*
    9628             :          * < 18 doesn't have not-null names, so an unnamed constraint is
    9629             :          * sufficient.
    9630             :          */
    9631           0 :         if (PQgetisnull(res, r, i_notnull_name))
    9632           0 :             tbinfo->notnull_constrs[j] = NULL;
    9633             :         else
    9634           0 :             tbinfo->notnull_constrs[j] = "";
    9635             :     }
    9636             :     else
    9637             :     {
    9638       48128 :         if (PQgetisnull(res, r, i_notnull_name))
    9639       43242 :             tbinfo->notnull_constrs[j] = NULL;
    9640             :         else
    9641             :         {
    9642             :             /*
    9643             :              * In binary upgrade of inheritance child tables, must have a
    9644             :              * constraint name that we can UPDATE later.
    9645             :              */
    9646        4886 :             if (dopt->binary_upgrade &&
    9647         550 :                 !tbinfo->ispartition &&
    9648         400 :                 !tbinfo->notnull_islocal)
    9649             :             {
    9650           0 :                 tbinfo->notnull_constrs[j] =
    9651           0 :                     pstrdup(PQgetvalue(res, r, i_notnull_name));
    9652             :             }
    9653             :             else
    9654             :             {
    9655             :                 char       *default_name;
    9656             : 
    9657             :                 /* XXX should match ChooseConstraintName better */
    9658        4886 :                 default_name = psprintf("%s_%s_not_null", tbinfo->dobj.name,
    9659        4886 :                                         tbinfo->attnames[j]);
    9660        4886 :                 if (strcmp(default_name,
    9661        4886 :                            PQgetvalue(res, r, i_notnull_name)) == 0)
    9662        3290 :                     tbinfo->notnull_constrs[j] = "";
    9663             :                 else
    9664             :                 {
    9665        1596 :                     tbinfo->notnull_constrs[j] =
    9666        1596 :                         pstrdup(PQgetvalue(res, r, i_notnull_name));
    9667             :                 }
    9668        4886 :                 free(default_name);
    9669             :             }
    9670             :         }
    9671             :     }
    9672       48128 : }
    9673             : 
    9674             : /*
    9675             :  * Test whether a column should be printed as part of table's CREATE TABLE.
    9676             :  * Column number is zero-based.
    9677             :  *
    9678             :  * Normally this is always true, but it's false for dropped columns, as well
    9679             :  * as those that were inherited without any local definition.  (If we print
    9680             :  * such a column it will mistakenly get pg_attribute.attislocal set to true.)
    9681             :  * For partitions, it's always true, because we want the partitions to be
    9682             :  * created independently and ATTACH PARTITION used afterwards.
    9683             :  *
    9684             :  * In binary_upgrade mode, we must print all columns and fix the attislocal/
    9685             :  * attisdropped state later, so as to keep control of the physical column
    9686             :  * order.
    9687             :  *
    9688             :  * This function exists because there are scattered nonobvious places that
    9689             :  * must be kept in sync with this decision.
    9690             :  */
    9691             : bool
    9692       79572 : shouldPrintColumn(const DumpOptions *dopt, const TableInfo *tbinfo, int colno)
    9693             : {
    9694       79572 :     if (dopt->binary_upgrade)
    9695       12184 :         return true;
    9696       67388 :     if (tbinfo->attisdropped[colno])
    9697        1468 :         return false;
    9698       65920 :     return (tbinfo->attislocal[colno] || tbinfo->ispartition);
    9699             : }
    9700             : 
    9701             : 
    9702             : /*
    9703             :  * getTSParsers:
    9704             :  *    get information about all text search parsers in the system catalogs
    9705             :  */
    9706             : void
    9707         354 : getTSParsers(Archive *fout)
    9708             : {
    9709             :     PGresult   *res;
    9710             :     int         ntups;
    9711             :     int         i;
    9712             :     PQExpBuffer query;
    9713             :     TSParserInfo *prsinfo;
    9714             :     int         i_tableoid;
    9715             :     int         i_oid;
    9716             :     int         i_prsname;
    9717             :     int         i_prsnamespace;
    9718             :     int         i_prsstart;
    9719             :     int         i_prstoken;
    9720             :     int         i_prsend;
    9721             :     int         i_prsheadline;
    9722             :     int         i_prslextype;
    9723             : 
    9724         354 :     query = createPQExpBuffer();
    9725             : 
    9726             :     /*
    9727             :      * find all text search objects, including builtin ones; we filter out
    9728             :      * system-defined objects at dump-out time.
    9729             :      */
    9730             : 
    9731         354 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, prsname, prsnamespace, "
    9732             :                          "prsstart::oid, prstoken::oid, "
    9733             :                          "prsend::oid, prsheadline::oid, prslextype::oid "
    9734             :                          "FROM pg_ts_parser");
    9735             : 
    9736         354 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    9737             : 
    9738         354 :     ntups = PQntuples(res);
    9739             : 
    9740         354 :     prsinfo = (TSParserInfo *) pg_malloc(ntups * sizeof(TSParserInfo));
    9741             : 
    9742         354 :     i_tableoid = PQfnumber(res, "tableoid");
    9743         354 :     i_oid = PQfnumber(res, "oid");
    9744         354 :     i_prsname = PQfnumber(res, "prsname");
    9745         354 :     i_prsnamespace = PQfnumber(res, "prsnamespace");
    9746         354 :     i_prsstart = PQfnumber(res, "prsstart");
    9747         354 :     i_prstoken = PQfnumber(res, "prstoken");
    9748         354 :     i_prsend = PQfnumber(res, "prsend");
    9749         354 :     i_prsheadline = PQfnumber(res, "prsheadline");
    9750         354 :     i_prslextype = PQfnumber(res, "prslextype");
    9751             : 
    9752         806 :     for (i = 0; i < ntups; i++)
    9753             :     {
    9754         452 :         prsinfo[i].dobj.objType = DO_TSPARSER;
    9755         452 :         prsinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    9756         452 :         prsinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    9757         452 :         AssignDumpId(&prsinfo[i].dobj);
    9758         452 :         prsinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_prsname));
    9759         904 :         prsinfo[i].dobj.namespace =
    9760         452 :             findNamespace(atooid(PQgetvalue(res, i, i_prsnamespace)));
    9761         452 :         prsinfo[i].prsstart = atooid(PQgetvalue(res, i, i_prsstart));
    9762         452 :         prsinfo[i].prstoken = atooid(PQgetvalue(res, i, i_prstoken));
    9763         452 :         prsinfo[i].prsend = atooid(PQgetvalue(res, i, i_prsend));
    9764         452 :         prsinfo[i].prsheadline = atooid(PQgetvalue(res, i, i_prsheadline));
    9765         452 :         prsinfo[i].prslextype = atooid(PQgetvalue(res, i, i_prslextype));
    9766             : 
    9767             :         /* Decide whether we want to dump it */
    9768         452 :         selectDumpableObject(&(prsinfo[i].dobj), fout);
    9769             :     }
    9770             : 
    9771         354 :     PQclear(res);
    9772             : 
    9773         354 :     destroyPQExpBuffer(query);
    9774         354 : }
    9775             : 
    9776             : /*
    9777             :  * getTSDictionaries:
    9778             :  *    get information about all text search dictionaries in the system catalogs
    9779             :  */
    9780             : void
    9781         354 : getTSDictionaries(Archive *fout)
    9782             : {
    9783             :     PGresult   *res;
    9784             :     int         ntups;
    9785             :     int         i;
    9786             :     PQExpBuffer query;
    9787             :     TSDictInfo *dictinfo;
    9788             :     int         i_tableoid;
    9789             :     int         i_oid;
    9790             :     int         i_dictname;
    9791             :     int         i_dictnamespace;
    9792             :     int         i_dictowner;
    9793             :     int         i_dicttemplate;
    9794             :     int         i_dictinitoption;
    9795             : 
    9796         354 :     query = createPQExpBuffer();
    9797             : 
    9798         354 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, dictname, "
    9799             :                          "dictnamespace, dictowner, "
    9800             :                          "dicttemplate, dictinitoption "
    9801             :                          "FROM pg_ts_dict");
    9802             : 
    9803         354 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    9804             : 
    9805         354 :     ntups = PQntuples(res);
    9806             : 
    9807         354 :     dictinfo = (TSDictInfo *) pg_malloc(ntups * sizeof(TSDictInfo));
    9808             : 
    9809         354 :     i_tableoid = PQfnumber(res, "tableoid");
    9810         354 :     i_oid = PQfnumber(res, "oid");
    9811         354 :     i_dictname = PQfnumber(res, "dictname");
    9812         354 :     i_dictnamespace = PQfnumber(res, "dictnamespace");
    9813         354 :     i_dictowner = PQfnumber(res, "dictowner");
    9814         354 :     i_dictinitoption = PQfnumber(res, "dictinitoption");
    9815         354 :     i_dicttemplate = PQfnumber(res, "dicttemplate");
    9816             : 
    9817       11198 :     for (i = 0; i < ntups; i++)
    9818             :     {
    9819       10844 :         dictinfo[i].dobj.objType = DO_TSDICT;
    9820       10844 :         dictinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    9821       10844 :         dictinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    9822       10844 :         AssignDumpId(&dictinfo[i].dobj);
    9823       10844 :         dictinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_dictname));
    9824       21688 :         dictinfo[i].dobj.namespace =
    9825       10844 :             findNamespace(atooid(PQgetvalue(res, i, i_dictnamespace)));
    9826       10844 :         dictinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_dictowner));
    9827       10844 :         dictinfo[i].dicttemplate = atooid(PQgetvalue(res, i, i_dicttemplate));
    9828       10844 :         if (PQgetisnull(res, i, i_dictinitoption))
    9829         452 :             dictinfo[i].dictinitoption = NULL;
    9830             :         else
    9831       10392 :             dictinfo[i].dictinitoption = pg_strdup(PQgetvalue(res, i, i_dictinitoption));
    9832             : 
    9833             :         /* Decide whether we want to dump it */
    9834       10844 :         selectDumpableObject(&(dictinfo[i].dobj), fout);
    9835             :     }
    9836             : 
    9837         354 :     PQclear(res);
    9838             : 
    9839         354 :     destroyPQExpBuffer(query);
    9840         354 : }
    9841             : 
    9842             : /*
    9843             :  * getTSTemplates:
    9844             :  *    get information about all text search templates in the system catalogs
    9845             :  */
    9846             : void
    9847         354 : getTSTemplates(Archive *fout)
    9848             : {
    9849             :     PGresult   *res;
    9850             :     int         ntups;
    9851             :     int         i;
    9852             :     PQExpBuffer query;
    9853             :     TSTemplateInfo *tmplinfo;
    9854             :     int         i_tableoid;
    9855             :     int         i_oid;
    9856             :     int         i_tmplname;
    9857             :     int         i_tmplnamespace;
    9858             :     int         i_tmplinit;
    9859             :     int         i_tmpllexize;
    9860             : 
    9861         354 :     query = createPQExpBuffer();
    9862             : 
    9863         354 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, tmplname, "
    9864             :                          "tmplnamespace, tmplinit::oid, tmpllexize::oid "
    9865             :                          "FROM pg_ts_template");
    9866             : 
    9867         354 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    9868             : 
    9869         354 :     ntups = PQntuples(res);
    9870             : 
    9871         354 :     tmplinfo = (TSTemplateInfo *) pg_malloc(ntups * sizeof(TSTemplateInfo));
    9872             : 
    9873         354 :     i_tableoid = PQfnumber(res, "tableoid");
    9874         354 :     i_oid = PQfnumber(res, "oid");
    9875         354 :     i_tmplname = PQfnumber(res, "tmplname");
    9876         354 :     i_tmplnamespace = PQfnumber(res, "tmplnamespace");
    9877         354 :     i_tmplinit = PQfnumber(res, "tmplinit");
    9878         354 :     i_tmpllexize = PQfnumber(res, "tmpllexize");
    9879             : 
    9880        2222 :     for (i = 0; i < ntups; i++)
    9881             :     {
    9882        1868 :         tmplinfo[i].dobj.objType = DO_TSTEMPLATE;
    9883        1868 :         tmplinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    9884        1868 :         tmplinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    9885        1868 :         AssignDumpId(&tmplinfo[i].dobj);
    9886        1868 :         tmplinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_tmplname));
    9887        3736 :         tmplinfo[i].dobj.namespace =
    9888        1868 :             findNamespace(atooid(PQgetvalue(res, i, i_tmplnamespace)));
    9889        1868 :         tmplinfo[i].tmplinit = atooid(PQgetvalue(res, i, i_tmplinit));
    9890        1868 :         tmplinfo[i].tmpllexize = atooid(PQgetvalue(res, i, i_tmpllexize));
    9891             : 
    9892             :         /* Decide whether we want to dump it */
    9893        1868 :         selectDumpableObject(&(tmplinfo[i].dobj), fout);
    9894             :     }
    9895             : 
    9896         354 :     PQclear(res);
    9897             : 
    9898         354 :     destroyPQExpBuffer(query);
    9899         354 : }
    9900             : 
    9901             : /*
    9902             :  * getTSConfigurations:
    9903             :  *    get information about all text search configurations
    9904             :  */
    9905             : void
    9906         354 : getTSConfigurations(Archive *fout)
    9907             : {
    9908             :     PGresult   *res;
    9909             :     int         ntups;
    9910             :     int         i;
    9911             :     PQExpBuffer query;
    9912             :     TSConfigInfo *cfginfo;
    9913             :     int         i_tableoid;
    9914             :     int         i_oid;
    9915             :     int         i_cfgname;
    9916             :     int         i_cfgnamespace;
    9917             :     int         i_cfgowner;
    9918             :     int         i_cfgparser;
    9919             : 
    9920         354 :     query = createPQExpBuffer();
    9921             : 
    9922         354 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, cfgname, "
    9923             :                          "cfgnamespace, cfgowner, cfgparser "
    9924             :                          "FROM pg_ts_config");
    9925             : 
    9926         354 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    9927             : 
    9928         354 :     ntups = PQntuples(res);
    9929             : 
    9930         354 :     cfginfo = (TSConfigInfo *) pg_malloc(ntups * sizeof(TSConfigInfo));
    9931             : 
    9932         354 :     i_tableoid = PQfnumber(res, "tableoid");
    9933         354 :     i_oid = PQfnumber(res, "oid");
    9934         354 :     i_cfgname = PQfnumber(res, "cfgname");
    9935         354 :     i_cfgnamespace = PQfnumber(res, "cfgnamespace");
    9936         354 :     i_cfgowner = PQfnumber(res, "cfgowner");
    9937         354 :     i_cfgparser = PQfnumber(res, "cfgparser");
    9938             : 
    9939       11128 :     for (i = 0; i < ntups; i++)
    9940             :     {
    9941       10774 :         cfginfo[i].dobj.objType = DO_TSCONFIG;
    9942       10774 :         cfginfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    9943       10774 :         cfginfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    9944       10774 :         AssignDumpId(&cfginfo[i].dobj);
    9945       10774 :         cfginfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_cfgname));
    9946       21548 :         cfginfo[i].dobj.namespace =
    9947       10774 :             findNamespace(atooid(PQgetvalue(res, i, i_cfgnamespace)));
    9948       10774 :         cfginfo[i].rolname = getRoleName(PQgetvalue(res, i, i_cfgowner));
    9949       10774 :         cfginfo[i].cfgparser = atooid(PQgetvalue(res, i, i_cfgparser));
    9950             : 
    9951             :         /* Decide whether we want to dump it */
    9952       10774 :         selectDumpableObject(&(cfginfo[i].dobj), fout);
    9953             :     }
    9954             : 
    9955         354 :     PQclear(res);
    9956             : 
    9957         354 :     destroyPQExpBuffer(query);
    9958         354 : }
    9959             : 
    9960             : /*
    9961             :  * getForeignDataWrappers:
    9962             :  *    get information about all foreign-data wrappers in the system catalogs
    9963             :  */
    9964             : void
    9965         354 : getForeignDataWrappers(Archive *fout)
    9966             : {
    9967             :     PGresult   *res;
    9968             :     int         ntups;
    9969             :     int         i;
    9970             :     PQExpBuffer query;
    9971             :     FdwInfo    *fdwinfo;
    9972             :     int         i_tableoid;
    9973             :     int         i_oid;
    9974             :     int         i_fdwname;
    9975             :     int         i_fdwowner;
    9976             :     int         i_fdwhandler;
    9977             :     int         i_fdwvalidator;
    9978             :     int         i_fdwacl;
    9979             :     int         i_acldefault;
    9980             :     int         i_fdwoptions;
    9981             : 
    9982         354 :     query = createPQExpBuffer();
    9983             : 
    9984         354 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, fdwname, "
    9985             :                          "fdwowner, "
    9986             :                          "fdwhandler::pg_catalog.regproc, "
    9987             :                          "fdwvalidator::pg_catalog.regproc, "
    9988             :                          "fdwacl, "
    9989             :                          "acldefault('F', fdwowner) AS acldefault, "
    9990             :                          "array_to_string(ARRAY("
    9991             :                          "SELECT quote_ident(option_name) || ' ' || "
    9992             :                          "quote_literal(option_value) "
    9993             :                          "FROM pg_options_to_table(fdwoptions) "
    9994             :                          "ORDER BY option_name"
    9995             :                          "), E',\n    ') AS fdwoptions "
    9996             :                          "FROM pg_foreign_data_wrapper");
    9997             : 
    9998         354 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    9999             : 
   10000         354 :     ntups = PQntuples(res);
   10001             : 
   10002         354 :     fdwinfo = (FdwInfo *) pg_malloc(ntups * sizeof(FdwInfo));
   10003             : 
   10004         354 :     i_tableoid = PQfnumber(res, "tableoid");
   10005         354 :     i_oid = PQfnumber(res, "oid");
   10006         354 :     i_fdwname = PQfnumber(res, "fdwname");
   10007         354 :     i_fdwowner = PQfnumber(res, "fdwowner");
   10008         354 :     i_fdwhandler = PQfnumber(res, "fdwhandler");
   10009         354 :     i_fdwvalidator = PQfnumber(res, "fdwvalidator");
   10010         354 :     i_fdwacl = PQfnumber(res, "fdwacl");
   10011         354 :     i_acldefault = PQfnumber(res, "acldefault");
   10012         354 :     i_fdwoptions = PQfnumber(res, "fdwoptions");
   10013             : 
   10014         504 :     for (i = 0; i < ntups; i++)
   10015             :     {
   10016         150 :         fdwinfo[i].dobj.objType = DO_FDW;
   10017         150 :         fdwinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
   10018         150 :         fdwinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
   10019         150 :         AssignDumpId(&fdwinfo[i].dobj);
   10020         150 :         fdwinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_fdwname));
   10021         150 :         fdwinfo[i].dobj.namespace = NULL;
   10022         150 :         fdwinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_fdwacl));
   10023         150 :         fdwinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
   10024         150 :         fdwinfo[i].dacl.privtype = 0;
   10025         150 :         fdwinfo[i].dacl.initprivs = NULL;
   10026         150 :         fdwinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_fdwowner));
   10027         150 :         fdwinfo[i].fdwhandler = pg_strdup(PQgetvalue(res, i, i_fdwhandler));
   10028         150 :         fdwinfo[i].fdwvalidator = pg_strdup(PQgetvalue(res, i, i_fdwvalidator));
   10029         150 :         fdwinfo[i].fdwoptions = pg_strdup(PQgetvalue(res, i, i_fdwoptions));
   10030             : 
   10031             :         /* Decide whether we want to dump it */
   10032         150 :         selectDumpableObject(&(fdwinfo[i].dobj), fout);
   10033             : 
   10034             :         /* Mark whether FDW has an ACL */
   10035         150 :         if (!PQgetisnull(res, i, i_fdwacl))
   10036          98 :             fdwinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
   10037             :     }
   10038             : 
   10039         354 :     PQclear(res);
   10040             : 
   10041         354 :     destroyPQExpBuffer(query);
   10042         354 : }
   10043             : 
   10044             : /*
   10045             :  * getForeignServers:
   10046             :  *    get information about all foreign servers in the system catalogs
   10047             :  */
   10048             : void
   10049         354 : getForeignServers(Archive *fout)
   10050             : {
   10051             :     PGresult   *res;
   10052             :     int         ntups;
   10053             :     int         i;
   10054             :     PQExpBuffer query;
   10055             :     ForeignServerInfo *srvinfo;
   10056             :     int         i_tableoid;
   10057             :     int         i_oid;
   10058             :     int         i_srvname;
   10059             :     int         i_srvowner;
   10060             :     int         i_srvfdw;
   10061             :     int         i_srvtype;
   10062             :     int         i_srvversion;
   10063             :     int         i_srvacl;
   10064             :     int         i_acldefault;
   10065             :     int         i_srvoptions;
   10066             : 
   10067         354 :     query = createPQExpBuffer();
   10068             : 
   10069         354 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, srvname, "
   10070             :                          "srvowner, "
   10071             :                          "srvfdw, srvtype, srvversion, srvacl, "
   10072             :                          "acldefault('S', srvowner) AS acldefault, "
   10073             :                          "array_to_string(ARRAY("
   10074             :                          "SELECT quote_ident(option_name) || ' ' || "
   10075             :                          "quote_literal(option_value) "
   10076             :                          "FROM pg_options_to_table(srvoptions) "
   10077             :                          "ORDER BY option_name"
   10078             :                          "), E',\n    ') AS srvoptions "
   10079             :                          "FROM pg_foreign_server");
   10080             : 
   10081         354 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   10082             : 
   10083         354 :     ntups = PQntuples(res);
   10084             : 
   10085         354 :     srvinfo = (ForeignServerInfo *) pg_malloc(ntups * sizeof(ForeignServerInfo));
   10086             : 
   10087         354 :     i_tableoid = PQfnumber(res, "tableoid");
   10088         354 :     i_oid = PQfnumber(res, "oid");
   10089         354 :     i_srvname = PQfnumber(res, "srvname");
   10090         354 :     i_srvowner = PQfnumber(res, "srvowner");
   10091         354 :     i_srvfdw = PQfnumber(res, "srvfdw");
   10092         354 :     i_srvtype = PQfnumber(res, "srvtype");
   10093         354 :     i_srvversion = PQfnumber(res, "srvversion");
   10094         354 :     i_srvacl = PQfnumber(res, "srvacl");
   10095         354 :     i_acldefault = PQfnumber(res, "acldefault");
   10096         354 :     i_srvoptions = PQfnumber(res, "srvoptions");
   10097             : 
   10098         512 :     for (i = 0; i < ntups; i++)
   10099             :     {
   10100         158 :         srvinfo[i].dobj.objType = DO_FOREIGN_SERVER;
   10101         158 :         srvinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
   10102         158 :         srvinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
   10103         158 :         AssignDumpId(&srvinfo[i].dobj);
   10104         158 :         srvinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_srvname));
   10105         158 :         srvinfo[i].dobj.namespace = NULL;
   10106         158 :         srvinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_srvacl));
   10107         158 :         srvinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
   10108         158 :         srvinfo[i].dacl.privtype = 0;
   10109         158 :         srvinfo[i].dacl.initprivs = NULL;
   10110         158 :         srvinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_srvowner));
   10111         158 :         srvinfo[i].srvfdw = atooid(PQgetvalue(res, i, i_srvfdw));
   10112         158 :         srvinfo[i].srvtype = pg_strdup(PQgetvalue(res, i, i_srvtype));
   10113         158 :         srvinfo[i].srvversion = pg_strdup(PQgetvalue(res, i, i_srvversion));
   10114         158 :         srvinfo[i].srvoptions = pg_strdup(PQgetvalue(res, i, i_srvoptions));
   10115             : 
   10116             :         /* Decide whether we want to dump it */
   10117         158 :         selectDumpableObject(&(srvinfo[i].dobj), fout);
   10118             : 
   10119             :         /* Servers have user mappings */
   10120         158 :         srvinfo[i].dobj.components |= DUMP_COMPONENT_USERMAP;
   10121             : 
   10122             :         /* Mark whether server has an ACL */
   10123         158 :         if (!PQgetisnull(res, i, i_srvacl))
   10124          98 :             srvinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
   10125             :     }
   10126             : 
   10127         354 :     PQclear(res);
   10128             : 
   10129         354 :     destroyPQExpBuffer(query);
   10130         354 : }
   10131             : 
   10132             : /*
   10133             :  * getDefaultACLs:
   10134             :  *    get information about all default ACL information in the system catalogs
   10135             :  */
   10136             : void
   10137         354 : getDefaultACLs(Archive *fout)
   10138             : {
   10139         354 :     DumpOptions *dopt = fout->dopt;
   10140             :     DefaultACLInfo *daclinfo;
   10141             :     PQExpBuffer query;
   10142             :     PGresult   *res;
   10143             :     int         i_oid;
   10144             :     int         i_tableoid;
   10145             :     int         i_defaclrole;
   10146             :     int         i_defaclnamespace;
   10147             :     int         i_defaclobjtype;
   10148             :     int         i_defaclacl;
   10149             :     int         i_acldefault;
   10150             :     int         i,
   10151             :                 ntups;
   10152             : 
   10153         354 :     query = createPQExpBuffer();
   10154             : 
   10155             :     /*
   10156             :      * Global entries (with defaclnamespace=0) replace the hard-wired default
   10157             :      * ACL for their object type.  We should dump them as deltas from the
   10158             :      * default ACL, since that will be used as a starting point for
   10159             :      * interpreting the ALTER DEFAULT PRIVILEGES commands.  On the other hand,
   10160             :      * non-global entries can only add privileges not revoke them.  We must
   10161             :      * dump those as-is (i.e., as deltas from an empty ACL).
   10162             :      *
   10163             :      * We can use defaclobjtype as the object type for acldefault(), except
   10164             :      * for the case of 'S' (DEFACLOBJ_SEQUENCE) which must be converted to
   10165             :      * 's'.
   10166             :      */
   10167         354 :     appendPQExpBufferStr(query,
   10168             :                          "SELECT oid, tableoid, "
   10169             :                          "defaclrole, "
   10170             :                          "defaclnamespace, "
   10171             :                          "defaclobjtype, "
   10172             :                          "defaclacl, "
   10173             :                          "CASE WHEN defaclnamespace = 0 THEN "
   10174             :                          "acldefault(CASE WHEN defaclobjtype = 'S' "
   10175             :                          "THEN 's'::\"char\" ELSE defaclobjtype END, "
   10176             :                          "defaclrole) ELSE '{}' END AS acldefault "
   10177             :                          "FROM pg_default_acl");
   10178             : 
   10179         354 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   10180             : 
   10181         354 :     ntups = PQntuples(res);
   10182             : 
   10183         354 :     daclinfo = (DefaultACLInfo *) pg_malloc(ntups * sizeof(DefaultACLInfo));
   10184             : 
   10185         354 :     i_oid = PQfnumber(res, "oid");
   10186         354 :     i_tableoid = PQfnumber(res, "tableoid");
   10187         354 :     i_defaclrole = PQfnumber(res, "defaclrole");
   10188         354 :     i_defaclnamespace = PQfnumber(res, "defaclnamespace");
   10189         354 :     i_defaclobjtype = PQfnumber(res, "defaclobjtype");
   10190         354 :     i_defaclacl = PQfnumber(res, "defaclacl");
   10191         354 :     i_acldefault = PQfnumber(res, "acldefault");
   10192             : 
   10193         746 :     for (i = 0; i < ntups; i++)
   10194             :     {
   10195         392 :         Oid         nspid = atooid(PQgetvalue(res, i, i_defaclnamespace));
   10196             : 
   10197         392 :         daclinfo[i].dobj.objType = DO_DEFAULT_ACL;
   10198         392 :         daclinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
   10199         392 :         daclinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
   10200         392 :         AssignDumpId(&daclinfo[i].dobj);
   10201             :         /* cheesy ... is it worth coming up with a better object name? */
   10202         392 :         daclinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_defaclobjtype));
   10203             : 
   10204         392 :         if (nspid != InvalidOid)
   10205         196 :             daclinfo[i].dobj.namespace = findNamespace(nspid);
   10206             :         else
   10207         196 :             daclinfo[i].dobj.namespace = NULL;
   10208             : 
   10209         392 :         daclinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_defaclacl));
   10210         392 :         daclinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
   10211         392 :         daclinfo[i].dacl.privtype = 0;
   10212         392 :         daclinfo[i].dacl.initprivs = NULL;
   10213         392 :         daclinfo[i].defaclrole = getRoleName(PQgetvalue(res, i, i_defaclrole));
   10214         392 :         daclinfo[i].defaclobjtype = *(PQgetvalue(res, i, i_defaclobjtype));
   10215             : 
   10216             :         /* Default ACLs are ACLs, of course */
   10217         392 :         daclinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
   10218             : 
   10219             :         /* Decide whether we want to dump it */
   10220         392 :         selectDumpableDefaultACL(&(daclinfo[i]), dopt);
   10221             :     }
   10222             : 
   10223         354 :     PQclear(res);
   10224             : 
   10225         354 :     destroyPQExpBuffer(query);
   10226         354 : }
   10227             : 
   10228             : /*
   10229             :  * getRoleName -- look up the name of a role, given its OID
   10230             :  *
   10231             :  * In current usage, we don't expect failures, so error out for a bad OID.
   10232             :  */
   10233             : static const char *
   10234     1107976 : getRoleName(const char *roleoid_str)
   10235             : {
   10236     1107976 :     Oid         roleoid = atooid(roleoid_str);
   10237             : 
   10238             :     /*
   10239             :      * Do binary search to find the appropriate item.
   10240             :      */
   10241     1107976 :     if (nrolenames > 0)
   10242             :     {
   10243     1107976 :         RoleNameItem *low = &rolenames[0];
   10244     1107976 :         RoleNameItem *high = &rolenames[nrolenames - 1];
   10245             : 
   10246     4432330 :         while (low <= high)
   10247             :         {
   10248     4432330 :             RoleNameItem *middle = low + (high - low) / 2;
   10249             : 
   10250     4432330 :             if (roleoid < middle->roleoid)
   10251     3321586 :                 high = middle - 1;
   10252     1110744 :             else if (roleoid > middle->roleoid)
   10253        2768 :                 low = middle + 1;
   10254             :             else
   10255     1107976 :                 return middle->rolename; /* found a match */
   10256             :         }
   10257             :     }
   10258             : 
   10259           0 :     pg_fatal("role with OID %u does not exist", roleoid);
   10260             :     return NULL;                /* keep compiler quiet */
   10261             : }
   10262             : 
   10263             : /*
   10264             :  * collectRoleNames --
   10265             :  *
   10266             :  * Construct a table of all known roles.
   10267             :  * The table is sorted by OID for speed in lookup.
   10268             :  */
   10269             : static void
   10270         356 : collectRoleNames(Archive *fout)
   10271             : {
   10272             :     PGresult   *res;
   10273             :     const char *query;
   10274             :     int         i;
   10275             : 
   10276         356 :     query = "SELECT oid, rolname FROM pg_catalog.pg_roles ORDER BY 1";
   10277             : 
   10278         356 :     res = ExecuteSqlQuery(fout, query, PGRES_TUPLES_OK);
   10279             : 
   10280         356 :     nrolenames = PQntuples(res);
   10281             : 
   10282         356 :     rolenames = (RoleNameItem *) pg_malloc(nrolenames * sizeof(RoleNameItem));
   10283             : 
   10284        6832 :     for (i = 0; i < nrolenames; i++)
   10285             :     {
   10286        6476 :         rolenames[i].roleoid = atooid(PQgetvalue(res, i, 0));
   10287        6476 :         rolenames[i].rolename = pg_strdup(PQgetvalue(res, i, 1));
   10288             :     }
   10289             : 
   10290         356 :     PQclear(res);
   10291         356 : }
   10292             : 
   10293             : /*
   10294             :  * getAdditionalACLs
   10295             :  *
   10296             :  * We have now created all the DumpableObjects, and collected the ACL data
   10297             :  * that appears in the directly-associated catalog entries.  However, there's
   10298             :  * more ACL-related info to collect.  If any of a table's columns have ACLs,
   10299             :  * we must set the TableInfo's DUMP_COMPONENT_ACL components flag, as well as
   10300             :  * its hascolumnACLs flag (we won't store the ACLs themselves here, though).
   10301             :  * Also, in versions having the pg_init_privs catalog, read that and load the
   10302             :  * information into the relevant DumpableObjects.
   10303             :  */
   10304             : static void
   10305         350 : getAdditionalACLs(Archive *fout)
   10306             : {
   10307         350 :     PQExpBuffer query = createPQExpBuffer();
   10308             :     PGresult   *res;
   10309             :     int         ntups,
   10310             :                 i;
   10311             : 
   10312             :     /* Check for per-column ACLs */
   10313         350 :     appendPQExpBufferStr(query,
   10314             :                          "SELECT DISTINCT attrelid FROM pg_attribute "
   10315             :                          "WHERE attacl IS NOT NULL");
   10316             : 
   10317         350 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   10318             : 
   10319         350 :     ntups = PQntuples(res);
   10320        1064 :     for (i = 0; i < ntups; i++)
   10321             :     {
   10322         714 :         Oid         relid = atooid(PQgetvalue(res, i, 0));
   10323             :         TableInfo  *tblinfo;
   10324             : 
   10325         714 :         tblinfo = findTableByOid(relid);
   10326             :         /* OK to ignore tables we haven't got a DumpableObject for */
   10327         714 :         if (tblinfo)
   10328             :         {
   10329         714 :             tblinfo->dobj.components |= DUMP_COMPONENT_ACL;
   10330         714 :             tblinfo->hascolumnACLs = true;
   10331             :         }
   10332             :     }
   10333         350 :     PQclear(res);
   10334             : 
   10335             :     /* Fetch initial-privileges data */
   10336         350 :     if (fout->remoteVersion >= 90600)
   10337             :     {
   10338         350 :         printfPQExpBuffer(query,
   10339             :                           "SELECT objoid, classoid, objsubid, privtype, initprivs "
   10340             :                           "FROM pg_init_privs");
   10341             : 
   10342         350 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   10343             : 
   10344         350 :         ntups = PQntuples(res);
   10345       79716 :         for (i = 0; i < ntups; i++)
   10346             :         {
   10347       79366 :             Oid         objoid = atooid(PQgetvalue(res, i, 0));
   10348       79366 :             Oid         classoid = atooid(PQgetvalue(res, i, 1));
   10349       79366 :             int         objsubid = atoi(PQgetvalue(res, i, 2));
   10350       79366 :             char        privtype = *(PQgetvalue(res, i, 3));
   10351       79366 :             char       *initprivs = PQgetvalue(res, i, 4);
   10352             :             CatalogId   objId;
   10353             :             DumpableObject *dobj;
   10354             : 
   10355       79366 :             objId.tableoid = classoid;
   10356       79366 :             objId.oid = objoid;
   10357       79366 :             dobj = findObjectByCatalogId(objId);
   10358             :             /* OK to ignore entries we haven't got a DumpableObject for */
   10359       79366 :             if (dobj)
   10360             :             {
   10361             :                 /* Cope with sub-object initprivs */
   10362       57062 :                 if (objsubid != 0)
   10363             :                 {
   10364        5998 :                     if (dobj->objType == DO_TABLE)
   10365             :                     {
   10366             :                         /* For a column initprivs, set the table's ACL flags */
   10367        5998 :                         dobj->components |= DUMP_COMPONENT_ACL;
   10368        5998 :                         ((TableInfo *) dobj)->hascolumnACLs = true;
   10369             :                     }
   10370             :                     else
   10371           0 :                         pg_log_warning("unsupported pg_init_privs entry: %u %u %d",
   10372             :                                        classoid, objoid, objsubid);
   10373        6340 :                     continue;
   10374             :                 }
   10375             : 
   10376             :                 /*
   10377             :                  * We ignore any pg_init_privs.initprivs entry for the public
   10378             :                  * schema, as explained in getNamespaces().
   10379             :                  */
   10380       51064 :                 if (dobj->objType == DO_NAMESPACE &&
   10381         692 :                     strcmp(dobj->name, "public") == 0)
   10382         342 :                     continue;
   10383             : 
   10384             :                 /* Else it had better be of a type we think has ACLs */
   10385       50722 :                 if (dobj->objType == DO_NAMESPACE ||
   10386       50372 :                     dobj->objType == DO_TYPE ||
   10387       50324 :                     dobj->objType == DO_FUNC ||
   10388       50132 :                     dobj->objType == DO_AGG ||
   10389       50084 :                     dobj->objType == DO_TABLE ||
   10390           0 :                     dobj->objType == DO_PROCLANG ||
   10391           0 :                     dobj->objType == DO_FDW ||
   10392           0 :                     dobj->objType == DO_FOREIGN_SERVER)
   10393       50722 :                 {
   10394       50722 :                     DumpableObjectWithAcl *daobj = (DumpableObjectWithAcl *) dobj;
   10395             : 
   10396       50722 :                     daobj->dacl.privtype = privtype;
   10397       50722 :                     daobj->dacl.initprivs = pstrdup(initprivs);
   10398             :                 }
   10399             :                 else
   10400           0 :                     pg_log_warning("unsupported pg_init_privs entry: %u %u %d",
   10401             :                                    classoid, objoid, objsubid);
   10402             :             }
   10403             :         }
   10404         350 :         PQclear(res);
   10405             :     }
   10406             : 
   10407         350 :     destroyPQExpBuffer(query);
   10408         350 : }
   10409             : 
   10410             : /*
   10411             :  * dumpCommentExtended --
   10412             :  *
   10413             :  * This routine is used to dump any comments associated with the
   10414             :  * object handed to this routine. The routine takes the object type
   10415             :  * and object name (ready to print, except for schema decoration), plus
   10416             :  * the namespace and owner of the object (for labeling the ArchiveEntry),
   10417             :  * plus catalog ID and subid which are the lookup key for pg_description,
   10418             :  * plus the dump ID for the object (for setting a dependency).
   10419             :  * If a matching pg_description entry is found, it is dumped.
   10420             :  *
   10421             :  * Note: in some cases, such as comments for triggers and rules, the "type"
   10422             :  * string really looks like, e.g., "TRIGGER name ON".  This is a bit of a hack
   10423             :  * but it doesn't seem worth complicating the API for all callers to make
   10424             :  * it cleaner.
   10425             :  *
   10426             :  * Note: although this routine takes a dumpId for dependency purposes,
   10427             :  * that purpose is just to mark the dependency in the emitted dump file
   10428             :  * for possible future use by pg_restore.  We do NOT use it for determining
   10429             :  * ordering of the comment in the dump file, because this routine is called
   10430             :  * after dependency sorting occurs.  This routine should be called just after
   10431             :  * calling ArchiveEntry() for the specified object.
   10432             :  */
   10433             : static void
   10434       12694 : dumpCommentExtended(Archive *fout, const char *type,
   10435             :                     const char *name, const char *namespace,
   10436             :                     const char *owner, CatalogId catalogId,
   10437             :                     int subid, DumpId dumpId,
   10438             :                     const char *initdb_comment)
   10439             : {
   10440       12694 :     DumpOptions *dopt = fout->dopt;
   10441             :     CommentItem *comments;
   10442             :     int         ncomments;
   10443             : 
   10444             :     /* do nothing, if --no-comments is supplied */
   10445       12694 :     if (dopt->no_comments)
   10446           0 :         return;
   10447             : 
   10448             :     /* Comments are schema not data ... except LO comments are data */
   10449       12694 :     if (strcmp(type, "LARGE OBJECT") != 0)
   10450             :     {
   10451       12590 :         if (!dopt->dumpSchema)
   10452           0 :             return;
   10453             :     }
   10454             :     else
   10455             :     {
   10456             :         /* We do dump LO comments in binary-upgrade mode */
   10457         104 :         if (!dopt->dumpData && !dopt->binary_upgrade)
   10458           0 :             return;
   10459             :     }
   10460             : 
   10461             :     /* Search for comments associated with catalogId, using table */
   10462       12694 :     ncomments = findComments(catalogId.tableoid, catalogId.oid,
   10463             :                              &comments);
   10464             : 
   10465             :     /* Is there one matching the subid? */
   10466       12694 :     while (ncomments > 0)
   10467             :     {
   10468       12604 :         if (comments->objsubid == subid)
   10469       12604 :             break;
   10470           0 :         comments++;
   10471           0 :         ncomments--;
   10472             :     }
   10473             : 
   10474       12694 :     if (initdb_comment != NULL)
   10475             :     {
   10476             :         static CommentItem empty_comment = {.descr = ""};
   10477             : 
   10478             :         /*
   10479             :          * initdb creates this object with a comment.  Skip dumping the
   10480             :          * initdb-provided comment, which would complicate matters for
   10481             :          * non-superuser use of pg_dump.  When the DBA has removed initdb's
   10482             :          * comment, replicate that.
   10483             :          */
   10484         226 :         if (ncomments == 0)
   10485             :         {
   10486           8 :             comments = &empty_comment;
   10487           8 :             ncomments = 1;
   10488             :         }
   10489         218 :         else if (strcmp(comments->descr, initdb_comment) == 0)
   10490         218 :             ncomments = 0;
   10491             :     }
   10492             : 
   10493             :     /* If a comment exists, build COMMENT ON statement */
   10494       12694 :     if (ncomments > 0)
   10495             :     {
   10496       12394 :         PQExpBuffer query = createPQExpBuffer();
   10497       12394 :         PQExpBuffer tag = createPQExpBuffer();
   10498             : 
   10499       12394 :         appendPQExpBuffer(query, "COMMENT ON %s ", type);
   10500       12394 :         if (namespace && *namespace)
   10501       12048 :             appendPQExpBuffer(query, "%s.", fmtId(namespace));
   10502       12394 :         appendPQExpBuffer(query, "%s IS ", name);
   10503       12394 :         appendStringLiteralAH(query, comments->descr, fout);
   10504       12394 :         appendPQExpBufferStr(query, ";\n");
   10505             : 
   10506       12394 :         appendPQExpBuffer(tag, "%s %s", type, name);
   10507             : 
   10508             :         /*
   10509             :          * We mark comments as SECTION_NONE because they really belong in the
   10510             :          * same section as their parent, whether that is pre-data or
   10511             :          * post-data.
   10512             :          */
   10513       12394 :         ArchiveEntry(fout, nilCatalogId, createDumpId(),
   10514       12394 :                      ARCHIVE_OPTS(.tag = tag->data,
   10515             :                                   .namespace = namespace,
   10516             :                                   .owner = owner,
   10517             :                                   .description = "COMMENT",
   10518             :                                   .section = SECTION_NONE,
   10519             :                                   .createStmt = query->data,
   10520             :                                   .deps = &dumpId,
   10521             :                                   .nDeps = 1));
   10522             : 
   10523       12394 :         destroyPQExpBuffer(query);
   10524       12394 :         destroyPQExpBuffer(tag);
   10525             :     }
   10526             : }
   10527             : 
   10528             : /*
   10529             :  * dumpComment --
   10530             :  *
   10531             :  * Typical simplification of the above function.
   10532             :  */
   10533             : static inline void
   10534       12400 : dumpComment(Archive *fout, const char *type,
   10535             :             const char *name, const char *namespace,
   10536             :             const char *owner, CatalogId catalogId,
   10537             :             int subid, DumpId dumpId)
   10538             : {
   10539       12400 :     dumpCommentExtended(fout, type, name, namespace, owner,
   10540             :                         catalogId, subid, dumpId, NULL);
   10541       12400 : }
   10542             : 
   10543             : /*
   10544             :  * appendNamedArgument --
   10545             :  *
   10546             :  * Convenience routine for constructing parameters of the form:
   10547             :  * 'paraname', 'value'::type
   10548             :  */
   10549             : static void
   10550       41356 : appendNamedArgument(PQExpBuffer out, Archive *fout, const char *argname,
   10551             :                     const char *argtype, const char *argval)
   10552             : {
   10553       41356 :     appendPQExpBufferStr(out, ",\n\t");
   10554             : 
   10555       41356 :     appendStringLiteralAH(out, argname, fout);
   10556       41356 :     appendPQExpBufferStr(out, ", ");
   10557             : 
   10558       41356 :     appendStringLiteralAH(out, argval, fout);
   10559       41356 :     appendPQExpBuffer(out, "::%s", argtype);
   10560       41356 : }
   10561             : 
   10562             : /*
   10563             :  * dumpRelationStats --
   10564             :  *
   10565             :  * Dump command to import stats into the relation on the new database.
   10566             :  */
   10567             : static void
   10568       12188 : dumpRelationStats(Archive *fout, const RelStatsInfo *rsinfo)
   10569             : {
   10570       12188 :     const DumpableObject *dobj = &rsinfo->dobj;
   10571             :     PGresult   *res;
   10572             :     PQExpBuffer query;
   10573             :     PQExpBuffer out;
   10574             :     int         i_attname;
   10575             :     int         i_inherited;
   10576             :     int         i_null_frac;
   10577             :     int         i_avg_width;
   10578             :     int         i_n_distinct;
   10579             :     int         i_most_common_vals;
   10580             :     int         i_most_common_freqs;
   10581             :     int         i_histogram_bounds;
   10582             :     int         i_correlation;
   10583             :     int         i_most_common_elems;
   10584             :     int         i_most_common_elem_freqs;
   10585             :     int         i_elem_count_histogram;
   10586             :     int         i_range_length_histogram;
   10587             :     int         i_range_empty_frac;
   10588             :     int         i_range_bounds_histogram;
   10589             : 
   10590             :     /* nothing to do if we are not dumping statistics */
   10591       12188 :     if (!fout->dopt->dumpStatistics)
   10592           0 :         return;
   10593             : 
   10594       12188 :     query = createPQExpBuffer();
   10595       12188 :     if (!fout->is_prepared[PREPQUERY_GETATTRIBUTESTATS])
   10596             :     {
   10597         206 :         appendPQExpBufferStr(query,
   10598             :                              "PREPARE getAttributeStats(pg_catalog.name, pg_catalog.name) AS\n"
   10599             :                              "SELECT s.attname, s.inherited, "
   10600             :                              "s.null_frac, s.avg_width, s.n_distinct, "
   10601             :                              "s.most_common_vals, s.most_common_freqs, "
   10602             :                              "s.histogram_bounds, s.correlation, "
   10603             :                              "s.most_common_elems, s.most_common_elem_freqs, "
   10604             :                              "s.elem_count_histogram, ");
   10605             : 
   10606         206 :         if (fout->remoteVersion >= 170000)
   10607         206 :             appendPQExpBufferStr(query,
   10608             :                                  "s.range_length_histogram, "
   10609             :                                  "s.range_empty_frac, "
   10610             :                                  "s.range_bounds_histogram ");
   10611             :         else
   10612           0 :             appendPQExpBufferStr(query,
   10613             :                                  "NULL AS range_length_histogram,"
   10614             :                                  "NULL AS range_empty_frac,"
   10615             :                                  "NULL AS range_bounds_histogram ");
   10616             : 
   10617         206 :         appendPQExpBufferStr(query,
   10618             :                              "FROM pg_catalog.pg_stats s "
   10619             :                              "WHERE s.schemaname = $1 "
   10620             :                              "AND s.tablename = $2 "
   10621             :                              "ORDER BY s.attname, s.inherited");
   10622             : 
   10623         206 :         ExecuteSqlStatement(fout, query->data);
   10624             : 
   10625         206 :         fout->is_prepared[PREPQUERY_GETATTRIBUTESTATS] = true;
   10626         206 :         resetPQExpBuffer(query);
   10627             :     }
   10628             : 
   10629       12188 :     out = createPQExpBuffer();
   10630             : 
   10631             :     /* restore relation stats */
   10632       12188 :     appendPQExpBufferStr(out, "SELECT * FROM pg_catalog.pg_restore_relation_stats(\n");
   10633       12188 :     appendPQExpBuffer(out, "\t'version', '%u'::integer,\n",
   10634             :                       fout->remoteVersion);
   10635       12188 :     appendPQExpBufferStr(out, "\t'schemaname', ");
   10636       12188 :     appendStringLiteralAH(out, rsinfo->dobj.namespace->dobj.name, fout);
   10637       12188 :     appendPQExpBufferStr(out, ",\n");
   10638       12188 :     appendPQExpBufferStr(out, "\t'relname', ");
   10639       12188 :     appendStringLiteralAH(out, rsinfo->dobj.name, fout);
   10640       12188 :     appendPQExpBufferStr(out, ",\n");
   10641       12188 :     appendPQExpBuffer(out, "\t'relpages', '%d'::integer,\n", rsinfo->relpages);
   10642       12188 :     appendPQExpBuffer(out, "\t'reltuples', '%s'::real,\n", rsinfo->reltuples);
   10643       12188 :     appendPQExpBuffer(out, "\t'relallvisible', '%d'::integer",
   10644             :                       rsinfo->relallvisible);
   10645             : 
   10646       12188 :     if (fout->remoteVersion >= 180000)
   10647       12188 :         appendPQExpBuffer(out, ",\n\t'relallfrozen', '%d'::integer", rsinfo->relallfrozen);
   10648             : 
   10649       12188 :     appendPQExpBufferStr(out, "\n);\n");
   10650             : 
   10651             : 
   10652             :     /* fetch attribute stats */
   10653       12188 :     appendPQExpBufferStr(query, "EXECUTE getAttributeStats(");
   10654       12188 :     appendStringLiteralAH(query, dobj->namespace->dobj.name, fout);
   10655       12188 :     appendPQExpBufferStr(query, ", ");
   10656       12188 :     appendStringLiteralAH(query, dobj->name, fout);
   10657       12188 :     appendPQExpBufferStr(query, ");");
   10658             : 
   10659       12188 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   10660             : 
   10661       12188 :     i_attname = PQfnumber(res, "attname");
   10662       12188 :     i_inherited = PQfnumber(res, "inherited");
   10663       12188 :     i_null_frac = PQfnumber(res, "null_frac");
   10664       12188 :     i_avg_width = PQfnumber(res, "avg_width");
   10665       12188 :     i_n_distinct = PQfnumber(res, "n_distinct");
   10666       12188 :     i_most_common_vals = PQfnumber(res, "most_common_vals");
   10667       12188 :     i_most_common_freqs = PQfnumber(res, "most_common_freqs");
   10668       12188 :     i_histogram_bounds = PQfnumber(res, "histogram_bounds");
   10669       12188 :     i_correlation = PQfnumber(res, "correlation");
   10670       12188 :     i_most_common_elems = PQfnumber(res, "most_common_elems");
   10671       12188 :     i_most_common_elem_freqs = PQfnumber(res, "most_common_elem_freqs");
   10672       12188 :     i_elem_count_histogram = PQfnumber(res, "elem_count_histogram");
   10673       12188 :     i_range_length_histogram = PQfnumber(res, "range_length_histogram");
   10674       12188 :     i_range_empty_frac = PQfnumber(res, "range_empty_frac");
   10675       12188 :     i_range_bounds_histogram = PQfnumber(res, "range_bounds_histogram");
   10676             : 
   10677             :     /* restore attribute stats */
   10678       18456 :     for (int rownum = 0; rownum < PQntuples(res); rownum++)
   10679             :     {
   10680             :         const char *attname;
   10681             : 
   10682        6268 :         appendPQExpBufferStr(out, "SELECT * FROM pg_catalog.pg_restore_attribute_stats(\n");
   10683        6268 :         appendPQExpBuffer(out, "\t'version', '%u'::integer,\n",
   10684             :                           fout->remoteVersion);
   10685        6268 :         appendPQExpBufferStr(out, "\t'schemaname', ");
   10686        6268 :         appendStringLiteralAH(out, rsinfo->dobj.namespace->dobj.name, fout);
   10687        6268 :         appendPQExpBufferStr(out, ",\n\t'relname', ");
   10688        6268 :         appendStringLiteralAH(out, rsinfo->dobj.name, fout);
   10689             : 
   10690        6268 :         if (PQgetisnull(res, rownum, i_attname))
   10691           0 :             pg_fatal("attname cannot be NULL");
   10692        6268 :         attname = PQgetvalue(res, rownum, i_attname);
   10693             : 
   10694             :         /*
   10695             :          * Indexes look up attname in indAttNames to derive attnum, all others
   10696             :          * use attname directly.  We must specify attnum for indexes, since
   10697             :          * their attnames are not necessarily stable across dump/reload.
   10698             :          */
   10699        6268 :         if (rsinfo->nindAttNames == 0)
   10700             :         {
   10701        6170 :             appendPQExpBuffer(out, ",\n\t'attname', ");
   10702        6170 :             appendStringLiteralAH(out, attname, fout);
   10703             :         }
   10704             :         else
   10705             :         {
   10706          98 :             bool        found = false;
   10707             : 
   10708         172 :             for (int i = 0; i < rsinfo->nindAttNames; i++)
   10709             :             {
   10710         172 :                 if (strcmp(attname, rsinfo->indAttNames[i]) == 0)
   10711             :                 {
   10712          98 :                     appendPQExpBuffer(out, ",\n\t'attnum', '%d'::smallint",
   10713             :                                       i + 1);
   10714          98 :                     found = true;
   10715          98 :                     break;
   10716             :                 }
   10717             :             }
   10718             : 
   10719          98 :             if (!found)
   10720           0 :                 pg_fatal("could not find index attname \"%s\"", attname);
   10721             :         }
   10722             : 
   10723        6268 :         if (!PQgetisnull(res, rownum, i_inherited))
   10724        6268 :             appendNamedArgument(out, fout, "inherited", "boolean",
   10725        6268 :                                 PQgetvalue(res, rownum, i_inherited));
   10726        6268 :         if (!PQgetisnull(res, rownum, i_null_frac))
   10727        6268 :             appendNamedArgument(out, fout, "null_frac", "real",
   10728        6268 :                                 PQgetvalue(res, rownum, i_null_frac));
   10729        6268 :         if (!PQgetisnull(res, rownum, i_avg_width))
   10730        6268 :             appendNamedArgument(out, fout, "avg_width", "integer",
   10731        6268 :                                 PQgetvalue(res, rownum, i_avg_width));
   10732        6268 :         if (!PQgetisnull(res, rownum, i_n_distinct))
   10733        6268 :             appendNamedArgument(out, fout, "n_distinct", "real",
   10734        6268 :                                 PQgetvalue(res, rownum, i_n_distinct));
   10735        6268 :         if (!PQgetisnull(res, rownum, i_most_common_vals))
   10736        3698 :             appendNamedArgument(out, fout, "most_common_vals", "text",
   10737        3698 :                                 PQgetvalue(res, rownum, i_most_common_vals));
   10738        6268 :         if (!PQgetisnull(res, rownum, i_most_common_freqs))
   10739        3698 :             appendNamedArgument(out, fout, "most_common_freqs", "real[]",
   10740        3698 :                                 PQgetvalue(res, rownum, i_most_common_freqs));
   10741        6268 :         if (!PQgetisnull(res, rownum, i_histogram_bounds))
   10742        2944 :             appendNamedArgument(out, fout, "histogram_bounds", "text",
   10743        2944 :                                 PQgetvalue(res, rownum, i_histogram_bounds));
   10744        6268 :         if (!PQgetisnull(res, rownum, i_correlation))
   10745        5662 :             appendNamedArgument(out, fout, "correlation", "real",
   10746        5662 :                                 PQgetvalue(res, rownum, i_correlation));
   10747        6268 :         if (!PQgetisnull(res, rownum, i_most_common_elems))
   10748          78 :             appendNamedArgument(out, fout, "most_common_elems", "text",
   10749          78 :                                 PQgetvalue(res, rownum, i_most_common_elems));
   10750        6268 :         if (!PQgetisnull(res, rownum, i_most_common_elem_freqs))
   10751          78 :             appendNamedArgument(out, fout, "most_common_elem_freqs", "real[]",
   10752          78 :                                 PQgetvalue(res, rownum, i_most_common_elem_freqs));
   10753        6268 :         if (!PQgetisnull(res, rownum, i_elem_count_histogram))
   10754          72 :             appendNamedArgument(out, fout, "elem_count_histogram", "real[]",
   10755          72 :                                 PQgetvalue(res, rownum, i_elem_count_histogram));
   10756        6268 :         if (fout->remoteVersion >= 170000)
   10757             :         {
   10758        6268 :             if (!PQgetisnull(res, rownum, i_range_length_histogram))
   10759          18 :                 appendNamedArgument(out, fout, "range_length_histogram", "text",
   10760          18 :                                     PQgetvalue(res, rownum, i_range_length_histogram));
   10761        6268 :             if (!PQgetisnull(res, rownum, i_range_empty_frac))
   10762          18 :                 appendNamedArgument(out, fout, "range_empty_frac", "real",
   10763          18 :                                     PQgetvalue(res, rownum, i_range_empty_frac));
   10764        6268 :             if (!PQgetisnull(res, rownum, i_range_bounds_histogram))
   10765          18 :                 appendNamedArgument(out, fout, "range_bounds_histogram", "text",
   10766          18 :                                     PQgetvalue(res, rownum, i_range_bounds_histogram));
   10767             :         }
   10768        6268 :         appendPQExpBufferStr(out, "\n);\n");
   10769             :     }
   10770             : 
   10771       12188 :     PQclear(res);
   10772             : 
   10773       12188 :     ArchiveEntry(fout, nilCatalogId, createDumpId(),
   10774       12188 :                  ARCHIVE_OPTS(.tag = dobj->name,
   10775             :                               .namespace = dobj->namespace->dobj.name,
   10776             :                               .description = "STATISTICS DATA",
   10777             :                               .section = rsinfo->section,
   10778             :                               .createStmt = out->data,
   10779             :                               .deps = dobj->dependencies,
   10780             :                               .nDeps = dobj->nDeps));
   10781             : 
   10782       12188 :     destroyPQExpBuffer(out);
   10783       12188 :     destroyPQExpBuffer(query);
   10784             : }
   10785             : 
   10786             : /*
   10787             :  * dumpTableComment --
   10788             :  *
   10789             :  * As above, but dump comments for both the specified table (or view)
   10790             :  * and its columns.
   10791             :  */
   10792             : static void
   10793         164 : dumpTableComment(Archive *fout, const TableInfo *tbinfo,
   10794             :                  const char *reltypename)
   10795             : {
   10796         164 :     DumpOptions *dopt = fout->dopt;
   10797             :     CommentItem *comments;
   10798             :     int         ncomments;
   10799             :     PQExpBuffer query;
   10800             :     PQExpBuffer tag;
   10801             : 
   10802             :     /* do nothing, if --no-comments is supplied */
   10803         164 :     if (dopt->no_comments)
   10804           0 :         return;
   10805             : 
   10806             :     /* Comments are SCHEMA not data */
   10807         164 :     if (!dopt->dumpSchema)
   10808           0 :         return;
   10809             : 
   10810             :     /* Search for comments associated with relation, using table */
   10811         164 :     ncomments = findComments(tbinfo->dobj.catId.tableoid,
   10812             :                              tbinfo->dobj.catId.oid,
   10813             :                              &comments);
   10814             : 
   10815             :     /* If comments exist, build COMMENT ON statements */
   10816         164 :     if (ncomments <= 0)
   10817           0 :         return;
   10818             : 
   10819         164 :     query = createPQExpBuffer();
   10820         164 :     tag = createPQExpBuffer();
   10821             : 
   10822         472 :     while (ncomments > 0)
   10823             :     {
   10824         308 :         const char *descr = comments->descr;
   10825         308 :         int         objsubid = comments->objsubid;
   10826             : 
   10827         308 :         if (objsubid == 0)
   10828             :         {
   10829          72 :             resetPQExpBuffer(tag);
   10830          72 :             appendPQExpBuffer(tag, "%s %s", reltypename,
   10831          72 :                               fmtId(tbinfo->dobj.name));
   10832             : 
   10833          72 :             resetPQExpBuffer(query);
   10834          72 :             appendPQExpBuffer(query, "COMMENT ON %s %s IS ", reltypename,
   10835          72 :                               fmtQualifiedDumpable(tbinfo));
   10836          72 :             appendStringLiteralAH(query, descr, fout);
   10837          72 :             appendPQExpBufferStr(query, ";\n");
   10838             : 
   10839          72 :             ArchiveEntry(fout, nilCatalogId, createDumpId(),
   10840          72 :                          ARCHIVE_OPTS(.tag = tag->data,
   10841             :                                       .namespace = tbinfo->dobj.namespace->dobj.name,
   10842             :                                       .owner = tbinfo->rolname,
   10843             :                                       .description = "COMMENT",
   10844             :                                       .section = SECTION_NONE,
   10845             :                                       .createStmt = query->data,
   10846             :                                       .deps = &(tbinfo->dobj.dumpId),
   10847             :                                       .nDeps = 1));
   10848             :         }
   10849         236 :         else if (objsubid > 0 && objsubid <= tbinfo->numatts)
   10850             :         {
   10851         236 :             resetPQExpBuffer(tag);
   10852         236 :             appendPQExpBuffer(tag, "COLUMN %s.",
   10853         236 :                               fmtId(tbinfo->dobj.name));
   10854         236 :             appendPQExpBufferStr(tag, fmtId(tbinfo->attnames[objsubid - 1]));
   10855             : 
   10856         236 :             resetPQExpBuffer(query);
   10857         236 :             appendPQExpBuffer(query, "COMMENT ON COLUMN %s.",
   10858         236 :                               fmtQualifiedDumpable(tbinfo));
   10859         236 :             appendPQExpBuffer(query, "%s IS ",
   10860         236 :                               fmtId(tbinfo->attnames[objsubid - 1]));
   10861         236 :             appendStringLiteralAH(query, descr, fout);
   10862         236 :             appendPQExpBufferStr(query, ";\n");
   10863             : 
   10864         236 :             ArchiveEntry(fout, nilCatalogId, createDumpId(),
   10865         236 :                          ARCHIVE_OPTS(.tag = tag->data,
   10866             :                                       .namespace = tbinfo->dobj.namespace->dobj.name,
   10867             :                                       .owner = tbinfo->rolname,
   10868             :                                       .description = "COMMENT",
   10869             :                                       .section = SECTION_NONE,
   10870             :                                       .createStmt = query->data,
   10871             :                                       .deps = &(tbinfo->dobj.dumpId),
   10872             :                                       .nDeps = 1));
   10873             :         }
   10874             : 
   10875         308 :         comments++;
   10876         308 :         ncomments--;
   10877             :     }
   10878             : 
   10879         164 :     destroyPQExpBuffer(query);
   10880         164 :     destroyPQExpBuffer(tag);
   10881             : }
   10882             : 
   10883             : /*
   10884             :  * findComments --
   10885             :  *
   10886             :  * Find the comment(s), if any, associated with the given object.  All the
   10887             :  * objsubid values associated with the given classoid/objoid are found with
   10888             :  * one search.
   10889             :  */
   10890             : static int
   10891       12930 : findComments(Oid classoid, Oid objoid, CommentItem **items)
   10892             : {
   10893       12930 :     CommentItem *middle = NULL;
   10894             :     CommentItem *low;
   10895             :     CommentItem *high;
   10896             :     int         nmatch;
   10897             : 
   10898             :     /*
   10899             :      * Do binary search to find some item matching the object.
   10900             :      */
   10901       12930 :     low = &comments[0];
   10902       12930 :     high = &comments[ncomments - 1];
   10903      128348 :     while (low <= high)
   10904             :     {
   10905      128258 :         middle = low + (high - low) / 2;
   10906             : 
   10907      128258 :         if (classoid < middle->classoid)
   10908       13692 :             high = middle - 1;
   10909      114566 :         else if (classoid > middle->classoid)
   10910       14368 :             low = middle + 1;
   10911      100198 :         else if (objoid < middle->objoid)
   10912       42212 :             high = middle - 1;
   10913       57986 :         else if (objoid > middle->objoid)
   10914       45146 :             low = middle + 1;
   10915             :         else
   10916       12840 :             break;              /* found a match */
   10917             :     }
   10918             : 
   10919       12930 :     if (low > high)              /* no matches */
   10920             :     {
   10921          90 :         *items = NULL;
   10922          90 :         return 0;
   10923             :     }
   10924             : 
   10925             :     /*
   10926             :      * Now determine how many items match the object.  The search loop
   10927             :      * invariant still holds: only items between low and high inclusive could
   10928             :      * match.
   10929             :      */
   10930       12840 :     nmatch = 1;
   10931       12840 :     while (middle > low)
   10932             :     {
   10933        6144 :         if (classoid != middle[-1].classoid ||
   10934        5906 :             objoid != middle[-1].objoid)
   10935             :             break;
   10936           0 :         middle--;
   10937           0 :         nmatch++;
   10938             :     }
   10939             : 
   10940       12840 :     *items = middle;
   10941             : 
   10942       12840 :     middle += nmatch;
   10943       12984 :     while (middle <= high)
   10944             :     {
   10945        7058 :         if (classoid != middle->classoid ||
   10946        6282 :             objoid != middle->objoid)
   10947             :             break;
   10948         144 :         middle++;
   10949         144 :         nmatch++;
   10950             :     }
   10951             : 
   10952       12840 :     return nmatch;
   10953             : }
   10954             : 
   10955             : /*
   10956             :  * collectComments --
   10957             :  *
   10958             :  * Construct a table of all comments available for database objects;
   10959             :  * also set the has-comment component flag for each relevant object.
   10960             :  *
   10961             :  * We used to do per-object queries for the comments, but it's much faster
   10962             :  * to pull them all over at once, and on most databases the memory cost
   10963             :  * isn't high.
   10964             :  *
   10965             :  * The table is sorted by classoid/objid/objsubid for speed in lookup.
   10966             :  */
   10967             : static void
   10968         354 : collectComments(Archive *fout)
   10969             : {
   10970             :     PGresult   *res;
   10971             :     PQExpBuffer query;
   10972             :     int         i_description;
   10973             :     int         i_classoid;
   10974             :     int         i_objoid;
   10975             :     int         i_objsubid;
   10976             :     int         ntups;
   10977             :     int         i;
   10978             :     DumpableObject *dobj;
   10979             : 
   10980         354 :     query = createPQExpBuffer();
   10981             : 
   10982         354 :     appendPQExpBufferStr(query, "SELECT description, classoid, objoid, objsubid "
   10983             :                          "FROM pg_catalog.pg_description "
   10984             :                          "ORDER BY classoid, objoid, objsubid");
   10985             : 
   10986         354 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   10987             : 
   10988             :     /* Construct lookup table containing OIDs in numeric form */
   10989             : 
   10990         354 :     i_description = PQfnumber(res, "description");
   10991         354 :     i_classoid = PQfnumber(res, "classoid");
   10992         354 :     i_objoid = PQfnumber(res, "objoid");
   10993         354 :     i_objsubid = PQfnumber(res, "objsubid");
   10994             : 
   10995         354 :     ntups = PQntuples(res);
   10996             : 
   10997         354 :     comments = (CommentItem *) pg_malloc(ntups * sizeof(CommentItem));
   10998         354 :     ncomments = 0;
   10999         354 :     dobj = NULL;
   11000             : 
   11001     1869890 :     for (i = 0; i < ntups; i++)
   11002             :     {
   11003             :         CatalogId   objId;
   11004             :         int         subid;
   11005             : 
   11006     1869536 :         objId.tableoid = atooid(PQgetvalue(res, i, i_classoid));
   11007     1869536 :         objId.oid = atooid(PQgetvalue(res, i, i_objoid));
   11008     1869536 :         subid = atoi(PQgetvalue(res, i, i_objsubid));
   11009             : 
   11010             :         /* We needn't remember comments that don't match any dumpable object */
   11011     1869536 :         if (dobj == NULL ||
   11012      671654 :             dobj->catId.tableoid != objId.tableoid ||
   11013      667256 :             dobj->catId.oid != objId.oid)
   11014     1869340 :             dobj = findObjectByCatalogId(objId);
   11015     1869536 :         if (dobj == NULL)
   11016     1197540 :             continue;
   11017             : 
   11018             :         /*
   11019             :          * Comments on columns of composite types are linked to the type's
   11020             :          * pg_class entry, but we need to set the DUMP_COMPONENT_COMMENT flag
   11021             :          * in the type's own DumpableObject.
   11022             :          */
   11023      671996 :         if (subid != 0 && dobj->objType == DO_TABLE &&
   11024         420 :             ((TableInfo *) dobj)->relkind == RELKIND_COMPOSITE_TYPE)
   11025          98 :         {
   11026             :             TypeInfo   *cTypeInfo;
   11027             : 
   11028          98 :             cTypeInfo = findTypeByOid(((TableInfo *) dobj)->reltype);
   11029          98 :             if (cTypeInfo)
   11030          98 :                 cTypeInfo->dobj.components |= DUMP_COMPONENT_COMMENT;
   11031             :         }
   11032             :         else
   11033      671898 :             dobj->components |= DUMP_COMPONENT_COMMENT;
   11034             : 
   11035      671996 :         comments[ncomments].descr = pg_strdup(PQgetvalue(res, i, i_description));
   11036      671996 :         comments[ncomments].classoid = objId.tableoid;
   11037      671996 :         comments[ncomments].objoid = objId.oid;
   11038      671996 :         comments[ncomments].objsubid = subid;
   11039      671996 :         ncomments++;
   11040             :     }
   11041             : 
   11042         354 :     PQclear(res);
   11043         354 :     destroyPQExpBuffer(query);
   11044         354 : }
   11045             : 
   11046             : /*
   11047             :  * dumpDumpableObject
   11048             :  *
   11049             :  * This routine and its subsidiaries are responsible for creating
   11050             :  * ArchiveEntries (TOC objects) for each object to be dumped.
   11051             :  */
   11052             : static void
   11053     1304936 : dumpDumpableObject(Archive *fout, DumpableObject *dobj)
   11054             : {
   11055             :     /*
   11056             :      * Clear any dump-request bits for components that don't exist for this
   11057             :      * object.  (This makes it safe to initially use DUMP_COMPONENT_ALL as the
   11058             :      * request for every kind of object.)
   11059             :      */
   11060     1304936 :     dobj->dump &= dobj->components;
   11061             : 
   11062             :     /* Now, short-circuit if there's nothing to be done here. */
   11063     1304936 :     if (dobj->dump == 0)
   11064     1152506 :         return;
   11065             : 
   11066      152430 :     switch (dobj->objType)
   11067             :     {
   11068         910 :         case DO_NAMESPACE:
   11069         910 :             dumpNamespace(fout, (const NamespaceInfo *) dobj);
   11070         910 :             break;
   11071          38 :         case DO_EXTENSION:
   11072          38 :             dumpExtension(fout, (const ExtensionInfo *) dobj);
   11073          38 :             break;
   11074        1786 :         case DO_TYPE:
   11075        1786 :             dumpType(fout, (const TypeInfo *) dobj);
   11076        1786 :             break;
   11077         154 :         case DO_SHELL_TYPE:
   11078         154 :             dumpShellType(fout, (const ShellTypeInfo *) dobj);
   11079         154 :             break;
   11080        3746 :         case DO_FUNC:
   11081        3746 :             dumpFunc(fout, (const FuncInfo *) dobj);
   11082        3746 :             break;
   11083         592 :         case DO_AGG:
   11084         592 :             dumpAgg(fout, (const AggInfo *) dobj);
   11085         592 :             break;
   11086        5016 :         case DO_OPERATOR:
   11087        5016 :             dumpOpr(fout, (const OprInfo *) dobj);
   11088        5016 :             break;
   11089         176 :         case DO_ACCESS_METHOD:
   11090         176 :             dumpAccessMethod(fout, (const AccessMethodInfo *) dobj);
   11091         176 :             break;
   11092        1344 :         case DO_OPCLASS:
   11093        1344 :             dumpOpclass(fout, (const OpclassInfo *) dobj);
   11094        1344 :             break;
   11095        1114 :         case DO_OPFAMILY:
   11096        1114 :             dumpOpfamily(fout, (const OpfamilyInfo *) dobj);
   11097        1114 :             break;
   11098        4952 :         case DO_COLLATION:
   11099        4952 :             dumpCollation(fout, (const CollInfo *) dobj);
   11100        4952 :             break;
   11101         852 :         case DO_CONVERSION:
   11102         852 :             dumpConversion(fout, (const ConvInfo *) dobj);
   11103         852 :             break;
   11104       57818 :         case DO_TABLE:
   11105       57818 :             dumpTable(fout, (const TableInfo *) dobj);
   11106       57818 :             break;
   11107        2630 :         case DO_TABLE_ATTACH:
   11108        2630 :             dumpTableAttach(fout, (const TableAttachInfo *) dobj);
   11109        2630 :             break;
   11110        2140 :         case DO_ATTRDEF:
   11111        2140 :             dumpAttrDef(fout, (const AttrDefInfo *) dobj);
   11112        2140 :             break;
   11113        5260 :         case DO_INDEX:
   11114        5260 :             dumpIndex(fout, (const IndxInfo *) dobj);
   11115        5260 :             break;
   11116        1192 :         case DO_INDEX_ATTACH:
   11117        1192 :             dumpIndexAttach(fout, (const IndexAttachInfo *) dobj);
   11118        1192 :             break;
   11119         290 :         case DO_STATSEXT:
   11120         290 :             dumpStatisticsExt(fout, (const StatsExtInfo *) dobj);
   11121         290 :             break;
   11122         804 :         case DO_REFRESH_MATVIEW:
   11123         804 :             refreshMatViewData(fout, (const TableDataInfo *) dobj);
   11124         804 :             break;
   11125        2374 :         case DO_RULE:
   11126        2374 :             dumpRule(fout, (const RuleInfo *) dobj);
   11127        2374 :             break;
   11128        1086 :         case DO_TRIGGER:
   11129        1086 :             dumpTrigger(fout, (const TriggerInfo *) dobj);
   11130        1086 :             break;
   11131          92 :         case DO_EVENT_TRIGGER:
   11132          92 :             dumpEventTrigger(fout, (const EventTriggerInfo *) dobj);
   11133          92 :             break;
   11134        4508 :         case DO_CONSTRAINT:
   11135        4508 :             dumpConstraint(fout, (const ConstraintInfo *) dobj);
   11136        4508 :             break;
   11137         358 :         case DO_FK_CONSTRAINT:
   11138         358 :             dumpConstraint(fout, (const ConstraintInfo *) dobj);
   11139         358 :             break;
   11140         180 :         case DO_PROCLANG:
   11141         180 :             dumpProcLang(fout, (const ProcLangInfo *) dobj);
   11142         180 :             break;
   11143         142 :         case DO_CAST:
   11144         142 :             dumpCast(fout, (const CastInfo *) dobj);
   11145         142 :             break;
   11146          92 :         case DO_TRANSFORM:
   11147          92 :             dumpTransform(fout, (const TransformInfo *) dobj);
   11148          92 :             break;
   11149         804 :         case DO_SEQUENCE_SET:
   11150         804 :             dumpSequenceData(fout, (const TableDataInfo *) dobj);
   11151         804 :             break;
   11152        7914 :         case DO_TABLE_DATA:
   11153        7914 :             dumpTableData(fout, (const TableDataInfo *) dobj);
   11154        7914 :             break;
   11155       27316 :         case DO_DUMMY_TYPE:
   11156             :             /* table rowtypes and array types are never dumped separately */
   11157       27316 :             break;
   11158          90 :         case DO_TSPARSER:
   11159          90 :             dumpTSParser(fout, (const TSParserInfo *) dobj);
   11160          90 :             break;
   11161         354 :         case DO_TSDICT:
   11162         354 :             dumpTSDictionary(fout, (const TSDictInfo *) dobj);
   11163         354 :             break;
   11164         114 :         case DO_TSTEMPLATE:
   11165         114 :             dumpTSTemplate(fout, (const TSTemplateInfo *) dobj);
   11166         114 :             break;
   11167         304 :         case DO_TSCONFIG:
   11168         304 :             dumpTSConfig(fout, (const TSConfigInfo *) dobj);
   11169         304 :             break;
   11170         112 :         case DO_FDW:
   11171         112 :             dumpForeignDataWrapper(fout, (const FdwInfo *) dobj);
   11172         112 :             break;
   11173         120 :         case DO_FOREIGN_SERVER:
   11174         120 :             dumpForeignServer(fout, (const ForeignServerInfo *) dobj);
   11175         120 :             break;
   11176         332 :         case DO_DEFAULT_ACL:
   11177         332 :             dumpDefaultACL(fout, (const DefaultACLInfo *) dobj);
   11178         332 :             break;
   11179         158 :         case DO_LARGE_OBJECT:
   11180         158 :             dumpLO(fout, (const LoInfo *) dobj);
   11181         158 :             break;
   11182         158 :         case DO_LARGE_OBJECT_DATA:
   11183         158 :             if (dobj->dump & DUMP_COMPONENT_DATA)
   11184             :             {
   11185             :                 LoInfo     *loinfo;
   11186             :                 TocEntry   *te;
   11187             : 
   11188         158 :                 loinfo = (LoInfo *) findObjectByDumpId(dobj->dependencies[0]);
   11189         158 :                 if (loinfo == NULL)
   11190           0 :                     pg_fatal("missing metadata for large objects \"%s\"",
   11191             :                              dobj->name);
   11192             : 
   11193         158 :                 te = ArchiveEntry(fout, dobj->catId, dobj->dumpId,
   11194         158 :                                   ARCHIVE_OPTS(.tag = dobj->name,
   11195             :                                                .owner = loinfo->rolname,
   11196             :                                                .description = "BLOBS",
   11197             :                                                .section = SECTION_DATA,
   11198             :                                                .deps = dobj->dependencies,
   11199             :                                                .nDeps = dobj->nDeps,
   11200             :                                                .dumpFn = dumpLOs,
   11201             :                                                .dumpArg = loinfo));
   11202             : 
   11203             :                 /*
   11204             :                  * Set the TocEntry's dataLength in case we are doing a
   11205             :                  * parallel dump and want to order dump jobs by table size.
   11206             :                  * (We need some size estimate for every TocEntry with a
   11207             :                  * DataDumper function.)  We don't currently have any cheap
   11208             :                  * way to estimate the size of LOs, but fortunately it doesn't
   11209             :                  * matter too much as long as we get large batches of LOs
   11210             :                  * processed reasonably early.  Assume 8K per blob.
   11211             :                  */
   11212         158 :                 te->dataLength = loinfo->numlos * (pgoff_t) 8192;
   11213             :             }
   11214         158 :             break;
   11215         708 :         case DO_POLICY:
   11216         708 :             dumpPolicy(fout, (const PolicyInfo *) dobj);
   11217         708 :             break;
   11218         412 :         case DO_PUBLICATION:
   11219         412 :             dumpPublication(fout, (const PublicationInfo *) dobj);
   11220         412 :             break;
   11221         574 :         case DO_PUBLICATION_REL:
   11222         574 :             dumpPublicationTable(fout, (const PublicationRelInfo *) dobj);
   11223         574 :             break;
   11224         164 :         case DO_PUBLICATION_TABLE_IN_SCHEMA:
   11225         164 :             dumpPublicationNamespace(fout,
   11226             :                                      (const PublicationSchemaInfo *) dobj);
   11227         164 :             break;
   11228         250 :         case DO_SUBSCRIPTION:
   11229         250 :             dumpSubscription(fout, (const SubscriptionInfo *) dobj);
   11230         250 :             break;
   11231           4 :         case DO_SUBSCRIPTION_REL:
   11232           4 :             dumpSubscriptionTable(fout, (const SubRelInfo *) dobj);
   11233           4 :             break;
   11234       12188 :         case DO_REL_STATS:
   11235       12188 :             dumpRelationStats(fout, (const RelStatsInfo *) dobj);
   11236       12188 :             break;
   11237         708 :         case DO_PRE_DATA_BOUNDARY:
   11238             :         case DO_POST_DATA_BOUNDARY:
   11239             :             /* never dumped, nothing to do */
   11240         708 :             break;
   11241             :     }
   11242             : }
   11243             : 
   11244             : /*
   11245             :  * dumpNamespace
   11246             :  *    writes out to fout the queries to recreate a user-defined namespace
   11247             :  */
   11248             : static void
   11249         910 : dumpNamespace(Archive *fout, const NamespaceInfo *nspinfo)
   11250             : {
   11251         910 :     DumpOptions *dopt = fout->dopt;
   11252             :     PQExpBuffer q;
   11253             :     PQExpBuffer delq;
   11254             :     char       *qnspname;
   11255             : 
   11256             :     /* Do nothing if not dumping schema */
   11257         910 :     if (!dopt->dumpSchema)
   11258          56 :         return;
   11259             : 
   11260         854 :     q = createPQExpBuffer();
   11261         854 :     delq = createPQExpBuffer();
   11262             : 
   11263         854 :     qnspname = pg_strdup(fmtId(nspinfo->dobj.name));
   11264             : 
   11265         854 :     if (nspinfo->create)
   11266             :     {
   11267         570 :         appendPQExpBuffer(delq, "DROP SCHEMA %s;\n", qnspname);
   11268         570 :         appendPQExpBuffer(q, "CREATE SCHEMA %s;\n", qnspname);
   11269             :     }
   11270             :     else
   11271             :     {
   11272             :         /* see selectDumpableNamespace() */
   11273         284 :         appendPQExpBufferStr(delq,
   11274             :                              "-- *not* dropping schema, since initdb creates it\n");
   11275         284 :         appendPQExpBufferStr(q,
   11276             :                              "-- *not* creating schema, since initdb creates it\n");
   11277             :     }
   11278             : 
   11279         854 :     if (dopt->binary_upgrade)
   11280         152 :         binary_upgrade_extension_member(q, &nspinfo->dobj,
   11281             :                                         "SCHEMA", qnspname, NULL);
   11282             : 
   11283         854 :     if (nspinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   11284         354 :         ArchiveEntry(fout, nspinfo->dobj.catId, nspinfo->dobj.dumpId,
   11285         354 :                      ARCHIVE_OPTS(.tag = nspinfo->dobj.name,
   11286             :                                   .owner = nspinfo->rolname,
   11287             :                                   .description = "SCHEMA",
   11288             :                                   .section = SECTION_PRE_DATA,
   11289             :                                   .createStmt = q->data,
   11290             :                                   .dropStmt = delq->data));
   11291             : 
   11292             :     /* Dump Schema Comments and Security Labels */
   11293         854 :     if (nspinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   11294             :     {
   11295         294 :         const char *initdb_comment = NULL;
   11296             : 
   11297         294 :         if (!nspinfo->create && strcmp(qnspname, "public") == 0)
   11298         226 :             initdb_comment = "standard public schema";
   11299         294 :         dumpCommentExtended(fout, "SCHEMA", qnspname,
   11300             :                             NULL, nspinfo->rolname,
   11301             :                             nspinfo->dobj.catId, 0, nspinfo->dobj.dumpId,
   11302             :                             initdb_comment);
   11303             :     }
   11304             : 
   11305         854 :     if (nspinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
   11306           0 :         dumpSecLabel(fout, "SCHEMA", qnspname,
   11307             :                      NULL, nspinfo->rolname,
   11308             :                      nspinfo->dobj.catId, 0, nspinfo->dobj.dumpId);
   11309             : 
   11310         854 :     if (nspinfo->dobj.dump & DUMP_COMPONENT_ACL)
   11311         682 :         dumpACL(fout, nspinfo->dobj.dumpId, InvalidDumpId, "SCHEMA",
   11312             :                 qnspname, NULL, NULL,
   11313             :                 NULL, nspinfo->rolname, &nspinfo->dacl);
   11314             : 
   11315         854 :     free(qnspname);
   11316             : 
   11317         854 :     destroyPQExpBuffer(q);
   11318         854 :     destroyPQExpBuffer(delq);
   11319             : }
   11320             : 
   11321             : /*
   11322             :  * dumpExtension
   11323             :  *    writes out to fout the queries to recreate an extension
   11324             :  */
   11325             : static void
   11326          38 : dumpExtension(Archive *fout, const ExtensionInfo *extinfo)
   11327             : {
   11328          38 :     DumpOptions *dopt = fout->dopt;
   11329             :     PQExpBuffer q;
   11330             :     PQExpBuffer delq;
   11331             :     char       *qextname;
   11332             : 
   11333             :     /* Do nothing if not dumping schema */
   11334          38 :     if (!dopt->dumpSchema)
   11335           2 :         return;
   11336             : 
   11337          36 :     q = createPQExpBuffer();
   11338          36 :     delq = createPQExpBuffer();
   11339             : 
   11340          36 :     qextname = pg_strdup(fmtId(extinfo->dobj.name));
   11341             : 
   11342          36 :     appendPQExpBuffer(delq, "DROP EXTENSION %s;\n", qextname);
   11343             : 
   11344          36 :     if (!dopt->binary_upgrade)
   11345             :     {
   11346             :         /*
   11347             :          * In a regular dump, we simply create the extension, intentionally
   11348             :          * not specifying a version, so that the destination installation's
   11349             :          * default version is used.
   11350             :          *
   11351             :          * Use of IF NOT EXISTS here is unlike our behavior for other object
   11352             :          * types; but there are various scenarios in which it's convenient to
   11353             :          * manually create the desired extension before restoring, so we
   11354             :          * prefer to allow it to exist already.
   11355             :          */
   11356          34 :         appendPQExpBuffer(q, "CREATE EXTENSION IF NOT EXISTS %s WITH SCHEMA %s;\n",
   11357          34 :                           qextname, fmtId(extinfo->namespace));
   11358             :     }
   11359             :     else
   11360             :     {
   11361             :         /*
   11362             :          * In binary-upgrade mode, it's critical to reproduce the state of the
   11363             :          * database exactly, so our procedure is to create an empty extension,
   11364             :          * restore all the contained objects normally, and add them to the
   11365             :          * extension one by one.  This function performs just the first of
   11366             :          * those steps.  binary_upgrade_extension_member() takes care of
   11367             :          * adding member objects as they're created.
   11368             :          */
   11369             :         int         i;
   11370             :         int         n;
   11371             : 
   11372           2 :         appendPQExpBufferStr(q, "-- For binary upgrade, create an empty extension and insert objects into it\n");
   11373             : 
   11374             :         /*
   11375             :          * We unconditionally create the extension, so we must drop it if it
   11376             :          * exists.  This could happen if the user deleted 'plpgsql' and then
   11377             :          * readded it, causing its oid to be greater than g_last_builtin_oid.
   11378             :          */
   11379           2 :         appendPQExpBuffer(q, "DROP EXTENSION IF EXISTS %s;\n", qextname);
   11380             : 
   11381           2 :         appendPQExpBufferStr(q,
   11382             :                              "SELECT pg_catalog.binary_upgrade_create_empty_extension(");
   11383           2 :         appendStringLiteralAH(q, extinfo->dobj.name, fout);
   11384           2 :         appendPQExpBufferStr(q, ", ");
   11385           2 :         appendStringLiteralAH(q, extinfo->namespace, fout);
   11386           2 :         appendPQExpBufferStr(q, ", ");
   11387           2 :         appendPQExpBuffer(q, "%s, ", extinfo->relocatable ? "true" : "false");
   11388           2 :         appendStringLiteralAH(q, extinfo->extversion, fout);
   11389           2 :         appendPQExpBufferStr(q, ", ");
   11390             : 
   11391             :         /*
   11392             :          * Note that we're pushing extconfig (an OID array) back into
   11393             :          * pg_extension exactly as-is.  This is OK because pg_class OIDs are
   11394             :          * preserved in binary upgrade.
   11395             :          */
   11396           2 :         if (strlen(extinfo->extconfig) > 2)
   11397           2 :             appendStringLiteralAH(q, extinfo->extconfig, fout);
   11398             :         else
   11399           0 :             appendPQExpBufferStr(q, "NULL");
   11400           2 :         appendPQExpBufferStr(q, ", ");
   11401           2 :         if (strlen(extinfo->extcondition) > 2)
   11402           2 :             appendStringLiteralAH(q, extinfo->extcondition, fout);
   11403             :         else
   11404           0 :             appendPQExpBufferStr(q, "NULL");
   11405           2 :         appendPQExpBufferStr(q, ", ");
   11406           2 :         appendPQExpBufferStr(q, "ARRAY[");
   11407           2 :         n = 0;
   11408           4 :         for (i = 0; i < extinfo->dobj.nDeps; i++)
   11409             :         {
   11410             :             DumpableObject *extobj;
   11411             : 
   11412           2 :             extobj = findObjectByDumpId(extinfo->dobj.dependencies[i]);
   11413           2 :             if (extobj && extobj->objType == DO_EXTENSION)
   11414             :             {
   11415           0 :                 if (n++ > 0)
   11416           0 :                     appendPQExpBufferChar(q, ',');
   11417           0 :                 appendStringLiteralAH(q, extobj->name, fout);
   11418             :             }
   11419             :         }
   11420           2 :         appendPQExpBufferStr(q, "]::pg_catalog.text[]");
   11421           2 :         appendPQExpBufferStr(q, ");\n");
   11422             :     }
   11423             : 
   11424          36 :     if (extinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   11425          36 :         ArchiveEntry(fout, extinfo->dobj.catId, extinfo->dobj.dumpId,
   11426          36 :                      ARCHIVE_OPTS(.tag = extinfo->dobj.name,
   11427             :                                   .description = "EXTENSION",
   11428             :                                   .section = SECTION_PRE_DATA,
   11429             :                                   .createStmt = q->data,
   11430             :                                   .dropStmt = delq->data));
   11431             : 
   11432             :     /* Dump Extension Comments and Security Labels */
   11433          36 :     if (extinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   11434          36 :         dumpComment(fout, "EXTENSION", qextname,
   11435             :                     NULL, "",
   11436             :                     extinfo->dobj.catId, 0, extinfo->dobj.dumpId);
   11437             : 
   11438          36 :     if (extinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
   11439           0 :         dumpSecLabel(fout, "EXTENSION", qextname,
   11440             :                      NULL, "",
   11441             :                      extinfo->dobj.catId, 0, extinfo->dobj.dumpId);
   11442             : 
   11443          36 :     free(qextname);
   11444             : 
   11445          36 :     destroyPQExpBuffer(q);
   11446          36 :     destroyPQExpBuffer(delq);
   11447             : }
   11448             : 
   11449             : /*
   11450             :  * dumpType
   11451             :  *    writes out to fout the queries to recreate a user-defined type
   11452             :  */
   11453             : static void
   11454        1786 : dumpType(Archive *fout, const TypeInfo *tyinfo)
   11455             : {
   11456        1786 :     DumpOptions *dopt = fout->dopt;
   11457             : 
   11458             :     /* Do nothing if not dumping schema */
   11459        1786 :     if (!dopt->dumpSchema)
   11460          86 :         return;
   11461             : 
   11462             :     /* Dump out in proper style */
   11463        1700 :     if (tyinfo->typtype == TYPTYPE_BASE)
   11464         562 :         dumpBaseType(fout, tyinfo);
   11465        1138 :     else if (tyinfo->typtype == TYPTYPE_DOMAIN)
   11466         282 :         dumpDomain(fout, tyinfo);
   11467         856 :     else if (tyinfo->typtype == TYPTYPE_COMPOSITE)
   11468         268 :         dumpCompositeType(fout, tyinfo);
   11469         588 :     else if (tyinfo->typtype == TYPTYPE_ENUM)
   11470         116 :         dumpEnumType(fout, tyinfo);
   11471         472 :     else if (tyinfo->typtype == TYPTYPE_RANGE)
   11472         240 :         dumpRangeType(fout, tyinfo);
   11473         232 :     else if (tyinfo->typtype == TYPTYPE_PSEUDO && !tyinfo->isDefined)
   11474          82 :         dumpUndefinedType(fout, tyinfo);
   11475             :     else
   11476         150 :         pg_log_warning("typtype of data type \"%s\" appears to be invalid",
   11477             :                        tyinfo->dobj.name);
   11478             : }
   11479             : 
   11480             : /*
   11481             :  * dumpEnumType
   11482             :  *    writes out to fout the queries to recreate a user-defined enum type
   11483             :  */
   11484             : static void
   11485         116 : dumpEnumType(Archive *fout, const TypeInfo *tyinfo)
   11486             : {
   11487         116 :     DumpOptions *dopt = fout->dopt;
   11488         116 :     PQExpBuffer q = createPQExpBuffer();
   11489         116 :     PQExpBuffer delq = createPQExpBuffer();
   11490         116 :     PQExpBuffer query = createPQExpBuffer();
   11491             :     PGresult   *res;
   11492             :     int         num,
   11493             :                 i;
   11494             :     Oid         enum_oid;
   11495             :     char       *qtypname;
   11496             :     char       *qualtypname;
   11497             :     char       *label;
   11498             :     int         i_enumlabel;
   11499             :     int         i_oid;
   11500             : 
   11501         116 :     if (!fout->is_prepared[PREPQUERY_DUMPENUMTYPE])
   11502             :     {
   11503             :         /* Set up query for enum-specific details */
   11504          86 :         appendPQExpBufferStr(query,
   11505             :                              "PREPARE dumpEnumType(pg_catalog.oid) AS\n"
   11506             :                              "SELECT oid, enumlabel "
   11507             :                              "FROM pg_catalog.pg_enum "
   11508             :                              "WHERE enumtypid = $1 "
   11509             :                              "ORDER BY enumsortorder");
   11510             : 
   11511          86 :         ExecuteSqlStatement(fout, query->data);
   11512             : 
   11513          86 :         fout->is_prepared[PREPQUERY_DUMPENUMTYPE] = true;
   11514             :     }
   11515             : 
   11516         116 :     printfPQExpBuffer(query,
   11517             :                       "EXECUTE dumpEnumType('%u')",
   11518             :                       tyinfo->dobj.catId.oid);
   11519             : 
   11520         116 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   11521             : 
   11522         116 :     num = PQntuples(res);
   11523             : 
   11524         116 :     qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
   11525         116 :     qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
   11526             : 
   11527             :     /*
   11528             :      * CASCADE shouldn't be required here as for normal types since the I/O
   11529             :      * functions are generic and do not get dropped.
   11530             :      */
   11531         116 :     appendPQExpBuffer(delq, "DROP TYPE %s;\n", qualtypname);
   11532             : 
   11533         116 :     if (dopt->binary_upgrade)
   11534          10 :         binary_upgrade_set_type_oids_by_type_oid(fout, q,
   11535             :                                                  tyinfo->dobj.catId.oid,
   11536             :                                                  false, false);
   11537             : 
   11538         116 :     appendPQExpBuffer(q, "CREATE TYPE %s AS ENUM (",
   11539             :                       qualtypname);
   11540             : 
   11541         116 :     if (!dopt->binary_upgrade)
   11542             :     {
   11543         106 :         i_enumlabel = PQfnumber(res, "enumlabel");
   11544             : 
   11545             :         /* Labels with server-assigned oids */
   11546         756 :         for (i = 0; i < num; i++)
   11547             :         {
   11548         650 :             label = PQgetvalue(res, i, i_enumlabel);
   11549         650 :             if (i > 0)
   11550         544 :                 appendPQExpBufferChar(q, ',');
   11551         650 :             appendPQExpBufferStr(q, "\n    ");
   11552         650 :             appendStringLiteralAH(q, label, fout);
   11553             :         }
   11554             :     }
   11555             : 
   11556         116 :     appendPQExpBufferStr(q, "\n);\n");
   11557             : 
   11558         116 :     if (dopt->binary_upgrade)
   11559             :     {
   11560          10 :         i_oid = PQfnumber(res, "oid");
   11561          10 :         i_enumlabel = PQfnumber(res, "enumlabel");
   11562             : 
   11563             :         /* Labels with dump-assigned (preserved) oids */
   11564         116 :         for (i = 0; i < num; i++)
   11565             :         {
   11566         106 :             enum_oid = atooid(PQgetvalue(res, i, i_oid));
   11567         106 :             label = PQgetvalue(res, i, i_enumlabel);
   11568             : 
   11569         106 :             if (i == 0)
   11570          10 :                 appendPQExpBufferStr(q, "\n-- For binary upgrade, must preserve pg_enum oids\n");
   11571         106 :             appendPQExpBuffer(q,
   11572             :                               "SELECT pg_catalog.binary_upgrade_set_next_pg_enum_oid('%u'::pg_catalog.oid);\n",
   11573             :                               enum_oid);
   11574         106 :             appendPQExpBuffer(q, "ALTER TYPE %s ADD VALUE ", qualtypname);
   11575         106 :             appendStringLiteralAH(q, label, fout);
   11576         106 :             appendPQExpBufferStr(q, ";\n\n");
   11577             :         }
   11578             :     }
   11579             : 
   11580         116 :     if (dopt->binary_upgrade)
   11581          10 :         binary_upgrade_extension_member(q, &tyinfo->dobj,
   11582             :                                         "TYPE", qtypname,
   11583          10 :                                         tyinfo->dobj.namespace->dobj.name);
   11584             : 
   11585         116 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   11586         116 :         ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
   11587         116 :                      ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
   11588             :                                   .namespace = tyinfo->dobj.namespace->dobj.name,
   11589             :                                   .owner = tyinfo->rolname,
   11590             :                                   .description = "TYPE",
   11591             :                                   .section = SECTION_PRE_DATA,
   11592             :                                   .createStmt = q->data,
   11593             :                                   .dropStmt = delq->data));
   11594             : 
   11595             :     /* Dump Type Comments and Security Labels */
   11596         116 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   11597          72 :         dumpComment(fout, "TYPE", qtypname,
   11598          72 :                     tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
   11599             :                     tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
   11600             : 
   11601         116 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
   11602           0 :         dumpSecLabel(fout, "TYPE", qtypname,
   11603           0 :                      tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
   11604             :                      tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
   11605             : 
   11606         116 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
   11607          72 :         dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
   11608             :                 qtypname, NULL,
   11609          72 :                 tyinfo->dobj.namespace->dobj.name,
   11610             :                 NULL, tyinfo->rolname, &tyinfo->dacl);
   11611             : 
   11612         116 :     PQclear(res);
   11613         116 :     destroyPQExpBuffer(q);
   11614         116 :     destroyPQExpBuffer(delq);
   11615         116 :     destroyPQExpBuffer(query);
   11616         116 :     free(qtypname);
   11617         116 :     free(qualtypname);
   11618         116 : }
   11619             : 
   11620             : /*
   11621             :  * dumpRangeType
   11622             :  *    writes out to fout the queries to recreate a user-defined range type
   11623             :  */
   11624             : static void
   11625         240 : dumpRangeType(Archive *fout, const TypeInfo *tyinfo)
   11626             : {
   11627         240 :     DumpOptions *dopt = fout->dopt;
   11628         240 :     PQExpBuffer q = createPQExpBuffer();
   11629         240 :     PQExpBuffer delq = createPQExpBuffer();
   11630         240 :     PQExpBuffer query = createPQExpBuffer();
   11631             :     PGresult   *res;
   11632             :     Oid         collationOid;
   11633             :     char       *qtypname;
   11634             :     char       *qualtypname;
   11635             :     char       *procname;
   11636             : 
   11637         240 :     if (!fout->is_prepared[PREPQUERY_DUMPRANGETYPE])
   11638             :     {
   11639             :         /* Set up query for range-specific details */
   11640          88 :         appendPQExpBufferStr(query,
   11641             :                              "PREPARE dumpRangeType(pg_catalog.oid) AS\n");
   11642             : 
   11643          88 :         appendPQExpBufferStr(query,
   11644             :                              "SELECT ");
   11645             : 
   11646          88 :         if (fout->remoteVersion >= 140000)
   11647          88 :             appendPQExpBufferStr(query,
   11648             :                                  "pg_catalog.format_type(rngmultitypid, NULL) AS rngmultitype, ");
   11649             :         else
   11650           0 :             appendPQExpBufferStr(query,
   11651             :                                  "NULL AS rngmultitype, ");
   11652             : 
   11653          88 :         appendPQExpBufferStr(query,
   11654             :                              "pg_catalog.format_type(rngsubtype, NULL) AS rngsubtype, "
   11655             :                              "opc.opcname AS opcname, "
   11656             :                              "(SELECT nspname FROM pg_catalog.pg_namespace nsp "
   11657             :                              "  WHERE nsp.oid = opc.opcnamespace) AS opcnsp, "
   11658             :                              "opc.opcdefault, "
   11659             :                              "CASE WHEN rngcollation = st.typcollation THEN 0 "
   11660             :                              "     ELSE rngcollation END AS collation, "
   11661             :                              "rngcanonical, rngsubdiff "
   11662             :                              "FROM pg_catalog.pg_range r, pg_catalog.pg_type st, "
   11663             :                              "     pg_catalog.pg_opclass opc "
   11664             :                              "WHERE st.oid = rngsubtype AND opc.oid = rngsubopc AND "
   11665             :                              "rngtypid = $1");
   11666             : 
   11667          88 :         ExecuteSqlStatement(fout, query->data);
   11668             : 
   11669          88 :         fout->is_prepared[PREPQUERY_DUMPRANGETYPE] = true;
   11670             :     }
   11671             : 
   11672         240 :     printfPQExpBuffer(query,
   11673             :                       "EXECUTE dumpRangeType('%u')",
   11674             :                       tyinfo->dobj.catId.oid);
   11675             : 
   11676         240 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   11677             : 
   11678         240 :     qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
   11679         240 :     qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
   11680             : 
   11681             :     /*
   11682             :      * CASCADE shouldn't be required here as for normal types since the I/O
   11683             :      * functions are generic and do not get dropped.
   11684             :      */
   11685         240 :     appendPQExpBuffer(delq, "DROP TYPE %s;\n", qualtypname);
   11686             : 
   11687         240 :     if (dopt->binary_upgrade)
   11688          16 :         binary_upgrade_set_type_oids_by_type_oid(fout, q,
   11689             :                                                  tyinfo->dobj.catId.oid,
   11690             :                                                  false, true);
   11691             : 
   11692         240 :     appendPQExpBuffer(q, "CREATE TYPE %s AS RANGE (",
   11693             :                       qualtypname);
   11694             : 
   11695         240 :     appendPQExpBuffer(q, "\n    subtype = %s",
   11696             :                       PQgetvalue(res, 0, PQfnumber(res, "rngsubtype")));
   11697             : 
   11698         240 :     if (!PQgetisnull(res, 0, PQfnumber(res, "rngmultitype")))
   11699         240 :         appendPQExpBuffer(q, ",\n    multirange_type_name = %s",
   11700             :                           PQgetvalue(res, 0, PQfnumber(res, "rngmultitype")));
   11701             : 
   11702             :     /* print subtype_opclass only if not default for subtype */
   11703         240 :     if (PQgetvalue(res, 0, PQfnumber(res, "opcdefault"))[0] != 't')
   11704             :     {
   11705          72 :         char       *opcname = PQgetvalue(res, 0, PQfnumber(res, "opcname"));
   11706          72 :         char       *nspname = PQgetvalue(res, 0, PQfnumber(res, "opcnsp"));
   11707             : 
   11708          72 :         appendPQExpBuffer(q, ",\n    subtype_opclass = %s.",
   11709             :                           fmtId(nspname));
   11710          72 :         appendPQExpBufferStr(q, fmtId(opcname));
   11711             :     }
   11712             : 
   11713         240 :     collationOid = atooid(PQgetvalue(res, 0, PQfnumber(res, "collation")));
   11714         240 :     if (OidIsValid(collationOid))
   11715             :     {
   11716          82 :         CollInfo   *coll = findCollationByOid(collationOid);
   11717             : 
   11718          82 :         if (coll)
   11719          82 :             appendPQExpBuffer(q, ",\n    collation = %s",
   11720          82 :                               fmtQualifiedDumpable(coll));
   11721             :     }
   11722             : 
   11723         240 :     procname = PQgetvalue(res, 0, PQfnumber(res, "rngcanonical"));
   11724         240 :     if (strcmp(procname, "-") != 0)
   11725          18 :         appendPQExpBuffer(q, ",\n    canonical = %s", procname);
   11726             : 
   11727         240 :     procname = PQgetvalue(res, 0, PQfnumber(res, "rngsubdiff"));
   11728         240 :     if (strcmp(procname, "-") != 0)
   11729          46 :         appendPQExpBuffer(q, ",\n    subtype_diff = %s", procname);
   11730             : 
   11731         240 :     appendPQExpBufferStr(q, "\n);\n");
   11732             : 
   11733         240 :     if (dopt->binary_upgrade)
   11734          16 :         binary_upgrade_extension_member(q, &tyinfo->dobj,
   11735             :                                         "TYPE", qtypname,
   11736          16 :                                         tyinfo->dobj.namespace->dobj.name);
   11737             : 
   11738         240 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   11739         240 :         ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
   11740         240 :                      ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
   11741             :                                   .namespace = tyinfo->dobj.namespace->dobj.name,
   11742             :                                   .owner = tyinfo->rolname,
   11743             :                                   .description = "TYPE",
   11744             :                                   .section = SECTION_PRE_DATA,
   11745             :                                   .createStmt = q->data,
   11746             :                                   .dropStmt = delq->data));
   11747             : 
   11748             :     /* Dump Type Comments and Security Labels */
   11749         240 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   11750         108 :         dumpComment(fout, "TYPE", qtypname,
   11751         108 :                     tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
   11752             :                     tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
   11753             : 
   11754         240 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
   11755           0 :         dumpSecLabel(fout, "TYPE", qtypname,
   11756           0 :                      tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
   11757             :                      tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
   11758             : 
   11759         240 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
   11760          72 :         dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
   11761             :                 qtypname, NULL,
   11762          72 :                 tyinfo->dobj.namespace->dobj.name,
   11763             :                 NULL, tyinfo->rolname, &tyinfo->dacl);
   11764             : 
   11765         240 :     PQclear(res);
   11766         240 :     destroyPQExpBuffer(q);
   11767         240 :     destroyPQExpBuffer(delq);
   11768         240 :     destroyPQExpBuffer(query);
   11769         240 :     free(qtypname);
   11770         240 :     free(qualtypname);
   11771         240 : }
   11772             : 
   11773             : /*
   11774             :  * dumpUndefinedType
   11775             :  *    writes out to fout the queries to recreate a !typisdefined type
   11776             :  *
   11777             :  * This is a shell type, but we use different terminology to distinguish
   11778             :  * this case from where we have to emit a shell type definition to break
   11779             :  * circular dependencies.  An undefined type shouldn't ever have anything
   11780             :  * depending on it.
   11781             :  */
   11782             : static void
   11783          82 : dumpUndefinedType(Archive *fout, const TypeInfo *tyinfo)
   11784             : {
   11785          82 :     DumpOptions *dopt = fout->dopt;
   11786          82 :     PQExpBuffer q = createPQExpBuffer();
   11787          82 :     PQExpBuffer delq = createPQExpBuffer();
   11788             :     char       *qtypname;
   11789             :     char       *qualtypname;
   11790             : 
   11791          82 :     qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
   11792          82 :     qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
   11793             : 
   11794          82 :     appendPQExpBuffer(delq, "DROP TYPE %s;\n", qualtypname);
   11795             : 
   11796          82 :     if (dopt->binary_upgrade)
   11797           4 :         binary_upgrade_set_type_oids_by_type_oid(fout, q,
   11798             :                                                  tyinfo->dobj.catId.oid,
   11799             :                                                  false, false);
   11800             : 
   11801          82 :     appendPQExpBuffer(q, "CREATE TYPE %s;\n",
   11802             :                       qualtypname);
   11803             : 
   11804          82 :     if (dopt->binary_upgrade)
   11805           4 :         binary_upgrade_extension_member(q, &tyinfo->dobj,
   11806             :                                         "TYPE", qtypname,
   11807           4 :                                         tyinfo->dobj.namespace->dobj.name);
   11808             : 
   11809          82 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   11810          82 :         ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
   11811          82 :                      ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
   11812             :                                   .namespace = tyinfo->dobj.namespace->dobj.name,
   11813             :                                   .owner = tyinfo->rolname,
   11814             :                                   .description = "TYPE",
   11815             :                                   .section = SECTION_PRE_DATA,
   11816             :                                   .createStmt = q->data,
   11817             :                                   .dropStmt = delq->data));
   11818             : 
   11819             :     /* Dump Type Comments and Security Labels */
   11820          82 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   11821          72 :         dumpComment(fout, "TYPE", qtypname,
   11822          72 :                     tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
   11823             :                     tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
   11824             : 
   11825          82 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
   11826           0 :         dumpSecLabel(fout, "TYPE", qtypname,
   11827           0 :                      tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
   11828             :                      tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
   11829             : 
   11830          82 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
   11831           0 :         dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
   11832             :                 qtypname, NULL,
   11833           0 :                 tyinfo->dobj.namespace->dobj.name,
   11834             :                 NULL, tyinfo->rolname, &tyinfo->dacl);
   11835             : 
   11836          82 :     destroyPQExpBuffer(q);
   11837          82 :     destroyPQExpBuffer(delq);
   11838          82 :     free(qtypname);
   11839          82 :     free(qualtypname);
   11840          82 : }
   11841             : 
   11842             : /*
   11843             :  * dumpBaseType
   11844             :  *    writes out to fout the queries to recreate a user-defined base type
   11845             :  */
   11846             : static void
   11847         562 : dumpBaseType(Archive *fout, const TypeInfo *tyinfo)
   11848             : {
   11849         562 :     DumpOptions *dopt = fout->dopt;
   11850         562 :     PQExpBuffer q = createPQExpBuffer();
   11851         562 :     PQExpBuffer delq = createPQExpBuffer();
   11852         562 :     PQExpBuffer query = createPQExpBuffer();
   11853             :     PGresult   *res;
   11854             :     char       *qtypname;
   11855             :     char       *qualtypname;
   11856             :     char       *typlen;
   11857             :     char       *typinput;
   11858             :     char       *typoutput;
   11859             :     char       *typreceive;
   11860             :     char       *typsend;
   11861             :     char       *typmodin;
   11862             :     char       *typmodout;
   11863             :     char       *typanalyze;
   11864             :     char       *typsubscript;
   11865             :     Oid         typreceiveoid;
   11866             :     Oid         typsendoid;
   11867             :     Oid         typmodinoid;
   11868             :     Oid         typmodoutoid;
   11869             :     Oid         typanalyzeoid;
   11870             :     Oid         typsubscriptoid;
   11871             :     char       *typcategory;
   11872             :     char       *typispreferred;
   11873             :     char       *typdelim;
   11874             :     char       *typbyval;
   11875             :     char       *typalign;
   11876             :     char       *typstorage;
   11877             :     char       *typcollatable;
   11878             :     char       *typdefault;
   11879         562 :     bool        typdefault_is_literal = false;
   11880             : 
   11881         562 :     if (!fout->is_prepared[PREPQUERY_DUMPBASETYPE])
   11882             :     {
   11883             :         /* Set up query for type-specific details */
   11884          88 :         appendPQExpBufferStr(query,
   11885             :                              "PREPARE dumpBaseType(pg_catalog.oid) AS\n"
   11886             :                              "SELECT typlen, "
   11887             :                              "typinput, typoutput, typreceive, typsend, "
   11888             :                              "typreceive::pg_catalog.oid AS typreceiveoid, "
   11889             :                              "typsend::pg_catalog.oid AS typsendoid, "
   11890             :                              "typanalyze, "
   11891             :                              "typanalyze::pg_catalog.oid AS typanalyzeoid, "
   11892             :                              "typdelim, typbyval, typalign, typstorage, "
   11893             :                              "typmodin, typmodout, "
   11894             :                              "typmodin::pg_catalog.oid AS typmodinoid, "
   11895             :                              "typmodout::pg_catalog.oid AS typmodoutoid, "
   11896             :                              "typcategory, typispreferred, "
   11897             :                              "(typcollation <> 0) AS typcollatable, "
   11898             :                              "pg_catalog.pg_get_expr(typdefaultbin, 0) AS typdefaultbin, typdefault, ");
   11899             : 
   11900          88 :         if (fout->remoteVersion >= 140000)
   11901          88 :             appendPQExpBufferStr(query,
   11902             :                                  "typsubscript, "
   11903             :                                  "typsubscript::pg_catalog.oid AS typsubscriptoid ");
   11904             :         else
   11905           0 :             appendPQExpBufferStr(query,
   11906             :                                  "'-' AS typsubscript, 0 AS typsubscriptoid ");
   11907             : 
   11908          88 :         appendPQExpBufferStr(query, "FROM pg_catalog.pg_type "
   11909             :                              "WHERE oid = $1");
   11910             : 
   11911          88 :         ExecuteSqlStatement(fout, query->data);
   11912             : 
   11913          88 :         fout->is_prepared[PREPQUERY_DUMPBASETYPE] = true;
   11914             :     }
   11915             : 
   11916         562 :     printfPQExpBuffer(query,
   11917             :                       "EXECUTE dumpBaseType('%u')",
   11918             :                       tyinfo->dobj.catId.oid);
   11919             : 
   11920         562 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   11921             : 
   11922         562 :     typlen = PQgetvalue(res, 0, PQfnumber(res, "typlen"));
   11923         562 :     typinput = PQgetvalue(res, 0, PQfnumber(res, "typinput"));
   11924         562 :     typoutput = PQgetvalue(res, 0, PQfnumber(res, "typoutput"));
   11925         562 :     typreceive = PQgetvalue(res, 0, PQfnumber(res, "typreceive"));
   11926         562 :     typsend = PQgetvalue(res, 0, PQfnumber(res, "typsend"));
   11927         562 :     typmodin = PQgetvalue(res, 0, PQfnumber(res, "typmodin"));
   11928         562 :     typmodout = PQgetvalue(res, 0, PQfnumber(res, "typmodout"));
   11929         562 :     typanalyze = PQgetvalue(res, 0, PQfnumber(res, "typanalyze"));
   11930         562 :     typsubscript = PQgetvalue(res, 0, PQfnumber(res, "typsubscript"));
   11931         562 :     typreceiveoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typreceiveoid")));
   11932         562 :     typsendoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typsendoid")));
   11933         562 :     typmodinoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typmodinoid")));
   11934         562 :     typmodoutoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typmodoutoid")));
   11935         562 :     typanalyzeoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typanalyzeoid")));
   11936         562 :     typsubscriptoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typsubscriptoid")));
   11937         562 :     typcategory = PQgetvalue(res, 0, PQfnumber(res, "typcategory"));
   11938         562 :     typispreferred = PQgetvalue(res, 0, PQfnumber(res, "typispreferred"));
   11939         562 :     typdelim = PQgetvalue(res, 0, PQfnumber(res, "typdelim"));
   11940         562 :     typbyval = PQgetvalue(res, 0, PQfnumber(res, "typbyval"));
   11941         562 :     typalign = PQgetvalue(res, 0, PQfnumber(res, "typalign"));
   11942         562 :     typstorage = PQgetvalue(res, 0, PQfnumber(res, "typstorage"));
   11943         562 :     typcollatable = PQgetvalue(res, 0, PQfnumber(res, "typcollatable"));
   11944         562 :     if (!PQgetisnull(res, 0, PQfnumber(res, "typdefaultbin")))
   11945           0 :         typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefaultbin"));
   11946         562 :     else if (!PQgetisnull(res, 0, PQfnumber(res, "typdefault")))
   11947             :     {
   11948          92 :         typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefault"));
   11949          92 :         typdefault_is_literal = true;   /* it needs quotes */
   11950             :     }
   11951             :     else
   11952         470 :         typdefault = NULL;
   11953             : 
   11954         562 :     qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
   11955         562 :     qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
   11956             : 
   11957             :     /*
   11958             :      * The reason we include CASCADE is that the circular dependency between
   11959             :      * the type and its I/O functions makes it impossible to drop the type any
   11960             :      * other way.
   11961             :      */
   11962         562 :     appendPQExpBuffer(delq, "DROP TYPE %s CASCADE;\n", qualtypname);
   11963             : 
   11964             :     /*
   11965             :      * We might already have a shell type, but setting pg_type_oid is
   11966             :      * harmless, and in any case we'd better set the array type OID.
   11967             :      */
   11968         562 :     if (dopt->binary_upgrade)
   11969          16 :         binary_upgrade_set_type_oids_by_type_oid(fout, q,
   11970             :                                                  tyinfo->dobj.catId.oid,
   11971             :                                                  false, false);
   11972             : 
   11973         562 :     appendPQExpBuffer(q,
   11974             :                       "CREATE TYPE %s (\n"
   11975             :                       "    INTERNALLENGTH = %s",
   11976             :                       qualtypname,
   11977         562 :                       (strcmp(typlen, "-1") == 0) ? "variable" : typlen);
   11978             : 
   11979             :     /* regproc result is sufficiently quoted already */
   11980         562 :     appendPQExpBuffer(q, ",\n    INPUT = %s", typinput);
   11981         562 :     appendPQExpBuffer(q, ",\n    OUTPUT = %s", typoutput);
   11982         562 :     if (OidIsValid(typreceiveoid))
   11983         408 :         appendPQExpBuffer(q, ",\n    RECEIVE = %s", typreceive);
   11984         562 :     if (OidIsValid(typsendoid))
   11985         408 :         appendPQExpBuffer(q, ",\n    SEND = %s", typsend);
   11986         562 :     if (OidIsValid(typmodinoid))
   11987          70 :         appendPQExpBuffer(q, ",\n    TYPMOD_IN = %s", typmodin);
   11988         562 :     if (OidIsValid(typmodoutoid))
   11989          70 :         appendPQExpBuffer(q, ",\n    TYPMOD_OUT = %s", typmodout);
   11990         562 :     if (OidIsValid(typanalyzeoid))
   11991           6 :         appendPQExpBuffer(q, ",\n    ANALYZE = %s", typanalyze);
   11992             : 
   11993         562 :     if (strcmp(typcollatable, "t") == 0)
   11994          60 :         appendPQExpBufferStr(q, ",\n    COLLATABLE = true");
   11995             : 
   11996         562 :     if (typdefault != NULL)
   11997             :     {
   11998          92 :         appendPQExpBufferStr(q, ",\n    DEFAULT = ");
   11999          92 :         if (typdefault_is_literal)
   12000          92 :             appendStringLiteralAH(q, typdefault, fout);
   12001             :         else
   12002           0 :             appendPQExpBufferStr(q, typdefault);
   12003             :     }
   12004             : 
   12005         562 :     if (OidIsValid(typsubscriptoid))
   12006          58 :         appendPQExpBuffer(q, ",\n    SUBSCRIPT = %s", typsubscript);
   12007             : 
   12008         562 :     if (OidIsValid(tyinfo->typelem))
   12009          52 :         appendPQExpBuffer(q, ",\n    ELEMENT = %s",
   12010             :                           getFormattedTypeName(fout, tyinfo->typelem,
   12011             :                                                zeroIsError));
   12012             : 
   12013         562 :     if (strcmp(typcategory, "U") != 0)
   12014             :     {
   12015         310 :         appendPQExpBufferStr(q, ",\n    CATEGORY = ");
   12016         310 :         appendStringLiteralAH(q, typcategory, fout);
   12017             :     }
   12018             : 
   12019         562 :     if (strcmp(typispreferred, "t") == 0)
   12020          58 :         appendPQExpBufferStr(q, ",\n    PREFERRED = true");
   12021             : 
   12022         562 :     if (typdelim && strcmp(typdelim, ",") != 0)
   12023             :     {
   12024           6 :         appendPQExpBufferStr(q, ",\n    DELIMITER = ");
   12025           6 :         appendStringLiteralAH(q, typdelim, fout);
   12026             :     }
   12027             : 
   12028         562 :     if (*typalign == TYPALIGN_CHAR)
   12029          24 :         appendPQExpBufferStr(q, ",\n    ALIGNMENT = char");
   12030         538 :     else if (*typalign == TYPALIGN_SHORT)
   12031          12 :         appendPQExpBufferStr(q, ",\n    ALIGNMENT = int2");
   12032         526 :     else if (*typalign == TYPALIGN_INT)
   12033         376 :         appendPQExpBufferStr(q, ",\n    ALIGNMENT = int4");
   12034         150 :     else if (*typalign == TYPALIGN_DOUBLE)
   12035         150 :         appendPQExpBufferStr(q, ",\n    ALIGNMENT = double");
   12036             : 
   12037         562 :     if (*typstorage == TYPSTORAGE_PLAIN)
   12038         412 :         appendPQExpBufferStr(q, ",\n    STORAGE = plain");
   12039         150 :     else if (*typstorage == TYPSTORAGE_EXTERNAL)
   12040           0 :         appendPQExpBufferStr(q, ",\n    STORAGE = external");
   12041         150 :     else if (*typstorage == TYPSTORAGE_EXTENDED)
   12042         132 :         appendPQExpBufferStr(q, ",\n    STORAGE = extended");
   12043          18 :     else if (*typstorage == TYPSTORAGE_MAIN)
   12044          18 :         appendPQExpBufferStr(q, ",\n    STORAGE = main");
   12045             : 
   12046         562 :     if (strcmp(typbyval, "t") == 0)
   12047         270 :         appendPQExpBufferStr(q, ",\n    PASSEDBYVALUE");
   12048             : 
   12049         562 :     appendPQExpBufferStr(q, "\n);\n");
   12050             : 
   12051         562 :     if (dopt->binary_upgrade)
   12052          16 :         binary_upgrade_extension_member(q, &tyinfo->dobj,
   12053             :                                         "TYPE", qtypname,
   12054          16 :                                         tyinfo->dobj.namespace->dobj.name);
   12055             : 
   12056         562 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   12057         562 :         ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
   12058         562 :                      ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
   12059             :                                   .namespace = tyinfo->dobj.namespace->dobj.name,
   12060             :                                   .owner = tyinfo->rolname,
   12061             :                                   .description = "TYPE",
   12062             :                                   .section = SECTION_PRE_DATA,
   12063             :                                   .createStmt = q->data,
   12064             :                                   .dropStmt = delq->data));
   12065             : 
   12066             :     /* Dump Type Comments and Security Labels */
   12067         562 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   12068         492 :         dumpComment(fout, "TYPE", qtypname,
   12069         492 :                     tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
   12070             :                     tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
   12071             : 
   12072         562 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
   12073           0 :         dumpSecLabel(fout, "TYPE", qtypname,
   12074           0 :                      tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
   12075             :                      tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
   12076             : 
   12077         562 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
   12078          72 :         dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
   12079             :                 qtypname, NULL,
   12080          72 :                 tyinfo->dobj.namespace->dobj.name,
   12081             :                 NULL, tyinfo->rolname, &tyinfo->dacl);
   12082             : 
   12083         562 :     PQclear(res);
   12084         562 :     destroyPQExpBuffer(q);
   12085         562 :     destroyPQExpBuffer(delq);
   12086         562 :     destroyPQExpBuffer(query);
   12087         562 :     free(qtypname);
   12088         562 :     free(qualtypname);
   12089         562 : }
   12090             : 
   12091             : /*
   12092             :  * dumpDomain
   12093             :  *    writes out to fout the queries to recreate a user-defined domain
   12094             :  */
   12095             : static void
   12096         282 : dumpDomain(Archive *fout, const TypeInfo *tyinfo)
   12097             : {
   12098         282 :     DumpOptions *dopt = fout->dopt;
   12099         282 :     PQExpBuffer q = createPQExpBuffer();
   12100         282 :     PQExpBuffer delq = createPQExpBuffer();
   12101         282 :     PQExpBuffer query = createPQExpBuffer();
   12102             :     PGresult   *res;
   12103             :     int         i;
   12104             :     char       *qtypname;
   12105             :     char       *qualtypname;
   12106             :     char       *typnotnull;
   12107             :     char       *typdefn;
   12108             :     char       *typdefault;
   12109             :     Oid         typcollation;
   12110         282 :     bool        typdefault_is_literal = false;
   12111             : 
   12112         282 :     if (!fout->is_prepared[PREPQUERY_DUMPDOMAIN])
   12113             :     {
   12114             :         /* Set up query for domain-specific details */
   12115          82 :         appendPQExpBufferStr(query,
   12116             :                              "PREPARE dumpDomain(pg_catalog.oid) AS\n");
   12117             : 
   12118          82 :         appendPQExpBufferStr(query, "SELECT t.typnotnull, "
   12119             :                              "pg_catalog.format_type(t.typbasetype, t.typtypmod) AS typdefn, "
   12120             :                              "pg_catalog.pg_get_expr(t.typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, "
   12121             :                              "t.typdefault, "
   12122             :                              "CASE WHEN t.typcollation <> u.typcollation "
   12123             :                              "THEN t.typcollation ELSE 0 END AS typcollation "
   12124             :                              "FROM pg_catalog.pg_type t "
   12125             :                              "LEFT JOIN pg_catalog.pg_type u ON (t.typbasetype = u.oid) "
   12126             :                              "WHERE t.oid = $1");
   12127             : 
   12128          82 :         ExecuteSqlStatement(fout, query->data);
   12129             : 
   12130          82 :         fout->is_prepared[PREPQUERY_DUMPDOMAIN] = true;
   12131             :     }
   12132             : 
   12133         282 :     printfPQExpBuffer(query,
   12134             :                       "EXECUTE dumpDomain('%u')",
   12135             :                       tyinfo->dobj.catId.oid);
   12136             : 
   12137         282 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   12138             : 
   12139         282 :     typnotnull = PQgetvalue(res, 0, PQfnumber(res, "typnotnull"));
   12140         282 :     typdefn = PQgetvalue(res, 0, PQfnumber(res, "typdefn"));
   12141         282 :     if (!PQgetisnull(res, 0, PQfnumber(res, "typdefaultbin")))
   12142          82 :         typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefaultbin"));
   12143         200 :     else if (!PQgetisnull(res, 0, PQfnumber(res, "typdefault")))
   12144             :     {
   12145           0 :         typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefault"));
   12146           0 :         typdefault_is_literal = true;   /* it needs quotes */
   12147             :     }
   12148             :     else
   12149         200 :         typdefault = NULL;
   12150         282 :     typcollation = atooid(PQgetvalue(res, 0, PQfnumber(res, "typcollation")));
   12151             : 
   12152         282 :     if (dopt->binary_upgrade)
   12153          44 :         binary_upgrade_set_type_oids_by_type_oid(fout, q,
   12154             :                                                  tyinfo->dobj.catId.oid,
   12155             :                                                  true,  /* force array type */
   12156             :                                                  false);    /* force multirange type */
   12157             : 
   12158         282 :     qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
   12159         282 :     qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
   12160             : 
   12161         282 :     appendPQExpBuffer(q,
   12162             :                       "CREATE DOMAIN %s AS %s",
   12163             :                       qualtypname,
   12164             :                       typdefn);
   12165             : 
   12166             :     /* Print collation only if different from base type's collation */
   12167         282 :     if (OidIsValid(typcollation))
   12168             :     {
   12169             :         CollInfo   *coll;
   12170             : 
   12171          72 :         coll = findCollationByOid(typcollation);
   12172          72 :         if (coll)
   12173          72 :             appendPQExpBuffer(q, " COLLATE %s", fmtQualifiedDumpable(coll));
   12174             :     }
   12175             : 
   12176         282 :     if (typnotnull[0] == 't')
   12177          30 :         appendPQExpBufferStr(q, " NOT NULL");
   12178             : 
   12179         282 :     if (typdefault != NULL)
   12180             :     {
   12181          82 :         appendPQExpBufferStr(q, " DEFAULT ");
   12182          82 :         if (typdefault_is_literal)
   12183           0 :             appendStringLiteralAH(q, typdefault, fout);
   12184             :         else
   12185          82 :             appendPQExpBufferStr(q, typdefault);
   12186             :     }
   12187             : 
   12188         282 :     PQclear(res);
   12189             : 
   12190             :     /*
   12191             :      * Add any CHECK constraints for the domain
   12192             :      */
   12193         474 :     for (i = 0; i < tyinfo->nDomChecks; i++)
   12194             :     {
   12195         192 :         ConstraintInfo *domcheck = &(tyinfo->domChecks[i]);
   12196             : 
   12197         192 :         if (!domcheck->separate)
   12198         192 :             appendPQExpBuffer(q, "\n\tCONSTRAINT %s %s",
   12199         192 :                               fmtId(domcheck->dobj.name), domcheck->condef);
   12200             :     }
   12201             : 
   12202         282 :     appendPQExpBufferStr(q, ";\n");
   12203             : 
   12204         282 :     appendPQExpBuffer(delq, "DROP DOMAIN %s;\n", qualtypname);
   12205             : 
   12206         282 :     if (dopt->binary_upgrade)
   12207          44 :         binary_upgrade_extension_member(q, &tyinfo->dobj,
   12208             :                                         "DOMAIN", qtypname,
   12209          44 :                                         tyinfo->dobj.namespace->dobj.name);
   12210             : 
   12211         282 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   12212         282 :         ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
   12213         282 :                      ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
   12214             :                                   .namespace = tyinfo->dobj.namespace->dobj.name,
   12215             :                                   .owner = tyinfo->rolname,
   12216             :                                   .description = "DOMAIN",
   12217             :                                   .section = SECTION_PRE_DATA,
   12218             :                                   .createStmt = q->data,
   12219             :                                   .dropStmt = delq->data));
   12220             : 
   12221             :     /* Dump Domain Comments and Security Labels */
   12222         282 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   12223           0 :         dumpComment(fout, "DOMAIN", qtypname,
   12224           0 :                     tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
   12225             :                     tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
   12226             : 
   12227         282 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
   12228           0 :         dumpSecLabel(fout, "DOMAIN", qtypname,
   12229           0 :                      tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
   12230             :                      tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
   12231             : 
   12232         282 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
   12233          72 :         dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
   12234             :                 qtypname, NULL,
   12235          72 :                 tyinfo->dobj.namespace->dobj.name,
   12236             :                 NULL, tyinfo->rolname, &tyinfo->dacl);
   12237             : 
   12238             :     /* Dump any per-constraint comments */
   12239         474 :     for (i = 0; i < tyinfo->nDomChecks; i++)
   12240             :     {
   12241         192 :         ConstraintInfo *domcheck = &(tyinfo->domChecks[i]);
   12242         192 :         PQExpBuffer conprefix = createPQExpBuffer();
   12243             : 
   12244         192 :         appendPQExpBuffer(conprefix, "CONSTRAINT %s ON DOMAIN",
   12245         192 :                           fmtId(domcheck->dobj.name));
   12246             : 
   12247         192 :         if (domcheck->dobj.dump & DUMP_COMPONENT_COMMENT)
   12248          72 :             dumpComment(fout, conprefix->data, qtypname,
   12249          72 :                         tyinfo->dobj.namespace->dobj.name,
   12250             :                         tyinfo->rolname,
   12251             :                         domcheck->dobj.catId, 0, tyinfo->dobj.dumpId);
   12252             : 
   12253         192 :         destroyPQExpBuffer(conprefix);
   12254             :     }
   12255             : 
   12256         282 :     destroyPQExpBuffer(q);
   12257         282 :     destroyPQExpBuffer(delq);
   12258         282 :     destroyPQExpBuffer(query);
   12259         282 :     free(qtypname);
   12260         282 :     free(qualtypname);
   12261         282 : }
   12262             : 
   12263             : /*
   12264             :  * dumpCompositeType
   12265             :  *    writes out to fout the queries to recreate a user-defined stand-alone
   12266             :  *    composite type
   12267             :  */
   12268             : static void
   12269         268 : dumpCompositeType(Archive *fout, const TypeInfo *tyinfo)
   12270             : {
   12271         268 :     DumpOptions *dopt = fout->dopt;
   12272         268 :     PQExpBuffer q = createPQExpBuffer();
   12273         268 :     PQExpBuffer dropped = createPQExpBuffer();
   12274         268 :     PQExpBuffer delq = createPQExpBuffer();
   12275         268 :     PQExpBuffer query = createPQExpBuffer();
   12276             :     PGresult   *res;
   12277             :     char       *qtypname;
   12278             :     char       *qualtypname;
   12279             :     int         ntups;
   12280             :     int         i_attname;
   12281             :     int         i_atttypdefn;
   12282             :     int         i_attlen;
   12283             :     int         i_attalign;
   12284             :     int         i_attisdropped;
   12285             :     int         i_attcollation;
   12286             :     int         i;
   12287             :     int         actual_atts;
   12288             : 
   12289         268 :     if (!fout->is_prepared[PREPQUERY_DUMPCOMPOSITETYPE])
   12290             :     {
   12291             :         /*
   12292             :          * Set up query for type-specific details.
   12293             :          *
   12294             :          * Since we only want to dump COLLATE clauses for attributes whose
   12295             :          * collation is different from their type's default, we use a CASE
   12296             :          * here to suppress uninteresting attcollations cheaply.  atttypid
   12297             :          * will be 0 for dropped columns; collation does not matter for those.
   12298             :          */
   12299         118 :         appendPQExpBufferStr(query,
   12300             :                              "PREPARE dumpCompositeType(pg_catalog.oid) AS\n"
   12301             :                              "SELECT a.attname, a.attnum, "
   12302             :                              "pg_catalog.format_type(a.atttypid, a.atttypmod) AS atttypdefn, "
   12303             :                              "a.attlen, a.attalign, a.attisdropped, "
   12304             :                              "CASE WHEN a.attcollation <> at.typcollation "
   12305             :                              "THEN a.attcollation ELSE 0 END AS attcollation "
   12306             :                              "FROM pg_catalog.pg_type ct "
   12307             :                              "JOIN pg_catalog.pg_attribute a ON a.attrelid = ct.typrelid "
   12308             :                              "LEFT JOIN pg_catalog.pg_type at ON at.oid = a.atttypid "
   12309             :                              "WHERE ct.oid = $1 "
   12310             :                              "ORDER BY a.attnum");
   12311             : 
   12312         118 :         ExecuteSqlStatement(fout, query->data);
   12313             : 
   12314         118 :         fout->is_prepared[PREPQUERY_DUMPCOMPOSITETYPE] = true;
   12315             :     }
   12316             : 
   12317         268 :     printfPQExpBuffer(query,
   12318             :                       "EXECUTE dumpCompositeType('%u')",
   12319             :                       tyinfo->dobj.catId.oid);
   12320             : 
   12321         268 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   12322             : 
   12323         268 :     ntups = PQntuples(res);
   12324             : 
   12325         268 :     i_attname = PQfnumber(res, "attname");
   12326         268 :     i_atttypdefn = PQfnumber(res, "atttypdefn");
   12327         268 :     i_attlen = PQfnumber(res, "attlen");
   12328         268 :     i_attalign = PQfnumber(res, "attalign");
   12329         268 :     i_attisdropped = PQfnumber(res, "attisdropped");
   12330         268 :     i_attcollation = PQfnumber(res, "attcollation");
   12331             : 
   12332         268 :     if (dopt->binary_upgrade)
   12333             :     {
   12334          36 :         binary_upgrade_set_type_oids_by_type_oid(fout, q,
   12335             :                                                  tyinfo->dobj.catId.oid,
   12336             :                                                  false, false);
   12337          36 :         binary_upgrade_set_pg_class_oids(fout, q, tyinfo->typrelid);
   12338             :     }
   12339             : 
   12340         268 :     qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
   12341         268 :     qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
   12342             : 
   12343         268 :     appendPQExpBuffer(q, "CREATE TYPE %s AS (",
   12344             :                       qualtypname);
   12345             : 
   12346         268 :     actual_atts = 0;
   12347         848 :     for (i = 0; i < ntups; i++)
   12348             :     {
   12349             :         char       *attname;
   12350             :         char       *atttypdefn;
   12351             :         char       *attlen;
   12352             :         char       *attalign;
   12353             :         bool        attisdropped;
   12354             :         Oid         attcollation;
   12355             : 
   12356         580 :         attname = PQgetvalue(res, i, i_attname);
   12357         580 :         atttypdefn = PQgetvalue(res, i, i_atttypdefn);
   12358         580 :         attlen = PQgetvalue(res, i, i_attlen);
   12359         580 :         attalign = PQgetvalue(res, i, i_attalign);
   12360         580 :         attisdropped = (PQgetvalue(res, i, i_attisdropped)[0] == 't');
   12361         580 :         attcollation = atooid(PQgetvalue(res, i, i_attcollation));
   12362             : 
   12363         580 :         if (attisdropped && !dopt->binary_upgrade)
   12364          16 :             continue;
   12365             : 
   12366             :         /* Format properly if not first attr */
   12367         564 :         if (actual_atts++ > 0)
   12368         296 :             appendPQExpBufferChar(q, ',');
   12369         564 :         appendPQExpBufferStr(q, "\n\t");
   12370             : 
   12371         564 :         if (!attisdropped)
   12372             :         {
   12373         560 :             appendPQExpBuffer(q, "%s %s", fmtId(attname), atttypdefn);
   12374             : 
   12375             :             /* Add collation if not default for the column type */
   12376         560 :             if (OidIsValid(attcollation))
   12377             :             {
   12378             :                 CollInfo   *coll;
   12379             : 
   12380           0 :                 coll = findCollationByOid(attcollation);
   12381           0 :                 if (coll)
   12382           0 :                     appendPQExpBuffer(q, " COLLATE %s",
   12383           0 :                                       fmtQualifiedDumpable(coll));
   12384             :             }
   12385             :         }
   12386             :         else
   12387             :         {
   12388             :             /*
   12389             :              * This is a dropped attribute and we're in binary_upgrade mode.
   12390             :              * Insert a placeholder for it in the CREATE TYPE command, and set
   12391             :              * length and alignment with direct UPDATE to the catalogs
   12392             :              * afterwards. See similar code in dumpTableSchema().
   12393             :              */
   12394           4 :             appendPQExpBuffer(q, "%s INTEGER /* dummy */", fmtId(attname));
   12395             : 
   12396             :             /* stash separately for insertion after the CREATE TYPE */
   12397           4 :             appendPQExpBufferStr(dropped,
   12398             :                                  "\n-- For binary upgrade, recreate dropped column.\n");
   12399           4 :             appendPQExpBuffer(dropped, "UPDATE pg_catalog.pg_attribute\n"
   12400             :                               "SET attlen = %s, "
   12401             :                               "attalign = '%s', attbyval = false\n"
   12402             :                               "WHERE attname = ", attlen, attalign);
   12403           4 :             appendStringLiteralAH(dropped, attname, fout);
   12404           4 :             appendPQExpBufferStr(dropped, "\n  AND attrelid = ");
   12405           4 :             appendStringLiteralAH(dropped, qualtypname, fout);
   12406           4 :             appendPQExpBufferStr(dropped, "::pg_catalog.regclass;\n");
   12407             : 
   12408           4 :             appendPQExpBuffer(dropped, "ALTER TYPE %s ",
   12409             :                               qualtypname);
   12410           4 :             appendPQExpBuffer(dropped, "DROP ATTRIBUTE %s;\n",
   12411             :                               fmtId(attname));
   12412             :         }
   12413             :     }
   12414         268 :     appendPQExpBufferStr(q, "\n);\n");
   12415         268 :     appendPQExpBufferStr(q, dropped->data);
   12416             : 
   12417         268 :     appendPQExpBuffer(delq, "DROP TYPE %s;\n", qualtypname);
   12418             : 
   12419         268 :     if (dopt->binary_upgrade)
   12420          36 :         binary_upgrade_extension_member(q, &tyinfo->dobj,
   12421             :                                         "TYPE", qtypname,
   12422          36 :                                         tyinfo->dobj.namespace->dobj.name);
   12423             : 
   12424         268 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   12425         234 :         ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
   12426         234 :                      ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
   12427             :                                   .namespace = tyinfo->dobj.namespace->dobj.name,
   12428             :                                   .owner = tyinfo->rolname,
   12429             :                                   .description = "TYPE",
   12430             :                                   .section = SECTION_PRE_DATA,
   12431             :                                   .createStmt = q->data,
   12432             :                                   .dropStmt = delq->data));
   12433             : 
   12434             : 
   12435             :     /* Dump Type Comments and Security Labels */
   12436         268 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   12437          72 :         dumpComment(fout, "TYPE", qtypname,
   12438          72 :                     tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
   12439             :                     tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
   12440             : 
   12441         268 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
   12442           0 :         dumpSecLabel(fout, "TYPE", qtypname,
   12443           0 :                      tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
   12444             :                      tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
   12445             : 
   12446         268 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
   12447          36 :         dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
   12448             :                 qtypname, NULL,
   12449          36 :                 tyinfo->dobj.namespace->dobj.name,
   12450             :                 NULL, tyinfo->rolname, &tyinfo->dacl);
   12451             : 
   12452             :     /* Dump any per-column comments */
   12453         268 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   12454          72 :         dumpCompositeTypeColComments(fout, tyinfo, res);
   12455             : 
   12456         268 :     PQclear(res);
   12457         268 :     destroyPQExpBuffer(q);
   12458         268 :     destroyPQExpBuffer(dropped);
   12459         268 :     destroyPQExpBuffer(delq);
   12460         268 :     destroyPQExpBuffer(query);
   12461         268 :     free(qtypname);
   12462         268 :     free(qualtypname);
   12463         268 : }
   12464             : 
   12465             : /*
   12466             :  * dumpCompositeTypeColComments
   12467             :  *    writes out to fout the queries to recreate comments on the columns of
   12468             :  *    a user-defined stand-alone composite type.
   12469             :  *
   12470             :  * The caller has already made a query to collect the names and attnums
   12471             :  * of the type's columns, so we just pass that result into here rather
   12472             :  * than reading them again.
   12473             :  */
   12474             : static void
   12475          72 : dumpCompositeTypeColComments(Archive *fout, const TypeInfo *tyinfo,
   12476             :                              PGresult *res)
   12477             : {
   12478             :     CommentItem *comments;
   12479             :     int         ncomments;
   12480             :     PQExpBuffer query;
   12481             :     PQExpBuffer target;
   12482             :     int         i;
   12483             :     int         ntups;
   12484             :     int         i_attname;
   12485             :     int         i_attnum;
   12486             :     int         i_attisdropped;
   12487             : 
   12488             :     /* do nothing, if --no-comments is supplied */
   12489          72 :     if (fout->dopt->no_comments)
   12490           0 :         return;
   12491             : 
   12492             :     /* Search for comments associated with type's pg_class OID */
   12493          72 :     ncomments = findComments(RelationRelationId, tyinfo->typrelid,
   12494             :                              &comments);
   12495             : 
   12496             :     /* If no comments exist, we're done */
   12497          72 :     if (ncomments <= 0)
   12498           0 :         return;
   12499             : 
   12500             :     /* Build COMMENT ON statements */
   12501          72 :     query = createPQExpBuffer();
   12502          72 :     target = createPQExpBuffer();
   12503             : 
   12504          72 :     ntups = PQntuples(res);
   12505          72 :     i_attnum = PQfnumber(res, "attnum");
   12506          72 :     i_attname = PQfnumber(res, "attname");
   12507          72 :     i_attisdropped = PQfnumber(res, "attisdropped");
   12508         144 :     while (ncomments > 0)
   12509             :     {
   12510             :         const char *attname;
   12511             : 
   12512          72 :         attname = NULL;
   12513          72 :         for (i = 0; i < ntups; i++)
   12514             :         {
   12515          72 :             if (atoi(PQgetvalue(res, i, i_attnum)) == comments->objsubid &&
   12516          72 :                 PQgetvalue(res, i, i_attisdropped)[0] != 't')
   12517             :             {
   12518          72 :                 attname = PQgetvalue(res, i, i_attname);
   12519          72 :                 break;
   12520             :             }
   12521             :         }
   12522          72 :         if (attname)            /* just in case we don't find it */
   12523             :         {
   12524          72 :             const char *descr = comments->descr;
   12525             : 
   12526          72 :             resetPQExpBuffer(target);
   12527          72 :             appendPQExpBuffer(target, "COLUMN %s.",
   12528          72 :                               fmtId(tyinfo->dobj.name));
   12529          72 :             appendPQExpBufferStr(target, fmtId(attname));
   12530             : 
   12531          72 :             resetPQExpBuffer(query);
   12532          72 :             appendPQExpBuffer(query, "COMMENT ON COLUMN %s.",
   12533          72 :                               fmtQualifiedDumpable(tyinfo));
   12534          72 :             appendPQExpBuffer(query, "%s IS ", fmtId(attname));
   12535          72 :             appendStringLiteralAH(query, descr, fout);
   12536          72 :             appendPQExpBufferStr(query, ";\n");
   12537             : 
   12538          72 :             ArchiveEntry(fout, nilCatalogId, createDumpId(),
   12539          72 :                          ARCHIVE_OPTS(.tag = target->data,
   12540             :                                       .namespace = tyinfo->dobj.namespace->dobj.name,
   12541             :                                       .owner = tyinfo->rolname,
   12542             :                                       .description = "COMMENT",
   12543             :                                       .section = SECTION_NONE,
   12544             :                                       .createStmt = query->data,
   12545             :                                       .deps = &(tyinfo->dobj.dumpId),
   12546             :                                       .nDeps = 1));
   12547             :         }
   12548             : 
   12549          72 :         comments++;
   12550          72 :         ncomments--;
   12551             :     }
   12552             : 
   12553          72 :     destroyPQExpBuffer(query);
   12554          72 :     destroyPQExpBuffer(target);
   12555             : }
   12556             : 
   12557             : /*
   12558             :  * dumpShellType
   12559             :  *    writes out to fout the queries to create a shell type
   12560             :  *
   12561             :  * We dump a shell definition in advance of the I/O functions for the type.
   12562             :  */
   12563             : static void
   12564         154 : dumpShellType(Archive *fout, const ShellTypeInfo *stinfo)
   12565             : {
   12566         154 :     DumpOptions *dopt = fout->dopt;
   12567             :     PQExpBuffer q;
   12568             : 
   12569             :     /* Do nothing if not dumping schema */
   12570         154 :     if (!dopt->dumpSchema)
   12571          12 :         return;
   12572             : 
   12573         142 :     q = createPQExpBuffer();
   12574             : 
   12575             :     /*
   12576             :      * Note the lack of a DROP command for the shell type; any required DROP
   12577             :      * is driven off the base type entry, instead.  This interacts with
   12578             :      * _printTocEntry()'s use of the presence of a DROP command to decide
   12579             :      * whether an entry needs an ALTER OWNER command.  We don't want to alter
   12580             :      * the shell type's owner immediately on creation; that should happen only
   12581             :      * after it's filled in, otherwise the backend complains.
   12582             :      */
   12583             : 
   12584         142 :     if (dopt->binary_upgrade)
   12585          16 :         binary_upgrade_set_type_oids_by_type_oid(fout, q,
   12586          16 :                                                  stinfo->baseType->dobj.catId.oid,
   12587             :                                                  false, false);
   12588             : 
   12589         142 :     appendPQExpBuffer(q, "CREATE TYPE %s;\n",
   12590         142 :                       fmtQualifiedDumpable(stinfo));
   12591             : 
   12592         142 :     if (stinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   12593         142 :         ArchiveEntry(fout, stinfo->dobj.catId, stinfo->dobj.dumpId,
   12594         142 :                      ARCHIVE_OPTS(.tag = stinfo->dobj.name,
   12595             :                                   .namespace = stinfo->dobj.namespace->dobj.name,
   12596             :                                   .owner = stinfo->baseType->rolname,
   12597             :                                   .description = "SHELL TYPE",
   12598             :                                   .section = SECTION_PRE_DATA,
   12599             :                                   .createStmt = q->data));
   12600             : 
   12601         142 :     destroyPQExpBuffer(q);
   12602             : }
   12603             : 
   12604             : /*
   12605             :  * dumpProcLang
   12606             :  *        writes out to fout the queries to recreate a user-defined
   12607             :  *        procedural language
   12608             :  */
   12609             : static void
   12610         180 : dumpProcLang(Archive *fout, const ProcLangInfo *plang)
   12611             : {
   12612         180 :     DumpOptions *dopt = fout->dopt;
   12613             :     PQExpBuffer defqry;
   12614             :     PQExpBuffer delqry;
   12615             :     bool        useParams;
   12616             :     char       *qlanname;
   12617             :     FuncInfo   *funcInfo;
   12618         180 :     FuncInfo   *inlineInfo = NULL;
   12619         180 :     FuncInfo   *validatorInfo = NULL;
   12620             : 
   12621             :     /* Do nothing if not dumping schema */
   12622         180 :     if (!dopt->dumpSchema)
   12623          26 :         return;
   12624             : 
   12625             :     /*
   12626             :      * Try to find the support function(s).  It is not an error if we don't
   12627             :      * find them --- if the functions are in the pg_catalog schema, as is
   12628             :      * standard in 8.1 and up, then we won't have loaded them. (In this case
   12629             :      * we will emit a parameterless CREATE LANGUAGE command, which will
   12630             :      * require PL template knowledge in the backend to reload.)
   12631             :      */
   12632             : 
   12633         154 :     funcInfo = findFuncByOid(plang->lanplcallfoid);
   12634         154 :     if (funcInfo != NULL && !funcInfo->dobj.dump)
   12635           4 :         funcInfo = NULL;        /* treat not-dumped same as not-found */
   12636             : 
   12637         154 :     if (OidIsValid(plang->laninline))
   12638             :     {
   12639          84 :         inlineInfo = findFuncByOid(plang->laninline);
   12640          84 :         if (inlineInfo != NULL && !inlineInfo->dobj.dump)
   12641           2 :             inlineInfo = NULL;
   12642             :     }
   12643             : 
   12644         154 :     if (OidIsValid(plang->lanvalidator))
   12645             :     {
   12646          84 :         validatorInfo = findFuncByOid(plang->lanvalidator);
   12647          84 :         if (validatorInfo != NULL && !validatorInfo->dobj.dump)
   12648           2 :             validatorInfo = NULL;
   12649             :     }
   12650             : 
   12651             :     /*
   12652             :      * If the functions are dumpable then emit a complete CREATE LANGUAGE with
   12653             :      * parameters.  Otherwise, we'll write a parameterless command, which will
   12654             :      * be interpreted as CREATE EXTENSION.
   12655             :      */
   12656          68 :     useParams = (funcInfo != NULL &&
   12657         290 :                  (inlineInfo != NULL || !OidIsValid(plang->laninline)) &&
   12658          68 :                  (validatorInfo != NULL || !OidIsValid(plang->lanvalidator)));
   12659             : 
   12660         154 :     defqry = createPQExpBuffer();
   12661         154 :     delqry = createPQExpBuffer();
   12662             : 
   12663         154 :     qlanname = pg_strdup(fmtId(plang->dobj.name));
   12664             : 
   12665         154 :     appendPQExpBuffer(delqry, "DROP PROCEDURAL LANGUAGE %s;\n",
   12666             :                       qlanname);
   12667             : 
   12668         154 :     if (useParams)
   12669             :     {
   12670          68 :         appendPQExpBuffer(defqry, "CREATE %sPROCEDURAL LANGUAGE %s",
   12671          68 :                           plang->lanpltrusted ? "TRUSTED " : "",
   12672             :                           qlanname);
   12673          68 :         appendPQExpBuffer(defqry, " HANDLER %s",
   12674          68 :                           fmtQualifiedDumpable(funcInfo));
   12675          68 :         if (OidIsValid(plang->laninline))
   12676           0 :             appendPQExpBuffer(defqry, " INLINE %s",
   12677           0 :                               fmtQualifiedDumpable(inlineInfo));
   12678          68 :         if (OidIsValid(plang->lanvalidator))
   12679           0 :             appendPQExpBuffer(defqry, " VALIDATOR %s",
   12680           0 :                               fmtQualifiedDumpable(validatorInfo));
   12681             :     }
   12682             :     else
   12683             :     {
   12684             :         /*
   12685             :          * If not dumping parameters, then use CREATE OR REPLACE so that the
   12686             :          * command will not fail if the language is preinstalled in the target
   12687             :          * database.
   12688             :          *
   12689             :          * Modern servers will interpret this as CREATE EXTENSION IF NOT
   12690             :          * EXISTS; perhaps we should emit that instead?  But it might just add
   12691             :          * confusion.
   12692             :          */
   12693          86 :         appendPQExpBuffer(defqry, "CREATE OR REPLACE PROCEDURAL LANGUAGE %s",
   12694             :                           qlanname);
   12695             :     }
   12696         154 :     appendPQExpBufferStr(defqry, ";\n");
   12697             : 
   12698         154 :     if (dopt->binary_upgrade)
   12699           4 :         binary_upgrade_extension_member(defqry, &plang->dobj,
   12700             :                                         "LANGUAGE", qlanname, NULL);
   12701             : 
   12702         154 :     if (plang->dobj.dump & DUMP_COMPONENT_DEFINITION)
   12703          70 :         ArchiveEntry(fout, plang->dobj.catId, plang->dobj.dumpId,
   12704          70 :                      ARCHIVE_OPTS(.tag = plang->dobj.name,
   12705             :                                   .owner = plang->lanowner,
   12706             :                                   .description = "PROCEDURAL LANGUAGE",
   12707             :                                   .section = SECTION_PRE_DATA,
   12708             :                                   .createStmt = defqry->data,
   12709             :                                   .dropStmt = delqry->data,
   12710             :                                   ));
   12711             : 
   12712             :     /* Dump Proc Lang Comments and Security Labels */
   12713         154 :     if (plang->dobj.dump & DUMP_COMPONENT_COMMENT)
   12714           0 :         dumpComment(fout, "LANGUAGE", qlanname,
   12715             :                     NULL, plang->lanowner,
   12716             :                     plang->dobj.catId, 0, plang->dobj.dumpId);
   12717             : 
   12718         154 :     if (plang->dobj.dump & DUMP_COMPONENT_SECLABEL)
   12719           0 :         dumpSecLabel(fout, "LANGUAGE", qlanname,
   12720             :                      NULL, plang->lanowner,
   12721             :                      plang->dobj.catId, 0, plang->dobj.dumpId);
   12722             : 
   12723         154 :     if (plang->lanpltrusted && plang->dobj.dump & DUMP_COMPONENT_ACL)
   12724          84 :         dumpACL(fout, plang->dobj.dumpId, InvalidDumpId, "LANGUAGE",
   12725             :                 qlanname, NULL, NULL,
   12726             :                 NULL, plang->lanowner, &plang->dacl);
   12727             : 
   12728         154 :     free(qlanname);
   12729             : 
   12730         154 :     destroyPQExpBuffer(defqry);
   12731         154 :     destroyPQExpBuffer(delqry);
   12732             : }
   12733             : 
   12734             : /*
   12735             :  * format_function_arguments: generate function name and argument list
   12736             :  *
   12737             :  * This is used when we can rely on pg_get_function_arguments to format
   12738             :  * the argument list.  Note, however, that pg_get_function_arguments
   12739             :  * does not special-case zero-argument aggregates.
   12740             :  */
   12741             : static char *
   12742        8400 : format_function_arguments(const FuncInfo *finfo, const char *funcargs, bool is_agg)
   12743             : {
   12744             :     PQExpBufferData fn;
   12745             : 
   12746        8400 :     initPQExpBuffer(&fn);
   12747        8400 :     appendPQExpBufferStr(&fn, fmtId(finfo->dobj.name));
   12748        8400 :     if (is_agg && finfo->nargs == 0)
   12749         160 :         appendPQExpBufferStr(&fn, "(*)");
   12750             :     else
   12751        8240 :         appendPQExpBuffer(&fn, "(%s)", funcargs);
   12752        8400 :     return fn.data;
   12753             : }
   12754             : 
   12755             : /*
   12756             :  * format_function_signature: generate function name and argument list
   12757             :  *
   12758             :  * Only a minimal list of input argument types is generated; this is
   12759             :  * sufficient to reference the function, but not to define it.
   12760             :  *
   12761             :  * If honor_quotes is false then the function name is never quoted.
   12762             :  * This is appropriate for use in TOC tags, but not in SQL commands.
   12763             :  */
   12764             : static char *
   12765        4440 : format_function_signature(Archive *fout, const FuncInfo *finfo, bool honor_quotes)
   12766             : {
   12767             :     PQExpBufferData fn;
   12768             :     int         j;
   12769             : 
   12770        4440 :     initPQExpBuffer(&fn);
   12771        4440 :     if (honor_quotes)
   12772         818 :         appendPQExpBuffer(&fn, "%s(", fmtId(finfo->dobj.name));
   12773             :     else
   12774        3622 :         appendPQExpBuffer(&fn, "%s(", finfo->dobj.name);
   12775        8096 :     for (j = 0; j < finfo->nargs; j++)
   12776             :     {
   12777        3656 :         if (j > 0)
   12778         844 :             appendPQExpBufferStr(&fn, ", ");
   12779             : 
   12780        3656 :         appendPQExpBufferStr(&fn,
   12781        3656 :                              getFormattedTypeName(fout, finfo->argtypes[j],
   12782             :                                                   zeroIsError));
   12783             :     }
   12784        4440 :     appendPQExpBufferChar(&fn, ')');
   12785        4440 :     return fn.data;
   12786             : }
   12787             : 
   12788             : 
   12789             : /*
   12790             :  * dumpFunc:
   12791             :  *    dump out one function
   12792             :  */
   12793             : static void
   12794        3746 : dumpFunc(Archive *fout, const FuncInfo *finfo)
   12795             : {
   12796        3746 :     DumpOptions *dopt = fout->dopt;
   12797             :     PQExpBuffer query;
   12798             :     PQExpBuffer q;
   12799             :     PQExpBuffer delqry;
   12800             :     PQExpBuffer asPart;
   12801             :     PGresult   *res;
   12802             :     char       *funcsig;        /* identity signature */
   12803        3746 :     char       *funcfullsig = NULL; /* full signature */
   12804             :     char       *funcsig_tag;
   12805             :     char       *qual_funcsig;
   12806             :     char       *proretset;
   12807             :     char       *prosrc;
   12808             :     char       *probin;
   12809             :     char       *prosqlbody;
   12810             :     char       *funcargs;
   12811             :     char       *funciargs;
   12812             :     char       *funcresult;
   12813             :     char       *protrftypes;
   12814             :     char       *prokind;
   12815             :     char       *provolatile;
   12816             :     char       *proisstrict;
   12817             :     char       *prosecdef;
   12818             :     char       *proleakproof;
   12819             :     char       *proconfig;
   12820             :     char       *procost;
   12821             :     char       *prorows;
   12822             :     char       *prosupport;
   12823             :     char       *proparallel;
   12824             :     char       *lanname;
   12825        3746 :     char      **configitems = NULL;
   12826        3746 :     int         nconfigitems = 0;
   12827             :     const char *keyword;
   12828             : 
   12829             :     /* Do nothing if not dumping schema */
   12830        3746 :     if (!dopt->dumpSchema)
   12831         124 :         return;
   12832             : 
   12833        3622 :     query = createPQExpBuffer();
   12834        3622 :     q = createPQExpBuffer();
   12835        3622 :     delqry = createPQExpBuffer();
   12836        3622 :     asPart = createPQExpBuffer();
   12837             : 
   12838        3622 :     if (!fout->is_prepared[PREPQUERY_DUMPFUNC])
   12839             :     {
   12840             :         /* Set up query for function-specific details */
   12841         130 :         appendPQExpBufferStr(query,
   12842             :                              "PREPARE dumpFunc(pg_catalog.oid) AS\n");
   12843             : 
   12844         130 :         appendPQExpBufferStr(query,
   12845             :                              "SELECT\n"
   12846             :                              "proretset,\n"
   12847             :                              "prosrc,\n"
   12848             :                              "probin,\n"
   12849             :                              "provolatile,\n"
   12850             :                              "proisstrict,\n"
   12851             :                              "prosecdef,\n"
   12852             :                              "lanname,\n"
   12853             :                              "proconfig,\n"
   12854             :                              "procost,\n"
   12855             :                              "prorows,\n"
   12856             :                              "pg_catalog.pg_get_function_arguments(p.oid) AS funcargs,\n"
   12857             :                              "pg_catalog.pg_get_function_identity_arguments(p.oid) AS funciargs,\n"
   12858             :                              "pg_catalog.pg_get_function_result(p.oid) AS funcresult,\n"
   12859             :                              "proleakproof,\n");
   12860             : 
   12861         130 :         if (fout->remoteVersion >= 90500)
   12862         130 :             appendPQExpBufferStr(query,
   12863             :                                  "array_to_string(protrftypes, ' ') AS protrftypes,\n");
   12864             :         else
   12865           0 :             appendPQExpBufferStr(query,
   12866             :                                  "NULL AS protrftypes,\n");
   12867             : 
   12868         130 :         if (fout->remoteVersion >= 90600)
   12869         130 :             appendPQExpBufferStr(query,
   12870             :                                  "proparallel,\n");
   12871             :         else
   12872           0 :             appendPQExpBufferStr(query,
   12873             :                                  "'u' AS proparallel,\n");
   12874             : 
   12875         130 :         if (fout->remoteVersion >= 110000)
   12876         130 :             appendPQExpBufferStr(query,
   12877             :                                  "prokind,\n");
   12878             :         else
   12879           0 :             appendPQExpBufferStr(query,
   12880             :                                  "CASE WHEN proiswindow THEN 'w' ELSE 'f' END AS prokind,\n");
   12881             : 
   12882         130 :         if (fout->remoteVersion >= 120000)
   12883         130 :             appendPQExpBufferStr(query,
   12884             :                                  "prosupport,\n");
   12885             :         else
   12886           0 :             appendPQExpBufferStr(query,
   12887             :                                  "'-' AS prosupport,\n");
   12888             : 
   12889         130 :         if (fout->remoteVersion >= 140000)
   12890         130 :             appendPQExpBufferStr(query,
   12891             :                                  "pg_get_function_sqlbody(p.oid) AS prosqlbody\n");
   12892             :         else
   12893           0 :             appendPQExpBufferStr(query,
   12894             :                                  "NULL AS prosqlbody\n");
   12895             : 
   12896         130 :         appendPQExpBufferStr(query,
   12897             :                              "FROM pg_catalog.pg_proc p, pg_catalog.pg_language l\n"
   12898             :                              "WHERE p.oid = $1 "
   12899             :                              "AND l.oid = p.prolang");
   12900             : 
   12901         130 :         ExecuteSqlStatement(fout, query->data);
   12902             : 
   12903         130 :         fout->is_prepared[PREPQUERY_DUMPFUNC] = true;
   12904             :     }
   12905             : 
   12906        3622 :     printfPQExpBuffer(query,
   12907             :                       "EXECUTE dumpFunc('%u')",
   12908             :                       finfo->dobj.catId.oid);
   12909             : 
   12910        3622 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   12911             : 
   12912        3622 :     proretset = PQgetvalue(res, 0, PQfnumber(res, "proretset"));
   12913        3622 :     if (PQgetisnull(res, 0, PQfnumber(res, "prosqlbody")))
   12914             :     {
   12915        3518 :         prosrc = PQgetvalue(res, 0, PQfnumber(res, "prosrc"));
   12916        3518 :         probin = PQgetvalue(res, 0, PQfnumber(res, "probin"));
   12917        3518 :         prosqlbody = NULL;
   12918             :     }
   12919             :     else
   12920             :     {
   12921         104 :         prosrc = NULL;
   12922         104 :         probin = NULL;
   12923         104 :         prosqlbody = PQgetvalue(res, 0, PQfnumber(res, "prosqlbody"));
   12924             :     }
   12925        3622 :     funcargs = PQgetvalue(res, 0, PQfnumber(res, "funcargs"));
   12926        3622 :     funciargs = PQgetvalue(res, 0, PQfnumber(res, "funciargs"));
   12927        3622 :     funcresult = PQgetvalue(res, 0, PQfnumber(res, "funcresult"));
   12928        3622 :     protrftypes = PQgetvalue(res, 0, PQfnumber(res, "protrftypes"));
   12929        3622 :     prokind = PQgetvalue(res, 0, PQfnumber(res, "prokind"));
   12930        3622 :     provolatile = PQgetvalue(res, 0, PQfnumber(res, "provolatile"));
   12931        3622 :     proisstrict = PQgetvalue(res, 0, PQfnumber(res, "proisstrict"));
   12932        3622 :     prosecdef = PQgetvalue(res, 0, PQfnumber(res, "prosecdef"));
   12933        3622 :     proleakproof = PQgetvalue(res, 0, PQfnumber(res, "proleakproof"));
   12934        3622 :     proconfig = PQgetvalue(res, 0, PQfnumber(res, "proconfig"));
   12935        3622 :     procost = PQgetvalue(res, 0, PQfnumber(res, "procost"));
   12936        3622 :     prorows = PQgetvalue(res, 0, PQfnumber(res, "prorows"));
   12937        3622 :     prosupport = PQgetvalue(res, 0, PQfnumber(res, "prosupport"));
   12938        3622 :     proparallel = PQgetvalue(res, 0, PQfnumber(res, "proparallel"));
   12939        3622 :     lanname = PQgetvalue(res, 0, PQfnumber(res, "lanname"));
   12940             : 
   12941             :     /*
   12942             :      * See backend/commands/functioncmds.c for details of how the 'AS' clause
   12943             :      * is used.
   12944             :      */
   12945        3622 :     if (prosqlbody)
   12946             :     {
   12947         104 :         appendPQExpBufferStr(asPart, prosqlbody);
   12948             :     }
   12949        3518 :     else if (probin[0] != '\0')
   12950             :     {
   12951         312 :         appendPQExpBufferStr(asPart, "AS ");
   12952         312 :         appendStringLiteralAH(asPart, probin, fout);
   12953         312 :         if (prosrc[0] != '\0')
   12954             :         {
   12955         312 :             appendPQExpBufferStr(asPart, ", ");
   12956             : 
   12957             :             /*
   12958             :              * where we have bin, use dollar quoting if allowed and src
   12959             :              * contains quote or backslash; else use regular quoting.
   12960             :              */
   12961         312 :             if (dopt->disable_dollar_quoting ||
   12962         312 :                 (strchr(prosrc, '\'') == NULL && strchr(prosrc, '\\') == NULL))
   12963         312 :                 appendStringLiteralAH(asPart, prosrc, fout);
   12964             :             else
   12965           0 :                 appendStringLiteralDQ(asPart, prosrc, NULL);
   12966             :         }
   12967             :     }
   12968             :     else
   12969             :     {
   12970        3206 :         appendPQExpBufferStr(asPart, "AS ");
   12971             :         /* with no bin, dollar quote src unconditionally if allowed */
   12972        3206 :         if (dopt->disable_dollar_quoting)
   12973           0 :             appendStringLiteralAH(asPart, prosrc, fout);
   12974             :         else
   12975        3206 :             appendStringLiteralDQ(asPart, prosrc, NULL);
   12976             :     }
   12977             : 
   12978        3622 :     if (*proconfig)
   12979             :     {
   12980          30 :         if (!parsePGArray(proconfig, &configitems, &nconfigitems))
   12981           0 :             pg_fatal("could not parse %s array", "proconfig");
   12982             :     }
   12983             :     else
   12984             :     {
   12985        3592 :         configitems = NULL;
   12986        3592 :         nconfigitems = 0;
   12987             :     }
   12988             : 
   12989        3622 :     funcfullsig = format_function_arguments(finfo, funcargs, false);
   12990        3622 :     funcsig = format_function_arguments(finfo, funciargs, false);
   12991             : 
   12992        3622 :     funcsig_tag = format_function_signature(fout, finfo, false);
   12993             : 
   12994        3622 :     qual_funcsig = psprintf("%s.%s",
   12995        3622 :                             fmtId(finfo->dobj.namespace->dobj.name),
   12996             :                             funcsig);
   12997             : 
   12998        3622 :     if (prokind[0] == PROKIND_PROCEDURE)
   12999         192 :         keyword = "PROCEDURE";
   13000             :     else
   13001        3430 :         keyword = "FUNCTION"; /* works for window functions too */
   13002             : 
   13003        3622 :     appendPQExpBuffer(delqry, "DROP %s %s;\n",
   13004             :                       keyword, qual_funcsig);
   13005             : 
   13006        7244 :     appendPQExpBuffer(q, "CREATE %s %s.%s",
   13007             :                       keyword,
   13008        3622 :                       fmtId(finfo->dobj.namespace->dobj.name),
   13009             :                       funcfullsig ? funcfullsig :
   13010             :                       funcsig);
   13011             : 
   13012        3622 :     if (prokind[0] == PROKIND_PROCEDURE)
   13013             :          /* no result type to output */ ;
   13014        3430 :     else if (funcresult)
   13015        3430 :         appendPQExpBuffer(q, " RETURNS %s", funcresult);
   13016             :     else
   13017           0 :         appendPQExpBuffer(q, " RETURNS %s%s",
   13018           0 :                           (proretset[0] == 't') ? "SETOF " : "",
   13019             :                           getFormattedTypeName(fout, finfo->prorettype,
   13020             :                                                zeroIsError));
   13021             : 
   13022        3622 :     appendPQExpBuffer(q, "\n    LANGUAGE %s", fmtId(lanname));
   13023             : 
   13024        3622 :     if (*protrftypes)
   13025             :     {
   13026           0 :         Oid        *typeids = pg_malloc(FUNC_MAX_ARGS * sizeof(Oid));
   13027             :         int         i;
   13028             : 
   13029           0 :         appendPQExpBufferStr(q, " TRANSFORM ");
   13030           0 :         parseOidArray(protrftypes, typeids, FUNC_MAX_ARGS);
   13031           0 :         for (i = 0; typeids[i]; i++)
   13032             :         {
   13033           0 :             if (i != 0)
   13034           0 :                 appendPQExpBufferStr(q, ", ");
   13035           0 :             appendPQExpBuffer(q, "FOR TYPE %s",
   13036           0 :                               getFormattedTypeName(fout, typeids[i], zeroAsNone));
   13037             :         }
   13038             : 
   13039           0 :         free(typeids);
   13040             :     }
   13041             : 
   13042        3622 :     if (prokind[0] == PROKIND_WINDOW)
   13043          10 :         appendPQExpBufferStr(q, " WINDOW");
   13044             : 
   13045        3622 :     if (provolatile[0] != PROVOLATILE_VOLATILE)
   13046             :     {
   13047         718 :         if (provolatile[0] == PROVOLATILE_IMMUTABLE)
   13048         676 :             appendPQExpBufferStr(q, " IMMUTABLE");
   13049          42 :         else if (provolatile[0] == PROVOLATILE_STABLE)
   13050          42 :             appendPQExpBufferStr(q, " STABLE");
   13051           0 :         else if (provolatile[0] != PROVOLATILE_VOLATILE)
   13052           0 :             pg_fatal("unrecognized provolatile value for function \"%s\"",
   13053             :                      finfo->dobj.name);
   13054             :     }
   13055             : 
   13056        3622 :     if (proisstrict[0] == 't')
   13057         730 :         appendPQExpBufferStr(q, " STRICT");
   13058             : 
   13059        3622 :     if (prosecdef[0] == 't')
   13060           0 :         appendPQExpBufferStr(q, " SECURITY DEFINER");
   13061             : 
   13062        3622 :     if (proleakproof[0] == 't')
   13063          20 :         appendPQExpBufferStr(q, " LEAKPROOF");
   13064             : 
   13065             :     /*
   13066             :      * COST and ROWS are emitted only if present and not default, so as not to
   13067             :      * break backwards-compatibility of the dump without need.  Keep this code
   13068             :      * in sync with the defaults in functioncmds.c.
   13069             :      */
   13070        3622 :     if (strcmp(procost, "0") != 0)
   13071             :     {
   13072        3622 :         if (strcmp(lanname, "internal") == 0 || strcmp(lanname, "c") == 0)
   13073             :         {
   13074             :             /* default cost is 1 */
   13075         802 :             if (strcmp(procost, "1") != 0)
   13076           0 :                 appendPQExpBuffer(q, " COST %s", procost);
   13077             :         }
   13078             :         else
   13079             :         {
   13080             :             /* default cost is 100 */
   13081        2820 :             if (strcmp(procost, "100") != 0)
   13082          12 :                 appendPQExpBuffer(q, " COST %s", procost);
   13083             :         }
   13084             :     }
   13085        3622 :     if (proretset[0] == 't' &&
   13086         382 :         strcmp(prorows, "0") != 0 && strcmp(prorows, "1000") != 0)
   13087           0 :         appendPQExpBuffer(q, " ROWS %s", prorows);
   13088             : 
   13089        3622 :     if (strcmp(prosupport, "-") != 0)
   13090             :     {
   13091             :         /* We rely on regprocout to provide quoting and qualification */
   13092          92 :         appendPQExpBuffer(q, " SUPPORT %s", prosupport);
   13093             :     }
   13094             : 
   13095        3622 :     if (proparallel[0] != PROPARALLEL_UNSAFE)
   13096             :     {
   13097         248 :         if (proparallel[0] == PROPARALLEL_SAFE)
   13098         238 :             appendPQExpBufferStr(q, " PARALLEL SAFE");
   13099          10 :         else if (proparallel[0] == PROPARALLEL_RESTRICTED)
   13100          10 :             appendPQExpBufferStr(q, " PARALLEL RESTRICTED");
   13101           0 :         else if (proparallel[0] != PROPARALLEL_UNSAFE)
   13102           0 :             pg_fatal("unrecognized proparallel value for function \"%s\"",
   13103             :                      finfo->dobj.name);
   13104             :     }
   13105             : 
   13106        3692 :     for (int i = 0; i < nconfigitems; i++)
   13107             :     {
   13108             :         /* we feel free to scribble on configitems[] here */
   13109          70 :         char       *configitem = configitems[i];
   13110             :         char       *pos;
   13111             : 
   13112          70 :         pos = strchr(configitem, '=');
   13113          70 :         if (pos == NULL)
   13114           0 :             continue;
   13115          70 :         *pos++ = '\0';
   13116          70 :         appendPQExpBuffer(q, "\n    SET %s TO ", fmtId(configitem));
   13117             : 
   13118             :         /*
   13119             :          * Variables that are marked GUC_LIST_QUOTE were already fully quoted
   13120             :          * by flatten_set_variable_args() before they were put into the
   13121             :          * proconfig array.  However, because the quoting rules used there
   13122             :          * aren't exactly like SQL's, we have to break the list value apart
   13123             :          * and then quote the elements as string literals.  (The elements may
   13124             :          * be double-quoted as-is, but we can't just feed them to the SQL
   13125             :          * parser; it would do the wrong thing with elements that are
   13126             :          * zero-length or longer than NAMEDATALEN.)
   13127             :          *
   13128             :          * Variables that are not so marked should just be emitted as simple
   13129             :          * string literals.  If the variable is not known to
   13130             :          * variable_is_guc_list_quote(), we'll do that; this makes it unsafe
   13131             :          * to use GUC_LIST_QUOTE for extension variables.
   13132             :          */
   13133          70 :         if (variable_is_guc_list_quote(configitem))
   13134             :         {
   13135             :             char      **namelist;
   13136             :             char      **nameptr;
   13137             : 
   13138             :             /* Parse string into list of identifiers */
   13139             :             /* this shouldn't fail really */
   13140          20 :             if (SplitGUCList(pos, ',', &namelist))
   13141             :             {
   13142          70 :                 for (nameptr = namelist; *nameptr; nameptr++)
   13143             :                 {
   13144          50 :                     if (nameptr != namelist)
   13145          30 :                         appendPQExpBufferStr(q, ", ");
   13146          50 :                     appendStringLiteralAH(q, *nameptr, fout);
   13147             :                 }
   13148             :             }
   13149          20 :             pg_free(namelist);
   13150             :         }
   13151             :         else
   13152          50 :             appendStringLiteralAH(q, pos, fout);
   13153             :     }
   13154             : 
   13155        3622 :     appendPQExpBuffer(q, "\n    %s;\n", asPart->data);
   13156             : 
   13157        3622 :     append_depends_on_extension(fout, q, &finfo->dobj,
   13158             :                                 "pg_catalog.pg_proc", keyword,
   13159             :                                 qual_funcsig);
   13160             : 
   13161        3622 :     if (dopt->binary_upgrade)
   13162         584 :         binary_upgrade_extension_member(q, &finfo->dobj,
   13163             :                                         keyword, funcsig,
   13164         584 :                                         finfo->dobj.namespace->dobj.name);
   13165             : 
   13166        3622 :     if (finfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   13167        3414 :         ArchiveEntry(fout, finfo->dobj.catId, finfo->dobj.dumpId,
   13168        3414 :                      ARCHIVE_OPTS(.tag = funcsig_tag,
   13169             :                                   .namespace = finfo->dobj.namespace->dobj.name,
   13170             :                                   .owner = finfo->rolname,
   13171             :                                   .description = keyword,
   13172             :                                   .section = finfo->postponed_def ?
   13173             :                                   SECTION_POST_DATA : SECTION_PRE_DATA,
   13174             :                                   .createStmt = q->data,
   13175             :                                   .dropStmt = delqry->data));
   13176             : 
   13177             :     /* Dump Function Comments and Security Labels */
   13178        3622 :     if (finfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   13179          18 :         dumpComment(fout, keyword, funcsig,
   13180          18 :                     finfo->dobj.namespace->dobj.name, finfo->rolname,
   13181             :                     finfo->dobj.catId, 0, finfo->dobj.dumpId);
   13182             : 
   13183        3622 :     if (finfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
   13184           0 :         dumpSecLabel(fout, keyword, funcsig,
   13185           0 :                      finfo->dobj.namespace->dobj.name, finfo->rolname,
   13186             :                      finfo->dobj.catId, 0, finfo->dobj.dumpId);
   13187             : 
   13188        3622 :     if (finfo->dobj.dump & DUMP_COMPONENT_ACL)
   13189         216 :         dumpACL(fout, finfo->dobj.dumpId, InvalidDumpId, keyword,
   13190             :                 funcsig, NULL,
   13191         216 :                 finfo->dobj.namespace->dobj.name,
   13192             :                 NULL, finfo->rolname, &finfo->dacl);
   13193             : 
   13194        3622 :     PQclear(res);
   13195             : 
   13196        3622 :     destroyPQExpBuffer(query);
   13197        3622 :     destroyPQExpBuffer(q);
   13198        3622 :     destroyPQExpBuffer(delqry);
   13199        3622 :     destroyPQExpBuffer(asPart);
   13200        3622 :     free(funcsig);
   13201        3622 :     free(funcfullsig);
   13202        3622 :     free(funcsig_tag);
   13203        3622 :     free(qual_funcsig);
   13204        3622 :     free(configitems);
   13205             : }
   13206             : 
   13207             : 
   13208             : /*
   13209             :  * Dump a user-defined cast
   13210             :  */
   13211             : static void
   13212         142 : dumpCast(Archive *fout, const CastInfo *cast)
   13213             : {
   13214         142 :     DumpOptions *dopt = fout->dopt;
   13215             :     PQExpBuffer defqry;
   13216             :     PQExpBuffer delqry;
   13217             :     PQExpBuffer labelq;
   13218             :     PQExpBuffer castargs;
   13219         142 :     FuncInfo   *funcInfo = NULL;
   13220             :     const char *sourceType;
   13221             :     const char *targetType;
   13222             : 
   13223             :     /* Do nothing if not dumping schema */
   13224         142 :     if (!dopt->dumpSchema)
   13225          12 :         return;
   13226             : 
   13227             :     /* Cannot dump if we don't have the cast function's info */
   13228         130 :     if (OidIsValid(cast->castfunc))
   13229             :     {
   13230          80 :         funcInfo = findFuncByOid(cast->castfunc);
   13231          80 :         if (funcInfo == NULL)
   13232           0 :             pg_fatal("could not find function definition for function with OID %u",
   13233             :                      cast->castfunc);
   13234             :     }
   13235             : 
   13236         130 :     defqry = createPQExpBuffer();
   13237         130 :     delqry = createPQExpBuffer();
   13238         130 :     labelq = createPQExpBuffer();
   13239         130 :     castargs = createPQExpBuffer();
   13240             : 
   13241         130 :     sourceType = getFormattedTypeName(fout, cast->castsource, zeroAsNone);
   13242         130 :     targetType = getFormattedTypeName(fout, cast->casttarget, zeroAsNone);
   13243         130 :     appendPQExpBuffer(delqry, "DROP CAST (%s AS %s);\n",
   13244             :                       sourceType, targetType);
   13245             : 
   13246         130 :     appendPQExpBuffer(defqry, "CREATE CAST (%s AS %s) ",
   13247             :                       sourceType, targetType);
   13248             : 
   13249         130 :     switch (cast->castmethod)
   13250             :     {
   13251          50 :         case COERCION_METHOD_BINARY:
   13252          50 :             appendPQExpBufferStr(defqry, "WITHOUT FUNCTION");
   13253          50 :             break;
   13254           0 :         case COERCION_METHOD_INOUT:
   13255           0 :             appendPQExpBufferStr(defqry, "WITH INOUT");
   13256           0 :             break;
   13257          80 :         case COERCION_METHOD_FUNCTION:
   13258          80 :             if (funcInfo)
   13259             :             {
   13260          80 :                 char       *fsig = format_function_signature(fout, funcInfo, true);
   13261             : 
   13262             :                 /*
   13263             :                  * Always qualify the function name (format_function_signature
   13264             :                  * won't qualify it).
   13265             :                  */
   13266          80 :                 appendPQExpBuffer(defqry, "WITH FUNCTION %s.%s",
   13267          80 :                                   fmtId(funcInfo->dobj.namespace->dobj.name), fsig);
   13268          80 :                 free(fsig);
   13269             :             }
   13270             :             else
   13271           0 :                 pg_log_warning("bogus value in pg_cast.castfunc or pg_cast.castmethod field");
   13272          80 :             break;
   13273           0 :         default:
   13274           0 :             pg_log_warning("bogus value in pg_cast.castmethod field");
   13275             :     }
   13276             : 
   13277         130 :     if (cast->castcontext == 'a')
   13278          70 :         appendPQExpBufferStr(defqry, " AS ASSIGNMENT");
   13279          60 :     else if (cast->castcontext == 'i')
   13280          20 :         appendPQExpBufferStr(defqry, " AS IMPLICIT");
   13281         130 :     appendPQExpBufferStr(defqry, ";\n");
   13282             : 
   13283         130 :     appendPQExpBuffer(labelq, "CAST (%s AS %s)",
   13284             :                       sourceType, targetType);
   13285             : 
   13286         130 :     appendPQExpBuffer(castargs, "(%s AS %s)",
   13287             :                       sourceType, targetType);
   13288             : 
   13289         130 :     if (dopt->binary_upgrade)
   13290          14 :         binary_upgrade_extension_member(defqry, &cast->dobj,
   13291          14 :                                         "CAST", castargs->data, NULL);
   13292             : 
   13293         130 :     if (cast->dobj.dump & DUMP_COMPONENT_DEFINITION)
   13294         130 :         ArchiveEntry(fout, cast->dobj.catId, cast->dobj.dumpId,
   13295         130 :                      ARCHIVE_OPTS(.tag = labelq->data,
   13296             :                                   .description = "CAST",
   13297             :                                   .section = SECTION_PRE_DATA,
   13298             :                                   .createStmt = defqry->data,
   13299             :                                   .dropStmt = delqry->data));
   13300             : 
   13301             :     /* Dump Cast Comments */
   13302         130 :     if (cast->dobj.dump & DUMP_COMPONENT_COMMENT)
   13303           0 :         dumpComment(fout, "CAST", castargs->data,
   13304             :                     NULL, "",
   13305             :                     cast->dobj.catId, 0, cast->dobj.dumpId);
   13306             : 
   13307         130 :     destroyPQExpBuffer(defqry);
   13308         130 :     destroyPQExpBuffer(delqry);
   13309         130 :     destroyPQExpBuffer(labelq);
   13310         130 :     destroyPQExpBuffer(castargs);
   13311             : }
   13312             : 
   13313             : /*
   13314             :  * Dump a transform
   13315             :  */
   13316             : static void
   13317          92 : dumpTransform(Archive *fout, const TransformInfo *transform)
   13318             : {
   13319          92 :     DumpOptions *dopt = fout->dopt;
   13320             :     PQExpBuffer defqry;
   13321             :     PQExpBuffer delqry;
   13322             :     PQExpBuffer labelq;
   13323             :     PQExpBuffer transformargs;
   13324          92 :     FuncInfo   *fromsqlFuncInfo = NULL;
   13325          92 :     FuncInfo   *tosqlFuncInfo = NULL;
   13326             :     char       *lanname;
   13327             :     const char *transformType;
   13328             : 
   13329             :     /* Do nothing if not dumping schema */
   13330          92 :     if (!dopt->dumpSchema)
   13331          12 :         return;
   13332             : 
   13333             :     /* Cannot dump if we don't have the transform functions' info */
   13334          80 :     if (OidIsValid(transform->trffromsql))
   13335             :     {
   13336          80 :         fromsqlFuncInfo = findFuncByOid(transform->trffromsql);
   13337          80 :         if (fromsqlFuncInfo == NULL)
   13338           0 :             pg_fatal("could not find function definition for function with OID %u",
   13339             :                      transform->trffromsql);
   13340             :     }
   13341          80 :     if (OidIsValid(transform->trftosql))
   13342             :     {
   13343          80 :         tosqlFuncInfo = findFuncByOid(transform->trftosql);
   13344          80 :         if (tosqlFuncInfo == NULL)
   13345           0 :             pg_fatal("could not find function definition for function with OID %u",
   13346             :                      transform->trftosql);
   13347             :     }
   13348             : 
   13349          80 :     defqry = createPQExpBuffer();
   13350          80 :     delqry = createPQExpBuffer();
   13351          80 :     labelq = createPQExpBuffer();
   13352          80 :     transformargs = createPQExpBuffer();
   13353             : 
   13354          80 :     lanname = get_language_name(fout, transform->trflang);
   13355          80 :     transformType = getFormattedTypeName(fout, transform->trftype, zeroAsNone);
   13356             : 
   13357          80 :     appendPQExpBuffer(delqry, "DROP TRANSFORM FOR %s LANGUAGE %s;\n",
   13358             :                       transformType, lanname);
   13359             : 
   13360          80 :     appendPQExpBuffer(defqry, "CREATE TRANSFORM FOR %s LANGUAGE %s (",
   13361             :                       transformType, lanname);
   13362             : 
   13363          80 :     if (!transform->trffromsql && !transform->trftosql)
   13364           0 :         pg_log_warning("bogus transform definition, at least one of trffromsql and trftosql should be nonzero");
   13365             : 
   13366          80 :     if (transform->trffromsql)
   13367             :     {
   13368          80 :         if (fromsqlFuncInfo)
   13369             :         {
   13370          80 :             char       *fsig = format_function_signature(fout, fromsqlFuncInfo, true);
   13371             : 
   13372             :             /*
   13373             :              * Always qualify the function name (format_function_signature
   13374             :              * won't qualify it).
   13375             :              */
   13376          80 :             appendPQExpBuffer(defqry, "FROM SQL WITH FUNCTION %s.%s",
   13377          80 :                               fmtId(fromsqlFuncInfo->dobj.namespace->dobj.name), fsig);
   13378          80 :             free(fsig);
   13379             :         }
   13380             :         else
   13381           0 :             pg_log_warning("bogus value in pg_transform.trffromsql field");
   13382             :     }
   13383             : 
   13384          80 :     if (transform->trftosql)
   13385             :     {
   13386          80 :         if (transform->trffromsql)
   13387          80 :             appendPQExpBufferStr(defqry, ", ");
   13388             : 
   13389          80 :         if (tosqlFuncInfo)
   13390             :         {
   13391          80 :             char       *fsig = format_function_signature(fout, tosqlFuncInfo, true);
   13392             : 
   13393             :             /*
   13394             :              * Always qualify the function name (format_function_signature
   13395             :              * won't qualify it).
   13396             :              */
   13397          80 :             appendPQExpBuffer(defqry, "TO SQL WITH FUNCTION %s.%s",
   13398          80 :                               fmtId(tosqlFuncInfo->dobj.namespace->dobj.name), fsig);
   13399          80 :             free(fsig);
   13400             :         }
   13401             :         else
   13402           0 :             pg_log_warning("bogus value in pg_transform.trftosql field");
   13403             :     }
   13404             : 
   13405          80 :     appendPQExpBufferStr(defqry, ");\n");
   13406             : 
   13407          80 :     appendPQExpBuffer(labelq, "TRANSFORM FOR %s LANGUAGE %s",
   13408             :                       transformType, lanname);
   13409             : 
   13410          80 :     appendPQExpBuffer(transformargs, "FOR %s LANGUAGE %s",
   13411             :                       transformType, lanname);
   13412             : 
   13413          80 :     if (dopt->binary_upgrade)
   13414           4 :         binary_upgrade_extension_member(defqry, &transform->dobj,
   13415           4 :                                         "TRANSFORM", transformargs->data, NULL);
   13416             : 
   13417          80 :     if (transform->dobj.dump & DUMP_COMPONENT_DEFINITION)
   13418          80 :         ArchiveEntry(fout, transform->dobj.catId, transform->dobj.dumpId,
   13419          80 :                      ARCHIVE_OPTS(.tag = labelq->data,
   13420             :                                   .description = "TRANSFORM",
   13421             :                                   .section = SECTION_PRE_DATA,
   13422             :                                   .createStmt = defqry->data,
   13423             :                                   .dropStmt = delqry->data,
   13424             :                                   .deps = transform->dobj.dependencies,
   13425             :                                   .nDeps = transform->dobj.nDeps));
   13426             : 
   13427             :     /* Dump Transform Comments */
   13428          80 :     if (transform->dobj.dump & DUMP_COMPONENT_COMMENT)
   13429           0 :         dumpComment(fout, "TRANSFORM", transformargs->data,
   13430             :                     NULL, "",
   13431             :                     transform->dobj.catId, 0, transform->dobj.dumpId);
   13432             : 
   13433          80 :     free(lanname);
   13434          80 :     destroyPQExpBuffer(defqry);
   13435          80 :     destroyPQExpBuffer(delqry);
   13436          80 :     destroyPQExpBuffer(labelq);
   13437          80 :     destroyPQExpBuffer(transformargs);
   13438             : }
   13439             : 
   13440             : 
   13441             : /*
   13442             :  * dumpOpr
   13443             :  *    write out a single operator definition
   13444             :  */
   13445             : static void
   13446        5016 : dumpOpr(Archive *fout, const OprInfo *oprinfo)
   13447             : {
   13448        5016 :     DumpOptions *dopt = fout->dopt;
   13449             :     PQExpBuffer query;
   13450             :     PQExpBuffer q;
   13451             :     PQExpBuffer delq;
   13452             :     PQExpBuffer oprid;
   13453             :     PQExpBuffer details;
   13454             :     PGresult   *res;
   13455             :     int         i_oprkind;
   13456             :     int         i_oprcode;
   13457             :     int         i_oprleft;
   13458             :     int         i_oprright;
   13459             :     int         i_oprcom;
   13460             :     int         i_oprnegate;
   13461             :     int         i_oprrest;
   13462             :     int         i_oprjoin;
   13463             :     int         i_oprcanmerge;
   13464             :     int         i_oprcanhash;
   13465             :     char       *oprkind;
   13466             :     char       *oprcode;
   13467             :     char       *oprleft;
   13468             :     char       *oprright;
   13469             :     char       *oprcom;
   13470             :     char       *oprnegate;
   13471             :     char       *oprrest;
   13472             :     char       *oprjoin;
   13473             :     char       *oprcanmerge;
   13474             :     char       *oprcanhash;
   13475             :     char       *oprregproc;
   13476             :     char       *oprref;
   13477             : 
   13478             :     /* Do nothing if not dumping schema */
   13479        5016 :     if (!dopt->dumpSchema)
   13480          12 :         return;
   13481             : 
   13482             :     /*
   13483             :      * some operators are invalid because they were the result of user
   13484             :      * defining operators before commutators exist
   13485             :      */
   13486        5004 :     if (!OidIsValid(oprinfo->oprcode))
   13487          28 :         return;
   13488             : 
   13489        4976 :     query = createPQExpBuffer();
   13490        4976 :     q = createPQExpBuffer();
   13491        4976 :     delq = createPQExpBuffer();
   13492        4976 :     oprid = createPQExpBuffer();
   13493        4976 :     details = createPQExpBuffer();
   13494             : 
   13495        4976 :     if (!fout->is_prepared[PREPQUERY_DUMPOPR])
   13496             :     {
   13497             :         /* Set up query for operator-specific details */
   13498          88 :         appendPQExpBufferStr(query,
   13499             :                              "PREPARE dumpOpr(pg_catalog.oid) AS\n"
   13500             :                              "SELECT oprkind, "
   13501             :                              "oprcode::pg_catalog.regprocedure, "
   13502             :                              "oprleft::pg_catalog.regtype, "
   13503             :                              "oprright::pg_catalog.regtype, "
   13504             :                              "oprcom, "
   13505             :                              "oprnegate, "
   13506             :                              "oprrest::pg_catalog.regprocedure, "
   13507             :                              "oprjoin::pg_catalog.regprocedure, "
   13508             :                              "oprcanmerge, oprcanhash "
   13509             :                              "FROM pg_catalog.pg_operator "
   13510             :                              "WHERE oid = $1");
   13511             : 
   13512          88 :         ExecuteSqlStatement(fout, query->data);
   13513             : 
   13514          88 :         fout->is_prepared[PREPQUERY_DUMPOPR] = true;
   13515             :     }
   13516             : 
   13517        4976 :     printfPQExpBuffer(query,
   13518             :                       "EXECUTE dumpOpr('%u')",
   13519             :                       oprinfo->dobj.catId.oid);
   13520             : 
   13521        4976 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   13522             : 
   13523        4976 :     i_oprkind = PQfnumber(res, "oprkind");
   13524        4976 :     i_oprcode = PQfnumber(res, "oprcode");
   13525        4976 :     i_oprleft = PQfnumber(res, "oprleft");
   13526        4976 :     i_oprright = PQfnumber(res, "oprright");
   13527        4976 :     i_oprcom = PQfnumber(res, "oprcom");
   13528        4976 :     i_oprnegate = PQfnumber(res, "oprnegate");
   13529        4976 :     i_oprrest = PQfnumber(res, "oprrest");
   13530        4976 :     i_oprjoin = PQfnumber(res, "oprjoin");
   13531        4976 :     i_oprcanmerge = PQfnumber(res, "oprcanmerge");
   13532        4976 :     i_oprcanhash = PQfnumber(res, "oprcanhash");
   13533             : 
   13534        4976 :     oprkind = PQgetvalue(res, 0, i_oprkind);
   13535        4976 :     oprcode = PQgetvalue(res, 0, i_oprcode);
   13536        4976 :     oprleft = PQgetvalue(res, 0, i_oprleft);
   13537        4976 :     oprright = PQgetvalue(res, 0, i_oprright);
   13538        4976 :     oprcom = PQgetvalue(res, 0, i_oprcom);
   13539        4976 :     oprnegate = PQgetvalue(res, 0, i_oprnegate);
   13540        4976 :     oprrest = PQgetvalue(res, 0, i_oprrest);
   13541        4976 :     oprjoin = PQgetvalue(res, 0, i_oprjoin);
   13542        4976 :     oprcanmerge = PQgetvalue(res, 0, i_oprcanmerge);
   13543        4976 :     oprcanhash = PQgetvalue(res, 0, i_oprcanhash);
   13544             : 
   13545             :     /* In PG14 upwards postfix operator support does not exist anymore. */
   13546        4976 :     if (strcmp(oprkind, "r") == 0)
   13547           0 :         pg_log_warning("postfix operators are not supported anymore (operator \"%s\")",
   13548             :                        oprcode);
   13549             : 
   13550        4976 :     oprregproc = convertRegProcReference(oprcode);
   13551        4976 :     if (oprregproc)
   13552             :     {
   13553        4976 :         appendPQExpBuffer(details, "    FUNCTION = %s", oprregproc);
   13554        4976 :         free(oprregproc);
   13555             :     }
   13556             : 
   13557        4976 :     appendPQExpBuffer(oprid, "%s (",
   13558             :                       oprinfo->dobj.name);
   13559             : 
   13560             :     /*
   13561             :      * right unary means there's a left arg and left unary means there's a
   13562             :      * right arg.  (Although the "r" case is dead code for PG14 and later,
   13563             :      * continue to support it in case we're dumping from an old server.)
   13564             :      */
   13565        4976 :     if (strcmp(oprkind, "r") == 0 ||
   13566        4976 :         strcmp(oprkind, "b") == 0)
   13567             :     {
   13568        4690 :         appendPQExpBuffer(details, ",\n    LEFTARG = %s", oprleft);
   13569        4690 :         appendPQExpBufferStr(oprid, oprleft);
   13570             :     }
   13571             :     else
   13572         286 :         appendPQExpBufferStr(oprid, "NONE");
   13573             : 
   13574        4976 :     if (strcmp(oprkind, "l") == 0 ||
   13575        4690 :         strcmp(oprkind, "b") == 0)
   13576             :     {
   13577        4976 :         appendPQExpBuffer(details, ",\n    RIGHTARG = %s", oprright);
   13578        4976 :         appendPQExpBuffer(oprid, ", %s)", oprright);
   13579             :     }
   13580             :     else
   13581           0 :         appendPQExpBufferStr(oprid, ", NONE)");
   13582             : 
   13583        4976 :     oprref = getFormattedOperatorName(oprcom);
   13584        4976 :     if (oprref)
   13585             :     {
   13586        3322 :         appendPQExpBuffer(details, ",\n    COMMUTATOR = %s", oprref);
   13587        3322 :         free(oprref);
   13588             :     }
   13589             : 
   13590        4976 :     oprref = getFormattedOperatorName(oprnegate);
   13591        4976 :     if (oprref)
   13592             :     {
   13593        2326 :         appendPQExpBuffer(details, ",\n    NEGATOR = %s", oprref);
   13594        2326 :         free(oprref);
   13595             :     }
   13596             : 
   13597        4976 :     if (strcmp(oprcanmerge, "t") == 0)
   13598         370 :         appendPQExpBufferStr(details, ",\n    MERGES");
   13599             : 
   13600        4976 :     if (strcmp(oprcanhash, "t") == 0)
   13601         276 :         appendPQExpBufferStr(details, ",\n    HASHES");
   13602             : 
   13603        4976 :     oprregproc = convertRegProcReference(oprrest);
   13604        4976 :     if (oprregproc)
   13605             :     {
   13606        3028 :         appendPQExpBuffer(details, ",\n    RESTRICT = %s", oprregproc);
   13607        3028 :         free(oprregproc);
   13608             :     }
   13609             : 
   13610        4976 :     oprregproc = convertRegProcReference(oprjoin);
   13611        4976 :     if (oprregproc)
   13612             :     {
   13613        3028 :         appendPQExpBuffer(details, ",\n    JOIN = %s", oprregproc);
   13614        3028 :         free(oprregproc);
   13615             :     }
   13616             : 
   13617        4976 :     appendPQExpBuffer(delq, "DROP OPERATOR %s.%s;\n",
   13618        4976 :                       fmtId(oprinfo->dobj.namespace->dobj.name),
   13619             :                       oprid->data);
   13620             : 
   13621        4976 :     appendPQExpBuffer(q, "CREATE OPERATOR %s.%s (\n%s\n);\n",
   13622        4976 :                       fmtId(oprinfo->dobj.namespace->dobj.name),
   13623             :                       oprinfo->dobj.name, details->data);
   13624             : 
   13625        4976 :     if (dopt->binary_upgrade)
   13626          24 :         binary_upgrade_extension_member(q, &oprinfo->dobj,
   13627          24 :                                         "OPERATOR", oprid->data,
   13628          24 :                                         oprinfo->dobj.namespace->dobj.name);
   13629             : 
   13630        4976 :     if (oprinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   13631        4976 :         ArchiveEntry(fout, oprinfo->dobj.catId, oprinfo->dobj.dumpId,
   13632        4976 :                      ARCHIVE_OPTS(.tag = oprinfo->dobj.name,
   13633             :                                   .namespace = oprinfo->dobj.namespace->dobj.name,
   13634             :                                   .owner = oprinfo->rolname,
   13635             :                                   .description = "OPERATOR",
   13636             :                                   .section = SECTION_PRE_DATA,
   13637             :                                   .createStmt = q->data,
   13638             :                                   .dropStmt = delq->data));
   13639             : 
   13640             :     /* Dump Operator Comments */
   13641        4976 :     if (oprinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   13642        4794 :         dumpComment(fout, "OPERATOR", oprid->data,
   13643        4794 :                     oprinfo->dobj.namespace->dobj.name, oprinfo->rolname,
   13644             :                     oprinfo->dobj.catId, 0, oprinfo->dobj.dumpId);
   13645             : 
   13646        4976 :     PQclear(res);
   13647             : 
   13648        4976 :     destroyPQExpBuffer(query);
   13649        4976 :     destroyPQExpBuffer(q);
   13650        4976 :     destroyPQExpBuffer(delq);
   13651        4976 :     destroyPQExpBuffer(oprid);
   13652        4976 :     destroyPQExpBuffer(details);
   13653             : }
   13654             : 
   13655             : /*
   13656             :  * Convert a function reference obtained from pg_operator
   13657             :  *
   13658             :  * Returns allocated string of what to print, or NULL if function references
   13659             :  * is InvalidOid. Returned string is expected to be free'd by the caller.
   13660             :  *
   13661             :  * The input is a REGPROCEDURE display; we have to strip the argument-types
   13662             :  * part.
   13663             :  */
   13664             : static char *
   13665       14928 : convertRegProcReference(const char *proc)
   13666             : {
   13667             :     char       *name;
   13668             :     char       *paren;
   13669             :     bool        inquote;
   13670             : 
   13671             :     /* In all cases "-" means a null reference */
   13672       14928 :     if (strcmp(proc, "-") == 0)
   13673        3896 :         return NULL;
   13674             : 
   13675       11032 :     name = pg_strdup(proc);
   13676             :     /* find non-double-quoted left paren */
   13677       11032 :     inquote = false;
   13678      132920 :     for (paren = name; *paren; paren++)
   13679             :     {
   13680      132920 :         if (*paren == '(' && !inquote)
   13681             :         {
   13682       11032 :             *paren = '\0';
   13683       11032 :             break;
   13684             :         }
   13685      121888 :         if (*paren == '"')
   13686         100 :             inquote = !inquote;
   13687             :     }
   13688       11032 :     return name;
   13689             : }
   13690             : 
   13691             : /*
   13692             :  * getFormattedOperatorName - retrieve the operator name for the
   13693             :  * given operator OID (presented in string form).
   13694             :  *
   13695             :  * Returns an allocated string, or NULL if the given OID is invalid.
   13696             :  * Caller is responsible for free'ing result string.
   13697             :  *
   13698             :  * What we produce has the format "OPERATOR(schema.oprname)".  This is only
   13699             :  * useful in commands where the operator's argument types can be inferred from
   13700             :  * context.  We always schema-qualify the name, though.  The predecessor to
   13701             :  * this code tried to skip the schema qualification if possible, but that led
   13702             :  * to wrong results in corner cases, such as if an operator and its negator
   13703             :  * are in different schemas.
   13704             :  */
   13705             : static char *
   13706       10530 : getFormattedOperatorName(const char *oproid)
   13707             : {
   13708             :     OprInfo    *oprInfo;
   13709             : 
   13710             :     /* In all cases "0" means a null reference */
   13711       10530 :     if (strcmp(oproid, "0") == 0)
   13712        4882 :         return NULL;
   13713             : 
   13714        5648 :     oprInfo = findOprByOid(atooid(oproid));
   13715        5648 :     if (oprInfo == NULL)
   13716             :     {
   13717           0 :         pg_log_warning("could not find operator with OID %s",
   13718             :                        oproid);
   13719           0 :         return NULL;
   13720             :     }
   13721             : 
   13722        5648 :     return psprintf("OPERATOR(%s.%s)",
   13723        5648 :                     fmtId(oprInfo->dobj.namespace->dobj.name),
   13724             :                     oprInfo->dobj.name);
   13725             : }
   13726             : 
   13727             : /*
   13728             :  * Convert a function OID obtained from pg_ts_parser or pg_ts_template
   13729             :  *
   13730             :  * It is sufficient to use REGPROC rather than REGPROCEDURE, since the
   13731             :  * argument lists of these functions are predetermined.  Note that the
   13732             :  * caller should ensure we are in the proper schema, because the results
   13733             :  * are search path dependent!
   13734             :  */
   13735             : static char *
   13736         450 : convertTSFunction(Archive *fout, Oid funcOid)
   13737             : {
   13738             :     char       *result;
   13739             :     char        query[128];
   13740             :     PGresult   *res;
   13741             : 
   13742         450 :     snprintf(query, sizeof(query),
   13743             :              "SELECT '%u'::pg_catalog.regproc", funcOid);
   13744         450 :     res = ExecuteSqlQueryForSingleRow(fout, query);
   13745             : 
   13746         450 :     result = pg_strdup(PQgetvalue(res, 0, 0));
   13747             : 
   13748         450 :     PQclear(res);
   13749             : 
   13750         450 :     return result;
   13751             : }
   13752             : 
   13753             : /*
   13754             :  * dumpAccessMethod
   13755             :  *    write out a single access method definition
   13756             :  */
   13757             : static void
   13758         176 : dumpAccessMethod(Archive *fout, const AccessMethodInfo *aminfo)
   13759             : {
   13760         176 :     DumpOptions *dopt = fout->dopt;
   13761             :     PQExpBuffer q;
   13762             :     PQExpBuffer delq;
   13763             :     char       *qamname;
   13764             : 
   13765             :     /* Do nothing if not dumping schema */
   13766         176 :     if (!dopt->dumpSchema)
   13767          24 :         return;
   13768             : 
   13769         152 :     q = createPQExpBuffer();
   13770         152 :     delq = createPQExpBuffer();
   13771             : 
   13772         152 :     qamname = pg_strdup(fmtId(aminfo->dobj.name));
   13773             : 
   13774         152 :     appendPQExpBuffer(q, "CREATE ACCESS METHOD %s ", qamname);
   13775             : 
   13776         152 :     switch (aminfo->amtype)
   13777             :     {
   13778          72 :         case AMTYPE_INDEX:
   13779          72 :             appendPQExpBufferStr(q, "TYPE INDEX ");
   13780          72 :             break;
   13781          80 :         case AMTYPE_TABLE:
   13782          80 :             appendPQExpBufferStr(q, "TYPE TABLE ");
   13783          80 :             break;
   13784           0 :         default:
   13785           0 :             pg_log_warning("invalid type \"%c\" of access method \"%s\"",
   13786             :                            aminfo->amtype, qamname);
   13787           0 :             destroyPQExpBuffer(q);
   13788           0 :             destroyPQExpBuffer(delq);
   13789           0 :             free(qamname);
   13790           0 :             return;
   13791             :     }
   13792             : 
   13793         152 :     appendPQExpBuffer(q, "HANDLER %s;\n", aminfo->amhandler);
   13794             : 
   13795         152 :     appendPQExpBuffer(delq, "DROP ACCESS METHOD %s;\n",
   13796             :                       qamname);
   13797             : 
   13798         152 :     if (dopt->binary_upgrade)
   13799           8 :         binary_upgrade_extension_member(q, &aminfo->dobj,
   13800             :                                         "ACCESS METHOD", qamname, NULL);
   13801             : 
   13802         152 :     if (aminfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   13803         152 :         ArchiveEntry(fout, aminfo->dobj.catId, aminfo->dobj.dumpId,
   13804         152 :                      ARCHIVE_OPTS(.tag = aminfo->dobj.name,
   13805             :                                   .description = "ACCESS METHOD",
   13806             :                                   .section = SECTION_PRE_DATA,
   13807             :                                   .createStmt = q->data,
   13808             :                                   .dropStmt = delq->data));
   13809             : 
   13810             :     /* Dump Access Method Comments */
   13811         152 :     if (aminfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   13812           0 :         dumpComment(fout, "ACCESS METHOD", qamname,
   13813             :                     NULL, "",
   13814             :                     aminfo->dobj.catId, 0, aminfo->dobj.dumpId);
   13815             : 
   13816         152 :     destroyPQExpBuffer(q);
   13817         152 :     destroyPQExpBuffer(delq);
   13818         152 :     free(qamname);
   13819             : }
   13820             : 
   13821             : /*
   13822             :  * dumpOpclass
   13823             :  *    write out a single operator class definition
   13824             :  */
   13825             : static void
   13826        1344 : dumpOpclass(Archive *fout, const OpclassInfo *opcinfo)
   13827             : {
   13828        1344 :     DumpOptions *dopt = fout->dopt;
   13829             :     PQExpBuffer query;
   13830             :     PQExpBuffer q;
   13831             :     PQExpBuffer delq;
   13832             :     PQExpBuffer nameusing;
   13833             :     PGresult   *res;
   13834             :     int         ntups;
   13835             :     int         i_opcintype;
   13836             :     int         i_opckeytype;
   13837             :     int         i_opcdefault;
   13838             :     int         i_opcfamily;
   13839             :     int         i_opcfamilyname;
   13840             :     int         i_opcfamilynsp;
   13841             :     int         i_amname;
   13842             :     int         i_amopstrategy;
   13843             :     int         i_amopopr;
   13844             :     int         i_sortfamily;
   13845             :     int         i_sortfamilynsp;
   13846             :     int         i_amprocnum;
   13847             :     int         i_amproc;
   13848             :     int         i_amproclefttype;
   13849             :     int         i_amprocrighttype;
   13850             :     char       *opcintype;
   13851             :     char       *opckeytype;
   13852             :     char       *opcdefault;
   13853             :     char       *opcfamily;
   13854             :     char       *opcfamilyname;
   13855             :     char       *opcfamilynsp;
   13856             :     char       *amname;
   13857             :     char       *amopstrategy;
   13858             :     char       *amopopr;
   13859             :     char       *sortfamily;
   13860             :     char       *sortfamilynsp;
   13861             :     char       *amprocnum;
   13862             :     char       *amproc;
   13863             :     char       *amproclefttype;
   13864             :     char       *amprocrighttype;
   13865             :     bool        needComma;
   13866             :     int         i;
   13867             : 
   13868             :     /* Do nothing if not dumping schema */
   13869        1344 :     if (!dopt->dumpSchema)
   13870          36 :         return;
   13871             : 
   13872        1308 :     query = createPQExpBuffer();
   13873        1308 :     q = createPQExpBuffer();
   13874        1308 :     delq = createPQExpBuffer();
   13875        1308 :     nameusing = createPQExpBuffer();
   13876             : 
   13877             :     /* Get additional fields from the pg_opclass row */
   13878        1308 :     appendPQExpBuffer(query, "SELECT opcintype::pg_catalog.regtype, "
   13879             :                       "opckeytype::pg_catalog.regtype, "
   13880             :                       "opcdefault, opcfamily, "
   13881             :                       "opfname AS opcfamilyname, "
   13882             :                       "nspname AS opcfamilynsp, "
   13883             :                       "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opcmethod) AS amname "
   13884             :                       "FROM pg_catalog.pg_opclass c "
   13885             :                       "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = opcfamily "
   13886             :                       "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
   13887             :                       "WHERE c.oid = '%u'::pg_catalog.oid",
   13888             :                       opcinfo->dobj.catId.oid);
   13889             : 
   13890        1308 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   13891             : 
   13892        1308 :     i_opcintype = PQfnumber(res, "opcintype");
   13893        1308 :     i_opckeytype = PQfnumber(res, "opckeytype");
   13894        1308 :     i_opcdefault = PQfnumber(res, "opcdefault");
   13895        1308 :     i_opcfamily = PQfnumber(res, "opcfamily");
   13896        1308 :     i_opcfamilyname = PQfnumber(res, "opcfamilyname");
   13897        1308 :     i_opcfamilynsp = PQfnumber(res, "opcfamilynsp");
   13898        1308 :     i_amname = PQfnumber(res, "amname");
   13899             : 
   13900             :     /* opcintype may still be needed after we PQclear res */
   13901        1308 :     opcintype = pg_strdup(PQgetvalue(res, 0, i_opcintype));
   13902        1308 :     opckeytype = PQgetvalue(res, 0, i_opckeytype);
   13903        1308 :     opcdefault = PQgetvalue(res, 0, i_opcdefault);
   13904             :     /* opcfamily will still be needed after we PQclear res */
   13905        1308 :     opcfamily = pg_strdup(PQgetvalue(res, 0, i_opcfamily));
   13906        1308 :     opcfamilyname = PQgetvalue(res, 0, i_opcfamilyname);
   13907        1308 :     opcfamilynsp = PQgetvalue(res, 0, i_opcfamilynsp);
   13908             :     /* amname will still be needed after we PQclear res */
   13909        1308 :     amname = pg_strdup(PQgetvalue(res, 0, i_amname));
   13910             : 
   13911        1308 :     appendPQExpBuffer(delq, "DROP OPERATOR CLASS %s",
   13912        1308 :                       fmtQualifiedDumpable(opcinfo));
   13913        1308 :     appendPQExpBuffer(delq, " USING %s;\n",
   13914             :                       fmtId(amname));
   13915             : 
   13916             :     /* Build the fixed portion of the CREATE command */
   13917        1308 :     appendPQExpBuffer(q, "CREATE OPERATOR CLASS %s\n    ",
   13918        1308 :                       fmtQualifiedDumpable(opcinfo));
   13919        1308 :     if (strcmp(opcdefault, "t") == 0)
   13920         714 :         appendPQExpBufferStr(q, "DEFAULT ");
   13921        1308 :     appendPQExpBuffer(q, "FOR TYPE %s USING %s",
   13922             :                       opcintype,
   13923             :                       fmtId(amname));
   13924        1308 :     if (strlen(opcfamilyname) > 0)
   13925             :     {
   13926        1308 :         appendPQExpBufferStr(q, " FAMILY ");
   13927        1308 :         appendPQExpBuffer(q, "%s.", fmtId(opcfamilynsp));
   13928        1308 :         appendPQExpBufferStr(q, fmtId(opcfamilyname));
   13929             :     }
   13930        1308 :     appendPQExpBufferStr(q, " AS\n    ");
   13931             : 
   13932        1308 :     needComma = false;
   13933             : 
   13934        1308 :     if (strcmp(opckeytype, "-") != 0)
   13935             :     {
   13936         504 :         appendPQExpBuffer(q, "STORAGE %s",
   13937             :                           opckeytype);
   13938         504 :         needComma = true;
   13939             :     }
   13940             : 
   13941        1308 :     PQclear(res);
   13942             : 
   13943             :     /*
   13944             :      * Now fetch and print the OPERATOR entries (pg_amop rows).
   13945             :      *
   13946             :      * Print only those opfamily members that are tied to the opclass by
   13947             :      * pg_depend entries.
   13948             :      */
   13949        1308 :     resetPQExpBuffer(query);
   13950        1308 :     appendPQExpBuffer(query, "SELECT amopstrategy, "
   13951             :                       "amopopr::pg_catalog.regoperator, "
   13952             :                       "opfname AS sortfamily, "
   13953             :                       "nspname AS sortfamilynsp "
   13954             :                       "FROM pg_catalog.pg_amop ao JOIN pg_catalog.pg_depend ON "
   13955             :                       "(classid = 'pg_catalog.pg_amop'::pg_catalog.regclass AND objid = ao.oid) "
   13956             :                       "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = amopsortfamily "
   13957             :                       "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
   13958             :                       "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
   13959             :                       "AND refobjid = '%u'::pg_catalog.oid "
   13960             :                       "AND amopfamily = '%s'::pg_catalog.oid "
   13961             :                       "ORDER BY amopstrategy",
   13962             :                       opcinfo->dobj.catId.oid,
   13963             :                       opcfamily);
   13964             : 
   13965        1308 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   13966             : 
   13967        1308 :     ntups = PQntuples(res);
   13968             : 
   13969        1308 :     i_amopstrategy = PQfnumber(res, "amopstrategy");
   13970        1308 :     i_amopopr = PQfnumber(res, "amopopr");
   13971        1308 :     i_sortfamily = PQfnumber(res, "sortfamily");
   13972        1308 :     i_sortfamilynsp = PQfnumber(res, "sortfamilynsp");
   13973             : 
   13974        1760 :     for (i = 0; i < ntups; i++)
   13975             :     {
   13976         452 :         amopstrategy = PQgetvalue(res, i, i_amopstrategy);
   13977         452 :         amopopr = PQgetvalue(res, i, i_amopopr);
   13978         452 :         sortfamily = PQgetvalue(res, i, i_sortfamily);
   13979         452 :         sortfamilynsp = PQgetvalue(res, i, i_sortfamilynsp);
   13980             : 
   13981         452 :         if (needComma)
   13982         288 :             appendPQExpBufferStr(q, " ,\n    ");
   13983             : 
   13984         452 :         appendPQExpBuffer(q, "OPERATOR %s %s",
   13985             :                           amopstrategy, amopopr);
   13986             : 
   13987         452 :         if (strlen(sortfamily) > 0)
   13988             :         {
   13989           0 :             appendPQExpBufferStr(q, " FOR ORDER BY ");
   13990           0 :             appendPQExpBuffer(q, "%s.", fmtId(sortfamilynsp));
   13991           0 :             appendPQExpBufferStr(q, fmtId(sortfamily));
   13992             :         }
   13993             : 
   13994         452 :         needComma = true;
   13995             :     }
   13996             : 
   13997        1308 :     PQclear(res);
   13998             : 
   13999             :     /*
   14000             :      * Now fetch and print the FUNCTION entries (pg_amproc rows).
   14001             :      *
   14002             :      * Print only those opfamily members that are tied to the opclass by
   14003             :      * pg_depend entries.
   14004             :      *
   14005             :      * We print the amproclefttype/amprocrighttype even though in most cases
   14006             :      * the backend could deduce the right values, because of the corner case
   14007             :      * of a btree sort support function for a cross-type comparison.
   14008             :      */
   14009        1308 :     resetPQExpBuffer(query);
   14010             : 
   14011        1308 :     appendPQExpBuffer(query, "SELECT amprocnum, "
   14012             :                       "amproc::pg_catalog.regprocedure, "
   14013             :                       "amproclefttype::pg_catalog.regtype, "
   14014             :                       "amprocrighttype::pg_catalog.regtype "
   14015             :                       "FROM pg_catalog.pg_amproc ap, pg_catalog.pg_depend "
   14016             :                       "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
   14017             :                       "AND refobjid = '%u'::pg_catalog.oid "
   14018             :                       "AND classid = 'pg_catalog.pg_amproc'::pg_catalog.regclass "
   14019             :                       "AND objid = ap.oid "
   14020             :                       "ORDER BY amprocnum",
   14021             :                       opcinfo->dobj.catId.oid);
   14022             : 
   14023        1308 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   14024             : 
   14025        1308 :     ntups = PQntuples(res);
   14026             : 
   14027        1308 :     i_amprocnum = PQfnumber(res, "amprocnum");
   14028        1308 :     i_amproc = PQfnumber(res, "amproc");
   14029        1308 :     i_amproclefttype = PQfnumber(res, "amproclefttype");
   14030        1308 :     i_amprocrighttype = PQfnumber(res, "amprocrighttype");
   14031             : 
   14032        1380 :     for (i = 0; i < ntups; i++)
   14033             :     {
   14034          72 :         amprocnum = PQgetvalue(res, i, i_amprocnum);
   14035          72 :         amproc = PQgetvalue(res, i, i_amproc);
   14036          72 :         amproclefttype = PQgetvalue(res, i, i_amproclefttype);
   14037          72 :         amprocrighttype = PQgetvalue(res, i, i_amprocrighttype);
   14038             : 
   14039          72 :         if (needComma)
   14040          72 :             appendPQExpBufferStr(q, " ,\n    ");
   14041             : 
   14042          72 :         appendPQExpBuffer(q, "FUNCTION %s", amprocnum);
   14043             : 
   14044          72 :         if (*amproclefttype && *amprocrighttype)
   14045          72 :             appendPQExpBuffer(q, " (%s, %s)", amproclefttype, amprocrighttype);
   14046             : 
   14047          72 :         appendPQExpBuffer(q, " %s", amproc);
   14048             : 
   14049          72 :         needComma = true;
   14050             :     }
   14051             : 
   14052        1308 :     PQclear(res);
   14053             : 
   14054             :     /*
   14055             :      * If needComma is still false it means we haven't added anything after
   14056             :      * the AS keyword.  To avoid printing broken SQL, append a dummy STORAGE
   14057             :      * clause with the same datatype.  This isn't sanctioned by the
   14058             :      * documentation, but actually DefineOpClass will treat it as a no-op.
   14059             :      */
   14060        1308 :     if (!needComma)
   14061         640 :         appendPQExpBuffer(q, "STORAGE %s", opcintype);
   14062             : 
   14063        1308 :     appendPQExpBufferStr(q, ";\n");
   14064             : 
   14065        1308 :     appendPQExpBufferStr(nameusing, fmtId(opcinfo->dobj.name));
   14066        1308 :     appendPQExpBuffer(nameusing, " USING %s",
   14067             :                       fmtId(amname));
   14068             : 
   14069        1308 :     if (dopt->binary_upgrade)
   14070          12 :         binary_upgrade_extension_member(q, &opcinfo->dobj,
   14071          12 :                                         "OPERATOR CLASS", nameusing->data,
   14072          12 :                                         opcinfo->dobj.namespace->dobj.name);
   14073             : 
   14074        1308 :     if (opcinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   14075        1308 :         ArchiveEntry(fout, opcinfo->dobj.catId, opcinfo->dobj.dumpId,
   14076        1308 :                      ARCHIVE_OPTS(.tag = opcinfo->dobj.name,
   14077             :                                   .namespace = opcinfo->dobj.namespace->dobj.name,
   14078             :                                   .owner = opcinfo->rolname,
   14079             :                                   .description = "OPERATOR CLASS",
   14080             :                                   .section = SECTION_PRE_DATA,
   14081             :                                   .createStmt = q->data,
   14082             :                                   .dropStmt = delq->data));
   14083             : 
   14084             :     /* Dump Operator Class Comments */
   14085        1308 :     if (opcinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   14086           0 :         dumpComment(fout, "OPERATOR CLASS", nameusing->data,
   14087           0 :                     opcinfo->dobj.namespace->dobj.name, opcinfo->rolname,
   14088             :                     opcinfo->dobj.catId, 0, opcinfo->dobj.dumpId);
   14089             : 
   14090        1308 :     free(opcintype);
   14091        1308 :     free(opcfamily);
   14092        1308 :     free(amname);
   14093        1308 :     destroyPQExpBuffer(query);
   14094        1308 :     destroyPQExpBuffer(q);
   14095        1308 :     destroyPQExpBuffer(delq);
   14096        1308 :     destroyPQExpBuffer(nameusing);
   14097             : }
   14098             : 
   14099             : /*
   14100             :  * dumpOpfamily
   14101             :  *    write out a single operator family definition
   14102             :  *
   14103             :  * Note: this also dumps any "loose" operator members that aren't bound to a
   14104             :  * specific opclass within the opfamily.
   14105             :  */
   14106             : static void
   14107        1114 : dumpOpfamily(Archive *fout, const OpfamilyInfo *opfinfo)
   14108             : {
   14109        1114 :     DumpOptions *dopt = fout->dopt;
   14110             :     PQExpBuffer query;
   14111             :     PQExpBuffer q;
   14112             :     PQExpBuffer delq;
   14113             :     PQExpBuffer nameusing;
   14114             :     PGresult   *res;
   14115             :     PGresult   *res_ops;
   14116             :     PGresult   *res_procs;
   14117             :     int         ntups;
   14118             :     int         i_amname;
   14119             :     int         i_amopstrategy;
   14120             :     int         i_amopopr;
   14121             :     int         i_sortfamily;
   14122             :     int         i_sortfamilynsp;
   14123             :     int         i_amprocnum;
   14124             :     int         i_amproc;
   14125             :     int         i_amproclefttype;
   14126             :     int         i_amprocrighttype;
   14127             :     char       *amname;
   14128             :     char       *amopstrategy;
   14129             :     char       *amopopr;
   14130             :     char       *sortfamily;
   14131             :     char       *sortfamilynsp;
   14132             :     char       *amprocnum;
   14133             :     char       *amproc;
   14134             :     char       *amproclefttype;
   14135             :     char       *amprocrighttype;
   14136             :     bool        needComma;
   14137             :     int         i;
   14138             : 
   14139             :     /* Do nothing if not dumping schema */
   14140        1114 :     if (!dopt->dumpSchema)
   14141          24 :         return;
   14142             : 
   14143        1090 :     query = createPQExpBuffer();
   14144        1090 :     q = createPQExpBuffer();
   14145        1090 :     delq = createPQExpBuffer();
   14146        1090 :     nameusing = createPQExpBuffer();
   14147             : 
   14148             :     /*
   14149             :      * Fetch only those opfamily members that are tied directly to the
   14150             :      * opfamily by pg_depend entries.
   14151             :      */
   14152        1090 :     appendPQExpBuffer(query, "SELECT amopstrategy, "
   14153             :                       "amopopr::pg_catalog.regoperator, "
   14154             :                       "opfname AS sortfamily, "
   14155             :                       "nspname AS sortfamilynsp "
   14156             :                       "FROM pg_catalog.pg_amop ao JOIN pg_catalog.pg_depend ON "
   14157             :                       "(classid = 'pg_catalog.pg_amop'::pg_catalog.regclass AND objid = ao.oid) "
   14158             :                       "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = amopsortfamily "
   14159             :                       "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
   14160             :                       "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
   14161             :                       "AND refobjid = '%u'::pg_catalog.oid "
   14162             :                       "AND amopfamily = '%u'::pg_catalog.oid "
   14163             :                       "ORDER BY amopstrategy",
   14164             :                       opfinfo->dobj.catId.oid,
   14165             :                       opfinfo->dobj.catId.oid);
   14166             : 
   14167        1090 :     res_ops = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   14168             : 
   14169        1090 :     resetPQExpBuffer(query);
   14170             : 
   14171        1090 :     appendPQExpBuffer(query, "SELECT amprocnum, "
   14172             :                       "amproc::pg_catalog.regprocedure, "
   14173             :                       "amproclefttype::pg_catalog.regtype, "
   14174             :                       "amprocrighttype::pg_catalog.regtype "
   14175             :                       "FROM pg_catalog.pg_amproc ap, pg_catalog.pg_depend "
   14176             :                       "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
   14177             :                       "AND refobjid = '%u'::pg_catalog.oid "
   14178             :                       "AND classid = 'pg_catalog.pg_amproc'::pg_catalog.regclass "
   14179             :                       "AND objid = ap.oid "
   14180             :                       "ORDER BY amprocnum",
   14181             :                       opfinfo->dobj.catId.oid);
   14182             : 
   14183        1090 :     res_procs = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   14184             : 
   14185             :     /* Get additional fields from the pg_opfamily row */
   14186        1090 :     resetPQExpBuffer(query);
   14187             : 
   14188        1090 :     appendPQExpBuffer(query, "SELECT "
   14189             :                       "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opfmethod) AS amname "
   14190             :                       "FROM pg_catalog.pg_opfamily "
   14191             :                       "WHERE oid = '%u'::pg_catalog.oid",
   14192             :                       opfinfo->dobj.catId.oid);
   14193             : 
   14194        1090 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   14195             : 
   14196        1090 :     i_amname = PQfnumber(res, "amname");
   14197             : 
   14198             :     /* amname will still be needed after we PQclear res */
   14199        1090 :     amname = pg_strdup(PQgetvalue(res, 0, i_amname));
   14200             : 
   14201        1090 :     appendPQExpBuffer(delq, "DROP OPERATOR FAMILY %s",
   14202        1090 :                       fmtQualifiedDumpable(opfinfo));
   14203        1090 :     appendPQExpBuffer(delq, " USING %s;\n",
   14204             :                       fmtId(amname));
   14205             : 
   14206             :     /* Build the fixed portion of the CREATE command */
   14207        1090 :     appendPQExpBuffer(q, "CREATE OPERATOR FAMILY %s",
   14208        1090 :                       fmtQualifiedDumpable(opfinfo));
   14209        1090 :     appendPQExpBuffer(q, " USING %s;\n",
   14210             :                       fmtId(amname));
   14211             : 
   14212        1090 :     PQclear(res);
   14213             : 
   14214             :     /* Do we need an ALTER to add loose members? */
   14215        1090 :     if (PQntuples(res_ops) > 0 || PQntuples(res_procs) > 0)
   14216             :     {
   14217         102 :         appendPQExpBuffer(q, "ALTER OPERATOR FAMILY %s",
   14218         102 :                           fmtQualifiedDumpable(opfinfo));
   14219         102 :         appendPQExpBuffer(q, " USING %s ADD\n    ",
   14220             :                           fmtId(amname));
   14221             : 
   14222         102 :         needComma = false;
   14223             : 
   14224             :         /*
   14225             :          * Now fetch and print the OPERATOR entries (pg_amop rows).
   14226             :          */
   14227         102 :         ntups = PQntuples(res_ops);
   14228             : 
   14229         102 :         i_amopstrategy = PQfnumber(res_ops, "amopstrategy");
   14230         102 :         i_amopopr = PQfnumber(res_ops, "amopopr");
   14231         102 :         i_sortfamily = PQfnumber(res_ops, "sortfamily");
   14232         102 :         i_sortfamilynsp = PQfnumber(res_ops, "sortfamilynsp");
   14233             : 
   14234         462 :         for (i = 0; i < ntups; i++)
   14235             :         {
   14236         360 :             amopstrategy = PQgetvalue(res_ops, i, i_amopstrategy);
   14237         360 :             amopopr = PQgetvalue(res_ops, i, i_amopopr);
   14238         360 :             sortfamily = PQgetvalue(res_ops, i, i_sortfamily);
   14239         360 :             sortfamilynsp = PQgetvalue(res_ops, i, i_sortfamilynsp);
   14240             : 
   14241         360 :             if (needComma)
   14242         288 :                 appendPQExpBufferStr(q, " ,\n    ");
   14243             : 
   14244         360 :             appendPQExpBuffer(q, "OPERATOR %s %s",
   14245             :                               amopstrategy, amopopr);
   14246             : 
   14247         360 :             if (strlen(sortfamily) > 0)
   14248             :             {
   14249           0 :                 appendPQExpBufferStr(q, " FOR ORDER BY ");
   14250           0 :                 appendPQExpBuffer(q, "%s.", fmtId(sortfamilynsp));
   14251           0 :                 appendPQExpBufferStr(q, fmtId(sortfamily));
   14252             :             }
   14253             : 
   14254         360 :             needComma = true;
   14255             :         }
   14256             : 
   14257             :         /*
   14258             :          * Now fetch and print the FUNCTION entries (pg_amproc rows).
   14259             :          */
   14260         102 :         ntups = PQntuples(res_procs);
   14261             : 
   14262         102 :         i_amprocnum = PQfnumber(res_procs, "amprocnum");
   14263         102 :         i_amproc = PQfnumber(res_procs, "amproc");
   14264         102 :         i_amproclefttype = PQfnumber(res_procs, "amproclefttype");
   14265         102 :         i_amprocrighttype = PQfnumber(res_procs, "amprocrighttype");
   14266             : 
   14267         492 :         for (i = 0; i < ntups; i++)
   14268             :         {
   14269         390 :             amprocnum = PQgetvalue(res_procs, i, i_amprocnum);
   14270         390 :             amproc = PQgetvalue(res_procs, i, i_amproc);
   14271         390 :             amproclefttype = PQgetvalue(res_procs, i, i_amproclefttype);
   14272         390 :             amprocrighttype = PQgetvalue(res_procs, i, i_amprocrighttype);
   14273             : 
   14274         390 :             if (needComma)
   14275         360 :                 appendPQExpBufferStr(q, " ,\n    ");
   14276             : 
   14277         390 :             appendPQExpBuffer(q, "FUNCTION %s (%s, %s) %s",
   14278             :                               amprocnum, amproclefttype, amprocrighttype,
   14279             :                               amproc);
   14280             : 
   14281         390 :             needComma = true;
   14282             :         }
   14283             : 
   14284         102 :         appendPQExpBufferStr(q, ";\n");
   14285             :     }
   14286             : 
   14287        1090 :     appendPQExpBufferStr(nameusing, fmtId(opfinfo->dobj.name));
   14288        1090 :     appendPQExpBuffer(nameusing, " USING %s",
   14289             :                       fmtId(amname));
   14290             : 
   14291        1090 :     if (dopt->binary_upgrade)
   14292          18 :         binary_upgrade_extension_member(q, &opfinfo->dobj,
   14293          18 :                                         "OPERATOR FAMILY", nameusing->data,
   14294          18 :                                         opfinfo->dobj.namespace->dobj.name);
   14295             : 
   14296        1090 :     if (opfinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   14297        1090 :         ArchiveEntry(fout, opfinfo->dobj.catId, opfinfo->dobj.dumpId,
   14298        1090 :                      ARCHIVE_OPTS(.tag = opfinfo->dobj.name,
   14299             :                                   .namespace = opfinfo->dobj.namespace->dobj.name,
   14300             :                                   .owner = opfinfo->rolname,
   14301             :                                   .description = "OPERATOR FAMILY",
   14302             :                                   .section = SECTION_PRE_DATA,
   14303             :                                   .createStmt = q->data,
   14304             :                                   .dropStmt = delq->data));
   14305             : 
   14306             :     /* Dump Operator Family Comments */
   14307        1090 :     if (opfinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   14308           0 :         dumpComment(fout, "OPERATOR FAMILY", nameusing->data,
   14309           0 :                     opfinfo->dobj.namespace->dobj.name, opfinfo->rolname,
   14310             :                     opfinfo->dobj.catId, 0, opfinfo->dobj.dumpId);
   14311             : 
   14312        1090 :     free(amname);
   14313        1090 :     PQclear(res_ops);
   14314        1090 :     PQclear(res_procs);
   14315        1090 :     destroyPQExpBuffer(query);
   14316        1090 :     destroyPQExpBuffer(q);
   14317        1090 :     destroyPQExpBuffer(delq);
   14318        1090 :     destroyPQExpBuffer(nameusing);
   14319             : }
   14320             : 
   14321             : /*
   14322             :  * dumpCollation
   14323             :  *    write out a single collation definition
   14324             :  */
   14325             : static void
   14326        4952 : dumpCollation(Archive *fout, const CollInfo *collinfo)
   14327             : {
   14328        4952 :     DumpOptions *dopt = fout->dopt;
   14329             :     PQExpBuffer query;
   14330             :     PQExpBuffer q;
   14331             :     PQExpBuffer delq;
   14332             :     char       *qcollname;
   14333             :     PGresult   *res;
   14334             :     int         i_collprovider;
   14335             :     int         i_collisdeterministic;
   14336             :     int         i_collcollate;
   14337             :     int         i_collctype;
   14338             :     int         i_colllocale;
   14339             :     int         i_collicurules;
   14340             :     const char *collprovider;
   14341             :     const char *collcollate;
   14342             :     const char *collctype;
   14343             :     const char *colllocale;
   14344             :     const char *collicurules;
   14345             : 
   14346             :     /* Do nothing if not dumping schema */
   14347        4952 :     if (!dopt->dumpSchema)
   14348          24 :         return;
   14349             : 
   14350        4928 :     query = createPQExpBuffer();
   14351        4928 :     q = createPQExpBuffer();
   14352        4928 :     delq = createPQExpBuffer();
   14353             : 
   14354        4928 :     qcollname = pg_strdup(fmtId(collinfo->dobj.name));
   14355             : 
   14356             :     /* Get collation-specific details */
   14357        4928 :     appendPQExpBufferStr(query, "SELECT ");
   14358             : 
   14359        4928 :     if (fout->remoteVersion >= 100000)
   14360        4928 :         appendPQExpBufferStr(query,
   14361             :                              "collprovider, "
   14362             :                              "collversion, ");
   14363             :     else
   14364           0 :         appendPQExpBufferStr(query,
   14365             :                              "'c' AS collprovider, "
   14366             :                              "NULL AS collversion, ");
   14367             : 
   14368        4928 :     if (fout->remoteVersion >= 120000)
   14369        4928 :         appendPQExpBufferStr(query,
   14370             :                              "collisdeterministic, ");
   14371             :     else
   14372           0 :         appendPQExpBufferStr(query,
   14373             :                              "true AS collisdeterministic, ");
   14374             : 
   14375        4928 :     if (fout->remoteVersion >= 170000)
   14376        4928 :         appendPQExpBufferStr(query,
   14377             :                              "colllocale, ");
   14378           0 :     else if (fout->remoteVersion >= 150000)
   14379           0 :         appendPQExpBufferStr(query,
   14380             :                              "colliculocale AS colllocale, ");
   14381             :     else
   14382           0 :         appendPQExpBufferStr(query,
   14383             :                              "NULL AS colllocale, ");
   14384             : 
   14385        4928 :     if (fout->remoteVersion >= 160000)
   14386        4928 :         appendPQExpBufferStr(query,
   14387             :                              "collicurules, ");
   14388             :     else
   14389           0 :         appendPQExpBufferStr(query,
   14390             :                              "NULL AS collicurules, ");
   14391             : 
   14392        4928 :     appendPQExpBuffer(query,
   14393             :                       "collcollate, "
   14394             :                       "collctype "
   14395             :                       "FROM pg_catalog.pg_collation c "
   14396             :                       "WHERE c.oid = '%u'::pg_catalog.oid",
   14397             :                       collinfo->dobj.catId.oid);
   14398             : 
   14399        4928 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   14400             : 
   14401        4928 :     i_collprovider = PQfnumber(res, "collprovider");
   14402        4928 :     i_collisdeterministic = PQfnumber(res, "collisdeterministic");
   14403        4928 :     i_collcollate = PQfnumber(res, "collcollate");
   14404        4928 :     i_collctype = PQfnumber(res, "collctype");
   14405        4928 :     i_colllocale = PQfnumber(res, "colllocale");
   14406        4928 :     i_collicurules = PQfnumber(res, "collicurules");
   14407             : 
   14408        4928 :     collprovider = PQgetvalue(res, 0, i_collprovider);
   14409             : 
   14410        4928 :     if (!PQgetisnull(res, 0, i_collcollate))
   14411         100 :         collcollate = PQgetvalue(res, 0, i_collcollate);
   14412             :     else
   14413        4828 :         collcollate = NULL;
   14414             : 
   14415        4928 :     if (!PQgetisnull(res, 0, i_collctype))
   14416         100 :         collctype = PQgetvalue(res, 0, i_collctype);
   14417             :     else
   14418        4828 :         collctype = NULL;
   14419             : 
   14420             :     /*
   14421             :      * Before version 15, collcollate and collctype were of type NAME and
   14422             :      * non-nullable. Treat empty strings as NULL for consistency.
   14423             :      */
   14424        4928 :     if (fout->remoteVersion < 150000)
   14425             :     {
   14426           0 :         if (collcollate[0] == '\0')
   14427           0 :             collcollate = NULL;
   14428           0 :         if (collctype[0] == '\0')
   14429           0 :             collctype = NULL;
   14430             :     }
   14431             : 
   14432        4928 :     if (!PQgetisnull(res, 0, i_colllocale))
   14433        4822 :         colllocale = PQgetvalue(res, 0, i_colllocale);
   14434             :     else
   14435         106 :         colllocale = NULL;
   14436             : 
   14437        4928 :     if (!PQgetisnull(res, 0, i_collicurules))
   14438           0 :         collicurules = PQgetvalue(res, 0, i_collicurules);
   14439             :     else
   14440        4928 :         collicurules = NULL;
   14441             : 
   14442        4928 :     appendPQExpBuffer(delq, "DROP COLLATION %s;\n",
   14443        4928 :                       fmtQualifiedDumpable(collinfo));
   14444             : 
   14445        4928 :     appendPQExpBuffer(q, "CREATE COLLATION %s (",
   14446        4928 :                       fmtQualifiedDumpable(collinfo));
   14447             : 
   14448        4928 :     appendPQExpBufferStr(q, "provider = ");
   14449        4928 :     if (collprovider[0] == 'b')
   14450          38 :         appendPQExpBufferStr(q, "builtin");
   14451        4890 :     else if (collprovider[0] == 'c')
   14452         100 :         appendPQExpBufferStr(q, "libc");
   14453        4790 :     else if (collprovider[0] == 'i')
   14454        4784 :         appendPQExpBufferStr(q, "icu");
   14455           6 :     else if (collprovider[0] == 'd')
   14456             :         /* to allow dumping pg_catalog; not accepted on input */
   14457           6 :         appendPQExpBufferStr(q, "default");
   14458             :     else
   14459           0 :         pg_fatal("unrecognized collation provider: %s",
   14460             :                  collprovider);
   14461             : 
   14462        4928 :     if (strcmp(PQgetvalue(res, 0, i_collisdeterministic), "f") == 0)
   14463           0 :         appendPQExpBufferStr(q, ", deterministic = false");
   14464             : 
   14465        4928 :     if (collprovider[0] == 'd')
   14466             :     {
   14467           6 :         if (collcollate || collctype || colllocale || collicurules)
   14468           0 :             pg_log_warning("invalid collation \"%s\"", qcollname);
   14469             : 
   14470             :         /* no locale -- the default collation cannot be reloaded anyway */
   14471             :     }
   14472        4922 :     else if (collprovider[0] == 'b')
   14473             :     {
   14474          38 :         if (collcollate || collctype || !colllocale || collicurules)
   14475           0 :             pg_log_warning("invalid collation \"%s\"", qcollname);
   14476             : 
   14477          38 :         appendPQExpBufferStr(q, ", locale = ");
   14478          38 :         appendStringLiteralAH(q, colllocale ? colllocale : "",
   14479             :                               fout);
   14480             :     }
   14481        4884 :     else if (collprovider[0] == 'i')
   14482             :     {
   14483        4784 :         if (fout->remoteVersion >= 150000)
   14484             :         {
   14485        4784 :             if (collcollate || collctype || !colllocale)
   14486           0 :                 pg_log_warning("invalid collation \"%s\"", qcollname);
   14487             : 
   14488        4784 :             appendPQExpBufferStr(q, ", locale = ");
   14489        4784 :             appendStringLiteralAH(q, colllocale ? colllocale : "",
   14490             :                                   fout);
   14491             :         }
   14492             :         else
   14493             :         {
   14494           0 :             if (!collcollate || !collctype || colllocale ||
   14495           0 :                 strcmp(collcollate, collctype) != 0)
   14496           0 :                 pg_log_warning("invalid collation \"%s\"", qcollname);
   14497             : 
   14498           0 :             appendPQExpBufferStr(q, ", locale = ");
   14499           0 :             appendStringLiteralAH(q, collcollate ? collcollate : "", fout);
   14500             :         }
   14501             : 
   14502        4784 :         if (collicurules)
   14503             :         {
   14504           0 :             appendPQExpBufferStr(q, ", rules = ");
   14505           0 :             appendStringLiteralAH(q, collicurules ? collicurules : "", fout);
   14506             :         }
   14507             :     }
   14508         100 :     else if (collprovider[0] == 'c')
   14509             :     {
   14510         100 :         if (colllocale || collicurules || !collcollate || !collctype)
   14511           0 :             pg_log_warning("invalid collation \"%s\"", qcollname);
   14512             : 
   14513         100 :         if (collcollate && collctype && strcmp(collcollate, collctype) == 0)
   14514             :         {
   14515         100 :             appendPQExpBufferStr(q, ", locale = ");
   14516         100 :             appendStringLiteralAH(q, collcollate ? collcollate : "", fout);
   14517             :         }
   14518             :         else
   14519             :         {
   14520           0 :             appendPQExpBufferStr(q, ", lc_collate = ");
   14521           0 :             appendStringLiteralAH(q, collcollate ? collcollate : "", fout);
   14522           0 :             appendPQExpBufferStr(q, ", lc_ctype = ");
   14523           0 :             appendStringLiteralAH(q, collctype ? collctype : "", fout);
   14524             :         }
   14525             :     }
   14526             :     else
   14527           0 :         pg_fatal("unrecognized collation provider: %s", collprovider);
   14528             : 
   14529             :     /*
   14530             :      * For binary upgrade, carry over the collation version.  For normal
   14531             :      * dump/restore, omit the version, so that it is computed upon restore.
   14532             :      */
   14533        4928 :     if (dopt->binary_upgrade)
   14534             :     {
   14535             :         int         i_collversion;
   14536             : 
   14537          10 :         i_collversion = PQfnumber(res, "collversion");
   14538          10 :         if (!PQgetisnull(res, 0, i_collversion))
   14539             :         {
   14540           8 :             appendPQExpBufferStr(q, ", version = ");
   14541           8 :             appendStringLiteralAH(q,
   14542             :                                   PQgetvalue(res, 0, i_collversion),
   14543             :                                   fout);
   14544             :         }
   14545             :     }
   14546             : 
   14547        4928 :     appendPQExpBufferStr(q, ");\n");
   14548             : 
   14549        4928 :     if (dopt->binary_upgrade)
   14550          10 :         binary_upgrade_extension_member(q, &collinfo->dobj,
   14551             :                                         "COLLATION", qcollname,
   14552          10 :                                         collinfo->dobj.namespace->dobj.name);
   14553             : 
   14554        4928 :     if (collinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   14555        4928 :         ArchiveEntry(fout, collinfo->dobj.catId, collinfo->dobj.dumpId,
   14556        4928 :                      ARCHIVE_OPTS(.tag = collinfo->dobj.name,
   14557             :                                   .namespace = collinfo->dobj.namespace->dobj.name,
   14558             :                                   .owner = collinfo->rolname,
   14559             :                                   .description = "COLLATION",
   14560             :                                   .section = SECTION_PRE_DATA,
   14561             :                                   .createStmt = q->data,
   14562             :                                   .dropStmt = delq->data));
   14563             : 
   14564             :     /* Dump Collation Comments */
   14565        4928 :     if (collinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   14566        4744 :         dumpComment(fout, "COLLATION", qcollname,
   14567        4744 :                     collinfo->dobj.namespace->dobj.name, collinfo->rolname,
   14568             :                     collinfo->dobj.catId, 0, collinfo->dobj.dumpId);
   14569             : 
   14570        4928 :     PQclear(res);
   14571             : 
   14572        4928 :     destroyPQExpBuffer(query);
   14573        4928 :     destroyPQExpBuffer(q);
   14574        4928 :     destroyPQExpBuffer(delq);
   14575        4928 :     free(qcollname);
   14576             : }
   14577             : 
   14578             : /*
   14579             :  * dumpConversion
   14580             :  *    write out a single conversion definition
   14581             :  */
   14582             : static void
   14583         852 : dumpConversion(Archive *fout, const ConvInfo *convinfo)
   14584             : {
   14585         852 :     DumpOptions *dopt = fout->dopt;
   14586             :     PQExpBuffer query;
   14587             :     PQExpBuffer q;
   14588             :     PQExpBuffer delq;
   14589             :     char       *qconvname;
   14590             :     PGresult   *res;
   14591             :     int         i_conforencoding;
   14592             :     int         i_contoencoding;
   14593             :     int         i_conproc;
   14594             :     int         i_condefault;
   14595             :     const char *conforencoding;
   14596             :     const char *contoencoding;
   14597             :     const char *conproc;
   14598             :     bool        condefault;
   14599             : 
   14600             :     /* Do nothing if not dumping schema */
   14601         852 :     if (!dopt->dumpSchema)
   14602          12 :         return;
   14603             : 
   14604         840 :     query = createPQExpBuffer();
   14605         840 :     q = createPQExpBuffer();
   14606         840 :     delq = createPQExpBuffer();
   14607             : 
   14608         840 :     qconvname = pg_strdup(fmtId(convinfo->dobj.name));
   14609             : 
   14610             :     /* Get conversion-specific details */
   14611         840 :     appendPQExpBuffer(query, "SELECT "
   14612             :                       "pg_catalog.pg_encoding_to_char(conforencoding) AS conforencoding, "
   14613             :                       "pg_catalog.pg_encoding_to_char(contoencoding) AS contoencoding, "
   14614             :                       "conproc, condefault "
   14615             :                       "FROM pg_catalog.pg_conversion c "
   14616             :                       "WHERE c.oid = '%u'::pg_catalog.oid",
   14617             :                       convinfo->dobj.catId.oid);
   14618             : 
   14619         840 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   14620             : 
   14621         840 :     i_conforencoding = PQfnumber(res, "conforencoding");
   14622         840 :     i_contoencoding = PQfnumber(res, "contoencoding");
   14623         840 :     i_conproc = PQfnumber(res, "conproc");
   14624         840 :     i_condefault = PQfnumber(res, "condefault");
   14625             : 
   14626         840 :     conforencoding = PQgetvalue(res, 0, i_conforencoding);
   14627         840 :     contoencoding = PQgetvalue(res, 0, i_contoencoding);
   14628         840 :     conproc = PQgetvalue(res, 0, i_conproc);
   14629         840 :     condefault = (PQgetvalue(res, 0, i_condefault)[0] == 't');
   14630             : 
   14631         840 :     appendPQExpBuffer(delq, "DROP CONVERSION %s;\n",
   14632         840 :                       fmtQualifiedDumpable(convinfo));
   14633             : 
   14634         840 :     appendPQExpBuffer(q, "CREATE %sCONVERSION %s FOR ",
   14635             :                       (condefault) ? "DEFAULT " : "",
   14636         840 :                       fmtQualifiedDumpable(convinfo));
   14637         840 :     appendStringLiteralAH(q, conforencoding, fout);
   14638         840 :     appendPQExpBufferStr(q, " TO ");
   14639         840 :     appendStringLiteralAH(q, contoencoding, fout);
   14640             :     /* regproc output is already sufficiently quoted */
   14641         840 :     appendPQExpBuffer(q, " FROM %s;\n", conproc);
   14642             : 
   14643         840 :     if (dopt->binary_upgrade)
   14644           2 :         binary_upgrade_extension_member(q, &convinfo->dobj,
   14645             :                                         "CONVERSION", qconvname,
   14646           2 :                                         convinfo->dobj.namespace->dobj.name);
   14647             : 
   14648         840 :     if (convinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   14649         840 :         ArchiveEntry(fout, convinfo->dobj.catId, convinfo->dobj.dumpId,
   14650         840 :                      ARCHIVE_OPTS(.tag = convinfo->dobj.name,
   14651             :                                   .namespace = convinfo->dobj.namespace->dobj.name,
   14652             :                                   .owner = convinfo->rolname,
   14653             :                                   .description = "CONVERSION",
   14654             :                                   .section = SECTION_PRE_DATA,
   14655             :                                   .createStmt = q->data,
   14656             :                                   .dropStmt = delq->data));
   14657             : 
   14658             :     /* Dump Conversion Comments */
   14659         840 :     if (convinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   14660         840 :         dumpComment(fout, "CONVERSION", qconvname,
   14661         840 :                     convinfo->dobj.namespace->dobj.name, convinfo->rolname,
   14662             :                     convinfo->dobj.catId, 0, convinfo->dobj.dumpId);
   14663             : 
   14664         840 :     PQclear(res);
   14665             : 
   14666         840 :     destroyPQExpBuffer(query);
   14667         840 :     destroyPQExpBuffer(q);
   14668         840 :     destroyPQExpBuffer(delq);
   14669         840 :     free(qconvname);
   14670             : }
   14671             : 
   14672             : /*
   14673             :  * format_aggregate_signature: generate aggregate name and argument list
   14674             :  *
   14675             :  * The argument type names are qualified if needed.  The aggregate name
   14676             :  * is never qualified.
   14677             :  */
   14678             : static char *
   14679         578 : format_aggregate_signature(const AggInfo *agginfo, Archive *fout, bool honor_quotes)
   14680             : {
   14681             :     PQExpBufferData buf;
   14682             :     int         j;
   14683             : 
   14684         578 :     initPQExpBuffer(&buf);
   14685         578 :     if (honor_quotes)
   14686           0 :         appendPQExpBufferStr(&buf, fmtId(agginfo->aggfn.dobj.name));
   14687             :     else
   14688         578 :         appendPQExpBufferStr(&buf, agginfo->aggfn.dobj.name);
   14689             : 
   14690         578 :     if (agginfo->aggfn.nargs == 0)
   14691          80 :         appendPQExpBufferStr(&buf, "(*)");
   14692             :     else
   14693             :     {
   14694         498 :         appendPQExpBufferChar(&buf, '(');
   14695        1086 :         for (j = 0; j < agginfo->aggfn.nargs; j++)
   14696         588 :             appendPQExpBuffer(&buf, "%s%s",
   14697             :                               (j > 0) ? ", " : "",
   14698             :                               getFormattedTypeName(fout,
   14699         588 :                                                    agginfo->aggfn.argtypes[j],
   14700             :                                                    zeroIsError));
   14701         498 :         appendPQExpBufferChar(&buf, ')');
   14702             :     }
   14703         578 :     return buf.data;
   14704             : }
   14705             : 
   14706             : /*
   14707             :  * dumpAgg
   14708             :  *    write out a single aggregate definition
   14709             :  */
   14710             : static void
   14711         592 : dumpAgg(Archive *fout, const AggInfo *agginfo)
   14712             : {
   14713         592 :     DumpOptions *dopt = fout->dopt;
   14714             :     PQExpBuffer query;
   14715             :     PQExpBuffer q;
   14716             :     PQExpBuffer delq;
   14717             :     PQExpBuffer details;
   14718             :     char       *aggsig;         /* identity signature */
   14719         592 :     char       *aggfullsig = NULL;  /* full signature */
   14720             :     char       *aggsig_tag;
   14721             :     PGresult   *res;
   14722             :     int         i_agginitval;
   14723             :     int         i_aggminitval;
   14724             :     const char *aggtransfn;
   14725             :     const char *aggfinalfn;
   14726             :     const char *aggcombinefn;
   14727             :     const char *aggserialfn;
   14728             :     const char *aggdeserialfn;
   14729             :     const char *aggmtransfn;
   14730             :     const char *aggminvtransfn;
   14731             :     const char *aggmfinalfn;
   14732             :     bool        aggfinalextra;
   14733             :     bool        aggmfinalextra;
   14734             :     char        aggfinalmodify;
   14735             :     char        aggmfinalmodify;
   14736             :     const char *aggsortop;
   14737             :     char       *aggsortconvop;
   14738             :     char        aggkind;
   14739             :     const char *aggtranstype;
   14740             :     const char *aggtransspace;
   14741             :     const char *aggmtranstype;
   14742             :     const char *aggmtransspace;
   14743             :     const char *agginitval;
   14744             :     const char *aggminitval;
   14745             :     const char *proparallel;
   14746             :     char        defaultfinalmodify;
   14747             : 
   14748             :     /* Do nothing if not dumping schema */
   14749         592 :     if (!dopt->dumpSchema)
   14750          14 :         return;
   14751             : 
   14752         578 :     query = createPQExpBuffer();
   14753         578 :     q = createPQExpBuffer();
   14754         578 :     delq = createPQExpBuffer();
   14755         578 :     details = createPQExpBuffer();
   14756             : 
   14757         578 :     if (!fout->is_prepared[PREPQUERY_DUMPAGG])
   14758             :     {
   14759             :         /* Set up query for aggregate-specific details */
   14760         118 :         appendPQExpBufferStr(query,
   14761             :                              "PREPARE dumpAgg(pg_catalog.oid) AS\n");
   14762             : 
   14763         118 :         appendPQExpBufferStr(query,
   14764             :                              "SELECT "
   14765             :                              "aggtransfn,\n"
   14766             :                              "aggfinalfn,\n"
   14767             :                              "aggtranstype::pg_catalog.regtype,\n"
   14768             :                              "agginitval,\n"
   14769             :                              "aggsortop,\n"
   14770             :                              "pg_catalog.pg_get_function_arguments(p.oid) AS funcargs,\n"
   14771             :                              "pg_catalog.pg_get_function_identity_arguments(p.oid) AS funciargs,\n");
   14772             : 
   14773         118 :         if (fout->remoteVersion >= 90400)
   14774         118 :             appendPQExpBufferStr(query,
   14775             :                                  "aggkind,\n"
   14776             :                                  "aggmtransfn,\n"
   14777             :                                  "aggminvtransfn,\n"
   14778             :                                  "aggmfinalfn,\n"
   14779             :                                  "aggmtranstype::pg_catalog.regtype,\n"
   14780             :                                  "aggfinalextra,\n"
   14781             :                                  "aggmfinalextra,\n"
   14782             :                                  "aggtransspace,\n"
   14783             :                                  "aggmtransspace,\n"
   14784             :                                  "aggminitval,\n");
   14785             :         else
   14786           0 :             appendPQExpBufferStr(query,
   14787             :                                  "'n' AS aggkind,\n"
   14788             :                                  "'-' AS aggmtransfn,\n"
   14789             :                                  "'-' AS aggminvtransfn,\n"
   14790             :                                  "'-' AS aggmfinalfn,\n"
   14791             :                                  "0 AS aggmtranstype,\n"
   14792             :                                  "false AS aggfinalextra,\n"
   14793             :                                  "false AS aggmfinalextra,\n"
   14794             :                                  "0 AS aggtransspace,\n"
   14795             :                                  "0 AS aggmtransspace,\n"
   14796             :                                  "NULL AS aggminitval,\n");
   14797             : 
   14798         118 :         if (fout->remoteVersion >= 90600)
   14799         118 :             appendPQExpBufferStr(query,
   14800             :                                  "aggcombinefn,\n"
   14801             :                                  "aggserialfn,\n"
   14802             :                                  "aggdeserialfn,\n"
   14803             :                                  "proparallel,\n");
   14804             :         else
   14805           0 :             appendPQExpBufferStr(query,
   14806             :                                  "'-' AS aggcombinefn,\n"
   14807             :                                  "'-' AS aggserialfn,\n"
   14808             :                                  "'-' AS aggdeserialfn,\n"
   14809             :                                  "'u' AS proparallel,\n");
   14810             : 
   14811         118 :         if (fout->remoteVersion >= 110000)
   14812         118 :             appendPQExpBufferStr(query,
   14813             :                                  "aggfinalmodify,\n"
   14814             :                                  "aggmfinalmodify\n");
   14815             :         else
   14816           0 :             appendPQExpBufferStr(query,
   14817             :                                  "'0' AS aggfinalmodify,\n"
   14818             :                                  "'0' AS aggmfinalmodify\n");
   14819             : 
   14820         118 :         appendPQExpBufferStr(query,
   14821             :                              "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
   14822             :                              "WHERE a.aggfnoid = p.oid "
   14823             :                              "AND p.oid = $1");
   14824             : 
   14825         118 :         ExecuteSqlStatement(fout, query->data);
   14826             : 
   14827         118 :         fout->is_prepared[PREPQUERY_DUMPAGG] = true;
   14828             :     }
   14829             : 
   14830         578 :     printfPQExpBuffer(query,
   14831             :                       "EXECUTE dumpAgg('%u')",
   14832             :                       agginfo->aggfn.dobj.catId.oid);
   14833             : 
   14834         578 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   14835             : 
   14836         578 :     i_agginitval = PQfnumber(res, "agginitval");
   14837         578 :     i_aggminitval = PQfnumber(res, "aggminitval");
   14838             : 
   14839         578 :     aggtransfn = PQgetvalue(res, 0, PQfnumber(res, "aggtransfn"));
   14840         578 :     aggfinalfn = PQgetvalue(res, 0, PQfnumber(res, "aggfinalfn"));
   14841         578 :     aggcombinefn = PQgetvalue(res, 0, PQfnumber(res, "aggcombinefn"));
   14842         578 :     aggserialfn = PQgetvalue(res, 0, PQfnumber(res, "aggserialfn"));
   14843         578 :     aggdeserialfn = PQgetvalue(res, 0, PQfnumber(res, "aggdeserialfn"));
   14844         578 :     aggmtransfn = PQgetvalue(res, 0, PQfnumber(res, "aggmtransfn"));
   14845         578 :     aggminvtransfn = PQgetvalue(res, 0, PQfnumber(res, "aggminvtransfn"));
   14846         578 :     aggmfinalfn = PQgetvalue(res, 0, PQfnumber(res, "aggmfinalfn"));
   14847         578 :     aggfinalextra = (PQgetvalue(res, 0, PQfnumber(res, "aggfinalextra"))[0] == 't');
   14848         578 :     aggmfinalextra = (PQgetvalue(res, 0, PQfnumber(res, "aggmfinalextra"))[0] == 't');
   14849         578 :     aggfinalmodify = PQgetvalue(res, 0, PQfnumber(res, "aggfinalmodify"))[0];
   14850         578 :     aggmfinalmodify = PQgetvalue(res, 0, PQfnumber(res, "aggmfinalmodify"))[0];
   14851         578 :     aggsortop = PQgetvalue(res, 0, PQfnumber(res, "aggsortop"));
   14852         578 :     aggkind = PQgetvalue(res, 0, PQfnumber(res, "aggkind"))[0];
   14853         578 :     aggtranstype = PQgetvalue(res, 0, PQfnumber(res, "aggtranstype"));
   14854         578 :     aggtransspace = PQgetvalue(res, 0, PQfnumber(res, "aggtransspace"));
   14855         578 :     aggmtranstype = PQgetvalue(res, 0, PQfnumber(res, "aggmtranstype"));
   14856         578 :     aggmtransspace = PQgetvalue(res, 0, PQfnumber(res, "aggmtransspace"));
   14857         578 :     agginitval = PQgetvalue(res, 0, i_agginitval);
   14858         578 :     aggminitval = PQgetvalue(res, 0, i_aggminitval);
   14859         578 :     proparallel = PQgetvalue(res, 0, PQfnumber(res, "proparallel"));
   14860             : 
   14861             :     {
   14862             :         char       *funcargs;
   14863             :         char       *funciargs;
   14864             : 
   14865         578 :         funcargs = PQgetvalue(res, 0, PQfnumber(res, "funcargs"));
   14866         578 :         funciargs = PQgetvalue(res, 0, PQfnumber(res, "funciargs"));
   14867         578 :         aggfullsig = format_function_arguments(&agginfo->aggfn, funcargs, true);
   14868         578 :         aggsig = format_function_arguments(&agginfo->aggfn, funciargs, true);
   14869             :     }
   14870             : 
   14871         578 :     aggsig_tag = format_aggregate_signature(agginfo, fout, false);
   14872             : 
   14873             :     /* identify default modify flag for aggkind (must match DefineAggregate) */
   14874         578 :     defaultfinalmodify = (aggkind == AGGKIND_NORMAL) ? AGGMODIFY_READ_ONLY : AGGMODIFY_READ_WRITE;
   14875             :     /* replace omitted flags for old versions */
   14876         578 :     if (aggfinalmodify == '0')
   14877           0 :         aggfinalmodify = defaultfinalmodify;
   14878         578 :     if (aggmfinalmodify == '0')
   14879           0 :         aggmfinalmodify = defaultfinalmodify;
   14880             : 
   14881             :     /* regproc and regtype output is already sufficiently quoted */
   14882         578 :     appendPQExpBuffer(details, "    SFUNC = %s,\n    STYPE = %s",
   14883             :                       aggtransfn, aggtranstype);
   14884             : 
   14885         578 :     if (strcmp(aggtransspace, "0") != 0)
   14886             :     {
   14887          10 :         appendPQExpBuffer(details, ",\n    SSPACE = %s",
   14888             :                           aggtransspace);
   14889             :     }
   14890             : 
   14891         578 :     if (!PQgetisnull(res, 0, i_agginitval))
   14892             :     {
   14893         422 :         appendPQExpBufferStr(details, ",\n    INITCOND = ");
   14894         422 :         appendStringLiteralAH(details, agginitval, fout);
   14895             :     }
   14896             : 
   14897         578 :     if (strcmp(aggfinalfn, "-") != 0)
   14898             :     {
   14899         272 :         appendPQExpBuffer(details, ",\n    FINALFUNC = %s",
   14900             :                           aggfinalfn);
   14901         272 :         if (aggfinalextra)
   14902          20 :             appendPQExpBufferStr(details, ",\n    FINALFUNC_EXTRA");
   14903         272 :         if (aggfinalmodify != defaultfinalmodify)
   14904             :         {
   14905          72 :             switch (aggfinalmodify)
   14906             :             {
   14907           0 :                 case AGGMODIFY_READ_ONLY:
   14908           0 :                     appendPQExpBufferStr(details, ",\n    FINALFUNC_MODIFY = READ_ONLY");
   14909           0 :                     break;
   14910          72 :                 case AGGMODIFY_SHAREABLE:
   14911          72 :                     appendPQExpBufferStr(details, ",\n    FINALFUNC_MODIFY = SHAREABLE");
   14912          72 :                     break;
   14913           0 :                 case AGGMODIFY_READ_WRITE:
   14914           0 :                     appendPQExpBufferStr(details, ",\n    FINALFUNC_MODIFY = READ_WRITE");
   14915           0 :                     break;
   14916           0 :                 default:
   14917           0 :                     pg_fatal("unrecognized aggfinalmodify value for aggregate \"%s\"",
   14918             :                              agginfo->aggfn.dobj.name);
   14919             :                     break;
   14920             :             }
   14921         506 :         }
   14922             :     }
   14923             : 
   14924         578 :     if (strcmp(aggcombinefn, "-") != 0)
   14925           0 :         appendPQExpBuffer(details, ",\n    COMBINEFUNC = %s", aggcombinefn);
   14926             : 
   14927         578 :     if (strcmp(aggserialfn, "-") != 0)
   14928           0 :         appendPQExpBuffer(details, ",\n    SERIALFUNC = %s", aggserialfn);
   14929             : 
   14930         578 :     if (strcmp(aggdeserialfn, "-") != 0)
   14931           0 :         appendPQExpBuffer(details, ",\n    DESERIALFUNC = %s", aggdeserialfn);
   14932             : 
   14933         578 :     if (strcmp(aggmtransfn, "-") != 0)
   14934             :     {
   14935          60 :         appendPQExpBuffer(details, ",\n    MSFUNC = %s,\n    MINVFUNC = %s,\n    MSTYPE = %s",
   14936             :                           aggmtransfn,
   14937             :                           aggminvtransfn,
   14938             :                           aggmtranstype);
   14939             :     }
   14940             : 
   14941         578 :     if (strcmp(aggmtransspace, "0") != 0)
   14942             :     {
   14943           0 :         appendPQExpBuffer(details, ",\n    MSSPACE = %s",
   14944             :                           aggmtransspace);
   14945             :     }
   14946             : 
   14947         578 :     if (!PQgetisnull(res, 0, i_aggminitval))
   14948             :     {
   14949          20 :         appendPQExpBufferStr(details, ",\n    MINITCOND = ");
   14950          20 :         appendStringLiteralAH(details, aggminitval, fout);
   14951             :     }
   14952             : 
   14953         578 :     if (strcmp(aggmfinalfn, "-") != 0)
   14954             :     {
   14955           0 :         appendPQExpBuffer(details, ",\n    MFINALFUNC = %s",
   14956             :                           aggmfinalfn);
   14957           0 :         if (aggmfinalextra)
   14958           0 :             appendPQExpBufferStr(details, ",\n    MFINALFUNC_EXTRA");
   14959           0 :         if (aggmfinalmodify != defaultfinalmodify)
   14960             :         {
   14961           0 :             switch (aggmfinalmodify)
   14962             :             {
   14963           0 :                 case AGGMODIFY_READ_ONLY:
   14964           0 :                     appendPQExpBufferStr(details, ",\n    MFINALFUNC_MODIFY = READ_ONLY");
   14965           0 :                     break;
   14966           0 :                 case AGGMODIFY_SHAREABLE:
   14967           0 :                     appendPQExpBufferStr(details, ",\n    MFINALFUNC_MODIFY = SHAREABLE");
   14968           0 :                     break;
   14969           0 :                 case AGGMODIFY_READ_WRITE:
   14970           0 :                     appendPQExpBufferStr(details, ",\n    MFINALFUNC_MODIFY = READ_WRITE");
   14971           0 :                     break;
   14972           0 :                 default:
   14973           0 :                     pg_fatal("unrecognized aggmfinalmodify value for aggregate \"%s\"",
   14974             :                              agginfo->aggfn.dobj.name);
   14975             :                     break;
   14976             :             }
   14977         578 :         }
   14978             :     }
   14979             : 
   14980         578 :     aggsortconvop = getFormattedOperatorName(aggsortop);
   14981         578 :     if (aggsortconvop)
   14982             :     {
   14983           0 :         appendPQExpBuffer(details, ",\n    SORTOP = %s",
   14984             :                           aggsortconvop);
   14985           0 :         free(aggsortconvop);
   14986             :     }
   14987             : 
   14988         578 :     if (aggkind == AGGKIND_HYPOTHETICAL)
   14989          10 :         appendPQExpBufferStr(details, ",\n    HYPOTHETICAL");
   14990             : 
   14991         578 :     if (proparallel[0] != PROPARALLEL_UNSAFE)
   14992             :     {
   14993          10 :         if (proparallel[0] == PROPARALLEL_SAFE)
   14994          10 :             appendPQExpBufferStr(details, ",\n    PARALLEL = safe");
   14995           0 :         else if (proparallel[0] == PROPARALLEL_RESTRICTED)
   14996           0 :             appendPQExpBufferStr(details, ",\n    PARALLEL = restricted");
   14997           0 :         else if (proparallel[0] != PROPARALLEL_UNSAFE)
   14998           0 :             pg_fatal("unrecognized proparallel value for function \"%s\"",
   14999             :                      agginfo->aggfn.dobj.name);
   15000             :     }
   15001             : 
   15002         578 :     appendPQExpBuffer(delq, "DROP AGGREGATE %s.%s;\n",
   15003         578 :                       fmtId(agginfo->aggfn.dobj.namespace->dobj.name),
   15004             :                       aggsig);
   15005             : 
   15006        1156 :     appendPQExpBuffer(q, "CREATE AGGREGATE %s.%s (\n%s\n);\n",
   15007         578 :                       fmtId(agginfo->aggfn.dobj.namespace->dobj.name),
   15008             :                       aggfullsig ? aggfullsig : aggsig, details->data);
   15009             : 
   15010         578 :     if (dopt->binary_upgrade)
   15011          98 :         binary_upgrade_extension_member(q, &agginfo->aggfn.dobj,
   15012             :                                         "AGGREGATE", aggsig,
   15013          98 :                                         agginfo->aggfn.dobj.namespace->dobj.name);
   15014             : 
   15015         578 :     if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_DEFINITION)
   15016         544 :         ArchiveEntry(fout, agginfo->aggfn.dobj.catId,
   15017             :                      agginfo->aggfn.dobj.dumpId,
   15018         544 :                      ARCHIVE_OPTS(.tag = aggsig_tag,
   15019             :                                   .namespace = agginfo->aggfn.dobj.namespace->dobj.name,
   15020             :                                   .owner = agginfo->aggfn.rolname,
   15021             :                                   .description = "AGGREGATE",
   15022             :                                   .section = SECTION_PRE_DATA,
   15023             :                                   .createStmt = q->data,
   15024             :                                   .dropStmt = delq->data));
   15025             : 
   15026             :     /* Dump Aggregate Comments */
   15027         578 :     if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_COMMENT)
   15028          20 :         dumpComment(fout, "AGGREGATE", aggsig,
   15029          20 :                     agginfo->aggfn.dobj.namespace->dobj.name,
   15030             :                     agginfo->aggfn.rolname,
   15031             :                     agginfo->aggfn.dobj.catId, 0, agginfo->aggfn.dobj.dumpId);
   15032             : 
   15033         578 :     if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_SECLABEL)
   15034           0 :         dumpSecLabel(fout, "AGGREGATE", aggsig,
   15035           0 :                      agginfo->aggfn.dobj.namespace->dobj.name,
   15036             :                      agginfo->aggfn.rolname,
   15037             :                      agginfo->aggfn.dobj.catId, 0, agginfo->aggfn.dobj.dumpId);
   15038             : 
   15039             :     /*
   15040             :      * Since there is no GRANT ON AGGREGATE syntax, we have to make the ACL
   15041             :      * command look like a function's GRANT; in particular this affects the
   15042             :      * syntax for zero-argument aggregates and ordered-set aggregates.
   15043             :      */
   15044         578 :     free(aggsig);
   15045             : 
   15046         578 :     aggsig = format_function_signature(fout, &agginfo->aggfn, true);
   15047             : 
   15048         578 :     if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_ACL)
   15049          36 :         dumpACL(fout, agginfo->aggfn.dobj.dumpId, InvalidDumpId,
   15050             :                 "FUNCTION", aggsig, NULL,
   15051          36 :                 agginfo->aggfn.dobj.namespace->dobj.name,
   15052             :                 NULL, agginfo->aggfn.rolname, &agginfo->aggfn.dacl);
   15053             : 
   15054         578 :     free(aggsig);
   15055         578 :     free(aggfullsig);
   15056         578 :     free(aggsig_tag);
   15057             : 
   15058         578 :     PQclear(res);
   15059             : 
   15060         578 :     destroyPQExpBuffer(query);
   15061         578 :     destroyPQExpBuffer(q);
   15062         578 :     destroyPQExpBuffer(delq);
   15063         578 :     destroyPQExpBuffer(details);
   15064             : }
   15065             : 
   15066             : /*
   15067             :  * dumpTSParser
   15068             :  *    write out a single text search parser
   15069             :  */
   15070             : static void
   15071          90 : dumpTSParser(Archive *fout, const TSParserInfo *prsinfo)
   15072             : {
   15073          90 :     DumpOptions *dopt = fout->dopt;
   15074             :     PQExpBuffer q;
   15075             :     PQExpBuffer delq;
   15076             :     char       *qprsname;
   15077             : 
   15078             :     /* Do nothing if not dumping schema */
   15079          90 :     if (!dopt->dumpSchema)
   15080          12 :         return;
   15081             : 
   15082          78 :     q = createPQExpBuffer();
   15083          78 :     delq = createPQExpBuffer();
   15084             : 
   15085          78 :     qprsname = pg_strdup(fmtId(prsinfo->dobj.name));
   15086             : 
   15087          78 :     appendPQExpBuffer(q, "CREATE TEXT SEARCH PARSER %s (\n",
   15088          78 :                       fmtQualifiedDumpable(prsinfo));
   15089             : 
   15090          78 :     appendPQExpBuffer(q, "    START = %s,\n",
   15091             :                       convertTSFunction(fout, prsinfo->prsstart));
   15092          78 :     appendPQExpBuffer(q, "    GETTOKEN = %s,\n",
   15093             :                       convertTSFunction(fout, prsinfo->prstoken));
   15094          78 :     appendPQExpBuffer(q, "    END = %s,\n",
   15095             :                       convertTSFunction(fout, prsinfo->prsend));
   15096          78 :     if (prsinfo->prsheadline != InvalidOid)
   15097           6 :         appendPQExpBuffer(q, "    HEADLINE = %s,\n",
   15098             :                           convertTSFunction(fout, prsinfo->prsheadline));
   15099          78 :     appendPQExpBuffer(q, "    LEXTYPES = %s );\n",
   15100             :                       convertTSFunction(fout, prsinfo->prslextype));
   15101             : 
   15102          78 :     appendPQExpBuffer(delq, "DROP TEXT SEARCH PARSER %s;\n",
   15103          78 :                       fmtQualifiedDumpable(prsinfo));
   15104             : 
   15105          78 :     if (dopt->binary_upgrade)
   15106           2 :         binary_upgrade_extension_member(q, &prsinfo->dobj,
   15107             :                                         "TEXT SEARCH PARSER", qprsname,
   15108           2 :                                         prsinfo->dobj.namespace->dobj.name);
   15109             : 
   15110          78 :     if (prsinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   15111          78 :         ArchiveEntry(fout, prsinfo->dobj.catId, prsinfo->dobj.dumpId,
   15112          78 :                      ARCHIVE_OPTS(.tag = prsinfo->dobj.name,
   15113             :                                   .namespace = prsinfo->dobj.namespace->dobj.name,
   15114             :                                   .description = "TEXT SEARCH PARSER",
   15115             :                                   .section = SECTION_PRE_DATA,
   15116             :                                   .createStmt = q->data,
   15117             :                                   .dropStmt = delq->data));
   15118             : 
   15119             :     /* Dump Parser Comments */
   15120          78 :     if (prsinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   15121          78 :         dumpComment(fout, "TEXT SEARCH PARSER", qprsname,
   15122          78 :                     prsinfo->dobj.namespace->dobj.name, "",
   15123             :                     prsinfo->dobj.catId, 0, prsinfo->dobj.dumpId);
   15124             : 
   15125          78 :     destroyPQExpBuffer(q);
   15126          78 :     destroyPQExpBuffer(delq);
   15127          78 :     free(qprsname);
   15128             : }
   15129             : 
   15130             : /*
   15131             :  * dumpTSDictionary
   15132             :  *    write out a single text search dictionary
   15133             :  */
   15134             : static void
   15135         354 : dumpTSDictionary(Archive *fout, const TSDictInfo *dictinfo)
   15136             : {
   15137         354 :     DumpOptions *dopt = fout->dopt;
   15138             :     PQExpBuffer q;
   15139             :     PQExpBuffer delq;
   15140             :     PQExpBuffer query;
   15141             :     char       *qdictname;
   15142             :     PGresult   *res;
   15143             :     char       *nspname;
   15144             :     char       *tmplname;
   15145             : 
   15146             :     /* Do nothing if not dumping schema */
   15147         354 :     if (!dopt->dumpSchema)
   15148          12 :         return;
   15149             : 
   15150         342 :     q = createPQExpBuffer();
   15151         342 :     delq = createPQExpBuffer();
   15152         342 :     query = createPQExpBuffer();
   15153             : 
   15154         342 :     qdictname = pg_strdup(fmtId(dictinfo->dobj.name));
   15155             : 
   15156             :     /* Fetch name and namespace of the dictionary's template */
   15157         342 :     appendPQExpBuffer(query, "SELECT nspname, tmplname "
   15158             :                       "FROM pg_ts_template p, pg_namespace n "
   15159             :                       "WHERE p.oid = '%u' AND n.oid = tmplnamespace",
   15160             :                       dictinfo->dicttemplate);
   15161         342 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   15162         342 :     nspname = PQgetvalue(res, 0, 0);
   15163         342 :     tmplname = PQgetvalue(res, 0, 1);
   15164             : 
   15165         342 :     appendPQExpBuffer(q, "CREATE TEXT SEARCH DICTIONARY %s (\n",
   15166         342 :                       fmtQualifiedDumpable(dictinfo));
   15167             : 
   15168         342 :     appendPQExpBufferStr(q, "    TEMPLATE = ");
   15169         342 :     appendPQExpBuffer(q, "%s.", fmtId(nspname));
   15170         342 :     appendPQExpBufferStr(q, fmtId(tmplname));
   15171             : 
   15172         342 :     PQclear(res);
   15173             : 
   15174             :     /* the dictinitoption can be dumped straight into the command */
   15175         342 :     if (dictinfo->dictinitoption)
   15176         264 :         appendPQExpBuffer(q, ",\n    %s", dictinfo->dictinitoption);
   15177             : 
   15178         342 :     appendPQExpBufferStr(q, " );\n");
   15179             : 
   15180         342 :     appendPQExpBuffer(delq, "DROP TEXT SEARCH DICTIONARY %s;\n",
   15181         342 :                       fmtQualifiedDumpable(dictinfo));
   15182             : 
   15183         342 :     if (dopt->binary_upgrade)
   15184          20 :         binary_upgrade_extension_member(q, &dictinfo->dobj,
   15185             :                                         "TEXT SEARCH DICTIONARY", qdictname,
   15186          20 :                                         dictinfo->dobj.namespace->dobj.name);
   15187             : 
   15188         342 :     if (dictinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   15189         342 :         ArchiveEntry(fout, dictinfo->dobj.catId, dictinfo->dobj.dumpId,
   15190         342 :                      ARCHIVE_OPTS(.tag = dictinfo->dobj.name,
   15191             :                                   .namespace = dictinfo->dobj.namespace->dobj.name,
   15192             :                                   .owner = dictinfo->rolname,
   15193             :                                   .description = "TEXT SEARCH DICTIONARY",
   15194             :                                   .section = SECTION_PRE_DATA,
   15195             :                                   .createStmt = q->data,
   15196             :                                   .dropStmt = delq->data));
   15197             : 
   15198             :     /* Dump Dictionary Comments */
   15199         342 :     if (dictinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   15200         252 :         dumpComment(fout, "TEXT SEARCH DICTIONARY", qdictname,
   15201         252 :                     dictinfo->dobj.namespace->dobj.name, dictinfo->rolname,
   15202             :                     dictinfo->dobj.catId, 0, dictinfo->dobj.dumpId);
   15203             : 
   15204         342 :     destroyPQExpBuffer(q);
   15205         342 :     destroyPQExpBuffer(delq);
   15206         342 :     destroyPQExpBuffer(query);
   15207         342 :     free(qdictname);
   15208             : }
   15209             : 
   15210             : /*
   15211             :  * dumpTSTemplate
   15212             :  *    write out a single text search template
   15213             :  */
   15214             : static void
   15215         114 : dumpTSTemplate(Archive *fout, const TSTemplateInfo *tmplinfo)
   15216             : {
   15217         114 :     DumpOptions *dopt = fout->dopt;
   15218             :     PQExpBuffer q;
   15219             :     PQExpBuffer delq;
   15220             :     char       *qtmplname;
   15221             : 
   15222             :     /* Do nothing if not dumping schema */
   15223         114 :     if (!dopt->dumpSchema)
   15224          12 :         return;
   15225             : 
   15226         102 :     q = createPQExpBuffer();
   15227         102 :     delq = createPQExpBuffer();
   15228             : 
   15229         102 :     qtmplname = pg_strdup(fmtId(tmplinfo->dobj.name));
   15230             : 
   15231         102 :     appendPQExpBuffer(q, "CREATE TEXT SEARCH TEMPLATE %s (\n",
   15232         102 :                       fmtQualifiedDumpable(tmplinfo));
   15233             : 
   15234         102 :     if (tmplinfo->tmplinit != InvalidOid)
   15235          30 :         appendPQExpBuffer(q, "    INIT = %s,\n",
   15236             :                           convertTSFunction(fout, tmplinfo->tmplinit));
   15237         102 :     appendPQExpBuffer(q, "    LEXIZE = %s );\n",
   15238             :                       convertTSFunction(fout, tmplinfo->tmpllexize));
   15239             : 
   15240         102 :     appendPQExpBuffer(delq, "DROP TEXT SEARCH TEMPLATE %s;\n",
   15241         102 :                       fmtQualifiedDumpable(tmplinfo));
   15242             : 
   15243         102 :     if (dopt->binary_upgrade)
   15244           2 :         binary_upgrade_extension_member(q, &tmplinfo->dobj,
   15245             :                                         "TEXT SEARCH TEMPLATE", qtmplname,
   15246           2 :                                         tmplinfo->dobj.namespace->dobj.name);
   15247             : 
   15248         102 :     if (tmplinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   15249         102 :         ArchiveEntry(fout, tmplinfo->dobj.catId, tmplinfo->dobj.dumpId,
   15250         102 :                      ARCHIVE_OPTS(.tag = tmplinfo->dobj.name,
   15251             :                                   .namespace = tmplinfo->dobj.namespace->dobj.name,
   15252             :                                   .description = "TEXT SEARCH TEMPLATE",
   15253             :                                   .section = SECTION_PRE_DATA,
   15254             :                                   .createStmt = q->data,
   15255             :                                   .dropStmt = delq->data));
   15256             : 
   15257             :     /* Dump Template Comments */
   15258         102 :     if (tmplinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   15259         102 :         dumpComment(fout, "TEXT SEARCH TEMPLATE", qtmplname,
   15260         102 :                     tmplinfo->dobj.namespace->dobj.name, "",
   15261             :                     tmplinfo->dobj.catId, 0, tmplinfo->dobj.dumpId);
   15262             : 
   15263         102 :     destroyPQExpBuffer(q);
   15264         102 :     destroyPQExpBuffer(delq);
   15265         102 :     free(qtmplname);
   15266             : }
   15267             : 
   15268             : /*
   15269             :  * dumpTSConfig
   15270             :  *    write out a single text search configuration
   15271             :  */
   15272             : static void
   15273         304 : dumpTSConfig(Archive *fout, const TSConfigInfo *cfginfo)
   15274             : {
   15275         304 :     DumpOptions *dopt = fout->dopt;
   15276             :     PQExpBuffer q;
   15277             :     PQExpBuffer delq;
   15278             :     PQExpBuffer query;
   15279             :     char       *qcfgname;
   15280             :     PGresult   *res;
   15281             :     char       *nspname;
   15282             :     char       *prsname;
   15283             :     int         ntups,
   15284             :                 i;
   15285             :     int         i_tokenname;
   15286             :     int         i_dictname;
   15287             : 
   15288             :     /* Do nothing if not dumping schema */
   15289         304 :     if (!dopt->dumpSchema)
   15290          12 :         return;
   15291             : 
   15292         292 :     q = createPQExpBuffer();
   15293         292 :     delq = createPQExpBuffer();
   15294         292 :     query = createPQExpBuffer();
   15295             : 
   15296         292 :     qcfgname = pg_strdup(fmtId(cfginfo->dobj.name));
   15297             : 
   15298             :     /* Fetch name and namespace of the config's parser */
   15299         292 :     appendPQExpBuffer(query, "SELECT nspname, prsname "
   15300             :                       "FROM pg_ts_parser p, pg_namespace n "
   15301             :                       "WHERE p.oid = '%u' AND n.oid = prsnamespace",
   15302             :                       cfginfo->cfgparser);
   15303         292 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   15304         292 :     nspname = PQgetvalue(res, 0, 0);
   15305         292 :     prsname = PQgetvalue(res, 0, 1);
   15306             : 
   15307         292 :     appendPQExpBuffer(q, "CREATE TEXT SEARCH CONFIGURATION %s (\n",
   15308         292 :                       fmtQualifiedDumpable(cfginfo));
   15309             : 
   15310         292 :     appendPQExpBuffer(q, "    PARSER = %s.", fmtId(nspname));
   15311         292 :     appendPQExpBuffer(q, "%s );\n", fmtId(prsname));
   15312             : 
   15313         292 :     PQclear(res);
   15314             : 
   15315         292 :     resetPQExpBuffer(query);
   15316         292 :     appendPQExpBuffer(query,
   15317             :                       "SELECT\n"
   15318             :                       "  ( SELECT alias FROM pg_catalog.ts_token_type('%u'::pg_catalog.oid) AS t\n"
   15319             :                       "    WHERE t.tokid = m.maptokentype ) AS tokenname,\n"
   15320             :                       "  m.mapdict::pg_catalog.regdictionary AS dictname\n"
   15321             :                       "FROM pg_catalog.pg_ts_config_map AS m\n"
   15322             :                       "WHERE m.mapcfg = '%u'\n"
   15323             :                       "ORDER BY m.mapcfg, m.maptokentype, m.mapseqno",
   15324             :                       cfginfo->cfgparser, cfginfo->dobj.catId.oid);
   15325             : 
   15326         292 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   15327         292 :     ntups = PQntuples(res);
   15328             : 
   15329         292 :     i_tokenname = PQfnumber(res, "tokenname");
   15330         292 :     i_dictname = PQfnumber(res, "dictname");
   15331             : 
   15332        6110 :     for (i = 0; i < ntups; i++)
   15333             :     {
   15334        5818 :         char       *tokenname = PQgetvalue(res, i, i_tokenname);
   15335        5818 :         char       *dictname = PQgetvalue(res, i, i_dictname);
   15336             : 
   15337        5818 :         if (i == 0 ||
   15338        5526 :             strcmp(tokenname, PQgetvalue(res, i - 1, i_tokenname)) != 0)
   15339             :         {
   15340             :             /* starting a new token type, so start a new command */
   15341        5548 :             if (i > 0)
   15342        5256 :                 appendPQExpBufferStr(q, ";\n");
   15343        5548 :             appendPQExpBuffer(q, "\nALTER TEXT SEARCH CONFIGURATION %s\n",
   15344        5548 :                               fmtQualifiedDumpable(cfginfo));
   15345             :             /* tokenname needs quoting, dictname does NOT */
   15346        5548 :             appendPQExpBuffer(q, "    ADD MAPPING FOR %s WITH %s",
   15347             :                               fmtId(tokenname), dictname);
   15348             :         }
   15349             :         else
   15350         270 :             appendPQExpBuffer(q, ", %s", dictname);
   15351             :     }
   15352             : 
   15353         292 :     if (ntups > 0)
   15354         292 :         appendPQExpBufferStr(q, ";\n");
   15355             : 
   15356         292 :     PQclear(res);
   15357             : 
   15358         292 :     appendPQExpBuffer(delq, "DROP TEXT SEARCH CONFIGURATION %s;\n",
   15359         292 :                       fmtQualifiedDumpable(cfginfo));
   15360             : 
   15361         292 :     if (dopt->binary_upgrade)
   15362          10 :         binary_upgrade_extension_member(q, &cfginfo->dobj,
   15363             :                                         "TEXT SEARCH CONFIGURATION", qcfgname,
   15364          10 :                                         cfginfo->dobj.namespace->dobj.name);
   15365             : 
   15366         292 :     if (cfginfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   15367         292 :         ArchiveEntry(fout, cfginfo->dobj.catId, cfginfo->dobj.dumpId,
   15368         292 :                      ARCHIVE_OPTS(.tag = cfginfo->dobj.name,
   15369             :                                   .namespace = cfginfo->dobj.namespace->dobj.name,
   15370             :                                   .owner = cfginfo->rolname,
   15371             :                                   .description = "TEXT SEARCH CONFIGURATION",
   15372             :                                   .section = SECTION_PRE_DATA,
   15373             :                                   .createStmt = q->data,
   15374             :                                   .dropStmt = delq->data));
   15375             : 
   15376             :     /* Dump Configuration Comments */
   15377         292 :     if (cfginfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   15378         252 :         dumpComment(fout, "TEXT SEARCH CONFIGURATION", qcfgname,
   15379         252 :                     cfginfo->dobj.namespace->dobj.name, cfginfo->rolname,
   15380             :                     cfginfo->dobj.catId, 0, cfginfo->dobj.dumpId);
   15381             : 
   15382         292 :     destroyPQExpBuffer(q);
   15383         292 :     destroyPQExpBuffer(delq);
   15384         292 :     destroyPQExpBuffer(query);
   15385         292 :     free(qcfgname);
   15386             : }
   15387             : 
   15388             : /*
   15389             :  * dumpForeignDataWrapper
   15390             :  *    write out a single foreign-data wrapper definition
   15391             :  */
   15392             : static void
   15393         112 : dumpForeignDataWrapper(Archive *fout, const FdwInfo *fdwinfo)
   15394             : {
   15395         112 :     DumpOptions *dopt = fout->dopt;
   15396             :     PQExpBuffer q;
   15397             :     PQExpBuffer delq;
   15398             :     char       *qfdwname;
   15399             : 
   15400             :     /* Do nothing if not dumping schema */
   15401         112 :     if (!dopt->dumpSchema)
   15402          14 :         return;
   15403             : 
   15404          98 :     q = createPQExpBuffer();
   15405          98 :     delq = createPQExpBuffer();
   15406             : 
   15407          98 :     qfdwname = pg_strdup(fmtId(fdwinfo->dobj.name));
   15408             : 
   15409          98 :     appendPQExpBuffer(q, "CREATE FOREIGN DATA WRAPPER %s",
   15410             :                       qfdwname);
   15411             : 
   15412          98 :     if (strcmp(fdwinfo->fdwhandler, "-") != 0)
   15413           0 :         appendPQExpBuffer(q, " HANDLER %s", fdwinfo->fdwhandler);
   15414             : 
   15415          98 :     if (strcmp(fdwinfo->fdwvalidator, "-") != 0)
   15416           0 :         appendPQExpBuffer(q, " VALIDATOR %s", fdwinfo->fdwvalidator);
   15417             : 
   15418          98 :     if (strlen(fdwinfo->fdwoptions) > 0)
   15419           0 :         appendPQExpBuffer(q, " OPTIONS (\n    %s\n)", fdwinfo->fdwoptions);
   15420             : 
   15421          98 :     appendPQExpBufferStr(q, ";\n");
   15422             : 
   15423          98 :     appendPQExpBuffer(delq, "DROP FOREIGN DATA WRAPPER %s;\n",
   15424             :                       qfdwname);
   15425             : 
   15426          98 :     if (dopt->binary_upgrade)
   15427           4 :         binary_upgrade_extension_member(q, &fdwinfo->dobj,
   15428             :                                         "FOREIGN DATA WRAPPER", qfdwname,
   15429             :                                         NULL);
   15430             : 
   15431          98 :     if (fdwinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   15432          98 :         ArchiveEntry(fout, fdwinfo->dobj.catId, fdwinfo->dobj.dumpId,
   15433          98 :                      ARCHIVE_OPTS(.tag = fdwinfo->dobj.name,
   15434             :                                   .owner = fdwinfo->rolname,
   15435             :                                   .description = "FOREIGN DATA WRAPPER",
   15436             :                                   .section = SECTION_PRE_DATA,
   15437             :                                   .createStmt = q->data,
   15438             :                                   .dropStmt = delq->data));
   15439             : 
   15440             :     /* Dump Foreign Data Wrapper Comments */
   15441          98 :     if (fdwinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   15442           0 :         dumpComment(fout, "FOREIGN DATA WRAPPER", qfdwname,
   15443             :                     NULL, fdwinfo->rolname,
   15444             :                     fdwinfo->dobj.catId, 0, fdwinfo->dobj.dumpId);
   15445             : 
   15446             :     /* Handle the ACL */
   15447          98 :     if (fdwinfo->dobj.dump & DUMP_COMPONENT_ACL)
   15448          70 :         dumpACL(fout, fdwinfo->dobj.dumpId, InvalidDumpId,
   15449             :                 "FOREIGN DATA WRAPPER", qfdwname, NULL, NULL,
   15450             :                 NULL, fdwinfo->rolname, &fdwinfo->dacl);
   15451             : 
   15452          98 :     free(qfdwname);
   15453             : 
   15454          98 :     destroyPQExpBuffer(q);
   15455          98 :     destroyPQExpBuffer(delq);
   15456             : }
   15457             : 
   15458             : /*
   15459             :  * dumpForeignServer
   15460             :  *    write out a foreign server definition
   15461             :  */
   15462             : static void
   15463         120 : dumpForeignServer(Archive *fout, const ForeignServerInfo *srvinfo)
   15464             : {
   15465         120 :     DumpOptions *dopt = fout->dopt;
   15466             :     PQExpBuffer q;
   15467             :     PQExpBuffer delq;
   15468             :     PQExpBuffer query;
   15469             :     PGresult   *res;
   15470             :     char       *qsrvname;
   15471             :     char       *fdwname;
   15472             : 
   15473             :     /* Do nothing if not dumping schema */
   15474         120 :     if (!dopt->dumpSchema)
   15475          18 :         return;
   15476             : 
   15477         102 :     q = createPQExpBuffer();
   15478         102 :     delq = createPQExpBuffer();
   15479         102 :     query = createPQExpBuffer();
   15480             : 
   15481         102 :     qsrvname = pg_strdup(fmtId(srvinfo->dobj.name));
   15482             : 
   15483             :     /* look up the foreign-data wrapper */
   15484         102 :     appendPQExpBuffer(query, "SELECT fdwname "
   15485             :                       "FROM pg_foreign_data_wrapper w "
   15486             :                       "WHERE w.oid = '%u'",
   15487             :                       srvinfo->srvfdw);
   15488         102 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   15489         102 :     fdwname = PQgetvalue(res, 0, 0);
   15490             : 
   15491         102 :     appendPQExpBuffer(q, "CREATE SERVER %s", qsrvname);
   15492         102 :     if (srvinfo->srvtype && strlen(srvinfo->srvtype) > 0)
   15493             :     {
   15494           0 :         appendPQExpBufferStr(q, " TYPE ");
   15495           0 :         appendStringLiteralAH(q, srvinfo->srvtype, fout);
   15496             :     }
   15497         102 :     if (srvinfo->srvversion && strlen(srvinfo->srvversion) > 0)
   15498             :     {
   15499           0 :         appendPQExpBufferStr(q, " VERSION ");
   15500           0 :         appendStringLiteralAH(q, srvinfo->srvversion, fout);
   15501             :     }
   15502             : 
   15503         102 :     appendPQExpBufferStr(q, " FOREIGN DATA WRAPPER ");
   15504         102 :     appendPQExpBufferStr(q, fmtId(fdwname));
   15505             : 
   15506         102 :     if (srvinfo->srvoptions && strlen(srvinfo->srvoptions) > 0)
   15507           0 :         appendPQExpBuffer(q, " OPTIONS (\n    %s\n)", srvinfo->srvoptions);
   15508             : 
   15509         102 :     appendPQExpBufferStr(q, ";\n");
   15510             : 
   15511         102 :     appendPQExpBuffer(delq, "DROP SERVER %s;\n",
   15512             :                       qsrvname);
   15513             : 
   15514         102 :     if (dopt->binary_upgrade)
   15515           4 :         binary_upgrade_extension_member(q, &srvinfo->dobj,
   15516             :                                         "SERVER", qsrvname, NULL);
   15517             : 
   15518         102 :     if (srvinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   15519         102 :         ArchiveEntry(fout, srvinfo->dobj.catId, srvinfo->dobj.dumpId,
   15520         102 :                      ARCHIVE_OPTS(.tag = srvinfo->dobj.name,
   15521             :                                   .owner = srvinfo->rolname,
   15522             :                                   .description = "SERVER",
   15523             :                                   .section = SECTION_PRE_DATA,
   15524             :                                   .createStmt = q->data,
   15525             :                                   .dropStmt = delq->data));
   15526             : 
   15527             :     /* Dump Foreign Server Comments */
   15528         102 :     if (srvinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   15529           0 :         dumpComment(fout, "SERVER", qsrvname,
   15530             :                     NULL, srvinfo->rolname,
   15531             :                     srvinfo->dobj.catId, 0, srvinfo->dobj.dumpId);
   15532             : 
   15533             :     /* Handle the ACL */
   15534         102 :     if (srvinfo->dobj.dump & DUMP_COMPONENT_ACL)
   15535          70 :         dumpACL(fout, srvinfo->dobj.dumpId, InvalidDumpId,
   15536             :                 "FOREIGN SERVER", qsrvname, NULL, NULL,
   15537             :                 NULL, srvinfo->rolname, &srvinfo->dacl);
   15538             : 
   15539             :     /* Dump user mappings */
   15540         102 :     if (srvinfo->dobj.dump & DUMP_COMPONENT_USERMAP)
   15541         102 :         dumpUserMappings(fout,
   15542         102 :                          srvinfo->dobj.name, NULL,
   15543             :                          srvinfo->rolname,
   15544             :                          srvinfo->dobj.catId, srvinfo->dobj.dumpId);
   15545             : 
   15546         102 :     PQclear(res);
   15547             : 
   15548         102 :     free(qsrvname);
   15549             : 
   15550         102 :     destroyPQExpBuffer(q);
   15551         102 :     destroyPQExpBuffer(delq);
   15552         102 :     destroyPQExpBuffer(query);
   15553             : }
   15554             : 
   15555             : /*
   15556             :  * dumpUserMappings
   15557             :  *
   15558             :  * This routine is used to dump any user mappings associated with the
   15559             :  * server handed to this routine. Should be called after ArchiveEntry()
   15560             :  * for the server.
   15561             :  */
   15562             : static void
   15563         102 : dumpUserMappings(Archive *fout,
   15564             :                  const char *servername, const char *namespace,
   15565             :                  const char *owner,
   15566             :                  CatalogId catalogId, DumpId dumpId)
   15567             : {
   15568             :     PQExpBuffer q;
   15569             :     PQExpBuffer delq;
   15570             :     PQExpBuffer query;
   15571             :     PQExpBuffer tag;
   15572             :     PGresult   *res;
   15573             :     int         ntups;
   15574             :     int         i_usename;
   15575             :     int         i_umoptions;
   15576             :     int         i;
   15577             : 
   15578         102 :     q = createPQExpBuffer();
   15579         102 :     tag = createPQExpBuffer();
   15580         102 :     delq = createPQExpBuffer();
   15581         102 :     query = createPQExpBuffer();
   15582             : 
   15583             :     /*
   15584             :      * We read from the publicly accessible view pg_user_mappings, so as not
   15585             :      * to fail if run by a non-superuser.  Note that the view will show
   15586             :      * umoptions as null if the user hasn't got privileges for the associated
   15587             :      * server; this means that pg_dump will dump such a mapping, but with no
   15588             :      * OPTIONS clause.  A possible alternative is to skip such mappings
   15589             :      * altogether, but it's not clear that that's an improvement.
   15590             :      */
   15591         102 :     appendPQExpBuffer(query,
   15592             :                       "SELECT usename, "
   15593             :                       "array_to_string(ARRAY("
   15594             :                       "SELECT quote_ident(option_name) || ' ' || "
   15595             :                       "quote_literal(option_value) "
   15596             :                       "FROM pg_options_to_table(umoptions) "
   15597             :                       "ORDER BY option_name"
   15598             :                       "), E',\n    ') AS umoptions "
   15599             :                       "FROM pg_user_mappings "
   15600             :                       "WHERE srvid = '%u' "
   15601             :                       "ORDER BY usename",
   15602             :                       catalogId.oid);
   15603             : 
   15604         102 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   15605             : 
   15606         102 :     ntups = PQntuples(res);
   15607         102 :     i_usename = PQfnumber(res, "usename");
   15608         102 :     i_umoptions = PQfnumber(res, "umoptions");
   15609             : 
   15610         172 :     for (i = 0; i < ntups; i++)
   15611             :     {
   15612             :         char       *usename;
   15613             :         char       *umoptions;
   15614             : 
   15615          70 :         usename = PQgetvalue(res, i, i_usename);
   15616          70 :         umoptions = PQgetvalue(res, i, i_umoptions);
   15617             : 
   15618          70 :         resetPQExpBuffer(q);
   15619          70 :         appendPQExpBuffer(q, "CREATE USER MAPPING FOR %s", fmtId(usename));
   15620          70 :         appendPQExpBuffer(q, " SERVER %s", fmtId(servername));
   15621             : 
   15622          70 :         if (umoptions && strlen(umoptions) > 0)
   15623           0 :             appendPQExpBuffer(q, " OPTIONS (\n    %s\n)", umoptions);
   15624             : 
   15625          70 :         appendPQExpBufferStr(q, ";\n");
   15626             : 
   15627          70 :         resetPQExpBuffer(delq);
   15628          70 :         appendPQExpBuffer(delq, "DROP USER MAPPING FOR %s", fmtId(usename));
   15629          70 :         appendPQExpBuffer(delq, " SERVER %s;\n", fmtId(servername));
   15630             : 
   15631          70 :         resetPQExpBuffer(tag);
   15632          70 :         appendPQExpBuffer(tag, "USER MAPPING %s SERVER %s",
   15633             :                           usename, servername);
   15634             : 
   15635          70 :         ArchiveEntry(fout, nilCatalogId, createDumpId(),
   15636          70 :                      ARCHIVE_OPTS(.tag = tag->data,
   15637             :                                   .namespace = namespace,
   15638             :                                   .owner = owner,
   15639             :                                   .description = "USER MAPPING",
   15640             :                                   .section = SECTION_PRE_DATA,
   15641             :                                   .createStmt = q->data,
   15642             :                                   .dropStmt = delq->data));
   15643             :     }
   15644             : 
   15645         102 :     PQclear(res);
   15646             : 
   15647         102 :     destroyPQExpBuffer(query);
   15648         102 :     destroyPQExpBuffer(delq);
   15649         102 :     destroyPQExpBuffer(tag);
   15650         102 :     destroyPQExpBuffer(q);
   15651         102 : }
   15652             : 
   15653             : /*
   15654             :  * Write out default privileges information
   15655             :  */
   15656             : static void
   15657         332 : dumpDefaultACL(Archive *fout, const DefaultACLInfo *daclinfo)
   15658             : {
   15659         332 :     DumpOptions *dopt = fout->dopt;
   15660             :     PQExpBuffer q;
   15661             :     PQExpBuffer tag;
   15662             :     const char *type;
   15663             : 
   15664             :     /* Do nothing if not dumping schema, or if we're skipping ACLs */
   15665         332 :     if (!dopt->dumpSchema || dopt->aclsSkip)
   15666          56 :         return;
   15667             : 
   15668         276 :     q = createPQExpBuffer();
   15669         276 :     tag = createPQExpBuffer();
   15670             : 
   15671         276 :     switch (daclinfo->defaclobjtype)
   15672             :     {
   15673         138 :         case DEFACLOBJ_RELATION:
   15674         138 :             type = "TABLES";
   15675         138 :             break;
   15676           0 :         case DEFACLOBJ_SEQUENCE:
   15677           0 :             type = "SEQUENCES";
   15678           0 :             break;
   15679         138 :         case DEFACLOBJ_FUNCTION:
   15680         138 :             type = "FUNCTIONS";
   15681         138 :             break;
   15682           0 :         case DEFACLOBJ_TYPE:
   15683           0 :             type = "TYPES";
   15684           0 :             break;
   15685           0 :         case DEFACLOBJ_NAMESPACE:
   15686           0 :             type = "SCHEMAS";
   15687           0 :             break;
   15688           0 :         default:
   15689             :             /* shouldn't get here */
   15690           0 :             pg_fatal("unrecognized object type in default privileges: %d",
   15691             :                      (int) daclinfo->defaclobjtype);
   15692             :             type = "";            /* keep compiler quiet */
   15693             :     }
   15694             : 
   15695         276 :     appendPQExpBuffer(tag, "DEFAULT PRIVILEGES FOR %s", type);
   15696             : 
   15697             :     /* build the actual command(s) for this tuple */
   15698         276 :     if (!buildDefaultACLCommands(type,
   15699         276 :                                  daclinfo->dobj.namespace != NULL ?
   15700         140 :                                  daclinfo->dobj.namespace->dobj.name : NULL,
   15701         276 :                                  daclinfo->dacl.acl,
   15702         276 :                                  daclinfo->dacl.acldefault,
   15703             :                                  daclinfo->defaclrole,
   15704             :                                  fout->remoteVersion,
   15705             :                                  q))
   15706           0 :         pg_fatal("could not parse default ACL list (%s)",
   15707             :                  daclinfo->dacl.acl);
   15708             : 
   15709         276 :     if (daclinfo->dobj.dump & DUMP_COMPONENT_ACL)
   15710         276 :         ArchiveEntry(fout, daclinfo->dobj.catId, daclinfo->dobj.dumpId,
   15711         276 :                      ARCHIVE_OPTS(.tag = tag->data,
   15712             :                                   .namespace = daclinfo->dobj.namespace ?
   15713             :                                   daclinfo->dobj.namespace->dobj.name : NULL,
   15714             :                                   .owner = daclinfo->defaclrole,
   15715             :                                   .description = "DEFAULT ACL",
   15716             :                                   .section = SECTION_POST_DATA,
   15717             :                                   .createStmt = q->data));
   15718             : 
   15719         276 :     destroyPQExpBuffer(tag);
   15720         276 :     destroyPQExpBuffer(q);
   15721             : }
   15722             : 
   15723             : /*----------
   15724             :  * Write out grant/revoke information
   15725             :  *
   15726             :  * 'objDumpId' is the dump ID of the underlying object.
   15727             :  * 'altDumpId' can be a second dumpId that the ACL entry must also depend on,
   15728             :  *      or InvalidDumpId if there is no need for a second dependency.
   15729             :  * 'type' must be one of
   15730             :  *      TABLE, SEQUENCE, FUNCTION, LANGUAGE, SCHEMA, DATABASE, TABLESPACE,
   15731             :  *      FOREIGN DATA WRAPPER, SERVER, or LARGE OBJECT.
   15732             :  * 'name' is the formatted name of the object.  Must be quoted etc. already.
   15733             :  * 'subname' is the formatted name of the sub-object, if any.  Must be quoted.
   15734             :  *      (Currently we assume that subname is only provided for table columns.)
   15735             :  * 'nspname' is the namespace the object is in (NULL if none).
   15736             :  * 'tag' is the tag to use for the ACL TOC entry; typically, this is NULL
   15737             :  *      to use the default for the object type.
   15738             :  * 'owner' is the owner, NULL if there is no owner (for languages).
   15739             :  * 'dacl' is the DumpableAcl struct for the object.
   15740             :  *
   15741             :  * Returns the dump ID assigned to the ACL TocEntry, or InvalidDumpId if
   15742             :  * no ACL entry was created.
   15743             :  *----------
   15744             :  */
   15745             : static DumpId
   15746       52620 : dumpACL(Archive *fout, DumpId objDumpId, DumpId altDumpId,
   15747             :         const char *type, const char *name, const char *subname,
   15748             :         const char *nspname, const char *tag, const char *owner,
   15749             :         const DumpableAcl *dacl)
   15750             : {
   15751       52620 :     DumpId      aclDumpId = InvalidDumpId;
   15752       52620 :     DumpOptions *dopt = fout->dopt;
   15753       52620 :     const char *acls = dacl->acl;
   15754       52620 :     const char *acldefault = dacl->acldefault;
   15755       52620 :     char        privtype = dacl->privtype;
   15756       52620 :     const char *initprivs = dacl->initprivs;
   15757             :     const char *baseacls;
   15758             :     PQExpBuffer sql;
   15759             : 
   15760             :     /* Do nothing if ACL dump is not enabled */
   15761       52620 :     if (dopt->aclsSkip)
   15762         636 :         return InvalidDumpId;
   15763             : 
   15764             :     /* --data-only skips ACLs *except* large object ACLs */
   15765       51984 :     if (!dopt->dumpSchema && strcmp(type, "LARGE OBJECT") != 0)
   15766           0 :         return InvalidDumpId;
   15767             : 
   15768       51984 :     sql = createPQExpBuffer();
   15769             : 
   15770             :     /*
   15771             :      * In binary upgrade mode, we don't run an extension's script but instead
   15772             :      * dump out the objects independently and then recreate them.  To preserve
   15773             :      * any initial privileges which were set on extension objects, we need to
   15774             :      * compute the set of GRANT and REVOKE commands necessary to get from the
   15775             :      * default privileges of an object to its initial privileges as recorded
   15776             :      * in pg_init_privs.
   15777             :      *
   15778             :      * At restore time, we apply these commands after having called
   15779             :      * binary_upgrade_set_record_init_privs(true).  That tells the backend to
   15780             :      * copy the results into pg_init_privs.  This is how we preserve the
   15781             :      * contents of that catalog across binary upgrades.
   15782             :      */
   15783       51984 :     if (dopt->binary_upgrade && privtype == 'e' &&
   15784          26 :         initprivs && *initprivs != '\0')
   15785             :     {
   15786          26 :         appendPQExpBufferStr(sql, "SELECT pg_catalog.binary_upgrade_set_record_init_privs(true);\n");
   15787          26 :         if (!buildACLCommands(name, subname, nspname, type,
   15788             :                               initprivs, acldefault, owner,
   15789             :                               "", fout->remoteVersion, sql))
   15790           0 :             pg_fatal("could not parse initial ACL list (%s) or default (%s) for object \"%s\" (%s)",
   15791             :                      initprivs, acldefault, name, type);
   15792          26 :         appendPQExpBufferStr(sql, "SELECT pg_catalog.binary_upgrade_set_record_init_privs(false);\n");
   15793             :     }
   15794             : 
   15795             :     /*
   15796             :      * Now figure the GRANT and REVOKE commands needed to get to the object's
   15797             :      * actual current ACL, starting from the initprivs if given, else from the
   15798             :      * object-type-specific default.  Also, while buildACLCommands will assume
   15799             :      * that a NULL/empty acls string means it needn't do anything, what that
   15800             :      * actually represents is the object-type-specific default; so we need to
   15801             :      * substitute the acldefault string to get the right results in that case.
   15802             :      */
   15803       51984 :     if (initprivs && *initprivs != '\0')
   15804             :     {
   15805       48156 :         baseacls = initprivs;
   15806       48156 :         if (acls == NULL || *acls == '\0')
   15807          34 :             acls = acldefault;
   15808             :     }
   15809             :     else
   15810        3828 :         baseacls = acldefault;
   15811             : 
   15812       51984 :     if (!buildACLCommands(name, subname, nspname, type,
   15813             :                           acls, baseacls, owner,
   15814             :                           "", fout->remoteVersion, sql))
   15815           0 :         pg_fatal("could not parse ACL list (%s) or default (%s) for object \"%s\" (%s)",
   15816             :                  acls, baseacls, name, type);
   15817             : 
   15818       51984 :     if (sql->len > 0)
   15819             :     {
   15820        3976 :         PQExpBuffer tagbuf = createPQExpBuffer();
   15821             :         DumpId      aclDeps[2];
   15822        3976 :         int         nDeps = 0;
   15823             : 
   15824        3976 :         if (tag)
   15825           0 :             appendPQExpBufferStr(tagbuf, tag);
   15826        3976 :         else if (subname)
   15827        2350 :             appendPQExpBuffer(tagbuf, "COLUMN %s.%s", name, subname);
   15828             :         else
   15829        1626 :             appendPQExpBuffer(tagbuf, "%s %s", type, name);
   15830             : 
   15831        3976 :         aclDeps[nDeps++] = objDumpId;
   15832        3976 :         if (altDumpId != InvalidDumpId)
   15833        2174 :             aclDeps[nDeps++] = altDumpId;
   15834             : 
   15835        3976 :         aclDumpId = createDumpId();
   15836             : 
   15837        3976 :         ArchiveEntry(fout, nilCatalogId, aclDumpId,
   15838        3976 :                      ARCHIVE_OPTS(.tag = tagbuf->data,
   15839             :                                   .namespace = nspname,
   15840             :                                   .owner = owner,
   15841             :                                   .description = "ACL",
   15842             :                                   .section = SECTION_NONE,
   15843             :                                   .createStmt = sql->data,
   15844             :                                   .deps = aclDeps,
   15845             :                                   .nDeps = nDeps));
   15846             : 
   15847        3976 :         destroyPQExpBuffer(tagbuf);
   15848             :     }
   15849             : 
   15850       51984 :     destroyPQExpBuffer(sql);
   15851             : 
   15852       51984 :     return aclDumpId;
   15853             : }
   15854             : 
   15855             : /*
   15856             :  * dumpSecLabel
   15857             :  *
   15858             :  * This routine is used to dump any security labels associated with the
   15859             :  * object handed to this routine. The routine takes the object type
   15860             :  * and object name (ready to print, except for schema decoration), plus
   15861             :  * the namespace and owner of the object (for labeling the ArchiveEntry),
   15862             :  * plus catalog ID and subid which are the lookup key for pg_seclabel,
   15863             :  * plus the dump ID for the object (for setting a dependency).
   15864             :  * If a matching pg_seclabel entry is found, it is dumped.
   15865             :  *
   15866             :  * Note: although this routine takes a dumpId for dependency purposes,
   15867             :  * that purpose is just to mark the dependency in the emitted dump file
   15868             :  * for possible future use by pg_restore.  We do NOT use it for determining
   15869             :  * ordering of the label in the dump file, because this routine is called
   15870             :  * after dependency sorting occurs.  This routine should be called just after
   15871             :  * calling ArchiveEntry() for the specified object.
   15872             :  */
   15873             : static void
   15874           0 : dumpSecLabel(Archive *fout, const char *type, const char *name,
   15875             :              const char *namespace, const char *owner,
   15876             :              CatalogId catalogId, int subid, DumpId dumpId)
   15877             : {
   15878           0 :     DumpOptions *dopt = fout->dopt;
   15879             :     SecLabelItem *labels;
   15880             :     int         nlabels;
   15881             :     int         i;
   15882             :     PQExpBuffer query;
   15883             : 
   15884             :     /* do nothing, if --no-security-labels is supplied */
   15885           0 :     if (dopt->no_security_labels)
   15886           0 :         return;
   15887             : 
   15888             :     /*
   15889             :      * Security labels are schema not data ... except large object labels are
   15890             :      * data
   15891             :      */
   15892           0 :     if (strcmp(type, "LARGE OBJECT") != 0)
   15893             :     {
   15894           0 :         if (!dopt->dumpSchema)
   15895           0 :             return;
   15896             :     }
   15897             :     else
   15898             :     {
   15899             :         /* We do dump large object security labels in binary-upgrade mode */
   15900           0 :         if (!dopt->dumpData && !dopt->binary_upgrade)
   15901           0 :             return;
   15902             :     }
   15903             : 
   15904             :     /* Search for security labels associated with catalogId, using table */
   15905           0 :     nlabels = findSecLabels(catalogId.tableoid, catalogId.oid, &labels);
   15906             : 
   15907           0 :     query = createPQExpBuffer();
   15908             : 
   15909           0 :     for (i = 0; i < nlabels; i++)
   15910             :     {
   15911             :         /*
   15912             :          * Ignore label entries for which the subid doesn't match.
   15913             :          */
   15914           0 :         if (labels[i].objsubid != subid)
   15915           0 :             continue;
   15916             : 
   15917           0 :         appendPQExpBuffer(query,
   15918             :                           "SECURITY LABEL FOR %s ON %s ",
   15919           0 :                           fmtId(labels[i].provider), type);
   15920           0 :         if (namespace && *namespace)
   15921           0 :             appendPQExpBuffer(query, "%s.", fmtId(namespace));
   15922           0 :         appendPQExpBuffer(query, "%s IS ", name);
   15923           0 :         appendStringLiteralAH(query, labels[i].label, fout);
   15924           0 :         appendPQExpBufferStr(query, ";\n");
   15925             :     }
   15926             : 
   15927           0 :     if (query->len > 0)
   15928             :     {
   15929           0 :         PQExpBuffer tag = createPQExpBuffer();
   15930             : 
   15931           0 :         appendPQExpBuffer(tag, "%s %s", type, name);
   15932           0 :         ArchiveEntry(fout, nilCatalogId, createDumpId(),
   15933           0 :                      ARCHIVE_OPTS(.tag = tag->data,
   15934             :                                   .namespace = namespace,
   15935             :                                   .owner = owner,
   15936             :                                   .description = "SECURITY LABEL",
   15937             :                                   .section = SECTION_NONE,
   15938             :                                   .createStmt = query->data,
   15939             :                                   .deps = &dumpId,
   15940             :                                   .nDeps = 1));
   15941           0 :         destroyPQExpBuffer(tag);
   15942             :     }
   15943             : 
   15944           0 :     destroyPQExpBuffer(query);
   15945             : }
   15946             : 
   15947             : /*
   15948             :  * dumpTableSecLabel
   15949             :  *
   15950             :  * As above, but dump security label for both the specified table (or view)
   15951             :  * and its columns.
   15952             :  */
   15953             : static void
   15954           0 : dumpTableSecLabel(Archive *fout, const TableInfo *tbinfo, const char *reltypename)
   15955             : {
   15956           0 :     DumpOptions *dopt = fout->dopt;
   15957             :     SecLabelItem *labels;
   15958             :     int         nlabels;
   15959             :     int         i;
   15960             :     PQExpBuffer query;
   15961             :     PQExpBuffer target;
   15962             : 
   15963             :     /* do nothing, if --no-security-labels is supplied */
   15964           0 :     if (dopt->no_security_labels)
   15965           0 :         return;
   15966             : 
   15967             :     /* SecLabel are SCHEMA not data */
   15968           0 :     if (!dopt->dumpSchema)
   15969           0 :         return;
   15970             : 
   15971             :     /* Search for comments associated with relation, using table */
   15972           0 :     nlabels = findSecLabels(tbinfo->dobj.catId.tableoid,
   15973             :                             tbinfo->dobj.catId.oid,
   15974             :                             &labels);
   15975             : 
   15976             :     /* If security labels exist, build SECURITY LABEL statements */
   15977           0 :     if (nlabels <= 0)
   15978           0 :         return;
   15979             : 
   15980           0 :     query = createPQExpBuffer();
   15981           0 :     target = createPQExpBuffer();
   15982             : 
   15983           0 :     for (i = 0; i < nlabels; i++)
   15984             :     {
   15985             :         const char *colname;
   15986           0 :         const char *provider = labels[i].provider;
   15987           0 :         const char *label = labels[i].label;
   15988           0 :         int         objsubid = labels[i].objsubid;
   15989             : 
   15990           0 :         resetPQExpBuffer(target);
   15991           0 :         if (objsubid == 0)
   15992             :         {
   15993           0 :             appendPQExpBuffer(target, "%s %s", reltypename,
   15994           0 :                               fmtQualifiedDumpable(tbinfo));
   15995             :         }
   15996             :         else
   15997             :         {
   15998           0 :             colname = getAttrName(objsubid, tbinfo);
   15999             :             /* first fmtXXX result must be consumed before calling again */
   16000           0 :             appendPQExpBuffer(target, "COLUMN %s",
   16001           0 :                               fmtQualifiedDumpable(tbinfo));
   16002           0 :             appendPQExpBuffer(target, ".%s", fmtId(colname));
   16003             :         }
   16004           0 :         appendPQExpBuffer(query, "SECURITY LABEL FOR %s ON %s IS ",
   16005             :                           fmtId(provider), target->data);
   16006           0 :         appendStringLiteralAH(query, label, fout);
   16007           0 :         appendPQExpBufferStr(query, ";\n");
   16008             :     }
   16009           0 :     if (query->len > 0)
   16010             :     {
   16011           0 :         resetPQExpBuffer(target);
   16012           0 :         appendPQExpBuffer(target, "%s %s", reltypename,
   16013           0 :                           fmtId(tbinfo->dobj.name));
   16014           0 :         ArchiveEntry(fout, nilCatalogId, createDumpId(),
   16015           0 :                      ARCHIVE_OPTS(.tag = target->data,
   16016             :                                   .namespace = tbinfo->dobj.namespace->dobj.name,
   16017             :                                   .owner = tbinfo->rolname,
   16018             :                                   .description = "SECURITY LABEL",
   16019             :                                   .section = SECTION_NONE,
   16020             :                                   .createStmt = query->data,
   16021             :                                   .deps = &(tbinfo->dobj.dumpId),
   16022             :                                   .nDeps = 1));
   16023             :     }
   16024           0 :     destroyPQExpBuffer(query);
   16025           0 :     destroyPQExpBuffer(target);
   16026             : }
   16027             : 
   16028             : /*
   16029             :  * findSecLabels
   16030             :  *
   16031             :  * Find the security label(s), if any, associated with the given object.
   16032             :  * All the objsubid values associated with the given classoid/objoid are
   16033             :  * found with one search.
   16034             :  */
   16035             : static int
   16036           0 : findSecLabels(Oid classoid, Oid objoid, SecLabelItem **items)
   16037             : {
   16038           0 :     SecLabelItem *middle = NULL;
   16039             :     SecLabelItem *low;
   16040             :     SecLabelItem *high;
   16041             :     int         nmatch;
   16042             : 
   16043           0 :     if (nseclabels <= 0)     /* no labels, so no match is possible */
   16044             :     {
   16045           0 :         *items = NULL;
   16046           0 :         return 0;
   16047             :     }
   16048             : 
   16049             :     /*
   16050             :      * Do binary search to find some item matching the object.
   16051             :      */
   16052           0 :     low = &seclabels[0];
   16053           0 :     high = &seclabels[nseclabels - 1];
   16054           0 :     while (low <= high)
   16055             :     {
   16056           0 :         middle = low + (high - low) / 2;
   16057             : 
   16058           0 :         if (classoid < middle->classoid)
   16059           0 :             high = middle - 1;
   16060           0 :         else if (classoid > middle->classoid)
   16061           0 :             low = middle + 1;
   16062           0 :         else if (objoid < middle->objoid)
   16063           0 :             high = middle - 1;
   16064           0 :         else if (objoid > middle->objoid)
   16065           0 :             low = middle + 1;
   16066             :         else
   16067           0 :             break;              /* found a match */
   16068             :     }
   16069             : 
   16070           0 :     if (low > high)              /* no matches */
   16071             :     {
   16072           0 :         *items = NULL;
   16073           0 :         return 0;
   16074             :     }
   16075             : 
   16076             :     /*
   16077             :      * Now determine how many items match the object.  The search loop
   16078             :      * invariant still holds: only items between low and high inclusive could
   16079             :      * match.
   16080             :      */
   16081           0 :     nmatch = 1;
   16082           0 :     while (middle > low)
   16083             :     {
   16084           0 :         if (classoid != middle[-1].classoid ||
   16085           0 :             objoid != middle[-1].objoid)
   16086             :             break;
   16087           0 :         middle--;
   16088           0 :         nmatch++;
   16089             :     }
   16090             : 
   16091           0 :     *items = middle;
   16092             : 
   16093           0 :     middle += nmatch;
   16094           0 :     while (middle <= high)
   16095             :     {
   16096           0 :         if (classoid != middle->classoid ||
   16097           0 :             objoid != middle->objoid)
   16098             :             break;
   16099           0 :         middle++;
   16100           0 :         nmatch++;
   16101             :     }
   16102             : 
   16103           0 :     return nmatch;
   16104             : }
   16105             : 
   16106             : /*
   16107             :  * collectSecLabels
   16108             :  *
   16109             :  * Construct a table of all security labels available for database objects;
   16110             :  * also set the has-seclabel component flag for each relevant object.
   16111             :  *
   16112             :  * The table is sorted by classoid/objid/objsubid for speed in lookup.
   16113             :  */
   16114             : static void
   16115         354 : collectSecLabels(Archive *fout)
   16116             : {
   16117             :     PGresult   *res;
   16118             :     PQExpBuffer query;
   16119             :     int         i_label;
   16120             :     int         i_provider;
   16121             :     int         i_classoid;
   16122             :     int         i_objoid;
   16123             :     int         i_objsubid;
   16124             :     int         ntups;
   16125             :     int         i;
   16126             :     DumpableObject *dobj;
   16127             : 
   16128         354 :     query = createPQExpBuffer();
   16129             : 
   16130         354 :     appendPQExpBufferStr(query,
   16131             :                          "SELECT label, provider, classoid, objoid, objsubid "
   16132             :                          "FROM pg_catalog.pg_seclabel "
   16133             :                          "ORDER BY classoid, objoid, objsubid");
   16134             : 
   16135         354 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   16136             : 
   16137             :     /* Construct lookup table containing OIDs in numeric form */
   16138         354 :     i_label = PQfnumber(res, "label");
   16139         354 :     i_provider = PQfnumber(res, "provider");
   16140         354 :     i_classoid = PQfnumber(res, "classoid");
   16141         354 :     i_objoid = PQfnumber(res, "objoid");
   16142         354 :     i_objsubid = PQfnumber(res, "objsubid");
   16143             : 
   16144         354 :     ntups = PQntuples(res);
   16145             : 
   16146         354 :     seclabels = (SecLabelItem *) pg_malloc(ntups * sizeof(SecLabelItem));
   16147         354 :     nseclabels = 0;
   16148         354 :     dobj = NULL;
   16149             : 
   16150         354 :     for (i = 0; i < ntups; i++)
   16151             :     {
   16152             :         CatalogId   objId;
   16153             :         int         subid;
   16154             : 
   16155           0 :         objId.tableoid = atooid(PQgetvalue(res, i, i_classoid));
   16156           0 :         objId.oid = atooid(PQgetvalue(res, i, i_objoid));
   16157           0 :         subid = atoi(PQgetvalue(res, i, i_objsubid));
   16158             : 
   16159             :         /* We needn't remember labels that don't match any dumpable object */
   16160           0 :         if (dobj == NULL ||
   16161           0 :             dobj->catId.tableoid != objId.tableoid ||
   16162           0 :             dobj->catId.oid != objId.oid)
   16163           0 :             dobj = findObjectByCatalogId(objId);
   16164           0 :         if (dobj == NULL)
   16165           0 :             continue;
   16166             : 
   16167             :         /*
   16168             :          * Labels on columns of composite types are linked to the type's
   16169             :          * pg_class entry, but we need to set the DUMP_COMPONENT_SECLABEL flag
   16170             :          * in the type's own DumpableObject.
   16171             :          */
   16172           0 :         if (subid != 0 && dobj->objType == DO_TABLE &&
   16173           0 :             ((TableInfo *) dobj)->relkind == RELKIND_COMPOSITE_TYPE)
   16174           0 :         {
   16175             :             TypeInfo   *cTypeInfo;
   16176             : 
   16177           0 :             cTypeInfo = findTypeByOid(((TableInfo *) dobj)->reltype);
   16178           0 :             if (cTypeInfo)
   16179           0 :                 cTypeInfo->dobj.components |= DUMP_COMPONENT_SECLABEL;
   16180             :         }
   16181             :         else
   16182           0 :             dobj->components |= DUMP_COMPONENT_SECLABEL;
   16183             : 
   16184           0 :         seclabels[nseclabels].label = pg_strdup(PQgetvalue(res, i, i_label));
   16185           0 :         seclabels[nseclabels].provider = pg_strdup(PQgetvalue(res, i, i_provider));
   16186           0 :         seclabels[nseclabels].classoid = objId.tableoid;
   16187           0 :         seclabels[nseclabels].objoid = objId.oid;
   16188           0 :         seclabels[nseclabels].objsubid = subid;
   16189           0 :         nseclabels++;
   16190             :     }
   16191             : 
   16192         354 :     PQclear(res);
   16193         354 :     destroyPQExpBuffer(query);
   16194         354 : }
   16195             : 
   16196             : /*
   16197             :  * dumpTable
   16198             :  *    write out to fout the declarations (not data) of a user-defined table
   16199             :  */
   16200             : static void
   16201       57818 : dumpTable(Archive *fout, const TableInfo *tbinfo)
   16202             : {
   16203       57818 :     DumpOptions *dopt = fout->dopt;
   16204       57818 :     DumpId      tableAclDumpId = InvalidDumpId;
   16205             :     char       *namecopy;
   16206             : 
   16207             :     /* Do nothing if not dumping schema */
   16208       57818 :     if (!dopt->dumpSchema)
   16209        2892 :         return;
   16210             : 
   16211       54926 :     if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   16212             :     {
   16213       12872 :         if (tbinfo->relkind == RELKIND_SEQUENCE)
   16214         774 :             dumpSequence(fout, tbinfo);
   16215             :         else
   16216       12098 :             dumpTableSchema(fout, tbinfo);
   16217             :     }
   16218             : 
   16219             :     /* Handle the ACL here */
   16220       54926 :     namecopy = pg_strdup(fmtId(tbinfo->dobj.name));
   16221       54926 :     if (tbinfo->dobj.dump & DUMP_COMPONENT_ACL)
   16222             :     {
   16223       43528 :         const char *objtype =
   16224       43528 :             (tbinfo->relkind == RELKIND_SEQUENCE) ? "SEQUENCE" : "TABLE";
   16225             : 
   16226             :         tableAclDumpId =
   16227       43528 :             dumpACL(fout, tbinfo->dobj.dumpId, InvalidDumpId,
   16228             :                     objtype, namecopy, NULL,
   16229       43528 :                     tbinfo->dobj.namespace->dobj.name,
   16230             :                     NULL, tbinfo->rolname, &tbinfo->dacl);
   16231             :     }
   16232             : 
   16233             :     /*
   16234             :      * Handle column ACLs, if any.  Note: we pull these with a separate query
   16235             :      * rather than trying to fetch them during getTableAttrs, so that we won't
   16236             :      * miss ACLs on system columns.  Doing it this way also allows us to dump
   16237             :      * ACLs for catalogs that we didn't mark "interesting" back in getTables.
   16238             :      */
   16239       54926 :     if ((tbinfo->dobj.dump & DUMP_COMPONENT_ACL) && tbinfo->hascolumnACLs)
   16240             :     {
   16241         568 :         PQExpBuffer query = createPQExpBuffer();
   16242             :         PGresult   *res;
   16243             :         int         i;
   16244             : 
   16245         568 :         if (!fout->is_prepared[PREPQUERY_GETCOLUMNACLS])
   16246             :         {
   16247             :             /* Set up query for column ACLs */
   16248         302 :             appendPQExpBufferStr(query,
   16249             :                                  "PREPARE getColumnACLs(pg_catalog.oid) AS\n");
   16250             : 
   16251         302 :             if (fout->remoteVersion >= 90600)
   16252             :             {
   16253             :                 /*
   16254             :                  * In principle we should call acldefault('c', relowner) to
   16255             :                  * get the default ACL for a column.  However, we don't
   16256             :                  * currently store the numeric OID of the relowner in
   16257             :                  * TableInfo.  We could convert the owner name using regrole,
   16258             :                  * but that creates a risk of failure due to concurrent role
   16259             :                  * renames.  Given that the default ACL for columns is empty
   16260             :                  * and is likely to stay that way, it's not worth extra cycles
   16261             :                  * and risk to avoid hard-wiring that knowledge here.
   16262             :                  */
   16263         302 :                 appendPQExpBufferStr(query,
   16264             :                                      "SELECT at.attname, "
   16265             :                                      "at.attacl, "
   16266             :                                      "'{}' AS acldefault, "
   16267             :                                      "pip.privtype, pip.initprivs "
   16268             :                                      "FROM pg_catalog.pg_attribute at "
   16269             :                                      "LEFT JOIN pg_catalog.pg_init_privs pip ON "
   16270             :                                      "(at.attrelid = pip.objoid "
   16271             :                                      "AND pip.classoid = 'pg_catalog.pg_class'::pg_catalog.regclass "
   16272             :                                      "AND at.attnum = pip.objsubid) "
   16273             :                                      "WHERE at.attrelid = $1 AND "
   16274             :                                      "NOT at.attisdropped "
   16275             :                                      "AND (at.attacl IS NOT NULL OR pip.initprivs IS NOT NULL) "
   16276             :                                      "ORDER BY at.attnum");
   16277             :             }
   16278             :             else
   16279             :             {
   16280           0 :                 appendPQExpBufferStr(query,
   16281             :                                      "SELECT attname, attacl, '{}' AS acldefault, "
   16282             :                                      "NULL AS privtype, NULL AS initprivs "
   16283             :                                      "FROM pg_catalog.pg_attribute "
   16284             :                                      "WHERE attrelid = $1 AND NOT attisdropped "
   16285             :                                      "AND attacl IS NOT NULL "
   16286             :                                      "ORDER BY attnum");
   16287             :             }
   16288             : 
   16289         302 :             ExecuteSqlStatement(fout, query->data);
   16290             : 
   16291         302 :             fout->is_prepared[PREPQUERY_GETCOLUMNACLS] = true;
   16292             :         }
   16293             : 
   16294         568 :         printfPQExpBuffer(query,
   16295             :                           "EXECUTE getColumnACLs('%u')",
   16296             :                           tbinfo->dobj.catId.oid);
   16297             : 
   16298         568 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   16299             : 
   16300        7950 :         for (i = 0; i < PQntuples(res); i++)
   16301             :         {
   16302        7382 :             char       *attname = PQgetvalue(res, i, 0);
   16303        7382 :             char       *attacl = PQgetvalue(res, i, 1);
   16304        7382 :             char       *acldefault = PQgetvalue(res, i, 2);
   16305        7382 :             char        privtype = *(PQgetvalue(res, i, 3));
   16306        7382 :             char       *initprivs = PQgetvalue(res, i, 4);
   16307             :             DumpableAcl coldacl;
   16308             :             char       *attnamecopy;
   16309             : 
   16310        7382 :             coldacl.acl = attacl;
   16311        7382 :             coldacl.acldefault = acldefault;
   16312        7382 :             coldacl.privtype = privtype;
   16313        7382 :             coldacl.initprivs = initprivs;
   16314        7382 :             attnamecopy = pg_strdup(fmtId(attname));
   16315             : 
   16316             :             /*
   16317             :              * Column's GRANT type is always TABLE.  Each column ACL depends
   16318             :              * on the table-level ACL, since we can restore column ACLs in
   16319             :              * parallel but the table-level ACL has to be done first.
   16320             :              */
   16321        7382 :             dumpACL(fout, tbinfo->dobj.dumpId, tableAclDumpId,
   16322             :                     "TABLE", namecopy, attnamecopy,
   16323        7382 :                     tbinfo->dobj.namespace->dobj.name,
   16324             :                     NULL, tbinfo->rolname, &coldacl);
   16325        7382 :             free(attnamecopy);
   16326             :         }
   16327         568 :         PQclear(res);
   16328         568 :         destroyPQExpBuffer(query);
   16329             :     }
   16330             : 
   16331       54926 :     free(namecopy);
   16332             : }
   16333             : 
   16334             : /*
   16335             :  * Create the AS clause for a view or materialized view. The semicolon is
   16336             :  * stripped because a materialized view must add a WITH NO DATA clause.
   16337             :  *
   16338             :  * This returns a new buffer which must be freed by the caller.
   16339             :  */
   16340             : static PQExpBuffer
   16341        1840 : createViewAsClause(Archive *fout, const TableInfo *tbinfo)
   16342             : {
   16343        1840 :     PQExpBuffer query = createPQExpBuffer();
   16344        1840 :     PQExpBuffer result = createPQExpBuffer();
   16345             :     PGresult   *res;
   16346             :     int         len;
   16347             : 
   16348             :     /* Fetch the view definition */
   16349        1840 :     appendPQExpBuffer(query,
   16350             :                       "SELECT pg_catalog.pg_get_viewdef('%u'::pg_catalog.oid) AS viewdef",
   16351             :                       tbinfo->dobj.catId.oid);
   16352             : 
   16353        1840 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   16354             : 
   16355        1840 :     if (PQntuples(res) != 1)
   16356             :     {
   16357           0 :         if (PQntuples(res) < 1)
   16358           0 :             pg_fatal("query to obtain definition of view \"%s\" returned no data",
   16359             :                      tbinfo->dobj.name);
   16360             :         else
   16361           0 :             pg_fatal("query to obtain definition of view \"%s\" returned more than one definition",
   16362             :                      tbinfo->dobj.name);
   16363             :     }
   16364             : 
   16365        1840 :     len = PQgetlength(res, 0, 0);
   16366             : 
   16367        1840 :     if (len == 0)
   16368           0 :         pg_fatal("definition of view \"%s\" appears to be empty (length zero)",
   16369             :                  tbinfo->dobj.name);
   16370             : 
   16371             :     /* Strip off the trailing semicolon so that other things may follow. */
   16372             :     Assert(PQgetvalue(res, 0, 0)[len - 1] == ';');
   16373        1840 :     appendBinaryPQExpBuffer(result, PQgetvalue(res, 0, 0), len - 1);
   16374             : 
   16375        1840 :     PQclear(res);
   16376        1840 :     destroyPQExpBuffer(query);
   16377             : 
   16378        1840 :     return result;
   16379             : }
   16380             : 
   16381             : /*
   16382             :  * Create a dummy AS clause for a view.  This is used when the real view
   16383             :  * definition has to be postponed because of circular dependencies.
   16384             :  * We must duplicate the view's external properties -- column names and types
   16385             :  * (including collation) -- so that it works for subsequent references.
   16386             :  *
   16387             :  * This returns a new buffer which must be freed by the caller.
   16388             :  */
   16389             : static PQExpBuffer
   16390          40 : createDummyViewAsClause(Archive *fout, const TableInfo *tbinfo)
   16391             : {
   16392          40 :     PQExpBuffer result = createPQExpBuffer();
   16393             :     int         j;
   16394             : 
   16395          40 :     appendPQExpBufferStr(result, "SELECT");
   16396             : 
   16397          80 :     for (j = 0; j < tbinfo->numatts; j++)
   16398             :     {
   16399          40 :         if (j > 0)
   16400          20 :             appendPQExpBufferChar(result, ',');
   16401          40 :         appendPQExpBufferStr(result, "\n    ");
   16402             : 
   16403          40 :         appendPQExpBuffer(result, "NULL::%s", tbinfo->atttypnames[j]);
   16404             : 
   16405             :         /*
   16406             :          * Must add collation if not default for the type, because CREATE OR
   16407             :          * REPLACE VIEW won't change it
   16408             :          */
   16409          40 :         if (OidIsValid(tbinfo->attcollation[j]))
   16410             :         {
   16411             :             CollInfo   *coll;
   16412             : 
   16413           0 :             coll = findCollationByOid(tbinfo->attcollation[j]);
   16414           0 :             if (coll)
   16415           0 :                 appendPQExpBuffer(result, " COLLATE %s",
   16416           0 :                                   fmtQualifiedDumpable(coll));
   16417             :         }
   16418             : 
   16419          40 :         appendPQExpBuffer(result, " AS %s", fmtId(tbinfo->attnames[j]));
   16420             :     }
   16421             : 
   16422          40 :     return result;
   16423             : }
   16424             : 
   16425             : /*
   16426             :  * dumpTableSchema
   16427             :  *    write the declaration (not data) of one user-defined table or view
   16428             :  */
   16429             : static void
   16430       12098 : dumpTableSchema(Archive *fout, const TableInfo *tbinfo)
   16431             : {
   16432       12098 :     DumpOptions *dopt = fout->dopt;
   16433       12098 :     PQExpBuffer q = createPQExpBuffer();
   16434       12098 :     PQExpBuffer delq = createPQExpBuffer();
   16435       12098 :     PQExpBuffer extra = createPQExpBuffer();
   16436             :     char       *qrelname;
   16437             :     char       *qualrelname;
   16438             :     int         numParents;
   16439             :     TableInfo **parents;
   16440             :     int         actual_atts;    /* number of attrs in this CREATE statement */
   16441             :     const char *reltypename;
   16442             :     char       *storage;
   16443             :     int         j,
   16444             :                 k;
   16445             : 
   16446             :     /* We had better have loaded per-column details about this table */
   16447             :     Assert(tbinfo->interesting);
   16448             : 
   16449       12098 :     qrelname = pg_strdup(fmtId(tbinfo->dobj.name));
   16450       12098 :     qualrelname = pg_strdup(fmtQualifiedDumpable(tbinfo));
   16451             : 
   16452       12098 :     if (tbinfo->hasoids)
   16453           0 :         pg_log_warning("WITH OIDS is not supported anymore (table \"%s\")",
   16454             :                        qrelname);
   16455             : 
   16456       12098 :     if (dopt->binary_upgrade)
   16457        1646 :         binary_upgrade_set_type_oids_by_rel(fout, q, tbinfo);
   16458             : 
   16459             :     /* Is it a table or a view? */
   16460       12098 :     if (tbinfo->relkind == RELKIND_VIEW)
   16461             :     {
   16462             :         PQExpBuffer result;
   16463             : 
   16464             :         /*
   16465             :          * Note: keep this code in sync with the is_view case in dumpRule()
   16466             :          */
   16467             : 
   16468        1040 :         reltypename = "VIEW";
   16469             : 
   16470        1040 :         appendPQExpBuffer(delq, "DROP VIEW %s;\n", qualrelname);
   16471             : 
   16472        1040 :         if (dopt->binary_upgrade)
   16473         102 :             binary_upgrade_set_pg_class_oids(fout, q,
   16474             :                                              tbinfo->dobj.catId.oid);
   16475             : 
   16476        1040 :         appendPQExpBuffer(q, "CREATE VIEW %s", qualrelname);
   16477             : 
   16478        1040 :         if (tbinfo->dummy_view)
   16479          20 :             result = createDummyViewAsClause(fout, tbinfo);
   16480             :         else
   16481             :         {
   16482        1020 :             if (nonemptyReloptions(tbinfo->reloptions))
   16483             :             {
   16484         130 :                 appendPQExpBufferStr(q, " WITH (");
   16485         130 :                 appendReloptionsArrayAH(q, tbinfo->reloptions, "", fout);
   16486         130 :                 appendPQExpBufferChar(q, ')');
   16487             :             }
   16488        1020 :             result = createViewAsClause(fout, tbinfo);
   16489             :         }
   16490        1040 :         appendPQExpBuffer(q, " AS\n%s", result->data);
   16491        1040 :         destroyPQExpBuffer(result);
   16492             : 
   16493        1040 :         if (tbinfo->checkoption != NULL && !tbinfo->dummy_view)
   16494          72 :             appendPQExpBuffer(q, "\n  WITH %s CHECK OPTION", tbinfo->checkoption);
   16495        1040 :         appendPQExpBufferStr(q, ";\n");
   16496             :     }
   16497             :     else
   16498             :     {
   16499       11058 :         char       *partkeydef = NULL;
   16500       11058 :         char       *ftoptions = NULL;
   16501       11058 :         char       *srvname = NULL;
   16502       11058 :         const char *foreign = "";
   16503             : 
   16504             :         /*
   16505             :          * Set reltypename, and collect any relkind-specific data that we
   16506             :          * didn't fetch during getTables().
   16507             :          */
   16508       11058 :         switch (tbinfo->relkind)
   16509             :         {
   16510        1074 :             case RELKIND_PARTITIONED_TABLE:
   16511             :                 {
   16512        1074 :                     PQExpBuffer query = createPQExpBuffer();
   16513             :                     PGresult   *res;
   16514             : 
   16515        1074 :                     reltypename = "TABLE";
   16516             : 
   16517             :                     /* retrieve partition key definition */
   16518        1074 :                     appendPQExpBuffer(query,
   16519             :                                       "SELECT pg_get_partkeydef('%u')",
   16520             :                                       tbinfo->dobj.catId.oid);
   16521        1074 :                     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   16522        1074 :                     partkeydef = pg_strdup(PQgetvalue(res, 0, 0));
   16523        1074 :                     PQclear(res);
   16524        1074 :                     destroyPQExpBuffer(query);
   16525        1074 :                     break;
   16526             :                 }
   16527          76 :             case RELKIND_FOREIGN_TABLE:
   16528             :                 {
   16529          76 :                     PQExpBuffer query = createPQExpBuffer();
   16530             :                     PGresult   *res;
   16531             :                     int         i_srvname;
   16532             :                     int         i_ftoptions;
   16533             : 
   16534          76 :                     reltypename = "FOREIGN TABLE";
   16535             : 
   16536             :                     /* retrieve name of foreign server and generic options */
   16537          76 :                     appendPQExpBuffer(query,
   16538             :                                       "SELECT fs.srvname, "
   16539             :                                       "pg_catalog.array_to_string(ARRAY("
   16540             :                                       "SELECT pg_catalog.quote_ident(option_name) || "
   16541             :                                       "' ' || pg_catalog.quote_literal(option_value) "
   16542             :                                       "FROM pg_catalog.pg_options_to_table(ftoptions) "
   16543             :                                       "ORDER BY option_name"
   16544             :                                       "), E',\n    ') AS ftoptions "
   16545             :                                       "FROM pg_catalog.pg_foreign_table ft "
   16546             :                                       "JOIN pg_catalog.pg_foreign_server fs "
   16547             :                                       "ON (fs.oid = ft.ftserver) "
   16548             :                                       "WHERE ft.ftrelid = '%u'",
   16549             :                                       tbinfo->dobj.catId.oid);
   16550          76 :                     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   16551          76 :                     i_srvname = PQfnumber(res, "srvname");
   16552          76 :                     i_ftoptions = PQfnumber(res, "ftoptions");
   16553          76 :                     srvname = pg_strdup(PQgetvalue(res, 0, i_srvname));
   16554          76 :                     ftoptions = pg_strdup(PQgetvalue(res, 0, i_ftoptions));
   16555          76 :                     PQclear(res);
   16556          76 :                     destroyPQExpBuffer(query);
   16557             : 
   16558          76 :                     foreign = "FOREIGN ";
   16559          76 :                     break;
   16560             :                 }
   16561         800 :             case RELKIND_MATVIEW:
   16562         800 :                 reltypename = "MATERIALIZED VIEW";
   16563         800 :                 break;
   16564        9108 :             default:
   16565        9108 :                 reltypename = "TABLE";
   16566        9108 :                 break;
   16567             :         }
   16568             : 
   16569       11058 :         numParents = tbinfo->numParents;
   16570       11058 :         parents = tbinfo->parents;
   16571             : 
   16572       11058 :         appendPQExpBuffer(delq, "DROP %s %s;\n", reltypename, qualrelname);
   16573             : 
   16574       11058 :         if (dopt->binary_upgrade)
   16575        1544 :             binary_upgrade_set_pg_class_oids(fout, q,
   16576             :                                              tbinfo->dobj.catId.oid);
   16577             : 
   16578             :         /*
   16579             :          * PostgreSQL 18 has disabled UNLOGGED for partitioned tables, so
   16580             :          * ignore it when dumping if it was set in this case.
   16581             :          */
   16582       11058 :         appendPQExpBuffer(q, "CREATE %s%s %s",
   16583       11058 :                           (tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED &&
   16584          40 :                            tbinfo->relkind != RELKIND_PARTITIONED_TABLE) ?
   16585             :                           "UNLOGGED " : "",
   16586             :                           reltypename,
   16587             :                           qualrelname);
   16588             : 
   16589             :         /*
   16590             :          * Attach to type, if reloftype; except in case of a binary upgrade,
   16591             :          * we dump the table normally and attach it to the type afterward.
   16592             :          */
   16593       11058 :         if (OidIsValid(tbinfo->reloftype) && !dopt->binary_upgrade)
   16594          48 :             appendPQExpBuffer(q, " OF %s",
   16595             :                               getFormattedTypeName(fout, tbinfo->reloftype,
   16596             :                                                    zeroIsError));
   16597             : 
   16598       11058 :         if (tbinfo->relkind != RELKIND_MATVIEW)
   16599             :         {
   16600             :             /* Dump the attributes */
   16601       10258 :             actual_atts = 0;
   16602       49602 :             for (j = 0; j < tbinfo->numatts; j++)
   16603             :             {
   16604             :                 /*
   16605             :                  * Normally, dump if it's locally defined in this table, and
   16606             :                  * not dropped.  But for binary upgrade, we'll dump all the
   16607             :                  * columns, and then fix up the dropped and nonlocal cases
   16608             :                  * below.
   16609             :                  */
   16610       39344 :                 if (shouldPrintColumn(dopt, tbinfo, j))
   16611             :                 {
   16612             :                     bool        print_default;
   16613             :                     bool        print_notnull;
   16614             : 
   16615             :                     /*
   16616             :                      * Default value --- suppress if to be printed separately
   16617             :                      * or not at all.
   16618             :                      */
   16619       77150 :                     print_default = (tbinfo->attrdefs[j] != NULL &&
   16620       39554 :                                      tbinfo->attrdefs[j]->dobj.dump &&
   16621        2060 :                                      !tbinfo->attrdefs[j]->separate);
   16622             : 
   16623             :                     /*
   16624             :                      * Not Null constraint --- print it if it is locally
   16625             :                      * defined, or if binary upgrade.  (In the latter case, we
   16626             :                      * reset conislocal below.)
   16627             :                      */
   16628       41864 :                     print_notnull = (tbinfo->notnull_constrs[j] != NULL &&
   16629        4370 :                                      (tbinfo->notnull_islocal[j] ||
   16630        1206 :                                       dopt->binary_upgrade ||
   16631        1042 :                                       tbinfo->ispartition));
   16632             : 
   16633             :                     /*
   16634             :                      * Skip column if fully defined by reloftype, except in
   16635             :                      * binary upgrade
   16636             :                      */
   16637       37494 :                     if (OidIsValid(tbinfo->reloftype) &&
   16638         100 :                         !print_default && !print_notnull &&
   16639          60 :                         !dopt->binary_upgrade)
   16640          48 :                         continue;
   16641             : 
   16642             :                     /* Format properly if not first attr */
   16643       37446 :                     if (actual_atts == 0)
   16644        9738 :                         appendPQExpBufferStr(q, " (");
   16645             :                     else
   16646       27708 :                         appendPQExpBufferChar(q, ',');
   16647       37446 :                     appendPQExpBufferStr(q, "\n    ");
   16648       37446 :                     actual_atts++;
   16649             : 
   16650             :                     /* Attribute name */
   16651       37446 :                     appendPQExpBufferStr(q, fmtId(tbinfo->attnames[j]));
   16652             : 
   16653       37446 :                     if (tbinfo->attisdropped[j])
   16654             :                     {
   16655             :                         /*
   16656             :                          * ALTER TABLE DROP COLUMN clears
   16657             :                          * pg_attribute.atttypid, so we will not have gotten a
   16658             :                          * valid type name; insert INTEGER as a stopgap. We'll
   16659             :                          * clean things up later.
   16660             :                          */
   16661         168 :                         appendPQExpBufferStr(q, " INTEGER /* dummy */");
   16662             :                         /* and skip to the next column */
   16663         168 :                         continue;
   16664             :                     }
   16665             : 
   16666             :                     /*
   16667             :                      * Attribute type; print it except when creating a typed
   16668             :                      * table ('OF type_name'), but in binary-upgrade mode,
   16669             :                      * print it in that case too.
   16670             :                      */
   16671       37278 :                     if (dopt->binary_upgrade || !OidIsValid(tbinfo->reloftype))
   16672             :                     {
   16673       37246 :                         appendPQExpBuffer(q, " %s",
   16674       37246 :                                           tbinfo->atttypnames[j]);
   16675             :                     }
   16676             : 
   16677       37278 :                     if (print_default)
   16678             :                     {
   16679        1784 :                         if (tbinfo->attgenerated[j] == ATTRIBUTE_GENERATED_STORED)
   16680         568 :                             appendPQExpBuffer(q, " GENERATED ALWAYS AS (%s) STORED",
   16681         568 :                                               tbinfo->attrdefs[j]->adef_expr);
   16682        1216 :                         else if (tbinfo->attgenerated[j] == ATTRIBUTE_GENERATED_VIRTUAL)
   16683         444 :                             appendPQExpBuffer(q, " GENERATED ALWAYS AS (%s)",
   16684         444 :                                               tbinfo->attrdefs[j]->adef_expr);
   16685             :                         else
   16686         772 :                             appendPQExpBuffer(q, " DEFAULT %s",
   16687         772 :                                               tbinfo->attrdefs[j]->adef_expr);
   16688             :                     }
   16689             : 
   16690       41648 :                     print_notnull = (tbinfo->notnull_constrs[j] != NULL &&
   16691        4370 :                                      (tbinfo->notnull_islocal[j] ||
   16692        1206 :                                       dopt->binary_upgrade ||
   16693        1042 :                                       tbinfo->ispartition));
   16694             : 
   16695       37278 :                     if (print_notnull)
   16696             :                     {
   16697        4300 :                         if (tbinfo->notnull_constrs[j][0] == '\0')
   16698        3092 :                             appendPQExpBufferStr(q, " NOT NULL");
   16699             :                         else
   16700        1208 :                             appendPQExpBuffer(q, " CONSTRAINT %s NOT NULL",
   16701        1208 :                                               fmtId(tbinfo->notnull_constrs[j]));
   16702             : 
   16703        4300 :                         if (tbinfo->notnull_noinh[j])
   16704           0 :                             appendPQExpBufferStr(q, " NO INHERIT");
   16705             :                     }
   16706             : 
   16707             :                     /* Add collation if not default for the type */
   16708       37278 :                     if (OidIsValid(tbinfo->attcollation[j]))
   16709             :                     {
   16710             :                         CollInfo   *coll;
   16711             : 
   16712         394 :                         coll = findCollationByOid(tbinfo->attcollation[j]);
   16713         394 :                         if (coll)
   16714         394 :                             appendPQExpBuffer(q, " COLLATE %s",
   16715         394 :                                               fmtQualifiedDumpable(coll));
   16716             :                     }
   16717             :                 }
   16718             : 
   16719             :                 /*
   16720             :                  * On the other hand, if we choose not to print a column
   16721             :                  * (likely because it is created by inheritance), but the
   16722             :                  * column has a locally-defined not-null constraint, we need
   16723             :                  * to dump the constraint as a standalone object.
   16724             :                  *
   16725             :                  * This syntax isn't SQL-conforming, but if you wanted
   16726             :                  * standard output you wouldn't be creating non-standard
   16727             :                  * objects to begin with.
   16728             :                  */
   16729       39128 :                 if (!shouldPrintColumn(dopt, tbinfo, j) &&
   16730        1850 :                     !tbinfo->attisdropped[j] &&
   16731        1116 :                     tbinfo->notnull_constrs[j] != NULL &&
   16732         206 :                     tbinfo->notnull_islocal[j])
   16733             :                 {
   16734             :                     /* Format properly if not first attr */
   16735          32 :                     if (actual_atts == 0)
   16736          24 :                         appendPQExpBufferStr(q, " (");
   16737             :                     else
   16738           8 :                         appendPQExpBufferChar(q, ',');
   16739          32 :                     appendPQExpBufferStr(q, "\n    ");
   16740          32 :                     actual_atts++;
   16741             : 
   16742          32 :                     if (tbinfo->notnull_constrs[j][0] == '\0')
   16743           8 :                         appendPQExpBuffer(q, "NOT NULL %s",
   16744           8 :                                           fmtId(tbinfo->attnames[j]));
   16745             :                     else
   16746          48 :                         appendPQExpBuffer(q, "CONSTRAINT %s NOT NULL %s",
   16747          24 :                                           tbinfo->notnull_constrs[j],
   16748          24 :                                           fmtId(tbinfo->attnames[j]));
   16749             :                 }
   16750             :             }
   16751             : 
   16752             :             /*
   16753             :              * Add non-inherited CHECK constraints, if any.
   16754             :              *
   16755             :              * For partitions, we need to include check constraints even if
   16756             :              * they're not defined locally, because the ALTER TABLE ATTACH
   16757             :              * PARTITION that we'll emit later expects the constraint to be
   16758             :              * there.  (No need to fix conislocal: ATTACH PARTITION does that)
   16759             :              */
   16760       11504 :             for (j = 0; j < tbinfo->ncheck; j++)
   16761             :             {
   16762        1246 :                 ConstraintInfo *constr = &(tbinfo->checkexprs[j]);
   16763             : 
   16764        1246 :                 if (constr->separate ||
   16765        1106 :                     (!constr->conislocal && !tbinfo->ispartition))
   16766         222 :                     continue;
   16767             : 
   16768        1024 :                 if (actual_atts == 0)
   16769          32 :                     appendPQExpBufferStr(q, " (\n    ");
   16770             :                 else
   16771         992 :                     appendPQExpBufferStr(q, ",\n    ");
   16772             : 
   16773        1024 :                 appendPQExpBuffer(q, "CONSTRAINT %s ",
   16774        1024 :                                   fmtId(constr->dobj.name));
   16775        1024 :                 appendPQExpBufferStr(q, constr->condef);
   16776             : 
   16777        1024 :                 actual_atts++;
   16778             :             }
   16779             : 
   16780       10258 :             if (actual_atts)
   16781        9794 :                 appendPQExpBufferStr(q, "\n)");
   16782         464 :             else if (!(OidIsValid(tbinfo->reloftype) && !dopt->binary_upgrade))
   16783             :             {
   16784             :                 /*
   16785             :                  * No attributes? we must have a parenthesized attribute list,
   16786             :                  * even though empty, when not using the OF TYPE syntax.
   16787             :                  */
   16788         440 :                 appendPQExpBufferStr(q, " (\n)");
   16789             :             }
   16790             : 
   16791             :             /*
   16792             :              * Emit the INHERITS clause (not for partitions), except in
   16793             :              * binary-upgrade mode.
   16794             :              */
   16795       10258 :             if (numParents > 0 && !tbinfo->ispartition &&
   16796         750 :                 !dopt->binary_upgrade)
   16797             :             {
   16798         640 :                 appendPQExpBufferStr(q, "\nINHERITS (");
   16799        1344 :                 for (k = 0; k < numParents; k++)
   16800             :                 {
   16801         704 :                     TableInfo  *parentRel = parents[k];
   16802             : 
   16803         704 :                     if (k > 0)
   16804          64 :                         appendPQExpBufferStr(q, ", ");
   16805         704 :                     appendPQExpBufferStr(q, fmtQualifiedDumpable(parentRel));
   16806             :                 }
   16807         640 :                 appendPQExpBufferChar(q, ')');
   16808             :             }
   16809             : 
   16810       10258 :             if (tbinfo->relkind == RELKIND_PARTITIONED_TABLE)
   16811        1074 :                 appendPQExpBuffer(q, "\nPARTITION BY %s", partkeydef);
   16812             : 
   16813       10258 :             if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
   16814          76 :                 appendPQExpBuffer(q, "\nSERVER %s", fmtId(srvname));
   16815             :         }
   16816             : 
   16817       21824 :         if (nonemptyReloptions(tbinfo->reloptions) ||
   16818       10766 :             nonemptyReloptions(tbinfo->toast_reloptions))
   16819             :         {
   16820         292 :             bool        addcomma = false;
   16821             : 
   16822         292 :             appendPQExpBufferStr(q, "\nWITH (");
   16823         292 :             if (nonemptyReloptions(tbinfo->reloptions))
   16824             :             {
   16825         292 :                 addcomma = true;
   16826         292 :                 appendReloptionsArrayAH(q, tbinfo->reloptions, "", fout);
   16827             :             }
   16828         292 :             if (nonemptyReloptions(tbinfo->toast_reloptions))
   16829             :             {
   16830          10 :                 if (addcomma)
   16831          10 :                     appendPQExpBufferStr(q, ", ");
   16832          10 :                 appendReloptionsArrayAH(q, tbinfo->toast_reloptions, "toast.",
   16833             :                                         fout);
   16834             :             }
   16835         292 :             appendPQExpBufferChar(q, ')');
   16836             :         }
   16837             : 
   16838             :         /* Dump generic options if any */
   16839       11058 :         if (ftoptions && ftoptions[0])
   16840          72 :             appendPQExpBuffer(q, "\nOPTIONS (\n    %s\n)", ftoptions);
   16841             : 
   16842             :         /*
   16843             :          * For materialized views, create the AS clause just like a view. At
   16844             :          * this point, we always mark the view as not populated.
   16845             :          */
   16846       11058 :         if (tbinfo->relkind == RELKIND_MATVIEW)
   16847             :         {
   16848             :             PQExpBuffer result;
   16849             : 
   16850         800 :             result = createViewAsClause(fout, tbinfo);
   16851         800 :             appendPQExpBuffer(q, " AS\n%s\n  WITH NO DATA;\n",
   16852             :                               result->data);
   16853         800 :             destroyPQExpBuffer(result);
   16854             :         }
   16855             :         else
   16856       10258 :             appendPQExpBufferStr(q, ";\n");
   16857             : 
   16858             :         /* Materialized views can depend on extensions */
   16859       11058 :         if (tbinfo->relkind == RELKIND_MATVIEW)
   16860         800 :             append_depends_on_extension(fout, q, &tbinfo->dobj,
   16861             :                                         "pg_catalog.pg_class",
   16862             :                                         "MATERIALIZED VIEW",
   16863             :                                         qualrelname);
   16864             : 
   16865             :         /*
   16866             :          * in binary upgrade mode, update the catalog with any missing values
   16867             :          * that might be present.
   16868             :          */
   16869       11058 :         if (dopt->binary_upgrade)
   16870             :         {
   16871        7702 :             for (j = 0; j < tbinfo->numatts; j++)
   16872             :             {
   16873        6158 :                 if (tbinfo->attmissingval[j][0] != '\0')
   16874             :                 {
   16875           4 :                     appendPQExpBufferStr(q, "\n-- set missing value.\n");
   16876           4 :                     appendPQExpBufferStr(q,
   16877             :                                          "SELECT pg_catalog.binary_upgrade_set_missing_value(");
   16878           4 :                     appendStringLiteralAH(q, qualrelname, fout);
   16879           4 :                     appendPQExpBufferStr(q, "::pg_catalog.regclass,");
   16880           4 :                     appendStringLiteralAH(q, tbinfo->attnames[j], fout);
   16881           4 :                     appendPQExpBufferChar(q, ',');
   16882           4 :                     appendStringLiteralAH(q, tbinfo->attmissingval[j], fout);
   16883           4 :                     appendPQExpBufferStr(q, ");\n\n");
   16884             :                 }
   16885             :             }
   16886             :         }
   16887             : 
   16888             :         /*
   16889             :          * To create binary-compatible heap files, we have to ensure the same
   16890             :          * physical column order, including dropped columns, as in the
   16891             :          * original.  Therefore, we create dropped columns above and drop them
   16892             :          * here, also updating their attlen/attalign values so that the
   16893             :          * dropped column can be skipped properly.  (We do not bother with
   16894             :          * restoring the original attbyval setting.)  Also, inheritance
   16895             :          * relationships are set up by doing ALTER TABLE INHERIT rather than
   16896             :          * using an INHERITS clause --- the latter would possibly mess up the
   16897             :          * column order.  That also means we have to take care about setting
   16898             :          * attislocal correctly, plus fix up any inherited CHECK constraints.
   16899             :          * Analogously, we set up typed tables using ALTER TABLE / OF here.
   16900             :          *
   16901             :          * We process foreign and partitioned tables here, even though they
   16902             :          * lack heap storage, because they can participate in inheritance
   16903             :          * relationships and we want this stuff to be consistent across the
   16904             :          * inheritance tree.  We can exclude indexes, toast tables, sequences
   16905             :          * and matviews, even though they have storage, because we don't
   16906             :          * support altering or dropping columns in them, nor can they be part
   16907             :          * of inheritance trees.
   16908             :          */
   16909       11058 :         if (dopt->binary_upgrade &&
   16910        1544 :             (tbinfo->relkind == RELKIND_RELATION ||
   16911         214 :              tbinfo->relkind == RELKIND_FOREIGN_TABLE ||
   16912         212 :              tbinfo->relkind == RELKIND_PARTITIONED_TABLE))
   16913             :         {
   16914             :             bool        firstitem;
   16915             :             bool        firstitem_extra;
   16916             : 
   16917             :             /*
   16918             :              * Drop any dropped columns.  Merge the pg_attribute manipulations
   16919             :              * into a single SQL command, so that we don't cause repeated
   16920             :              * relcache flushes on the target table.  Otherwise we risk O(N^2)
   16921             :              * relcache bloat while dropping N columns.
   16922             :              */
   16923        1508 :             resetPQExpBuffer(extra);
   16924        1508 :             firstitem = true;
   16925        7622 :             for (j = 0; j < tbinfo->numatts; j++)
   16926             :             {
   16927        6114 :                 if (tbinfo->attisdropped[j])
   16928             :                 {
   16929         168 :                     if (firstitem)
   16930             :                     {
   16931          76 :                         appendPQExpBufferStr(q, "\n-- For binary upgrade, recreate dropped columns.\n"
   16932             :                                              "UPDATE pg_catalog.pg_attribute\n"
   16933             :                                              "SET attlen = v.dlen, "
   16934             :                                              "attalign = v.dalign, "
   16935             :                                              "attbyval = false\n"
   16936             :                                              "FROM (VALUES ");
   16937          76 :                         firstitem = false;
   16938             :                     }
   16939             :                     else
   16940          92 :                         appendPQExpBufferStr(q, ",\n             ");
   16941         168 :                     appendPQExpBufferChar(q, '(');
   16942         168 :                     appendStringLiteralAH(q, tbinfo->attnames[j], fout);
   16943         168 :                     appendPQExpBuffer(q, ", %d, '%c')",
   16944         168 :                                       tbinfo->attlen[j],
   16945         168 :                                       tbinfo->attalign[j]);
   16946             :                     /* The ALTER ... DROP COLUMN commands must come after */
   16947         168 :                     appendPQExpBuffer(extra, "ALTER %sTABLE ONLY %s ",
   16948             :                                       foreign, qualrelname);
   16949         168 :                     appendPQExpBuffer(extra, "DROP COLUMN %s;\n",
   16950         168 :                                       fmtId(tbinfo->attnames[j]));
   16951             :                 }
   16952             :             }
   16953        1508 :             if (!firstitem)
   16954             :             {
   16955          76 :                 appendPQExpBufferStr(q, ") v(dname, dlen, dalign)\n"
   16956             :                                      "WHERE attrelid = ");
   16957          76 :                 appendStringLiteralAH(q, qualrelname, fout);
   16958          76 :                 appendPQExpBufferStr(q, "::pg_catalog.regclass\n"
   16959             :                                      "  AND attname = v.dname;\n");
   16960             :                 /* Now we can issue the actual DROP COLUMN commands */
   16961          76 :                 appendBinaryPQExpBuffer(q, extra->data, extra->len);
   16962             :             }
   16963             : 
   16964             :             /*
   16965             :              * Fix up inherited columns.  As above, do the pg_attribute
   16966             :              * manipulations in a single SQL command.
   16967             :              */
   16968        1508 :             firstitem = true;
   16969        7622 :             for (j = 0; j < tbinfo->numatts; j++)
   16970             :             {
   16971        6114 :                 if (!tbinfo->attisdropped[j] &&
   16972        5946 :                     !tbinfo->attislocal[j])
   16973             :                 {
   16974        1174 :                     if (firstitem)
   16975             :                     {
   16976         508 :                         appendPQExpBufferStr(q, "\n-- For binary upgrade, recreate inherited columns.\n");
   16977         508 :                         appendPQExpBufferStr(q, "UPDATE pg_catalog.pg_attribute\n"
   16978             :                                              "SET attislocal = false\n"
   16979             :                                              "WHERE attrelid = ");
   16980         508 :                         appendStringLiteralAH(q, qualrelname, fout);
   16981         508 :                         appendPQExpBufferStr(q, "::pg_catalog.regclass\n"
   16982             :                                              "  AND attname IN (");
   16983         508 :                         firstitem = false;
   16984             :                     }
   16985             :                     else
   16986         666 :                         appendPQExpBufferStr(q, ", ");
   16987        1174 :                     appendStringLiteralAH(q, tbinfo->attnames[j], fout);
   16988             :                 }
   16989             :             }
   16990        1508 :             if (!firstitem)
   16991         508 :                 appendPQExpBufferStr(q, ");\n");
   16992             : 
   16993             :             /*
   16994             :              * Fix up not-null constraints that come from inheritance.  As
   16995             :              * above, do the pg_constraint manipulations in a single SQL
   16996             :              * command.  (Actually, two in special cases, if we're doing an
   16997             :              * upgrade from < 18).
   16998             :              */
   16999        1508 :             firstitem = true;
   17000        1508 :             firstitem_extra = true;
   17001        1508 :             resetPQExpBuffer(extra);
   17002        7622 :             for (j = 0; j < tbinfo->numatts; j++)
   17003             :             {
   17004             :                 /*
   17005             :                  * If a not-null constraint comes from inheritance, reset
   17006             :                  * conislocal.  The inhcount is fixed by ALTER TABLE INHERIT,
   17007             :                  * below.  Special hack: in versions < 18, columns with no
   17008             :                  * local definition need their constraint to be matched by
   17009             :                  * column number in conkeys instead of by constraint name,
   17010             :                  * because the latter is not available.  (We distinguish the
   17011             :                  * case because the constraint name is the empty string.)
   17012             :                  */
   17013        6114 :                 if (tbinfo->notnull_constrs[j] != NULL &&
   17014         550 :                     !tbinfo->notnull_islocal[j])
   17015             :                 {
   17016         164 :                     if (tbinfo->notnull_constrs[j][0] != '\0')
   17017             :                     {
   17018         138 :                         if (firstitem)
   17019             :                         {
   17020         118 :                             appendPQExpBufferStr(q, "UPDATE pg_catalog.pg_constraint\n"
   17021             :                                                  "SET conislocal = false\n"
   17022             :                                                  "WHERE contype = 'n' AND conrelid = ");
   17023         118 :                             appendStringLiteralAH(q, qualrelname, fout);
   17024         118 :                             appendPQExpBufferStr(q, "::pg_catalog.regclass AND\n"
   17025             :                                                  "conname IN (");
   17026         118 :                             firstitem = false;
   17027             :                         }
   17028             :                         else
   17029          20 :                             appendPQExpBufferStr(q, ", ");
   17030         138 :                         appendStringLiteralAH(q, tbinfo->notnull_constrs[j], fout);
   17031             :                     }
   17032             :                     else
   17033             :                     {
   17034          26 :                         if (firstitem_extra)
   17035             :                         {
   17036          26 :                             appendPQExpBufferStr(extra, "UPDATE pg_catalog.pg_constraint\n"
   17037             :                                                  "SET conislocal = false\n"
   17038             :                                                  "WHERE contype = 'n' AND conrelid = ");
   17039          26 :                             appendStringLiteralAH(extra, qualrelname, fout);
   17040          26 :                             appendPQExpBufferStr(extra, "::pg_catalog.regclass AND\n"
   17041             :                                                  "conkey IN (");
   17042          26 :                             firstitem_extra = false;
   17043             :                         }
   17044             :                         else
   17045           0 :                             appendPQExpBufferStr(extra, ", ");
   17046          26 :                         appendPQExpBuffer(extra, "'{%d}'", j + 1);
   17047             :                     }
   17048             :                 }
   17049             :             }
   17050        1508 :             if (!firstitem)
   17051         118 :                 appendPQExpBufferStr(q, ");\n");
   17052        1508 :             if (!firstitem_extra)
   17053          26 :                 appendPQExpBufferStr(extra, ");\n");
   17054             : 
   17055        1508 :             if (extra->len > 0)
   17056          26 :                 appendBinaryPQExpBuffer(q, extra->data, extra->len);
   17057             : 
   17058             :             /*
   17059             :              * Add inherited CHECK constraints, if any.
   17060             :              *
   17061             :              * For partitions, they were already dumped, and conislocal
   17062             :              * doesn't need fixing.
   17063             :              *
   17064             :              * As above, issue only one direct manipulation of pg_constraint.
   17065             :              * Although it is tempting to merge the ALTER ADD CONSTRAINT
   17066             :              * commands into one as well, refrain for now due to concern about
   17067             :              * possible backend memory bloat if there are many such
   17068             :              * constraints.
   17069             :              */
   17070        1508 :             resetPQExpBuffer(extra);
   17071        1508 :             firstitem = true;
   17072        1636 :             for (k = 0; k < tbinfo->ncheck; k++)
   17073             :             {
   17074         128 :                 ConstraintInfo *constr = &(tbinfo->checkexprs[k]);
   17075             : 
   17076         128 :                 if (constr->separate || constr->conislocal || tbinfo->ispartition)
   17077         124 :                     continue;
   17078             : 
   17079           4 :                 if (firstitem)
   17080           4 :                     appendPQExpBufferStr(q, "\n-- For binary upgrade, set up inherited constraints.\n");
   17081           4 :                 appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s ADD CONSTRAINT %s %s;\n",
   17082             :                                   foreign, qualrelname,
   17083           4 :                                   fmtId(constr->dobj.name),
   17084             :                                   constr->condef);
   17085             :                 /* Update pg_constraint after all the ALTER TABLEs */
   17086           4 :                 if (firstitem)
   17087             :                 {
   17088           4 :                     appendPQExpBufferStr(extra, "UPDATE pg_catalog.pg_constraint\n"
   17089             :                                          "SET conislocal = false\n"
   17090             :                                          "WHERE contype = 'c' AND conrelid = ");
   17091           4 :                     appendStringLiteralAH(extra, qualrelname, fout);
   17092           4 :                     appendPQExpBufferStr(extra, "::pg_catalog.regclass\n");
   17093           4 :                     appendPQExpBufferStr(extra, "  AND conname IN (");
   17094           4 :                     firstitem = false;
   17095             :                 }
   17096             :                 else
   17097           0 :                     appendPQExpBufferStr(extra, ", ");
   17098           4 :                 appendStringLiteralAH(extra, constr->dobj.name, fout);
   17099             :             }
   17100        1508 :             if (!firstitem)
   17101             :             {
   17102           4 :                 appendPQExpBufferStr(extra, ");\n");
   17103           4 :                 appendBinaryPQExpBuffer(q, extra->data, extra->len);
   17104             :             }
   17105             : 
   17106        1508 :             if (numParents > 0 && !tbinfo->ispartition)
   17107             :             {
   17108         110 :                 appendPQExpBufferStr(q, "\n-- For binary upgrade, set up inheritance this way.\n");
   17109         236 :                 for (k = 0; k < numParents; k++)
   17110             :                 {
   17111         126 :                     TableInfo  *parentRel = parents[k];
   17112             : 
   17113         126 :                     appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s INHERIT %s;\n", foreign,
   17114             :                                       qualrelname,
   17115         126 :                                       fmtQualifiedDumpable(parentRel));
   17116             :                 }
   17117             :             }
   17118             : 
   17119        1508 :             if (OidIsValid(tbinfo->reloftype))
   17120             :             {
   17121          12 :                 appendPQExpBufferStr(q, "\n-- For binary upgrade, set up typed tables this way.\n");
   17122          12 :                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s OF %s;\n",
   17123             :                                   qualrelname,
   17124             :                                   getFormattedTypeName(fout, tbinfo->reloftype,
   17125             :                                                        zeroIsError));
   17126             :             }
   17127             :         }
   17128             : 
   17129             :         /*
   17130             :          * In binary_upgrade mode, arrange to restore the old relfrozenxid and
   17131             :          * relminmxid of all vacuumable relations.  (While vacuum.c processes
   17132             :          * TOAST tables semi-independently, here we see them only as children
   17133             :          * of other relations; so this "if" lacks RELKIND_TOASTVALUE, and the
   17134             :          * child toast table is handled below.)
   17135             :          */
   17136       11058 :         if (dopt->binary_upgrade &&
   17137        1544 :             (tbinfo->relkind == RELKIND_RELATION ||
   17138         214 :              tbinfo->relkind == RELKIND_MATVIEW))
   17139             :         {
   17140        1366 :             appendPQExpBufferStr(q, "\n-- For binary upgrade, set heap's relfrozenxid and relminmxid\n");
   17141        1366 :             appendPQExpBuffer(q, "UPDATE pg_catalog.pg_class\n"
   17142             :                               "SET relfrozenxid = '%u', relminmxid = '%u'\n"
   17143             :                               "WHERE oid = ",
   17144             :                               tbinfo->frozenxid, tbinfo->minmxid);
   17145        1366 :             appendStringLiteralAH(q, qualrelname, fout);
   17146        1366 :             appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
   17147             : 
   17148        1366 :             if (tbinfo->toast_oid)
   17149             :             {
   17150             :                 /*
   17151             :                  * The toast table will have the same OID at restore, so we
   17152             :                  * can safely target it by OID.
   17153             :                  */
   17154         552 :                 appendPQExpBufferStr(q, "\n-- For binary upgrade, set toast's relfrozenxid and relminmxid\n");
   17155         552 :                 appendPQExpBuffer(q, "UPDATE pg_catalog.pg_class\n"
   17156             :                                   "SET relfrozenxid = '%u', relminmxid = '%u'\n"
   17157             :                                   "WHERE oid = '%u';\n",
   17158             :                                   tbinfo->toast_frozenxid,
   17159             :                                   tbinfo->toast_minmxid, tbinfo->toast_oid);
   17160             :             }
   17161             :         }
   17162             : 
   17163             :         /*
   17164             :          * In binary_upgrade mode, restore matviews' populated status by
   17165             :          * poking pg_class directly.  This is pretty ugly, but we can't use
   17166             :          * REFRESH MATERIALIZED VIEW since it's possible that some underlying
   17167             :          * matview is not populated even though this matview is; in any case,
   17168             :          * we want to transfer the matview's heap storage, not run REFRESH.
   17169             :          */
   17170       11058 :         if (dopt->binary_upgrade && tbinfo->relkind == RELKIND_MATVIEW &&
   17171          36 :             tbinfo->relispopulated)
   17172             :         {
   17173          32 :             appendPQExpBufferStr(q, "\n-- For binary upgrade, mark materialized view as populated\n");
   17174          32 :             appendPQExpBufferStr(q, "UPDATE pg_catalog.pg_class\n"
   17175             :                                  "SET relispopulated = 't'\n"
   17176             :                                  "WHERE oid = ");
   17177          32 :             appendStringLiteralAH(q, qualrelname, fout);
   17178          32 :             appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
   17179             :         }
   17180             : 
   17181             :         /*
   17182             :          * Dump additional per-column properties that we can't handle in the
   17183             :          * main CREATE TABLE command.
   17184             :          */
   17185       51366 :         for (j = 0; j < tbinfo->numatts; j++)
   17186             :         {
   17187             :             /* None of this applies to dropped columns */
   17188       40308 :             if (tbinfo->attisdropped[j])
   17189         902 :                 continue;
   17190             : 
   17191             :             /*
   17192             :              * Dump per-column statistics information. We only issue an ALTER
   17193             :              * TABLE statement if the attstattarget entry for this column is
   17194             :              * not the default value.
   17195             :              */
   17196       39406 :             if (tbinfo->attstattarget[j] >= 0)
   17197          72 :                 appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s ALTER COLUMN %s SET STATISTICS %d;\n",
   17198             :                                   foreign, qualrelname,
   17199          72 :                                   fmtId(tbinfo->attnames[j]),
   17200          72 :                                   tbinfo->attstattarget[j]);
   17201             : 
   17202             :             /*
   17203             :              * Dump per-column storage information.  The statement is only
   17204             :              * dumped if the storage has been changed from the type's default.
   17205             :              */
   17206       39406 :             if (tbinfo->attstorage[j] != tbinfo->typstorage[j])
   17207             :             {
   17208         174 :                 switch (tbinfo->attstorage[j])
   17209             :                 {
   17210          20 :                     case TYPSTORAGE_PLAIN:
   17211          20 :                         storage = "PLAIN";
   17212          20 :                         break;
   17213          82 :                     case TYPSTORAGE_EXTERNAL:
   17214          82 :                         storage = "EXTERNAL";
   17215          82 :                         break;
   17216           0 :                     case TYPSTORAGE_EXTENDED:
   17217           0 :                         storage = "EXTENDED";
   17218           0 :                         break;
   17219          72 :                     case TYPSTORAGE_MAIN:
   17220          72 :                         storage = "MAIN";
   17221          72 :                         break;
   17222           0 :                     default:
   17223           0 :                         storage = NULL;
   17224             :                 }
   17225             : 
   17226             :                 /*
   17227             :                  * Only dump the statement if it's a storage type we recognize
   17228             :                  */
   17229         174 :                 if (storage != NULL)
   17230         174 :                     appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s ALTER COLUMN %s SET STORAGE %s;\n",
   17231             :                                       foreign, qualrelname,
   17232         174 :                                       fmtId(tbinfo->attnames[j]),
   17233             :                                       storage);
   17234             :             }
   17235             : 
   17236             :             /*
   17237             :              * Dump per-column compression, if it's been set.
   17238             :              */
   17239       39406 :             if (!dopt->no_toast_compression)
   17240             :             {
   17241             :                 const char *cmname;
   17242             : 
   17243       39226 :                 switch (tbinfo->attcompression[j])
   17244             :                 {
   17245         120 :                     case 'p':
   17246         120 :                         cmname = "pglz";
   17247         120 :                         break;
   17248         200 :                     case 'l':
   17249         200 :                         cmname = "lz4";
   17250         200 :                         break;
   17251       38906 :                     default:
   17252       38906 :                         cmname = NULL;
   17253       38906 :                         break;
   17254             :                 }
   17255             : 
   17256       39226 :                 if (cmname != NULL)
   17257         320 :                     appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s ALTER COLUMN %s SET COMPRESSION %s;\n",
   17258             :                                       foreign, qualrelname,
   17259         320 :                                       fmtId(tbinfo->attnames[j]),
   17260             :                                       cmname);
   17261             :             }
   17262             : 
   17263             :             /*
   17264             :              * Dump per-column attributes.
   17265             :              */
   17266       39406 :             if (tbinfo->attoptions[j][0] != '\0')
   17267          72 :                 appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s ALTER COLUMN %s SET (%s);\n",
   17268             :                                   foreign, qualrelname,
   17269          72 :                                   fmtId(tbinfo->attnames[j]),
   17270          72 :                                   tbinfo->attoptions[j]);
   17271             : 
   17272             :             /*
   17273             :              * Dump per-column fdw options.
   17274             :              */
   17275       39406 :             if (tbinfo->relkind == RELKIND_FOREIGN_TABLE &&
   17276          76 :                 tbinfo->attfdwoptions[j][0] != '\0')
   17277          72 :                 appendPQExpBuffer(q,
   17278             :                                   "ALTER FOREIGN TABLE ONLY %s ALTER COLUMN %s OPTIONS (\n"
   17279             :                                   "    %s\n"
   17280             :                                   ");\n",
   17281             :                                   qualrelname,
   17282          72 :                                   fmtId(tbinfo->attnames[j]),
   17283          72 :                                   tbinfo->attfdwoptions[j]);
   17284             :         }                       /* end loop over columns */
   17285             : 
   17286       11058 :         free(partkeydef);
   17287       11058 :         free(ftoptions);
   17288       11058 :         free(srvname);
   17289             :     }
   17290             : 
   17291             :     /*
   17292             :      * dump properties we only have ALTER TABLE syntax for
   17293             :      */
   17294       12098 :     if ((tbinfo->relkind == RELKIND_RELATION ||
   17295        2990 :          tbinfo->relkind == RELKIND_PARTITIONED_TABLE ||
   17296        1916 :          tbinfo->relkind == RELKIND_MATVIEW) &&
   17297       10982 :         tbinfo->relreplident != REPLICA_IDENTITY_DEFAULT)
   17298             :     {
   17299         384 :         if (tbinfo->relreplident == REPLICA_IDENTITY_INDEX)
   17300             :         {
   17301             :             /* nothing to do, will be set when the index is dumped */
   17302             :         }
   17303         384 :         else if (tbinfo->relreplident == REPLICA_IDENTITY_NOTHING)
   17304             :         {
   17305         384 :             appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY NOTHING;\n",
   17306             :                               qualrelname);
   17307             :         }
   17308           0 :         else if (tbinfo->relreplident == REPLICA_IDENTITY_FULL)
   17309             :         {
   17310           0 :             appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY FULL;\n",
   17311             :                               qualrelname);
   17312             :         }
   17313             :     }
   17314             : 
   17315       12098 :     if (tbinfo->forcerowsec)
   17316          10 :         appendPQExpBuffer(q, "\nALTER TABLE ONLY %s FORCE ROW LEVEL SECURITY;\n",
   17317             :                           qualrelname);
   17318             : 
   17319       12098 :     if (dopt->binary_upgrade)
   17320        1646 :         binary_upgrade_extension_member(q, &tbinfo->dobj,
   17321             :                                         reltypename, qrelname,
   17322        1646 :                                         tbinfo->dobj.namespace->dobj.name);
   17323             : 
   17324       12098 :     if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   17325             :     {
   17326       12098 :         char       *tablespace = NULL;
   17327       12098 :         char       *tableam = NULL;
   17328             : 
   17329             :         /*
   17330             :          * _selectTablespace() relies on tablespace-enabled objects in the
   17331             :          * default tablespace to have a tablespace of "" (empty string) versus
   17332             :          * non-tablespace-enabled objects to have a tablespace of NULL.
   17333             :          * getTables() sets tbinfo->reltablespace to "" for the default
   17334             :          * tablespace (not NULL).
   17335             :          */
   17336       12098 :         if (RELKIND_HAS_TABLESPACE(tbinfo->relkind))
   17337       10982 :             tablespace = tbinfo->reltablespace;
   17338             : 
   17339       12098 :         if (RELKIND_HAS_TABLE_AM(tbinfo->relkind) ||
   17340        2190 :             tbinfo->relkind == RELKIND_PARTITIONED_TABLE)
   17341       10982 :             tableam = tbinfo->amname;
   17342             : 
   17343       12098 :         ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
   17344       12098 :                      ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
   17345             :                                   .namespace = tbinfo->dobj.namespace->dobj.name,
   17346             :                                   .tablespace = tablespace,
   17347             :                                   .tableam = tableam,
   17348             :                                   .relkind = tbinfo->relkind,
   17349             :                                   .owner = tbinfo->rolname,
   17350             :                                   .description = reltypename,
   17351             :                                   .section = tbinfo->postponed_def ?
   17352             :                                   SECTION_POST_DATA : SECTION_PRE_DATA,
   17353             :                                   .createStmt = q->data,
   17354             :                                   .dropStmt = delq->data));
   17355             :     }
   17356             : 
   17357             :     /* Dump Table Comments */
   17358       12098 :     if (tbinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   17359         164 :         dumpTableComment(fout, tbinfo, reltypename);
   17360             : 
   17361             :     /* Dump Table Security Labels */
   17362       12098 :     if (tbinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
   17363           0 :         dumpTableSecLabel(fout, tbinfo, reltypename);
   17364             : 
   17365             :     /* Dump comments on inlined table constraints */
   17366       13344 :     for (j = 0; j < tbinfo->ncheck; j++)
   17367             :     {
   17368        1246 :         ConstraintInfo *constr = &(tbinfo->checkexprs[j]);
   17369             : 
   17370        1246 :         if (constr->separate || !constr->conislocal)
   17371         528 :             continue;
   17372             : 
   17373         718 :         if (constr->dobj.dump & DUMP_COMPONENT_COMMENT)
   17374          82 :             dumpTableConstraintComment(fout, constr);
   17375             :     }
   17376             : 
   17377       12098 :     destroyPQExpBuffer(q);
   17378       12098 :     destroyPQExpBuffer(delq);
   17379       12098 :     destroyPQExpBuffer(extra);
   17380       12098 :     free(qrelname);
   17381       12098 :     free(qualrelname);
   17382       12098 : }
   17383             : 
   17384             : /*
   17385             :  * dumpTableAttach
   17386             :  *    write to fout the commands to attach a child partition
   17387             :  *
   17388             :  * Child partitions are always made by creating them separately
   17389             :  * and then using ATTACH PARTITION, rather than using
   17390             :  * CREATE TABLE ... PARTITION OF.  This is important for preserving
   17391             :  * any possible discrepancy in column layout, to allow assigning the
   17392             :  * correct tablespace if different, and so that it's possible to restore
   17393             :  * a partition without restoring its parent.  (You'll get an error from
   17394             :  * the ATTACH PARTITION command, but that can be ignored, or skipped
   17395             :  * using "pg_restore -L" if you prefer.)  The last point motivates
   17396             :  * treating ATTACH PARTITION as a completely separate ArchiveEntry
   17397             :  * rather than emitting it within the child partition's ArchiveEntry.
   17398             :  */
   17399             : static void
   17400        2630 : dumpTableAttach(Archive *fout, const TableAttachInfo *attachinfo)
   17401             : {
   17402        2630 :     DumpOptions *dopt = fout->dopt;
   17403             :     PQExpBuffer q;
   17404             :     PGresult   *res;
   17405             :     char       *partbound;
   17406             : 
   17407             :     /* Do nothing if not dumping schema */
   17408        2630 :     if (!dopt->dumpSchema)
   17409          84 :         return;
   17410             : 
   17411        2546 :     q = createPQExpBuffer();
   17412             : 
   17413        2546 :     if (!fout->is_prepared[PREPQUERY_DUMPTABLEATTACH])
   17414             :     {
   17415             :         /* Set up query for partbound details */
   17416          94 :         appendPQExpBufferStr(q,
   17417             :                              "PREPARE dumpTableAttach(pg_catalog.oid) AS\n");
   17418             : 
   17419          94 :         appendPQExpBufferStr(q,
   17420             :                              "SELECT pg_get_expr(c.relpartbound, c.oid) "
   17421             :                              "FROM pg_class c "
   17422             :                              "WHERE c.oid = $1");
   17423             : 
   17424          94 :         ExecuteSqlStatement(fout, q->data);
   17425             : 
   17426          94 :         fout->is_prepared[PREPQUERY_DUMPTABLEATTACH] = true;
   17427             :     }
   17428             : 
   17429        2546 :     printfPQExpBuffer(q,
   17430             :                       "EXECUTE dumpTableAttach('%u')",
   17431        2546 :                       attachinfo->partitionTbl->dobj.catId.oid);
   17432             : 
   17433        2546 :     res = ExecuteSqlQueryForSingleRow(fout, q->data);
   17434        2546 :     partbound = PQgetvalue(res, 0, 0);
   17435             : 
   17436             :     /* Perform ALTER TABLE on the parent */
   17437        2546 :     printfPQExpBuffer(q,
   17438             :                       "ALTER TABLE ONLY %s ",
   17439        2546 :                       fmtQualifiedDumpable(attachinfo->parentTbl));
   17440        2546 :     appendPQExpBuffer(q,
   17441             :                       "ATTACH PARTITION %s %s;\n",
   17442        2546 :                       fmtQualifiedDumpable(attachinfo->partitionTbl),
   17443             :                       partbound);
   17444             : 
   17445             :     /*
   17446             :      * There is no point in creating a drop query as the drop is done by table
   17447             :      * drop.  (If you think to change this, see also _printTocEntry().)
   17448             :      * Although this object doesn't really have ownership as such, set the
   17449             :      * owner field anyway to ensure that the command is run by the correct
   17450             :      * role at restore time.
   17451             :      */
   17452        2546 :     ArchiveEntry(fout, attachinfo->dobj.catId, attachinfo->dobj.dumpId,
   17453        2546 :                  ARCHIVE_OPTS(.tag = attachinfo->dobj.name,
   17454             :                               .namespace = attachinfo->dobj.namespace->dobj.name,
   17455             :                               .owner = attachinfo->partitionTbl->rolname,
   17456             :                               .description = "TABLE ATTACH",
   17457             :                               .section = SECTION_PRE_DATA,
   17458             :                               .createStmt = q->data));
   17459             : 
   17460        2546 :     PQclear(res);
   17461        2546 :     destroyPQExpBuffer(q);
   17462             : }
   17463             : 
   17464             : /*
   17465             :  * dumpAttrDef --- dump an attribute's default-value declaration
   17466             :  */
   17467             : static void
   17468        2140 : dumpAttrDef(Archive *fout, const AttrDefInfo *adinfo)
   17469             : {
   17470        2140 :     DumpOptions *dopt = fout->dopt;
   17471        2140 :     TableInfo  *tbinfo = adinfo->adtable;
   17472        2140 :     int         adnum = adinfo->adnum;
   17473             :     PQExpBuffer q;
   17474             :     PQExpBuffer delq;
   17475             :     char       *qualrelname;
   17476             :     char       *tag;
   17477             :     char       *foreign;
   17478             : 
   17479             :     /* Do nothing if not dumping schema */
   17480        2140 :     if (!dopt->dumpSchema)
   17481           0 :         return;
   17482             : 
   17483             :     /* Skip if not "separate"; it was dumped in the table's definition */
   17484        2140 :     if (!adinfo->separate)
   17485        1784 :         return;
   17486             : 
   17487         356 :     q = createPQExpBuffer();
   17488         356 :     delq = createPQExpBuffer();
   17489             : 
   17490         356 :     qualrelname = pg_strdup(fmtQualifiedDumpable(tbinfo));
   17491             : 
   17492         356 :     foreign = tbinfo->relkind == RELKIND_FOREIGN_TABLE ? "FOREIGN " : "";
   17493             : 
   17494         356 :     appendPQExpBuffer(q,
   17495             :                       "ALTER %sTABLE ONLY %s ALTER COLUMN %s SET DEFAULT %s;\n",
   17496         356 :                       foreign, qualrelname, fmtId(tbinfo->attnames[adnum - 1]),
   17497             :                       adinfo->adef_expr);
   17498             : 
   17499         356 :     appendPQExpBuffer(delq, "ALTER %sTABLE %s ALTER COLUMN %s DROP DEFAULT;\n",
   17500             :                       foreign, qualrelname,
   17501         356 :                       fmtId(tbinfo->attnames[adnum - 1]));
   17502             : 
   17503         356 :     tag = psprintf("%s %s", tbinfo->dobj.name, tbinfo->attnames[adnum - 1]);
   17504             : 
   17505         356 :     if (adinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   17506         356 :         ArchiveEntry(fout, adinfo->dobj.catId, adinfo->dobj.dumpId,
   17507         356 :                      ARCHIVE_OPTS(.tag = tag,
   17508             :                                   .namespace = tbinfo->dobj.namespace->dobj.name,
   17509             :                                   .owner = tbinfo->rolname,
   17510             :                                   .description = "DEFAULT",
   17511             :                                   .section = SECTION_PRE_DATA,
   17512             :                                   .createStmt = q->data,
   17513             :                                   .dropStmt = delq->data));
   17514             : 
   17515         356 :     free(tag);
   17516         356 :     destroyPQExpBuffer(q);
   17517         356 :     destroyPQExpBuffer(delq);
   17518         356 :     free(qualrelname);
   17519             : }
   17520             : 
   17521             : /*
   17522             :  * getAttrName: extract the correct name for an attribute
   17523             :  *
   17524             :  * The array tblInfo->attnames[] only provides names of user attributes;
   17525             :  * if a system attribute number is supplied, we have to fake it.
   17526             :  * We also do a little bit of bounds checking for safety's sake.
   17527             :  */
   17528             : static const char *
   17529        4200 : getAttrName(int attrnum, const TableInfo *tblInfo)
   17530             : {
   17531        4200 :     if (attrnum > 0 && attrnum <= tblInfo->numatts)
   17532        4200 :         return tblInfo->attnames[attrnum - 1];
   17533           0 :     switch (attrnum)
   17534             :     {
   17535           0 :         case SelfItemPointerAttributeNumber:
   17536           0 :             return "ctid";
   17537           0 :         case MinTransactionIdAttributeNumber:
   17538           0 :             return "xmin";
   17539           0 :         case MinCommandIdAttributeNumber:
   17540           0 :             return "cmin";
   17541           0 :         case MaxTransactionIdAttributeNumber:
   17542           0 :             return "xmax";
   17543           0 :         case MaxCommandIdAttributeNumber:
   17544           0 :             return "cmax";
   17545           0 :         case TableOidAttributeNumber:
   17546           0 :             return "tableoid";
   17547             :     }
   17548           0 :     pg_fatal("invalid column number %d for table \"%s\"",
   17549             :              attrnum, tblInfo->dobj.name);
   17550             :     return NULL;                /* keep compiler quiet */
   17551             : }
   17552             : 
   17553             : /*
   17554             :  * dumpIndex
   17555             :  *    write out to fout a user-defined index
   17556             :  */
   17557             : static void
   17558        5260 : dumpIndex(Archive *fout, const IndxInfo *indxinfo)
   17559             : {
   17560        5260 :     DumpOptions *dopt = fout->dopt;
   17561        5260 :     TableInfo  *tbinfo = indxinfo->indextable;
   17562        5260 :     bool        is_constraint = (indxinfo->indexconstraint != 0);
   17563             :     PQExpBuffer q;
   17564             :     PQExpBuffer delq;
   17565             :     char       *qindxname;
   17566             :     char       *qqindxname;
   17567             : 
   17568             :     /* Do nothing if not dumping schema */
   17569        5260 :     if (!dopt->dumpSchema)
   17570         234 :         return;
   17571             : 
   17572        5026 :     q = createPQExpBuffer();
   17573        5026 :     delq = createPQExpBuffer();
   17574             : 
   17575        5026 :     qindxname = pg_strdup(fmtId(indxinfo->dobj.name));
   17576        5026 :     qqindxname = pg_strdup(fmtQualifiedDumpable(indxinfo));
   17577             : 
   17578             :     /*
   17579             :      * If there's an associated constraint, don't dump the index per se, but
   17580             :      * do dump any comment for it.  (This is safe because dependency ordering
   17581             :      * will have ensured the constraint is emitted first.)  Note that the
   17582             :      * emitted comment has to be shown as depending on the constraint, not the
   17583             :      * index, in such cases.
   17584             :      */
   17585        5026 :     if (!is_constraint)
   17586             :     {
   17587        2116 :         char       *indstatcols = indxinfo->indstatcols;
   17588        2116 :         char       *indstatvals = indxinfo->indstatvals;
   17589        2116 :         char      **indstatcolsarray = NULL;
   17590        2116 :         char      **indstatvalsarray = NULL;
   17591        2116 :         int         nstatcols = 0;
   17592        2116 :         int         nstatvals = 0;
   17593             : 
   17594        2116 :         if (dopt->binary_upgrade)
   17595         310 :             binary_upgrade_set_pg_class_oids(fout, q,
   17596             :                                              indxinfo->dobj.catId.oid);
   17597             : 
   17598             :         /* Plain secondary index */
   17599        2116 :         appendPQExpBuffer(q, "%s;\n", indxinfo->indexdef);
   17600             : 
   17601             :         /*
   17602             :          * Append ALTER TABLE commands as needed to set properties that we
   17603             :          * only have ALTER TABLE syntax for.  Keep this in sync with the
   17604             :          * similar code in dumpConstraint!
   17605             :          */
   17606             : 
   17607             :         /* If the index is clustered, we need to record that. */
   17608        2116 :         if (indxinfo->indisclustered)
   17609             :         {
   17610           0 :             appendPQExpBuffer(q, "\nALTER TABLE %s CLUSTER",
   17611           0 :                               fmtQualifiedDumpable(tbinfo));
   17612             :             /* index name is not qualified in this syntax */
   17613           0 :             appendPQExpBuffer(q, " ON %s;\n",
   17614             :                               qindxname);
   17615             :         }
   17616             : 
   17617             :         /*
   17618             :          * If the index has any statistics on some of its columns, generate
   17619             :          * the associated ALTER INDEX queries.
   17620             :          */
   17621        2116 :         if (strlen(indstatcols) != 0 || strlen(indstatvals) != 0)
   17622             :         {
   17623             :             int         j;
   17624             : 
   17625          72 :             if (!parsePGArray(indstatcols, &indstatcolsarray, &nstatcols))
   17626           0 :                 pg_fatal("could not parse index statistic columns");
   17627          72 :             if (!parsePGArray(indstatvals, &indstatvalsarray, &nstatvals))
   17628           0 :                 pg_fatal("could not parse index statistic values");
   17629          72 :             if (nstatcols != nstatvals)
   17630           0 :                 pg_fatal("mismatched number of columns and values for index statistics");
   17631             : 
   17632         216 :             for (j = 0; j < nstatcols; j++)
   17633             :             {
   17634         144 :                 appendPQExpBuffer(q, "ALTER INDEX %s ", qqindxname);
   17635             : 
   17636             :                 /*
   17637             :                  * Note that this is a column number, so no quotes should be
   17638             :                  * used.
   17639             :                  */
   17640         144 :                 appendPQExpBuffer(q, "ALTER COLUMN %s ",
   17641         144 :                                   indstatcolsarray[j]);
   17642         144 :                 appendPQExpBuffer(q, "SET STATISTICS %s;\n",
   17643         144 :                                   indstatvalsarray[j]);
   17644             :             }
   17645             :         }
   17646             : 
   17647             :         /* Indexes can depend on extensions */
   17648        2116 :         append_depends_on_extension(fout, q, &indxinfo->dobj,
   17649             :                                     "pg_catalog.pg_class",
   17650             :                                     "INDEX", qqindxname);
   17651             : 
   17652             :         /* If the index defines identity, we need to record that. */
   17653        2116 :         if (indxinfo->indisreplident)
   17654             :         {
   17655           0 :             appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY USING",
   17656           0 :                               fmtQualifiedDumpable(tbinfo));
   17657             :             /* index name is not qualified in this syntax */
   17658           0 :             appendPQExpBuffer(q, " INDEX %s;\n",
   17659             :                               qindxname);
   17660             :         }
   17661             : 
   17662        2116 :         appendPQExpBuffer(delq, "DROP INDEX %s;\n", qqindxname);
   17663             : 
   17664        2116 :         if (indxinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   17665        2116 :             ArchiveEntry(fout, indxinfo->dobj.catId, indxinfo->dobj.dumpId,
   17666        2116 :                          ARCHIVE_OPTS(.tag = indxinfo->dobj.name,
   17667             :                                       .namespace = tbinfo->dobj.namespace->dobj.name,
   17668             :                                       .tablespace = indxinfo->tablespace,
   17669             :                                       .owner = tbinfo->rolname,
   17670             :                                       .description = "INDEX",
   17671             :                                       .section = SECTION_POST_DATA,
   17672             :                                       .createStmt = q->data,
   17673             :                                       .dropStmt = delq->data));
   17674             : 
   17675        2116 :         free(indstatcolsarray);
   17676        2116 :         free(indstatvalsarray);
   17677             :     }
   17678             : 
   17679             :     /* Dump Index Comments */
   17680        5026 :     if (indxinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   17681          30 :         dumpComment(fout, "INDEX", qindxname,
   17682          30 :                     tbinfo->dobj.namespace->dobj.name,
   17683             :                     tbinfo->rolname,
   17684             :                     indxinfo->dobj.catId, 0,
   17685             :                     is_constraint ? indxinfo->indexconstraint :
   17686             :                     indxinfo->dobj.dumpId);
   17687             : 
   17688        5026 :     destroyPQExpBuffer(q);
   17689        5026 :     destroyPQExpBuffer(delq);
   17690        5026 :     free(qindxname);
   17691        5026 :     free(qqindxname);
   17692             : }
   17693             : 
   17694             : /*
   17695             :  * dumpIndexAttach
   17696             :  *    write out to fout a partitioned-index attachment clause
   17697             :  */
   17698             : static void
   17699        1192 : dumpIndexAttach(Archive *fout, const IndexAttachInfo *attachinfo)
   17700             : {
   17701             :     /* Do nothing if not dumping schema */
   17702        1192 :     if (!fout->dopt->dumpSchema)
   17703          96 :         return;
   17704             : 
   17705        1096 :     if (attachinfo->partitionIdx->dobj.dump & DUMP_COMPONENT_DEFINITION)
   17706             :     {
   17707        1096 :         PQExpBuffer q = createPQExpBuffer();
   17708             : 
   17709        1096 :         appendPQExpBuffer(q, "ALTER INDEX %s ",
   17710        1096 :                           fmtQualifiedDumpable(attachinfo->parentIdx));
   17711        1096 :         appendPQExpBuffer(q, "ATTACH PARTITION %s;\n",
   17712        1096 :                           fmtQualifiedDumpable(attachinfo->partitionIdx));
   17713             : 
   17714             :         /*
   17715             :          * There is no point in creating a drop query as the drop is done by
   17716             :          * index drop.  (If you think to change this, see also
   17717             :          * _printTocEntry().)  Although this object doesn't really have
   17718             :          * ownership as such, set the owner field anyway to ensure that the
   17719             :          * command is run by the correct role at restore time.
   17720             :          */
   17721        1096 :         ArchiveEntry(fout, attachinfo->dobj.catId, attachinfo->dobj.dumpId,
   17722        1096 :                      ARCHIVE_OPTS(.tag = attachinfo->dobj.name,
   17723             :                                   .namespace = attachinfo->dobj.namespace->dobj.name,
   17724             :                                   .owner = attachinfo->parentIdx->indextable->rolname,
   17725             :                                   .description = "INDEX ATTACH",
   17726             :                                   .section = SECTION_POST_DATA,
   17727             :                                   .createStmt = q->data));
   17728             : 
   17729        1096 :         destroyPQExpBuffer(q);
   17730             :     }
   17731             : }
   17732             : 
   17733             : /*
   17734             :  * dumpStatisticsExt
   17735             :  *    write out to fout an extended statistics object
   17736             :  */
   17737             : static void
   17738         290 : dumpStatisticsExt(Archive *fout, const StatsExtInfo *statsextinfo)
   17739             : {
   17740         290 :     DumpOptions *dopt = fout->dopt;
   17741             :     PQExpBuffer q;
   17742             :     PQExpBuffer delq;
   17743             :     PQExpBuffer query;
   17744             :     char       *qstatsextname;
   17745             :     PGresult   *res;
   17746             :     char       *stxdef;
   17747             : 
   17748             :     /* Do nothing if not dumping schema */
   17749         290 :     if (!dopt->dumpSchema)
   17750          36 :         return;
   17751             : 
   17752         254 :     q = createPQExpBuffer();
   17753         254 :     delq = createPQExpBuffer();
   17754         254 :     query = createPQExpBuffer();
   17755             : 
   17756         254 :     qstatsextname = pg_strdup(fmtId(statsextinfo->dobj.name));
   17757             : 
   17758         254 :     appendPQExpBuffer(query, "SELECT "
   17759             :                       "pg_catalog.pg_get_statisticsobjdef('%u'::pg_catalog.oid)",
   17760             :                       statsextinfo->dobj.catId.oid);
   17761             : 
   17762         254 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   17763             : 
   17764         254 :     stxdef = PQgetvalue(res, 0, 0);
   17765             : 
   17766             :     /* Result of pg_get_statisticsobjdef is complete except for semicolon */
   17767         254 :     appendPQExpBuffer(q, "%s;\n", stxdef);
   17768             : 
   17769             :     /*
   17770             :      * We only issue an ALTER STATISTICS statement if the stxstattarget entry
   17771             :      * for this statistics object is not the default value.
   17772             :      */
   17773         254 :     if (statsextinfo->stattarget >= 0)
   17774             :     {
   17775          72 :         appendPQExpBuffer(q, "ALTER STATISTICS %s ",
   17776          72 :                           fmtQualifiedDumpable(statsextinfo));
   17777          72 :         appendPQExpBuffer(q, "SET STATISTICS %d;\n",
   17778             :                           statsextinfo->stattarget);
   17779             :     }
   17780             : 
   17781         254 :     appendPQExpBuffer(delq, "DROP STATISTICS %s;\n",
   17782         254 :                       fmtQualifiedDumpable(statsextinfo));
   17783             : 
   17784         254 :     if (statsextinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   17785         254 :         ArchiveEntry(fout, statsextinfo->dobj.catId,
   17786             :                      statsextinfo->dobj.dumpId,
   17787         254 :                      ARCHIVE_OPTS(.tag = statsextinfo->dobj.name,
   17788             :                                   .namespace = statsextinfo->dobj.namespace->dobj.name,
   17789             :                                   .owner = statsextinfo->rolname,
   17790             :                                   .description = "STATISTICS",
   17791             :                                   .section = SECTION_POST_DATA,
   17792             :                                   .createStmt = q->data,
   17793             :                                   .dropStmt = delq->data));
   17794             : 
   17795             :     /* Dump Statistics Comments */
   17796         254 :     if (statsextinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   17797           0 :         dumpComment(fout, "STATISTICS", qstatsextname,
   17798           0 :                     statsextinfo->dobj.namespace->dobj.name,
   17799             :                     statsextinfo->rolname,
   17800             :                     statsextinfo->dobj.catId, 0,
   17801             :                     statsextinfo->dobj.dumpId);
   17802             : 
   17803         254 :     PQclear(res);
   17804         254 :     destroyPQExpBuffer(q);
   17805         254 :     destroyPQExpBuffer(delq);
   17806         254 :     destroyPQExpBuffer(query);
   17807         254 :     free(qstatsextname);
   17808             : }
   17809             : 
   17810             : /*
   17811             :  * dumpConstraint
   17812             :  *    write out to fout a user-defined constraint
   17813             :  */
   17814             : static void
   17815        4866 : dumpConstraint(Archive *fout, const ConstraintInfo *coninfo)
   17816             : {
   17817        4866 :     DumpOptions *dopt = fout->dopt;
   17818        4866 :     TableInfo  *tbinfo = coninfo->contable;
   17819             :     PQExpBuffer q;
   17820             :     PQExpBuffer delq;
   17821        4866 :     char       *tag = NULL;
   17822             :     char       *foreign;
   17823             : 
   17824             :     /* Do nothing if not dumping schema */
   17825        4866 :     if (!dopt->dumpSchema)
   17826         184 :         return;
   17827             : 
   17828        4682 :     q = createPQExpBuffer();
   17829        4682 :     delq = createPQExpBuffer();
   17830             : 
   17831        9172 :     foreign = tbinfo &&
   17832        4682 :         tbinfo->relkind == RELKIND_FOREIGN_TABLE ? "FOREIGN " : "";
   17833             : 
   17834        4682 :     if (coninfo->contype == 'p' ||
   17835        2258 :         coninfo->contype == 'u' ||
   17836        1792 :         coninfo->contype == 'x')
   17837        2910 :     {
   17838             :         /* Index-related constraint */
   17839             :         IndxInfo   *indxinfo;
   17840             :         int         k;
   17841             : 
   17842        2910 :         indxinfo = (IndxInfo *) findObjectByDumpId(coninfo->conindex);
   17843             : 
   17844        2910 :         if (indxinfo == NULL)
   17845           0 :             pg_fatal("missing index for constraint \"%s\"",
   17846             :                      coninfo->dobj.name);
   17847             : 
   17848        2910 :         if (dopt->binary_upgrade)
   17849         286 :             binary_upgrade_set_pg_class_oids(fout, q,
   17850             :                                              indxinfo->dobj.catId.oid);
   17851             : 
   17852        2910 :         appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s\n", foreign,
   17853        2910 :                           fmtQualifiedDumpable(tbinfo));
   17854        2910 :         appendPQExpBuffer(q, "    ADD CONSTRAINT %s ",
   17855        2910 :                           fmtId(coninfo->dobj.name));
   17856             : 
   17857        2910 :         if (coninfo->condef)
   17858             :         {
   17859             :             /* pg_get_constraintdef should have provided everything */
   17860          20 :             appendPQExpBuffer(q, "%s;\n", coninfo->condef);
   17861             :         }
   17862             :         else
   17863             :         {
   17864        2890 :             appendPQExpBufferStr(q,
   17865        2890 :                                  coninfo->contype == 'p' ? "PRIMARY KEY" : "UNIQUE");
   17866             : 
   17867             :             /*
   17868             :              * PRIMARY KEY constraints should not be using NULLS NOT DISTINCT
   17869             :              * indexes. Being able to create this was fixed, but we need to
   17870             :              * make the index distinct in order to be able to restore the
   17871             :              * dump.
   17872             :              */
   17873        2890 :             if (indxinfo->indnullsnotdistinct && coninfo->contype != 'p')
   17874           0 :                 appendPQExpBufferStr(q, " NULLS NOT DISTINCT");
   17875        2890 :             appendPQExpBufferStr(q, " (");
   17876        7010 :             for (k = 0; k < indxinfo->indnkeyattrs; k++)
   17877             :             {
   17878        4120 :                 int         indkey = (int) indxinfo->indkeys[k];
   17879             :                 const char *attname;
   17880             : 
   17881        4120 :                 if (indkey == InvalidAttrNumber)
   17882           0 :                     break;
   17883        4120 :                 attname = getAttrName(indkey, tbinfo);
   17884             : 
   17885        4120 :                 appendPQExpBuffer(q, "%s%s",
   17886             :                                   (k == 0) ? "" : ", ",
   17887             :                                   fmtId(attname));
   17888             :             }
   17889        2890 :             if (coninfo->conperiod)
   17890         224 :                 appendPQExpBufferStr(q, " WITHOUT OVERLAPS");
   17891             : 
   17892        2890 :             if (indxinfo->indnkeyattrs < indxinfo->indnattrs)
   17893          40 :                 appendPQExpBufferStr(q, ") INCLUDE (");
   17894             : 
   17895        2970 :             for (k = indxinfo->indnkeyattrs; k < indxinfo->indnattrs; k++)
   17896             :             {
   17897          80 :                 int         indkey = (int) indxinfo->indkeys[k];
   17898             :                 const char *attname;
   17899             : 
   17900          80 :                 if (indkey == InvalidAttrNumber)
   17901           0 :                     break;
   17902          80 :                 attname = getAttrName(indkey, tbinfo);
   17903             : 
   17904         160 :                 appendPQExpBuffer(q, "%s%s",
   17905          80 :                                   (k == indxinfo->indnkeyattrs) ? "" : ", ",
   17906             :                                   fmtId(attname));
   17907             :             }
   17908             : 
   17909        2890 :             appendPQExpBufferChar(q, ')');
   17910             : 
   17911        2890 :             if (nonemptyReloptions(indxinfo->indreloptions))
   17912             :             {
   17913           0 :                 appendPQExpBufferStr(q, " WITH (");
   17914           0 :                 appendReloptionsArrayAH(q, indxinfo->indreloptions, "", fout);
   17915           0 :                 appendPQExpBufferChar(q, ')');
   17916             :             }
   17917             : 
   17918        2890 :             if (coninfo->condeferrable)
   17919             :             {
   17920          50 :                 appendPQExpBufferStr(q, " DEFERRABLE");
   17921          50 :                 if (coninfo->condeferred)
   17922          30 :                     appendPQExpBufferStr(q, " INITIALLY DEFERRED");
   17923             :             }
   17924             : 
   17925        2890 :             appendPQExpBufferStr(q, ";\n");
   17926             :         }
   17927             : 
   17928             :         /*
   17929             :          * Append ALTER TABLE commands as needed to set properties that we
   17930             :          * only have ALTER TABLE syntax for.  Keep this in sync with the
   17931             :          * similar code in dumpIndex!
   17932             :          */
   17933             : 
   17934             :         /* If the index is clustered, we need to record that. */
   17935        2910 :         if (indxinfo->indisclustered)
   17936             :         {
   17937          72 :             appendPQExpBuffer(q, "\nALTER TABLE %s CLUSTER",
   17938          72 :                               fmtQualifiedDumpable(tbinfo));
   17939             :             /* index name is not qualified in this syntax */
   17940          72 :             appendPQExpBuffer(q, " ON %s;\n",
   17941          72 :                               fmtId(indxinfo->dobj.name));
   17942             :         }
   17943             : 
   17944             :         /* If the index defines identity, we need to record that. */
   17945        2910 :         if (indxinfo->indisreplident)
   17946             :         {
   17947           0 :             appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY USING",
   17948           0 :                               fmtQualifiedDumpable(tbinfo));
   17949             :             /* index name is not qualified in this syntax */
   17950           0 :             appendPQExpBuffer(q, " INDEX %s;\n",
   17951           0 :                               fmtId(indxinfo->dobj.name));
   17952             :         }
   17953             : 
   17954             :         /* Indexes can depend on extensions */
   17955        2910 :         append_depends_on_extension(fout, q, &indxinfo->dobj,
   17956             :                                     "pg_catalog.pg_class", "INDEX",
   17957        2910 :                                     fmtQualifiedDumpable(indxinfo));
   17958             : 
   17959        2910 :         appendPQExpBuffer(delq, "ALTER %sTABLE ONLY %s ", foreign,
   17960        2910 :                           fmtQualifiedDumpable(tbinfo));
   17961        2910 :         appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
   17962        2910 :                           fmtId(coninfo->dobj.name));
   17963             : 
   17964        2910 :         tag = psprintf("%s %s", tbinfo->dobj.name, coninfo->dobj.name);
   17965             : 
   17966        2910 :         if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   17967        2910 :             ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
   17968        2910 :                          ARCHIVE_OPTS(.tag = tag,
   17969             :                                       .namespace = tbinfo->dobj.namespace->dobj.name,
   17970             :                                       .tablespace = indxinfo->tablespace,
   17971             :                                       .owner = tbinfo->rolname,
   17972             :                                       .description = "CONSTRAINT",
   17973             :                                       .section = SECTION_POST_DATA,
   17974             :                                       .createStmt = q->data,
   17975             :                                       .dropStmt = delq->data));
   17976             :     }
   17977        1772 :     else if (coninfo->contype == 'f')
   17978             :     {
   17979             :         char       *only;
   17980             : 
   17981             :         /*
   17982             :          * Foreign keys on partitioned tables are always declared as
   17983             :          * inheriting to partitions; for all other cases, emit them as
   17984             :          * applying ONLY directly to the named table, because that's how they
   17985             :          * work for regular inherited tables.
   17986             :          */
   17987         334 :         only = tbinfo->relkind == RELKIND_PARTITIONED_TABLE ? "" : "ONLY ";
   17988             : 
   17989             :         /*
   17990             :          * XXX Potentially wrap in a 'SET CONSTRAINTS OFF' block so that the
   17991             :          * current table data is not processed
   17992             :          */
   17993         334 :         appendPQExpBuffer(q, "ALTER %sTABLE %s%s\n", foreign,
   17994         334 :                           only, fmtQualifiedDumpable(tbinfo));
   17995         334 :         appendPQExpBuffer(q, "    ADD CONSTRAINT %s %s;\n",
   17996         334 :                           fmtId(coninfo->dobj.name),
   17997             :                           coninfo->condef);
   17998             : 
   17999         334 :         appendPQExpBuffer(delq, "ALTER %sTABLE %s%s ", foreign,
   18000         334 :                           only, fmtQualifiedDumpable(tbinfo));
   18001         334 :         appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
   18002         334 :                           fmtId(coninfo->dobj.name));
   18003             : 
   18004         334 :         tag = psprintf("%s %s", tbinfo->dobj.name, coninfo->dobj.name);
   18005             : 
   18006         334 :         if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   18007         334 :             ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
   18008         334 :                          ARCHIVE_OPTS(.tag = tag,
   18009             :                                       .namespace = tbinfo->dobj.namespace->dobj.name,
   18010             :                                       .owner = tbinfo->rolname,
   18011             :                                       .description = "FK CONSTRAINT",
   18012             :                                       .section = SECTION_POST_DATA,
   18013             :                                       .createStmt = q->data,
   18014             :                                       .dropStmt = delq->data));
   18015             :     }
   18016        1438 :     else if (coninfo->contype == 'c' && tbinfo)
   18017             :     {
   18018             :         /* CHECK constraint on a table */
   18019             : 
   18020             :         /* Ignore if not to be dumped separately, or if it was inherited */
   18021        1246 :         if (coninfo->separate && coninfo->conislocal)
   18022             :         {
   18023             :             /* not ONLY since we want it to propagate to children */
   18024          90 :             appendPQExpBuffer(q, "ALTER %sTABLE %s\n", foreign,
   18025          90 :                               fmtQualifiedDumpable(tbinfo));
   18026          90 :             appendPQExpBuffer(q, "    ADD CONSTRAINT %s %s;\n",
   18027          90 :                               fmtId(coninfo->dobj.name),
   18028             :                               coninfo->condef);
   18029             : 
   18030          90 :             appendPQExpBuffer(delq, "ALTER %sTABLE %s ", foreign,
   18031          90 :                               fmtQualifiedDumpable(tbinfo));
   18032          90 :             appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
   18033          90 :                               fmtId(coninfo->dobj.name));
   18034             : 
   18035          90 :             tag = psprintf("%s %s", tbinfo->dobj.name, coninfo->dobj.name);
   18036             : 
   18037          90 :             if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   18038          90 :                 ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
   18039          90 :                              ARCHIVE_OPTS(.tag = tag,
   18040             :                                           .namespace = tbinfo->dobj.namespace->dobj.name,
   18041             :                                           .owner = tbinfo->rolname,
   18042             :                                           .description = "CHECK CONSTRAINT",
   18043             :                                           .section = SECTION_POST_DATA,
   18044             :                                           .createStmt = q->data,
   18045             :                                           .dropStmt = delq->data));
   18046             :         }
   18047             :     }
   18048         192 :     else if (coninfo->contype == 'c' && tbinfo == NULL)
   18049         192 :     {
   18050             :         /* CHECK constraint on a domain */
   18051         192 :         TypeInfo   *tyinfo = coninfo->condomain;
   18052             : 
   18053             :         /* Ignore if not to be dumped separately */
   18054         192 :         if (coninfo->separate)
   18055             :         {
   18056           0 :             appendPQExpBuffer(q, "ALTER DOMAIN %s\n",
   18057           0 :                               fmtQualifiedDumpable(tyinfo));
   18058           0 :             appendPQExpBuffer(q, "    ADD CONSTRAINT %s %s;\n",
   18059           0 :                               fmtId(coninfo->dobj.name),
   18060             :                               coninfo->condef);
   18061             : 
   18062           0 :             appendPQExpBuffer(delq, "ALTER DOMAIN %s ",
   18063           0 :                               fmtQualifiedDumpable(tyinfo));
   18064           0 :             appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
   18065           0 :                               fmtId(coninfo->dobj.name));
   18066             : 
   18067           0 :             tag = psprintf("%s %s", tyinfo->dobj.name, coninfo->dobj.name);
   18068             : 
   18069           0 :             if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   18070           0 :                 ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
   18071           0 :                              ARCHIVE_OPTS(.tag = tag,
   18072             :                                           .namespace = tyinfo->dobj.namespace->dobj.name,
   18073             :                                           .owner = tyinfo->rolname,
   18074             :                                           .description = "CHECK CONSTRAINT",
   18075             :                                           .section = SECTION_POST_DATA,
   18076             :                                           .createStmt = q->data,
   18077             :                                           .dropStmt = delq->data));
   18078             :         }
   18079             :     }
   18080             :     else
   18081             :     {
   18082           0 :         pg_fatal("unrecognized constraint type: %c",
   18083             :                  coninfo->contype);
   18084             :     }
   18085             : 
   18086             :     /* Dump Constraint Comments --- only works for table constraints */
   18087        4682 :     if (tbinfo && coninfo->separate &&
   18088        3384 :         coninfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   18089          20 :         dumpTableConstraintComment(fout, coninfo);
   18090             : 
   18091        4682 :     free(tag);
   18092        4682 :     destroyPQExpBuffer(q);
   18093        4682 :     destroyPQExpBuffer(delq);
   18094             : }
   18095             : 
   18096             : /*
   18097             :  * dumpTableConstraintComment --- dump a constraint's comment if any
   18098             :  *
   18099             :  * This is split out because we need the function in two different places
   18100             :  * depending on whether the constraint is dumped as part of CREATE TABLE
   18101             :  * or as a separate ALTER command.
   18102             :  */
   18103             : static void
   18104         102 : dumpTableConstraintComment(Archive *fout, const ConstraintInfo *coninfo)
   18105             : {
   18106         102 :     TableInfo  *tbinfo = coninfo->contable;
   18107         102 :     PQExpBuffer conprefix = createPQExpBuffer();
   18108             :     char       *qtabname;
   18109             : 
   18110         102 :     qtabname = pg_strdup(fmtId(tbinfo->dobj.name));
   18111             : 
   18112         102 :     appendPQExpBuffer(conprefix, "CONSTRAINT %s ON",
   18113         102 :                       fmtId(coninfo->dobj.name));
   18114             : 
   18115         102 :     if (coninfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   18116         102 :         dumpComment(fout, conprefix->data, qtabname,
   18117         102 :                     tbinfo->dobj.namespace->dobj.name,
   18118             :                     tbinfo->rolname,
   18119             :                     coninfo->dobj.catId, 0,
   18120         102 :                     coninfo->separate ? coninfo->dobj.dumpId : tbinfo->dobj.dumpId);
   18121             : 
   18122         102 :     destroyPQExpBuffer(conprefix);
   18123         102 :     free(qtabname);
   18124         102 : }
   18125             : 
   18126             : static inline SeqType
   18127        1300 : parse_sequence_type(const char *name)
   18128             : {
   18129        2898 :     for (int i = 0; i < lengthof(SeqTypeNames); i++)
   18130             :     {
   18131        2898 :         if (strcmp(SeqTypeNames[i], name) == 0)
   18132        1300 :             return (SeqType) i;
   18133             :     }
   18134             : 
   18135           0 :     pg_fatal("unrecognized sequence type: %s", name);
   18136             :     return (SeqType) 0;         /* keep compiler quiet */
   18137             : }
   18138             : 
   18139             : /*
   18140             :  * bsearch() comparator for SequenceItem
   18141             :  */
   18142             : static int
   18143        5984 : SequenceItemCmp(const void *p1, const void *p2)
   18144             : {
   18145        5984 :     SequenceItem v1 = *((const SequenceItem *) p1);
   18146        5984 :     SequenceItem v2 = *((const SequenceItem *) p2);
   18147             : 
   18148        5984 :     return pg_cmp_u32(v1.oid, v2.oid);
   18149             : }
   18150             : 
   18151             : /*
   18152             :  * collectSequences
   18153             :  *
   18154             :  * Construct a table of sequence information.  This table is sorted by OID for
   18155             :  * speed in lookup.
   18156             :  */
   18157             : static void
   18158         354 : collectSequences(Archive *fout)
   18159             : {
   18160             :     PGresult   *res;
   18161             :     const char *query;
   18162             : 
   18163             :     /*
   18164             :      * Before Postgres 10, sequence metadata is in the sequence itself.  With
   18165             :      * some extra effort, we might be able to use the sorted table for those
   18166             :      * versions, but for now it seems unlikely to be worth it.
   18167             :      *
   18168             :      * Since version 18, we can gather the sequence data in this query with
   18169             :      * pg_get_sequence_data(), but we only do so for non-schema-only dumps.
   18170             :      */
   18171         354 :     if (fout->remoteVersion < 100000)
   18172           0 :         return;
   18173         354 :     else if (fout->remoteVersion < 180000 ||
   18174         354 :              (!fout->dopt->dumpData && !fout->dopt->sequence_data))
   18175          16 :         query = "SELECT seqrelid, format_type(seqtypid, NULL), "
   18176             :             "seqstart, seqincrement, "
   18177             :             "seqmax, seqmin, "
   18178             :             "seqcache, seqcycle, "
   18179             :             "NULL, 'f' "
   18180             :             "FROM pg_catalog.pg_sequence "
   18181             :             "ORDER BY seqrelid";
   18182             :     else
   18183         338 :         query = "SELECT seqrelid, format_type(seqtypid, NULL), "
   18184             :             "seqstart, seqincrement, "
   18185             :             "seqmax, seqmin, "
   18186             :             "seqcache, seqcycle, "
   18187             :             "last_value, is_called "
   18188             :             "FROM pg_catalog.pg_sequence, "
   18189             :             "pg_get_sequence_data(seqrelid) "
   18190             :             "ORDER BY seqrelid;";
   18191             : 
   18192         354 :     res = ExecuteSqlQuery(fout, query, PGRES_TUPLES_OK);
   18193             : 
   18194         354 :     nsequences = PQntuples(res);
   18195         354 :     sequences = (SequenceItem *) pg_malloc(nsequences * sizeof(SequenceItem));
   18196             : 
   18197        1654 :     for (int i = 0; i < nsequences; i++)
   18198             :     {
   18199        1300 :         sequences[i].oid = atooid(PQgetvalue(res, i, 0));
   18200        1300 :         sequences[i].seqtype = parse_sequence_type(PQgetvalue(res, i, 1));
   18201        1300 :         sequences[i].startv = strtoi64(PQgetvalue(res, i, 2), NULL, 10);
   18202        1300 :         sequences[i].incby = strtoi64(PQgetvalue(res, i, 3), NULL, 10);
   18203        1300 :         sequences[i].maxv = strtoi64(PQgetvalue(res, i, 4), NULL, 10);
   18204        1300 :         sequences[i].minv = strtoi64(PQgetvalue(res, i, 5), NULL, 10);
   18205        1300 :         sequences[i].cache = strtoi64(PQgetvalue(res, i, 6), NULL, 10);
   18206        1300 :         sequences[i].cycled = (strcmp(PQgetvalue(res, i, 7), "t") == 0);
   18207        1300 :         sequences[i].last_value = strtoi64(PQgetvalue(res, i, 8), NULL, 10);
   18208        1300 :         sequences[i].is_called = (strcmp(PQgetvalue(res, i, 9), "t") == 0);
   18209             :     }
   18210             : 
   18211         354 :     PQclear(res);
   18212             : }
   18213             : 
   18214             : /*
   18215             :  * dumpSequence
   18216             :  *    write the declaration (not data) of one user-defined sequence
   18217             :  */
   18218             : static void
   18219         774 : dumpSequence(Archive *fout, const TableInfo *tbinfo)
   18220             : {
   18221         774 :     DumpOptions *dopt = fout->dopt;
   18222             :     SequenceItem *seq;
   18223             :     bool        is_ascending;
   18224             :     int64       default_minv,
   18225             :                 default_maxv;
   18226         774 :     PQExpBuffer query = createPQExpBuffer();
   18227         774 :     PQExpBuffer delqry = createPQExpBuffer();
   18228             :     char       *qseqname;
   18229         774 :     TableInfo  *owning_tab = NULL;
   18230             : 
   18231         774 :     qseqname = pg_strdup(fmtId(tbinfo->dobj.name));
   18232             : 
   18233             :     /*
   18234             :      * For versions >= 10, the sequence information is gathered in a sorted
   18235             :      * table before any calls to dumpSequence().  See collectSequences() for
   18236             :      * more information.
   18237             :      */
   18238         774 :     if (fout->remoteVersion >= 100000)
   18239             :     {
   18240         774 :         SequenceItem key = {0};
   18241             : 
   18242             :         Assert(sequences);
   18243             : 
   18244         774 :         key.oid = tbinfo->dobj.catId.oid;
   18245         774 :         seq = bsearch(&key, sequences, nsequences,
   18246             :                       sizeof(SequenceItem), SequenceItemCmp);
   18247             :     }
   18248             :     else
   18249             :     {
   18250             :         PGresult   *res;
   18251             : 
   18252             :         /*
   18253             :          * Before PostgreSQL 10, sequence metadata is in the sequence itself.
   18254             :          *
   18255             :          * Note: it might seem that 'bigint' potentially needs to be
   18256             :          * schema-qualified, but actually that's a keyword.
   18257             :          */
   18258           0 :         appendPQExpBuffer(query,
   18259             :                           "SELECT 'bigint' AS sequence_type, "
   18260             :                           "start_value, increment_by, max_value, min_value, "
   18261             :                           "cache_value, is_cycled FROM %s",
   18262           0 :                           fmtQualifiedDumpable(tbinfo));
   18263             : 
   18264           0 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   18265             : 
   18266           0 :         if (PQntuples(res) != 1)
   18267           0 :             pg_fatal(ngettext("query to get data of sequence \"%s\" returned %d row (expected 1)",
   18268             :                               "query to get data of sequence \"%s\" returned %d rows (expected 1)",
   18269             :                               PQntuples(res)),
   18270             :                      tbinfo->dobj.name, PQntuples(res));
   18271             : 
   18272           0 :         seq = pg_malloc0(sizeof(SequenceItem));
   18273           0 :         seq->seqtype = parse_sequence_type(PQgetvalue(res, 0, 0));
   18274           0 :         seq->startv = strtoi64(PQgetvalue(res, 0, 1), NULL, 10);
   18275           0 :         seq->incby = strtoi64(PQgetvalue(res, 0, 2), NULL, 10);
   18276           0 :         seq->maxv = strtoi64(PQgetvalue(res, 0, 3), NULL, 10);
   18277           0 :         seq->minv = strtoi64(PQgetvalue(res, 0, 4), NULL, 10);
   18278           0 :         seq->cache = strtoi64(PQgetvalue(res, 0, 5), NULL, 10);
   18279           0 :         seq->cycled = (strcmp(PQgetvalue(res, 0, 6), "t") == 0);
   18280             : 
   18281           0 :         PQclear(res);
   18282             :     }
   18283             : 
   18284             :     /* Calculate default limits for a sequence of this type */
   18285         774 :     is_ascending = (seq->incby >= 0);
   18286         774 :     if (seq->seqtype == SEQTYPE_SMALLINT)
   18287             :     {
   18288          50 :         default_minv = is_ascending ? 1 : PG_INT16_MIN;
   18289          50 :         default_maxv = is_ascending ? PG_INT16_MAX : -1;
   18290             :     }
   18291         724 :     else if (seq->seqtype == SEQTYPE_INTEGER)
   18292             :     {
   18293         592 :         default_minv = is_ascending ? 1 : PG_INT32_MIN;
   18294         592 :         default_maxv = is_ascending ? PG_INT32_MAX : -1;
   18295             :     }
   18296         132 :     else if (seq->seqtype == SEQTYPE_BIGINT)
   18297             :     {
   18298         132 :         default_minv = is_ascending ? 1 : PG_INT64_MIN;
   18299         132 :         default_maxv = is_ascending ? PG_INT64_MAX : -1;
   18300             :     }
   18301             :     else
   18302             :     {
   18303           0 :         pg_fatal("unrecognized sequence type: %d", seq->seqtype);
   18304             :         default_minv = default_maxv = 0;    /* keep compiler quiet */
   18305             :     }
   18306             : 
   18307             :     /*
   18308             :      * Identity sequences are not to be dropped separately.
   18309             :      */
   18310         774 :     if (!tbinfo->is_identity_sequence)
   18311             :     {
   18312         482 :         appendPQExpBuffer(delqry, "DROP SEQUENCE %s;\n",
   18313         482 :                           fmtQualifiedDumpable(tbinfo));
   18314             :     }
   18315             : 
   18316         774 :     resetPQExpBuffer(query);
   18317             : 
   18318         774 :     if (dopt->binary_upgrade)
   18319             :     {
   18320         132 :         binary_upgrade_set_pg_class_oids(fout, query,
   18321             :                                          tbinfo->dobj.catId.oid);
   18322             : 
   18323             :         /*
   18324             :          * In older PG versions a sequence will have a pg_type entry, but v14
   18325             :          * and up don't use that, so don't attempt to preserve the type OID.
   18326             :          */
   18327             :     }
   18328             : 
   18329         774 :     if (tbinfo->is_identity_sequence)
   18330             :     {
   18331         292 :         owning_tab = findTableByOid(tbinfo->owning_tab);
   18332             : 
   18333         292 :         appendPQExpBuffer(query,
   18334             :                           "ALTER TABLE %s ",
   18335         292 :                           fmtQualifiedDumpable(owning_tab));
   18336         292 :         appendPQExpBuffer(query,
   18337             :                           "ALTER COLUMN %s ADD GENERATED ",
   18338         292 :                           fmtId(owning_tab->attnames[tbinfo->owning_col - 1]));
   18339         292 :         if (owning_tab->attidentity[tbinfo->owning_col - 1] == ATTRIBUTE_IDENTITY_ALWAYS)
   18340         212 :             appendPQExpBufferStr(query, "ALWAYS");
   18341          80 :         else if (owning_tab->attidentity[tbinfo->owning_col - 1] == ATTRIBUTE_IDENTITY_BY_DEFAULT)
   18342          80 :             appendPQExpBufferStr(query, "BY DEFAULT");
   18343         292 :         appendPQExpBuffer(query, " AS IDENTITY (\n    SEQUENCE NAME %s\n",
   18344         292 :                           fmtQualifiedDumpable(tbinfo));
   18345             : 
   18346             :         /*
   18347             :          * Emit persistence option only if it's different from the owning
   18348             :          * table's.  This avoids using this new syntax unnecessarily.
   18349             :          */
   18350         292 :         if (tbinfo->relpersistence != owning_tab->relpersistence)
   18351          20 :             appendPQExpBuffer(query, "    %s\n",
   18352          20 :                               tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED ?
   18353             :                               "UNLOGGED" : "LOGGED");
   18354             :     }
   18355             :     else
   18356             :     {
   18357         482 :         appendPQExpBuffer(query,
   18358             :                           "CREATE %sSEQUENCE %s\n",
   18359         482 :                           tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED ?
   18360             :                           "UNLOGGED " : "",
   18361         482 :                           fmtQualifiedDumpable(tbinfo));
   18362             : 
   18363         482 :         if (seq->seqtype != SEQTYPE_BIGINT)
   18364         380 :             appendPQExpBuffer(query, "    AS %s\n", SeqTypeNames[seq->seqtype]);
   18365             :     }
   18366             : 
   18367         774 :     appendPQExpBuffer(query, "    START WITH " INT64_FORMAT "\n", seq->startv);
   18368             : 
   18369         774 :     appendPQExpBuffer(query, "    INCREMENT BY " INT64_FORMAT "\n", seq->incby);
   18370             : 
   18371         774 :     if (seq->minv != default_minv)
   18372          30 :         appendPQExpBuffer(query, "    MINVALUE " INT64_FORMAT "\n", seq->minv);
   18373             :     else
   18374         744 :         appendPQExpBufferStr(query, "    NO MINVALUE\n");
   18375             : 
   18376         774 :     if (seq->maxv != default_maxv)
   18377          30 :         appendPQExpBuffer(query, "    MAXVALUE " INT64_FORMAT "\n", seq->maxv);
   18378             :     else
   18379         744 :         appendPQExpBufferStr(query, "    NO MAXVALUE\n");
   18380             : 
   18381         774 :     appendPQExpBuffer(query,
   18382             :                       "    CACHE " INT64_FORMAT "%s",
   18383         774 :                       seq->cache, (seq->cycled ? "\n    CYCLE" : ""));
   18384             : 
   18385         774 :     if (tbinfo->is_identity_sequence)
   18386         292 :         appendPQExpBufferStr(query, "\n);\n");
   18387             :     else
   18388         482 :         appendPQExpBufferStr(query, ";\n");
   18389             : 
   18390             :     /* binary_upgrade:  no need to clear TOAST table oid */
   18391             : 
   18392         774 :     if (dopt->binary_upgrade)
   18393         132 :         binary_upgrade_extension_member(query, &tbinfo->dobj,
   18394             :                                         "SEQUENCE", qseqname,
   18395         132 :                                         tbinfo->dobj.namespace->dobj.name);
   18396             : 
   18397         774 :     if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   18398         774 :         ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
   18399         774 :                      ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
   18400             :                                   .namespace = tbinfo->dobj.namespace->dobj.name,
   18401             :                                   .owner = tbinfo->rolname,
   18402             :                                   .description = "SEQUENCE",
   18403             :                                   .section = SECTION_PRE_DATA,
   18404             :                                   .createStmt = query->data,
   18405             :                                   .dropStmt = delqry->data));
   18406             : 
   18407             :     /*
   18408             :      * If the sequence is owned by a table column, emit the ALTER for it as a
   18409             :      * separate TOC entry immediately following the sequence's own entry. It's
   18410             :      * OK to do this rather than using full sorting logic, because the
   18411             :      * dependency that tells us it's owned will have forced the table to be
   18412             :      * created first.  We can't just include the ALTER in the TOC entry
   18413             :      * because it will fail if we haven't reassigned the sequence owner to
   18414             :      * match the table's owner.
   18415             :      *
   18416             :      * We need not schema-qualify the table reference because both sequence
   18417             :      * and table must be in the same schema.
   18418             :      */
   18419         774 :     if (OidIsValid(tbinfo->owning_tab) && !tbinfo->is_identity_sequence)
   18420             :     {
   18421         290 :         owning_tab = findTableByOid(tbinfo->owning_tab);
   18422             : 
   18423         290 :         if (owning_tab == NULL)
   18424           0 :             pg_fatal("failed sanity check, parent table with OID %u of sequence with OID %u not found",
   18425             :                      tbinfo->owning_tab, tbinfo->dobj.catId.oid);
   18426             : 
   18427         290 :         if (owning_tab->dobj.dump & DUMP_COMPONENT_DEFINITION)
   18428             :         {
   18429         286 :             resetPQExpBuffer(query);
   18430         286 :             appendPQExpBuffer(query, "ALTER SEQUENCE %s",
   18431         286 :                               fmtQualifiedDumpable(tbinfo));
   18432         286 :             appendPQExpBuffer(query, " OWNED BY %s",
   18433         286 :                               fmtQualifiedDumpable(owning_tab));
   18434         286 :             appendPQExpBuffer(query, ".%s;\n",
   18435         286 :                               fmtId(owning_tab->attnames[tbinfo->owning_col - 1]));
   18436             : 
   18437         286 :             if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   18438         286 :                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
   18439         286 :                              ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
   18440             :                                           .namespace = tbinfo->dobj.namespace->dobj.name,
   18441             :                                           .owner = tbinfo->rolname,
   18442             :                                           .description = "SEQUENCE OWNED BY",
   18443             :                                           .section = SECTION_PRE_DATA,
   18444             :                                           .createStmt = query->data,
   18445             :                                           .deps = &(tbinfo->dobj.dumpId),
   18446             :                                           .nDeps = 1));
   18447             :         }
   18448             :     }
   18449             : 
   18450             :     /* Dump Sequence Comments and Security Labels */
   18451         774 :     if (tbinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   18452           0 :         dumpComment(fout, "SEQUENCE", qseqname,
   18453           0 :                     tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
   18454             :                     tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
   18455             : 
   18456         774 :     if (tbinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
   18457           0 :         dumpSecLabel(fout, "SEQUENCE", qseqname,
   18458           0 :                      tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
   18459             :                      tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
   18460             : 
   18461         774 :     if (fout->remoteVersion < 100000)
   18462           0 :         pg_free(seq);
   18463         774 :     destroyPQExpBuffer(query);
   18464         774 :     destroyPQExpBuffer(delqry);
   18465         774 :     free(qseqname);
   18466         774 : }
   18467             : 
   18468             : /*
   18469             :  * dumpSequenceData
   18470             :  *    write the data of one user-defined sequence
   18471             :  */
   18472             : static void
   18473         804 : dumpSequenceData(Archive *fout, const TableDataInfo *tdinfo)
   18474             : {
   18475         804 :     TableInfo  *tbinfo = tdinfo->tdtable;
   18476             :     int64       last;
   18477             :     bool        called;
   18478         804 :     PQExpBuffer query = createPQExpBuffer();
   18479             : 
   18480             :     /*
   18481             :      * For versions >= 18, the sequence information is gathered in the sorted
   18482             :      * array before any calls to dumpSequenceData().  See collectSequences()
   18483             :      * for more information.
   18484             :      *
   18485             :      * For older versions, we have to query the sequence relations
   18486             :      * individually.
   18487             :      */
   18488         804 :     if (fout->remoteVersion < 180000)
   18489             :     {
   18490             :         PGresult   *res;
   18491             : 
   18492           0 :         appendPQExpBuffer(query,
   18493             :                           "SELECT last_value, is_called FROM %s",
   18494           0 :                           fmtQualifiedDumpable(tbinfo));
   18495             : 
   18496           0 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   18497             : 
   18498           0 :         if (PQntuples(res) != 1)
   18499           0 :             pg_fatal(ngettext("query to get data of sequence \"%s\" returned %d row (expected 1)",
   18500             :                               "query to get data of sequence \"%s\" returned %d rows (expected 1)",
   18501             :                               PQntuples(res)),
   18502             :                      tbinfo->dobj.name, PQntuples(res));
   18503             : 
   18504           0 :         last = strtoi64(PQgetvalue(res, 0, 0), NULL, 10);
   18505           0 :         called = (strcmp(PQgetvalue(res, 0, 1), "t") == 0);
   18506             : 
   18507           0 :         PQclear(res);
   18508             :     }
   18509             :     else
   18510             :     {
   18511         804 :         SequenceItem key = {0};
   18512             :         SequenceItem *entry;
   18513             : 
   18514             :         Assert(sequences);
   18515             :         Assert(tbinfo->dobj.catId.oid);
   18516             : 
   18517         804 :         key.oid = tbinfo->dobj.catId.oid;
   18518         804 :         entry = bsearch(&key, sequences, nsequences,
   18519             :                         sizeof(SequenceItem), SequenceItemCmp);
   18520             : 
   18521         804 :         last = entry->last_value;
   18522         804 :         called = entry->is_called;
   18523             :     }
   18524             : 
   18525         804 :     resetPQExpBuffer(query);
   18526         804 :     appendPQExpBufferStr(query, "SELECT pg_catalog.setval(");
   18527         804 :     appendStringLiteralAH(query, fmtQualifiedDumpable(tbinfo), fout);
   18528         804 :     appendPQExpBuffer(query, ", " INT64_FORMAT ", %s);\n",
   18529             :                       last, (called ? "true" : "false"));
   18530             : 
   18531         804 :     if (tdinfo->dobj.dump & DUMP_COMPONENT_DATA)
   18532         804 :         ArchiveEntry(fout, nilCatalogId, createDumpId(),
   18533         804 :                      ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
   18534             :                                   .namespace = tbinfo->dobj.namespace->dobj.name,
   18535             :                                   .owner = tbinfo->rolname,
   18536             :                                   .description = "SEQUENCE SET",
   18537             :                                   .section = SECTION_DATA,
   18538             :                                   .createStmt = query->data,
   18539             :                                   .deps = &(tbinfo->dobj.dumpId),
   18540             :                                   .nDeps = 1));
   18541             : 
   18542         804 :     destroyPQExpBuffer(query);
   18543         804 : }
   18544             : 
   18545             : /*
   18546             :  * dumpTrigger
   18547             :  *    write the declaration of one user-defined table trigger
   18548             :  */
   18549             : static void
   18550        1086 : dumpTrigger(Archive *fout, const TriggerInfo *tginfo)
   18551             : {
   18552        1086 :     DumpOptions *dopt = fout->dopt;
   18553        1086 :     TableInfo  *tbinfo = tginfo->tgtable;
   18554             :     PQExpBuffer query;
   18555             :     PQExpBuffer delqry;
   18556             :     PQExpBuffer trigprefix;
   18557             :     PQExpBuffer trigidentity;
   18558             :     char       *qtabname;
   18559             :     char       *tag;
   18560             : 
   18561             :     /* Do nothing if not dumping schema */
   18562        1086 :     if (!dopt->dumpSchema)
   18563          62 :         return;
   18564             : 
   18565        1024 :     query = createPQExpBuffer();
   18566        1024 :     delqry = createPQExpBuffer();
   18567        1024 :     trigprefix = createPQExpBuffer();
   18568        1024 :     trigidentity = createPQExpBuffer();
   18569             : 
   18570        1024 :     qtabname = pg_strdup(fmtId(tbinfo->dobj.name));
   18571             : 
   18572        1024 :     appendPQExpBuffer(trigidentity, "%s ", fmtId(tginfo->dobj.name));
   18573        1024 :     appendPQExpBuffer(trigidentity, "ON %s", fmtQualifiedDumpable(tbinfo));
   18574             : 
   18575        1024 :     appendPQExpBuffer(query, "%s;\n", tginfo->tgdef);
   18576        1024 :     appendPQExpBuffer(delqry, "DROP TRIGGER %s;\n", trigidentity->data);
   18577             : 
   18578             :     /* Triggers can depend on extensions */
   18579        1024 :     append_depends_on_extension(fout, query, &tginfo->dobj,
   18580             :                                 "pg_catalog.pg_trigger", "TRIGGER",
   18581        1024 :                                 trigidentity->data);
   18582             : 
   18583        1024 :     if (tginfo->tgispartition)
   18584             :     {
   18585             :         Assert(tbinfo->ispartition);
   18586             : 
   18587             :         /*
   18588             :          * Partition triggers only appear here because their 'tgenabled' flag
   18589             :          * differs from its parent's.  The trigger is created already, so
   18590             :          * remove the CREATE and replace it with an ALTER.  (Clear out the
   18591             :          * DROP query too, so that pg_dump --create does not cause errors.)
   18592             :          */
   18593         242 :         resetPQExpBuffer(query);
   18594         242 :         resetPQExpBuffer(delqry);
   18595         242 :         appendPQExpBuffer(query, "\nALTER %sTABLE %s ",
   18596         242 :                           tbinfo->relkind == RELKIND_FOREIGN_TABLE ? "FOREIGN " : "",
   18597         242 :                           fmtQualifiedDumpable(tbinfo));
   18598         242 :         switch (tginfo->tgenabled)
   18599             :         {
   18600          84 :             case 'f':
   18601             :             case 'D':
   18602          84 :                 appendPQExpBufferStr(query, "DISABLE");
   18603          84 :                 break;
   18604           0 :             case 't':
   18605             :             case 'O':
   18606           0 :                 appendPQExpBufferStr(query, "ENABLE");
   18607           0 :                 break;
   18608          74 :             case 'R':
   18609          74 :                 appendPQExpBufferStr(query, "ENABLE REPLICA");
   18610          74 :                 break;
   18611          84 :             case 'A':
   18612          84 :                 appendPQExpBufferStr(query, "ENABLE ALWAYS");
   18613          84 :                 break;
   18614             :         }
   18615         242 :         appendPQExpBuffer(query, " TRIGGER %s;\n",
   18616         242 :                           fmtId(tginfo->dobj.name));
   18617             :     }
   18618         782 :     else if (tginfo->tgenabled != 't' && tginfo->tgenabled != 'O')
   18619             :     {
   18620           0 :         appendPQExpBuffer(query, "\nALTER %sTABLE %s ",
   18621           0 :                           tbinfo->relkind == RELKIND_FOREIGN_TABLE ? "FOREIGN " : "",
   18622           0 :                           fmtQualifiedDumpable(tbinfo));
   18623           0 :         switch (tginfo->tgenabled)
   18624             :         {
   18625           0 :             case 'D':
   18626             :             case 'f':
   18627           0 :                 appendPQExpBufferStr(query, "DISABLE");
   18628           0 :                 break;
   18629           0 :             case 'A':
   18630           0 :                 appendPQExpBufferStr(query, "ENABLE ALWAYS");
   18631           0 :                 break;
   18632           0 :             case 'R':
   18633           0 :                 appendPQExpBufferStr(query, "ENABLE REPLICA");
   18634           0 :                 break;
   18635           0 :             default:
   18636           0 :                 appendPQExpBufferStr(query, "ENABLE");
   18637           0 :                 break;
   18638             :         }
   18639           0 :         appendPQExpBuffer(query, " TRIGGER %s;\n",
   18640           0 :                           fmtId(tginfo->dobj.name));
   18641             :     }
   18642             : 
   18643        1024 :     appendPQExpBuffer(trigprefix, "TRIGGER %s ON",
   18644        1024 :                       fmtId(tginfo->dobj.name));
   18645             : 
   18646        1024 :     tag = psprintf("%s %s", tbinfo->dobj.name, tginfo->dobj.name);
   18647             : 
   18648        1024 :     if (tginfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   18649        1024 :         ArchiveEntry(fout, tginfo->dobj.catId, tginfo->dobj.dumpId,
   18650        1024 :                      ARCHIVE_OPTS(.tag = tag,
   18651             :                                   .namespace = tbinfo->dobj.namespace->dobj.name,
   18652             :                                   .owner = tbinfo->rolname,
   18653             :                                   .description = "TRIGGER",
   18654             :                                   .section = SECTION_POST_DATA,
   18655             :                                   .createStmt = query->data,
   18656             :                                   .dropStmt = delqry->data));
   18657             : 
   18658        1024 :     if (tginfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   18659           0 :         dumpComment(fout, trigprefix->data, qtabname,
   18660           0 :                     tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
   18661             :                     tginfo->dobj.catId, 0, tginfo->dobj.dumpId);
   18662             : 
   18663        1024 :     free(tag);
   18664        1024 :     destroyPQExpBuffer(query);
   18665        1024 :     destroyPQExpBuffer(delqry);
   18666        1024 :     destroyPQExpBuffer(trigprefix);
   18667        1024 :     destroyPQExpBuffer(trigidentity);
   18668        1024 :     free(qtabname);
   18669             : }
   18670             : 
   18671             : /*
   18672             :  * dumpEventTrigger
   18673             :  *    write the declaration of one user-defined event trigger
   18674             :  */
   18675             : static void
   18676          92 : dumpEventTrigger(Archive *fout, const EventTriggerInfo *evtinfo)
   18677             : {
   18678          92 :     DumpOptions *dopt = fout->dopt;
   18679             :     PQExpBuffer query;
   18680             :     PQExpBuffer delqry;
   18681             :     char       *qevtname;
   18682             : 
   18683             :     /* Do nothing if not dumping schema */
   18684          92 :     if (!dopt->dumpSchema)
   18685          12 :         return;
   18686             : 
   18687          80 :     query = createPQExpBuffer();
   18688          80 :     delqry = createPQExpBuffer();
   18689             : 
   18690          80 :     qevtname = pg_strdup(fmtId(evtinfo->dobj.name));
   18691             : 
   18692          80 :     appendPQExpBufferStr(query, "CREATE EVENT TRIGGER ");
   18693          80 :     appendPQExpBufferStr(query, qevtname);
   18694          80 :     appendPQExpBufferStr(query, " ON ");
   18695          80 :     appendPQExpBufferStr(query, fmtId(evtinfo->evtevent));
   18696             : 
   18697          80 :     if (strcmp("", evtinfo->evttags) != 0)
   18698             :     {
   18699          10 :         appendPQExpBufferStr(query, "\n         WHEN TAG IN (");
   18700          10 :         appendPQExpBufferStr(query, evtinfo->evttags);
   18701          10 :         appendPQExpBufferChar(query, ')');
   18702             :     }
   18703             : 
   18704          80 :     appendPQExpBufferStr(query, "\n   EXECUTE FUNCTION ");
   18705          80 :     appendPQExpBufferStr(query, evtinfo->evtfname);
   18706          80 :     appendPQExpBufferStr(query, "();\n");
   18707             : 
   18708          80 :     if (evtinfo->evtenabled != 'O')
   18709             :     {
   18710           0 :         appendPQExpBuffer(query, "\nALTER EVENT TRIGGER %s ",
   18711             :                           qevtname);
   18712           0 :         switch (evtinfo->evtenabled)
   18713             :         {
   18714           0 :             case 'D':
   18715           0 :                 appendPQExpBufferStr(query, "DISABLE");
   18716           0 :                 break;
   18717           0 :             case 'A':
   18718           0 :                 appendPQExpBufferStr(query, "ENABLE ALWAYS");
   18719           0 :                 break;
   18720           0 :             case 'R':
   18721           0 :                 appendPQExpBufferStr(query, "ENABLE REPLICA");
   18722           0 :                 break;
   18723           0 :             default:
   18724           0 :                 appendPQExpBufferStr(query, "ENABLE");
   18725           0 :                 break;
   18726             :         }
   18727           0 :         appendPQExpBufferStr(query, ";\n");
   18728             :     }
   18729             : 
   18730          80 :     appendPQExpBuffer(delqry, "DROP EVENT TRIGGER %s;\n",
   18731             :                       qevtname);
   18732             : 
   18733          80 :     if (dopt->binary_upgrade)
   18734           4 :         binary_upgrade_extension_member(query, &evtinfo->dobj,
   18735             :                                         "EVENT TRIGGER", qevtname, NULL);
   18736             : 
   18737          80 :     if (evtinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   18738          80 :         ArchiveEntry(fout, evtinfo->dobj.catId, evtinfo->dobj.dumpId,
   18739          80 :                      ARCHIVE_OPTS(.tag = evtinfo->dobj.name,
   18740             :                                   .owner = evtinfo->evtowner,
   18741             :                                   .description = "EVENT TRIGGER",
   18742             :                                   .section = SECTION_POST_DATA,
   18743             :                                   .createStmt = query->data,
   18744             :                                   .dropStmt = delqry->data));
   18745             : 
   18746          80 :     if (evtinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   18747           0 :         dumpComment(fout, "EVENT TRIGGER", qevtname,
   18748             :                     NULL, evtinfo->evtowner,
   18749             :                     evtinfo->dobj.catId, 0, evtinfo->dobj.dumpId);
   18750             : 
   18751          80 :     destroyPQExpBuffer(query);
   18752          80 :     destroyPQExpBuffer(delqry);
   18753          80 :     free(qevtname);
   18754             : }
   18755             : 
   18756             : /*
   18757             :  * dumpRule
   18758             :  *      Dump a rule
   18759             :  */
   18760             : static void
   18761        2374 : dumpRule(Archive *fout, const RuleInfo *rinfo)
   18762             : {
   18763        2374 :     DumpOptions *dopt = fout->dopt;
   18764        2374 :     TableInfo  *tbinfo = rinfo->ruletable;
   18765             :     bool        is_view;
   18766             :     PQExpBuffer query;
   18767             :     PQExpBuffer cmd;
   18768             :     PQExpBuffer delcmd;
   18769             :     PQExpBuffer ruleprefix;
   18770             :     char       *qtabname;
   18771             :     PGresult   *res;
   18772             :     char       *tag;
   18773             : 
   18774             :     /* Do nothing if not dumping schema */
   18775        2374 :     if (!dopt->dumpSchema)
   18776         132 :         return;
   18777             : 
   18778             :     /*
   18779             :      * If it is an ON SELECT rule that is created implicitly by CREATE VIEW,
   18780             :      * we do not want to dump it as a separate object.
   18781             :      */
   18782        2242 :     if (!rinfo->separate)
   18783        1820 :         return;
   18784             : 
   18785             :     /*
   18786             :      * If it's an ON SELECT rule, we want to print it as a view definition,
   18787             :      * instead of a rule.
   18788             :      */
   18789         422 :     is_view = (rinfo->ev_type == '1' && rinfo->is_instead);
   18790             : 
   18791         422 :     query = createPQExpBuffer();
   18792         422 :     cmd = createPQExpBuffer();
   18793         422 :     delcmd = createPQExpBuffer();
   18794         422 :     ruleprefix = createPQExpBuffer();
   18795             : 
   18796         422 :     qtabname = pg_strdup(fmtId(tbinfo->dobj.name));
   18797             : 
   18798         422 :     if (is_view)
   18799             :     {
   18800             :         PQExpBuffer result;
   18801             : 
   18802             :         /*
   18803             :          * We need OR REPLACE here because we'll be replacing a dummy view.
   18804             :          * Otherwise this should look largely like the regular view dump code.
   18805             :          */
   18806          20 :         appendPQExpBuffer(cmd, "CREATE OR REPLACE VIEW %s",
   18807          20 :                           fmtQualifiedDumpable(tbinfo));
   18808          20 :         if (nonemptyReloptions(tbinfo->reloptions))
   18809             :         {
   18810           0 :             appendPQExpBufferStr(cmd, " WITH (");
   18811           0 :             appendReloptionsArrayAH(cmd, tbinfo->reloptions, "", fout);
   18812           0 :             appendPQExpBufferChar(cmd, ')');
   18813             :         }
   18814          20 :         result = createViewAsClause(fout, tbinfo);
   18815          20 :         appendPQExpBuffer(cmd, " AS\n%s", result->data);
   18816          20 :         destroyPQExpBuffer(result);
   18817          20 :         if (tbinfo->checkoption != NULL)
   18818           0 :             appendPQExpBuffer(cmd, "\n  WITH %s CHECK OPTION",
   18819             :                               tbinfo->checkoption);
   18820          20 :         appendPQExpBufferStr(cmd, ";\n");
   18821             :     }
   18822             :     else
   18823             :     {
   18824             :         /* In the rule case, just print pg_get_ruledef's result verbatim */
   18825         402 :         appendPQExpBuffer(query,
   18826             :                           "SELECT pg_catalog.pg_get_ruledef('%u'::pg_catalog.oid)",
   18827             :                           rinfo->dobj.catId.oid);
   18828             : 
   18829         402 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   18830             : 
   18831         402 :         if (PQntuples(res) != 1)
   18832           0 :             pg_fatal("query to get rule \"%s\" for table \"%s\" failed: wrong number of rows returned",
   18833             :                      rinfo->dobj.name, tbinfo->dobj.name);
   18834             : 
   18835         402 :         printfPQExpBuffer(cmd, "%s\n", PQgetvalue(res, 0, 0));
   18836             : 
   18837         402 :         PQclear(res);
   18838             :     }
   18839             : 
   18840             :     /*
   18841             :      * Add the command to alter the rules replication firing semantics if it
   18842             :      * differs from the default.
   18843             :      */
   18844         422 :     if (rinfo->ev_enabled != 'O')
   18845             :     {
   18846          30 :         appendPQExpBuffer(cmd, "ALTER TABLE %s ", fmtQualifiedDumpable(tbinfo));
   18847          30 :         switch (rinfo->ev_enabled)
   18848             :         {
   18849           0 :             case 'A':
   18850           0 :                 appendPQExpBuffer(cmd, "ENABLE ALWAYS RULE %s;\n",
   18851           0 :                                   fmtId(rinfo->dobj.name));
   18852           0 :                 break;
   18853           0 :             case 'R':
   18854           0 :                 appendPQExpBuffer(cmd, "ENABLE REPLICA RULE %s;\n",
   18855           0 :                                   fmtId(rinfo->dobj.name));
   18856           0 :                 break;
   18857          30 :             case 'D':
   18858          30 :                 appendPQExpBuffer(cmd, "DISABLE RULE %s;\n",
   18859          30 :                                   fmtId(rinfo->dobj.name));
   18860          30 :                 break;
   18861             :         }
   18862         392 :     }
   18863             : 
   18864         422 :     if (is_view)
   18865             :     {
   18866             :         /*
   18867             :          * We can't DROP a view's ON SELECT rule.  Instead, use CREATE OR
   18868             :          * REPLACE VIEW to replace the rule with something with minimal
   18869             :          * dependencies.
   18870             :          */
   18871             :         PQExpBuffer result;
   18872             : 
   18873          20 :         appendPQExpBuffer(delcmd, "CREATE OR REPLACE VIEW %s",
   18874          20 :                           fmtQualifiedDumpable(tbinfo));
   18875          20 :         result = createDummyViewAsClause(fout, tbinfo);
   18876          20 :         appendPQExpBuffer(delcmd, " AS\n%s;\n", result->data);
   18877          20 :         destroyPQExpBuffer(result);
   18878             :     }
   18879             :     else
   18880             :     {
   18881         402 :         appendPQExpBuffer(delcmd, "DROP RULE %s ",
   18882         402 :                           fmtId(rinfo->dobj.name));
   18883         402 :         appendPQExpBuffer(delcmd, "ON %s;\n",
   18884         402 :                           fmtQualifiedDumpable(tbinfo));
   18885             :     }
   18886             : 
   18887         422 :     appendPQExpBuffer(ruleprefix, "RULE %s ON",
   18888         422 :                       fmtId(rinfo->dobj.name));
   18889             : 
   18890         422 :     tag = psprintf("%s %s", tbinfo->dobj.name, rinfo->dobj.name);
   18891             : 
   18892         422 :     if (rinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   18893         422 :         ArchiveEntry(fout, rinfo->dobj.catId, rinfo->dobj.dumpId,
   18894         422 :                      ARCHIVE_OPTS(.tag = tag,
   18895             :                                   .namespace = tbinfo->dobj.namespace->dobj.name,
   18896             :                                   .owner = tbinfo->rolname,
   18897             :                                   .description = "RULE",
   18898             :                                   .section = SECTION_POST_DATA,
   18899             :                                   .createStmt = cmd->data,
   18900             :                                   .dropStmt = delcmd->data));
   18901             : 
   18902             :     /* Dump rule comments */
   18903         422 :     if (rinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   18904           0 :         dumpComment(fout, ruleprefix->data, qtabname,
   18905           0 :                     tbinfo->dobj.namespace->dobj.name,
   18906             :                     tbinfo->rolname,
   18907             :                     rinfo->dobj.catId, 0, rinfo->dobj.dumpId);
   18908             : 
   18909         422 :     free(tag);
   18910         422 :     destroyPQExpBuffer(query);
   18911         422 :     destroyPQExpBuffer(cmd);
   18912         422 :     destroyPQExpBuffer(delcmd);
   18913         422 :     destroyPQExpBuffer(ruleprefix);
   18914         422 :     free(qtabname);
   18915             : }
   18916             : 
   18917             : /*
   18918             :  * getExtensionMembership --- obtain extension membership data
   18919             :  *
   18920             :  * We need to identify objects that are extension members as soon as they're
   18921             :  * loaded, so that we can correctly determine whether they need to be dumped.
   18922             :  * Generally speaking, extension member objects will get marked as *not* to
   18923             :  * be dumped, as they will be recreated by the single CREATE EXTENSION
   18924             :  * command.  However, in binary upgrade mode we still need to dump the members
   18925             :  * individually.
   18926             :  */
   18927             : void
   18928         356 : getExtensionMembership(Archive *fout, ExtensionInfo extinfo[],
   18929             :                        int numExtensions)
   18930             : {
   18931             :     PQExpBuffer query;
   18932             :     PGresult   *res;
   18933             :     int         ntups,
   18934             :                 i;
   18935             :     int         i_classid,
   18936             :                 i_objid,
   18937             :                 i_refobjid;
   18938             :     ExtensionInfo *ext;
   18939             : 
   18940             :     /* Nothing to do if no extensions */
   18941         356 :     if (numExtensions == 0)
   18942           0 :         return;
   18943             : 
   18944         356 :     query = createPQExpBuffer();
   18945             : 
   18946             :     /* refclassid constraint is redundant but may speed the search */
   18947         356 :     appendPQExpBufferStr(query, "SELECT "
   18948             :                          "classid, objid, refobjid "
   18949             :                          "FROM pg_depend "
   18950             :                          "WHERE refclassid = 'pg_extension'::regclass "
   18951             :                          "AND deptype = 'e' "
   18952             :                          "ORDER BY 3");
   18953             : 
   18954         356 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   18955             : 
   18956         356 :     ntups = PQntuples(res);
   18957             : 
   18958         356 :     i_classid = PQfnumber(res, "classid");
   18959         356 :     i_objid = PQfnumber(res, "objid");
   18960         356 :     i_refobjid = PQfnumber(res, "refobjid");
   18961             : 
   18962             :     /*
   18963             :      * Since we ordered the SELECT by referenced ID, we can expect that
   18964             :      * multiple entries for the same extension will appear together; this
   18965             :      * saves on searches.
   18966             :      */
   18967         356 :     ext = NULL;
   18968             : 
   18969        2980 :     for (i = 0; i < ntups; i++)
   18970             :     {
   18971             :         CatalogId   objId;
   18972             :         Oid         extId;
   18973             : 
   18974        2624 :         objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
   18975        2624 :         objId.oid = atooid(PQgetvalue(res, i, i_objid));
   18976        2624 :         extId = atooid(PQgetvalue(res, i, i_refobjid));
   18977             : 
   18978        2624 :         if (ext == NULL ||
   18979        2268 :             ext->dobj.catId.oid != extId)
   18980         406 :             ext = findExtensionByOid(extId);
   18981             : 
   18982        2624 :         if (ext == NULL)
   18983             :         {
   18984             :             /* shouldn't happen */
   18985           0 :             pg_log_warning("could not find referenced extension %u", extId);
   18986           0 :             continue;
   18987             :         }
   18988             : 
   18989        2624 :         recordExtensionMembership(objId, ext);
   18990             :     }
   18991             : 
   18992         356 :     PQclear(res);
   18993             : 
   18994         356 :     destroyPQExpBuffer(query);
   18995             : }
   18996             : 
   18997             : /*
   18998             :  * processExtensionTables --- deal with extension configuration tables
   18999             :  *
   19000             :  * There are two parts to this process:
   19001             :  *
   19002             :  * 1. Identify and create dump records for extension configuration tables.
   19003             :  *
   19004             :  *    Extensions can mark tables as "configuration", which means that the user
   19005             :  *    is able and expected to modify those tables after the extension has been
   19006             :  *    loaded.  For these tables, we dump out only the data- the structure is
   19007             :  *    expected to be handled at CREATE EXTENSION time, including any indexes or
   19008             :  *    foreign keys, which brings us to-
   19009             :  *
   19010             :  * 2. Record FK dependencies between configuration tables.
   19011             :  *
   19012             :  *    Due to the FKs being created at CREATE EXTENSION time and therefore before
   19013             :  *    the data is loaded, we have to work out what the best order for reloading
   19014             :  *    the data is, to avoid FK violations when the tables are restored.  This is
   19015             :  *    not perfect- we can't handle circular dependencies and if any exist they
   19016             :  *    will cause an invalid dump to be produced (though at least all of the data
   19017             :  *    is included for a user to manually restore).  This is currently documented
   19018             :  *    but perhaps we can provide a better solution in the future.
   19019             :  */
   19020             : void
   19021         354 : processExtensionTables(Archive *fout, ExtensionInfo extinfo[],
   19022             :                        int numExtensions)
   19023             : {
   19024         354 :     DumpOptions *dopt = fout->dopt;
   19025             :     PQExpBuffer query;
   19026             :     PGresult   *res;
   19027             :     int         ntups,
   19028             :                 i;
   19029             :     int         i_conrelid,
   19030             :                 i_confrelid;
   19031             : 
   19032             :     /* Nothing to do if no extensions */
   19033         354 :     if (numExtensions == 0)
   19034           0 :         return;
   19035             : 
   19036             :     /*
   19037             :      * Identify extension configuration tables and create TableDataInfo
   19038             :      * objects for them, ensuring their data will be dumped even though the
   19039             :      * tables themselves won't be.
   19040             :      *
   19041             :      * Note that we create TableDataInfo objects even in schema-only mode, ie,
   19042             :      * user data in a configuration table is treated like schema data. This
   19043             :      * seems appropriate since system data in a config table would get
   19044             :      * reloaded by CREATE EXTENSION.  If the extension is not listed in the
   19045             :      * list of extensions to be included, none of its data is dumped.
   19046             :      */
   19047         758 :     for (i = 0; i < numExtensions; i++)
   19048             :     {
   19049         404 :         ExtensionInfo *curext = &(extinfo[i]);
   19050         404 :         char       *extconfig = curext->extconfig;
   19051         404 :         char       *extcondition = curext->extcondition;
   19052         404 :         char      **extconfigarray = NULL;
   19053         404 :         char      **extconditionarray = NULL;
   19054         404 :         int         nconfigitems = 0;
   19055         404 :         int         nconditionitems = 0;
   19056             : 
   19057             :         /*
   19058             :          * Check if this extension is listed as to include in the dump.  If
   19059             :          * not, any table data associated with it is discarded.
   19060             :          */
   19061         404 :         if (extension_include_oids.head != NULL &&
   19062          16 :             !simple_oid_list_member(&extension_include_oids,
   19063             :                                     curext->dobj.catId.oid))
   19064          12 :             continue;
   19065             : 
   19066             :         /*
   19067             :          * Check if this extension is listed as to exclude in the dump.  If
   19068             :          * yes, any table data associated with it is discarded.
   19069             :          */
   19070         404 :         if (extension_exclude_oids.head != NULL &&
   19071           8 :             simple_oid_list_member(&extension_exclude_oids,
   19072             :                                    curext->dobj.catId.oid))
   19073           4 :             continue;
   19074             : 
   19075         392 :         if (strlen(extconfig) != 0 || strlen(extcondition) != 0)
   19076             :         {
   19077             :             int         j;
   19078             : 
   19079          40 :             if (!parsePGArray(extconfig, &extconfigarray, &nconfigitems))
   19080           0 :                 pg_fatal("could not parse %s array", "extconfig");
   19081          40 :             if (!parsePGArray(extcondition, &extconditionarray, &nconditionitems))
   19082           0 :                 pg_fatal("could not parse %s array", "extcondition");
   19083          40 :             if (nconfigitems != nconditionitems)
   19084           0 :                 pg_fatal("mismatched number of configurations and conditions for extension");
   19085             : 
   19086         120 :             for (j = 0; j < nconfigitems; j++)
   19087             :             {
   19088             :                 TableInfo  *configtbl;
   19089          80 :                 Oid         configtbloid = atooid(extconfigarray[j]);
   19090          80 :                 bool        dumpobj =
   19091          80 :                     curext->dobj.dump & DUMP_COMPONENT_DEFINITION;
   19092             : 
   19093          80 :                 configtbl = findTableByOid(configtbloid);
   19094          80 :                 if (configtbl == NULL)
   19095           0 :                     continue;
   19096             : 
   19097             :                 /*
   19098             :                  * Tables of not-to-be-dumped extensions shouldn't be dumped
   19099             :                  * unless the table or its schema is explicitly included
   19100             :                  */
   19101          80 :                 if (!(curext->dobj.dump & DUMP_COMPONENT_DEFINITION))
   19102             :                 {
   19103             :                     /* check table explicitly requested */
   19104           4 :                     if (table_include_oids.head != NULL &&
   19105           0 :                         simple_oid_list_member(&table_include_oids,
   19106             :                                                configtbloid))
   19107           0 :                         dumpobj = true;
   19108             : 
   19109             :                     /* check table's schema explicitly requested */
   19110           4 :                     if (configtbl->dobj.namespace->dobj.dump &
   19111             :                         DUMP_COMPONENT_DATA)
   19112           4 :                         dumpobj = true;
   19113             :                 }
   19114             : 
   19115             :                 /* check table excluded by an exclusion switch */
   19116          88 :                 if (table_exclude_oids.head != NULL &&
   19117           8 :                     simple_oid_list_member(&table_exclude_oids,
   19118             :                                            configtbloid))
   19119           2 :                     dumpobj = false;
   19120             : 
   19121             :                 /* check schema excluded by an exclusion switch */
   19122          80 :                 if (simple_oid_list_member(&schema_exclude_oids,
   19123          80 :                                            configtbl->dobj.namespace->dobj.catId.oid))
   19124           0 :                     dumpobj = false;
   19125             : 
   19126          80 :                 if (dumpobj)
   19127             :                 {
   19128          78 :                     makeTableDataInfo(dopt, configtbl);
   19129          78 :                     if (configtbl->dataObj != NULL)
   19130             :                     {
   19131          78 :                         if (strlen(extconditionarray[j]) > 0)
   19132           0 :                             configtbl->dataObj->filtercond = pg_strdup(extconditionarray[j]);
   19133             :                     }
   19134             :                 }
   19135             :             }
   19136             :         }
   19137         392 :         if (extconfigarray)
   19138          40 :             free(extconfigarray);
   19139         392 :         if (extconditionarray)
   19140          40 :             free(extconditionarray);
   19141             :     }
   19142             : 
   19143             :     /*
   19144             :      * Now that all the TableDataInfo objects have been created for all the
   19145             :      * extensions, check their FK dependencies and register them to try and
   19146             :      * dump the data out in an order that they can be restored in.
   19147             :      *
   19148             :      * Note that this is not a problem for user tables as their FKs are
   19149             :      * recreated after the data has been loaded.
   19150             :      */
   19151             : 
   19152         354 :     query = createPQExpBuffer();
   19153             : 
   19154         354 :     printfPQExpBuffer(query,
   19155             :                       "SELECT conrelid, confrelid "
   19156             :                       "FROM pg_constraint "
   19157             :                       "JOIN pg_depend ON (objid = confrelid) "
   19158             :                       "WHERE contype = 'f' "
   19159             :                       "AND refclassid = 'pg_extension'::regclass "
   19160             :                       "AND classid = 'pg_class'::regclass;");
   19161             : 
   19162         354 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   19163         354 :     ntups = PQntuples(res);
   19164             : 
   19165         354 :     i_conrelid = PQfnumber(res, "conrelid");
   19166         354 :     i_confrelid = PQfnumber(res, "confrelid");
   19167             : 
   19168             :     /* Now get the dependencies and register them */
   19169         354 :     for (i = 0; i < ntups; i++)
   19170             :     {
   19171             :         Oid         conrelid,
   19172             :                     confrelid;
   19173             :         TableInfo  *reftable,
   19174             :                    *contable;
   19175             : 
   19176           0 :         conrelid = atooid(PQgetvalue(res, i, i_conrelid));
   19177           0 :         confrelid = atooid(PQgetvalue(res, i, i_confrelid));
   19178           0 :         contable = findTableByOid(conrelid);
   19179           0 :         reftable = findTableByOid(confrelid);
   19180             : 
   19181           0 :         if (reftable == NULL ||
   19182           0 :             reftable->dataObj == NULL ||
   19183           0 :             contable == NULL ||
   19184           0 :             contable->dataObj == NULL)
   19185           0 :             continue;
   19186             : 
   19187             :         /*
   19188             :          * Make referencing TABLE_DATA object depend on the referenced table's
   19189             :          * TABLE_DATA object.
   19190             :          */
   19191           0 :         addObjectDependency(&contable->dataObj->dobj,
   19192           0 :                             reftable->dataObj->dobj.dumpId);
   19193             :     }
   19194         354 :     PQclear(res);
   19195         354 :     destroyPQExpBuffer(query);
   19196             : }
   19197             : 
   19198             : /*
   19199             :  * getDependencies --- obtain available dependency data
   19200             :  */
   19201             : static void
   19202         354 : getDependencies(Archive *fout)
   19203             : {
   19204             :     PQExpBuffer query;
   19205             :     PGresult   *res;
   19206             :     int         ntups,
   19207             :                 i;
   19208             :     int         i_classid,
   19209             :                 i_objid,
   19210             :                 i_refclassid,
   19211             :                 i_refobjid,
   19212             :                 i_deptype;
   19213             :     DumpableObject *dobj,
   19214             :                *refdobj;
   19215             : 
   19216         354 :     pg_log_info("reading dependency data");
   19217             : 
   19218         354 :     query = createPQExpBuffer();
   19219             : 
   19220             :     /*
   19221             :      * Messy query to collect the dependency data we need.  Note that we
   19222             :      * ignore the sub-object column, so that dependencies of or on a column
   19223             :      * look the same as dependencies of or on a whole table.
   19224             :      *
   19225             :      * PIN dependencies aren't interesting, and EXTENSION dependencies were
   19226             :      * already processed by getExtensionMembership.
   19227             :      */
   19228         354 :     appendPQExpBufferStr(query, "SELECT "
   19229             :                          "classid, objid, refclassid, refobjid, deptype "
   19230             :                          "FROM pg_depend "
   19231             :                          "WHERE deptype != 'p' AND deptype != 'e'\n");
   19232             : 
   19233             :     /*
   19234             :      * Since we don't treat pg_amop entries as separate DumpableObjects, we
   19235             :      * have to translate their dependencies into dependencies of their parent
   19236             :      * opfamily.  Ignore internal dependencies though, as those will point to
   19237             :      * their parent opclass, which we needn't consider here (and if we did,
   19238             :      * it'd just result in circular dependencies).  Also, "loose" opfamily
   19239             :      * entries will have dependencies on their parent opfamily, which we
   19240             :      * should drop since they'd likewise become useless self-dependencies.
   19241             :      * (But be sure to keep deps on *other* opfamilies; see amopsortfamily.)
   19242             :      */
   19243         354 :     appendPQExpBufferStr(query, "UNION ALL\n"
   19244             :                          "SELECT 'pg_opfamily'::regclass AS classid, amopfamily AS objid, refclassid, refobjid, deptype "
   19245             :                          "FROM pg_depend d, pg_amop o "
   19246             :                          "WHERE deptype NOT IN ('p', 'e', 'i') AND "
   19247             :                          "classid = 'pg_amop'::regclass AND objid = o.oid "
   19248             :                          "AND NOT (refclassid = 'pg_opfamily'::regclass AND amopfamily = refobjid)\n");
   19249             : 
   19250             :     /* Likewise for pg_amproc entries */
   19251         354 :     appendPQExpBufferStr(query, "UNION ALL\n"
   19252             :                          "SELECT 'pg_opfamily'::regclass AS classid, amprocfamily AS objid, refclassid, refobjid, deptype "
   19253             :                          "FROM pg_depend d, pg_amproc p "
   19254             :                          "WHERE deptype NOT IN ('p', 'e', 'i') AND "
   19255             :                          "classid = 'pg_amproc'::regclass AND objid = p.oid "
   19256             :                          "AND NOT (refclassid = 'pg_opfamily'::regclass AND amprocfamily = refobjid)\n");
   19257             : 
   19258             :     /* Sort the output for efficiency below */
   19259         354 :     appendPQExpBufferStr(query, "ORDER BY 1,2");
   19260             : 
   19261         354 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   19262             : 
   19263         354 :     ntups = PQntuples(res);
   19264             : 
   19265         354 :     i_classid = PQfnumber(res, "classid");
   19266         354 :     i_objid = PQfnumber(res, "objid");
   19267         354 :     i_refclassid = PQfnumber(res, "refclassid");
   19268         354 :     i_refobjid = PQfnumber(res, "refobjid");
   19269         354 :     i_deptype = PQfnumber(res, "deptype");
   19270             : 
   19271             :     /*
   19272             :      * Since we ordered the SELECT by referencing ID, we can expect that
   19273             :      * multiple entries for the same object will appear together; this saves
   19274             :      * on searches.
   19275             :      */
   19276         354 :     dobj = NULL;
   19277             : 
   19278      765112 :     for (i = 0; i < ntups; i++)
   19279             :     {
   19280             :         CatalogId   objId;
   19281             :         CatalogId   refobjId;
   19282             :         char        deptype;
   19283             : 
   19284      764758 :         objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
   19285      764758 :         objId.oid = atooid(PQgetvalue(res, i, i_objid));
   19286      764758 :         refobjId.tableoid = atooid(PQgetvalue(res, i, i_refclassid));
   19287      764758 :         refobjId.oid = atooid(PQgetvalue(res, i, i_refobjid));
   19288      764758 :         deptype = *(PQgetvalue(res, i, i_deptype));
   19289             : 
   19290      764758 :         if (dobj == NULL ||
   19291      715440 :             dobj->catId.tableoid != objId.tableoid ||
   19292      711262 :             dobj->catId.oid != objId.oid)
   19293      334862 :             dobj = findObjectByCatalogId(objId);
   19294             : 
   19295             :         /*
   19296             :          * Failure to find objects mentioned in pg_depend is not unexpected,
   19297             :          * since for example we don't collect info about TOAST tables.
   19298             :          */
   19299      764758 :         if (dobj == NULL)
   19300             :         {
   19301             : #ifdef NOT_USED
   19302             :             pg_log_warning("no referencing object %u %u",
   19303             :                            objId.tableoid, objId.oid);
   19304             : #endif
   19305       50612 :             continue;
   19306             :         }
   19307             : 
   19308      715794 :         refdobj = findObjectByCatalogId(refobjId);
   19309             : 
   19310      715794 :         if (refdobj == NULL)
   19311             :         {
   19312             : #ifdef NOT_USED
   19313             :             pg_log_warning("no referenced object %u %u",
   19314             :                            refobjId.tableoid, refobjId.oid);
   19315             : #endif
   19316        1648 :             continue;
   19317             :         }
   19318             : 
   19319             :         /*
   19320             :          * For 'x' dependencies, mark the object for later; we still add the
   19321             :          * normal dependency, for possible ordering purposes.  Currently
   19322             :          * pg_dump_sort.c knows to put extensions ahead of all object types
   19323             :          * that could possibly depend on them, but this is safer.
   19324             :          */
   19325      714146 :         if (deptype == 'x')
   19326          88 :             dobj->depends_on_ext = true;
   19327             : 
   19328             :         /*
   19329             :          * Ordinarily, table rowtypes have implicit dependencies on their
   19330             :          * tables.  However, for a composite type the implicit dependency goes
   19331             :          * the other way in pg_depend; which is the right thing for DROP but
   19332             :          * it doesn't produce the dependency ordering we need. So in that one
   19333             :          * case, we reverse the direction of the dependency.
   19334             :          */
   19335      714146 :         if (deptype == 'i' &&
   19336      198130 :             dobj->objType == DO_TABLE &&
   19337        2410 :             refdobj->objType == DO_TYPE)
   19338         372 :             addObjectDependency(refdobj, dobj->dumpId);
   19339             :         else
   19340             :             /* normal case */
   19341      713774 :             addObjectDependency(dobj, refdobj->dumpId);
   19342             :     }
   19343             : 
   19344         354 :     PQclear(res);
   19345             : 
   19346         354 :     destroyPQExpBuffer(query);
   19347         354 : }
   19348             : 
   19349             : 
   19350             : /*
   19351             :  * createBoundaryObjects - create dummy DumpableObjects to represent
   19352             :  * dump section boundaries.
   19353             :  */
   19354             : static DumpableObject *
   19355         354 : createBoundaryObjects(void)
   19356             : {
   19357             :     DumpableObject *dobjs;
   19358             : 
   19359         354 :     dobjs = (DumpableObject *) pg_malloc(2 * sizeof(DumpableObject));
   19360             : 
   19361         354 :     dobjs[0].objType = DO_PRE_DATA_BOUNDARY;
   19362         354 :     dobjs[0].catId = nilCatalogId;
   19363         354 :     AssignDumpId(dobjs + 0);
   19364         354 :     dobjs[0].name = pg_strdup("PRE-DATA BOUNDARY");
   19365             : 
   19366         354 :     dobjs[1].objType = DO_POST_DATA_BOUNDARY;
   19367         354 :     dobjs[1].catId = nilCatalogId;
   19368         354 :     AssignDumpId(dobjs + 1);
   19369         354 :     dobjs[1].name = pg_strdup("POST-DATA BOUNDARY");
   19370             : 
   19371         354 :     return dobjs;
   19372             : }
   19373             : 
   19374             : /*
   19375             :  * addBoundaryDependencies - add dependencies as needed to enforce the dump
   19376             :  * section boundaries.
   19377             :  */
   19378             : static void
   19379         354 : addBoundaryDependencies(DumpableObject **dobjs, int numObjs,
   19380             :                         DumpableObject *boundaryObjs)
   19381             : {
   19382         354 :     DumpableObject *preDataBound = boundaryObjs + 0;
   19383         354 :     DumpableObject *postDataBound = boundaryObjs + 1;
   19384             :     int         i;
   19385             : 
   19386     1305290 :     for (i = 0; i < numObjs; i++)
   19387             :     {
   19388     1304936 :         DumpableObject *dobj = dobjs[i];
   19389             : 
   19390             :         /*
   19391             :          * The classification of object types here must match the SECTION_xxx
   19392             :          * values assigned during subsequent ArchiveEntry calls!
   19393             :          */
   19394     1304936 :         switch (dobj->objType)
   19395             :         {
   19396     1212700 :             case DO_NAMESPACE:
   19397             :             case DO_EXTENSION:
   19398             :             case DO_TYPE:
   19399             :             case DO_SHELL_TYPE:
   19400             :             case DO_FUNC:
   19401             :             case DO_AGG:
   19402             :             case DO_OPERATOR:
   19403             :             case DO_ACCESS_METHOD:
   19404             :             case DO_OPCLASS:
   19405             :             case DO_OPFAMILY:
   19406             :             case DO_COLLATION:
   19407             :             case DO_CONVERSION:
   19408             :             case DO_TABLE:
   19409             :             case DO_TABLE_ATTACH:
   19410             :             case DO_ATTRDEF:
   19411             :             case DO_PROCLANG:
   19412             :             case DO_CAST:
   19413             :             case DO_DUMMY_TYPE:
   19414             :             case DO_TSPARSER:
   19415             :             case DO_TSDICT:
   19416             :             case DO_TSTEMPLATE:
   19417             :             case DO_TSCONFIG:
   19418             :             case DO_FDW:
   19419             :             case DO_FOREIGN_SERVER:
   19420             :             case DO_TRANSFORM:
   19421             :                 /* Pre-data objects: must come before the pre-data boundary */
   19422     1212700 :                 addObjectDependency(preDataBound, dobj->dumpId);
   19423     1212700 :                 break;
   19424        9034 :             case DO_TABLE_DATA:
   19425             :             case DO_SEQUENCE_SET:
   19426             :             case DO_LARGE_OBJECT:
   19427             :             case DO_LARGE_OBJECT_DATA:
   19428             :                 /* Data objects: must come between the boundaries */
   19429        9034 :                 addObjectDependency(dobj, preDataBound->dumpId);
   19430        9034 :                 addObjectDependency(postDataBound, dobj->dumpId);
   19431        9034 :                 break;
   19432       11586 :             case DO_INDEX:
   19433             :             case DO_INDEX_ATTACH:
   19434             :             case DO_STATSEXT:
   19435             :             case DO_REFRESH_MATVIEW:
   19436             :             case DO_TRIGGER:
   19437             :             case DO_EVENT_TRIGGER:
   19438             :             case DO_DEFAULT_ACL:
   19439             :             case DO_POLICY:
   19440             :             case DO_PUBLICATION:
   19441             :             case DO_PUBLICATION_REL:
   19442             :             case DO_PUBLICATION_TABLE_IN_SCHEMA:
   19443             :             case DO_SUBSCRIPTION:
   19444             :             case DO_SUBSCRIPTION_REL:
   19445             :                 /* Post-data objects: must come after the post-data boundary */
   19446       11586 :                 addObjectDependency(dobj, postDataBound->dumpId);
   19447       11586 :                 break;
   19448       53766 :             case DO_RULE:
   19449             :                 /* Rules are post-data, but only if dumped separately */
   19450       53766 :                 if (((RuleInfo *) dobj)->separate)
   19451        1254 :                     addObjectDependency(dobj, postDataBound->dumpId);
   19452       53766 :                 break;
   19453        4954 :             case DO_CONSTRAINT:
   19454             :             case DO_FK_CONSTRAINT:
   19455             :                 /* Constraints are post-data, but only if dumped separately */
   19456        4954 :                 if (((ConstraintInfo *) dobj)->separate)
   19457        3556 :                     addObjectDependency(dobj, postDataBound->dumpId);
   19458        4954 :                 break;
   19459         354 :             case DO_PRE_DATA_BOUNDARY:
   19460             :                 /* nothing to do */
   19461         354 :                 break;
   19462         354 :             case DO_POST_DATA_BOUNDARY:
   19463             :                 /* must come after the pre-data boundary */
   19464         354 :                 addObjectDependency(dobj, preDataBound->dumpId);
   19465         354 :                 break;
   19466       12188 :             case DO_REL_STATS:
   19467             :                 /* stats section varies by parent object type, DATA or POST */
   19468       12188 :                 if (((RelStatsInfo *) dobj)->section == SECTION_DATA)
   19469             :                 {
   19470        7530 :                     addObjectDependency(dobj, preDataBound->dumpId);
   19471        7530 :                     addObjectDependency(postDataBound, dobj->dumpId);
   19472             :                 }
   19473             :                 else
   19474        4658 :                     addObjectDependency(dobj, postDataBound->dumpId);
   19475       12188 :                 break;
   19476             :         }
   19477     1304936 :     }
   19478         354 : }
   19479             : 
   19480             : 
   19481             : /*
   19482             :  * BuildArchiveDependencies - create dependency data for archive TOC entries
   19483             :  *
   19484             :  * The raw dependency data obtained by getDependencies() is not terribly
   19485             :  * useful in an archive dump, because in many cases there are dependency
   19486             :  * chains linking through objects that don't appear explicitly in the dump.
   19487             :  * For example, a view will depend on its _RETURN rule while the _RETURN rule
   19488             :  * will depend on other objects --- but the rule will not appear as a separate
   19489             :  * object in the dump.  We need to adjust the view's dependencies to include
   19490             :  * whatever the rule depends on that is included in the dump.
   19491             :  *
   19492             :  * Just to make things more complicated, there are also "special" dependencies
   19493             :  * such as the dependency of a TABLE DATA item on its TABLE, which we must
   19494             :  * not rearrange because pg_restore knows that TABLE DATA only depends on
   19495             :  * its table.  In these cases we must leave the dependencies strictly as-is
   19496             :  * even if they refer to not-to-be-dumped objects.
   19497             :  *
   19498             :  * To handle this, the convention is that "special" dependencies are created
   19499             :  * during ArchiveEntry calls, and an archive TOC item that has any such
   19500             :  * entries will not be touched here.  Otherwise, we recursively search the
   19501             :  * DumpableObject data structures to build the correct dependencies for each
   19502             :  * archive TOC item.
   19503             :  */
   19504             : static void
   19505          96 : BuildArchiveDependencies(Archive *fout)
   19506             : {
   19507          96 :     ArchiveHandle *AH = (ArchiveHandle *) fout;
   19508             :     TocEntry   *te;
   19509             : 
   19510             :     /* Scan all TOC entries in the archive */
   19511       13666 :     for (te = AH->toc->next; te != AH->toc; te = te->next)
   19512             :     {
   19513             :         DumpableObject *dobj;
   19514             :         DumpId     *dependencies;
   19515             :         int         nDeps;
   19516             :         int         allocDeps;
   19517             : 
   19518             :         /* No need to process entries that will not be dumped */
   19519       13570 :         if (te->reqs == 0)
   19520        6584 :             continue;
   19521             :         /* Ignore entries that already have "special" dependencies */
   19522       13564 :         if (te->nDeps > 0)
   19523        5844 :             continue;
   19524             :         /* Otherwise, look up the item's original DumpableObject, if any */
   19525        7720 :         dobj = findObjectByDumpId(te->dumpId);
   19526        7720 :         if (dobj == NULL)
   19527         522 :             continue;
   19528             :         /* No work if it has no dependencies */
   19529        7198 :         if (dobj->nDeps <= 0)
   19530         212 :             continue;
   19531             :         /* Set up work array */
   19532        6986 :         allocDeps = 64;
   19533        6986 :         dependencies = (DumpId *) pg_malloc(allocDeps * sizeof(DumpId));
   19534        6986 :         nDeps = 0;
   19535             :         /* Recursively find all dumpable dependencies */
   19536        6986 :         findDumpableDependencies(AH, dobj,
   19537             :                                  &dependencies, &nDeps, &allocDeps);
   19538             :         /* And save 'em ... */
   19539        6986 :         if (nDeps > 0)
   19540             :         {
   19541        5330 :             dependencies = (DumpId *) pg_realloc(dependencies,
   19542             :                                                  nDeps * sizeof(DumpId));
   19543        5330 :             te->dependencies = dependencies;
   19544        5330 :             te->nDeps = nDeps;
   19545             :         }
   19546             :         else
   19547        1656 :             free(dependencies);
   19548             :     }
   19549          96 : }
   19550             : 
   19551             : /* Recursive search subroutine for BuildArchiveDependencies */
   19552             : static void
   19553       17104 : findDumpableDependencies(ArchiveHandle *AH, const DumpableObject *dobj,
   19554             :                          DumpId **dependencies, int *nDeps, int *allocDeps)
   19555             : {
   19556             :     int         i;
   19557             : 
   19558             :     /*
   19559             :      * Ignore section boundary objects: if we search through them, we'll
   19560             :      * report lots of bogus dependencies.
   19561             :      */
   19562       17104 :     if (dobj->objType == DO_PRE_DATA_BOUNDARY ||
   19563       17066 :         dobj->objType == DO_POST_DATA_BOUNDARY)
   19564        2992 :         return;
   19565             : 
   19566       35574 :     for (i = 0; i < dobj->nDeps; i++)
   19567             :     {
   19568       21462 :         DumpId      depid = dobj->dependencies[i];
   19569             : 
   19570       21462 :         if (TocIDRequired(AH, depid) != 0)
   19571             :         {
   19572             :             /* Object will be dumped, so just reference it as a dependency */
   19573       11344 :             if (*nDeps >= *allocDeps)
   19574             :             {
   19575           0 :                 *allocDeps *= 2;
   19576           0 :                 *dependencies = (DumpId *) pg_realloc(*dependencies,
   19577           0 :                                                       *allocDeps * sizeof(DumpId));
   19578             :             }
   19579       11344 :             (*dependencies)[*nDeps] = depid;
   19580       11344 :             (*nDeps)++;
   19581             :         }
   19582             :         else
   19583             :         {
   19584             :             /*
   19585             :              * Object will not be dumped, so recursively consider its deps. We
   19586             :              * rely on the assumption that sortDumpableObjects already broke
   19587             :              * any dependency loops, else we might recurse infinitely.
   19588             :              */
   19589       10118 :             DumpableObject *otherdobj = findObjectByDumpId(depid);
   19590             : 
   19591       10118 :             if (otherdobj)
   19592       10118 :                 findDumpableDependencies(AH, otherdobj,
   19593             :                                          dependencies, nDeps, allocDeps);
   19594             :         }
   19595             :     }
   19596             : }
   19597             : 
   19598             : 
   19599             : /*
   19600             :  * getFormattedTypeName - retrieve a nicely-formatted type name for the
   19601             :  * given type OID.
   19602             :  *
   19603             :  * This does not guarantee to schema-qualify the output, so it should not
   19604             :  * be used to create the target object name for CREATE or ALTER commands.
   19605             :  *
   19606             :  * Note that the result is cached and must not be freed by the caller.
   19607             :  */
   19608             : static const char *
   19609        4696 : getFormattedTypeName(Archive *fout, Oid oid, OidOptions opts)
   19610             : {
   19611             :     TypeInfo   *typeInfo;
   19612             :     char       *result;
   19613             :     PQExpBuffer query;
   19614             :     PGresult   *res;
   19615             : 
   19616        4696 :     if (oid == 0)
   19617             :     {
   19618           0 :         if ((opts & zeroAsStar) != 0)
   19619           0 :             return "*";
   19620           0 :         else if ((opts & zeroAsNone) != 0)
   19621           0 :             return "NONE";
   19622             :     }
   19623             : 
   19624             :     /* see if we have the result cached in the type's TypeInfo record */
   19625        4696 :     typeInfo = findTypeByOid(oid);
   19626        4696 :     if (typeInfo && typeInfo->ftypname)
   19627        3706 :         return typeInfo->ftypname;
   19628             : 
   19629         990 :     query = createPQExpBuffer();
   19630         990 :     appendPQExpBuffer(query, "SELECT pg_catalog.format_type('%u'::pg_catalog.oid, NULL)",
   19631             :                       oid);
   19632             : 
   19633         990 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   19634             : 
   19635             :     /* result of format_type is already quoted */
   19636         990 :     result = pg_strdup(PQgetvalue(res, 0, 0));
   19637             : 
   19638         990 :     PQclear(res);
   19639         990 :     destroyPQExpBuffer(query);
   19640             : 
   19641             :     /*
   19642             :      * Cache the result for re-use in later requests, if possible.  If we
   19643             :      * don't have a TypeInfo for the type, the string will be leaked once the
   19644             :      * caller is done with it ... but that case really should not happen, so
   19645             :      * leaking if it does seems acceptable.
   19646             :      */
   19647         990 :     if (typeInfo)
   19648         990 :         typeInfo->ftypname = result;
   19649             : 
   19650         990 :     return result;
   19651             : }
   19652             : 
   19653             : /*
   19654             :  * Return a column list clause for the given relation.
   19655             :  *
   19656             :  * Special case: if there are no undropped columns in the relation, return
   19657             :  * "", not an invalid "()" column list.
   19658             :  */
   19659             : static const char *
   19660       15404 : fmtCopyColumnList(const TableInfo *ti, PQExpBuffer buffer)
   19661             : {
   19662       15404 :     int         numatts = ti->numatts;
   19663       15404 :     char      **attnames = ti->attnames;
   19664       15404 :     bool       *attisdropped = ti->attisdropped;
   19665       15404 :     char       *attgenerated = ti->attgenerated;
   19666             :     bool        needComma;
   19667             :     int         i;
   19668             : 
   19669       15404 :     appendPQExpBufferChar(buffer, '(');
   19670       15404 :     needComma = false;
   19671       77124 :     for (i = 0; i < numatts; i++)
   19672             :     {
   19673       61720 :         if (attisdropped[i])
   19674        1208 :             continue;
   19675       60512 :         if (attgenerated[i])
   19676        2272 :             continue;
   19677       58240 :         if (needComma)
   19678       43320 :             appendPQExpBufferStr(buffer, ", ");
   19679       58240 :         appendPQExpBufferStr(buffer, fmtId(attnames[i]));
   19680       58240 :         needComma = true;
   19681             :     }
   19682             : 
   19683       15404 :     if (!needComma)
   19684         484 :         return "";                /* no undropped columns */
   19685             : 
   19686       14920 :     appendPQExpBufferChar(buffer, ')');
   19687       14920 :     return buffer->data;
   19688             : }
   19689             : 
   19690             : /*
   19691             :  * Check if a reloptions array is nonempty.
   19692             :  */
   19693             : static bool
   19694       26338 : nonemptyReloptions(const char *reloptions)
   19695             : {
   19696             :     /* Don't want to print it if it's just "{}" */
   19697       26338 :     return (reloptions != NULL && strlen(reloptions) > 2);
   19698             : }
   19699             : 
   19700             : /*
   19701             :  * Format a reloptions array and append it to the given buffer.
   19702             :  *
   19703             :  * "prefix" is prepended to the option names; typically it's "" or "toast.".
   19704             :  */
   19705             : static void
   19706         432 : appendReloptionsArrayAH(PQExpBuffer buffer, const char *reloptions,
   19707             :                         const char *prefix, Archive *fout)
   19708             : {
   19709             :     bool        res;
   19710             : 
   19711         432 :     res = appendReloptionsArray(buffer, reloptions, prefix, fout->encoding,
   19712         432 :                                 fout->std_strings);
   19713         432 :     if (!res)
   19714           0 :         pg_log_warning("could not parse %s array", "reloptions");
   19715         432 : }
   19716             : 
   19717             : /*
   19718             :  * read_dump_filters - retrieve object identifier patterns from file
   19719             :  *
   19720             :  * Parse the specified filter file for include and exclude patterns, and add
   19721             :  * them to the relevant lists.  If the filename is "-" then filters will be
   19722             :  * read from STDIN rather than a file.
   19723             :  */
   19724             : static void
   19725          52 : read_dump_filters(const char *filename, DumpOptions *dopt)
   19726             : {
   19727             :     FilterStateData fstate;
   19728             :     char       *objname;
   19729             :     FilterCommandType comtype;
   19730             :     FilterObjectType objtype;
   19731             : 
   19732          52 :     filter_init(&fstate, filename, exit_nicely);
   19733             : 
   19734         116 :     while (filter_read_item(&fstate, &objname, &comtype, &objtype))
   19735             :     {
   19736          66 :         if (comtype == FILTER_COMMAND_TYPE_INCLUDE)
   19737             :         {
   19738          34 :             switch (objtype)
   19739             :             {
   19740           0 :                 case FILTER_OBJECT_TYPE_NONE:
   19741           0 :                     break;
   19742           0 :                 case FILTER_OBJECT_TYPE_DATABASE:
   19743             :                 case FILTER_OBJECT_TYPE_FUNCTION:
   19744             :                 case FILTER_OBJECT_TYPE_INDEX:
   19745             :                 case FILTER_OBJECT_TYPE_TABLE_DATA:
   19746             :                 case FILTER_OBJECT_TYPE_TABLE_DATA_AND_CHILDREN:
   19747             :                 case FILTER_OBJECT_TYPE_TRIGGER:
   19748           0 :                     pg_log_filter_error(&fstate, _("%s filter for \"%s\" is not allowed"),
   19749             :                                         "include",
   19750             :                                         filter_object_type_name(objtype));
   19751           0 :                     exit_nicely(1);
   19752             :                     break;      /* unreachable */
   19753             : 
   19754           2 :                 case FILTER_OBJECT_TYPE_EXTENSION:
   19755           2 :                     simple_string_list_append(&extension_include_patterns, objname);
   19756           2 :                     break;
   19757           2 :                 case FILTER_OBJECT_TYPE_FOREIGN_DATA:
   19758           2 :                     simple_string_list_append(&foreign_servers_include_patterns, objname);
   19759           2 :                     break;
   19760           2 :                 case FILTER_OBJECT_TYPE_SCHEMA:
   19761           2 :                     simple_string_list_append(&schema_include_patterns, objname);
   19762           2 :                     dopt->include_everything = false;
   19763           2 :                     break;
   19764          26 :                 case FILTER_OBJECT_TYPE_TABLE:
   19765          26 :                     simple_string_list_append(&table_include_patterns, objname);
   19766          26 :                     dopt->include_everything = false;
   19767          26 :                     break;
   19768           2 :                 case FILTER_OBJECT_TYPE_TABLE_AND_CHILDREN:
   19769           2 :                     simple_string_list_append(&table_include_patterns_and_children,
   19770             :                                               objname);
   19771           2 :                     dopt->include_everything = false;
   19772           2 :                     break;
   19773             :             }
   19774          34 :         }
   19775          32 :         else if (comtype == FILTER_COMMAND_TYPE_EXCLUDE)
   19776             :         {
   19777          18 :             switch (objtype)
   19778             :             {
   19779           0 :                 case FILTER_OBJECT_TYPE_NONE:
   19780           0 :                     break;
   19781           2 :                 case FILTER_OBJECT_TYPE_DATABASE:
   19782             :                 case FILTER_OBJECT_TYPE_FUNCTION:
   19783             :                 case FILTER_OBJECT_TYPE_INDEX:
   19784             :                 case FILTER_OBJECT_TYPE_TRIGGER:
   19785             :                 case FILTER_OBJECT_TYPE_FOREIGN_DATA:
   19786           2 :                     pg_log_filter_error(&fstate, _("%s filter for \"%s\" is not allowed"),
   19787             :                                         "exclude",
   19788             :                                         filter_object_type_name(objtype));
   19789           2 :                     exit_nicely(1);
   19790             :                     break;
   19791             : 
   19792           2 :                 case FILTER_OBJECT_TYPE_EXTENSION:
   19793           2 :                     simple_string_list_append(&extension_exclude_patterns, objname);
   19794           2 :                     break;
   19795           2 :                 case FILTER_OBJECT_TYPE_TABLE_DATA:
   19796           2 :                     simple_string_list_append(&tabledata_exclude_patterns,
   19797             :                                               objname);
   19798           2 :                     break;
   19799           2 :                 case FILTER_OBJECT_TYPE_TABLE_DATA_AND_CHILDREN:
   19800           2 :                     simple_string_list_append(&tabledata_exclude_patterns_and_children,
   19801             :                                               objname);
   19802           2 :                     break;
   19803           4 :                 case FILTER_OBJECT_TYPE_SCHEMA:
   19804           4 :                     simple_string_list_append(&schema_exclude_patterns, objname);
   19805           4 :                     break;
   19806           4 :                 case FILTER_OBJECT_TYPE_TABLE:
   19807           4 :                     simple_string_list_append(&table_exclude_patterns, objname);
   19808           4 :                     break;
   19809           2 :                 case FILTER_OBJECT_TYPE_TABLE_AND_CHILDREN:
   19810           2 :                     simple_string_list_append(&table_exclude_patterns_and_children,
   19811             :                                               objname);
   19812           2 :                     break;
   19813             :             }
   19814          16 :         }
   19815             :         else
   19816             :         {
   19817             :             Assert(comtype == FILTER_COMMAND_TYPE_NONE);
   19818             :             Assert(objtype == FILTER_OBJECT_TYPE_NONE);
   19819             :         }
   19820             : 
   19821          64 :         if (objname)
   19822          50 :             free(objname);
   19823             :     }
   19824             : 
   19825          44 :     filter_free(&fstate);
   19826          44 : }

Generated by: LCOV version 1.14