LCOV - code coverage report
Current view: top level - src/bin/pg_dump - pg_dump.c (source / functions) Hit Total Coverage
Test: PostgreSQL 18devel Lines: 6904 7656 90.2 %
Date: 2025-01-18 04:15:08 Functions: 179 183 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_subscription_d.h"
      54             : #include "catalog/pg_type_d.h"
      55             : #include "common/connect.h"
      56             : #include "common/int.h"
      57             : #include "common/relpath.h"
      58             : #include "compress_io.h"
      59             : #include "dumputils.h"
      60             : #include "fe_utils/option_utils.h"
      61             : #include "fe_utils/string_utils.h"
      62             : #include "filter.h"
      63             : #include "getopt_long.h"
      64             : #include "libpq/libpq-fs.h"
      65             : #include "parallel.h"
      66             : #include "pg_backup_db.h"
      67             : #include "pg_backup_utils.h"
      68             : #include "pg_dump.h"
      69             : #include "storage/block.h"
      70             : 
      71             : typedef struct
      72             : {
      73             :     Oid         roleoid;        /* role's OID */
      74             :     const char *rolename;       /* role's name */
      75             : } RoleNameItem;
      76             : 
      77             : typedef struct
      78             : {
      79             :     const char *descr;          /* comment for an object */
      80             :     Oid         classoid;       /* object class (catalog OID) */
      81             :     Oid         objoid;         /* object OID */
      82             :     int         objsubid;       /* subobject (table column #) */
      83             : } CommentItem;
      84             : 
      85             : typedef struct
      86             : {
      87             :     const char *provider;       /* label provider of this security label */
      88             :     const char *label;          /* security label for an object */
      89             :     Oid         classoid;       /* object class (catalog OID) */
      90             :     Oid         objoid;         /* object OID */
      91             :     int         objsubid;       /* subobject (table column #) */
      92             : } SecLabelItem;
      93             : 
      94             : typedef struct
      95             : {
      96             :     Oid         oid;            /* object OID */
      97             :     char        relkind;        /* object kind */
      98             :     RelFileNumber relfilenumber;    /* object filenode */
      99             :     Oid         toast_oid;      /* toast table OID */
     100             :     RelFileNumber toast_relfilenumber;  /* toast table filenode */
     101             :     Oid         toast_index_oid;    /* toast table index OID */
     102             :     RelFileNumber toast_index_relfilenumber;    /* toast table index filenode */
     103             : } BinaryUpgradeClassOidItem;
     104             : 
     105             : /* sequence types */
     106             : typedef enum SeqType
     107             : {
     108             :     SEQTYPE_SMALLINT,
     109             :     SEQTYPE_INTEGER,
     110             :     SEQTYPE_BIGINT,
     111             : } SeqType;
     112             : 
     113             : static const char *const SeqTypeNames[] =
     114             : {
     115             :     [SEQTYPE_SMALLINT] = "smallint",
     116             :     [SEQTYPE_INTEGER] = "integer",
     117             :     [SEQTYPE_BIGINT] = "bigint",
     118             : };
     119             : 
     120             : StaticAssertDecl(lengthof(SeqTypeNames) == (SEQTYPE_BIGINT + 1),
     121             :                  "array length mismatch");
     122             : 
     123             : typedef struct
     124             : {
     125             :     Oid         oid;            /* sequence OID */
     126             :     SeqType     seqtype;        /* data type of sequence */
     127             :     bool        cycled;         /* whether sequence cycles */
     128             :     int64       minv;           /* minimum value */
     129             :     int64       maxv;           /* maximum value */
     130             :     int64       startv;         /* start value */
     131             :     int64       incby;          /* increment value */
     132             :     int64       cache;          /* cache size */
     133             :     int64       last_value;     /* last value of sequence */
     134             :     bool        is_called;      /* whether nextval advances before returning */
     135             : } SequenceItem;
     136             : 
     137             : typedef enum OidOptions
     138             : {
     139             :     zeroIsError = 1,
     140             :     zeroAsStar = 2,
     141             :     zeroAsNone = 4,
     142             : } OidOptions;
     143             : 
     144             : /* global decls */
     145             : static bool dosync = true;      /* Issue fsync() to make dump durable on disk. */
     146             : 
     147             : static Oid  g_last_builtin_oid; /* value of the last builtin oid */
     148             : 
     149             : /* The specified names/patterns should to match at least one entity */
     150             : static int  strict_names = 0;
     151             : 
     152             : static pg_compress_algorithm compression_algorithm = PG_COMPRESSION_NONE;
     153             : 
     154             : /*
     155             :  * Object inclusion/exclusion lists
     156             :  *
     157             :  * The string lists record the patterns given by command-line switches,
     158             :  * which we then convert to lists of OIDs of matching objects.
     159             :  */
     160             : static SimpleStringList schema_include_patterns = {NULL, NULL};
     161             : static SimpleOidList schema_include_oids = {NULL, NULL};
     162             : static SimpleStringList schema_exclude_patterns = {NULL, NULL};
     163             : static SimpleOidList schema_exclude_oids = {NULL, NULL};
     164             : 
     165             : static SimpleStringList table_include_patterns = {NULL, NULL};
     166             : static SimpleStringList table_include_patterns_and_children = {NULL, NULL};
     167             : static SimpleOidList table_include_oids = {NULL, NULL};
     168             : static SimpleStringList table_exclude_patterns = {NULL, NULL};
     169             : static SimpleStringList table_exclude_patterns_and_children = {NULL, NULL};
     170             : static SimpleOidList table_exclude_oids = {NULL, NULL};
     171             : static SimpleStringList tabledata_exclude_patterns = {NULL, NULL};
     172             : static SimpleStringList tabledata_exclude_patterns_and_children = {NULL, NULL};
     173             : static SimpleOidList tabledata_exclude_oids = {NULL, NULL};
     174             : 
     175             : static SimpleStringList foreign_servers_include_patterns = {NULL, NULL};
     176             : static SimpleOidList foreign_servers_include_oids = {NULL, NULL};
     177             : 
     178             : static SimpleStringList extension_include_patterns = {NULL, NULL};
     179             : static SimpleOidList extension_include_oids = {NULL, NULL};
     180             : 
     181             : static SimpleStringList extension_exclude_patterns = {NULL, NULL};
     182             : static SimpleOidList extension_exclude_oids = {NULL, NULL};
     183             : 
     184             : static const CatalogId nilCatalogId = {0, 0};
     185             : 
     186             : /* override for standard extra_float_digits setting */
     187             : static bool have_extra_float_digits = false;
     188             : static int  extra_float_digits;
     189             : 
     190             : /* sorted table of role names */
     191             : static RoleNameItem *rolenames = NULL;
     192             : static int  nrolenames = 0;
     193             : 
     194             : /* sorted table of comments */
     195             : static CommentItem *comments = NULL;
     196             : static int  ncomments = 0;
     197             : 
     198             : /* sorted table of security labels */
     199             : static SecLabelItem *seclabels = NULL;
     200             : static int  nseclabels = 0;
     201             : 
     202             : /* sorted table of pg_class information for binary upgrade */
     203             : static BinaryUpgradeClassOidItem *binaryUpgradeClassOids = NULL;
     204             : static int  nbinaryUpgradeClassOids = 0;
     205             : 
     206             : /* sorted table of sequences */
     207             : static SequenceItem *sequences = NULL;
     208             : static int  nsequences = 0;
     209             : 
     210             : /*
     211             :  * The default number of rows per INSERT when
     212             :  * --inserts is specified without --rows-per-insert
     213             :  */
     214             : #define DUMP_DEFAULT_ROWS_PER_INSERT 1
     215             : 
     216             : /*
     217             :  * Maximum number of large objects to group into a single ArchiveEntry.
     218             :  * At some point we might want to make this user-controllable, but for now
     219             :  * a hard-wired setting will suffice.
     220             :  */
     221             : #define MAX_BLOBS_PER_ARCHIVE_ENTRY 1000
     222             : 
     223             : /*
     224             :  * Macro for producing quoted, schema-qualified name of a dumpable object.
     225             :  */
     226             : #define fmtQualifiedDumpable(obj) \
     227             :     fmtQualifiedId((obj)->dobj.namespace->dobj.name, \
     228             :                    (obj)->dobj.name)
     229             : 
     230             : static void help(const char *progname);
     231             : static void setup_connection(Archive *AH,
     232             :                              const char *dumpencoding, const char *dumpsnapshot,
     233             :                              char *use_role);
     234             : static ArchiveFormat parseArchiveFormat(const char *format, ArchiveMode *mode);
     235             : static void expand_schema_name_patterns(Archive *fout,
     236             :                                         SimpleStringList *patterns,
     237             :                                         SimpleOidList *oids,
     238             :                                         bool strict_names);
     239             : static void expand_extension_name_patterns(Archive *fout,
     240             :                                            SimpleStringList *patterns,
     241             :                                            SimpleOidList *oids,
     242             :                                            bool strict_names);
     243             : static void expand_foreign_server_name_patterns(Archive *fout,
     244             :                                                 SimpleStringList *patterns,
     245             :                                                 SimpleOidList *oids);
     246             : static void expand_table_name_patterns(Archive *fout,
     247             :                                        SimpleStringList *patterns,
     248             :                                        SimpleOidList *oids,
     249             :                                        bool strict_names,
     250             :                                        bool with_child_tables);
     251             : static void prohibit_crossdb_refs(PGconn *conn, const char *dbname,
     252             :                                   const char *pattern);
     253             : 
     254             : static NamespaceInfo *findNamespace(Oid nsoid);
     255             : static void dumpTableData(Archive *fout, const TableDataInfo *tdinfo);
     256             : static void refreshMatViewData(Archive *fout, const TableDataInfo *tdinfo);
     257             : static const char *getRoleName(const char *roleoid_str);
     258             : static void collectRoleNames(Archive *fout);
     259             : static void getAdditionalACLs(Archive *fout);
     260             : static void dumpCommentExtended(Archive *fout, const char *type,
     261             :                                 const char *name, const char *namespace,
     262             :                                 const char *owner, CatalogId catalogId,
     263             :                                 int subid, DumpId dumpId,
     264             :                                 const char *initdb_comment);
     265             : static inline void dumpComment(Archive *fout, const char *type,
     266             :                                const char *name, const char *namespace,
     267             :                                const char *owner, CatalogId catalogId,
     268             :                                int subid, DumpId dumpId);
     269             : static int  findComments(Oid classoid, Oid objoid, CommentItem **items);
     270             : static void collectComments(Archive *fout);
     271             : static void dumpSecLabel(Archive *fout, const char *type, const char *name,
     272             :                          const char *namespace, const char *owner,
     273             :                          CatalogId catalogId, int subid, DumpId dumpId);
     274             : static int  findSecLabels(Oid classoid, Oid objoid, SecLabelItem **items);
     275             : static void collectSecLabels(Archive *fout);
     276             : static void dumpDumpableObject(Archive *fout, DumpableObject *dobj);
     277             : static void dumpNamespace(Archive *fout, const NamespaceInfo *nspinfo);
     278             : static void dumpExtension(Archive *fout, const ExtensionInfo *extinfo);
     279             : static void dumpType(Archive *fout, const TypeInfo *tyinfo);
     280             : static void dumpBaseType(Archive *fout, const TypeInfo *tyinfo);
     281             : static void dumpEnumType(Archive *fout, const TypeInfo *tyinfo);
     282             : static void dumpRangeType(Archive *fout, const TypeInfo *tyinfo);
     283             : static void dumpUndefinedType(Archive *fout, const TypeInfo *tyinfo);
     284             : static void dumpDomain(Archive *fout, const TypeInfo *tyinfo);
     285             : static void dumpCompositeType(Archive *fout, const TypeInfo *tyinfo);
     286             : static void dumpCompositeTypeColComments(Archive *fout, const TypeInfo *tyinfo,
     287             :                                          PGresult *res);
     288             : static void dumpShellType(Archive *fout, const ShellTypeInfo *stinfo);
     289             : static void dumpProcLang(Archive *fout, const ProcLangInfo *plang);
     290             : static void dumpFunc(Archive *fout, const FuncInfo *finfo);
     291             : static void dumpCast(Archive *fout, const CastInfo *cast);
     292             : static void dumpTransform(Archive *fout, const TransformInfo *transform);
     293             : static void dumpOpr(Archive *fout, const OprInfo *oprinfo);
     294             : static void dumpAccessMethod(Archive *fout, const AccessMethodInfo *aminfo);
     295             : static void dumpOpclass(Archive *fout, const OpclassInfo *opcinfo);
     296             : static void dumpOpfamily(Archive *fout, const OpfamilyInfo *opfinfo);
     297             : static void dumpCollation(Archive *fout, const CollInfo *collinfo);
     298             : static void dumpConversion(Archive *fout, const ConvInfo *convinfo);
     299             : static void dumpRule(Archive *fout, const RuleInfo *rinfo);
     300             : static void dumpAgg(Archive *fout, const AggInfo *agginfo);
     301             : static void dumpTrigger(Archive *fout, const TriggerInfo *tginfo);
     302             : static void dumpEventTrigger(Archive *fout, const EventTriggerInfo *evtinfo);
     303             : static void dumpTable(Archive *fout, const TableInfo *tbinfo);
     304             : static void dumpTableSchema(Archive *fout, const TableInfo *tbinfo);
     305             : static void dumpTableAttach(Archive *fout, const TableAttachInfo *attachinfo);
     306             : static void dumpAttrDef(Archive *fout, const AttrDefInfo *adinfo);
     307             : static void collectSequences(Archive *fout);
     308             : static void dumpSequence(Archive *fout, const TableInfo *tbinfo);
     309             : static void dumpSequenceData(Archive *fout, const TableDataInfo *tdinfo);
     310             : static void dumpIndex(Archive *fout, const IndxInfo *indxinfo);
     311             : static void dumpIndexAttach(Archive *fout, const IndexAttachInfo *attachinfo);
     312             : static void dumpStatisticsExt(Archive *fout, const StatsExtInfo *statsextinfo);
     313             : static void dumpConstraint(Archive *fout, const ConstraintInfo *coninfo);
     314             : static void dumpTableConstraintComment(Archive *fout, const ConstraintInfo *coninfo);
     315             : static void dumpTSParser(Archive *fout, const TSParserInfo *prsinfo);
     316             : static void dumpTSDictionary(Archive *fout, const TSDictInfo *dictinfo);
     317             : static void dumpTSTemplate(Archive *fout, const TSTemplateInfo *tmplinfo);
     318             : static void dumpTSConfig(Archive *fout, const TSConfigInfo *cfginfo);
     319             : static void dumpForeignDataWrapper(Archive *fout, const FdwInfo *fdwinfo);
     320             : static void dumpForeignServer(Archive *fout, const ForeignServerInfo *srvinfo);
     321             : static void dumpUserMappings(Archive *fout,
     322             :                              const char *servername, const char *namespace,
     323             :                              const char *owner, CatalogId catalogId, DumpId dumpId);
     324             : static void dumpDefaultACL(Archive *fout, const DefaultACLInfo *daclinfo);
     325             : 
     326             : static DumpId dumpACL(Archive *fout, DumpId objDumpId, DumpId altDumpId,
     327             :                       const char *type, const char *name, const char *subname,
     328             :                       const char *nspname, const char *tag, const char *owner,
     329             :                       const DumpableAcl *dacl);
     330             : 
     331             : static void getDependencies(Archive *fout);
     332             : static void BuildArchiveDependencies(Archive *fout);
     333             : static void findDumpableDependencies(ArchiveHandle *AH, const DumpableObject *dobj,
     334             :                                      DumpId **dependencies, int *nDeps, int *allocDeps);
     335             : 
     336             : static DumpableObject *createBoundaryObjects(void);
     337             : static void addBoundaryDependencies(DumpableObject **dobjs, int numObjs,
     338             :                                     DumpableObject *boundaryObjs);
     339             : 
     340             : static void addConstrChildIdxDeps(DumpableObject *dobj, const IndxInfo *refidx);
     341             : static void getDomainConstraints(Archive *fout, TypeInfo *tyinfo);
     342             : static void getTableData(DumpOptions *dopt, TableInfo *tblinfo, int numTables, char relkind);
     343             : static void makeTableDataInfo(DumpOptions *dopt, TableInfo *tbinfo);
     344             : static void buildMatViewRefreshDependencies(Archive *fout);
     345             : static void getTableDataFKConstraints(void);
     346             : static void determineNotNullFlags(Archive *fout, PGresult *res, int r,
     347             :                                   TableInfo *tbinfo, int j,
     348             :                                   int i_notnull_name, int i_notnull_noinherit,
     349             :                                   int i_notnull_islocal);
     350             : static char *format_function_arguments(const FuncInfo *finfo, const char *funcargs,
     351             :                                        bool is_agg);
     352             : static char *format_function_signature(Archive *fout,
     353             :                                        const FuncInfo *finfo, bool honor_quotes);
     354             : static char *convertRegProcReference(const char *proc);
     355             : static char *getFormattedOperatorName(const char *oproid);
     356             : static char *convertTSFunction(Archive *fout, Oid funcOid);
     357             : static const char *getFormattedTypeName(Archive *fout, Oid oid, OidOptions opts);
     358             : static void getLOs(Archive *fout);
     359             : static void dumpLO(Archive *fout, const LoInfo *loinfo);
     360             : static int  dumpLOs(Archive *fout, const void *arg);
     361             : static void dumpPolicy(Archive *fout, const PolicyInfo *polinfo);
     362             : static void dumpPublication(Archive *fout, const PublicationInfo *pubinfo);
     363             : static void dumpPublicationTable(Archive *fout, const PublicationRelInfo *pubrinfo);
     364             : static void dumpSubscription(Archive *fout, const SubscriptionInfo *subinfo);
     365             : static void dumpSubscriptionTable(Archive *fout, const SubRelInfo *subrinfo);
     366             : static void dumpDatabase(Archive *fout);
     367             : static void dumpDatabaseConfig(Archive *AH, PQExpBuffer outbuf,
     368             :                                const char *dbname, Oid dboid);
     369             : static void dumpEncoding(Archive *AH);
     370             : static void dumpStdStrings(Archive *AH);
     371             : static void dumpSearchPath(Archive *AH);
     372             : static void binary_upgrade_set_type_oids_by_type_oid(Archive *fout,
     373             :                                                      PQExpBuffer upgrade_buffer,
     374             :                                                      Oid pg_type_oid,
     375             :                                                      bool force_array_type,
     376             :                                                      bool include_multirange_type);
     377             : static void binary_upgrade_set_type_oids_by_rel(Archive *fout,
     378             :                                                 PQExpBuffer upgrade_buffer,
     379             :                                                 const TableInfo *tbinfo);
     380             : static void collectBinaryUpgradeClassOids(Archive *fout);
     381             : static void binary_upgrade_set_pg_class_oids(Archive *fout,
     382             :                                              PQExpBuffer upgrade_buffer,
     383             :                                              Oid pg_class_oid);
     384             : static void binary_upgrade_extension_member(PQExpBuffer upgrade_buffer,
     385             :                                             const DumpableObject *dobj,
     386             :                                             const char *objtype,
     387             :                                             const char *objname,
     388             :                                             const char *objnamespace);
     389             : static const char *getAttrName(int attrnum, const TableInfo *tblInfo);
     390             : static const char *fmtCopyColumnList(const TableInfo *ti, PQExpBuffer buffer);
     391             : static bool nonemptyReloptions(const char *reloptions);
     392             : static void appendReloptionsArrayAH(PQExpBuffer buffer, const char *reloptions,
     393             :                                     const char *prefix, Archive *fout);
     394             : static char *get_synchronized_snapshot(Archive *fout);
     395             : static void set_restrict_relation_kind(Archive *AH, const char *value);
     396             : static void setupDumpWorker(Archive *AH);
     397             : static TableInfo *getRootTableInfo(const TableInfo *tbinfo);
     398             : static bool forcePartitionRootLoad(const TableInfo *tbinfo);
     399             : static void read_dump_filters(const char *filename, DumpOptions *dopt);
     400             : 
     401             : 
     402             : int
     403         486 : main(int argc, char **argv)
     404             : {
     405             :     int         c;
     406         486 :     const char *filename = NULL;
     407         486 :     const char *format = "p";
     408             :     TableInfo  *tblinfo;
     409             :     int         numTables;
     410             :     DumpableObject **dobjs;
     411             :     int         numObjs;
     412             :     DumpableObject *boundaryObjs;
     413             :     int         i;
     414             :     int         optindex;
     415             :     RestoreOptions *ropt;
     416             :     Archive    *fout;           /* the script file */
     417         486 :     bool        g_verbose = false;
     418         486 :     const char *dumpencoding = NULL;
     419         486 :     const char *dumpsnapshot = NULL;
     420         486 :     char       *use_role = NULL;
     421         486 :     int         numWorkers = 1;
     422         486 :     int         plainText = 0;
     423         486 :     ArchiveFormat archiveFormat = archUnknown;
     424             :     ArchiveMode archiveMode;
     425         486 :     pg_compress_specification compression_spec = {0};
     426         486 :     char       *compression_detail = NULL;
     427         486 :     char       *compression_algorithm_str = "none";
     428         486 :     char       *error_detail = NULL;
     429         486 :     bool        user_compression_defined = false;
     430         486 :     DataDirSyncMethod sync_method = DATA_DIR_SYNC_METHOD_FSYNC;
     431         486 :     bool        data_only = false;
     432         486 :     bool        schema_only = false;
     433             : 
     434             :     static DumpOptions dopt;
     435             : 
     436             :     static struct option long_options[] = {
     437             :         {"data-only", no_argument, NULL, 'a'},
     438             :         {"blobs", no_argument, NULL, 'b'},
     439             :         {"large-objects", no_argument, NULL, 'b'},
     440             :         {"no-blobs", no_argument, NULL, 'B'},
     441             :         {"no-large-objects", no_argument, NULL, 'B'},
     442             :         {"clean", no_argument, NULL, 'c'},
     443             :         {"create", no_argument, NULL, 'C'},
     444             :         {"dbname", required_argument, NULL, 'd'},
     445             :         {"extension", required_argument, NULL, 'e'},
     446             :         {"file", required_argument, NULL, 'f'},
     447             :         {"format", required_argument, NULL, 'F'},
     448             :         {"host", required_argument, NULL, 'h'},
     449             :         {"jobs", 1, NULL, 'j'},
     450             :         {"no-reconnect", no_argument, NULL, 'R'},
     451             :         {"no-owner", no_argument, NULL, 'O'},
     452             :         {"port", required_argument, NULL, 'p'},
     453             :         {"schema", required_argument, NULL, 'n'},
     454             :         {"exclude-schema", required_argument, NULL, 'N'},
     455             :         {"schema-only", no_argument, NULL, 's'},
     456             :         {"superuser", required_argument, NULL, 'S'},
     457             :         {"table", required_argument, NULL, 't'},
     458             :         {"exclude-table", required_argument, NULL, 'T'},
     459             :         {"no-password", no_argument, NULL, 'w'},
     460             :         {"password", no_argument, NULL, 'W'},
     461             :         {"username", required_argument, NULL, 'U'},
     462             :         {"verbose", no_argument, NULL, 'v'},
     463             :         {"no-privileges", no_argument, NULL, 'x'},
     464             :         {"no-acl", no_argument, NULL, 'x'},
     465             :         {"compress", required_argument, NULL, 'Z'},
     466             :         {"encoding", required_argument, NULL, 'E'},
     467             :         {"help", no_argument, NULL, '?'},
     468             :         {"version", no_argument, NULL, 'V'},
     469             : 
     470             :         /*
     471             :          * the following options don't have an equivalent short option letter
     472             :          */
     473             :         {"attribute-inserts", no_argument, &dopt.column_inserts, 1},
     474             :         {"binary-upgrade", no_argument, &dopt.binary_upgrade, 1},
     475             :         {"column-inserts", no_argument, &dopt.column_inserts, 1},
     476             :         {"disable-dollar-quoting", no_argument, &dopt.disable_dollar_quoting, 1},
     477             :         {"disable-triggers", no_argument, &dopt.disable_triggers, 1},
     478             :         {"enable-row-security", no_argument, &dopt.enable_row_security, 1},
     479             :         {"exclude-table-data", required_argument, NULL, 4},
     480             :         {"extra-float-digits", required_argument, NULL, 8},
     481             :         {"if-exists", no_argument, &dopt.if_exists, 1},
     482             :         {"inserts", no_argument, NULL, 9},
     483             :         {"lock-wait-timeout", required_argument, NULL, 2},
     484             :         {"no-table-access-method", no_argument, &dopt.outputNoTableAm, 1},
     485             :         {"no-tablespaces", no_argument, &dopt.outputNoTablespaces, 1},
     486             :         {"quote-all-identifiers", no_argument, &quote_all_identifiers, 1},
     487             :         {"load-via-partition-root", no_argument, &dopt.load_via_partition_root, 1},
     488             :         {"role", required_argument, NULL, 3},
     489             :         {"section", required_argument, NULL, 5},
     490             :         {"serializable-deferrable", no_argument, &dopt.serializable_deferrable, 1},
     491             :         {"snapshot", required_argument, NULL, 6},
     492             :         {"strict-names", no_argument, &strict_names, 1},
     493             :         {"use-set-session-authorization", no_argument, &dopt.use_setsessauth, 1},
     494             :         {"no-comments", no_argument, &dopt.no_comments, 1},
     495             :         {"no-publications", no_argument, &dopt.no_publications, 1},
     496             :         {"no-security-labels", no_argument, &dopt.no_security_labels, 1},
     497             :         {"no-subscriptions", no_argument, &dopt.no_subscriptions, 1},
     498             :         {"no-toast-compression", no_argument, &dopt.no_toast_compression, 1},
     499             :         {"no-unlogged-table-data", no_argument, &dopt.no_unlogged_table_data, 1},
     500             :         {"no-sync", no_argument, NULL, 7},
     501             :         {"on-conflict-do-nothing", no_argument, &dopt.do_nothing, 1},
     502             :         {"rows-per-insert", required_argument, NULL, 10},
     503             :         {"include-foreign-data", required_argument, NULL, 11},
     504             :         {"table-and-children", required_argument, NULL, 12},
     505             :         {"exclude-table-and-children", required_argument, NULL, 13},
     506             :         {"exclude-table-data-and-children", required_argument, NULL, 14},
     507             :         {"sync-method", required_argument, NULL, 15},
     508             :         {"filter", required_argument, NULL, 16},
     509             :         {"exclude-extension", required_argument, NULL, 17},
     510             : 
     511             :         {NULL, 0, NULL, 0}
     512             :     };
     513             : 
     514         486 :     pg_logging_init(argv[0]);
     515         486 :     pg_logging_set_level(PG_LOG_WARNING);
     516         486 :     set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_dump"));
     517             : 
     518             :     /*
     519             :      * Initialize what we need for parallel execution, especially for thread
     520             :      * support on Windows.
     521             :      */
     522         486 :     init_parallel_dump_utils();
     523             : 
     524         486 :     progname = get_progname(argv[0]);
     525             : 
     526         486 :     if (argc > 1)
     527             :     {
     528         486 :         if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
     529             :         {
     530           2 :             help(progname);
     531           2 :             exit_nicely(0);
     532             :         }
     533         484 :         if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
     534             :         {
     535          94 :             puts("pg_dump (PostgreSQL) " PG_VERSION);
     536          94 :             exit_nicely(0);
     537             :         }
     538             :     }
     539             : 
     540         390 :     InitDumpOptions(&dopt);
     541             : 
     542        1712 :     while ((c = getopt_long(argc, argv, "abBcCd:e:E:f:F:h:j:n:N:Op:RsS:t:T:U:vwWxZ:",
     543             :                             long_options, &optindex)) != -1)
     544             :     {
     545        1338 :         switch (c)
     546             :         {
     547          16 :             case 'a':           /* Dump data only */
     548          16 :                 data_only = true;
     549          16 :                 break;
     550             : 
     551           2 :             case 'b':           /* Dump LOs */
     552           2 :                 dopt.outputLOs = true;
     553           2 :                 break;
     554             : 
     555           4 :             case 'B':           /* Don't dump LOs */
     556           4 :                 dopt.dontOutputLOs = true;
     557           4 :                 break;
     558             : 
     559          12 :             case 'c':           /* clean (i.e., drop) schema prior to create */
     560          12 :                 dopt.outputClean = 1;
     561          12 :                 break;
     562             : 
     563          58 :             case 'C':           /* Create DB */
     564          58 :                 dopt.outputCreateDB = 1;
     565          58 :                 break;
     566             : 
     567          10 :             case 'd':           /* database name */
     568          10 :                 dopt.cparams.dbname = pg_strdup(optarg);
     569          10 :                 break;
     570             : 
     571           8 :             case 'e':           /* include extension(s) */
     572           8 :                 simple_string_list_append(&extension_include_patterns, optarg);
     573           8 :                 dopt.include_everything = false;
     574           8 :                 break;
     575             : 
     576           4 :             case 'E':           /* Dump encoding */
     577           4 :                 dumpencoding = pg_strdup(optarg);
     578           4 :                 break;
     579             : 
     580         306 :             case 'f':
     581         306 :                 filename = pg_strdup(optarg);
     582         306 :                 break;
     583             : 
     584         170 :             case 'F':
     585         170 :                 format = pg_strdup(optarg);
     586         170 :                 break;
     587             : 
     588          24 :             case 'h':           /* server host */
     589          24 :                 dopt.cparams.pghost = pg_strdup(optarg);
     590          24 :                 break;
     591             : 
     592          22 :             case 'j':           /* number of dump jobs */
     593          22 :                 if (!option_parse_int(optarg, "-j/--jobs", 1,
     594             :                                       PG_MAX_JOBS,
     595             :                                       &numWorkers))
     596           2 :                     exit_nicely(1);
     597          20 :                 break;
     598             : 
     599          34 :             case 'n':           /* include schema(s) */
     600          34 :                 simple_string_list_append(&schema_include_patterns, optarg);
     601          34 :                 dopt.include_everything = false;
     602          34 :                 break;
     603             : 
     604           2 :             case 'N':           /* exclude schema(s) */
     605           2 :                 simple_string_list_append(&schema_exclude_patterns, optarg);
     606           2 :                 break;
     607             : 
     608           4 :             case 'O':           /* Don't reconnect to match owner */
     609           4 :                 dopt.outputNoOwner = 1;
     610           4 :                 break;
     611             : 
     612         100 :             case 'p':           /* server port */
     613         100 :                 dopt.cparams.pgport = pg_strdup(optarg);
     614         100 :                 break;
     615             : 
     616           4 :             case 'R':
     617             :                 /* no-op, still accepted for backwards compatibility */
     618           4 :                 break;
     619             : 
     620          36 :             case 's':           /* dump schema only */
     621          36 :                 schema_only = true;
     622          36 :                 break;
     623             : 
     624           2 :             case 'S':           /* Username for superuser in plain text output */
     625           2 :                 dopt.outputSuperuser = pg_strdup(optarg);
     626           2 :                 break;
     627             : 
     628          16 :             case 't':           /* include table(s) */
     629          16 :                 simple_string_list_append(&table_include_patterns, optarg);
     630          16 :                 dopt.include_everything = false;
     631          16 :                 break;
     632             : 
     633           8 :             case 'T':           /* exclude table(s) */
     634           8 :                 simple_string_list_append(&table_exclude_patterns, optarg);
     635           8 :                 break;
     636             : 
     637          28 :             case 'U':
     638          28 :                 dopt.cparams.username = pg_strdup(optarg);
     639          28 :                 break;
     640             : 
     641          12 :             case 'v':           /* verbose */
     642          12 :                 g_verbose = true;
     643          12 :                 pg_logging_increase_verbosity();
     644          12 :                 break;
     645             : 
     646           2 :             case 'w':
     647           2 :                 dopt.cparams.promptPassword = TRI_NO;
     648           2 :                 break;
     649             : 
     650           0 :             case 'W':
     651           0 :                 dopt.cparams.promptPassword = TRI_YES;
     652           0 :                 break;
     653             : 
     654           4 :             case 'x':           /* skip ACL dump */
     655           4 :                 dopt.aclsSkip = true;
     656           4 :                 break;
     657             : 
     658          24 :             case 'Z':           /* Compression */
     659          24 :                 parse_compress_options(optarg, &compression_algorithm_str,
     660             :                                        &compression_detail);
     661          24 :                 user_compression_defined = true;
     662          24 :                 break;
     663             : 
     664         100 :             case 0:
     665             :                 /* This covers the long options. */
     666         100 :                 break;
     667             : 
     668           4 :             case 2:             /* lock-wait-timeout */
     669           4 :                 dopt.lockWaitTimeout = pg_strdup(optarg);
     670           4 :                 break;
     671             : 
     672           6 :             case 3:             /* SET ROLE */
     673           6 :                 use_role = pg_strdup(optarg);
     674           6 :                 break;
     675             : 
     676           2 :             case 4:             /* exclude table(s) data */
     677           2 :                 simple_string_list_append(&tabledata_exclude_patterns, optarg);
     678           2 :                 break;
     679             : 
     680          12 :             case 5:             /* section */
     681          12 :                 set_dump_section(optarg, &dopt.dumpSections);
     682          12 :                 break;
     683             : 
     684           0 :             case 6:             /* snapshot */
     685           0 :                 dumpsnapshot = pg_strdup(optarg);
     686           0 :                 break;
     687             : 
     688         222 :             case 7:             /* no-sync */
     689         222 :                 dosync = false;
     690         222 :                 break;
     691             : 
     692           2 :             case 8:
     693           2 :                 have_extra_float_digits = true;
     694           2 :                 if (!option_parse_int(optarg, "--extra-float-digits", -15, 3,
     695             :                                       &extra_float_digits))
     696           2 :                     exit_nicely(1);
     697           0 :                 break;
     698             : 
     699           4 :             case 9:             /* inserts */
     700             : 
     701             :                 /*
     702             :                  * dump_inserts also stores --rows-per-insert, careful not to
     703             :                  * overwrite that.
     704             :                  */
     705           4 :                 if (dopt.dump_inserts == 0)
     706           4 :                     dopt.dump_inserts = DUMP_DEFAULT_ROWS_PER_INSERT;
     707           4 :                 break;
     708             : 
     709           4 :             case 10:            /* rows per insert */
     710           4 :                 if (!option_parse_int(optarg, "--rows-per-insert", 1, INT_MAX,
     711             :                                       &dopt.dump_inserts))
     712           2 :                     exit_nicely(1);
     713           2 :                 break;
     714             : 
     715           8 :             case 11:            /* include foreign data */
     716           8 :                 simple_string_list_append(&foreign_servers_include_patterns,
     717             :                                           optarg);
     718           8 :                 break;
     719             : 
     720           2 :             case 12:            /* include table(s) and their children */
     721           2 :                 simple_string_list_append(&table_include_patterns_and_children,
     722             :                                           optarg);
     723           2 :                 dopt.include_everything = false;
     724           2 :                 break;
     725             : 
     726           2 :             case 13:            /* exclude table(s) and their children */
     727           2 :                 simple_string_list_append(&table_exclude_patterns_and_children,
     728             :                                           optarg);
     729           2 :                 break;
     730             : 
     731           2 :             case 14:            /* exclude data of table(s) and children */
     732           2 :                 simple_string_list_append(&tabledata_exclude_patterns_and_children,
     733             :                                           optarg);
     734           2 :                 break;
     735             : 
     736           0 :             case 15:
     737           0 :                 if (!parse_sync_method(optarg, &sync_method))
     738           0 :                     exit_nicely(1);
     739           0 :                 break;
     740             : 
     741          52 :             case 16:            /* read object filters from file */
     742          52 :                 read_dump_filters(optarg, &dopt);
     743          44 :                 break;
     744             : 
     745           2 :             case 17:            /* exclude extension(s) */
     746           2 :                 simple_string_list_append(&extension_exclude_patterns,
     747             :                                           optarg);
     748           2 :                 break;
     749             : 
     750           2 :             default:
     751             :                 /* getopt_long already emitted a complaint */
     752           2 :                 pg_log_error_hint("Try \"%s --help\" for more information.", progname);
     753           2 :                 exit_nicely(1);
     754             :         }
     755             :     }
     756             : 
     757             :     /*
     758             :      * Non-option argument specifies database name as long as it wasn't
     759             :      * already specified with -d / --dbname
     760             :      */
     761         374 :     if (optind < argc && dopt.cparams.dbname == NULL)
     762         310 :         dopt.cparams.dbname = argv[optind++];
     763             : 
     764             :     /* Complain if any arguments remain */
     765         374 :     if (optind < argc)
     766             :     {
     767           2 :         pg_log_error("too many command-line arguments (first is \"%s\")",
     768             :                      argv[optind]);
     769           2 :         pg_log_error_hint("Try \"%s --help\" for more information.", progname);
     770           2 :         exit_nicely(1);
     771             :     }
     772             : 
     773             :     /* --column-inserts implies --inserts */
     774         372 :     if (dopt.column_inserts && dopt.dump_inserts == 0)
     775           2 :         dopt.dump_inserts = DUMP_DEFAULT_ROWS_PER_INSERT;
     776             : 
     777             :     /*
     778             :      * Binary upgrade mode implies dumping sequence data even in schema-only
     779             :      * mode.  This is not exposed as a separate option, but kept separate
     780             :      * internally for clarity.
     781             :      */
     782         372 :     if (dopt.binary_upgrade)
     783          28 :         dopt.sequence_data = 1;
     784             : 
     785         372 :     if (data_only && schema_only)
     786           2 :         pg_fatal("options -s/--schema-only and -a/--data-only cannot be used together");
     787             : 
     788         370 :     if (schema_only && foreign_servers_include_patterns.head != NULL)
     789           2 :         pg_fatal("options -s/--schema-only and --include-foreign-data cannot be used together");
     790             : 
     791         368 :     if (numWorkers > 1 && foreign_servers_include_patterns.head != NULL)
     792           2 :         pg_fatal("option --include-foreign-data is not supported with parallel backup");
     793             : 
     794         366 :     if (data_only && dopt.outputClean)
     795           2 :         pg_fatal("options -c/--clean and -a/--data-only cannot be used together");
     796             : 
     797         364 :     if (dopt.if_exists && !dopt.outputClean)
     798           2 :         pg_fatal("option --if-exists requires option -c/--clean");
     799             : 
     800             :     /* set derivative flags */
     801         362 :     dopt.dumpSchema = (!data_only);
     802         362 :     dopt.dumpData = (!schema_only);
     803             : 
     804             :     /*
     805             :      * --inserts are already implied above if --column-inserts or
     806             :      * --rows-per-insert were specified.
     807             :      */
     808         362 :     if (dopt.do_nothing && dopt.dump_inserts == 0)
     809           2 :         pg_fatal("option --on-conflict-do-nothing requires option --inserts, --rows-per-insert, or --column-inserts");
     810             : 
     811             :     /* Identify archive format to emit */
     812         360 :     archiveFormat = parseArchiveFormat(format, &archiveMode);
     813             : 
     814             :     /* archiveFormat specific setup */
     815         358 :     if (archiveFormat == archNull)
     816         294 :         plainText = 1;
     817             : 
     818             :     /*
     819             :      * Custom and directory formats are compressed by default with gzip when
     820             :      * available, not the others.  If gzip is not available, no compression is
     821             :      * done by default.
     822             :      */
     823         358 :     if ((archiveFormat == archCustom || archiveFormat == archDirectory) &&
     824          58 :         !user_compression_defined)
     825             :     {
     826             : #ifdef HAVE_LIBZ
     827          48 :         compression_algorithm_str = "gzip";
     828             : #else
     829             :         compression_algorithm_str = "none";
     830             : #endif
     831             :     }
     832             : 
     833             :     /*
     834             :      * Compression options
     835             :      */
     836         358 :     if (!parse_compress_algorithm(compression_algorithm_str,
     837             :                                   &compression_algorithm))
     838           2 :         pg_fatal("unrecognized compression algorithm: \"%s\"",
     839             :                  compression_algorithm_str);
     840             : 
     841         356 :     parse_compress_specification(compression_algorithm, compression_detail,
     842             :                                  &compression_spec);
     843         356 :     error_detail = validate_compress_specification(&compression_spec);
     844         356 :     if (error_detail != NULL)
     845           6 :         pg_fatal("invalid compression specification: %s",
     846             :                  error_detail);
     847             : 
     848         350 :     error_detail = supports_compression(compression_spec);
     849         350 :     if (error_detail != NULL)
     850           0 :         pg_fatal("%s", error_detail);
     851             : 
     852             :     /*
     853             :      * Disable support for zstd workers for now - these are based on
     854             :      * threading, and it's unclear how it interacts with parallel dumps on
     855             :      * platforms where that relies on threads too (e.g. Windows).
     856             :      */
     857         350 :     if (compression_spec.options & PG_COMPRESSION_OPTION_WORKERS)
     858           0 :         pg_log_warning("compression option \"%s\" is not currently supported by pg_dump",
     859             :                        "workers");
     860             : 
     861             :     /*
     862             :      * If emitting an archive format, we always want to emit a DATABASE item,
     863             :      * in case --create is specified at pg_restore time.
     864             :      */
     865         350 :     if (!plainText)
     866          64 :         dopt.outputCreateDB = 1;
     867             : 
     868             :     /* Parallel backup only in the directory archive format so far */
     869         350 :     if (archiveFormat != archDirectory && numWorkers > 1)
     870           2 :         pg_fatal("parallel backup only supported by the directory format");
     871             : 
     872             :     /* Open the output file */
     873         348 :     fout = CreateArchive(filename, archiveFormat, compression_spec,
     874             :                          dosync, archiveMode, setupDumpWorker, sync_method);
     875             : 
     876             :     /* Make dump options accessible right away */
     877         346 :     SetArchiveOptions(fout, &dopt, NULL);
     878             : 
     879             :     /* Register the cleanup hook */
     880         346 :     on_exit_close_archive(fout);
     881             : 
     882             :     /* Let the archiver know how noisy to be */
     883         346 :     fout->verbose = g_verbose;
     884             : 
     885             : 
     886             :     /*
     887             :      * We allow the server to be back to 9.2, and up to any minor release of
     888             :      * our own major version.  (See also version check in pg_dumpall.c.)
     889             :      */
     890         346 :     fout->minRemoteVersion = 90200;
     891         346 :     fout->maxRemoteVersion = (PG_VERSION_NUM / 100) * 100 + 99;
     892             : 
     893         346 :     fout->numWorkers = numWorkers;
     894             : 
     895             :     /*
     896             :      * Open the database using the Archiver, so it knows about it. Errors mean
     897             :      * death.
     898             :      */
     899         346 :     ConnectDatabase(fout, &dopt.cparams, false);
     900         342 :     setup_connection(fout, dumpencoding, dumpsnapshot, use_role);
     901             : 
     902             :     /*
     903             :      * On hot standbys, never try to dump unlogged table data, since it will
     904             :      * just throw an error.
     905             :      */
     906         342 :     if (fout->isStandby)
     907           8 :         dopt.no_unlogged_table_data = true;
     908             : 
     909             :     /*
     910             :      * Find the last built-in OID, if needed (prior to 8.1)
     911             :      *
     912             :      * With 8.1 and above, we can just use FirstNormalObjectId - 1.
     913             :      */
     914         342 :     g_last_builtin_oid = FirstNormalObjectId - 1;
     915             : 
     916         342 :     pg_log_info("last built-in OID is %u", g_last_builtin_oid);
     917             : 
     918             :     /* Expand schema selection patterns into OID lists */
     919         342 :     if (schema_include_patterns.head != NULL)
     920             :     {
     921          36 :         expand_schema_name_patterns(fout, &schema_include_patterns,
     922             :                                     &schema_include_oids,
     923             :                                     strict_names);
     924          24 :         if (schema_include_oids.head == NULL)
     925           2 :             pg_fatal("no matching schemas were found");
     926             :     }
     927         328 :     expand_schema_name_patterns(fout, &schema_exclude_patterns,
     928             :                                 &schema_exclude_oids,
     929             :                                 false);
     930             :     /* non-matching exclusion patterns aren't an error */
     931             : 
     932             :     /* Expand table selection patterns into OID lists */
     933         328 :     expand_table_name_patterns(fout, &table_include_patterns,
     934             :                                &table_include_oids,
     935             :                                strict_names, false);
     936         318 :     expand_table_name_patterns(fout, &table_include_patterns_and_children,
     937             :                                &table_include_oids,
     938             :                                strict_names, true);
     939         318 :     if ((table_include_patterns.head != NULL ||
     940         296 :          table_include_patterns_and_children.head != NULL) &&
     941          26 :         table_include_oids.head == NULL)
     942           4 :         pg_fatal("no matching tables were found");
     943             : 
     944         314 :     expand_table_name_patterns(fout, &table_exclude_patterns,
     945             :                                &table_exclude_oids,
     946             :                                false, false);
     947         314 :     expand_table_name_patterns(fout, &table_exclude_patterns_and_children,
     948             :                                &table_exclude_oids,
     949             :                                false, true);
     950             : 
     951         314 :     expand_table_name_patterns(fout, &tabledata_exclude_patterns,
     952             :                                &tabledata_exclude_oids,
     953             :                                false, false);
     954         314 :     expand_table_name_patterns(fout, &tabledata_exclude_patterns_and_children,
     955             :                                &tabledata_exclude_oids,
     956             :                                false, true);
     957             : 
     958         314 :     expand_foreign_server_name_patterns(fout, &foreign_servers_include_patterns,
     959             :                                         &foreign_servers_include_oids);
     960             : 
     961             :     /* non-matching exclusion patterns aren't an error */
     962             : 
     963             :     /* Expand extension selection patterns into OID lists */
     964         312 :     if (extension_include_patterns.head != NULL)
     965             :     {
     966          10 :         expand_extension_name_patterns(fout, &extension_include_patterns,
     967             :                                        &extension_include_oids,
     968             :                                        strict_names);
     969          10 :         if (extension_include_oids.head == NULL)
     970           2 :             pg_fatal("no matching extensions were found");
     971             :     }
     972         310 :     expand_extension_name_patterns(fout, &extension_exclude_patterns,
     973             :                                    &extension_exclude_oids,
     974             :                                    false);
     975             :     /* non-matching exclusion patterns aren't an error */
     976             : 
     977             :     /*
     978             :      * Dumping LOs is the default for dumps where an inclusion switch is not
     979             :      * used (an "include everything" dump).  -B can be used to exclude LOs
     980             :      * from those dumps.  -b can be used to include LOs even when an inclusion
     981             :      * switch is used.
     982             :      *
     983             :      * -s means "schema only" and LOs are data, not schema, so we never
     984             :      * include LOs when -s is used.
     985             :      */
     986         310 :     if (dopt.include_everything && dopt.dumpData && !dopt.dontOutputLOs)
     987         228 :         dopt.outputLOs = true;
     988             : 
     989             :     /*
     990             :      * Collect role names so we can map object owner OIDs to names.
     991             :      */
     992         310 :     collectRoleNames(fout);
     993             : 
     994             :     /*
     995             :      * Now scan the database and create DumpableObject structs for all the
     996             :      * objects we intend to dump.
     997             :      */
     998         310 :     tblinfo = getSchemaData(fout, &numTables);
     999             : 
    1000         308 :     if (dopt.dumpData)
    1001             :     {
    1002         276 :         getTableData(&dopt, tblinfo, numTables, 0);
    1003         276 :         buildMatViewRefreshDependencies(fout);
    1004         276 :         if (!dopt.dumpSchema)
    1005          12 :             getTableDataFKConstraints();
    1006             :     }
    1007             : 
    1008         308 :     if (!dopt.dumpData && dopt.sequence_data)
    1009          28 :         getTableData(&dopt, tblinfo, numTables, RELKIND_SEQUENCE);
    1010             : 
    1011             :     /*
    1012             :      * In binary-upgrade mode, we do not have to worry about the actual LO
    1013             :      * data or the associated metadata that resides in the pg_largeobject and
    1014             :      * pg_largeobject_metadata tables, respectively.
    1015             :      *
    1016             :      * However, we do need to collect LO information as there may be comments
    1017             :      * or other information on LOs that we do need to dump out.
    1018             :      */
    1019         308 :     if (dopt.outputLOs || dopt.binary_upgrade)
    1020         256 :         getLOs(fout);
    1021             : 
    1022             :     /*
    1023             :      * Collect dependency data to assist in ordering the objects.
    1024             :      */
    1025         308 :     getDependencies(fout);
    1026             : 
    1027             :     /*
    1028             :      * Collect ACLs, comments, and security labels, if wanted.
    1029             :      */
    1030         308 :     if (!dopt.aclsSkip)
    1031         304 :         getAdditionalACLs(fout);
    1032         308 :     if (!dopt.no_comments)
    1033         308 :         collectComments(fout);
    1034         308 :     if (!dopt.no_security_labels)
    1035         308 :         collectSecLabels(fout);
    1036             : 
    1037             :     /* For binary upgrade mode, collect required pg_class information. */
    1038         308 :     if (dopt.binary_upgrade)
    1039          28 :         collectBinaryUpgradeClassOids(fout);
    1040             : 
    1041             :     /* Collect sequence information. */
    1042         308 :     collectSequences(fout);
    1043             : 
    1044             :     /* Lastly, create dummy objects to represent the section boundaries */
    1045         308 :     boundaryObjs = createBoundaryObjects();
    1046             : 
    1047             :     /* Get pointers to all the known DumpableObjects */
    1048         308 :     getDumpableObjects(&dobjs, &numObjs);
    1049             : 
    1050             :     /*
    1051             :      * Add dummy dependencies to enforce the dump section ordering.
    1052             :      */
    1053         308 :     addBoundaryDependencies(dobjs, numObjs, boundaryObjs);
    1054             : 
    1055             :     /*
    1056             :      * Sort the objects into a safe dump order (no forward references).
    1057             :      *
    1058             :      * We rely on dependency information to help us determine a safe order, so
    1059             :      * the initial sort is mostly for cosmetic purposes: we sort by name to
    1060             :      * ensure that logically identical schemas will dump identically.
    1061             :      */
    1062         308 :     sortDumpableObjectsByTypeName(dobjs, numObjs);
    1063             : 
    1064         308 :     sortDumpableObjects(dobjs, numObjs,
    1065         308 :                         boundaryObjs[0].dumpId, boundaryObjs[1].dumpId);
    1066             : 
    1067             :     /*
    1068             :      * Create archive TOC entries for all the objects to be dumped, in a safe
    1069             :      * order.
    1070             :      */
    1071             : 
    1072             :     /*
    1073             :      * First the special entries for ENCODING, STDSTRINGS, and SEARCHPATH.
    1074             :      */
    1075         308 :     dumpEncoding(fout);
    1076         308 :     dumpStdStrings(fout);
    1077         308 :     dumpSearchPath(fout);
    1078             : 
    1079             :     /* The database items are always next, unless we don't want them at all */
    1080         308 :     if (dopt.outputCreateDB)
    1081         120 :         dumpDatabase(fout);
    1082             : 
    1083             :     /* Now the rearrangeable objects. */
    1084     1126600 :     for (i = 0; i < numObjs; i++)
    1085     1126292 :         dumpDumpableObject(fout, dobjs[i]);
    1086             : 
    1087             :     /*
    1088             :      * Set up options info to ensure we dump what we want.
    1089             :      */
    1090         308 :     ropt = NewRestoreOptions();
    1091         308 :     ropt->filename = filename;
    1092             : 
    1093             :     /* if you change this list, see dumpOptionsFromRestoreOptions */
    1094         308 :     ropt->cparams.dbname = dopt.cparams.dbname ? pg_strdup(dopt.cparams.dbname) : NULL;
    1095         308 :     ropt->cparams.pgport = dopt.cparams.pgport ? pg_strdup(dopt.cparams.pgport) : NULL;
    1096         308 :     ropt->cparams.pghost = dopt.cparams.pghost ? pg_strdup(dopt.cparams.pghost) : NULL;
    1097         308 :     ropt->cparams.username = dopt.cparams.username ? pg_strdup(dopt.cparams.username) : NULL;
    1098         308 :     ropt->cparams.promptPassword = dopt.cparams.promptPassword;
    1099         308 :     ropt->dropSchema = dopt.outputClean;
    1100         308 :     ropt->dumpData = dopt.dumpData;
    1101         308 :     ropt->dumpSchema = dopt.dumpSchema;
    1102         308 :     ropt->if_exists = dopt.if_exists;
    1103         308 :     ropt->column_inserts = dopt.column_inserts;
    1104         308 :     ropt->dumpSections = dopt.dumpSections;
    1105         308 :     ropt->aclsSkip = dopt.aclsSkip;
    1106         308 :     ropt->superuser = dopt.outputSuperuser;
    1107         308 :     ropt->createDB = dopt.outputCreateDB;
    1108         308 :     ropt->noOwner = dopt.outputNoOwner;
    1109         308 :     ropt->noTableAm = dopt.outputNoTableAm;
    1110         308 :     ropt->noTablespace = dopt.outputNoTablespaces;
    1111         308 :     ropt->disable_triggers = dopt.disable_triggers;
    1112         308 :     ropt->use_setsessauth = dopt.use_setsessauth;
    1113         308 :     ropt->disable_dollar_quoting = dopt.disable_dollar_quoting;
    1114         308 :     ropt->dump_inserts = dopt.dump_inserts;
    1115         308 :     ropt->no_comments = dopt.no_comments;
    1116         308 :     ropt->no_publications = dopt.no_publications;
    1117         308 :     ropt->no_security_labels = dopt.no_security_labels;
    1118         308 :     ropt->no_subscriptions = dopt.no_subscriptions;
    1119         308 :     ropt->lockWaitTimeout = dopt.lockWaitTimeout;
    1120         308 :     ropt->include_everything = dopt.include_everything;
    1121         308 :     ropt->enable_row_security = dopt.enable_row_security;
    1122         308 :     ropt->sequence_data = dopt.sequence_data;
    1123         308 :     ropt->binary_upgrade = dopt.binary_upgrade;
    1124             : 
    1125         308 :     ropt->compression_spec = compression_spec;
    1126             : 
    1127         308 :     ropt->suppressDumpWarnings = true;   /* We've already shown them */
    1128             : 
    1129         308 :     SetArchiveOptions(fout, &dopt, ropt);
    1130             : 
    1131             :     /* Mark which entries should be output */
    1132         308 :     ProcessArchiveRestoreOptions(fout);
    1133             : 
    1134             :     /*
    1135             :      * The archive's TOC entries are now marked as to which ones will actually
    1136             :      * be output, so we can set up their dependency lists properly. This isn't
    1137             :      * necessary for plain-text output, though.
    1138             :      */
    1139         308 :     if (!plainText)
    1140          62 :         BuildArchiveDependencies(fout);
    1141             : 
    1142             :     /*
    1143             :      * And finally we can do the actual output.
    1144             :      *
    1145             :      * Note: for non-plain-text output formats, the output file is written
    1146             :      * inside CloseArchive().  This is, um, bizarre; but not worth changing
    1147             :      * right now.
    1148             :      */
    1149         308 :     if (plainText)
    1150         246 :         RestoreArchive(fout);
    1151             : 
    1152         306 :     CloseArchive(fout);
    1153             : 
    1154         306 :     exit_nicely(0);
    1155             : }
    1156             : 
    1157             : 
    1158             : static void
    1159           2 : help(const char *progname)
    1160             : {
    1161           2 :     printf(_("%s dumps a database as a text file or to other formats.\n\n"), progname);
    1162           2 :     printf(_("Usage:\n"));
    1163           2 :     printf(_("  %s [OPTION]... [DBNAME]\n"), progname);
    1164             : 
    1165           2 :     printf(_("\nGeneral options:\n"));
    1166           2 :     printf(_("  -f, --file=FILENAME          output file or directory name\n"));
    1167           2 :     printf(_("  -F, --format=c|d|t|p         output file format (custom, directory, tar,\n"
    1168             :              "                               plain text (default))\n"));
    1169           2 :     printf(_("  -j, --jobs=NUM               use this many parallel jobs to dump\n"));
    1170           2 :     printf(_("  -v, --verbose                verbose mode\n"));
    1171           2 :     printf(_("  -V, --version                output version information, then exit\n"));
    1172           2 :     printf(_("  -Z, --compress=METHOD[:DETAIL]\n"
    1173             :              "                               compress as specified\n"));
    1174           2 :     printf(_("  --lock-wait-timeout=TIMEOUT  fail after waiting TIMEOUT for a table lock\n"));
    1175           2 :     printf(_("  --no-sync                    do not wait for changes to be written safely to disk\n"));
    1176           2 :     printf(_("  --sync-method=METHOD         set method for syncing files to disk\n"));
    1177           2 :     printf(_("  -?, --help                   show this help, then exit\n"));
    1178             : 
    1179           2 :     printf(_("\nOptions controlling the output content:\n"));
    1180           2 :     printf(_("  -a, --data-only              dump only the data, not the schema\n"));
    1181           2 :     printf(_("  -b, --large-objects          include large objects in dump\n"));
    1182           2 :     printf(_("  --blobs                      (same as --large-objects, deprecated)\n"));
    1183           2 :     printf(_("  -B, --no-large-objects       exclude large objects in dump\n"));
    1184           2 :     printf(_("  --no-blobs                   (same as --no-large-objects, deprecated)\n"));
    1185           2 :     printf(_("  -c, --clean                  clean (drop) database objects before recreating\n"));
    1186           2 :     printf(_("  -C, --create                 include commands to create database in dump\n"));
    1187           2 :     printf(_("  -e, --extension=PATTERN      dump the specified extension(s) only\n"));
    1188           2 :     printf(_("  -E, --encoding=ENCODING      dump the data in encoding ENCODING\n"));
    1189           2 :     printf(_("  -n, --schema=PATTERN         dump the specified schema(s) only\n"));
    1190           2 :     printf(_("  -N, --exclude-schema=PATTERN do NOT dump the specified schema(s)\n"));
    1191           2 :     printf(_("  -O, --no-owner               skip restoration of object ownership in\n"
    1192             :              "                               plain-text format\n"));
    1193           2 :     printf(_("  -s, --schema-only            dump only the schema, no data\n"));
    1194           2 :     printf(_("  -S, --superuser=NAME         superuser user name to use in plain-text format\n"));
    1195           2 :     printf(_("  -t, --table=PATTERN          dump only the specified table(s)\n"));
    1196           2 :     printf(_("  -T, --exclude-table=PATTERN  do NOT dump the specified table(s)\n"));
    1197           2 :     printf(_("  -x, --no-privileges          do not dump privileges (grant/revoke)\n"));
    1198           2 :     printf(_("  --binary-upgrade             for use by upgrade utilities only\n"));
    1199           2 :     printf(_("  --column-inserts             dump data as INSERT commands with column names\n"));
    1200           2 :     printf(_("  --disable-dollar-quoting     disable dollar quoting, use SQL standard quoting\n"));
    1201           2 :     printf(_("  --disable-triggers           disable triggers during data-only restore\n"));
    1202           2 :     printf(_("  --enable-row-security        enable row security (dump only content user has\n"
    1203             :              "                               access to)\n"));
    1204           2 :     printf(_("  --exclude-extension=PATTERN  do NOT dump the specified extension(s)\n"));
    1205           2 :     printf(_("  --exclude-table-and-children=PATTERN\n"
    1206             :              "                               do NOT dump the specified table(s), including\n"
    1207             :              "                               child and partition tables\n"));
    1208           2 :     printf(_("  --exclude-table-data=PATTERN do NOT dump data for the specified table(s)\n"));
    1209           2 :     printf(_("  --exclude-table-data-and-children=PATTERN\n"
    1210             :              "                               do NOT dump data for the specified table(s),\n"
    1211             :              "                               including child and partition tables\n"));
    1212           2 :     printf(_("  --extra-float-digits=NUM     override default setting for extra_float_digits\n"));
    1213           2 :     printf(_("  --filter=FILENAME            include or exclude objects and data from dump\n"
    1214             :              "                               based on expressions in FILENAME\n"));
    1215           2 :     printf(_("  --if-exists                  use IF EXISTS when dropping objects\n"));
    1216           2 :     printf(_("  --include-foreign-data=PATTERN\n"
    1217             :              "                               include data of foreign tables on foreign\n"
    1218             :              "                               servers matching PATTERN\n"));
    1219           2 :     printf(_("  --inserts                    dump data as INSERT commands, rather than COPY\n"));
    1220           2 :     printf(_("  --load-via-partition-root    load partitions via the root table\n"));
    1221           2 :     printf(_("  --no-comments                do not dump comment commands\n"));
    1222           2 :     printf(_("  --no-publications            do not dump publications\n"));
    1223           2 :     printf(_("  --no-security-labels         do not dump security label assignments\n"));
    1224           2 :     printf(_("  --no-subscriptions           do not dump subscriptions\n"));
    1225           2 :     printf(_("  --no-table-access-method     do not dump table access methods\n"));
    1226           2 :     printf(_("  --no-tablespaces             do not dump tablespace assignments\n"));
    1227           2 :     printf(_("  --no-toast-compression       do not dump TOAST compression methods\n"));
    1228           2 :     printf(_("  --no-unlogged-table-data     do not dump unlogged table data\n"));
    1229           2 :     printf(_("  --on-conflict-do-nothing     add ON CONFLICT DO NOTHING to INSERT commands\n"));
    1230           2 :     printf(_("  --quote-all-identifiers      quote all identifiers, even if not key words\n"));
    1231           2 :     printf(_("  --rows-per-insert=NROWS      number of rows per INSERT; implies --inserts\n"));
    1232           2 :     printf(_("  --section=SECTION            dump named section (pre-data, data, or post-data)\n"));
    1233           2 :     printf(_("  --serializable-deferrable    wait until the dump can run without anomalies\n"));
    1234           2 :     printf(_("  --snapshot=SNAPSHOT          use given snapshot for the dump\n"));
    1235           2 :     printf(_("  --strict-names               require table and/or schema include patterns to\n"
    1236             :              "                               match at least one entity each\n"));
    1237           2 :     printf(_("  --table-and-children=PATTERN dump only the specified table(s), including\n"
    1238             :              "                               child and partition tables\n"));
    1239           2 :     printf(_("  --use-set-session-authorization\n"
    1240             :              "                               use SET SESSION AUTHORIZATION commands instead of\n"
    1241             :              "                               ALTER OWNER commands to set ownership\n"));
    1242             : 
    1243           2 :     printf(_("\nConnection options:\n"));
    1244           2 :     printf(_("  -d, --dbname=DBNAME      database to dump\n"));
    1245           2 :     printf(_("  -h, --host=HOSTNAME      database server host or socket directory\n"));
    1246           2 :     printf(_("  -p, --port=PORT          database server port number\n"));
    1247           2 :     printf(_("  -U, --username=NAME      connect as specified database user\n"));
    1248           2 :     printf(_("  -w, --no-password        never prompt for password\n"));
    1249           2 :     printf(_("  -W, --password           force password prompt (should happen automatically)\n"));
    1250           2 :     printf(_("  --role=ROLENAME          do SET ROLE before dump\n"));
    1251             : 
    1252           2 :     printf(_("\nIf no database name is supplied, then the PGDATABASE environment\n"
    1253             :              "variable value is used.\n\n"));
    1254           2 :     printf(_("Report bugs to <%s>.\n"), PACKAGE_BUGREPORT);
    1255           2 :     printf(_("%s home page: <%s>\n"), PACKAGE_NAME, PACKAGE_URL);
    1256           2 : }
    1257             : 
    1258             : static void
    1259         374 : setup_connection(Archive *AH, const char *dumpencoding,
    1260             :                  const char *dumpsnapshot, char *use_role)
    1261             : {
    1262         374 :     DumpOptions *dopt = AH->dopt;
    1263         374 :     PGconn     *conn = GetConnection(AH);
    1264             :     const char *std_strings;
    1265             : 
    1266         374 :     PQclear(ExecuteSqlQueryForSingleRow(AH, ALWAYS_SECURE_SEARCH_PATH_SQL));
    1267             : 
    1268             :     /*
    1269             :      * Set the client encoding if requested.
    1270             :      */
    1271         374 :     if (dumpencoding)
    1272             :     {
    1273          36 :         if (PQsetClientEncoding(conn, dumpencoding) < 0)
    1274           0 :             pg_fatal("invalid client encoding \"%s\" specified",
    1275             :                      dumpencoding);
    1276             :     }
    1277             : 
    1278             :     /*
    1279             :      * Get the active encoding and the standard_conforming_strings setting, so
    1280             :      * we know how to escape strings.
    1281             :      */
    1282         374 :     AH->encoding = PQclientEncoding(conn);
    1283             : 
    1284         374 :     std_strings = PQparameterStatus(conn, "standard_conforming_strings");
    1285         374 :     AH->std_strings = (std_strings && strcmp(std_strings, "on") == 0);
    1286             : 
    1287             :     /*
    1288             :      * Set the role if requested.  In a parallel dump worker, we'll be passed
    1289             :      * use_role == NULL, but AH->use_role is already set (if user specified it
    1290             :      * originally) and we should use that.
    1291             :      */
    1292         374 :     if (!use_role && AH->use_role)
    1293           4 :         use_role = AH->use_role;
    1294             : 
    1295             :     /* Set the role if requested */
    1296         374 :     if (use_role)
    1297             :     {
    1298          10 :         PQExpBuffer query = createPQExpBuffer();
    1299             : 
    1300          10 :         appendPQExpBuffer(query, "SET ROLE %s", fmtId(use_role));
    1301          10 :         ExecuteSqlStatement(AH, query->data);
    1302          10 :         destroyPQExpBuffer(query);
    1303             : 
    1304             :         /* save it for possible later use by parallel workers */
    1305          10 :         if (!AH->use_role)
    1306           6 :             AH->use_role = pg_strdup(use_role);
    1307             :     }
    1308             : 
    1309             :     /* Set the datestyle to ISO to ensure the dump's portability */
    1310         374 :     ExecuteSqlStatement(AH, "SET DATESTYLE = ISO");
    1311             : 
    1312             :     /* Likewise, avoid using sql_standard intervalstyle */
    1313         374 :     ExecuteSqlStatement(AH, "SET INTERVALSTYLE = POSTGRES");
    1314             : 
    1315             :     /*
    1316             :      * Use an explicitly specified extra_float_digits if it has been provided.
    1317             :      * Otherwise, set extra_float_digits so that we can dump float data
    1318             :      * exactly (given correctly implemented float I/O code, anyway).
    1319             :      */
    1320         374 :     if (have_extra_float_digits)
    1321             :     {
    1322           0 :         PQExpBuffer q = createPQExpBuffer();
    1323             : 
    1324           0 :         appendPQExpBuffer(q, "SET extra_float_digits TO %d",
    1325             :                           extra_float_digits);
    1326           0 :         ExecuteSqlStatement(AH, q->data);
    1327           0 :         destroyPQExpBuffer(q);
    1328             :     }
    1329             :     else
    1330         374 :         ExecuteSqlStatement(AH, "SET extra_float_digits TO 3");
    1331             : 
    1332             :     /*
    1333             :      * Disable synchronized scanning, to prevent unpredictable changes in row
    1334             :      * ordering across a dump and reload.
    1335             :      */
    1336         374 :     ExecuteSqlStatement(AH, "SET synchronize_seqscans TO off");
    1337             : 
    1338             :     /*
    1339             :      * Disable timeouts if supported.
    1340             :      */
    1341         374 :     ExecuteSqlStatement(AH, "SET statement_timeout = 0");
    1342         374 :     if (AH->remoteVersion >= 90300)
    1343         374 :         ExecuteSqlStatement(AH, "SET lock_timeout = 0");
    1344         374 :     if (AH->remoteVersion >= 90600)
    1345         374 :         ExecuteSqlStatement(AH, "SET idle_in_transaction_session_timeout = 0");
    1346         374 :     if (AH->remoteVersion >= 170000)
    1347         374 :         ExecuteSqlStatement(AH, "SET transaction_timeout = 0");
    1348             : 
    1349             :     /*
    1350             :      * Quote all identifiers, if requested.
    1351             :      */
    1352         374 :     if (quote_all_identifiers)
    1353          24 :         ExecuteSqlStatement(AH, "SET quote_all_identifiers = true");
    1354             : 
    1355             :     /*
    1356             :      * Adjust row-security mode, if supported.
    1357             :      */
    1358         374 :     if (AH->remoteVersion >= 90500)
    1359             :     {
    1360         374 :         if (dopt->enable_row_security)
    1361           0 :             ExecuteSqlStatement(AH, "SET row_security = on");
    1362             :         else
    1363         374 :             ExecuteSqlStatement(AH, "SET row_security = off");
    1364             :     }
    1365             : 
    1366             :     /*
    1367             :      * For security reasons, we restrict the expansion of non-system views and
    1368             :      * access to foreign tables during the pg_dump process. This restriction
    1369             :      * is adjusted when dumping foreign table data.
    1370             :      */
    1371         374 :     set_restrict_relation_kind(AH, "view, foreign-table");
    1372             : 
    1373             :     /*
    1374             :      * Initialize prepared-query state to "nothing prepared".  We do this here
    1375             :      * so that a parallel dump worker will have its own state.
    1376             :      */
    1377         374 :     AH->is_prepared = (bool *) pg_malloc0(NUM_PREP_QUERIES * sizeof(bool));
    1378             : 
    1379             :     /*
    1380             :      * Start transaction-snapshot mode transaction to dump consistent data.
    1381             :      */
    1382         374 :     ExecuteSqlStatement(AH, "BEGIN");
    1383             : 
    1384             :     /*
    1385             :      * To support the combination of serializable_deferrable with the jobs
    1386             :      * option we use REPEATABLE READ for the worker connections that are
    1387             :      * passed a snapshot.  As long as the snapshot is acquired in a
    1388             :      * SERIALIZABLE, READ ONLY, DEFERRABLE transaction, its use within a
    1389             :      * REPEATABLE READ transaction provides the appropriate integrity
    1390             :      * guarantees.  This is a kluge, but safe for back-patching.
    1391             :      */
    1392         374 :     if (dopt->serializable_deferrable && AH->sync_snapshot_id == NULL)
    1393           0 :         ExecuteSqlStatement(AH,
    1394             :                             "SET TRANSACTION ISOLATION LEVEL "
    1395             :                             "SERIALIZABLE, READ ONLY, DEFERRABLE");
    1396             :     else
    1397         374 :         ExecuteSqlStatement(AH,
    1398             :                             "SET TRANSACTION ISOLATION LEVEL "
    1399             :                             "REPEATABLE READ, READ ONLY");
    1400             : 
    1401             :     /*
    1402             :      * If user specified a snapshot to use, select that.  In a parallel dump
    1403             :      * worker, we'll be passed dumpsnapshot == NULL, but AH->sync_snapshot_id
    1404             :      * is already set (if the server can handle it) and we should use that.
    1405             :      */
    1406         374 :     if (dumpsnapshot)
    1407           0 :         AH->sync_snapshot_id = pg_strdup(dumpsnapshot);
    1408             : 
    1409         374 :     if (AH->sync_snapshot_id)
    1410             :     {
    1411          32 :         PQExpBuffer query = createPQExpBuffer();
    1412             : 
    1413          32 :         appendPQExpBufferStr(query, "SET TRANSACTION SNAPSHOT ");
    1414          32 :         appendStringLiteralConn(query, AH->sync_snapshot_id, conn);
    1415          32 :         ExecuteSqlStatement(AH, query->data);
    1416          32 :         destroyPQExpBuffer(query);
    1417             :     }
    1418         342 :     else if (AH->numWorkers > 1)
    1419             :     {
    1420          16 :         if (AH->isStandby && AH->remoteVersion < 100000)
    1421           0 :             pg_fatal("parallel dumps from standby servers are not supported by this server version");
    1422          16 :         AH->sync_snapshot_id = get_synchronized_snapshot(AH);
    1423             :     }
    1424         374 : }
    1425             : 
    1426             : /* Set up connection for a parallel worker process */
    1427             : static void
    1428          32 : setupDumpWorker(Archive *AH)
    1429             : {
    1430             :     /*
    1431             :      * We want to re-select all the same values the leader connection is
    1432             :      * using.  We'll have inherited directly-usable values in
    1433             :      * AH->sync_snapshot_id and AH->use_role, but we need to translate the
    1434             :      * inherited encoding value back to a string to pass to setup_connection.
    1435             :      */
    1436          32 :     setup_connection(AH,
    1437             :                      pg_encoding_to_char(AH->encoding),
    1438             :                      NULL,
    1439             :                      NULL);
    1440          32 : }
    1441             : 
    1442             : static char *
    1443          16 : get_synchronized_snapshot(Archive *fout)
    1444             : {
    1445          16 :     char       *query = "SELECT pg_catalog.pg_export_snapshot()";
    1446             :     char       *result;
    1447             :     PGresult   *res;
    1448             : 
    1449          16 :     res = ExecuteSqlQueryForSingleRow(fout, query);
    1450          16 :     result = pg_strdup(PQgetvalue(res, 0, 0));
    1451          16 :     PQclear(res);
    1452             : 
    1453          16 :     return result;
    1454             : }
    1455             : 
    1456             : static ArchiveFormat
    1457         360 : parseArchiveFormat(const char *format, ArchiveMode *mode)
    1458             : {
    1459             :     ArchiveFormat archiveFormat;
    1460             : 
    1461         360 :     *mode = archModeWrite;
    1462             : 
    1463         360 :     if (pg_strcasecmp(format, "a") == 0 || pg_strcasecmp(format, "append") == 0)
    1464             :     {
    1465             :         /* This is used by pg_dumpall, and is not documented */
    1466          86 :         archiveFormat = archNull;
    1467          86 :         *mode = archModeAppend;
    1468             :     }
    1469         274 :     else if (pg_strcasecmp(format, "c") == 0)
    1470           8 :         archiveFormat = archCustom;
    1471         266 :     else if (pg_strcasecmp(format, "custom") == 0)
    1472          30 :         archiveFormat = archCustom;
    1473         236 :     else if (pg_strcasecmp(format, "d") == 0)
    1474          14 :         archiveFormat = archDirectory;
    1475         222 :     else if (pg_strcasecmp(format, "directory") == 0)
    1476           6 :         archiveFormat = archDirectory;
    1477         216 :     else if (pg_strcasecmp(format, "p") == 0)
    1478         202 :         archiveFormat = archNull;
    1479          14 :     else if (pg_strcasecmp(format, "plain") == 0)
    1480           6 :         archiveFormat = archNull;
    1481           8 :     else if (pg_strcasecmp(format, "t") == 0)
    1482           4 :         archiveFormat = archTar;
    1483           4 :     else if (pg_strcasecmp(format, "tar") == 0)
    1484           2 :         archiveFormat = archTar;
    1485             :     else
    1486           2 :         pg_fatal("invalid output format \"%s\" specified", format);
    1487         358 :     return archiveFormat;
    1488             : }
    1489             : 
    1490             : /*
    1491             :  * Find the OIDs of all schemas matching the given list of patterns,
    1492             :  * and append them to the given OID list.
    1493             :  */
    1494             : static void
    1495         364 : expand_schema_name_patterns(Archive *fout,
    1496             :                             SimpleStringList *patterns,
    1497             :                             SimpleOidList *oids,
    1498             :                             bool strict_names)
    1499             : {
    1500             :     PQExpBuffer query;
    1501             :     PGresult   *res;
    1502             :     SimpleStringListCell *cell;
    1503             :     int         i;
    1504             : 
    1505         364 :     if (patterns->head == NULL)
    1506         322 :         return;                 /* nothing to do */
    1507             : 
    1508          42 :     query = createPQExpBuffer();
    1509             : 
    1510             :     /*
    1511             :      * The loop below runs multiple SELECTs might sometimes result in
    1512             :      * duplicate entries in the OID list, but we don't care.
    1513             :      */
    1514             : 
    1515          72 :     for (cell = patterns->head; cell; cell = cell->next)
    1516             :     {
    1517             :         PQExpBufferData dbbuf;
    1518             :         int         dotcnt;
    1519             : 
    1520          42 :         appendPQExpBufferStr(query,
    1521             :                              "SELECT oid FROM pg_catalog.pg_namespace n\n");
    1522          42 :         initPQExpBuffer(&dbbuf);
    1523          42 :         processSQLNamePattern(GetConnection(fout), query, cell->val, false,
    1524             :                               false, NULL, "n.nspname", NULL, NULL, &dbbuf,
    1525             :                               &dotcnt);
    1526          42 :         if (dotcnt > 1)
    1527           4 :             pg_fatal("improper qualified name (too many dotted names): %s",
    1528             :                      cell->val);
    1529          38 :         else if (dotcnt == 1)
    1530           6 :             prohibit_crossdb_refs(GetConnection(fout), dbbuf.data, cell->val);
    1531          32 :         termPQExpBuffer(&dbbuf);
    1532             : 
    1533          32 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    1534          32 :         if (strict_names && PQntuples(res) == 0)
    1535           2 :             pg_fatal("no matching schemas were found for pattern \"%s\"", cell->val);
    1536             : 
    1537          58 :         for (i = 0; i < PQntuples(res); i++)
    1538             :         {
    1539          28 :             simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
    1540             :         }
    1541             : 
    1542          30 :         PQclear(res);
    1543          30 :         resetPQExpBuffer(query);
    1544             :     }
    1545             : 
    1546          30 :     destroyPQExpBuffer(query);
    1547             : }
    1548             : 
    1549             : /*
    1550             :  * Find the OIDs of all extensions matching the given list of patterns,
    1551             :  * and append them to the given OID list.
    1552             :  */
    1553             : static void
    1554         320 : expand_extension_name_patterns(Archive *fout,
    1555             :                                SimpleStringList *patterns,
    1556             :                                SimpleOidList *oids,
    1557             :                                bool strict_names)
    1558             : {
    1559             :     PQExpBuffer query;
    1560             :     PGresult   *res;
    1561             :     SimpleStringListCell *cell;
    1562             :     int         i;
    1563             : 
    1564         320 :     if (patterns->head == NULL)
    1565         306 :         return;                 /* nothing to do */
    1566             : 
    1567          14 :     query = createPQExpBuffer();
    1568             : 
    1569             :     /*
    1570             :      * The loop below runs multiple SELECTs might sometimes result in
    1571             :      * duplicate entries in the OID list, but we don't care.
    1572             :      */
    1573          28 :     for (cell = patterns->head; cell; cell = cell->next)
    1574             :     {
    1575             :         int         dotcnt;
    1576             : 
    1577          14 :         appendPQExpBufferStr(query,
    1578             :                              "SELECT oid FROM pg_catalog.pg_extension e\n");
    1579          14 :         processSQLNamePattern(GetConnection(fout), query, cell->val, false,
    1580             :                               false, NULL, "e.extname", NULL, NULL, NULL,
    1581             :                               &dotcnt);
    1582          14 :         if (dotcnt > 0)
    1583           0 :             pg_fatal("improper qualified name (too many dotted names): %s",
    1584             :                      cell->val);
    1585             : 
    1586          14 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    1587          14 :         if (strict_names && PQntuples(res) == 0)
    1588           0 :             pg_fatal("no matching extensions were found for pattern \"%s\"", cell->val);
    1589             : 
    1590          26 :         for (i = 0; i < PQntuples(res); i++)
    1591             :         {
    1592          12 :             simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
    1593             :         }
    1594             : 
    1595          14 :         PQclear(res);
    1596          14 :         resetPQExpBuffer(query);
    1597             :     }
    1598             : 
    1599          14 :     destroyPQExpBuffer(query);
    1600             : }
    1601             : 
    1602             : /*
    1603             :  * Find the OIDs of all foreign servers matching the given list of patterns,
    1604             :  * and append them to the given OID list.
    1605             :  */
    1606             : static void
    1607         314 : expand_foreign_server_name_patterns(Archive *fout,
    1608             :                                     SimpleStringList *patterns,
    1609             :                                     SimpleOidList *oids)
    1610             : {
    1611             :     PQExpBuffer query;
    1612             :     PGresult   *res;
    1613             :     SimpleStringListCell *cell;
    1614             :     int         i;
    1615             : 
    1616         314 :     if (patterns->head == NULL)
    1617         308 :         return;                 /* nothing to do */
    1618             : 
    1619           6 :     query = createPQExpBuffer();
    1620             : 
    1621             :     /*
    1622             :      * The loop below runs multiple SELECTs might sometimes result in
    1623             :      * duplicate entries in the OID list, but we don't care.
    1624             :      */
    1625             : 
    1626          10 :     for (cell = patterns->head; cell; cell = cell->next)
    1627             :     {
    1628             :         int         dotcnt;
    1629             : 
    1630           6 :         appendPQExpBufferStr(query,
    1631             :                              "SELECT oid FROM pg_catalog.pg_foreign_server s\n");
    1632           6 :         processSQLNamePattern(GetConnection(fout), query, cell->val, false,
    1633             :                               false, NULL, "s.srvname", NULL, NULL, NULL,
    1634             :                               &dotcnt);
    1635           6 :         if (dotcnt > 0)
    1636           0 :             pg_fatal("improper qualified name (too many dotted names): %s",
    1637             :                      cell->val);
    1638             : 
    1639           6 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    1640           6 :         if (PQntuples(res) == 0)
    1641           2 :             pg_fatal("no matching foreign servers were found for pattern \"%s\"", cell->val);
    1642             : 
    1643           8 :         for (i = 0; i < PQntuples(res); i++)
    1644           4 :             simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
    1645             : 
    1646           4 :         PQclear(res);
    1647           4 :         resetPQExpBuffer(query);
    1648             :     }
    1649             : 
    1650           4 :     destroyPQExpBuffer(query);
    1651             : }
    1652             : 
    1653             : /*
    1654             :  * Find the OIDs of all tables matching the given list of patterns,
    1655             :  * and append them to the given OID list. See also expand_dbname_patterns()
    1656             :  * in pg_dumpall.c
    1657             :  */
    1658             : static void
    1659        1902 : expand_table_name_patterns(Archive *fout,
    1660             :                            SimpleStringList *patterns, SimpleOidList *oids,
    1661             :                            bool strict_names, bool with_child_tables)
    1662             : {
    1663             :     PQExpBuffer query;
    1664             :     PGresult   *res;
    1665             :     SimpleStringListCell *cell;
    1666             :     int         i;
    1667             : 
    1668        1902 :     if (patterns->head == NULL)
    1669        1844 :         return;                 /* nothing to do */
    1670             : 
    1671          58 :     query = createPQExpBuffer();
    1672             : 
    1673             :     /*
    1674             :      * this might sometimes result in duplicate entries in the OID list, but
    1675             :      * we don't care.
    1676             :      */
    1677             : 
    1678         118 :     for (cell = patterns->head; cell; cell = cell->next)
    1679             :     {
    1680             :         PQExpBufferData dbbuf;
    1681             :         int         dotcnt;
    1682             : 
    1683             :         /*
    1684             :          * Query must remain ABSOLUTELY devoid of unqualified names.  This
    1685             :          * would be unnecessary given a pg_table_is_visible() variant taking a
    1686             :          * search_path argument.
    1687             :          *
    1688             :          * For with_child_tables, we start with the basic query's results and
    1689             :          * recursively search the inheritance tree to add child tables.
    1690             :          */
    1691          70 :         if (with_child_tables)
    1692             :         {
    1693          12 :             appendPQExpBuffer(query, "WITH RECURSIVE partition_tree (relid) AS (\n");
    1694             :         }
    1695             : 
    1696          70 :         appendPQExpBuffer(query,
    1697             :                           "SELECT c.oid"
    1698             :                           "\nFROM pg_catalog.pg_class c"
    1699             :                           "\n     LEFT JOIN pg_catalog.pg_namespace n"
    1700             :                           "\n     ON n.oid OPERATOR(pg_catalog.=) c.relnamespace"
    1701             :                           "\nWHERE c.relkind OPERATOR(pg_catalog.=) ANY"
    1702             :                           "\n    (array['%c', '%c', '%c', '%c', '%c', '%c'])\n",
    1703             :                           RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_VIEW,
    1704             :                           RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE,
    1705             :                           RELKIND_PARTITIONED_TABLE);
    1706          70 :         initPQExpBuffer(&dbbuf);
    1707          70 :         processSQLNamePattern(GetConnection(fout), query, cell->val, true,
    1708             :                               false, "n.nspname", "c.relname", NULL,
    1709             :                               "pg_catalog.pg_table_is_visible(c.oid)", &dbbuf,
    1710             :                               &dotcnt);
    1711          70 :         if (dotcnt > 2)
    1712           2 :             pg_fatal("improper relation name (too many dotted names): %s",
    1713             :                      cell->val);
    1714          68 :         else if (dotcnt == 2)
    1715           4 :             prohibit_crossdb_refs(GetConnection(fout), dbbuf.data, cell->val);
    1716          64 :         termPQExpBuffer(&dbbuf);
    1717             : 
    1718          64 :         if (with_child_tables)
    1719             :         {
    1720          12 :             appendPQExpBuffer(query, "UNION"
    1721             :                               "\nSELECT i.inhrelid"
    1722             :                               "\nFROM partition_tree p"
    1723             :                               "\n     JOIN pg_catalog.pg_inherits i"
    1724             :                               "\n     ON p.relid OPERATOR(pg_catalog.=) i.inhparent"
    1725             :                               "\n)"
    1726             :                               "\nSELECT relid FROM partition_tree");
    1727             :         }
    1728             : 
    1729          64 :         ExecuteSqlStatement(fout, "RESET search_path");
    1730          64 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    1731          64 :         PQclear(ExecuteSqlQueryForSingleRow(fout,
    1732             :                                             ALWAYS_SECURE_SEARCH_PATH_SQL));
    1733          64 :         if (strict_names && PQntuples(res) == 0)
    1734           4 :             pg_fatal("no matching tables were found for pattern \"%s\"", cell->val);
    1735             : 
    1736         148 :         for (i = 0; i < PQntuples(res); i++)
    1737             :         {
    1738          88 :             simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
    1739             :         }
    1740             : 
    1741          60 :         PQclear(res);
    1742          60 :         resetPQExpBuffer(query);
    1743             :     }
    1744             : 
    1745          48 :     destroyPQExpBuffer(query);
    1746             : }
    1747             : 
    1748             : /*
    1749             :  * Verifies that the connected database name matches the given database name,
    1750             :  * and if not, dies with an error about the given pattern.
    1751             :  *
    1752             :  * The 'dbname' argument should be a literal name parsed from 'pattern'.
    1753             :  */
    1754             : static void
    1755          10 : prohibit_crossdb_refs(PGconn *conn, const char *dbname, const char *pattern)
    1756             : {
    1757             :     const char *db;
    1758             : 
    1759          10 :     db = PQdb(conn);
    1760          10 :     if (db == NULL)
    1761           0 :         pg_fatal("You are currently not connected to a database.");
    1762             : 
    1763          10 :     if (strcmp(db, dbname) != 0)
    1764          10 :         pg_fatal("cross-database references are not implemented: %s",
    1765             :                  pattern);
    1766           0 : }
    1767             : 
    1768             : /*
    1769             :  * checkExtensionMembership
    1770             :  *      Determine whether object is an extension member, and if so,
    1771             :  *      record an appropriate dependency and set the object's dump flag.
    1772             :  *
    1773             :  * It's important to call this for each object that could be an extension
    1774             :  * member.  Generally, we integrate this with determining the object's
    1775             :  * to-be-dumped-ness, since extension membership overrides other rules for that.
    1776             :  *
    1777             :  * Returns true if object is an extension member, else false.
    1778             :  */
    1779             : static bool
    1780      959922 : checkExtensionMembership(DumpableObject *dobj, Archive *fout)
    1781             : {
    1782      959922 :     ExtensionInfo *ext = findOwningExtension(dobj->catId);
    1783             : 
    1784      959922 :     if (ext == NULL)
    1785      958530 :         return false;
    1786             : 
    1787        1392 :     dobj->ext_member = true;
    1788             : 
    1789             :     /* Record dependency so that getDependencies needn't deal with that */
    1790        1392 :     addObjectDependency(dobj, ext->dobj.dumpId);
    1791             : 
    1792             :     /*
    1793             :      * In 9.6 and above, mark the member object to have any non-initial ACLs
    1794             :      * dumped.  (Any initial ACLs will be removed later, using data from
    1795             :      * pg_init_privs, so that we'll dump only the delta from the extension's
    1796             :      * initial setup.)
    1797             :      *
    1798             :      * Prior to 9.6, we do not include any extension member components.
    1799             :      *
    1800             :      * In binary upgrades, we still dump all components of the members
    1801             :      * individually, since the idea is to exactly reproduce the database
    1802             :      * contents rather than replace the extension contents with something
    1803             :      * different.
    1804             :      *
    1805             :      * Note: it might be interesting someday to implement storage and delta
    1806             :      * dumping of extension members' RLS policies and/or security labels.
    1807             :      * However there is a pitfall for RLS policies: trying to dump them
    1808             :      * requires getting a lock on their tables, and the calling user might not
    1809             :      * have privileges for that.  We need no lock to examine a table's ACLs,
    1810             :      * so the current feature doesn't have a problem of that sort.
    1811             :      */
    1812        1392 :     if (fout->dopt->binary_upgrade)
    1813         152 :         dobj->dump = ext->dobj.dump;
    1814             :     else
    1815             :     {
    1816        1240 :         if (fout->remoteVersion < 90600)
    1817           0 :             dobj->dump = DUMP_COMPONENT_NONE;
    1818             :         else
    1819        1240 :             dobj->dump = ext->dobj.dump_contains & (DUMP_COMPONENT_ACL);
    1820             :     }
    1821             : 
    1822        1392 :     return true;
    1823             : }
    1824             : 
    1825             : /*
    1826             :  * selectDumpableNamespace: policy-setting subroutine
    1827             :  *      Mark a namespace as to be dumped or not
    1828             :  */
    1829             : static void
    1830        2510 : selectDumpableNamespace(NamespaceInfo *nsinfo, Archive *fout)
    1831             : {
    1832             :     /*
    1833             :      * DUMP_COMPONENT_DEFINITION typically implies a CREATE SCHEMA statement
    1834             :      * and (for --clean) a DROP SCHEMA statement.  (In the absence of
    1835             :      * DUMP_COMPONENT_DEFINITION, this value is irrelevant.)
    1836             :      */
    1837        2510 :     nsinfo->create = true;
    1838             : 
    1839             :     /*
    1840             :      * If specific tables are being dumped, do not dump any complete
    1841             :      * namespaces. If specific namespaces are being dumped, dump just those
    1842             :      * namespaces. Otherwise, dump all non-system namespaces.
    1843             :      */
    1844        2510 :     if (table_include_oids.head != NULL)
    1845         100 :         nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
    1846        2410 :     else if (schema_include_oids.head != NULL)
    1847         354 :         nsinfo->dobj.dump_contains = nsinfo->dobj.dump =
    1848         354 :             simple_oid_list_member(&schema_include_oids,
    1849             :                                    nsinfo->dobj.catId.oid) ?
    1850         354 :             DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
    1851        2056 :     else if (fout->remoteVersion >= 90600 &&
    1852        2056 :              strcmp(nsinfo->dobj.name, "pg_catalog") == 0)
    1853             :     {
    1854             :         /*
    1855             :          * In 9.6 and above, we dump out any ACLs defined in pg_catalog, if
    1856             :          * they are interesting (and not the original ACLs which were set at
    1857             :          * initdb time, see pg_init_privs).
    1858             :          */
    1859         266 :         nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_ACL;
    1860             :     }
    1861        1790 :     else if (strncmp(nsinfo->dobj.name, "pg_", 3) == 0 ||
    1862         820 :              strcmp(nsinfo->dobj.name, "information_schema") == 0)
    1863             :     {
    1864             :         /* Other system schemas don't get dumped */
    1865        1236 :         nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
    1866             :     }
    1867         554 :     else if (strcmp(nsinfo->dobj.name, "public") == 0)
    1868             :     {
    1869             :         /*
    1870             :          * The public schema is a strange beast that sits in a sort of
    1871             :          * no-mans-land between being a system object and a user object.
    1872             :          * CREATE SCHEMA would fail, so its DUMP_COMPONENT_DEFINITION is just
    1873             :          * a comment and an indication of ownership.  If the owner is the
    1874             :          * default, omit that superfluous DUMP_COMPONENT_DEFINITION.  Before
    1875             :          * v15, the default owner was BOOTSTRAP_SUPERUSERID.
    1876             :          */
    1877         258 :         nsinfo->create = false;
    1878         258 :         nsinfo->dobj.dump = DUMP_COMPONENT_ALL;
    1879         258 :         if (nsinfo->nspowner == ROLE_PG_DATABASE_OWNER)
    1880         178 :             nsinfo->dobj.dump &= ~DUMP_COMPONENT_DEFINITION;
    1881         258 :         nsinfo->dobj.dump_contains = DUMP_COMPONENT_ALL;
    1882             : 
    1883             :         /*
    1884             :          * Also, make like it has a comment even if it doesn't; this is so
    1885             :          * that we'll emit a command to drop the comment, if appropriate.
    1886             :          * (Without this, we'd not call dumpCommentExtended for it.)
    1887             :          */
    1888         258 :         nsinfo->dobj.components |= DUMP_COMPONENT_COMMENT;
    1889             :     }
    1890             :     else
    1891         296 :         nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_ALL;
    1892             : 
    1893             :     /*
    1894             :      * In any case, a namespace can be excluded by an exclusion switch
    1895             :      */
    1896        3352 :     if (nsinfo->dobj.dump_contains &&
    1897         842 :         simple_oid_list_member(&schema_exclude_oids,
    1898             :                                nsinfo->dobj.catId.oid))
    1899           6 :         nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
    1900             : 
    1901             :     /*
    1902             :      * If the schema belongs to an extension, allow extension membership to
    1903             :      * override the dump decision for the schema itself.  However, this does
    1904             :      * not change dump_contains, so this won't change what we do with objects
    1905             :      * within the schema.  (If they belong to the extension, they'll get
    1906             :      * suppressed by it, otherwise not.)
    1907             :      */
    1908        2510 :     (void) checkExtensionMembership(&nsinfo->dobj, fout);
    1909        2510 : }
    1910             : 
    1911             : /*
    1912             :  * selectDumpableTable: policy-setting subroutine
    1913             :  *      Mark a table as to be dumped or not
    1914             :  */
    1915             : static void
    1916       81078 : selectDumpableTable(TableInfo *tbinfo, Archive *fout)
    1917             : {
    1918       81078 :     if (checkExtensionMembership(&tbinfo->dobj, fout))
    1919         450 :         return;                 /* extension membership overrides all else */
    1920             : 
    1921             :     /*
    1922             :      * If specific tables are being dumped, dump just those tables; else, dump
    1923             :      * according to the parent namespace's dump flag.
    1924             :      */
    1925       80628 :     if (table_include_oids.head != NULL)
    1926       10104 :         tbinfo->dobj.dump = simple_oid_list_member(&table_include_oids,
    1927             :                                                    tbinfo->dobj.catId.oid) ?
    1928        5052 :             DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
    1929             :     else
    1930       75576 :         tbinfo->dobj.dump = tbinfo->dobj.namespace->dobj.dump_contains;
    1931             : 
    1932             :     /*
    1933             :      * In any case, a table can be excluded by an exclusion switch
    1934             :      */
    1935      130666 :     if (tbinfo->dobj.dump &&
    1936       50038 :         simple_oid_list_member(&table_exclude_oids,
    1937             :                                tbinfo->dobj.catId.oid))
    1938          24 :         tbinfo->dobj.dump = DUMP_COMPONENT_NONE;
    1939             : }
    1940             : 
    1941             : /*
    1942             :  * selectDumpableType: policy-setting subroutine
    1943             :  *      Mark a type as to be dumped or not
    1944             :  *
    1945             :  * If it's a table's rowtype or an autogenerated array type, we also apply a
    1946             :  * special type code to facilitate sorting into the desired order.  (We don't
    1947             :  * want to consider those to be ordinary types because that would bring tables
    1948             :  * up into the datatype part of the dump order.)  We still set the object's
    1949             :  * dump flag; that's not going to cause the dummy type to be dumped, but we
    1950             :  * need it so that casts involving such types will be dumped correctly -- see
    1951             :  * dumpCast.  This means the flag should be set the same as for the underlying
    1952             :  * object (the table or base type).
    1953             :  */
    1954             : static void
    1955      221940 : selectDumpableType(TypeInfo *tyinfo, Archive *fout)
    1956             : {
    1957             :     /* skip complex types, except for standalone composite types */
    1958      221940 :     if (OidIsValid(tyinfo->typrelid) &&
    1959       79738 :         tyinfo->typrelkind != RELKIND_COMPOSITE_TYPE)
    1960             :     {
    1961       79378 :         TableInfo  *tytable = findTableByOid(tyinfo->typrelid);
    1962             : 
    1963       79378 :         tyinfo->dobj.objType = DO_DUMMY_TYPE;
    1964       79378 :         if (tytable != NULL)
    1965       79378 :             tyinfo->dobj.dump = tytable->dobj.dump;
    1966             :         else
    1967           0 :             tyinfo->dobj.dump = DUMP_COMPONENT_NONE;
    1968       79378 :         return;
    1969             :     }
    1970             : 
    1971             :     /* skip auto-generated array and multirange types */
    1972      142562 :     if (tyinfo->isArray || tyinfo->isMultirange)
    1973             :     {
    1974      108530 :         tyinfo->dobj.objType = DO_DUMMY_TYPE;
    1975             : 
    1976             :         /*
    1977             :          * Fall through to set the dump flag; we assume that the subsequent
    1978             :          * rules will do the same thing as they would for the array's base
    1979             :          * type or multirange's range type.  (We cannot reliably look up the
    1980             :          * base type here, since getTypes may not have processed it yet.)
    1981             :          */
    1982             :     }
    1983             : 
    1984      142562 :     if (checkExtensionMembership(&tyinfo->dobj, fout))
    1985         300 :         return;                 /* extension membership overrides all else */
    1986             : 
    1987             :     /* Dump based on if the contents of the namespace are being dumped */
    1988      142262 :     tyinfo->dobj.dump = tyinfo->dobj.namespace->dobj.dump_contains;
    1989             : }
    1990             : 
    1991             : /*
    1992             :  * selectDumpableDefaultACL: policy-setting subroutine
    1993             :  *      Mark a default ACL as to be dumped or not
    1994             :  *
    1995             :  * For per-schema default ACLs, dump if the schema is to be dumped.
    1996             :  * Otherwise dump if we are dumping "everything".  Note that dumpSchema
    1997             :  * and aclsSkip are checked separately.
    1998             :  */
    1999             : static void
    2000         344 : selectDumpableDefaultACL(DefaultACLInfo *dinfo, DumpOptions *dopt)
    2001             : {
    2002             :     /* Default ACLs can't be extension members */
    2003             : 
    2004         344 :     if (dinfo->dobj.namespace)
    2005             :         /* default ACLs are considered part of the namespace */
    2006         172 :         dinfo->dobj.dump = dinfo->dobj.namespace->dobj.dump_contains;
    2007             :     else
    2008         172 :         dinfo->dobj.dump = dopt->include_everything ?
    2009         172 :             DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
    2010         344 : }
    2011             : 
    2012             : /*
    2013             :  * selectDumpableCast: policy-setting subroutine
    2014             :  *      Mark a cast as to be dumped or not
    2015             :  *
    2016             :  * Casts do not belong to any particular namespace (since they haven't got
    2017             :  * names), nor do they have identifiable owners.  To distinguish user-defined
    2018             :  * casts from built-in ones, we must resort to checking whether the cast's
    2019             :  * OID is in the range reserved for initdb.
    2020             :  */
    2021             : static void
    2022       68854 : selectDumpableCast(CastInfo *cast, Archive *fout)
    2023             : {
    2024       68854 :     if (checkExtensionMembership(&cast->dobj, fout))
    2025           0 :         return;                 /* extension membership overrides all else */
    2026             : 
    2027             :     /*
    2028             :      * This would be DUMP_COMPONENT_ACL for from-initdb casts, but they do not
    2029             :      * support ACLs currently.
    2030             :      */
    2031       68854 :     if (cast->dobj.catId.oid <= (Oid) g_last_builtin_oid)
    2032       68684 :         cast->dobj.dump = DUMP_COMPONENT_NONE;
    2033             :     else
    2034         170 :         cast->dobj.dump = fout->dopt->include_everything ?
    2035         170 :             DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
    2036             : }
    2037             : 
    2038             : /*
    2039             :  * selectDumpableProcLang: policy-setting subroutine
    2040             :  *      Mark a procedural language as to be dumped or not
    2041             :  *
    2042             :  * Procedural languages do not belong to any particular namespace.  To
    2043             :  * identify built-in languages, we must resort to checking whether the
    2044             :  * language's OID is in the range reserved for initdb.
    2045             :  */
    2046             : static void
    2047         394 : selectDumpableProcLang(ProcLangInfo *plang, Archive *fout)
    2048             : {
    2049         394 :     if (checkExtensionMembership(&plang->dobj, fout))
    2050         308 :         return;                 /* extension membership overrides all else */
    2051             : 
    2052             :     /*
    2053             :      * Only include procedural languages when we are dumping everything.
    2054             :      *
    2055             :      * For from-initdb procedural languages, only include ACLs, as we do for
    2056             :      * the pg_catalog namespace.  We need this because procedural languages do
    2057             :      * not live in any namespace.
    2058             :      */
    2059          86 :     if (!fout->dopt->include_everything)
    2060          16 :         plang->dobj.dump = DUMP_COMPONENT_NONE;
    2061             :     else
    2062             :     {
    2063          70 :         if (plang->dobj.catId.oid <= (Oid) g_last_builtin_oid)
    2064           0 :             plang->dobj.dump = fout->remoteVersion < 90600 ?
    2065           0 :                 DUMP_COMPONENT_NONE : DUMP_COMPONENT_ACL;
    2066             :         else
    2067          70 :             plang->dobj.dump = DUMP_COMPONENT_ALL;
    2068             :     }
    2069             : }
    2070             : 
    2071             : /*
    2072             :  * selectDumpableAccessMethod: policy-setting subroutine
    2073             :  *      Mark an access method as to be dumped or not
    2074             :  *
    2075             :  * Access methods do not belong to any particular namespace.  To identify
    2076             :  * built-in access methods, we must resort to checking whether the
    2077             :  * method's OID is in the range reserved for initdb.
    2078             :  */
    2079             : static void
    2080        2392 : selectDumpableAccessMethod(AccessMethodInfo *method, Archive *fout)
    2081             : {
    2082        2392 :     if (checkExtensionMembership(&method->dobj, fout))
    2083          50 :         return;                 /* extension membership overrides all else */
    2084             : 
    2085             :     /*
    2086             :      * This would be DUMP_COMPONENT_ACL for from-initdb access methods, but
    2087             :      * they do not support ACLs currently.
    2088             :      */
    2089        2342 :     if (method->dobj.catId.oid <= (Oid) g_last_builtin_oid)
    2090        2156 :         method->dobj.dump = DUMP_COMPONENT_NONE;
    2091             :     else
    2092         186 :         method->dobj.dump = fout->dopt->include_everything ?
    2093         186 :             DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
    2094             : }
    2095             : 
    2096             : /*
    2097             :  * selectDumpableExtension: policy-setting subroutine
    2098             :  *      Mark an extension as to be dumped or not
    2099             :  *
    2100             :  * Built-in extensions should be skipped except for checking ACLs, since we
    2101             :  * assume those will already be installed in the target database.  We identify
    2102             :  * such extensions by their having OIDs in the range reserved for initdb.
    2103             :  * We dump all user-added extensions by default.  No extensions are dumped
    2104             :  * if include_everything is false (i.e., a --schema or --table switch was
    2105             :  * given), except if --extension specifies a list of extensions to dump.
    2106             :  */
    2107             : static void
    2108         360 : selectDumpableExtension(ExtensionInfo *extinfo, DumpOptions *dopt)
    2109             : {
    2110             :     /*
    2111             :      * Use DUMP_COMPONENT_ACL for built-in extensions, to allow users to
    2112             :      * change permissions on their member objects, if they wish to, and have
    2113             :      * those changes preserved.
    2114             :      */
    2115         360 :     if (extinfo->dobj.catId.oid <= (Oid) g_last_builtin_oid)
    2116         310 :         extinfo->dobj.dump = extinfo->dobj.dump_contains = DUMP_COMPONENT_ACL;
    2117             :     else
    2118             :     {
    2119             :         /* check if there is a list of extensions to dump */
    2120          50 :         if (extension_include_oids.head != NULL)
    2121           8 :             extinfo->dobj.dump = extinfo->dobj.dump_contains =
    2122           8 :                 simple_oid_list_member(&extension_include_oids,
    2123             :                                        extinfo->dobj.catId.oid) ?
    2124           8 :                 DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
    2125             :         else
    2126          42 :             extinfo->dobj.dump = extinfo->dobj.dump_contains =
    2127          42 :                 dopt->include_everything ?
    2128          42 :                 DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
    2129             : 
    2130             :         /* check that the extension is not explicitly excluded */
    2131          92 :         if (extinfo->dobj.dump &&
    2132          42 :             simple_oid_list_member(&extension_exclude_oids,
    2133             :                                    extinfo->dobj.catId.oid))
    2134           4 :             extinfo->dobj.dump = extinfo->dobj.dump_contains = DUMP_COMPONENT_NONE;
    2135             :     }
    2136         360 : }
    2137             : 
    2138             : /*
    2139             :  * selectDumpablePublicationObject: policy-setting subroutine
    2140             :  *      Mark a publication object as to be dumped or not
    2141             :  *
    2142             :  * A publication can have schemas and tables which have schemas, but those are
    2143             :  * ignored in decision making, because publications are only dumped when we are
    2144             :  * dumping everything.
    2145             :  */
    2146             : static void
    2147         652 : selectDumpablePublicationObject(DumpableObject *dobj, Archive *fout)
    2148             : {
    2149         652 :     if (checkExtensionMembership(dobj, fout))
    2150           0 :         return;                 /* extension membership overrides all else */
    2151             : 
    2152         652 :     dobj->dump = fout->dopt->include_everything ?
    2153         652 :         DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
    2154             : }
    2155             : 
    2156             : /*
    2157             :  * selectDumpableStatisticsObject: policy-setting subroutine
    2158             :  *      Mark an extended statistics object as to be dumped or not
    2159             :  *
    2160             :  * We dump an extended statistics object if the schema it's in and the table
    2161             :  * it's for are being dumped.  (This'll need more thought if statistics
    2162             :  * objects ever support cross-table stats.)
    2163             :  */
    2164             : static void
    2165         314 : selectDumpableStatisticsObject(StatsExtInfo *sobj, Archive *fout)
    2166             : {
    2167         314 :     if (checkExtensionMembership(&sobj->dobj, fout))
    2168           0 :         return;                 /* extension membership overrides all else */
    2169             : 
    2170         314 :     sobj->dobj.dump = sobj->dobj.namespace->dobj.dump_contains;
    2171         314 :     if (sobj->stattable == NULL ||
    2172         314 :         !(sobj->stattable->dobj.dump & DUMP_COMPONENT_DEFINITION))
    2173          56 :         sobj->dobj.dump = DUMP_COMPONENT_NONE;
    2174             : }
    2175             : 
    2176             : /*
    2177             :  * selectDumpableObject: policy-setting subroutine
    2178             :  *      Mark a generic dumpable object as to be dumped or not
    2179             :  *
    2180             :  * Use this only for object types without a special-case routine above.
    2181             :  */
    2182             : static void
    2183      661166 : selectDumpableObject(DumpableObject *dobj, Archive *fout)
    2184             : {
    2185      661166 :     if (checkExtensionMembership(dobj, fout))
    2186         234 :         return;                 /* extension membership overrides all else */
    2187             : 
    2188             :     /*
    2189             :      * Default policy is to dump if parent namespace is dumpable, or for
    2190             :      * non-namespace-associated items, dump if we're dumping "everything".
    2191             :      */
    2192      660932 :     if (dobj->namespace)
    2193      659762 :         dobj->dump = dobj->namespace->dobj.dump_contains;
    2194             :     else
    2195        1170 :         dobj->dump = fout->dopt->include_everything ?
    2196        1170 :             DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
    2197             : }
    2198             : 
    2199             : /*
    2200             :  *  Dump a table's contents for loading using the COPY command
    2201             :  *  - this routine is called by the Archiver when it wants the table
    2202             :  *    to be dumped.
    2203             :  */
    2204             : static int
    2205        7026 : dumpTableData_copy(Archive *fout, const void *dcontext)
    2206             : {
    2207        7026 :     TableDataInfo *tdinfo = (TableDataInfo *) dcontext;
    2208        7026 :     TableInfo  *tbinfo = tdinfo->tdtable;
    2209        7026 :     const char *classname = tbinfo->dobj.name;
    2210        7026 :     PQExpBuffer q = createPQExpBuffer();
    2211             : 
    2212             :     /*
    2213             :      * Note: can't use getThreadLocalPQExpBuffer() here, we're calling fmtId
    2214             :      * which uses it already.
    2215             :      */
    2216        7026 :     PQExpBuffer clistBuf = createPQExpBuffer();
    2217        7026 :     PGconn     *conn = GetConnection(fout);
    2218             :     PGresult   *res;
    2219             :     int         ret;
    2220             :     char       *copybuf;
    2221             :     const char *column_list;
    2222             : 
    2223        7026 :     pg_log_info("dumping contents of table \"%s.%s\"",
    2224             :                 tbinfo->dobj.namespace->dobj.name, classname);
    2225             : 
    2226             :     /*
    2227             :      * Specify the column list explicitly so that we have no possibility of
    2228             :      * retrieving data in the wrong column order.  (The default column
    2229             :      * ordering of COPY will not be what we want in certain corner cases
    2230             :      * involving ADD COLUMN and inheritance.)
    2231             :      */
    2232        7026 :     column_list = fmtCopyColumnList(tbinfo, clistBuf);
    2233             : 
    2234             :     /*
    2235             :      * Use COPY (SELECT ...) TO when dumping a foreign table's data, and when
    2236             :      * a filter condition was specified.  For other cases a simple COPY
    2237             :      * suffices.
    2238             :      */
    2239        7026 :     if (tdinfo->filtercond || tbinfo->relkind == RELKIND_FOREIGN_TABLE)
    2240             :     {
    2241             :         /* Temporary allows to access to foreign tables to dump data */
    2242           2 :         if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
    2243           2 :             set_restrict_relation_kind(fout, "view");
    2244             : 
    2245           2 :         appendPQExpBufferStr(q, "COPY (SELECT ");
    2246             :         /* klugery to get rid of parens in column list */
    2247           2 :         if (strlen(column_list) > 2)
    2248             :         {
    2249           2 :             appendPQExpBufferStr(q, column_list + 1);
    2250           2 :             q->data[q->len - 1] = ' ';
    2251             :         }
    2252             :         else
    2253           0 :             appendPQExpBufferStr(q, "* ");
    2254             : 
    2255           4 :         appendPQExpBuffer(q, "FROM %s %s) TO stdout;",
    2256           2 :                           fmtQualifiedDumpable(tbinfo),
    2257           2 :                           tdinfo->filtercond ? tdinfo->filtercond : "");
    2258             :     }
    2259             :     else
    2260             :     {
    2261        7024 :         appendPQExpBuffer(q, "COPY %s %s TO stdout;",
    2262        7024 :                           fmtQualifiedDumpable(tbinfo),
    2263             :                           column_list);
    2264             :     }
    2265        7026 :     res = ExecuteSqlQuery(fout, q->data, PGRES_COPY_OUT);
    2266        7024 :     PQclear(res);
    2267        7024 :     destroyPQExpBuffer(clistBuf);
    2268             : 
    2269             :     for (;;)
    2270             :     {
    2271     3602012 :         ret = PQgetCopyData(conn, &copybuf, 0);
    2272             : 
    2273     3602012 :         if (ret < 0)
    2274        7024 :             break;              /* done or error */
    2275             : 
    2276     3594988 :         if (copybuf)
    2277             :         {
    2278     3594988 :             WriteData(fout, copybuf, ret);
    2279     3594988 :             PQfreemem(copybuf);
    2280             :         }
    2281             : 
    2282             :         /* ----------
    2283             :          * THROTTLE:
    2284             :          *
    2285             :          * There was considerable discussion in late July, 2000 regarding
    2286             :          * slowing down pg_dump when backing up large tables. Users with both
    2287             :          * slow & fast (multi-processor) machines experienced performance
    2288             :          * degradation when doing a backup.
    2289             :          *
    2290             :          * Initial attempts based on sleeping for a number of ms for each ms
    2291             :          * of work were deemed too complex, then a simple 'sleep in each loop'
    2292             :          * implementation was suggested. The latter failed because the loop
    2293             :          * was too tight. Finally, the following was implemented:
    2294             :          *
    2295             :          * If throttle is non-zero, then
    2296             :          *      See how long since the last sleep.
    2297             :          *      Work out how long to sleep (based on ratio).
    2298             :          *      If sleep is more than 100ms, then
    2299             :          *          sleep
    2300             :          *          reset timer
    2301             :          *      EndIf
    2302             :          * EndIf
    2303             :          *
    2304             :          * where the throttle value was the number of ms to sleep per ms of
    2305             :          * work. The calculation was done in each loop.
    2306             :          *
    2307             :          * Most of the hard work is done in the backend, and this solution
    2308             :          * still did not work particularly well: on slow machines, the ratio
    2309             :          * was 50:1, and on medium paced machines, 1:1, and on fast
    2310             :          * multi-processor machines, it had little or no effect, for reasons
    2311             :          * that were unclear.
    2312             :          *
    2313             :          * Further discussion ensued, and the proposal was dropped.
    2314             :          *
    2315             :          * For those people who want this feature, it can be implemented using
    2316             :          * gettimeofday in each loop, calculating the time since last sleep,
    2317             :          * multiplying that by the sleep ratio, then if the result is more
    2318             :          * than a preset 'minimum sleep time' (say 100ms), call the 'select'
    2319             :          * function to sleep for a subsecond period ie.
    2320             :          *
    2321             :          * select(0, NULL, NULL, NULL, &tvi);
    2322             :          *
    2323             :          * This will return after the interval specified in the structure tvi.
    2324             :          * Finally, call gettimeofday again to save the 'last sleep time'.
    2325             :          * ----------
    2326             :          */
    2327             :     }
    2328        7024 :     archprintf(fout, "\\.\n\n\n");
    2329             : 
    2330        7024 :     if (ret == -2)
    2331             :     {
    2332             :         /* copy data transfer failed */
    2333           0 :         pg_log_error("Dumping the contents of table \"%s\" failed: PQgetCopyData() failed.", classname);
    2334           0 :         pg_log_error_detail("Error message from server: %s", PQerrorMessage(conn));
    2335           0 :         pg_log_error_detail("Command was: %s", q->data);
    2336           0 :         exit_nicely(1);
    2337             :     }
    2338             : 
    2339             :     /* Check command status and return to normal libpq state */
    2340        7024 :     res = PQgetResult(conn);
    2341        7024 :     if (PQresultStatus(res) != PGRES_COMMAND_OK)
    2342             :     {
    2343           0 :         pg_log_error("Dumping the contents of table \"%s\" failed: PQgetResult() failed.", classname);
    2344           0 :         pg_log_error_detail("Error message from server: %s", PQerrorMessage(conn));
    2345           0 :         pg_log_error_detail("Command was: %s", q->data);
    2346           0 :         exit_nicely(1);
    2347             :     }
    2348        7024 :     PQclear(res);
    2349             : 
    2350             :     /* Do this to ensure we've pumped libpq back to idle state */
    2351        7024 :     if (PQgetResult(conn) != NULL)
    2352           0 :         pg_log_warning("unexpected extra results during COPY of table \"%s\"",
    2353             :                        classname);
    2354             : 
    2355        7024 :     destroyPQExpBuffer(q);
    2356             : 
    2357             :     /* Revert back the setting */
    2358        7024 :     if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
    2359           0 :         set_restrict_relation_kind(fout, "view, foreign-table");
    2360             : 
    2361        7024 :     return 1;
    2362             : }
    2363             : 
    2364             : /*
    2365             :  * Dump table data using INSERT commands.
    2366             :  *
    2367             :  * Caution: when we restore from an archive file direct to database, the
    2368             :  * INSERT commands emitted by this function have to be parsed by
    2369             :  * pg_backup_db.c's ExecuteSimpleCommands(), which will not handle comments,
    2370             :  * E'' strings, or dollar-quoted strings.  So don't emit anything like that.
    2371             :  */
    2372             : static int
    2373         138 : dumpTableData_insert(Archive *fout, const void *dcontext)
    2374             : {
    2375         138 :     TableDataInfo *tdinfo = (TableDataInfo *) dcontext;
    2376         138 :     TableInfo  *tbinfo = tdinfo->tdtable;
    2377         138 :     DumpOptions *dopt = fout->dopt;
    2378         138 :     PQExpBuffer q = createPQExpBuffer();
    2379         138 :     PQExpBuffer insertStmt = NULL;
    2380             :     char       *attgenerated;
    2381             :     PGresult   *res;
    2382             :     int         nfields,
    2383             :                 i;
    2384         138 :     int         rows_per_statement = dopt->dump_inserts;
    2385         138 :     int         rows_this_statement = 0;
    2386             : 
    2387             :     /* Temporary allows to access to foreign tables to dump data */
    2388         138 :     if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
    2389           0 :         set_restrict_relation_kind(fout, "view");
    2390             : 
    2391             :     /*
    2392             :      * If we're going to emit INSERTs with column names, the most efficient
    2393             :      * way to deal with generated columns is to exclude them entirely.  For
    2394             :      * INSERTs without column names, we have to emit DEFAULT rather than the
    2395             :      * actual column value --- but we can save a few cycles by fetching nulls
    2396             :      * rather than the uninteresting-to-us value.
    2397             :      */
    2398         138 :     attgenerated = (char *) pg_malloc(tbinfo->numatts * sizeof(char));
    2399         138 :     appendPQExpBufferStr(q, "DECLARE _pg_dump_cursor CURSOR FOR SELECT ");
    2400         138 :     nfields = 0;
    2401         442 :     for (i = 0; i < tbinfo->numatts; i++)
    2402             :     {
    2403         304 :         if (tbinfo->attisdropped[i])
    2404           4 :             continue;
    2405         300 :         if (tbinfo->attgenerated[i] && dopt->column_inserts)
    2406          10 :             continue;
    2407         290 :         if (nfields > 0)
    2408         166 :             appendPQExpBufferStr(q, ", ");
    2409         290 :         if (tbinfo->attgenerated[i])
    2410          10 :             appendPQExpBufferStr(q, "NULL");
    2411             :         else
    2412         280 :             appendPQExpBufferStr(q, fmtId(tbinfo->attnames[i]));
    2413         290 :         attgenerated[nfields] = tbinfo->attgenerated[i];
    2414         290 :         nfields++;
    2415             :     }
    2416             :     /* Servers before 9.4 will complain about zero-column SELECT */
    2417         138 :     if (nfields == 0)
    2418          14 :         appendPQExpBufferStr(q, "NULL");
    2419         138 :     appendPQExpBuffer(q, " FROM ONLY %s",
    2420         138 :                       fmtQualifiedDumpable(tbinfo));
    2421         138 :     if (tdinfo->filtercond)
    2422           0 :         appendPQExpBuffer(q, " %s", tdinfo->filtercond);
    2423             : 
    2424         138 :     ExecuteSqlStatement(fout, q->data);
    2425             : 
    2426             :     while (1)
    2427             :     {
    2428         238 :         res = ExecuteSqlQuery(fout, "FETCH 100 FROM _pg_dump_cursor",
    2429             :                               PGRES_TUPLES_OK);
    2430             : 
    2431             :         /* cross-check field count, allowing for dummy NULL if any */
    2432         238 :         if (nfields != PQnfields(res) &&
    2433          20 :             !(nfields == 0 && PQnfields(res) == 1))
    2434           0 :             pg_fatal("wrong number of fields retrieved from table \"%s\"",
    2435             :                      tbinfo->dobj.name);
    2436             : 
    2437             :         /*
    2438             :          * First time through, we build as much of the INSERT statement as
    2439             :          * possible in "insertStmt", which we can then just print for each
    2440             :          * statement. If the table happens to have zero dumpable columns then
    2441             :          * this will be a complete statement, otherwise it will end in
    2442             :          * "VALUES" and be ready to have the row's column values printed.
    2443             :          */
    2444         238 :         if (insertStmt == NULL)
    2445             :         {
    2446             :             TableInfo  *targettab;
    2447             : 
    2448         138 :             insertStmt = createPQExpBuffer();
    2449             : 
    2450             :             /*
    2451             :              * When load-via-partition-root is set or forced, get the root
    2452             :              * table name for the partition table, so that we can reload data
    2453             :              * through the root table.
    2454             :              */
    2455         138 :             if (tbinfo->ispartition &&
    2456          80 :                 (dopt->load_via_partition_root ||
    2457          40 :                  forcePartitionRootLoad(tbinfo)))
    2458           6 :                 targettab = getRootTableInfo(tbinfo);
    2459             :             else
    2460         132 :                 targettab = tbinfo;
    2461             : 
    2462         138 :             appendPQExpBuffer(insertStmt, "INSERT INTO %s ",
    2463         138 :                               fmtQualifiedDumpable(targettab));
    2464             : 
    2465             :             /* corner case for zero-column table */
    2466         138 :             if (nfields == 0)
    2467             :             {
    2468          14 :                 appendPQExpBufferStr(insertStmt, "DEFAULT VALUES;\n");
    2469             :             }
    2470             :             else
    2471             :             {
    2472             :                 /* append the list of column names if required */
    2473         124 :                 if (dopt->column_inserts)
    2474             :                 {
    2475          54 :                     appendPQExpBufferChar(insertStmt, '(');
    2476         176 :                     for (int field = 0; field < nfields; field++)
    2477             :                     {
    2478         122 :                         if (field > 0)
    2479          68 :                             appendPQExpBufferStr(insertStmt, ", ");
    2480         122 :                         appendPQExpBufferStr(insertStmt,
    2481         122 :                                              fmtId(PQfname(res, field)));
    2482             :                     }
    2483          54 :                     appendPQExpBufferStr(insertStmt, ") ");
    2484             :                 }
    2485             : 
    2486         124 :                 if (tbinfo->needs_override)
    2487           4 :                     appendPQExpBufferStr(insertStmt, "OVERRIDING SYSTEM VALUE ");
    2488             : 
    2489         124 :                 appendPQExpBufferStr(insertStmt, "VALUES");
    2490             :             }
    2491             :         }
    2492             : 
    2493        6380 :         for (int tuple = 0; tuple < PQntuples(res); tuple++)
    2494             :         {
    2495             :             /* Write the INSERT if not in the middle of a multi-row INSERT. */
    2496        6142 :             if (rows_this_statement == 0)
    2497        6130 :                 archputs(insertStmt->data, fout);
    2498             : 
    2499             :             /*
    2500             :              * If it is zero-column table then we've already written the
    2501             :              * complete statement, which will mean we've disobeyed
    2502             :              * --rows-per-insert when it's set greater than 1.  We do support
    2503             :              * a way to make this multi-row with: SELECT UNION ALL SELECT
    2504             :              * UNION ALL ... but that's non-standard so we should avoid it
    2505             :              * given that using INSERTs is mostly only ever needed for
    2506             :              * cross-database exports.
    2507             :              */
    2508        6142 :             if (nfields == 0)
    2509          12 :                 continue;
    2510             : 
    2511             :             /* Emit a row heading */
    2512        6130 :             if (rows_per_statement == 1)
    2513        6112 :                 archputs(" (", fout);
    2514          18 :             else if (rows_this_statement > 0)
    2515          12 :                 archputs(",\n\t(", fout);
    2516             :             else
    2517           6 :                 archputs("\n\t(", fout);
    2518             : 
    2519       18498 :             for (int field = 0; field < nfields; field++)
    2520             :             {
    2521       12368 :                 if (field > 0)
    2522        6238 :                     archputs(", ", fout);
    2523       12368 :                 if (attgenerated[field])
    2524             :                 {
    2525           4 :                     archputs("DEFAULT", fout);
    2526           4 :                     continue;
    2527             :                 }
    2528       12364 :                 if (PQgetisnull(res, tuple, field))
    2529             :                 {
    2530         166 :                     archputs("NULL", fout);
    2531         166 :                     continue;
    2532             :                 }
    2533             : 
    2534             :                 /* XXX This code is partially duplicated in ruleutils.c */
    2535       12198 :                 switch (PQftype(res, field))
    2536             :                 {
    2537        8138 :                     case INT2OID:
    2538             :                     case INT4OID:
    2539             :                     case INT8OID:
    2540             :                     case OIDOID:
    2541             :                     case FLOAT4OID:
    2542             :                     case FLOAT8OID:
    2543             :                     case NUMERICOID:
    2544             :                         {
    2545             :                             /*
    2546             :                              * These types are printed without quotes unless
    2547             :                              * they contain values that aren't accepted by the
    2548             :                              * scanner unquoted (e.g., 'NaN').  Note that
    2549             :                              * strtod() and friends might accept NaN, so we
    2550             :                              * can't use that to test.
    2551             :                              *
    2552             :                              * In reality we only need to defend against
    2553             :                              * infinity and NaN, so we need not get too crazy
    2554             :                              * about pattern matching here.
    2555             :                              */
    2556        8138 :                             const char *s = PQgetvalue(res, tuple, field);
    2557             : 
    2558        8138 :                             if (strspn(s, "0123456789 +-eE.") == strlen(s))
    2559        8134 :                                 archputs(s, fout);
    2560             :                             else
    2561           4 :                                 archprintf(fout, "'%s'", s);
    2562             :                         }
    2563        8138 :                         break;
    2564             : 
    2565           4 :                     case BITOID:
    2566             :                     case VARBITOID:
    2567           4 :                         archprintf(fout, "B'%s'",
    2568             :                                    PQgetvalue(res, tuple, field));
    2569           4 :                         break;
    2570             : 
    2571           8 :                     case BOOLOID:
    2572           8 :                         if (strcmp(PQgetvalue(res, tuple, field), "t") == 0)
    2573           4 :                             archputs("true", fout);
    2574             :                         else
    2575           4 :                             archputs("false", fout);
    2576           8 :                         break;
    2577             : 
    2578        4048 :                     default:
    2579             :                         /* All other types are printed as string literals. */
    2580        4048 :                         resetPQExpBuffer(q);
    2581        4048 :                         appendStringLiteralAH(q,
    2582             :                                               PQgetvalue(res, tuple, field),
    2583             :                                               fout);
    2584        4048 :                         archputs(q->data, fout);
    2585        4048 :                         break;
    2586             :                 }
    2587             :             }
    2588             : 
    2589             :             /* Terminate the row ... */
    2590        6130 :             archputs(")", fout);
    2591             : 
    2592             :             /* ... and the statement, if the target no. of rows is reached */
    2593        6130 :             if (++rows_this_statement >= rows_per_statement)
    2594             :             {
    2595        6116 :                 if (dopt->do_nothing)
    2596           0 :                     archputs(" ON CONFLICT DO NOTHING;\n", fout);
    2597             :                 else
    2598        6116 :                     archputs(";\n", fout);
    2599             :                 /* Reset the row counter */
    2600        6116 :                 rows_this_statement = 0;
    2601             :             }
    2602             :         }
    2603             : 
    2604         238 :         if (PQntuples(res) <= 0)
    2605             :         {
    2606         138 :             PQclear(res);
    2607         138 :             break;
    2608             :         }
    2609         100 :         PQclear(res);
    2610             :     }
    2611             : 
    2612             :     /* Terminate any statements that didn't make the row count. */
    2613         138 :     if (rows_this_statement > 0)
    2614             :     {
    2615           2 :         if (dopt->do_nothing)
    2616           0 :             archputs(" ON CONFLICT DO NOTHING;\n", fout);
    2617             :         else
    2618           2 :             archputs(";\n", fout);
    2619             :     }
    2620             : 
    2621         138 :     archputs("\n\n", fout);
    2622             : 
    2623         138 :     ExecuteSqlStatement(fout, "CLOSE _pg_dump_cursor");
    2624             : 
    2625         138 :     destroyPQExpBuffer(q);
    2626         138 :     if (insertStmt != NULL)
    2627         138 :         destroyPQExpBuffer(insertStmt);
    2628         138 :     free(attgenerated);
    2629             : 
    2630             :     /* Revert back the setting */
    2631         138 :     if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
    2632           0 :         set_restrict_relation_kind(fout, "view, foreign-table");
    2633             : 
    2634         138 :     return 1;
    2635             : }
    2636             : 
    2637             : /*
    2638             :  * getRootTableInfo:
    2639             :  *     get the root TableInfo for the given partition table.
    2640             :  */
    2641             : static TableInfo *
    2642          18 : getRootTableInfo(const TableInfo *tbinfo)
    2643             : {
    2644             :     TableInfo  *parentTbinfo;
    2645             : 
    2646             :     Assert(tbinfo->ispartition);
    2647             :     Assert(tbinfo->numParents == 1);
    2648             : 
    2649          18 :     parentTbinfo = tbinfo->parents[0];
    2650          18 :     while (parentTbinfo->ispartition)
    2651             :     {
    2652             :         Assert(parentTbinfo->numParents == 1);
    2653           0 :         parentTbinfo = parentTbinfo->parents[0];
    2654             :     }
    2655             : 
    2656          18 :     return parentTbinfo;
    2657             : }
    2658             : 
    2659             : /*
    2660             :  * forcePartitionRootLoad
    2661             :  *     Check if we must force load_via_partition_root for this partition.
    2662             :  *
    2663             :  * This is required if any level of ancestral partitioned table has an
    2664             :  * unsafe partitioning scheme.
    2665             :  */
    2666             : static bool
    2667        1884 : forcePartitionRootLoad(const TableInfo *tbinfo)
    2668             : {
    2669             :     TableInfo  *parentTbinfo;
    2670             : 
    2671             :     Assert(tbinfo->ispartition);
    2672             :     Assert(tbinfo->numParents == 1);
    2673             : 
    2674        1884 :     parentTbinfo = tbinfo->parents[0];
    2675        1884 :     if (parentTbinfo->unsafe_partitions)
    2676          18 :         return true;
    2677        2298 :     while (parentTbinfo->ispartition)
    2678             :     {
    2679             :         Assert(parentTbinfo->numParents == 1);
    2680         432 :         parentTbinfo = parentTbinfo->parents[0];
    2681         432 :         if (parentTbinfo->unsafe_partitions)
    2682           0 :             return true;
    2683             :     }
    2684             : 
    2685        1866 :     return false;
    2686             : }
    2687             : 
    2688             : /*
    2689             :  * dumpTableData -
    2690             :  *    dump the contents of a single table
    2691             :  *
    2692             :  * Actually, this just makes an ArchiveEntry for the table contents.
    2693             :  */
    2694             : static void
    2695        7300 : dumpTableData(Archive *fout, const TableDataInfo *tdinfo)
    2696             : {
    2697        7300 :     DumpOptions *dopt = fout->dopt;
    2698        7300 :     TableInfo  *tbinfo = tdinfo->tdtable;
    2699        7300 :     PQExpBuffer copyBuf = createPQExpBuffer();
    2700        7300 :     PQExpBuffer clistBuf = createPQExpBuffer();
    2701             :     DataDumperPtr dumpFn;
    2702        7300 :     char       *tdDefn = NULL;
    2703             :     char       *copyStmt;
    2704             :     const char *copyFrom;
    2705             : 
    2706             :     /* We had better have loaded per-column details about this table */
    2707             :     Assert(tbinfo->interesting);
    2708             : 
    2709             :     /*
    2710             :      * When load-via-partition-root is set or forced, get the root table name
    2711             :      * for the partition table, so that we can reload data through the root
    2712             :      * table.  Then construct a comment to be inserted into the TOC entry's
    2713             :      * defn field, so that such cases can be identified reliably.
    2714             :      */
    2715        7300 :     if (tbinfo->ispartition &&
    2716        3688 :         (dopt->load_via_partition_root ||
    2717        1844 :          forcePartitionRootLoad(tbinfo)))
    2718          12 :     {
    2719             :         TableInfo  *parentTbinfo;
    2720             : 
    2721          12 :         parentTbinfo = getRootTableInfo(tbinfo);
    2722          12 :         copyFrom = fmtQualifiedDumpable(parentTbinfo);
    2723          12 :         printfPQExpBuffer(copyBuf, "-- load via partition root %s",
    2724             :                           copyFrom);
    2725          12 :         tdDefn = pg_strdup(copyBuf->data);
    2726             :     }
    2727             :     else
    2728        7288 :         copyFrom = fmtQualifiedDumpable(tbinfo);
    2729             : 
    2730        7300 :     if (dopt->dump_inserts == 0)
    2731             :     {
    2732             :         /* Dump/restore using COPY */
    2733        7162 :         dumpFn = dumpTableData_copy;
    2734             :         /* must use 2 steps here 'cause fmtId is nonreentrant */
    2735        7162 :         printfPQExpBuffer(copyBuf, "COPY %s ",
    2736             :                           copyFrom);
    2737        7162 :         appendPQExpBuffer(copyBuf, "%s FROM stdin;\n",
    2738             :                           fmtCopyColumnList(tbinfo, clistBuf));
    2739        7162 :         copyStmt = copyBuf->data;
    2740             :     }
    2741             :     else
    2742             :     {
    2743             :         /* Restore using INSERT */
    2744         138 :         dumpFn = dumpTableData_insert;
    2745         138 :         copyStmt = NULL;
    2746             :     }
    2747             : 
    2748             :     /*
    2749             :      * Note: although the TableDataInfo is a full DumpableObject, we treat its
    2750             :      * dependency on its table as "special" and pass it to ArchiveEntry now.
    2751             :      * See comments for BuildArchiveDependencies.
    2752             :      */
    2753        7300 :     if (tdinfo->dobj.dump & DUMP_COMPONENT_DATA)
    2754             :     {
    2755             :         TocEntry   *te;
    2756             : 
    2757        7300 :         te = ArchiveEntry(fout, tdinfo->dobj.catId, tdinfo->dobj.dumpId,
    2758        7300 :                           ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
    2759             :                                        .namespace = tbinfo->dobj.namespace->dobj.name,
    2760             :                                        .owner = tbinfo->rolname,
    2761             :                                        .description = "TABLE DATA",
    2762             :                                        .section = SECTION_DATA,
    2763             :                                        .createStmt = tdDefn,
    2764             :                                        .copyStmt = copyStmt,
    2765             :                                        .deps = &(tbinfo->dobj.dumpId),
    2766             :                                        .nDeps = 1,
    2767             :                                        .dumpFn = dumpFn,
    2768             :                                        .dumpArg = tdinfo));
    2769             : 
    2770             :         /*
    2771             :          * Set the TocEntry's dataLength in case we are doing a parallel dump
    2772             :          * and want to order dump jobs by table size.  We choose to measure
    2773             :          * dataLength in table pages (including TOAST pages) during dump, so
    2774             :          * no scaling is needed.
    2775             :          *
    2776             :          * However, relpages is declared as "integer" in pg_class, and hence
    2777             :          * also in TableInfo, but it's really BlockNumber a/k/a unsigned int.
    2778             :          * Cast so that we get the right interpretation of table sizes
    2779             :          * exceeding INT_MAX pages.
    2780             :          */
    2781        7300 :         te->dataLength = (BlockNumber) tbinfo->relpages;
    2782        7300 :         te->dataLength += (BlockNumber) tbinfo->toastpages;
    2783             : 
    2784             :         /*
    2785             :          * If pgoff_t is only 32 bits wide, the above refinement is useless,
    2786             :          * and instead we'd better worry about integer overflow.  Clamp to
    2787             :          * INT_MAX if the correct result exceeds that.
    2788             :          */
    2789             :         if (sizeof(te->dataLength) == 4 &&
    2790             :             (tbinfo->relpages < 0 || tbinfo->toastpages < 0 ||
    2791             :              te->dataLength < 0))
    2792             :             te->dataLength = INT_MAX;
    2793             :     }
    2794             : 
    2795        7300 :     destroyPQExpBuffer(copyBuf);
    2796        7300 :     destroyPQExpBuffer(clistBuf);
    2797        7300 : }
    2798             : 
    2799             : /*
    2800             :  * refreshMatViewData -
    2801             :  *    load or refresh the contents of a single materialized view
    2802             :  *
    2803             :  * Actually, this just makes an ArchiveEntry for the REFRESH MATERIALIZED VIEW
    2804             :  * statement.
    2805             :  */
    2806             : static void
    2807         676 : refreshMatViewData(Archive *fout, const TableDataInfo *tdinfo)
    2808             : {
    2809         676 :     TableInfo  *tbinfo = tdinfo->tdtable;
    2810             :     PQExpBuffer q;
    2811             : 
    2812             :     /* If the materialized view is not flagged as populated, skip this. */
    2813         676 :     if (!tbinfo->relispopulated)
    2814         136 :         return;
    2815             : 
    2816         540 :     q = createPQExpBuffer();
    2817             : 
    2818         540 :     appendPQExpBuffer(q, "REFRESH MATERIALIZED VIEW %s;\n",
    2819         540 :                       fmtQualifiedDumpable(tbinfo));
    2820             : 
    2821         540 :     if (tdinfo->dobj.dump & DUMP_COMPONENT_DATA)
    2822         540 :         ArchiveEntry(fout,
    2823             :                      tdinfo->dobj.catId, /* catalog ID */
    2824             :                      tdinfo->dobj.dumpId,    /* dump ID */
    2825         540 :                      ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
    2826             :                                   .namespace = tbinfo->dobj.namespace->dobj.name,
    2827             :                                   .owner = tbinfo->rolname,
    2828             :                                   .description = "MATERIALIZED VIEW DATA",
    2829             :                                   .section = SECTION_POST_DATA,
    2830             :                                   .createStmt = q->data,
    2831             :                                   .deps = tdinfo->dobj.dependencies,
    2832             :                                   .nDeps = tdinfo->dobj.nDeps));
    2833             : 
    2834         540 :     destroyPQExpBuffer(q);
    2835             : }
    2836             : 
    2837             : /*
    2838             :  * getTableData -
    2839             :  *    set up dumpable objects representing the contents of tables
    2840             :  */
    2841             : static void
    2842         304 : getTableData(DumpOptions *dopt, TableInfo *tblinfo, int numTables, char relkind)
    2843             : {
    2844             :     int         i;
    2845             : 
    2846       80262 :     for (i = 0; i < numTables; i++)
    2847             :     {
    2848       79958 :         if (tblinfo[i].dobj.dump & DUMP_COMPONENT_DATA &&
    2849        1636 :             (!relkind || tblinfo[i].relkind == relkind))
    2850       10550 :             makeTableDataInfo(dopt, &(tblinfo[i]));
    2851             :     }
    2852         304 : }
    2853             : 
    2854             : /*
    2855             :  * Make a dumpable object for the data of this specific table
    2856             :  *
    2857             :  * Note: we make a TableDataInfo if and only if we are going to dump the
    2858             :  * table data; the "dump" field in such objects isn't very interesting.
    2859             :  */
    2860             : static void
    2861       10628 : makeTableDataInfo(DumpOptions *dopt, TableInfo *tbinfo)
    2862             : {
    2863             :     TableDataInfo *tdinfo;
    2864             : 
    2865             :     /*
    2866             :      * Nothing to do if we already decided to dump the table.  This will
    2867             :      * happen for "config" tables.
    2868             :      */
    2869       10628 :     if (tbinfo->dataObj != NULL)
    2870           2 :         return;
    2871             : 
    2872             :     /* Skip VIEWs (no data to dump) */
    2873       10626 :     if (tbinfo->relkind == RELKIND_VIEW)
    2874         920 :         return;
    2875             :     /* Skip FOREIGN TABLEs (no data to dump) unless requested explicitly */
    2876        9706 :     if (tbinfo->relkind == RELKIND_FOREIGN_TABLE &&
    2877          76 :         (foreign_servers_include_oids.head == NULL ||
    2878           8 :          !simple_oid_list_member(&foreign_servers_include_oids,
    2879             :                                  tbinfo->foreign_server)))
    2880          74 :         return;
    2881             :     /* Skip partitioned tables (data in partitions) */
    2882        9632 :     if (tbinfo->relkind == RELKIND_PARTITIONED_TABLE)
    2883         876 :         return;
    2884             : 
    2885             :     /* Don't dump data in unlogged tables, if so requested */
    2886        8756 :     if (tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED &&
    2887          82 :         dopt->no_unlogged_table_data)
    2888          36 :         return;
    2889             : 
    2890             :     /* Check that the data is not explicitly excluded */
    2891        8720 :     if (simple_oid_list_member(&tabledata_exclude_oids,
    2892             :                                tbinfo->dobj.catId.oid))
    2893          16 :         return;
    2894             : 
    2895             :     /* OK, let's dump it */
    2896        8704 :     tdinfo = (TableDataInfo *) pg_malloc(sizeof(TableDataInfo));
    2897             : 
    2898        8704 :     if (tbinfo->relkind == RELKIND_MATVIEW)
    2899         676 :         tdinfo->dobj.objType = DO_REFRESH_MATVIEW;
    2900        8028 :     else if (tbinfo->relkind == RELKIND_SEQUENCE)
    2901         728 :         tdinfo->dobj.objType = DO_SEQUENCE_SET;
    2902             :     else
    2903        7300 :         tdinfo->dobj.objType = DO_TABLE_DATA;
    2904             : 
    2905             :     /*
    2906             :      * Note: use tableoid 0 so that this object won't be mistaken for
    2907             :      * something that pg_depend entries apply to.
    2908             :      */
    2909        8704 :     tdinfo->dobj.catId.tableoid = 0;
    2910        8704 :     tdinfo->dobj.catId.oid = tbinfo->dobj.catId.oid;
    2911        8704 :     AssignDumpId(&tdinfo->dobj);
    2912        8704 :     tdinfo->dobj.name = tbinfo->dobj.name;
    2913        8704 :     tdinfo->dobj.namespace = tbinfo->dobj.namespace;
    2914        8704 :     tdinfo->tdtable = tbinfo;
    2915        8704 :     tdinfo->filtercond = NULL;   /* might get set later */
    2916        8704 :     addObjectDependency(&tdinfo->dobj, tbinfo->dobj.dumpId);
    2917             : 
    2918             :     /* A TableDataInfo contains data, of course */
    2919        8704 :     tdinfo->dobj.components |= DUMP_COMPONENT_DATA;
    2920             : 
    2921        8704 :     tbinfo->dataObj = tdinfo;
    2922             : 
    2923             :     /* Make sure that we'll collect per-column info for this table. */
    2924        8704 :     tbinfo->interesting = true;
    2925             : }
    2926             : 
    2927             : /*
    2928             :  * The refresh for a materialized view must be dependent on the refresh for
    2929             :  * any materialized view that this one is dependent on.
    2930             :  *
    2931             :  * This must be called after all the objects are created, but before they are
    2932             :  * sorted.
    2933             :  */
    2934             : static void
    2935         276 : buildMatViewRefreshDependencies(Archive *fout)
    2936             : {
    2937             :     PQExpBuffer query;
    2938             :     PGresult   *res;
    2939             :     int         ntups,
    2940             :                 i;
    2941             :     int         i_classid,
    2942             :                 i_objid,
    2943             :                 i_refobjid;
    2944             : 
    2945             :     /* No Mat Views before 9.3. */
    2946         276 :     if (fout->remoteVersion < 90300)
    2947           0 :         return;
    2948             : 
    2949         276 :     query = createPQExpBuffer();
    2950             : 
    2951         276 :     appendPQExpBufferStr(query, "WITH RECURSIVE w AS "
    2952             :                          "( "
    2953             :                          "SELECT d1.objid, d2.refobjid, c2.relkind AS refrelkind "
    2954             :                          "FROM pg_depend d1 "
    2955             :                          "JOIN pg_class c1 ON c1.oid = d1.objid "
    2956             :                          "AND c1.relkind = " CppAsString2(RELKIND_MATVIEW)
    2957             :                          " JOIN pg_rewrite r1 ON r1.ev_class = d1.objid "
    2958             :                          "JOIN pg_depend d2 ON d2.classid = 'pg_rewrite'::regclass "
    2959             :                          "AND d2.objid = r1.oid "
    2960             :                          "AND d2.refobjid <> d1.objid "
    2961             :                          "JOIN pg_class c2 ON c2.oid = d2.refobjid "
    2962             :                          "AND c2.relkind IN (" CppAsString2(RELKIND_MATVIEW) ","
    2963             :                          CppAsString2(RELKIND_VIEW) ") "
    2964             :                          "WHERE d1.classid = 'pg_class'::regclass "
    2965             :                          "UNION "
    2966             :                          "SELECT w.objid, d3.refobjid, c3.relkind "
    2967             :                          "FROM w "
    2968             :                          "JOIN pg_rewrite r3 ON r3.ev_class = w.refobjid "
    2969             :                          "JOIN pg_depend d3 ON d3.classid = 'pg_rewrite'::regclass "
    2970             :                          "AND d3.objid = r3.oid "
    2971             :                          "AND d3.refobjid <> w.refobjid "
    2972             :                          "JOIN pg_class c3 ON c3.oid = d3.refobjid "
    2973             :                          "AND c3.relkind IN (" CppAsString2(RELKIND_MATVIEW) ","
    2974             :                          CppAsString2(RELKIND_VIEW) ") "
    2975             :                          ") "
    2976             :                          "SELECT 'pg_class'::regclass::oid AS classid, objid, refobjid "
    2977             :                          "FROM w "
    2978             :                          "WHERE refrelkind = " CppAsString2(RELKIND_MATVIEW));
    2979             : 
    2980         276 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    2981             : 
    2982         276 :     ntups = PQntuples(res);
    2983             : 
    2984         276 :     i_classid = PQfnumber(res, "classid");
    2985         276 :     i_objid = PQfnumber(res, "objid");
    2986         276 :     i_refobjid = PQfnumber(res, "refobjid");
    2987             : 
    2988         804 :     for (i = 0; i < ntups; i++)
    2989             :     {
    2990             :         CatalogId   objId;
    2991             :         CatalogId   refobjId;
    2992             :         DumpableObject *dobj;
    2993             :         DumpableObject *refdobj;
    2994             :         TableInfo  *tbinfo;
    2995             :         TableInfo  *reftbinfo;
    2996             : 
    2997         528 :         objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
    2998         528 :         objId.oid = atooid(PQgetvalue(res, i, i_objid));
    2999         528 :         refobjId.tableoid = objId.tableoid;
    3000         528 :         refobjId.oid = atooid(PQgetvalue(res, i, i_refobjid));
    3001             : 
    3002         528 :         dobj = findObjectByCatalogId(objId);
    3003         528 :         if (dobj == NULL)
    3004          96 :             continue;
    3005             : 
    3006             :         Assert(dobj->objType == DO_TABLE);
    3007         528 :         tbinfo = (TableInfo *) dobj;
    3008             :         Assert(tbinfo->relkind == RELKIND_MATVIEW);
    3009         528 :         dobj = (DumpableObject *) tbinfo->dataObj;
    3010         528 :         if (dobj == NULL)
    3011          96 :             continue;
    3012             :         Assert(dobj->objType == DO_REFRESH_MATVIEW);
    3013             : 
    3014         432 :         refdobj = findObjectByCatalogId(refobjId);
    3015         432 :         if (refdobj == NULL)
    3016           0 :             continue;
    3017             : 
    3018             :         Assert(refdobj->objType == DO_TABLE);
    3019         432 :         reftbinfo = (TableInfo *) refdobj;
    3020             :         Assert(reftbinfo->relkind == RELKIND_MATVIEW);
    3021         432 :         refdobj = (DumpableObject *) reftbinfo->dataObj;
    3022         432 :         if (refdobj == NULL)
    3023           0 :             continue;
    3024             :         Assert(refdobj->objType == DO_REFRESH_MATVIEW);
    3025             : 
    3026         432 :         addObjectDependency(dobj, refdobj->dumpId);
    3027             : 
    3028         432 :         if (!reftbinfo->relispopulated)
    3029          68 :             tbinfo->relispopulated = false;
    3030             :     }
    3031             : 
    3032         276 :     PQclear(res);
    3033             : 
    3034         276 :     destroyPQExpBuffer(query);
    3035             : }
    3036             : 
    3037             : /*
    3038             :  * getTableDataFKConstraints -
    3039             :  *    add dump-order dependencies reflecting foreign key constraints
    3040             :  *
    3041             :  * This code is executed only in a data-only dump --- in schema+data dumps
    3042             :  * we handle foreign key issues by not creating the FK constraints until
    3043             :  * after the data is loaded.  In a data-only dump, however, we want to
    3044             :  * order the table data objects in such a way that a table's referenced
    3045             :  * tables are restored first.  (In the presence of circular references or
    3046             :  * self-references this may be impossible; we'll detect and complain about
    3047             :  * that during the dependency sorting step.)
    3048             :  */
    3049             : static void
    3050          12 : getTableDataFKConstraints(void)
    3051             : {
    3052             :     DumpableObject **dobjs;
    3053             :     int         numObjs;
    3054             :     int         i;
    3055             : 
    3056             :     /* Search through all the dumpable objects for FK constraints */
    3057          12 :     getDumpableObjects(&dobjs, &numObjs);
    3058       42790 :     for (i = 0; i < numObjs; i++)
    3059             :     {
    3060       42778 :         if (dobjs[i]->objType == DO_FK_CONSTRAINT)
    3061             :         {
    3062          12 :             ConstraintInfo *cinfo = (ConstraintInfo *) dobjs[i];
    3063             :             TableInfo  *ftable;
    3064             : 
    3065             :             /* Not interesting unless both tables are to be dumped */
    3066          12 :             if (cinfo->contable == NULL ||
    3067          12 :                 cinfo->contable->dataObj == NULL)
    3068           6 :                 continue;
    3069           6 :             ftable = findTableByOid(cinfo->confrelid);
    3070           6 :             if (ftable == NULL ||
    3071           6 :                 ftable->dataObj == NULL)
    3072           0 :                 continue;
    3073             : 
    3074             :             /*
    3075             :              * Okay, make referencing table's TABLE_DATA object depend on the
    3076             :              * referenced table's TABLE_DATA object.
    3077             :              */
    3078           6 :             addObjectDependency(&cinfo->contable->dataObj->dobj,
    3079           6 :                                 ftable->dataObj->dobj.dumpId);
    3080             :         }
    3081             :     }
    3082          12 :     free(dobjs);
    3083          12 : }
    3084             : 
    3085             : 
    3086             : /*
    3087             :  * dumpDatabase:
    3088             :  *  dump the database definition
    3089             :  */
    3090             : static void
    3091         120 : dumpDatabase(Archive *fout)
    3092             : {
    3093         120 :     DumpOptions *dopt = fout->dopt;
    3094         120 :     PQExpBuffer dbQry = createPQExpBuffer();
    3095         120 :     PQExpBuffer delQry = createPQExpBuffer();
    3096         120 :     PQExpBuffer creaQry = createPQExpBuffer();
    3097         120 :     PQExpBuffer labelq = createPQExpBuffer();
    3098         120 :     PGconn     *conn = GetConnection(fout);
    3099             :     PGresult   *res;
    3100             :     int         i_tableoid,
    3101             :                 i_oid,
    3102             :                 i_datname,
    3103             :                 i_datdba,
    3104             :                 i_encoding,
    3105             :                 i_datlocprovider,
    3106             :                 i_collate,
    3107             :                 i_ctype,
    3108             :                 i_datlocale,
    3109             :                 i_daticurules,
    3110             :                 i_frozenxid,
    3111             :                 i_minmxid,
    3112             :                 i_datacl,
    3113             :                 i_acldefault,
    3114             :                 i_datistemplate,
    3115             :                 i_datconnlimit,
    3116             :                 i_datcollversion,
    3117             :                 i_tablespace;
    3118             :     CatalogId   dbCatId;
    3119             :     DumpId      dbDumpId;
    3120             :     DumpableAcl dbdacl;
    3121             :     const char *datname,
    3122             :                *dba,
    3123             :                *encoding,
    3124             :                *datlocprovider,
    3125             :                *collate,
    3126             :                *ctype,
    3127             :                *locale,
    3128             :                *icurules,
    3129             :                *datistemplate,
    3130             :                *datconnlimit,
    3131             :                *tablespace;
    3132             :     uint32      frozenxid,
    3133             :                 minmxid;
    3134             :     char       *qdatname;
    3135             : 
    3136         120 :     pg_log_info("saving database definition");
    3137             : 
    3138             :     /*
    3139             :      * Fetch the database-level properties for this database.
    3140             :      */
    3141         120 :     appendPQExpBufferStr(dbQry, "SELECT tableoid, oid, datname, "
    3142             :                          "datdba, "
    3143             :                          "pg_encoding_to_char(encoding) AS encoding, "
    3144             :                          "datcollate, datctype, datfrozenxid, "
    3145             :                          "datacl, acldefault('d', datdba) AS acldefault, "
    3146             :                          "datistemplate, datconnlimit, ");
    3147         120 :     if (fout->remoteVersion >= 90300)
    3148         120 :         appendPQExpBufferStr(dbQry, "datminmxid, ");
    3149             :     else
    3150           0 :         appendPQExpBufferStr(dbQry, "0 AS datminmxid, ");
    3151         120 :     if (fout->remoteVersion >= 170000)
    3152         120 :         appendPQExpBufferStr(dbQry, "datlocprovider, datlocale, datcollversion, ");
    3153           0 :     else if (fout->remoteVersion >= 150000)
    3154           0 :         appendPQExpBufferStr(dbQry, "datlocprovider, daticulocale AS datlocale, datcollversion, ");
    3155             :     else
    3156           0 :         appendPQExpBufferStr(dbQry, "'c' AS datlocprovider, NULL AS datlocale, NULL AS datcollversion, ");
    3157         120 :     if (fout->remoteVersion >= 160000)
    3158         120 :         appendPQExpBufferStr(dbQry, "daticurules, ");
    3159             :     else
    3160           0 :         appendPQExpBufferStr(dbQry, "NULL AS daticurules, ");
    3161         120 :     appendPQExpBufferStr(dbQry,
    3162             :                          "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace, "
    3163             :                          "shobj_description(oid, 'pg_database') AS description "
    3164             :                          "FROM pg_database "
    3165             :                          "WHERE datname = current_database()");
    3166             : 
    3167         120 :     res = ExecuteSqlQueryForSingleRow(fout, dbQry->data);
    3168             : 
    3169         120 :     i_tableoid = PQfnumber(res, "tableoid");
    3170         120 :     i_oid = PQfnumber(res, "oid");
    3171         120 :     i_datname = PQfnumber(res, "datname");
    3172         120 :     i_datdba = PQfnumber(res, "datdba");
    3173         120 :     i_encoding = PQfnumber(res, "encoding");
    3174         120 :     i_datlocprovider = PQfnumber(res, "datlocprovider");
    3175         120 :     i_collate = PQfnumber(res, "datcollate");
    3176         120 :     i_ctype = PQfnumber(res, "datctype");
    3177         120 :     i_datlocale = PQfnumber(res, "datlocale");
    3178         120 :     i_daticurules = PQfnumber(res, "daticurules");
    3179         120 :     i_frozenxid = PQfnumber(res, "datfrozenxid");
    3180         120 :     i_minmxid = PQfnumber(res, "datminmxid");
    3181         120 :     i_datacl = PQfnumber(res, "datacl");
    3182         120 :     i_acldefault = PQfnumber(res, "acldefault");
    3183         120 :     i_datistemplate = PQfnumber(res, "datistemplate");
    3184         120 :     i_datconnlimit = PQfnumber(res, "datconnlimit");
    3185         120 :     i_datcollversion = PQfnumber(res, "datcollversion");
    3186         120 :     i_tablespace = PQfnumber(res, "tablespace");
    3187             : 
    3188         120 :     dbCatId.tableoid = atooid(PQgetvalue(res, 0, i_tableoid));
    3189         120 :     dbCatId.oid = atooid(PQgetvalue(res, 0, i_oid));
    3190         120 :     datname = PQgetvalue(res, 0, i_datname);
    3191         120 :     dba = getRoleName(PQgetvalue(res, 0, i_datdba));
    3192         120 :     encoding = PQgetvalue(res, 0, i_encoding);
    3193         120 :     datlocprovider = PQgetvalue(res, 0, i_datlocprovider);
    3194         120 :     collate = PQgetvalue(res, 0, i_collate);
    3195         120 :     ctype = PQgetvalue(res, 0, i_ctype);
    3196         120 :     if (!PQgetisnull(res, 0, i_datlocale))
    3197          28 :         locale = PQgetvalue(res, 0, i_datlocale);
    3198             :     else
    3199          92 :         locale = NULL;
    3200         120 :     if (!PQgetisnull(res, 0, i_daticurules))
    3201           0 :         icurules = PQgetvalue(res, 0, i_daticurules);
    3202             :     else
    3203         120 :         icurules = NULL;
    3204         120 :     frozenxid = atooid(PQgetvalue(res, 0, i_frozenxid));
    3205         120 :     minmxid = atooid(PQgetvalue(res, 0, i_minmxid));
    3206         120 :     dbdacl.acl = PQgetvalue(res, 0, i_datacl);
    3207         120 :     dbdacl.acldefault = PQgetvalue(res, 0, i_acldefault);
    3208         120 :     datistemplate = PQgetvalue(res, 0, i_datistemplate);
    3209         120 :     datconnlimit = PQgetvalue(res, 0, i_datconnlimit);
    3210         120 :     tablespace = PQgetvalue(res, 0, i_tablespace);
    3211             : 
    3212         120 :     qdatname = pg_strdup(fmtId(datname));
    3213             : 
    3214             :     /*
    3215             :      * Prepare the CREATE DATABASE command.  We must specify OID (if we want
    3216             :      * to preserve that), as well as the encoding, locale, and tablespace
    3217             :      * since those can't be altered later.  Other DB properties are left to
    3218             :      * the DATABASE PROPERTIES entry, so that they can be applied after
    3219             :      * reconnecting to the target DB.
    3220             :      *
    3221             :      * For binary upgrade, we use the FILE_COPY strategy because testing has
    3222             :      * shown it to be faster.  When the server is in binary upgrade mode, it
    3223             :      * will also skip the checkpoints this strategy ordinarily performs.
    3224             :      */
    3225         120 :     if (dopt->binary_upgrade)
    3226             :     {
    3227          26 :         appendPQExpBuffer(creaQry,
    3228             :                           "CREATE DATABASE %s WITH TEMPLATE = template0 "
    3229             :                           "OID = %u STRATEGY = FILE_COPY",
    3230             :                           qdatname, dbCatId.oid);
    3231             :     }
    3232             :     else
    3233             :     {
    3234          94 :         appendPQExpBuffer(creaQry, "CREATE DATABASE %s WITH TEMPLATE = template0",
    3235             :                           qdatname);
    3236             :     }
    3237         120 :     if (strlen(encoding) > 0)
    3238             :     {
    3239         120 :         appendPQExpBufferStr(creaQry, " ENCODING = ");
    3240         120 :         appendStringLiteralAH(creaQry, encoding, fout);
    3241             :     }
    3242             : 
    3243         120 :     appendPQExpBufferStr(creaQry, " LOCALE_PROVIDER = ");
    3244         120 :     if (datlocprovider[0] == 'b')
    3245          28 :         appendPQExpBufferStr(creaQry, "builtin");
    3246          92 :     else if (datlocprovider[0] == 'c')
    3247          92 :         appendPQExpBufferStr(creaQry, "libc");
    3248           0 :     else if (datlocprovider[0] == 'i')
    3249           0 :         appendPQExpBufferStr(creaQry, "icu");
    3250             :     else
    3251           0 :         pg_fatal("unrecognized locale provider: %s",
    3252             :                  datlocprovider);
    3253             : 
    3254         120 :     if (strlen(collate) > 0 && strcmp(collate, ctype) == 0)
    3255             :     {
    3256         120 :         appendPQExpBufferStr(creaQry, " LOCALE = ");
    3257         120 :         appendStringLiteralAH(creaQry, collate, fout);
    3258             :     }
    3259             :     else
    3260             :     {
    3261           0 :         if (strlen(collate) > 0)
    3262             :         {
    3263           0 :             appendPQExpBufferStr(creaQry, " LC_COLLATE = ");
    3264           0 :             appendStringLiteralAH(creaQry, collate, fout);
    3265             :         }
    3266           0 :         if (strlen(ctype) > 0)
    3267             :         {
    3268           0 :             appendPQExpBufferStr(creaQry, " LC_CTYPE = ");
    3269           0 :             appendStringLiteralAH(creaQry, ctype, fout);
    3270             :         }
    3271             :     }
    3272         120 :     if (locale)
    3273             :     {
    3274          28 :         if (datlocprovider[0] == 'b')
    3275          28 :             appendPQExpBufferStr(creaQry, " BUILTIN_LOCALE = ");
    3276             :         else
    3277           0 :             appendPQExpBufferStr(creaQry, " ICU_LOCALE = ");
    3278             : 
    3279          28 :         appendStringLiteralAH(creaQry, locale, fout);
    3280             :     }
    3281             : 
    3282         120 :     if (icurules)
    3283             :     {
    3284           0 :         appendPQExpBufferStr(creaQry, " ICU_RULES = ");
    3285           0 :         appendStringLiteralAH(creaQry, icurules, fout);
    3286             :     }
    3287             : 
    3288             :     /*
    3289             :      * For binary upgrade, carry over the collation version.  For normal
    3290             :      * dump/restore, omit the version, so that it is computed upon restore.
    3291             :      */
    3292         120 :     if (dopt->binary_upgrade)
    3293             :     {
    3294          26 :         if (!PQgetisnull(res, 0, i_datcollversion))
    3295             :         {
    3296          26 :             appendPQExpBufferStr(creaQry, " COLLATION_VERSION = ");
    3297          26 :             appendStringLiteralAH(creaQry,
    3298             :                                   PQgetvalue(res, 0, i_datcollversion),
    3299             :                                   fout);
    3300             :         }
    3301             :     }
    3302             : 
    3303             :     /*
    3304             :      * Note: looking at dopt->outputNoTablespaces here is completely the wrong
    3305             :      * thing; the decision whether to specify a tablespace should be left till
    3306             :      * pg_restore, so that pg_restore --no-tablespaces applies.  Ideally we'd
    3307             :      * label the DATABASE entry with the tablespace and let the normal
    3308             :      * tablespace selection logic work ... but CREATE DATABASE doesn't pay
    3309             :      * attention to default_tablespace, so that won't work.
    3310             :      */
    3311         120 :     if (strlen(tablespace) > 0 && strcmp(tablespace, "pg_default") != 0 &&
    3312           0 :         !dopt->outputNoTablespaces)
    3313           0 :         appendPQExpBuffer(creaQry, " TABLESPACE = %s",
    3314             :                           fmtId(tablespace));
    3315         120 :     appendPQExpBufferStr(creaQry, ";\n");
    3316             : 
    3317         120 :     appendPQExpBuffer(delQry, "DROP DATABASE %s;\n",
    3318             :                       qdatname);
    3319             : 
    3320         120 :     dbDumpId = createDumpId();
    3321             : 
    3322         120 :     ArchiveEntry(fout,
    3323             :                  dbCatId,       /* catalog ID */
    3324             :                  dbDumpId,      /* dump ID */
    3325         120 :                  ARCHIVE_OPTS(.tag = datname,
    3326             :                               .owner = dba,
    3327             :                               .description = "DATABASE",
    3328             :                               .section = SECTION_PRE_DATA,
    3329             :                               .createStmt = creaQry->data,
    3330             :                               .dropStmt = delQry->data));
    3331             : 
    3332             :     /* Compute correct tag for archive entry */
    3333         120 :     appendPQExpBuffer(labelq, "DATABASE %s", qdatname);
    3334             : 
    3335             :     /* Dump DB comment if any */
    3336             :     {
    3337             :         /*
    3338             :          * 8.2 and up keep comments on shared objects in a shared table, so we
    3339             :          * cannot use the dumpComment() code used for other database objects.
    3340             :          * Be careful that the ArchiveEntry parameters match that function.
    3341             :          */
    3342         120 :         char       *comment = PQgetvalue(res, 0, PQfnumber(res, "description"));
    3343             : 
    3344         120 :         if (comment && *comment && !dopt->no_comments)
    3345             :         {
    3346          50 :             resetPQExpBuffer(dbQry);
    3347             : 
    3348             :             /*
    3349             :              * Generates warning when loaded into a differently-named
    3350             :              * database.
    3351             :              */
    3352          50 :             appendPQExpBuffer(dbQry, "COMMENT ON DATABASE %s IS ", qdatname);
    3353          50 :             appendStringLiteralAH(dbQry, comment, fout);
    3354          50 :             appendPQExpBufferStr(dbQry, ";\n");
    3355             : 
    3356          50 :             ArchiveEntry(fout, nilCatalogId, createDumpId(),
    3357          50 :                          ARCHIVE_OPTS(.tag = labelq->data,
    3358             :                                       .owner = dba,
    3359             :                                       .description = "COMMENT",
    3360             :                                       .section = SECTION_NONE,
    3361             :                                       .createStmt = dbQry->data,
    3362             :                                       .deps = &dbDumpId,
    3363             :                                       .nDeps = 1));
    3364             :         }
    3365             :     }
    3366             : 
    3367             :     /* Dump DB security label, if enabled */
    3368         120 :     if (!dopt->no_security_labels)
    3369             :     {
    3370             :         PGresult   *shres;
    3371             :         PQExpBuffer seclabelQry;
    3372             : 
    3373         120 :         seclabelQry = createPQExpBuffer();
    3374             : 
    3375         120 :         buildShSecLabelQuery("pg_database", dbCatId.oid, seclabelQry);
    3376         120 :         shres = ExecuteSqlQuery(fout, seclabelQry->data, PGRES_TUPLES_OK);
    3377         120 :         resetPQExpBuffer(seclabelQry);
    3378         120 :         emitShSecLabels(conn, shres, seclabelQry, "DATABASE", datname);
    3379         120 :         if (seclabelQry->len > 0)
    3380           0 :             ArchiveEntry(fout, nilCatalogId, createDumpId(),
    3381           0 :                          ARCHIVE_OPTS(.tag = labelq->data,
    3382             :                                       .owner = dba,
    3383             :                                       .description = "SECURITY LABEL",
    3384             :                                       .section = SECTION_NONE,
    3385             :                                       .createStmt = seclabelQry->data,
    3386             :                                       .deps = &dbDumpId,
    3387             :                                       .nDeps = 1));
    3388         120 :         destroyPQExpBuffer(seclabelQry);
    3389         120 :         PQclear(shres);
    3390             :     }
    3391             : 
    3392             :     /*
    3393             :      * Dump ACL if any.  Note that we do not support initial privileges
    3394             :      * (pg_init_privs) on databases.
    3395             :      */
    3396         120 :     dbdacl.privtype = 0;
    3397         120 :     dbdacl.initprivs = NULL;
    3398             : 
    3399         120 :     dumpACL(fout, dbDumpId, InvalidDumpId, "DATABASE",
    3400             :             qdatname, NULL, NULL,
    3401             :             NULL, dba, &dbdacl);
    3402             : 
    3403             :     /*
    3404             :      * Now construct a DATABASE PROPERTIES archive entry to restore any
    3405             :      * non-default database-level properties.  (The reason this must be
    3406             :      * separate is that we cannot put any additional commands into the TOC
    3407             :      * entry that has CREATE DATABASE.  pg_restore would execute such a group
    3408             :      * in an implicit transaction block, and the backend won't allow CREATE
    3409             :      * DATABASE in that context.)
    3410             :      */
    3411         120 :     resetPQExpBuffer(creaQry);
    3412         120 :     resetPQExpBuffer(delQry);
    3413             : 
    3414         120 :     if (strlen(datconnlimit) > 0 && strcmp(datconnlimit, "-1") != 0)
    3415           0 :         appendPQExpBuffer(creaQry, "ALTER DATABASE %s CONNECTION LIMIT = %s;\n",
    3416             :                           qdatname, datconnlimit);
    3417             : 
    3418         120 :     if (strcmp(datistemplate, "t") == 0)
    3419             :     {
    3420           8 :         appendPQExpBuffer(creaQry, "ALTER DATABASE %s IS_TEMPLATE = true;\n",
    3421             :                           qdatname);
    3422             : 
    3423             :         /*
    3424             :          * The backend won't accept DROP DATABASE on a template database.  We
    3425             :          * can deal with that by removing the template marking before the DROP
    3426             :          * gets issued.  We'd prefer to use ALTER DATABASE IF EXISTS here, but
    3427             :          * since no such command is currently supported, fake it with a direct
    3428             :          * UPDATE on pg_database.
    3429             :          */
    3430           8 :         appendPQExpBufferStr(delQry, "UPDATE pg_catalog.pg_database "
    3431             :                              "SET datistemplate = false WHERE datname = ");
    3432           8 :         appendStringLiteralAH(delQry, datname, fout);
    3433           8 :         appendPQExpBufferStr(delQry, ";\n");
    3434             :     }
    3435             : 
    3436             :     /*
    3437             :      * We do not restore pg_database.dathasloginevt because it is set
    3438             :      * automatically on login event trigger creation.
    3439             :      */
    3440             : 
    3441             :     /* Add database-specific SET options */
    3442         120 :     dumpDatabaseConfig(fout, creaQry, datname, dbCatId.oid);
    3443             : 
    3444             :     /*
    3445             :      * We stick this binary-upgrade query into the DATABASE PROPERTIES archive
    3446             :      * entry, too, for lack of a better place.
    3447             :      */
    3448         120 :     if (dopt->binary_upgrade)
    3449             :     {
    3450          26 :         appendPQExpBufferStr(creaQry, "\n-- For binary upgrade, set datfrozenxid and datminmxid.\n");
    3451          26 :         appendPQExpBuffer(creaQry, "UPDATE pg_catalog.pg_database\n"
    3452             :                           "SET datfrozenxid = '%u', datminmxid = '%u'\n"
    3453             :                           "WHERE datname = ",
    3454             :                           frozenxid, minmxid);
    3455          26 :         appendStringLiteralAH(creaQry, datname, fout);
    3456          26 :         appendPQExpBufferStr(creaQry, ";\n");
    3457             :     }
    3458             : 
    3459         120 :     if (creaQry->len > 0)
    3460          34 :         ArchiveEntry(fout, nilCatalogId, createDumpId(),
    3461          34 :                      ARCHIVE_OPTS(.tag = datname,
    3462             :                                   .owner = dba,
    3463             :                                   .description = "DATABASE PROPERTIES",
    3464             :                                   .section = SECTION_PRE_DATA,
    3465             :                                   .createStmt = creaQry->data,
    3466             :                                   .dropStmt = delQry->data,
    3467             :                                   .deps = &dbDumpId));
    3468             : 
    3469             :     /*
    3470             :      * pg_largeobject comes from the old system intact, so set its
    3471             :      * relfrozenxids, relminmxids and relfilenode.
    3472             :      */
    3473         120 :     if (dopt->binary_upgrade)
    3474             :     {
    3475             :         PGresult   *lo_res;
    3476          26 :         PQExpBuffer loFrozenQry = createPQExpBuffer();
    3477          26 :         PQExpBuffer loOutQry = createPQExpBuffer();
    3478          26 :         PQExpBuffer loHorizonQry = createPQExpBuffer();
    3479             :         int         ii_relfrozenxid,
    3480             :                     ii_relfilenode,
    3481             :                     ii_oid,
    3482             :                     ii_relminmxid;
    3483             : 
    3484             :         /*
    3485             :          * pg_largeobject
    3486             :          */
    3487          26 :         if (fout->remoteVersion >= 90300)
    3488          26 :             appendPQExpBuffer(loFrozenQry, "SELECT relfrozenxid, relminmxid, relfilenode, oid\n"
    3489             :                               "FROM pg_catalog.pg_class\n"
    3490             :                               "WHERE oid IN (%u, %u);\n",
    3491             :                               LargeObjectRelationId, LargeObjectLOidPNIndexId);
    3492             :         else
    3493           0 :             appendPQExpBuffer(loFrozenQry, "SELECT relfrozenxid, 0 AS relminmxid, relfilenode, oid\n"
    3494             :                               "FROM pg_catalog.pg_class\n"
    3495             :                               "WHERE oid IN (%u, %u);\n",
    3496             :                               LargeObjectRelationId, LargeObjectLOidPNIndexId);
    3497             : 
    3498          26 :         lo_res = ExecuteSqlQuery(fout, loFrozenQry->data, PGRES_TUPLES_OK);
    3499             : 
    3500          26 :         ii_relfrozenxid = PQfnumber(lo_res, "relfrozenxid");
    3501          26 :         ii_relminmxid = PQfnumber(lo_res, "relminmxid");
    3502          26 :         ii_relfilenode = PQfnumber(lo_res, "relfilenode");
    3503          26 :         ii_oid = PQfnumber(lo_res, "oid");
    3504             : 
    3505          26 :         appendPQExpBufferStr(loHorizonQry, "\n-- For binary upgrade, set pg_largeobject relfrozenxid and relminmxid\n");
    3506          26 :         appendPQExpBufferStr(loOutQry, "\n-- For binary upgrade, preserve pg_largeobject and index relfilenodes\n");
    3507          78 :         for (int i = 0; i < PQntuples(lo_res); ++i)
    3508             :         {
    3509             :             Oid         oid;
    3510             :             RelFileNumber relfilenumber;
    3511             : 
    3512          52 :             appendPQExpBuffer(loHorizonQry, "UPDATE pg_catalog.pg_class\n"
    3513             :                               "SET relfrozenxid = '%u', relminmxid = '%u'\n"
    3514             :                               "WHERE oid = %u;\n",
    3515          52 :                               atooid(PQgetvalue(lo_res, i, ii_relfrozenxid)),
    3516          52 :                               atooid(PQgetvalue(lo_res, i, ii_relminmxid)),
    3517          52 :                               atooid(PQgetvalue(lo_res, i, ii_oid)));
    3518             : 
    3519          52 :             oid = atooid(PQgetvalue(lo_res, i, ii_oid));
    3520          52 :             relfilenumber = atooid(PQgetvalue(lo_res, i, ii_relfilenode));
    3521             : 
    3522          52 :             if (oid == LargeObjectRelationId)
    3523          26 :                 appendPQExpBuffer(loOutQry,
    3524             :                                   "SELECT pg_catalog.binary_upgrade_set_next_heap_relfilenode('%u'::pg_catalog.oid);\n",
    3525             :                                   relfilenumber);
    3526          26 :             else if (oid == LargeObjectLOidPNIndexId)
    3527          26 :                 appendPQExpBuffer(loOutQry,
    3528             :                                   "SELECT pg_catalog.binary_upgrade_set_next_index_relfilenode('%u'::pg_catalog.oid);\n",
    3529             :                                   relfilenumber);
    3530             :         }
    3531             : 
    3532          26 :         appendPQExpBufferStr(loOutQry,
    3533             :                              "TRUNCATE pg_catalog.pg_largeobject;\n");
    3534          26 :         appendPQExpBufferStr(loOutQry, loHorizonQry->data);
    3535             : 
    3536          26 :         ArchiveEntry(fout, nilCatalogId, createDumpId(),
    3537          26 :                      ARCHIVE_OPTS(.tag = "pg_largeobject",
    3538             :                                   .description = "pg_largeobject",
    3539             :                                   .section = SECTION_PRE_DATA,
    3540             :                                   .createStmt = loOutQry->data));
    3541             : 
    3542          26 :         PQclear(lo_res);
    3543             : 
    3544          26 :         destroyPQExpBuffer(loFrozenQry);
    3545          26 :         destroyPQExpBuffer(loHorizonQry);
    3546          26 :         destroyPQExpBuffer(loOutQry);
    3547             :     }
    3548             : 
    3549         120 :     PQclear(res);
    3550             : 
    3551         120 :     free(qdatname);
    3552         120 :     destroyPQExpBuffer(dbQry);
    3553         120 :     destroyPQExpBuffer(delQry);
    3554         120 :     destroyPQExpBuffer(creaQry);
    3555         120 :     destroyPQExpBuffer(labelq);
    3556         120 : }
    3557             : 
    3558             : /*
    3559             :  * Collect any database-specific or role-and-database-specific SET options
    3560             :  * for this database, and append them to outbuf.
    3561             :  */
    3562             : static void
    3563         120 : dumpDatabaseConfig(Archive *AH, PQExpBuffer outbuf,
    3564             :                    const char *dbname, Oid dboid)
    3565             : {
    3566         120 :     PGconn     *conn = GetConnection(AH);
    3567         120 :     PQExpBuffer buf = createPQExpBuffer();
    3568             :     PGresult   *res;
    3569             : 
    3570             :     /* First collect database-specific options */
    3571         120 :     printfPQExpBuffer(buf, "SELECT unnest(setconfig) FROM pg_db_role_setting "
    3572             :                       "WHERE setrole = 0 AND setdatabase = '%u'::oid",
    3573             :                       dboid);
    3574             : 
    3575         120 :     res = ExecuteSqlQuery(AH, buf->data, PGRES_TUPLES_OK);
    3576             : 
    3577         180 :     for (int i = 0; i < PQntuples(res); i++)
    3578          60 :         makeAlterConfigCommand(conn, PQgetvalue(res, i, 0),
    3579             :                                "DATABASE", dbname, NULL, NULL,
    3580             :                                outbuf);
    3581             : 
    3582         120 :     PQclear(res);
    3583             : 
    3584             :     /* Now look for role-and-database-specific options */
    3585         120 :     printfPQExpBuffer(buf, "SELECT rolname, unnest(setconfig) "
    3586             :                       "FROM pg_db_role_setting s, pg_roles r "
    3587             :                       "WHERE setrole = r.oid AND setdatabase = '%u'::oid",
    3588             :                       dboid);
    3589             : 
    3590         120 :     res = ExecuteSqlQuery(AH, buf->data, PGRES_TUPLES_OK);
    3591             : 
    3592         120 :     for (int i = 0; i < PQntuples(res); i++)
    3593           0 :         makeAlterConfigCommand(conn, PQgetvalue(res, i, 1),
    3594           0 :                                "ROLE", PQgetvalue(res, i, 0),
    3595             :                                "DATABASE", dbname,
    3596             :                                outbuf);
    3597             : 
    3598         120 :     PQclear(res);
    3599             : 
    3600         120 :     destroyPQExpBuffer(buf);
    3601         120 : }
    3602             : 
    3603             : /*
    3604             :  * dumpEncoding: put the correct encoding into the archive
    3605             :  */
    3606             : static void
    3607         308 : dumpEncoding(Archive *AH)
    3608             : {
    3609         308 :     const char *encname = pg_encoding_to_char(AH->encoding);
    3610         308 :     PQExpBuffer qry = createPQExpBuffer();
    3611             : 
    3612         308 :     pg_log_info("saving encoding = %s", encname);
    3613             : 
    3614         308 :     appendPQExpBufferStr(qry, "SET client_encoding = ");
    3615         308 :     appendStringLiteralAH(qry, encname, AH);
    3616         308 :     appendPQExpBufferStr(qry, ";\n");
    3617             : 
    3618         308 :     ArchiveEntry(AH, nilCatalogId, createDumpId(),
    3619         308 :                  ARCHIVE_OPTS(.tag = "ENCODING",
    3620             :                               .description = "ENCODING",
    3621             :                               .section = SECTION_PRE_DATA,
    3622             :                               .createStmt = qry->data));
    3623             : 
    3624         308 :     destroyPQExpBuffer(qry);
    3625         308 : }
    3626             : 
    3627             : 
    3628             : /*
    3629             :  * dumpStdStrings: put the correct escape string behavior into the archive
    3630             :  */
    3631             : static void
    3632         308 : dumpStdStrings(Archive *AH)
    3633             : {
    3634         308 :     const char *stdstrings = AH->std_strings ? "on" : "off";
    3635         308 :     PQExpBuffer qry = createPQExpBuffer();
    3636             : 
    3637         308 :     pg_log_info("saving \"standard_conforming_strings = %s\"",
    3638             :                 stdstrings);
    3639             : 
    3640         308 :     appendPQExpBuffer(qry, "SET standard_conforming_strings = '%s';\n",
    3641             :                       stdstrings);
    3642             : 
    3643         308 :     ArchiveEntry(AH, nilCatalogId, createDumpId(),
    3644         308 :                  ARCHIVE_OPTS(.tag = "STDSTRINGS",
    3645             :                               .description = "STDSTRINGS",
    3646             :                               .section = SECTION_PRE_DATA,
    3647             :                               .createStmt = qry->data));
    3648             : 
    3649         308 :     destroyPQExpBuffer(qry);
    3650         308 : }
    3651             : 
    3652             : /*
    3653             :  * dumpSearchPath: record the active search_path in the archive
    3654             :  */
    3655             : static void
    3656         308 : dumpSearchPath(Archive *AH)
    3657             : {
    3658         308 :     PQExpBuffer qry = createPQExpBuffer();
    3659         308 :     PQExpBuffer path = createPQExpBuffer();
    3660             :     PGresult   *res;
    3661         308 :     char      **schemanames = NULL;
    3662         308 :     int         nschemanames = 0;
    3663             :     int         i;
    3664             : 
    3665             :     /*
    3666             :      * We use the result of current_schemas(), not the search_path GUC,
    3667             :      * because that might contain wildcards such as "$user", which won't
    3668             :      * necessarily have the same value during restore.  Also, this way avoids
    3669             :      * listing schemas that may appear in search_path but not actually exist,
    3670             :      * which seems like a prudent exclusion.
    3671             :      */
    3672         308 :     res = ExecuteSqlQueryForSingleRow(AH,
    3673             :                                       "SELECT pg_catalog.current_schemas(false)");
    3674             : 
    3675         308 :     if (!parsePGArray(PQgetvalue(res, 0, 0), &schemanames, &nschemanames))
    3676           0 :         pg_fatal("could not parse result of current_schemas()");
    3677             : 
    3678             :     /*
    3679             :      * We use set_config(), not a simple "SET search_path" command, because
    3680             :      * the latter has less-clean behavior if the search path is empty.  While
    3681             :      * that's likely to get fixed at some point, it seems like a good idea to
    3682             :      * be as backwards-compatible as possible in what we put into archives.
    3683             :      */
    3684         308 :     for (i = 0; i < nschemanames; i++)
    3685             :     {
    3686           0 :         if (i > 0)
    3687           0 :             appendPQExpBufferStr(path, ", ");
    3688           0 :         appendPQExpBufferStr(path, fmtId(schemanames[i]));
    3689             :     }
    3690             : 
    3691         308 :     appendPQExpBufferStr(qry, "SELECT pg_catalog.set_config('search_path', ");
    3692         308 :     appendStringLiteralAH(qry, path->data, AH);
    3693         308 :     appendPQExpBufferStr(qry, ", false);\n");
    3694             : 
    3695         308 :     pg_log_info("saving \"search_path = %s\"", path->data);
    3696             : 
    3697         308 :     ArchiveEntry(AH, nilCatalogId, createDumpId(),
    3698         308 :                  ARCHIVE_OPTS(.tag = "SEARCHPATH",
    3699             :                               .description = "SEARCHPATH",
    3700             :                               .section = SECTION_PRE_DATA,
    3701             :                               .createStmt = qry->data));
    3702             : 
    3703             :     /* Also save it in AH->searchpath, in case we're doing plain text dump */
    3704         308 :     AH->searchpath = pg_strdup(qry->data);
    3705             : 
    3706         308 :     free(schemanames);
    3707         308 :     PQclear(res);
    3708         308 :     destroyPQExpBuffer(qry);
    3709         308 :     destroyPQExpBuffer(path);
    3710         308 : }
    3711             : 
    3712             : 
    3713             : /*
    3714             :  * getLOs:
    3715             :  *  Collect schema-level data about large objects
    3716             :  */
    3717             : static void
    3718         256 : getLOs(Archive *fout)
    3719             : {
    3720         256 :     DumpOptions *dopt = fout->dopt;
    3721         256 :     PQExpBuffer loQry = createPQExpBuffer();
    3722             :     PGresult   *res;
    3723             :     int         ntups;
    3724             :     int         i;
    3725             :     int         n;
    3726             :     int         i_oid;
    3727             :     int         i_lomowner;
    3728             :     int         i_lomacl;
    3729             :     int         i_acldefault;
    3730             : 
    3731         256 :     pg_log_info("reading large objects");
    3732             : 
    3733             :     /*
    3734             :      * Fetch LO OIDs and owner/ACL data.  Order the data so that all the blobs
    3735             :      * with the same owner/ACL appear together.
    3736             :      */
    3737         256 :     appendPQExpBufferStr(loQry,
    3738             :                          "SELECT oid, lomowner, lomacl, "
    3739             :                          "acldefault('L', lomowner) AS acldefault "
    3740             :                          "FROM pg_largeobject_metadata "
    3741             :                          "ORDER BY lomowner, lomacl::pg_catalog.text, oid");
    3742             : 
    3743         256 :     res = ExecuteSqlQuery(fout, loQry->data, PGRES_TUPLES_OK);
    3744             : 
    3745         256 :     i_oid = PQfnumber(res, "oid");
    3746         256 :     i_lomowner = PQfnumber(res, "lomowner");
    3747         256 :     i_lomacl = PQfnumber(res, "lomacl");
    3748         256 :     i_acldefault = PQfnumber(res, "acldefault");
    3749             : 
    3750         256 :     ntups = PQntuples(res);
    3751             : 
    3752             :     /*
    3753             :      * Group the blobs into suitably-sized groups that have the same owner and
    3754             :      * ACL setting, and build a metadata and a data DumpableObject for each
    3755             :      * group.  (If we supported initprivs for blobs, we'd have to insist that
    3756             :      * groups also share initprivs settings, since the DumpableObject only has
    3757             :      * room for one.)  i is the index of the first tuple in the current group,
    3758             :      * and n is the number of tuples we include in the group.
    3759             :      */
    3760         402 :     for (i = 0; i < ntups; i += n)
    3761             :     {
    3762         146 :         Oid         thisoid = atooid(PQgetvalue(res, i, i_oid));
    3763         146 :         char       *thisowner = PQgetvalue(res, i, i_lomowner);
    3764         146 :         char       *thisacl = PQgetvalue(res, i, i_lomacl);
    3765             :         LoInfo     *loinfo;
    3766             :         DumpableObject *lodata;
    3767             :         char        namebuf[64];
    3768             : 
    3769             :         /* Scan to find first tuple not to be included in group */
    3770         146 :         n = 1;
    3771         166 :         while (n < MAX_BLOBS_PER_ARCHIVE_ENTRY && i + n < ntups)
    3772             :         {
    3773          88 :             if (strcmp(thisowner, PQgetvalue(res, i + n, i_lomowner)) != 0 ||
    3774          88 :                 strcmp(thisacl, PQgetvalue(res, i + n, i_lomacl)) != 0)
    3775             :                 break;
    3776          20 :             n++;
    3777             :         }
    3778             : 
    3779             :         /* Build the metadata DumpableObject */
    3780         146 :         loinfo = (LoInfo *) pg_malloc(offsetof(LoInfo, looids) + n * sizeof(Oid));
    3781             : 
    3782         146 :         loinfo->dobj.objType = DO_LARGE_OBJECT;
    3783         146 :         loinfo->dobj.catId.tableoid = LargeObjectRelationId;
    3784         146 :         loinfo->dobj.catId.oid = thisoid;
    3785         146 :         AssignDumpId(&loinfo->dobj);
    3786             : 
    3787         146 :         if (n > 1)
    3788          10 :             snprintf(namebuf, sizeof(namebuf), "%u..%u", thisoid,
    3789          10 :                      atooid(PQgetvalue(res, i + n - 1, i_oid)));
    3790             :         else
    3791         136 :             snprintf(namebuf, sizeof(namebuf), "%u", thisoid);
    3792         146 :         loinfo->dobj.name = pg_strdup(namebuf);
    3793         146 :         loinfo->dacl.acl = pg_strdup(thisacl);
    3794         146 :         loinfo->dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
    3795         146 :         loinfo->dacl.privtype = 0;
    3796         146 :         loinfo->dacl.initprivs = NULL;
    3797         146 :         loinfo->rolname = getRoleName(thisowner);
    3798         146 :         loinfo->numlos = n;
    3799         146 :         loinfo->looids[0] = thisoid;
    3800             :         /* Collect OIDs of the remaining blobs in this group */
    3801         166 :         for (int k = 1; k < n; k++)
    3802             :         {
    3803             :             CatalogId   extraID;
    3804             : 
    3805          20 :             loinfo->looids[k] = atooid(PQgetvalue(res, i + k, i_oid));
    3806             : 
    3807             :             /* Make sure we can look up loinfo by any of the blobs' OIDs */
    3808          20 :             extraID.tableoid = LargeObjectRelationId;
    3809          20 :             extraID.oid = loinfo->looids[k];
    3810          20 :             recordAdditionalCatalogID(extraID, &loinfo->dobj);
    3811             :         }
    3812             : 
    3813             :         /* LOs have data */
    3814         146 :         loinfo->dobj.components |= DUMP_COMPONENT_DATA;
    3815             : 
    3816             :         /* Mark whether LO group has a non-empty ACL */
    3817         146 :         if (!PQgetisnull(res, i, i_lomacl))
    3818          68 :             loinfo->dobj.components |= DUMP_COMPONENT_ACL;
    3819             : 
    3820             :         /*
    3821             :          * In binary-upgrade mode for LOs, we do *not* dump out the LO data,
    3822             :          * as it will be copied by pg_upgrade, which simply copies the
    3823             :          * pg_largeobject table. We *do* however dump out anything but the
    3824             :          * data, as pg_upgrade copies just pg_largeobject, but not
    3825             :          * pg_largeobject_metadata, after the dump is restored.
    3826             :          */
    3827         146 :         if (dopt->binary_upgrade)
    3828           6 :             loinfo->dobj.dump &= ~DUMP_COMPONENT_DATA;
    3829             : 
    3830             :         /*
    3831             :          * Create a "BLOBS" data item for the group, too. This is just a
    3832             :          * placeholder for sorting; it carries no data now.
    3833             :          */
    3834         146 :         lodata = (DumpableObject *) pg_malloc(sizeof(DumpableObject));
    3835         146 :         lodata->objType = DO_LARGE_OBJECT_DATA;
    3836         146 :         lodata->catId = nilCatalogId;
    3837         146 :         AssignDumpId(lodata);
    3838         146 :         lodata->name = pg_strdup(namebuf);
    3839         146 :         lodata->components |= DUMP_COMPONENT_DATA;
    3840             :         /* Set up explicit dependency from data to metadata */
    3841         146 :         lodata->dependencies = (DumpId *) pg_malloc(sizeof(DumpId));
    3842         146 :         lodata->dependencies[0] = loinfo->dobj.dumpId;
    3843         146 :         lodata->nDeps = lodata->allocDeps = 1;
    3844             :     }
    3845             : 
    3846         256 :     PQclear(res);
    3847         256 :     destroyPQExpBuffer(loQry);
    3848         256 : }
    3849             : 
    3850             : /*
    3851             :  * dumpLO
    3852             :  *
    3853             :  * dump the definition (metadata) of the given large object group
    3854             :  */
    3855             : static void
    3856         146 : dumpLO(Archive *fout, const LoInfo *loinfo)
    3857             : {
    3858         146 :     PQExpBuffer cquery = createPQExpBuffer();
    3859             : 
    3860             :     /*
    3861             :      * The "definition" is just a newline-separated list of OIDs.  We need to
    3862             :      * put something into the dropStmt too, but it can just be a comment.
    3863             :      */
    3864         312 :     for (int i = 0; i < loinfo->numlos; i++)
    3865         166 :         appendPQExpBuffer(cquery, "%u\n", loinfo->looids[i]);
    3866             : 
    3867         146 :     if (loinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
    3868         146 :         ArchiveEntry(fout, loinfo->dobj.catId, loinfo->dobj.dumpId,
    3869         146 :                      ARCHIVE_OPTS(.tag = loinfo->dobj.name,
    3870             :                                   .owner = loinfo->rolname,
    3871             :                                   .description = "BLOB METADATA",
    3872             :                                   .section = SECTION_DATA,
    3873             :                                   .createStmt = cquery->data,
    3874             :                                   .dropStmt = "-- dummy"));
    3875             : 
    3876             :     /*
    3877             :      * Dump per-blob comments and seclabels if any.  We assume these are rare
    3878             :      * enough that it's okay to generate retail TOC entries for them.
    3879             :      */
    3880         146 :     if (loinfo->dobj.dump & (DUMP_COMPONENT_COMMENT |
    3881             :                              DUMP_COMPONENT_SECLABEL))
    3882             :     {
    3883         176 :         for (int i = 0; i < loinfo->numlos; i++)
    3884             :         {
    3885             :             CatalogId   catId;
    3886             :             char        namebuf[32];
    3887             : 
    3888             :             /* Build identifying info for this blob */
    3889          98 :             catId.tableoid = loinfo->dobj.catId.tableoid;
    3890          98 :             catId.oid = loinfo->looids[i];
    3891          98 :             snprintf(namebuf, sizeof(namebuf), "%u", loinfo->looids[i]);
    3892             : 
    3893          98 :             if (loinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
    3894          98 :                 dumpComment(fout, "LARGE OBJECT", namebuf,
    3895             :                             NULL, loinfo->rolname,
    3896             :                             catId, 0, loinfo->dobj.dumpId);
    3897             : 
    3898          98 :             if (loinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
    3899           0 :                 dumpSecLabel(fout, "LARGE OBJECT", namebuf,
    3900             :                              NULL, loinfo->rolname,
    3901             :                              catId, 0, loinfo->dobj.dumpId);
    3902             :         }
    3903             :     }
    3904             : 
    3905             :     /*
    3906             :      * Dump the ACLs if any (remember that all blobs in the group will have
    3907             :      * the same ACL).  If there's just one blob, dump a simple ACL entry; if
    3908             :      * there's more, make a "LARGE OBJECTS" entry that really contains only
    3909             :      * the ACL for the first blob.  _printTocEntry() will be cued by the tag
    3910             :      * string to emit a mutated version for each blob.
    3911             :      */
    3912         146 :     if (loinfo->dobj.dump & DUMP_COMPONENT_ACL)
    3913             :     {
    3914             :         char        namebuf[32];
    3915             : 
    3916             :         /* Build identifying info for the first blob */
    3917          68 :         snprintf(namebuf, sizeof(namebuf), "%u", loinfo->looids[0]);
    3918             : 
    3919          68 :         if (loinfo->numlos > 1)
    3920             :         {
    3921             :             char        tagbuf[64];
    3922             : 
    3923           0 :             snprintf(tagbuf, sizeof(tagbuf), "LARGE OBJECTS %u..%u",
    3924           0 :                      loinfo->looids[0], loinfo->looids[loinfo->numlos - 1]);
    3925             : 
    3926           0 :             dumpACL(fout, loinfo->dobj.dumpId, InvalidDumpId,
    3927             :                     "LARGE OBJECT", namebuf, NULL, NULL,
    3928             :                     tagbuf, loinfo->rolname, &loinfo->dacl);
    3929             :         }
    3930             :         else
    3931             :         {
    3932          68 :             dumpACL(fout, loinfo->dobj.dumpId, InvalidDumpId,
    3933             :                     "LARGE OBJECT", namebuf, NULL, NULL,
    3934             :                     NULL, loinfo->rolname, &loinfo->dacl);
    3935             :         }
    3936             :     }
    3937             : 
    3938         146 :     destroyPQExpBuffer(cquery);
    3939         146 : }
    3940             : 
    3941             : /*
    3942             :  * dumpLOs:
    3943             :  *  dump the data contents of the large objects in the given group
    3944             :  */
    3945             : static int
    3946         132 : dumpLOs(Archive *fout, const void *arg)
    3947             : {
    3948         132 :     const LoInfo *loinfo = (const LoInfo *) arg;
    3949         132 :     PGconn     *conn = GetConnection(fout);
    3950             :     char        buf[LOBBUFSIZE];
    3951             : 
    3952         132 :     pg_log_info("saving large objects \"%s\"", loinfo->dobj.name);
    3953             : 
    3954         280 :     for (int i = 0; i < loinfo->numlos; i++)
    3955             :     {
    3956         148 :         Oid         loOid = loinfo->looids[i];
    3957             :         int         loFd;
    3958             :         int         cnt;
    3959             : 
    3960             :         /* Open the LO */
    3961         148 :         loFd = lo_open(conn, loOid, INV_READ);
    3962         148 :         if (loFd == -1)
    3963           0 :             pg_fatal("could not open large object %u: %s",
    3964             :                      loOid, PQerrorMessage(conn));
    3965             : 
    3966         148 :         StartLO(fout, loOid);
    3967             : 
    3968             :         /* Now read it in chunks, sending data to archive */
    3969             :         do
    3970             :         {
    3971         226 :             cnt = lo_read(conn, loFd, buf, LOBBUFSIZE);
    3972         226 :             if (cnt < 0)
    3973           0 :                 pg_fatal("error reading large object %u: %s",
    3974             :                          loOid, PQerrorMessage(conn));
    3975             : 
    3976         226 :             WriteData(fout, buf, cnt);
    3977         226 :         } while (cnt > 0);
    3978             : 
    3979         148 :         lo_close(conn, loFd);
    3980             : 
    3981         148 :         EndLO(fout, loOid);
    3982             :     }
    3983             : 
    3984         132 :     return 1;
    3985             : }
    3986             : 
    3987             : /*
    3988             :  * getPolicies
    3989             :  *    get information about all RLS policies on dumpable tables.
    3990             :  */
    3991             : void
    3992         308 : getPolicies(Archive *fout, TableInfo tblinfo[], int numTables)
    3993             : {
    3994             :     PQExpBuffer query;
    3995             :     PQExpBuffer tbloids;
    3996             :     PGresult   *res;
    3997             :     PolicyInfo *polinfo;
    3998             :     int         i_oid;
    3999             :     int         i_tableoid;
    4000             :     int         i_polrelid;
    4001             :     int         i_polname;
    4002             :     int         i_polcmd;
    4003             :     int         i_polpermissive;
    4004             :     int         i_polroles;
    4005             :     int         i_polqual;
    4006             :     int         i_polwithcheck;
    4007             :     int         i,
    4008             :                 j,
    4009             :                 ntups;
    4010             : 
    4011             :     /* No policies before 9.5 */
    4012         308 :     if (fout->remoteVersion < 90500)
    4013           0 :         return;
    4014             : 
    4015         308 :     query = createPQExpBuffer();
    4016         308 :     tbloids = createPQExpBuffer();
    4017             : 
    4018             :     /*
    4019             :      * Identify tables of interest, and check which ones have RLS enabled.
    4020             :      */
    4021         308 :     appendPQExpBufferChar(tbloids, '{');
    4022       81230 :     for (i = 0; i < numTables; i++)
    4023             :     {
    4024       80922 :         TableInfo  *tbinfo = &tblinfo[i];
    4025             : 
    4026             :         /* Ignore row security on tables not to be dumped */
    4027       80922 :         if (!(tbinfo->dobj.dump & DUMP_COMPONENT_POLICY))
    4028       68750 :             continue;
    4029             : 
    4030             :         /* It can't have RLS or policies if it's not a table */
    4031       12172 :         if (tbinfo->relkind != RELKIND_RELATION &&
    4032        3598 :             tbinfo->relkind != RELKIND_PARTITIONED_TABLE)
    4033        2544 :             continue;
    4034             : 
    4035             :         /* Add it to the list of table OIDs to be probed below */
    4036        9628 :         if (tbloids->len > 1) /* do we have more than the '{'? */
    4037        9432 :             appendPQExpBufferChar(tbloids, ',');
    4038        9628 :         appendPQExpBuffer(tbloids, "%u", tbinfo->dobj.catId.oid);
    4039             : 
    4040             :         /* Is RLS enabled?  (That's separate from whether it has policies) */
    4041        9628 :         if (tbinfo->rowsec)
    4042             :         {
    4043         104 :             tbinfo->dobj.components |= DUMP_COMPONENT_POLICY;
    4044             : 
    4045             :             /*
    4046             :              * We represent RLS being enabled on a table by creating a
    4047             :              * PolicyInfo object with null polname.
    4048             :              *
    4049             :              * Note: use tableoid 0 so that this object won't be mistaken for
    4050             :              * something that pg_depend entries apply to.
    4051             :              */
    4052         104 :             polinfo = pg_malloc(sizeof(PolicyInfo));
    4053         104 :             polinfo->dobj.objType = DO_POLICY;
    4054         104 :             polinfo->dobj.catId.tableoid = 0;
    4055         104 :             polinfo->dobj.catId.oid = tbinfo->dobj.catId.oid;
    4056         104 :             AssignDumpId(&polinfo->dobj);
    4057         104 :             polinfo->dobj.namespace = tbinfo->dobj.namespace;
    4058         104 :             polinfo->dobj.name = pg_strdup(tbinfo->dobj.name);
    4059         104 :             polinfo->poltable = tbinfo;
    4060         104 :             polinfo->polname = NULL;
    4061         104 :             polinfo->polcmd = '\0';
    4062         104 :             polinfo->polpermissive = 0;
    4063         104 :             polinfo->polroles = NULL;
    4064         104 :             polinfo->polqual = NULL;
    4065         104 :             polinfo->polwithcheck = NULL;
    4066             :         }
    4067             :     }
    4068         308 :     appendPQExpBufferChar(tbloids, '}');
    4069             : 
    4070             :     /*
    4071             :      * Now, read all RLS policies belonging to the tables of interest, and
    4072             :      * create PolicyInfo objects for them.  (Note that we must filter the
    4073             :      * results server-side not locally, because we dare not apply pg_get_expr
    4074             :      * to tables we don't have lock on.)
    4075             :      */
    4076         308 :     pg_log_info("reading row-level security policies");
    4077             : 
    4078         308 :     printfPQExpBuffer(query,
    4079             :                       "SELECT pol.oid, pol.tableoid, pol.polrelid, pol.polname, pol.polcmd, ");
    4080         308 :     if (fout->remoteVersion >= 100000)
    4081         308 :         appendPQExpBufferStr(query, "pol.polpermissive, ");
    4082             :     else
    4083           0 :         appendPQExpBufferStr(query, "'t' as polpermissive, ");
    4084         308 :     appendPQExpBuffer(query,
    4085             :                       "CASE WHEN pol.polroles = '{0}' THEN NULL ELSE "
    4086             :                       "   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, "
    4087             :                       "pg_catalog.pg_get_expr(pol.polqual, pol.polrelid) AS polqual, "
    4088             :                       "pg_catalog.pg_get_expr(pol.polwithcheck, pol.polrelid) AS polwithcheck "
    4089             :                       "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
    4090             :                       "JOIN pg_catalog.pg_policy pol ON (src.tbloid = pol.polrelid)",
    4091             :                       tbloids->data);
    4092             : 
    4093         308 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    4094             : 
    4095         308 :     ntups = PQntuples(res);
    4096         308 :     if (ntups > 0)
    4097             :     {
    4098          84 :         i_oid = PQfnumber(res, "oid");
    4099          84 :         i_tableoid = PQfnumber(res, "tableoid");
    4100          84 :         i_polrelid = PQfnumber(res, "polrelid");
    4101          84 :         i_polname = PQfnumber(res, "polname");
    4102          84 :         i_polcmd = PQfnumber(res, "polcmd");
    4103          84 :         i_polpermissive = PQfnumber(res, "polpermissive");
    4104          84 :         i_polroles = PQfnumber(res, "polroles");
    4105          84 :         i_polqual = PQfnumber(res, "polqual");
    4106          84 :         i_polwithcheck = PQfnumber(res, "polwithcheck");
    4107             : 
    4108          84 :         polinfo = pg_malloc(ntups * sizeof(PolicyInfo));
    4109             : 
    4110         618 :         for (j = 0; j < ntups; j++)
    4111             :         {
    4112         534 :             Oid         polrelid = atooid(PQgetvalue(res, j, i_polrelid));
    4113         534 :             TableInfo  *tbinfo = findTableByOid(polrelid);
    4114             : 
    4115         534 :             tbinfo->dobj.components |= DUMP_COMPONENT_POLICY;
    4116             : 
    4117         534 :             polinfo[j].dobj.objType = DO_POLICY;
    4118         534 :             polinfo[j].dobj.catId.tableoid =
    4119         534 :                 atooid(PQgetvalue(res, j, i_tableoid));
    4120         534 :             polinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
    4121         534 :             AssignDumpId(&polinfo[j].dobj);
    4122         534 :             polinfo[j].dobj.namespace = tbinfo->dobj.namespace;
    4123         534 :             polinfo[j].poltable = tbinfo;
    4124         534 :             polinfo[j].polname = pg_strdup(PQgetvalue(res, j, i_polname));
    4125         534 :             polinfo[j].dobj.name = pg_strdup(polinfo[j].polname);
    4126             : 
    4127         534 :             polinfo[j].polcmd = *(PQgetvalue(res, j, i_polcmd));
    4128         534 :             polinfo[j].polpermissive = *(PQgetvalue(res, j, i_polpermissive)) == 't';
    4129             : 
    4130         534 :             if (PQgetisnull(res, j, i_polroles))
    4131         238 :                 polinfo[j].polroles = NULL;
    4132             :             else
    4133         296 :                 polinfo[j].polroles = pg_strdup(PQgetvalue(res, j, i_polroles));
    4134             : 
    4135         534 :             if (PQgetisnull(res, j, i_polqual))
    4136          74 :                 polinfo[j].polqual = NULL;
    4137             :             else
    4138         460 :                 polinfo[j].polqual = pg_strdup(PQgetvalue(res, j, i_polqual));
    4139             : 
    4140         534 :             if (PQgetisnull(res, j, i_polwithcheck))
    4141         282 :                 polinfo[j].polwithcheck = NULL;
    4142             :             else
    4143         252 :                 polinfo[j].polwithcheck
    4144         252 :                     = pg_strdup(PQgetvalue(res, j, i_polwithcheck));
    4145             :         }
    4146             :     }
    4147             : 
    4148         308 :     PQclear(res);
    4149             : 
    4150         308 :     destroyPQExpBuffer(query);
    4151         308 :     destroyPQExpBuffer(tbloids);
    4152             : }
    4153             : 
    4154             : /*
    4155             :  * dumpPolicy
    4156             :  *    dump the definition of the given policy
    4157             :  */
    4158             : static void
    4159         638 : dumpPolicy(Archive *fout, const PolicyInfo *polinfo)
    4160             : {
    4161         638 :     DumpOptions *dopt = fout->dopt;
    4162         638 :     TableInfo  *tbinfo = polinfo->poltable;
    4163             :     PQExpBuffer query;
    4164             :     PQExpBuffer delqry;
    4165             :     PQExpBuffer polprefix;
    4166             :     char       *qtabname;
    4167             :     const char *cmd;
    4168             :     char       *tag;
    4169             : 
    4170             :     /* Do nothing if not dumping schema */
    4171         638 :     if (!dopt->dumpSchema)
    4172          56 :         return;
    4173             : 
    4174             :     /*
    4175             :      * If polname is NULL, then this record is just indicating that ROW LEVEL
    4176             :      * SECURITY is enabled for the table. Dump as ALTER TABLE <table> ENABLE
    4177             :      * ROW LEVEL SECURITY.
    4178             :      */
    4179         582 :     if (polinfo->polname == NULL)
    4180             :     {
    4181          96 :         query = createPQExpBuffer();
    4182             : 
    4183          96 :         appendPQExpBuffer(query, "ALTER TABLE %s ENABLE ROW LEVEL SECURITY;",
    4184          96 :                           fmtQualifiedDumpable(tbinfo));
    4185             : 
    4186             :         /*
    4187             :          * We must emit the ROW SECURITY object's dependency on its table
    4188             :          * explicitly, because it will not match anything in pg_depend (unlike
    4189             :          * the case for other PolicyInfo objects).
    4190             :          */
    4191          96 :         if (polinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
    4192          96 :             ArchiveEntry(fout, polinfo->dobj.catId, polinfo->dobj.dumpId,
    4193          96 :                          ARCHIVE_OPTS(.tag = polinfo->dobj.name,
    4194             :                                       .namespace = polinfo->dobj.namespace->dobj.name,
    4195             :                                       .owner = tbinfo->rolname,
    4196             :                                       .description = "ROW SECURITY",
    4197             :                                       .section = SECTION_POST_DATA,
    4198             :                                       .createStmt = query->data,
    4199             :                                       .deps = &(tbinfo->dobj.dumpId),
    4200             :                                       .nDeps = 1));
    4201             : 
    4202          96 :         destroyPQExpBuffer(query);
    4203          96 :         return;
    4204             :     }
    4205             : 
    4206         486 :     if (polinfo->polcmd == '*')
    4207         162 :         cmd = "";
    4208         324 :     else if (polinfo->polcmd == 'r')
    4209          86 :         cmd = " FOR SELECT";
    4210         238 :     else if (polinfo->polcmd == 'a')
    4211          66 :         cmd = " FOR INSERT";
    4212         172 :     else if (polinfo->polcmd == 'w')
    4213          86 :         cmd = " FOR UPDATE";
    4214          86 :     else if (polinfo->polcmd == 'd')
    4215          86 :         cmd = " FOR DELETE";
    4216             :     else
    4217           0 :         pg_fatal("unexpected policy command type: %c",
    4218             :                  polinfo->polcmd);
    4219             : 
    4220         486 :     query = createPQExpBuffer();
    4221         486 :     delqry = createPQExpBuffer();
    4222         486 :     polprefix = createPQExpBuffer();
    4223             : 
    4224         486 :     qtabname = pg_strdup(fmtId(tbinfo->dobj.name));
    4225             : 
    4226         486 :     appendPQExpBuffer(query, "CREATE POLICY %s", fmtId(polinfo->polname));
    4227             : 
    4228         486 :     appendPQExpBuffer(query, " ON %s%s%s", fmtQualifiedDumpable(tbinfo),
    4229         486 :                       !polinfo->polpermissive ? " AS RESTRICTIVE" : "", cmd);
    4230             : 
    4231         486 :     if (polinfo->polroles != NULL)
    4232         264 :         appendPQExpBuffer(query, " TO %s", polinfo->polroles);
    4233             : 
    4234         486 :     if (polinfo->polqual != NULL)
    4235         420 :         appendPQExpBuffer(query, " USING (%s)", polinfo->polqual);
    4236             : 
    4237         486 :     if (polinfo->polwithcheck != NULL)
    4238         228 :         appendPQExpBuffer(query, " WITH CHECK (%s)", polinfo->polwithcheck);
    4239             : 
    4240         486 :     appendPQExpBufferStr(query, ";\n");
    4241             : 
    4242         486 :     appendPQExpBuffer(delqry, "DROP POLICY %s", fmtId(polinfo->polname));
    4243         486 :     appendPQExpBuffer(delqry, " ON %s;\n", fmtQualifiedDumpable(tbinfo));
    4244             : 
    4245         486 :     appendPQExpBuffer(polprefix, "POLICY %s ON",
    4246         486 :                       fmtId(polinfo->polname));
    4247             : 
    4248         486 :     tag = psprintf("%s %s", tbinfo->dobj.name, polinfo->dobj.name);
    4249             : 
    4250         486 :     if (polinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
    4251         486 :         ArchiveEntry(fout, polinfo->dobj.catId, polinfo->dobj.dumpId,
    4252         486 :                      ARCHIVE_OPTS(.tag = tag,
    4253             :                                   .namespace = polinfo->dobj.namespace->dobj.name,
    4254             :                                   .owner = tbinfo->rolname,
    4255             :                                   .description = "POLICY",
    4256             :                                   .section = SECTION_POST_DATA,
    4257             :                                   .createStmt = query->data,
    4258             :                                   .dropStmt = delqry->data));
    4259             : 
    4260         486 :     if (polinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
    4261           0 :         dumpComment(fout, polprefix->data, qtabname,
    4262           0 :                     tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
    4263             :                     polinfo->dobj.catId, 0, polinfo->dobj.dumpId);
    4264             : 
    4265         486 :     free(tag);
    4266         486 :     destroyPQExpBuffer(query);
    4267         486 :     destroyPQExpBuffer(delqry);
    4268         486 :     destroyPQExpBuffer(polprefix);
    4269         486 :     free(qtabname);
    4270             : }
    4271             : 
    4272             : /*
    4273             :  * getPublications
    4274             :  *    get information about publications
    4275             :  */
    4276             : void
    4277         308 : getPublications(Archive *fout)
    4278             : {
    4279         308 :     DumpOptions *dopt = fout->dopt;
    4280             :     PQExpBuffer query;
    4281             :     PGresult   *res;
    4282             :     PublicationInfo *pubinfo;
    4283             :     int         i_tableoid;
    4284             :     int         i_oid;
    4285             :     int         i_pubname;
    4286             :     int         i_pubowner;
    4287             :     int         i_puballtables;
    4288             :     int         i_pubinsert;
    4289             :     int         i_pubupdate;
    4290             :     int         i_pubdelete;
    4291             :     int         i_pubtruncate;
    4292             :     int         i_pubviaroot;
    4293             :     int         i_pubgencols;
    4294             :     int         i,
    4295             :                 ntups;
    4296             : 
    4297         308 :     if (dopt->no_publications || fout->remoteVersion < 100000)
    4298           0 :         return;
    4299             : 
    4300         308 :     query = createPQExpBuffer();
    4301             : 
    4302             :     /* Get the publications. */
    4303         308 :     appendPQExpBufferStr(query, "SELECT p.tableoid, p.oid, p.pubname, "
    4304             :                          "p.pubowner, p.puballtables, p.pubinsert, "
    4305             :                          "p.pubupdate, p.pubdelete, ");
    4306             : 
    4307         308 :     if (fout->remoteVersion >= 110000)
    4308         308 :         appendPQExpBufferStr(query, "p.pubtruncate, ");
    4309             :     else
    4310           0 :         appendPQExpBufferStr(query, "false AS pubtruncate, ");
    4311             : 
    4312         308 :     if (fout->remoteVersion >= 130000)
    4313         308 :         appendPQExpBufferStr(query, "p.pubviaroot, ");
    4314             :     else
    4315           0 :         appendPQExpBufferStr(query, "false AS pubviaroot, ");
    4316             : 
    4317         308 :     if (fout->remoteVersion >= 180000)
    4318         308 :         appendPQExpBufferStr(query, "p.pubgencols ");
    4319             :     else
    4320           0 :         appendPQExpBufferStr(query, "false AS pubgencols ");
    4321             : 
    4322         308 :     appendPQExpBufferStr(query, "FROM pg_publication p");
    4323             : 
    4324         308 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    4325             : 
    4326         308 :     ntups = PQntuples(res);
    4327             : 
    4328         308 :     if (ntups == 0)
    4329         220 :         goto cleanup;
    4330             : 
    4331          88 :     i_tableoid = PQfnumber(res, "tableoid");
    4332          88 :     i_oid = PQfnumber(res, "oid");
    4333          88 :     i_pubname = PQfnumber(res, "pubname");
    4334          88 :     i_pubowner = PQfnumber(res, "pubowner");
    4335          88 :     i_puballtables = PQfnumber(res, "puballtables");
    4336          88 :     i_pubinsert = PQfnumber(res, "pubinsert");
    4337          88 :     i_pubupdate = PQfnumber(res, "pubupdate");
    4338          88 :     i_pubdelete = PQfnumber(res, "pubdelete");
    4339          88 :     i_pubtruncate = PQfnumber(res, "pubtruncate");
    4340          88 :     i_pubviaroot = PQfnumber(res, "pubviaroot");
    4341          88 :     i_pubgencols = PQfnumber(res, "pubgencols");
    4342             : 
    4343          88 :     pubinfo = pg_malloc(ntups * sizeof(PublicationInfo));
    4344             : 
    4345         520 :     for (i = 0; i < ntups; i++)
    4346             :     {
    4347         432 :         pubinfo[i].dobj.objType = DO_PUBLICATION;
    4348         432 :         pubinfo[i].dobj.catId.tableoid =
    4349         432 :             atooid(PQgetvalue(res, i, i_tableoid));
    4350         432 :         pubinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    4351         432 :         AssignDumpId(&pubinfo[i].dobj);
    4352         432 :         pubinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_pubname));
    4353         432 :         pubinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_pubowner));
    4354         432 :         pubinfo[i].puballtables =
    4355         432 :             (strcmp(PQgetvalue(res, i, i_puballtables), "t") == 0);
    4356         432 :         pubinfo[i].pubinsert =
    4357         432 :             (strcmp(PQgetvalue(res, i, i_pubinsert), "t") == 0);
    4358         432 :         pubinfo[i].pubupdate =
    4359         432 :             (strcmp(PQgetvalue(res, i, i_pubupdate), "t") == 0);
    4360         432 :         pubinfo[i].pubdelete =
    4361         432 :             (strcmp(PQgetvalue(res, i, i_pubdelete), "t") == 0);
    4362         432 :         pubinfo[i].pubtruncate =
    4363         432 :             (strcmp(PQgetvalue(res, i, i_pubtruncate), "t") == 0);
    4364         432 :         pubinfo[i].pubviaroot =
    4365         432 :             (strcmp(PQgetvalue(res, i, i_pubviaroot), "t") == 0);
    4366         432 :         pubinfo[i].pubgencols =
    4367         432 :             (strcmp(PQgetvalue(res, i, i_pubgencols), "t") == 0);
    4368             : 
    4369             :         /* Decide whether we want to dump it */
    4370         432 :         selectDumpableObject(&(pubinfo[i].dobj), fout);
    4371             :     }
    4372             : 
    4373          88 : cleanup:
    4374         308 :     PQclear(res);
    4375             : 
    4376         308 :     destroyPQExpBuffer(query);
    4377             : }
    4378             : 
    4379             : /*
    4380             :  * dumpPublication
    4381             :  *    dump the definition of the given publication
    4382             :  */
    4383             : static void
    4384         352 : dumpPublication(Archive *fout, const PublicationInfo *pubinfo)
    4385             : {
    4386         352 :     DumpOptions *dopt = fout->dopt;
    4387             :     PQExpBuffer delq;
    4388             :     PQExpBuffer query;
    4389             :     char       *qpubname;
    4390         352 :     bool        first = true;
    4391             : 
    4392             :     /* Do nothing if not dumping schema */
    4393         352 :     if (!dopt->dumpSchema)
    4394          30 :         return;
    4395             : 
    4396         322 :     delq = createPQExpBuffer();
    4397         322 :     query = createPQExpBuffer();
    4398             : 
    4399         322 :     qpubname = pg_strdup(fmtId(pubinfo->dobj.name));
    4400             : 
    4401         322 :     appendPQExpBuffer(delq, "DROP PUBLICATION %s;\n",
    4402             :                       qpubname);
    4403             : 
    4404         322 :     appendPQExpBuffer(query, "CREATE PUBLICATION %s",
    4405             :                       qpubname);
    4406             : 
    4407         322 :     if (pubinfo->puballtables)
    4408          66 :         appendPQExpBufferStr(query, " FOR ALL TABLES");
    4409             : 
    4410         322 :     appendPQExpBufferStr(query, " WITH (publish = '");
    4411         322 :     if (pubinfo->pubinsert)
    4412             :     {
    4413         258 :         appendPQExpBufferStr(query, "insert");
    4414         258 :         first = false;
    4415             :     }
    4416             : 
    4417         322 :     if (pubinfo->pubupdate)
    4418             :     {
    4419         258 :         if (!first)
    4420         258 :             appendPQExpBufferStr(query, ", ");
    4421             : 
    4422         258 :         appendPQExpBufferStr(query, "update");
    4423         258 :         first = false;
    4424             :     }
    4425             : 
    4426         322 :     if (pubinfo->pubdelete)
    4427             :     {
    4428         258 :         if (!first)
    4429         258 :             appendPQExpBufferStr(query, ", ");
    4430             : 
    4431         258 :         appendPQExpBufferStr(query, "delete");
    4432         258 :         first = false;
    4433             :     }
    4434             : 
    4435         322 :     if (pubinfo->pubtruncate)
    4436             :     {
    4437         258 :         if (!first)
    4438         258 :             appendPQExpBufferStr(query, ", ");
    4439             : 
    4440         258 :         appendPQExpBufferStr(query, "truncate");
    4441         258 :         first = false;
    4442             :     }
    4443             : 
    4444         322 :     appendPQExpBufferChar(query, '\'');
    4445             : 
    4446         322 :     if (pubinfo->pubviaroot)
    4447           0 :         appendPQExpBufferStr(query, ", publish_via_partition_root = true");
    4448             : 
    4449         322 :     if (pubinfo->pubgencols)
    4450          64 :         appendPQExpBufferStr(query, ", publish_generated_columns = true");
    4451             : 
    4452         322 :     appendPQExpBufferStr(query, ");\n");
    4453             : 
    4454         322 :     if (pubinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
    4455         322 :         ArchiveEntry(fout, pubinfo->dobj.catId, pubinfo->dobj.dumpId,
    4456         322 :                      ARCHIVE_OPTS(.tag = pubinfo->dobj.name,
    4457             :                                   .owner = pubinfo->rolname,
    4458             :                                   .description = "PUBLICATION",
    4459             :                                   .section = SECTION_POST_DATA,
    4460             :                                   .createStmt = query->data,
    4461             :                                   .dropStmt = delq->data));
    4462             : 
    4463         322 :     if (pubinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
    4464          64 :         dumpComment(fout, "PUBLICATION", qpubname,
    4465             :                     NULL, pubinfo->rolname,
    4466             :                     pubinfo->dobj.catId, 0, pubinfo->dobj.dumpId);
    4467             : 
    4468         322 :     if (pubinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
    4469           0 :         dumpSecLabel(fout, "PUBLICATION", qpubname,
    4470             :                      NULL, pubinfo->rolname,
    4471             :                      pubinfo->dobj.catId, 0, pubinfo->dobj.dumpId);
    4472             : 
    4473         322 :     destroyPQExpBuffer(delq);
    4474         322 :     destroyPQExpBuffer(query);
    4475         322 :     free(qpubname);
    4476             : }
    4477             : 
    4478             : /*
    4479             :  * getPublicationNamespaces
    4480             :  *    get information about publication membership for dumpable schemas.
    4481             :  */
    4482             : void
    4483         308 : getPublicationNamespaces(Archive *fout)
    4484             : {
    4485             :     PQExpBuffer query;
    4486             :     PGresult   *res;
    4487             :     PublicationSchemaInfo *pubsinfo;
    4488         308 :     DumpOptions *dopt = fout->dopt;
    4489             :     int         i_tableoid;
    4490             :     int         i_oid;
    4491             :     int         i_pnpubid;
    4492             :     int         i_pnnspid;
    4493             :     int         i,
    4494             :                 j,
    4495             :                 ntups;
    4496             : 
    4497         308 :     if (dopt->no_publications || fout->remoteVersion < 150000)
    4498           0 :         return;
    4499             : 
    4500         308 :     query = createPQExpBuffer();
    4501             : 
    4502             :     /* Collect all publication membership info. */
    4503         308 :     appendPQExpBufferStr(query,
    4504             :                          "SELECT tableoid, oid, pnpubid, pnnspid "
    4505             :                          "FROM pg_catalog.pg_publication_namespace");
    4506         308 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    4507             : 
    4508         308 :     ntups = PQntuples(res);
    4509             : 
    4510         308 :     i_tableoid = PQfnumber(res, "tableoid");
    4511         308 :     i_oid = PQfnumber(res, "oid");
    4512         308 :     i_pnpubid = PQfnumber(res, "pnpubid");
    4513         308 :     i_pnnspid = PQfnumber(res, "pnnspid");
    4514             : 
    4515             :     /* this allocation may be more than we need */
    4516         308 :     pubsinfo = pg_malloc(ntups * sizeof(PublicationSchemaInfo));
    4517         308 :     j = 0;
    4518             : 
    4519         480 :     for (i = 0; i < ntups; i++)
    4520             :     {
    4521         172 :         Oid         pnpubid = atooid(PQgetvalue(res, i, i_pnpubid));
    4522         172 :         Oid         pnnspid = atooid(PQgetvalue(res, i, i_pnnspid));
    4523             :         PublicationInfo *pubinfo;
    4524             :         NamespaceInfo *nspinfo;
    4525             : 
    4526             :         /*
    4527             :          * Ignore any entries for which we aren't interested in either the
    4528             :          * publication or the rel.
    4529             :          */
    4530         172 :         pubinfo = findPublicationByOid(pnpubid);
    4531         172 :         if (pubinfo == NULL)
    4532           0 :             continue;
    4533         172 :         nspinfo = findNamespaceByOid(pnnspid);
    4534         172 :         if (nspinfo == NULL)
    4535           0 :             continue;
    4536             : 
    4537             :         /*
    4538             :          * We always dump publication namespaces unless the corresponding
    4539             :          * namespace is excluded from the dump.
    4540             :          */
    4541         172 :         if (nspinfo->dobj.dump == DUMP_COMPONENT_NONE)
    4542          30 :             continue;
    4543             : 
    4544             :         /* OK, make a DumpableObject for this relationship */
    4545         142 :         pubsinfo[j].dobj.objType = DO_PUBLICATION_TABLE_IN_SCHEMA;
    4546         142 :         pubsinfo[j].dobj.catId.tableoid =
    4547         142 :             atooid(PQgetvalue(res, i, i_tableoid));
    4548         142 :         pubsinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    4549         142 :         AssignDumpId(&pubsinfo[j].dobj);
    4550         142 :         pubsinfo[j].dobj.namespace = nspinfo->dobj.namespace;
    4551         142 :         pubsinfo[j].dobj.name = nspinfo->dobj.name;
    4552         142 :         pubsinfo[j].publication = pubinfo;
    4553         142 :         pubsinfo[j].pubschema = nspinfo;
    4554             : 
    4555             :         /* Decide whether we want to dump it */
    4556         142 :         selectDumpablePublicationObject(&(pubsinfo[j].dobj), fout);
    4557             : 
    4558         142 :         j++;
    4559             :     }
    4560             : 
    4561         308 :     PQclear(res);
    4562         308 :     destroyPQExpBuffer(query);
    4563             : }
    4564             : 
    4565             : /*
    4566             :  * getPublicationTables
    4567             :  *    get information about publication membership for dumpable tables.
    4568             :  */
    4569             : void
    4570         308 : getPublicationTables(Archive *fout, TableInfo tblinfo[], int numTables)
    4571             : {
    4572             :     PQExpBuffer query;
    4573             :     PGresult   *res;
    4574             :     PublicationRelInfo *pubrinfo;
    4575         308 :     DumpOptions *dopt = fout->dopt;
    4576             :     int         i_tableoid;
    4577             :     int         i_oid;
    4578             :     int         i_prpubid;
    4579             :     int         i_prrelid;
    4580             :     int         i_prrelqual;
    4581             :     int         i_prattrs;
    4582             :     int         i,
    4583             :                 j,
    4584             :                 ntups;
    4585             : 
    4586         308 :     if (dopt->no_publications || fout->remoteVersion < 100000)
    4587           0 :         return;
    4588             : 
    4589         308 :     query = createPQExpBuffer();
    4590             : 
    4591             :     /* Collect all publication membership info. */
    4592         308 :     if (fout->remoteVersion >= 150000)
    4593         308 :         appendPQExpBufferStr(query,
    4594             :                              "SELECT tableoid, oid, prpubid, prrelid, "
    4595             :                              "pg_catalog.pg_get_expr(prqual, prrelid) AS prrelqual, "
    4596             :                              "(CASE\n"
    4597             :                              "  WHEN pr.prattrs IS NOT NULL THEN\n"
    4598             :                              "    (SELECT array_agg(attname)\n"
    4599             :                              "       FROM\n"
    4600             :                              "         pg_catalog.generate_series(0, pg_catalog.array_upper(pr.prattrs::pg_catalog.int2[], 1)) s,\n"
    4601             :                              "         pg_catalog.pg_attribute\n"
    4602             :                              "      WHERE attrelid = pr.prrelid AND attnum = prattrs[s])\n"
    4603             :                              "  ELSE NULL END) prattrs "
    4604             :                              "FROM pg_catalog.pg_publication_rel pr");
    4605             :     else
    4606           0 :         appendPQExpBufferStr(query,
    4607             :                              "SELECT tableoid, oid, prpubid, prrelid, "
    4608             :                              "NULL AS prrelqual, NULL AS prattrs "
    4609             :                              "FROM pg_catalog.pg_publication_rel");
    4610         308 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    4611             : 
    4612         308 :     ntups = PQntuples(res);
    4613             : 
    4614         308 :     i_tableoid = PQfnumber(res, "tableoid");
    4615         308 :     i_oid = PQfnumber(res, "oid");
    4616         308 :     i_prpubid = PQfnumber(res, "prpubid");
    4617         308 :     i_prrelid = PQfnumber(res, "prrelid");
    4618         308 :     i_prrelqual = PQfnumber(res, "prrelqual");
    4619         308 :     i_prattrs = PQfnumber(res, "prattrs");
    4620             : 
    4621             :     /* this allocation may be more than we need */
    4622         308 :     pubrinfo = pg_malloc(ntups * sizeof(PublicationRelInfo));
    4623         308 :     j = 0;
    4624             : 
    4625         910 :     for (i = 0; i < ntups; i++)
    4626             :     {
    4627         602 :         Oid         prpubid = atooid(PQgetvalue(res, i, i_prpubid));
    4628         602 :         Oid         prrelid = atooid(PQgetvalue(res, i, i_prrelid));
    4629             :         PublicationInfo *pubinfo;
    4630             :         TableInfo  *tbinfo;
    4631             : 
    4632             :         /*
    4633             :          * Ignore any entries for which we aren't interested in either the
    4634             :          * publication or the rel.
    4635             :          */
    4636         602 :         pubinfo = findPublicationByOid(prpubid);
    4637         602 :         if (pubinfo == NULL)
    4638           0 :             continue;
    4639         602 :         tbinfo = findTableByOid(prrelid);
    4640         602 :         if (tbinfo == NULL)
    4641           0 :             continue;
    4642             : 
    4643             :         /*
    4644             :          * Ignore publication membership of tables whose definitions are not
    4645             :          * to be dumped.
    4646             :          */
    4647         602 :         if (!(tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
    4648          92 :             continue;
    4649             : 
    4650             :         /* OK, make a DumpableObject for this relationship */
    4651         510 :         pubrinfo[j].dobj.objType = DO_PUBLICATION_REL;
    4652         510 :         pubrinfo[j].dobj.catId.tableoid =
    4653         510 :             atooid(PQgetvalue(res, i, i_tableoid));
    4654         510 :         pubrinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    4655         510 :         AssignDumpId(&pubrinfo[j].dobj);
    4656         510 :         pubrinfo[j].dobj.namespace = tbinfo->dobj.namespace;
    4657         510 :         pubrinfo[j].dobj.name = tbinfo->dobj.name;
    4658         510 :         pubrinfo[j].publication = pubinfo;
    4659         510 :         pubrinfo[j].pubtable = tbinfo;
    4660         510 :         if (PQgetisnull(res, i, i_prrelqual))
    4661         292 :             pubrinfo[j].pubrelqual = NULL;
    4662             :         else
    4663         218 :             pubrinfo[j].pubrelqual = pg_strdup(PQgetvalue(res, i, i_prrelqual));
    4664             : 
    4665         510 :         if (!PQgetisnull(res, i, i_prattrs))
    4666             :         {
    4667             :             char      **attnames;
    4668             :             int         nattnames;
    4669             :             PQExpBuffer attribs;
    4670             : 
    4671         144 :             if (!parsePGArray(PQgetvalue(res, i, i_prattrs),
    4672             :                               &attnames, &nattnames))
    4673           0 :                 pg_fatal("could not parse %s array", "prattrs");
    4674         144 :             attribs = createPQExpBuffer();
    4675         432 :             for (int k = 0; k < nattnames; k++)
    4676             :             {
    4677         288 :                 if (k > 0)
    4678         144 :                     appendPQExpBufferStr(attribs, ", ");
    4679             : 
    4680         288 :                 appendPQExpBufferStr(attribs, fmtId(attnames[k]));
    4681             :             }
    4682         144 :             pubrinfo[j].pubrattrs = attribs->data;
    4683             :         }
    4684             :         else
    4685         366 :             pubrinfo[j].pubrattrs = NULL;
    4686             : 
    4687             :         /* Decide whether we want to dump it */
    4688         510 :         selectDumpablePublicationObject(&(pubrinfo[j].dobj), fout);
    4689             : 
    4690         510 :         j++;
    4691             :     }
    4692             : 
    4693         308 :     PQclear(res);
    4694         308 :     destroyPQExpBuffer(query);
    4695             : }
    4696             : 
    4697             : /*
    4698             :  * dumpPublicationNamespace
    4699             :  *    dump the definition of the given publication schema mapping.
    4700             :  */
    4701             : static void
    4702         138 : dumpPublicationNamespace(Archive *fout, const PublicationSchemaInfo *pubsinfo)
    4703             : {
    4704         138 :     DumpOptions *dopt = fout->dopt;
    4705         138 :     NamespaceInfo *schemainfo = pubsinfo->pubschema;
    4706         138 :     PublicationInfo *pubinfo = pubsinfo->publication;
    4707             :     PQExpBuffer query;
    4708             :     char       *tag;
    4709             : 
    4710             :     /* Do nothing if not dumping schema */
    4711         138 :     if (!dopt->dumpSchema)
    4712          12 :         return;
    4713             : 
    4714         126 :     tag = psprintf("%s %s", pubinfo->dobj.name, schemainfo->dobj.name);
    4715             : 
    4716         126 :     query = createPQExpBuffer();
    4717             : 
    4718         126 :     appendPQExpBuffer(query, "ALTER PUBLICATION %s ", fmtId(pubinfo->dobj.name));
    4719         126 :     appendPQExpBuffer(query, "ADD TABLES IN SCHEMA %s;\n", fmtId(schemainfo->dobj.name));
    4720             : 
    4721             :     /*
    4722             :      * There is no point in creating drop query as the drop is done by schema
    4723             :      * drop.
    4724             :      */
    4725         126 :     if (pubsinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
    4726         126 :         ArchiveEntry(fout, pubsinfo->dobj.catId, pubsinfo->dobj.dumpId,
    4727         126 :                      ARCHIVE_OPTS(.tag = tag,
    4728             :                                   .namespace = schemainfo->dobj.name,
    4729             :                                   .owner = pubinfo->rolname,
    4730             :                                   .description = "PUBLICATION TABLES IN SCHEMA",
    4731             :                                   .section = SECTION_POST_DATA,
    4732             :                                   .createStmt = query->data));
    4733             : 
    4734             :     /* These objects can't currently have comments or seclabels */
    4735             : 
    4736         126 :     free(tag);
    4737         126 :     destroyPQExpBuffer(query);
    4738             : }
    4739             : 
    4740             : /*
    4741             :  * dumpPublicationTable
    4742             :  *    dump the definition of the given publication table mapping
    4743             :  */
    4744             : static void
    4745         470 : dumpPublicationTable(Archive *fout, const PublicationRelInfo *pubrinfo)
    4746             : {
    4747         470 :     DumpOptions *dopt = fout->dopt;
    4748         470 :     PublicationInfo *pubinfo = pubrinfo->publication;
    4749         470 :     TableInfo  *tbinfo = pubrinfo->pubtable;
    4750             :     PQExpBuffer query;
    4751             :     char       *tag;
    4752             : 
    4753             :     /* Do nothing if not dumping schema */
    4754         470 :     if (!dopt->dumpSchema)
    4755          42 :         return;
    4756             : 
    4757         428 :     tag = psprintf("%s %s", pubinfo->dobj.name, tbinfo->dobj.name);
    4758             : 
    4759         428 :     query = createPQExpBuffer();
    4760             : 
    4761         428 :     appendPQExpBuffer(query, "ALTER PUBLICATION %s ADD TABLE ONLY",
    4762         428 :                       fmtId(pubinfo->dobj.name));
    4763         428 :     appendPQExpBuffer(query, " %s",
    4764         428 :                       fmtQualifiedDumpable(tbinfo));
    4765             : 
    4766         428 :     if (pubrinfo->pubrattrs)
    4767         124 :         appendPQExpBuffer(query, " (%s)", pubrinfo->pubrattrs);
    4768             : 
    4769         428 :     if (pubrinfo->pubrelqual)
    4770             :     {
    4771             :         /*
    4772             :          * It's necessary to add parentheses around the expression because
    4773             :          * pg_get_expr won't supply the parentheses for things like WHERE
    4774             :          * TRUE.
    4775             :          */
    4776         184 :         appendPQExpBuffer(query, " WHERE (%s)", pubrinfo->pubrelqual);
    4777             :     }
    4778         428 :     appendPQExpBufferStr(query, ";\n");
    4779             : 
    4780             :     /*
    4781             :      * There is no point in creating a drop query as the drop is done by table
    4782             :      * drop.  (If you think to change this, see also _printTocEntry().)
    4783             :      * Although this object doesn't really have ownership as such, set the
    4784             :      * owner field anyway to ensure that the command is run by the correct
    4785             :      * role at restore time.
    4786             :      */
    4787         428 :     if (pubrinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
    4788         428 :         ArchiveEntry(fout, pubrinfo->dobj.catId, pubrinfo->dobj.dumpId,
    4789         428 :                      ARCHIVE_OPTS(.tag = tag,
    4790             :                                   .namespace = tbinfo->dobj.namespace->dobj.name,
    4791             :                                   .owner = pubinfo->rolname,
    4792             :                                   .description = "PUBLICATION TABLE",
    4793             :                                   .section = SECTION_POST_DATA,
    4794             :                                   .createStmt = query->data));
    4795             : 
    4796             :     /* These objects can't currently have comments or seclabels */
    4797             : 
    4798         428 :     free(tag);
    4799         428 :     destroyPQExpBuffer(query);
    4800             : }
    4801             : 
    4802             : /*
    4803             :  * Is the currently connected user a superuser?
    4804             :  */
    4805             : static bool
    4806         308 : is_superuser(Archive *fout)
    4807             : {
    4808         308 :     ArchiveHandle *AH = (ArchiveHandle *) fout;
    4809             :     const char *val;
    4810             : 
    4811         308 :     val = PQparameterStatus(AH->connection, "is_superuser");
    4812             : 
    4813         308 :     if (val && strcmp(val, "on") == 0)
    4814         302 :         return true;
    4815             : 
    4816           6 :     return false;
    4817             : }
    4818             : 
    4819             : /*
    4820             :  * Set the given value to restrict_nonsystem_relation_kind value. Since
    4821             :  * restrict_nonsystem_relation_kind is introduced in minor version releases,
    4822             :  * the setting query is effective only where available.
    4823             :  */
    4824             : static void
    4825         376 : set_restrict_relation_kind(Archive *AH, const char *value)
    4826             : {
    4827         376 :     PQExpBuffer query = createPQExpBuffer();
    4828             :     PGresult   *res;
    4829             : 
    4830         376 :     appendPQExpBuffer(query,
    4831             :                       "SELECT set_config(name, '%s', false) "
    4832             :                       "FROM pg_settings "
    4833             :                       "WHERE name = 'restrict_nonsystem_relation_kind'",
    4834             :                       value);
    4835         376 :     res = ExecuteSqlQuery(AH, query->data, PGRES_TUPLES_OK);
    4836             : 
    4837         376 :     PQclear(res);
    4838         376 :     destroyPQExpBuffer(query);
    4839         376 : }
    4840             : 
    4841             : /*
    4842             :  * getSubscriptions
    4843             :  *    get information about subscriptions
    4844             :  */
    4845             : void
    4846         308 : getSubscriptions(Archive *fout)
    4847             : {
    4848         308 :     DumpOptions *dopt = fout->dopt;
    4849             :     PQExpBuffer query;
    4850             :     PGresult   *res;
    4851             :     SubscriptionInfo *subinfo;
    4852             :     int         i_tableoid;
    4853             :     int         i_oid;
    4854             :     int         i_subname;
    4855             :     int         i_subowner;
    4856             :     int         i_subbinary;
    4857             :     int         i_substream;
    4858             :     int         i_subtwophasestate;
    4859             :     int         i_subdisableonerr;
    4860             :     int         i_subpasswordrequired;
    4861             :     int         i_subrunasowner;
    4862             :     int         i_subconninfo;
    4863             :     int         i_subslotname;
    4864             :     int         i_subsynccommit;
    4865             :     int         i_subpublications;
    4866             :     int         i_suborigin;
    4867             :     int         i_suboriginremotelsn;
    4868             :     int         i_subenabled;
    4869             :     int         i_subfailover;
    4870             :     int         i,
    4871             :                 ntups;
    4872             : 
    4873         308 :     if (dopt->no_subscriptions || fout->remoteVersion < 100000)
    4874           0 :         return;
    4875             : 
    4876         308 :     if (!is_superuser(fout))
    4877             :     {
    4878             :         int         n;
    4879             : 
    4880           6 :         res = ExecuteSqlQuery(fout,
    4881             :                               "SELECT count(*) FROM pg_subscription "
    4882             :                               "WHERE subdbid = (SELECT oid FROM pg_database"
    4883             :                               "                 WHERE datname = current_database())",
    4884             :                               PGRES_TUPLES_OK);
    4885           6 :         n = atoi(PQgetvalue(res, 0, 0));
    4886           6 :         if (n > 0)
    4887           4 :             pg_log_warning("subscriptions not dumped because current user is not a superuser");
    4888           6 :         PQclear(res);
    4889           6 :         return;
    4890             :     }
    4891             : 
    4892         302 :     query = createPQExpBuffer();
    4893             : 
    4894             :     /* Get the subscriptions in current database. */
    4895         302 :     appendPQExpBufferStr(query,
    4896             :                          "SELECT s.tableoid, s.oid, s.subname,\n"
    4897             :                          " s.subowner,\n"
    4898             :                          " s.subconninfo, s.subslotname, s.subsynccommit,\n"
    4899             :                          " s.subpublications,\n");
    4900             : 
    4901         302 :     if (fout->remoteVersion >= 140000)
    4902         302 :         appendPQExpBufferStr(query, " s.subbinary,\n");
    4903             :     else
    4904           0 :         appendPQExpBufferStr(query, " false AS subbinary,\n");
    4905             : 
    4906         302 :     if (fout->remoteVersion >= 140000)
    4907         302 :         appendPQExpBufferStr(query, " s.substream,\n");
    4908             :     else
    4909           0 :         appendPQExpBufferStr(query, " 'f' AS substream,\n");
    4910             : 
    4911         302 :     if (fout->remoteVersion >= 150000)
    4912         302 :         appendPQExpBufferStr(query,
    4913             :                              " s.subtwophasestate,\n"
    4914             :                              " s.subdisableonerr,\n");
    4915             :     else
    4916           0 :         appendPQExpBuffer(query,
    4917             :                           " '%c' AS subtwophasestate,\n"
    4918             :                           " false AS subdisableonerr,\n",
    4919             :                           LOGICALREP_TWOPHASE_STATE_DISABLED);
    4920             : 
    4921         302 :     if (fout->remoteVersion >= 160000)
    4922         302 :         appendPQExpBufferStr(query,
    4923             :                              " s.subpasswordrequired,\n"
    4924             :                              " s.subrunasowner,\n"
    4925             :                              " s.suborigin,\n");
    4926             :     else
    4927           0 :         appendPQExpBuffer(query,
    4928             :                           " 't' AS subpasswordrequired,\n"
    4929             :                           " 't' AS subrunasowner,\n"
    4930             :                           " '%s' AS suborigin,\n",
    4931             :                           LOGICALREP_ORIGIN_ANY);
    4932             : 
    4933         302 :     if (dopt->binary_upgrade && fout->remoteVersion >= 170000)
    4934          28 :         appendPQExpBufferStr(query, " o.remote_lsn AS suboriginremotelsn,\n"
    4935             :                              " s.subenabled,\n");
    4936             :     else
    4937         274 :         appendPQExpBufferStr(query, " NULL AS suboriginremotelsn,\n"
    4938             :                              " false AS subenabled,\n");
    4939             : 
    4940         302 :     if (fout->remoteVersion >= 170000)
    4941         302 :         appendPQExpBufferStr(query,
    4942             :                              " s.subfailover\n");
    4943             :     else
    4944           0 :         appendPQExpBuffer(query,
    4945             :                           " false AS subfailover\n");
    4946             : 
    4947         302 :     appendPQExpBufferStr(query,
    4948             :                          "FROM pg_subscription s\n");
    4949             : 
    4950         302 :     if (dopt->binary_upgrade && fout->remoteVersion >= 170000)
    4951          28 :         appendPQExpBufferStr(query,
    4952             :                              "LEFT JOIN pg_catalog.pg_replication_origin_status o \n"
    4953             :                              "    ON o.external_id = 'pg_' || s.oid::text \n");
    4954             : 
    4955         302 :     appendPQExpBufferStr(query,
    4956             :                          "WHERE s.subdbid = (SELECT oid FROM pg_database\n"
    4957             :                          "                   WHERE datname = current_database())");
    4958             : 
    4959         302 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    4960             : 
    4961         302 :     ntups = PQntuples(res);
    4962             : 
    4963             :     /*
    4964             :      * Get subscription fields. We don't include subskiplsn in the dump as
    4965             :      * after restoring the dump this value may no longer be relevant.
    4966             :      */
    4967         302 :     i_tableoid = PQfnumber(res, "tableoid");
    4968         302 :     i_oid = PQfnumber(res, "oid");
    4969         302 :     i_subname = PQfnumber(res, "subname");
    4970         302 :     i_subowner = PQfnumber(res, "subowner");
    4971         302 :     i_subenabled = PQfnumber(res, "subenabled");
    4972         302 :     i_subbinary = PQfnumber(res, "subbinary");
    4973         302 :     i_substream = PQfnumber(res, "substream");
    4974         302 :     i_subtwophasestate = PQfnumber(res, "subtwophasestate");
    4975         302 :     i_subdisableonerr = PQfnumber(res, "subdisableonerr");
    4976         302 :     i_subpasswordrequired = PQfnumber(res, "subpasswordrequired");
    4977         302 :     i_subrunasowner = PQfnumber(res, "subrunasowner");
    4978         302 :     i_subfailover = PQfnumber(res, "subfailover");
    4979         302 :     i_subconninfo = PQfnumber(res, "subconninfo");
    4980         302 :     i_subslotname = PQfnumber(res, "subslotname");
    4981         302 :     i_subsynccommit = PQfnumber(res, "subsynccommit");
    4982         302 :     i_subpublications = PQfnumber(res, "subpublications");
    4983         302 :     i_suborigin = PQfnumber(res, "suborigin");
    4984         302 :     i_suboriginremotelsn = PQfnumber(res, "suboriginremotelsn");
    4985             : 
    4986         302 :     subinfo = pg_malloc(ntups * sizeof(SubscriptionInfo));
    4987             : 
    4988         552 :     for (i = 0; i < ntups; i++)
    4989             :     {
    4990         250 :         subinfo[i].dobj.objType = DO_SUBSCRIPTION;
    4991         250 :         subinfo[i].dobj.catId.tableoid =
    4992         250 :             atooid(PQgetvalue(res, i, i_tableoid));
    4993         250 :         subinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    4994         250 :         AssignDumpId(&subinfo[i].dobj);
    4995         250 :         subinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_subname));
    4996         250 :         subinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_subowner));
    4997             : 
    4998         250 :         subinfo[i].subenabled =
    4999         250 :             (strcmp(PQgetvalue(res, i, i_subenabled), "t") == 0);
    5000         250 :         subinfo[i].subbinary =
    5001         250 :             (strcmp(PQgetvalue(res, i, i_subbinary), "t") == 0);
    5002         250 :         subinfo[i].substream = *(PQgetvalue(res, i, i_substream));
    5003         250 :         subinfo[i].subtwophasestate = *(PQgetvalue(res, i, i_subtwophasestate));
    5004         250 :         subinfo[i].subdisableonerr =
    5005         250 :             (strcmp(PQgetvalue(res, i, i_subdisableonerr), "t") == 0);
    5006         250 :         subinfo[i].subpasswordrequired =
    5007         250 :             (strcmp(PQgetvalue(res, i, i_subpasswordrequired), "t") == 0);
    5008         250 :         subinfo[i].subrunasowner =
    5009         250 :             (strcmp(PQgetvalue(res, i, i_subrunasowner), "t") == 0);
    5010         250 :         subinfo[i].subfailover =
    5011         250 :             (strcmp(PQgetvalue(res, i, i_subfailover), "t") == 0);
    5012         500 :         subinfo[i].subconninfo =
    5013         250 :             pg_strdup(PQgetvalue(res, i, i_subconninfo));
    5014         250 :         if (PQgetisnull(res, i, i_subslotname))
    5015           0 :             subinfo[i].subslotname = NULL;
    5016             :         else
    5017         250 :             subinfo[i].subslotname =
    5018         250 :                 pg_strdup(PQgetvalue(res, i, i_subslotname));
    5019         500 :         subinfo[i].subsynccommit =
    5020         250 :             pg_strdup(PQgetvalue(res, i, i_subsynccommit));
    5021         500 :         subinfo[i].subpublications =
    5022         250 :             pg_strdup(PQgetvalue(res, i, i_subpublications));
    5023         250 :         subinfo[i].suborigin = pg_strdup(PQgetvalue(res, i, i_suborigin));
    5024         250 :         if (PQgetisnull(res, i, i_suboriginremotelsn))
    5025         248 :             subinfo[i].suboriginremotelsn = NULL;
    5026             :         else
    5027           2 :             subinfo[i].suboriginremotelsn =
    5028           2 :                 pg_strdup(PQgetvalue(res, i, i_suboriginremotelsn));
    5029             : 
    5030             :         /* Decide whether we want to dump it */
    5031         250 :         selectDumpableObject(&(subinfo[i].dobj), fout);
    5032             :     }
    5033         302 :     PQclear(res);
    5034             : 
    5035         302 :     destroyPQExpBuffer(query);
    5036             : }
    5037             : 
    5038             : /*
    5039             :  * getSubscriptionTables
    5040             :  *    Get information about subscription membership for dumpable tables. This
    5041             :  *    will be used only in binary-upgrade mode for PG17 or later versions.
    5042             :  */
    5043             : void
    5044         308 : getSubscriptionTables(Archive *fout)
    5045             : {
    5046         308 :     DumpOptions *dopt = fout->dopt;
    5047         308 :     SubscriptionInfo *subinfo = NULL;
    5048             :     SubRelInfo *subrinfo;
    5049             :     PGresult   *res;
    5050             :     int         i_srsubid;
    5051             :     int         i_srrelid;
    5052             :     int         i_srsubstate;
    5053             :     int         i_srsublsn;
    5054             :     int         ntups;
    5055         308 :     Oid         last_srsubid = InvalidOid;
    5056             : 
    5057         308 :     if (dopt->no_subscriptions || !dopt->binary_upgrade ||
    5058          28 :         fout->remoteVersion < 170000)
    5059         280 :         return;
    5060             : 
    5061          28 :     res = ExecuteSqlQuery(fout,
    5062             :                           "SELECT srsubid, srrelid, srsubstate, srsublsn "
    5063             :                           "FROM pg_catalog.pg_subscription_rel "
    5064             :                           "ORDER BY srsubid",
    5065             :                           PGRES_TUPLES_OK);
    5066          28 :     ntups = PQntuples(res);
    5067          28 :     if (ntups == 0)
    5068          26 :         goto cleanup;
    5069             : 
    5070             :     /* Get pg_subscription_rel attributes */
    5071           2 :     i_srsubid = PQfnumber(res, "srsubid");
    5072           2 :     i_srrelid = PQfnumber(res, "srrelid");
    5073           2 :     i_srsubstate = PQfnumber(res, "srsubstate");
    5074           2 :     i_srsublsn = PQfnumber(res, "srsublsn");
    5075             : 
    5076           2 :     subrinfo = pg_malloc(ntups * sizeof(SubRelInfo));
    5077           6 :     for (int i = 0; i < ntups; i++)
    5078             :     {
    5079           4 :         Oid         cur_srsubid = atooid(PQgetvalue(res, i, i_srsubid));
    5080           4 :         Oid         relid = atooid(PQgetvalue(res, i, i_srrelid));
    5081             :         TableInfo  *tblinfo;
    5082             : 
    5083             :         /*
    5084             :          * If we switched to a new subscription, check if the subscription
    5085             :          * exists.
    5086             :          */
    5087           4 :         if (cur_srsubid != last_srsubid)
    5088             :         {
    5089           4 :             subinfo = findSubscriptionByOid(cur_srsubid);
    5090           4 :             if (subinfo == NULL)
    5091           0 :                 pg_fatal("subscription with OID %u does not exist", cur_srsubid);
    5092             : 
    5093           4 :             last_srsubid = cur_srsubid;
    5094             :         }
    5095             : 
    5096           4 :         tblinfo = findTableByOid(relid);
    5097           4 :         if (tblinfo == NULL)
    5098           0 :             pg_fatal("failed sanity check, table with OID %u not found",
    5099             :                      relid);
    5100             : 
    5101             :         /* OK, make a DumpableObject for this relationship */
    5102           4 :         subrinfo[i].dobj.objType = DO_SUBSCRIPTION_REL;
    5103           4 :         subrinfo[i].dobj.catId.tableoid = relid;
    5104           4 :         subrinfo[i].dobj.catId.oid = cur_srsubid;
    5105           4 :         AssignDumpId(&subrinfo[i].dobj);
    5106           4 :         subrinfo[i].dobj.name = pg_strdup(subinfo->dobj.name);
    5107           4 :         subrinfo[i].tblinfo = tblinfo;
    5108           4 :         subrinfo[i].srsubstate = PQgetvalue(res, i, i_srsubstate)[0];
    5109           4 :         if (PQgetisnull(res, i, i_srsublsn))
    5110           2 :             subrinfo[i].srsublsn = NULL;
    5111             :         else
    5112           2 :             subrinfo[i].srsublsn = pg_strdup(PQgetvalue(res, i, i_srsublsn));
    5113             : 
    5114           4 :         subrinfo[i].subinfo = subinfo;
    5115             : 
    5116             :         /* Decide whether we want to dump it */
    5117           4 :         selectDumpableObject(&(subrinfo[i].dobj), fout);
    5118             :     }
    5119             : 
    5120           2 : cleanup:
    5121          28 :     PQclear(res);
    5122             : }
    5123             : 
    5124             : /*
    5125             :  * dumpSubscriptionTable
    5126             :  *    Dump the definition of the given subscription table mapping. This will be
    5127             :  *    used only in binary-upgrade mode for PG17 or later versions.
    5128             :  */
    5129             : static void
    5130           4 : dumpSubscriptionTable(Archive *fout, const SubRelInfo *subrinfo)
    5131             : {
    5132           4 :     DumpOptions *dopt = fout->dopt;
    5133           4 :     SubscriptionInfo *subinfo = subrinfo->subinfo;
    5134             :     PQExpBuffer query;
    5135             :     char       *tag;
    5136             : 
    5137             :     /* Do nothing if not dumping schema */
    5138           4 :     if (!dopt->dumpSchema)
    5139           0 :         return;
    5140             : 
    5141             :     Assert(fout->dopt->binary_upgrade && fout->remoteVersion >= 170000);
    5142             : 
    5143           4 :     tag = psprintf("%s %s", subinfo->dobj.name, subrinfo->dobj.name);
    5144             : 
    5145           4 :     query = createPQExpBuffer();
    5146             : 
    5147           4 :     if (subinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
    5148             :     {
    5149             :         /*
    5150             :          * binary_upgrade_add_sub_rel_state will add the subscription relation
    5151             :          * to pg_subscription_rel table. This will be used only in
    5152             :          * binary-upgrade mode.
    5153             :          */
    5154           4 :         appendPQExpBufferStr(query,
    5155             :                              "\n-- For binary upgrade, must preserve the subscriber table.\n");
    5156           4 :         appendPQExpBufferStr(query,
    5157             :                              "SELECT pg_catalog.binary_upgrade_add_sub_rel_state(");
    5158           4 :         appendStringLiteralAH(query, subrinfo->dobj.name, fout);
    5159           4 :         appendPQExpBuffer(query,
    5160             :                           ", %u, '%c'",
    5161           4 :                           subrinfo->tblinfo->dobj.catId.oid,
    5162           4 :                           subrinfo->srsubstate);
    5163             : 
    5164           4 :         if (subrinfo->srsublsn && subrinfo->srsublsn[0] != '\0')
    5165           2 :             appendPQExpBuffer(query, ", '%s'", subrinfo->srsublsn);
    5166             :         else
    5167           2 :             appendPQExpBuffer(query, ", NULL");
    5168             : 
    5169           4 :         appendPQExpBufferStr(query, ");\n");
    5170             :     }
    5171             : 
    5172             :     /*
    5173             :      * There is no point in creating a drop query as the drop is done by table
    5174             :      * drop.  (If you think to change this, see also _printTocEntry().)
    5175             :      * Although this object doesn't really have ownership as such, set the
    5176             :      * owner field anyway to ensure that the command is run by the correct
    5177             :      * role at restore time.
    5178             :      */
    5179           4 :     if (subrinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
    5180           4 :         ArchiveEntry(fout, subrinfo->dobj.catId, subrinfo->dobj.dumpId,
    5181           4 :                      ARCHIVE_OPTS(.tag = tag,
    5182             :                                   .namespace = subrinfo->tblinfo->dobj.namespace->dobj.name,
    5183             :                                   .owner = subinfo->rolname,
    5184             :                                   .description = "SUBSCRIPTION TABLE",
    5185             :                                   .section = SECTION_POST_DATA,
    5186             :                                   .createStmt = query->data));
    5187             : 
    5188             :     /* These objects can't currently have comments or seclabels */
    5189             : 
    5190           4 :     free(tag);
    5191           4 :     destroyPQExpBuffer(query);
    5192             : }
    5193             : 
    5194             : /*
    5195             :  * dumpSubscription
    5196             :  *    dump the definition of the given subscription
    5197             :  */
    5198             : static void
    5199         214 : dumpSubscription(Archive *fout, const SubscriptionInfo *subinfo)
    5200             : {
    5201         214 :     DumpOptions *dopt = fout->dopt;
    5202             :     PQExpBuffer delq;
    5203             :     PQExpBuffer query;
    5204             :     PQExpBuffer publications;
    5205             :     char       *qsubname;
    5206         214 :     char      **pubnames = NULL;
    5207         214 :     int         npubnames = 0;
    5208             :     int         i;
    5209             : 
    5210             :     /* Do nothing if not dumping schema */
    5211         214 :     if (!dopt->dumpSchema)
    5212          18 :         return;
    5213             : 
    5214         196 :     delq = createPQExpBuffer();
    5215         196 :     query = createPQExpBuffer();
    5216             : 
    5217         196 :     qsubname = pg_strdup(fmtId(subinfo->dobj.name));
    5218             : 
    5219         196 :     appendPQExpBuffer(delq, "DROP SUBSCRIPTION %s;\n",
    5220             :                       qsubname);
    5221             : 
    5222         196 :     appendPQExpBuffer(query, "CREATE SUBSCRIPTION %s CONNECTION ",
    5223             :                       qsubname);
    5224         196 :     appendStringLiteralAH(query, subinfo->subconninfo, fout);
    5225             : 
    5226             :     /* Build list of quoted publications and append them to query. */
    5227         196 :     if (!parsePGArray(subinfo->subpublications, &pubnames, &npubnames))
    5228           0 :         pg_fatal("could not parse %s array", "subpublications");
    5229             : 
    5230         196 :     publications = createPQExpBuffer();
    5231         392 :     for (i = 0; i < npubnames; i++)
    5232             :     {
    5233         196 :         if (i > 0)
    5234           0 :             appendPQExpBufferStr(publications, ", ");
    5235             : 
    5236         196 :         appendPQExpBufferStr(publications, fmtId(pubnames[i]));
    5237             :     }
    5238             : 
    5239         196 :     appendPQExpBuffer(query, " PUBLICATION %s WITH (connect = false, slot_name = ", publications->data);
    5240         196 :     if (subinfo->subslotname)
    5241         196 :         appendStringLiteralAH(query, subinfo->subslotname, fout);
    5242             :     else
    5243           0 :         appendPQExpBufferStr(query, "NONE");
    5244             : 
    5245         196 :     if (subinfo->subbinary)
    5246           0 :         appendPQExpBufferStr(query, ", binary = true");
    5247             : 
    5248         196 :     if (subinfo->substream == LOGICALREP_STREAM_ON)
    5249          64 :         appendPQExpBufferStr(query, ", streaming = on");
    5250         132 :     else if (subinfo->substream == LOGICALREP_STREAM_PARALLEL)
    5251          68 :         appendPQExpBufferStr(query, ", streaming = parallel");
    5252             :     else
    5253          64 :         appendPQExpBufferStr(query, ", streaming = off");
    5254             : 
    5255         196 :     if (subinfo->subtwophasestate != LOGICALREP_TWOPHASE_STATE_DISABLED)
    5256           0 :         appendPQExpBufferStr(query, ", two_phase = on");
    5257             : 
    5258         196 :     if (subinfo->subdisableonerr)
    5259           0 :         appendPQExpBufferStr(query, ", disable_on_error = true");
    5260             : 
    5261         196 :     if (!subinfo->subpasswordrequired)
    5262           0 :         appendPQExpBuffer(query, ", password_required = false");
    5263             : 
    5264         196 :     if (subinfo->subrunasowner)
    5265           0 :         appendPQExpBufferStr(query, ", run_as_owner = true");
    5266             : 
    5267         196 :     if (subinfo->subfailover)
    5268           2 :         appendPQExpBufferStr(query, ", failover = true");
    5269             : 
    5270         196 :     if (strcmp(subinfo->subsynccommit, "off") != 0)
    5271           0 :         appendPQExpBuffer(query, ", synchronous_commit = %s", fmtId(subinfo->subsynccommit));
    5272             : 
    5273         196 :     if (pg_strcasecmp(subinfo->suborigin, LOGICALREP_ORIGIN_ANY) != 0)
    5274          64 :         appendPQExpBuffer(query, ", origin = %s", subinfo->suborigin);
    5275             : 
    5276         196 :     appendPQExpBufferStr(query, ");\n");
    5277             : 
    5278             :     /*
    5279             :      * In binary-upgrade mode, we allow the replication to continue after the
    5280             :      * upgrade.
    5281             :      */
    5282         196 :     if (dopt->binary_upgrade && fout->remoteVersion >= 170000)
    5283             :     {
    5284          10 :         if (subinfo->suboriginremotelsn)
    5285             :         {
    5286             :             /*
    5287             :              * Preserve the remote_lsn for the subscriber's replication
    5288             :              * origin. This value is required to start the replication from
    5289             :              * the position before the upgrade. This value will be stale if
    5290             :              * the publisher gets upgraded before the subscriber node.
    5291             :              * However, this shouldn't be a problem as the upgrade of the
    5292             :              * publisher ensures that all the transactions were replicated
    5293             :              * before upgrading it.
    5294             :              */
    5295           2 :             appendPQExpBufferStr(query,
    5296             :                                  "\n-- For binary upgrade, must preserve the remote_lsn for the subscriber's replication origin.\n");
    5297           2 :             appendPQExpBufferStr(query,
    5298             :                                  "SELECT pg_catalog.binary_upgrade_replorigin_advance(");
    5299           2 :             appendStringLiteralAH(query, subinfo->dobj.name, fout);
    5300           2 :             appendPQExpBuffer(query, ", '%s');\n", subinfo->suboriginremotelsn);
    5301             :         }
    5302             : 
    5303          10 :         if (subinfo->subenabled)
    5304             :         {
    5305             :             /*
    5306             :              * Enable the subscription to allow the replication to continue
    5307             :              * after the upgrade.
    5308             :              */
    5309           2 :             appendPQExpBufferStr(query,
    5310             :                                  "\n-- For binary upgrade, must preserve the subscriber's running state.\n");
    5311           2 :             appendPQExpBuffer(query, "ALTER SUBSCRIPTION %s ENABLE;\n", qsubname);
    5312             :         }
    5313             :     }
    5314             : 
    5315         196 :     if (subinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
    5316         196 :         ArchiveEntry(fout, subinfo->dobj.catId, subinfo->dobj.dumpId,
    5317         196 :                      ARCHIVE_OPTS(.tag = subinfo->dobj.name,
    5318             :                                   .owner = subinfo->rolname,
    5319             :                                   .description = "SUBSCRIPTION",
    5320             :                                   .section = SECTION_POST_DATA,
    5321             :                                   .createStmt = query->data,
    5322             :                                   .dropStmt = delq->data));
    5323             : 
    5324         196 :     if (subinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
    5325          64 :         dumpComment(fout, "SUBSCRIPTION", qsubname,
    5326             :                     NULL, subinfo->rolname,
    5327             :                     subinfo->dobj.catId, 0, subinfo->dobj.dumpId);
    5328             : 
    5329         196 :     if (subinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
    5330           0 :         dumpSecLabel(fout, "SUBSCRIPTION", qsubname,
    5331             :                      NULL, subinfo->rolname,
    5332             :                      subinfo->dobj.catId, 0, subinfo->dobj.dumpId);
    5333             : 
    5334         196 :     destroyPQExpBuffer(publications);
    5335         196 :     free(pubnames);
    5336             : 
    5337         196 :     destroyPQExpBuffer(delq);
    5338         196 :     destroyPQExpBuffer(query);
    5339         196 :     free(qsubname);
    5340             : }
    5341             : 
    5342             : /*
    5343             :  * Given a "create query", append as many ALTER ... DEPENDS ON EXTENSION as
    5344             :  * the object needs.
    5345             :  */
    5346             : static void
    5347        9756 : append_depends_on_extension(Archive *fout,
    5348             :                             PQExpBuffer create,
    5349             :                             const DumpableObject *dobj,
    5350             :                             const char *catalog,
    5351             :                             const char *keyword,
    5352             :                             const char *objname)
    5353             : {
    5354        9756 :     if (dobj->depends_on_ext)
    5355             :     {
    5356             :         char       *nm;
    5357             :         PGresult   *res;
    5358             :         PQExpBuffer query;
    5359             :         int         ntups;
    5360             :         int         i_extname;
    5361             :         int         i;
    5362             : 
    5363             :         /* dodge fmtId() non-reentrancy */
    5364          84 :         nm = pg_strdup(objname);
    5365             : 
    5366          84 :         query = createPQExpBuffer();
    5367          84 :         appendPQExpBuffer(query,
    5368             :                           "SELECT e.extname "
    5369             :                           "FROM pg_catalog.pg_depend d, pg_catalog.pg_extension e "
    5370             :                           "WHERE d.refobjid = e.oid AND classid = '%s'::pg_catalog.regclass "
    5371             :                           "AND objid = '%u'::pg_catalog.oid AND deptype = 'x' "
    5372             :                           "AND refclassid = 'pg_catalog.pg_extension'::pg_catalog.regclass",
    5373             :                           catalog,
    5374             :                           dobj->catId.oid);
    5375          84 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    5376          84 :         ntups = PQntuples(res);
    5377          84 :         i_extname = PQfnumber(res, "extname");
    5378         168 :         for (i = 0; i < ntups; i++)
    5379             :         {
    5380          84 :             appendPQExpBuffer(create, "\nALTER %s %s DEPENDS ON EXTENSION %s;",
    5381             :                               keyword, nm,
    5382          84 :                               fmtId(PQgetvalue(res, i, i_extname)));
    5383             :         }
    5384             : 
    5385          84 :         PQclear(res);
    5386          84 :         destroyPQExpBuffer(query);
    5387          84 :         pg_free(nm);
    5388             :     }
    5389        9756 : }
    5390             : 
    5391             : static Oid
    5392           0 : get_next_possible_free_pg_type_oid(Archive *fout, PQExpBuffer upgrade_query)
    5393             : {
    5394             :     /*
    5395             :      * If the old version didn't assign an array type, but the new version
    5396             :      * does, we must select an unused type OID to assign.  This currently only
    5397             :      * happens for domains, when upgrading pre-v11 to v11 and up.
    5398             :      *
    5399             :      * Note: local state here is kind of ugly, but we must have some, since we
    5400             :      * mustn't choose the same unused OID more than once.
    5401             :      */
    5402             :     static Oid  next_possible_free_oid = FirstNormalObjectId;
    5403             :     PGresult   *res;
    5404             :     bool        is_dup;
    5405             : 
    5406             :     do
    5407             :     {
    5408           0 :         ++next_possible_free_oid;
    5409           0 :         printfPQExpBuffer(upgrade_query,
    5410             :                           "SELECT EXISTS(SELECT 1 "
    5411             :                           "FROM pg_catalog.pg_type "
    5412             :                           "WHERE oid = '%u'::pg_catalog.oid);",
    5413             :                           next_possible_free_oid);
    5414           0 :         res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data);
    5415           0 :         is_dup = (PQgetvalue(res, 0, 0)[0] == 't');
    5416           0 :         PQclear(res);
    5417           0 :     } while (is_dup);
    5418             : 
    5419           0 :     return next_possible_free_oid;
    5420             : }
    5421             : 
    5422             : static void
    5423        1660 : binary_upgrade_set_type_oids_by_type_oid(Archive *fout,
    5424             :                                          PQExpBuffer upgrade_buffer,
    5425             :                                          Oid pg_type_oid,
    5426             :                                          bool force_array_type,
    5427             :                                          bool include_multirange_type)
    5428             : {
    5429        1660 :     PQExpBuffer upgrade_query = createPQExpBuffer();
    5430             :     PGresult   *res;
    5431             :     Oid         pg_type_array_oid;
    5432             :     Oid         pg_type_multirange_oid;
    5433             :     Oid         pg_type_multirange_array_oid;
    5434             :     TypeInfo   *tinfo;
    5435             : 
    5436        1660 :     appendPQExpBufferStr(upgrade_buffer, "\n-- For binary upgrade, must preserve pg_type oid\n");
    5437        1660 :     appendPQExpBuffer(upgrade_buffer,
    5438             :                       "SELECT pg_catalog.binary_upgrade_set_next_pg_type_oid('%u'::pg_catalog.oid);\n\n",
    5439             :                       pg_type_oid);
    5440             : 
    5441        1660 :     tinfo = findTypeByOid(pg_type_oid);
    5442        1660 :     if (tinfo)
    5443        1660 :         pg_type_array_oid = tinfo->typarray;
    5444             :     else
    5445           0 :         pg_type_array_oid = InvalidOid;
    5446             : 
    5447        1660 :     if (!OidIsValid(pg_type_array_oid) && force_array_type)
    5448           0 :         pg_type_array_oid = get_next_possible_free_pg_type_oid(fout, upgrade_query);
    5449             : 
    5450        1660 :     if (OidIsValid(pg_type_array_oid))
    5451             :     {
    5452        1656 :         appendPQExpBufferStr(upgrade_buffer,
    5453             :                              "\n-- For binary upgrade, must preserve pg_type array oid\n");
    5454        1656 :         appendPQExpBuffer(upgrade_buffer,
    5455             :                           "SELECT pg_catalog.binary_upgrade_set_next_array_pg_type_oid('%u'::pg_catalog.oid);\n\n",
    5456             :                           pg_type_array_oid);
    5457             :     }
    5458             : 
    5459             :     /*
    5460             :      * Pre-set the multirange type oid and its own array type oid.
    5461             :      */
    5462        1660 :     if (include_multirange_type)
    5463             :     {
    5464          12 :         if (fout->remoteVersion >= 140000)
    5465             :         {
    5466          12 :             printfPQExpBuffer(upgrade_query,
    5467             :                               "SELECT t.oid, t.typarray "
    5468             :                               "FROM pg_catalog.pg_type t "
    5469             :                               "JOIN pg_catalog.pg_range r "
    5470             :                               "ON t.oid = r.rngmultitypid "
    5471             :                               "WHERE r.rngtypid = '%u'::pg_catalog.oid;",
    5472             :                               pg_type_oid);
    5473             : 
    5474          12 :             res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data);
    5475             : 
    5476          12 :             pg_type_multirange_oid = atooid(PQgetvalue(res, 0, PQfnumber(res, "oid")));
    5477          12 :             pg_type_multirange_array_oid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typarray")));
    5478             : 
    5479          12 :             PQclear(res);
    5480             :         }
    5481             :         else
    5482             :         {
    5483           0 :             pg_type_multirange_oid = get_next_possible_free_pg_type_oid(fout, upgrade_query);
    5484           0 :             pg_type_multirange_array_oid = get_next_possible_free_pg_type_oid(fout, upgrade_query);
    5485             :         }
    5486             : 
    5487          12 :         appendPQExpBufferStr(upgrade_buffer,
    5488             :                              "\n-- For binary upgrade, must preserve multirange pg_type oid\n");
    5489          12 :         appendPQExpBuffer(upgrade_buffer,
    5490             :                           "SELECT pg_catalog.binary_upgrade_set_next_multirange_pg_type_oid('%u'::pg_catalog.oid);\n\n",
    5491             :                           pg_type_multirange_oid);
    5492          12 :         appendPQExpBufferStr(upgrade_buffer,
    5493             :                              "\n-- For binary upgrade, must preserve multirange pg_type array oid\n");
    5494          12 :         appendPQExpBuffer(upgrade_buffer,
    5495             :                           "SELECT pg_catalog.binary_upgrade_set_next_multirange_array_pg_type_oid('%u'::pg_catalog.oid);\n\n",
    5496             :                           pg_type_multirange_array_oid);
    5497             :     }
    5498             : 
    5499        1660 :     destroyPQExpBuffer(upgrade_query);
    5500        1660 : }
    5501             : 
    5502             : static void
    5503        1524 : binary_upgrade_set_type_oids_by_rel(Archive *fout,
    5504             :                                     PQExpBuffer upgrade_buffer,
    5505             :                                     const TableInfo *tbinfo)
    5506             : {
    5507        1524 :     Oid         pg_type_oid = tbinfo->reltype;
    5508             : 
    5509        1524 :     if (OidIsValid(pg_type_oid))
    5510        1524 :         binary_upgrade_set_type_oids_by_type_oid(fout, upgrade_buffer,
    5511             :                                                  pg_type_oid, false, false);
    5512        1524 : }
    5513             : 
    5514             : /*
    5515             :  * bsearch() comparator for BinaryUpgradeClassOidItem
    5516             :  */
    5517             : static int
    5518       21832 : BinaryUpgradeClassOidItemCmp(const void *p1, const void *p2)
    5519             : {
    5520       21832 :     BinaryUpgradeClassOidItem v1 = *((const BinaryUpgradeClassOidItem *) p1);
    5521       21832 :     BinaryUpgradeClassOidItem v2 = *((const BinaryUpgradeClassOidItem *) p2);
    5522             : 
    5523       21832 :     return pg_cmp_u32(v1.oid, v2.oid);
    5524             : }
    5525             : 
    5526             : /*
    5527             :  * collectBinaryUpgradeClassOids
    5528             :  *
    5529             :  * Construct a table of pg_class information required for
    5530             :  * binary_upgrade_set_pg_class_oids().  The table is sorted by OID for speed in
    5531             :  * lookup.
    5532             :  */
    5533             : static void
    5534          28 : collectBinaryUpgradeClassOids(Archive *fout)
    5535             : {
    5536             :     PGresult   *res;
    5537             :     const char *query;
    5538             : 
    5539          28 :     query = "SELECT c.oid, c.relkind, c.relfilenode, c.reltoastrelid, "
    5540             :         "ct.relfilenode, i.indexrelid, cti.relfilenode "
    5541             :         "FROM pg_catalog.pg_class c LEFT JOIN pg_catalog.pg_index i "
    5542             :         "ON (c.reltoastrelid = i.indrelid AND i.indisvalid) "
    5543             :         "LEFT JOIN pg_catalog.pg_class ct ON (c.reltoastrelid = ct.oid) "
    5544             :         "LEFT JOIN pg_catalog.pg_class AS cti ON (i.indexrelid = cti.oid) "
    5545             :         "ORDER BY c.oid;";
    5546             : 
    5547          28 :     res = ExecuteSqlQuery(fout, query, PGRES_TUPLES_OK);
    5548             : 
    5549          28 :     nbinaryUpgradeClassOids = PQntuples(res);
    5550          28 :     binaryUpgradeClassOids = (BinaryUpgradeClassOidItem *)
    5551          28 :         pg_malloc(nbinaryUpgradeClassOids * sizeof(BinaryUpgradeClassOidItem));
    5552             : 
    5553       14966 :     for (int i = 0; i < nbinaryUpgradeClassOids; i++)
    5554             :     {
    5555       14938 :         binaryUpgradeClassOids[i].oid = atooid(PQgetvalue(res, i, 0));
    5556       14938 :         binaryUpgradeClassOids[i].relkind = *PQgetvalue(res, i, 1);
    5557       14938 :         binaryUpgradeClassOids[i].relfilenumber = atooid(PQgetvalue(res, i, 2));
    5558       14938 :         binaryUpgradeClassOids[i].toast_oid = atooid(PQgetvalue(res, i, 3));
    5559       14938 :         binaryUpgradeClassOids[i].toast_relfilenumber = atooid(PQgetvalue(res, i, 4));
    5560       14938 :         binaryUpgradeClassOids[i].toast_index_oid = atooid(PQgetvalue(res, i, 5));
    5561       14938 :         binaryUpgradeClassOids[i].toast_index_relfilenumber = atooid(PQgetvalue(res, i, 6));
    5562             :     }
    5563             : 
    5564          28 :     PQclear(res);
    5565          28 : }
    5566             : 
    5567             : static void
    5568        2222 : binary_upgrade_set_pg_class_oids(Archive *fout,
    5569             :                                  PQExpBuffer upgrade_buffer, Oid pg_class_oid)
    5570             : {
    5571        2222 :     BinaryUpgradeClassOidItem key = {0};
    5572             :     BinaryUpgradeClassOidItem *entry;
    5573             : 
    5574             :     Assert(binaryUpgradeClassOids);
    5575             : 
    5576             :     /*
    5577             :      * Preserve the OID and relfilenumber of the table, table's index, table's
    5578             :      * toast table and toast table's index if any.
    5579             :      *
    5580             :      * One complexity is that the current table definition might not require
    5581             :      * the creation of a TOAST table, but the old database might have a TOAST
    5582             :      * table that was created earlier, before some wide columns were dropped.
    5583             :      * By setting the TOAST oid we force creation of the TOAST heap and index
    5584             :      * by the new backend, so we can copy the files during binary upgrade
    5585             :      * without worrying about this case.
    5586             :      */
    5587        2222 :     key.oid = pg_class_oid;
    5588        2222 :     entry = bsearch(&key, binaryUpgradeClassOids, nbinaryUpgradeClassOids,
    5589             :                     sizeof(BinaryUpgradeClassOidItem),
    5590             :                     BinaryUpgradeClassOidItemCmp);
    5591             : 
    5592        2222 :     appendPQExpBufferStr(upgrade_buffer,
    5593             :                          "\n-- For binary upgrade, must preserve pg_class oids and relfilenodes\n");
    5594             : 
    5595        2222 :     if (entry->relkind != RELKIND_INDEX &&
    5596        1722 :         entry->relkind != RELKIND_PARTITIONED_INDEX)
    5597             :     {
    5598        1672 :         appendPQExpBuffer(upgrade_buffer,
    5599             :                           "SELECT pg_catalog.binary_upgrade_set_next_heap_pg_class_oid('%u'::pg_catalog.oid);\n",
    5600             :                           pg_class_oid);
    5601             : 
    5602             :         /*
    5603             :          * Not every relation has storage. Also, in a pre-v12 database,
    5604             :          * partitioned tables have a relfilenumber, which should not be
    5605             :          * preserved when upgrading.
    5606             :          */
    5607        1672 :         if (RelFileNumberIsValid(entry->relfilenumber) &&
    5608        1364 :             entry->relkind != RELKIND_PARTITIONED_TABLE)
    5609        1364 :             appendPQExpBuffer(upgrade_buffer,
    5610             :                               "SELECT pg_catalog.binary_upgrade_set_next_heap_relfilenode('%u'::pg_catalog.oid);\n",
    5611             :                               entry->relfilenumber);
    5612             : 
    5613             :         /*
    5614             :          * In a pre-v12 database, partitioned tables might be marked as having
    5615             :          * toast tables, but we should ignore them if so.
    5616             :          */
    5617        1672 :         if (OidIsValid(entry->toast_oid) &&
    5618         548 :             entry->relkind != RELKIND_PARTITIONED_TABLE)
    5619             :         {
    5620         548 :             appendPQExpBuffer(upgrade_buffer,
    5621             :                               "SELECT pg_catalog.binary_upgrade_set_next_toast_pg_class_oid('%u'::pg_catalog.oid);\n",
    5622             :                               entry->toast_oid);
    5623         548 :             appendPQExpBuffer(upgrade_buffer,
    5624             :                               "SELECT pg_catalog.binary_upgrade_set_next_toast_relfilenode('%u'::pg_catalog.oid);\n",
    5625             :                               entry->toast_relfilenumber);
    5626             : 
    5627             :             /* every toast table has an index */
    5628         548 :             appendPQExpBuffer(upgrade_buffer,
    5629             :                               "SELECT pg_catalog.binary_upgrade_set_next_index_pg_class_oid('%u'::pg_catalog.oid);\n",
    5630             :                               entry->toast_index_oid);
    5631         548 :             appendPQExpBuffer(upgrade_buffer,
    5632             :                               "SELECT pg_catalog.binary_upgrade_set_next_index_relfilenode('%u'::pg_catalog.oid);\n",
    5633             :                               entry->toast_index_relfilenumber);
    5634             :         }
    5635             :     }
    5636             :     else
    5637             :     {
    5638             :         /* Preserve the OID and relfilenumber of the index */
    5639         550 :         appendPQExpBuffer(upgrade_buffer,
    5640             :                           "SELECT pg_catalog.binary_upgrade_set_next_index_pg_class_oid('%u'::pg_catalog.oid);\n",
    5641             :                           pg_class_oid);
    5642         550 :         appendPQExpBuffer(upgrade_buffer,
    5643             :                           "SELECT pg_catalog.binary_upgrade_set_next_index_relfilenode('%u'::pg_catalog.oid);\n",
    5644             :                           entry->relfilenumber);
    5645             :     }
    5646             : 
    5647        2222 :     appendPQExpBufferChar(upgrade_buffer, '\n');
    5648        2222 : }
    5649             : 
    5650             : /*
    5651             :  * If the DumpableObject is a member of an extension, add a suitable
    5652             :  * ALTER EXTENSION ADD command to the creation commands in upgrade_buffer.
    5653             :  *
    5654             :  * For somewhat historical reasons, objname should already be quoted,
    5655             :  * but not objnamespace (if any).
    5656             :  */
    5657             : static void
    5658        2650 : binary_upgrade_extension_member(PQExpBuffer upgrade_buffer,
    5659             :                                 const DumpableObject *dobj,
    5660             :                                 const char *objtype,
    5661             :                                 const char *objname,
    5662             :                                 const char *objnamespace)
    5663             : {
    5664        2650 :     DumpableObject *extobj = NULL;
    5665             :     int         i;
    5666             : 
    5667        2650 :     if (!dobj->ext_member)
    5668        2618 :         return;
    5669             : 
    5670             :     /*
    5671             :      * Find the parent extension.  We could avoid this search if we wanted to
    5672             :      * add a link field to DumpableObject, but the space costs of that would
    5673             :      * be considerable.  We assume that member objects could only have a
    5674             :      * direct dependency on their own extension, not any others.
    5675             :      */
    5676          32 :     for (i = 0; i < dobj->nDeps; i++)
    5677             :     {
    5678          32 :         extobj = findObjectByDumpId(dobj->dependencies[i]);
    5679          32 :         if (extobj && extobj->objType == DO_EXTENSION)
    5680          32 :             break;
    5681           0 :         extobj = NULL;
    5682             :     }
    5683          32 :     if (extobj == NULL)
    5684           0 :         pg_fatal("could not find parent extension for %s %s",
    5685             :                  objtype, objname);
    5686             : 
    5687          32 :     appendPQExpBufferStr(upgrade_buffer,
    5688             :                          "\n-- For binary upgrade, handle extension membership the hard way\n");
    5689          32 :     appendPQExpBuffer(upgrade_buffer, "ALTER EXTENSION %s ADD %s ",
    5690          32 :                       fmtId(extobj->name),
    5691             :                       objtype);
    5692          32 :     if (objnamespace && *objnamespace)
    5693          26 :         appendPQExpBuffer(upgrade_buffer, "%s.", fmtId(objnamespace));
    5694          32 :     appendPQExpBuffer(upgrade_buffer, "%s;\n", objname);
    5695             : }
    5696             : 
    5697             : /*
    5698             :  * getNamespaces:
    5699             :  *    get information about all namespaces in the system catalogs
    5700             :  */
    5701             : void
    5702         310 : getNamespaces(Archive *fout)
    5703             : {
    5704             :     PGresult   *res;
    5705             :     int         ntups;
    5706             :     int         i;
    5707             :     PQExpBuffer query;
    5708             :     NamespaceInfo *nsinfo;
    5709             :     int         i_tableoid;
    5710             :     int         i_oid;
    5711             :     int         i_nspname;
    5712             :     int         i_nspowner;
    5713             :     int         i_nspacl;
    5714             :     int         i_acldefault;
    5715             : 
    5716         310 :     query = createPQExpBuffer();
    5717             : 
    5718             :     /*
    5719             :      * we fetch all namespaces including system ones, so that every object we
    5720             :      * read in can be linked to a containing namespace.
    5721             :      */
    5722         310 :     appendPQExpBufferStr(query, "SELECT n.tableoid, n.oid, n.nspname, "
    5723             :                          "n.nspowner, "
    5724             :                          "n.nspacl, "
    5725             :                          "acldefault('n', n.nspowner) AS acldefault "
    5726             :                          "FROM pg_namespace n");
    5727             : 
    5728         310 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    5729             : 
    5730         310 :     ntups = PQntuples(res);
    5731             : 
    5732         310 :     nsinfo = (NamespaceInfo *) pg_malloc(ntups * sizeof(NamespaceInfo));
    5733             : 
    5734         310 :     i_tableoid = PQfnumber(res, "tableoid");
    5735         310 :     i_oid = PQfnumber(res, "oid");
    5736         310 :     i_nspname = PQfnumber(res, "nspname");
    5737         310 :     i_nspowner = PQfnumber(res, "nspowner");
    5738         310 :     i_nspacl = PQfnumber(res, "nspacl");
    5739         310 :     i_acldefault = PQfnumber(res, "acldefault");
    5740             : 
    5741        2820 :     for (i = 0; i < ntups; i++)
    5742             :     {
    5743             :         const char *nspowner;
    5744             : 
    5745        2510 :         nsinfo[i].dobj.objType = DO_NAMESPACE;
    5746        2510 :         nsinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    5747        2510 :         nsinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    5748        2510 :         AssignDumpId(&nsinfo[i].dobj);
    5749        2510 :         nsinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_nspname));
    5750        2510 :         nsinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_nspacl));
    5751        2510 :         nsinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
    5752        2510 :         nsinfo[i].dacl.privtype = 0;
    5753        2510 :         nsinfo[i].dacl.initprivs = NULL;
    5754        2510 :         nspowner = PQgetvalue(res, i, i_nspowner);
    5755        2510 :         nsinfo[i].nspowner = atooid(nspowner);
    5756        2510 :         nsinfo[i].rolname = getRoleName(nspowner);
    5757             : 
    5758             :         /* Decide whether to dump this namespace */
    5759        2510 :         selectDumpableNamespace(&nsinfo[i], fout);
    5760             : 
    5761             :         /* Mark whether namespace has an ACL */
    5762        2510 :         if (!PQgetisnull(res, i, i_nspacl))
    5763        1036 :             nsinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
    5764             : 
    5765             :         /*
    5766             :          * We ignore any pg_init_privs.initprivs entry for the public schema
    5767             :          * and assume a predetermined default, for several reasons.  First,
    5768             :          * dropping and recreating the schema removes its pg_init_privs entry,
    5769             :          * but an empty destination database starts with this ACL nonetheless.
    5770             :          * Second, we support dump/reload of public schema ownership changes.
    5771             :          * ALTER SCHEMA OWNER filters nspacl through aclnewowner(), but
    5772             :          * initprivs continues to reflect the initial owner.  Hence,
    5773             :          * synthesize the value that nspacl will have after the restore's
    5774             :          * ALTER SCHEMA OWNER.  Third, this makes the destination database
    5775             :          * match the source's ACL, even if the latter was an initdb-default
    5776             :          * ACL, which changed in v15.  An upgrade pulls in changes to most
    5777             :          * system object ACLs that the DBA had not customized.  We've made the
    5778             :          * public schema depart from that, because changing its ACL so easily
    5779             :          * breaks applications.
    5780             :          */
    5781        2510 :         if (strcmp(nsinfo[i].dobj.name, "public") == 0)
    5782             :         {
    5783         302 :             PQExpBuffer aclarray = createPQExpBuffer();
    5784         302 :             PQExpBuffer aclitem = createPQExpBuffer();
    5785             : 
    5786             :             /* Standard ACL as of v15 is {owner=UC/owner,=U/owner} */
    5787         302 :             appendPQExpBufferChar(aclarray, '{');
    5788         302 :             quoteAclUserName(aclitem, nsinfo[i].rolname);
    5789         302 :             appendPQExpBufferStr(aclitem, "=UC/");
    5790         302 :             quoteAclUserName(aclitem, nsinfo[i].rolname);
    5791         302 :             appendPGArray(aclarray, aclitem->data);
    5792         302 :             resetPQExpBuffer(aclitem);
    5793         302 :             appendPQExpBufferStr(aclitem, "=U/");
    5794         302 :             quoteAclUserName(aclitem, nsinfo[i].rolname);
    5795         302 :             appendPGArray(aclarray, aclitem->data);
    5796         302 :             appendPQExpBufferChar(aclarray, '}');
    5797             : 
    5798         302 :             nsinfo[i].dacl.privtype = 'i';
    5799         302 :             nsinfo[i].dacl.initprivs = pstrdup(aclarray->data);
    5800         302 :             nsinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
    5801             : 
    5802         302 :             destroyPQExpBuffer(aclarray);
    5803         302 :             destroyPQExpBuffer(aclitem);
    5804             :         }
    5805             :     }
    5806             : 
    5807         310 :     PQclear(res);
    5808         310 :     destroyPQExpBuffer(query);
    5809         310 : }
    5810             : 
    5811             : /*
    5812             :  * findNamespace:
    5813             :  *      given a namespace OID, look up the info read by getNamespaces
    5814             :  */
    5815             : static NamespaceInfo *
    5816      963862 : findNamespace(Oid nsoid)
    5817             : {
    5818             :     NamespaceInfo *nsinfo;
    5819             : 
    5820      963862 :     nsinfo = findNamespaceByOid(nsoid);
    5821      963862 :     if (nsinfo == NULL)
    5822           0 :         pg_fatal("schema with OID %u does not exist", nsoid);
    5823      963862 :     return nsinfo;
    5824             : }
    5825             : 
    5826             : /*
    5827             :  * getExtensions:
    5828             :  *    read all extensions in the system catalogs and return them in the
    5829             :  * ExtensionInfo* structure
    5830             :  *
    5831             :  *  numExtensions is set to the number of extensions read in
    5832             :  */
    5833             : ExtensionInfo *
    5834         310 : getExtensions(Archive *fout, int *numExtensions)
    5835             : {
    5836         310 :     DumpOptions *dopt = fout->dopt;
    5837             :     PGresult   *res;
    5838             :     int         ntups;
    5839             :     int         i;
    5840             :     PQExpBuffer query;
    5841         310 :     ExtensionInfo *extinfo = NULL;
    5842             :     int         i_tableoid;
    5843             :     int         i_oid;
    5844             :     int         i_extname;
    5845             :     int         i_nspname;
    5846             :     int         i_extrelocatable;
    5847             :     int         i_extversion;
    5848             :     int         i_extconfig;
    5849             :     int         i_extcondition;
    5850             : 
    5851         310 :     query = createPQExpBuffer();
    5852             : 
    5853         310 :     appendPQExpBufferStr(query, "SELECT x.tableoid, x.oid, "
    5854             :                          "x.extname, n.nspname, x.extrelocatable, x.extversion, x.extconfig, x.extcondition "
    5855             :                          "FROM pg_extension x "
    5856             :                          "JOIN pg_namespace n ON n.oid = x.extnamespace");
    5857             : 
    5858         310 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    5859             : 
    5860         310 :     ntups = PQntuples(res);
    5861         310 :     if (ntups == 0)
    5862           0 :         goto cleanup;
    5863             : 
    5864         310 :     extinfo = (ExtensionInfo *) pg_malloc(ntups * sizeof(ExtensionInfo));
    5865             : 
    5866         310 :     i_tableoid = PQfnumber(res, "tableoid");
    5867         310 :     i_oid = PQfnumber(res, "oid");
    5868         310 :     i_extname = PQfnumber(res, "extname");
    5869         310 :     i_nspname = PQfnumber(res, "nspname");
    5870         310 :     i_extrelocatable = PQfnumber(res, "extrelocatable");
    5871         310 :     i_extversion = PQfnumber(res, "extversion");
    5872         310 :     i_extconfig = PQfnumber(res, "extconfig");
    5873         310 :     i_extcondition = PQfnumber(res, "extcondition");
    5874             : 
    5875         670 :     for (i = 0; i < ntups; i++)
    5876             :     {
    5877         360 :         extinfo[i].dobj.objType = DO_EXTENSION;
    5878         360 :         extinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    5879         360 :         extinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    5880         360 :         AssignDumpId(&extinfo[i].dobj);
    5881         360 :         extinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_extname));
    5882         360 :         extinfo[i].namespace = pg_strdup(PQgetvalue(res, i, i_nspname));
    5883         360 :         extinfo[i].relocatable = *(PQgetvalue(res, i, i_extrelocatable)) == 't';
    5884         360 :         extinfo[i].extversion = pg_strdup(PQgetvalue(res, i, i_extversion));
    5885         360 :         extinfo[i].extconfig = pg_strdup(PQgetvalue(res, i, i_extconfig));
    5886         360 :         extinfo[i].extcondition = pg_strdup(PQgetvalue(res, i, i_extcondition));
    5887             : 
    5888             :         /* Decide whether we want to dump it */
    5889         360 :         selectDumpableExtension(&(extinfo[i]), dopt);
    5890             :     }
    5891             : 
    5892         310 : cleanup:
    5893         310 :     PQclear(res);
    5894         310 :     destroyPQExpBuffer(query);
    5895             : 
    5896         310 :     *numExtensions = ntups;
    5897             : 
    5898         310 :     return extinfo;
    5899             : }
    5900             : 
    5901             : /*
    5902             :  * getTypes:
    5903             :  *    get information about all types in the system catalogs
    5904             :  *
    5905             :  * NB: this must run after getFuncs() because we assume we can do
    5906             :  * findFuncByOid().
    5907             :  */
    5908             : void
    5909         308 : getTypes(Archive *fout)
    5910             : {
    5911             :     PGresult   *res;
    5912             :     int         ntups;
    5913             :     int         i;
    5914         308 :     PQExpBuffer query = createPQExpBuffer();
    5915             :     TypeInfo   *tyinfo;
    5916             :     ShellTypeInfo *stinfo;
    5917             :     int         i_tableoid;
    5918             :     int         i_oid;
    5919             :     int         i_typname;
    5920             :     int         i_typnamespace;
    5921             :     int         i_typacl;
    5922             :     int         i_acldefault;
    5923             :     int         i_typowner;
    5924             :     int         i_typelem;
    5925             :     int         i_typrelid;
    5926             :     int         i_typrelkind;
    5927             :     int         i_typtype;
    5928             :     int         i_typisdefined;
    5929             :     int         i_isarray;
    5930             :     int         i_typarray;
    5931             : 
    5932             :     /*
    5933             :      * we include even the built-in types because those may be used as array
    5934             :      * elements by user-defined types
    5935             :      *
    5936             :      * we filter out the built-in types when we dump out the types
    5937             :      *
    5938             :      * same approach for undefined (shell) types and array types
    5939             :      *
    5940             :      * Note: as of 8.3 we can reliably detect whether a type is an
    5941             :      * auto-generated array type by checking the element type's typarray.
    5942             :      * (Before that the test is capable of generating false positives.) We
    5943             :      * still check for name beginning with '_', though, so as to avoid the
    5944             :      * cost of the subselect probe for all standard types.  This would have to
    5945             :      * be revisited if the backend ever allows renaming of array types.
    5946             :      */
    5947         308 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, typname, "
    5948             :                          "typnamespace, typacl, "
    5949             :                          "acldefault('T', typowner) AS acldefault, "
    5950             :                          "typowner, "
    5951             :                          "typelem, typrelid, typarray, "
    5952             :                          "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
    5953             :                          "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
    5954             :                          "typtype, typisdefined, "
    5955             :                          "typname[0] = '_' AND typelem != 0 AND "
    5956             :                          "(SELECT typarray FROM pg_type te WHERE oid = pg_type.typelem) = oid AS isarray "
    5957             :                          "FROM pg_type");
    5958             : 
    5959         308 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    5960             : 
    5961         308 :     ntups = PQntuples(res);
    5962             : 
    5963         308 :     tyinfo = (TypeInfo *) pg_malloc(ntups * sizeof(TypeInfo));
    5964             : 
    5965         308 :     i_tableoid = PQfnumber(res, "tableoid");
    5966         308 :     i_oid = PQfnumber(res, "oid");
    5967         308 :     i_typname = PQfnumber(res, "typname");
    5968         308 :     i_typnamespace = PQfnumber(res, "typnamespace");
    5969         308 :     i_typacl = PQfnumber(res, "typacl");
    5970         308 :     i_acldefault = PQfnumber(res, "acldefault");
    5971         308 :     i_typowner = PQfnumber(res, "typowner");
    5972         308 :     i_typelem = PQfnumber(res, "typelem");
    5973         308 :     i_typrelid = PQfnumber(res, "typrelid");
    5974         308 :     i_typrelkind = PQfnumber(res, "typrelkind");
    5975         308 :     i_typtype = PQfnumber(res, "typtype");
    5976         308 :     i_typisdefined = PQfnumber(res, "typisdefined");
    5977         308 :     i_isarray = PQfnumber(res, "isarray");
    5978         308 :     i_typarray = PQfnumber(res, "typarray");
    5979             : 
    5980      222248 :     for (i = 0; i < ntups; i++)
    5981             :     {
    5982      221940 :         tyinfo[i].dobj.objType = DO_TYPE;
    5983      221940 :         tyinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    5984      221940 :         tyinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    5985      221940 :         AssignDumpId(&tyinfo[i].dobj);
    5986      221940 :         tyinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_typname));
    5987      443880 :         tyinfo[i].dobj.namespace =
    5988      221940 :             findNamespace(atooid(PQgetvalue(res, i, i_typnamespace)));
    5989      221940 :         tyinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_typacl));
    5990      221940 :         tyinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
    5991      221940 :         tyinfo[i].dacl.privtype = 0;
    5992      221940 :         tyinfo[i].dacl.initprivs = NULL;
    5993      221940 :         tyinfo[i].ftypname = NULL;  /* may get filled later */
    5994      221940 :         tyinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_typowner));
    5995      221940 :         tyinfo[i].typelem = atooid(PQgetvalue(res, i, i_typelem));
    5996      221940 :         tyinfo[i].typrelid = atooid(PQgetvalue(res, i, i_typrelid));
    5997      221940 :         tyinfo[i].typrelkind = *PQgetvalue(res, i, i_typrelkind);
    5998      221940 :         tyinfo[i].typtype = *PQgetvalue(res, i, i_typtype);
    5999      221940 :         tyinfo[i].shellType = NULL;
    6000             : 
    6001      221940 :         if (strcmp(PQgetvalue(res, i, i_typisdefined), "t") == 0)
    6002      221840 :             tyinfo[i].isDefined = true;
    6003             :         else
    6004         100 :             tyinfo[i].isDefined = false;
    6005             : 
    6006      221940 :         if (strcmp(PQgetvalue(res, i, i_isarray), "t") == 0)
    6007      106454 :             tyinfo[i].isArray = true;
    6008             :         else
    6009      115486 :             tyinfo[i].isArray = false;
    6010             : 
    6011      221940 :         tyinfo[i].typarray = atooid(PQgetvalue(res, i, i_typarray));
    6012             : 
    6013      221940 :         if (tyinfo[i].typtype == TYPTYPE_MULTIRANGE)
    6014        2076 :             tyinfo[i].isMultirange = true;
    6015             :         else
    6016      219864 :             tyinfo[i].isMultirange = false;
    6017             : 
    6018             :         /* Decide whether we want to dump it */
    6019      221940 :         selectDumpableType(&tyinfo[i], fout);
    6020             : 
    6021             :         /* Mark whether type has an ACL */
    6022      221940 :         if (!PQgetisnull(res, i, i_typacl))
    6023         394 :             tyinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
    6024             : 
    6025             :         /*
    6026             :          * If it's a domain, fetch info about its constraints, if any
    6027             :          */
    6028      221940 :         tyinfo[i].nDomChecks = 0;
    6029      221940 :         tyinfo[i].domChecks = NULL;
    6030      221940 :         if ((tyinfo[i].dobj.dump & DUMP_COMPONENT_DEFINITION) &&
    6031       26350 :             tyinfo[i].typtype == TYPTYPE_DOMAIN)
    6032         272 :             getDomainConstraints(fout, &(tyinfo[i]));
    6033             : 
    6034             :         /*
    6035             :          * If it's a base type, make a DumpableObject representing a shell
    6036             :          * definition of the type.  We will need to dump that ahead of the I/O
    6037             :          * functions for the type.  Similarly, range types need a shell
    6038             :          * definition in case they have a canonicalize function.
    6039             :          *
    6040             :          * Note: the shell type doesn't have a catId.  You might think it
    6041             :          * should copy the base type's catId, but then it might capture the
    6042             :          * pg_depend entries for the type, which we don't want.
    6043             :          */
    6044      221940 :         if ((tyinfo[i].dobj.dump & DUMP_COMPONENT_DEFINITION) &&
    6045       26350 :             (tyinfo[i].typtype == TYPTYPE_BASE ||
    6046       12756 :              tyinfo[i].typtype == TYPTYPE_RANGE))
    6047             :         {
    6048       13814 :             stinfo = (ShellTypeInfo *) pg_malloc(sizeof(ShellTypeInfo));
    6049       13814 :             stinfo->dobj.objType = DO_SHELL_TYPE;
    6050       13814 :             stinfo->dobj.catId = nilCatalogId;
    6051       13814 :             AssignDumpId(&stinfo->dobj);
    6052       13814 :             stinfo->dobj.name = pg_strdup(tyinfo[i].dobj.name);
    6053       13814 :             stinfo->dobj.namespace = tyinfo[i].dobj.namespace;
    6054       13814 :             stinfo->baseType = &(tyinfo[i]);
    6055       13814 :             tyinfo[i].shellType = stinfo;
    6056             : 
    6057             :             /*
    6058             :              * Initially mark the shell type as not to be dumped.  We'll only
    6059             :              * dump it if the I/O or canonicalize functions need to be dumped;
    6060             :              * this is taken care of while sorting dependencies.
    6061             :              */
    6062       13814 :             stinfo->dobj.dump = DUMP_COMPONENT_NONE;
    6063             :         }
    6064             :     }
    6065             : 
    6066         308 :     PQclear(res);
    6067             : 
    6068         308 :     destroyPQExpBuffer(query);
    6069         308 : }
    6070             : 
    6071             : /*
    6072             :  * getOperators:
    6073             :  *    get information about all operators in the system catalogs
    6074             :  */
    6075             : void
    6076         308 : getOperators(Archive *fout)
    6077             : {
    6078             :     PGresult   *res;
    6079             :     int         ntups;
    6080             :     int         i;
    6081         308 :     PQExpBuffer query = createPQExpBuffer();
    6082             :     OprInfo    *oprinfo;
    6083             :     int         i_tableoid;
    6084             :     int         i_oid;
    6085             :     int         i_oprname;
    6086             :     int         i_oprnamespace;
    6087             :     int         i_oprowner;
    6088             :     int         i_oprkind;
    6089             :     int         i_oprcode;
    6090             : 
    6091             :     /*
    6092             :      * find all operators, including builtin operators; we filter out
    6093             :      * system-defined operators at dump-out time.
    6094             :      */
    6095             : 
    6096         308 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, oprname, "
    6097             :                          "oprnamespace, "
    6098             :                          "oprowner, "
    6099             :                          "oprkind, "
    6100             :                          "oprcode::oid AS oprcode "
    6101             :                          "FROM pg_operator");
    6102             : 
    6103         308 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    6104             : 
    6105         308 :     ntups = PQntuples(res);
    6106             : 
    6107         308 :     oprinfo = (OprInfo *) pg_malloc(ntups * sizeof(OprInfo));
    6108             : 
    6109         308 :     i_tableoid = PQfnumber(res, "tableoid");
    6110         308 :     i_oid = PQfnumber(res, "oid");
    6111         308 :     i_oprname = PQfnumber(res, "oprname");
    6112         308 :     i_oprnamespace = PQfnumber(res, "oprnamespace");
    6113         308 :     i_oprowner = PQfnumber(res, "oprowner");
    6114         308 :     i_oprkind = PQfnumber(res, "oprkind");
    6115         308 :     i_oprcode = PQfnumber(res, "oprcode");
    6116             : 
    6117      246680 :     for (i = 0; i < ntups; i++)
    6118             :     {
    6119      246372 :         oprinfo[i].dobj.objType = DO_OPERATOR;
    6120      246372 :         oprinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    6121      246372 :         oprinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    6122      246372 :         AssignDumpId(&oprinfo[i].dobj);
    6123      246372 :         oprinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_oprname));
    6124      492744 :         oprinfo[i].dobj.namespace =
    6125      246372 :             findNamespace(atooid(PQgetvalue(res, i, i_oprnamespace)));
    6126      246372 :         oprinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_oprowner));
    6127      246372 :         oprinfo[i].oprkind = (PQgetvalue(res, i, i_oprkind))[0];
    6128      246372 :         oprinfo[i].oprcode = atooid(PQgetvalue(res, i, i_oprcode));
    6129             : 
    6130             :         /* Decide whether we want to dump it */
    6131      246372 :         selectDumpableObject(&(oprinfo[i].dobj), fout);
    6132             :     }
    6133             : 
    6134         308 :     PQclear(res);
    6135             : 
    6136         308 :     destroyPQExpBuffer(query);
    6137         308 : }
    6138             : 
    6139             : /*
    6140             :  * getCollations:
    6141             :  *    get information about all collations in the system catalogs
    6142             :  */
    6143             : void
    6144         308 : getCollations(Archive *fout)
    6145             : {
    6146             :     PGresult   *res;
    6147             :     int         ntups;
    6148             :     int         i;
    6149             :     PQExpBuffer query;
    6150             :     CollInfo   *collinfo;
    6151             :     int         i_tableoid;
    6152             :     int         i_oid;
    6153             :     int         i_collname;
    6154             :     int         i_collnamespace;
    6155             :     int         i_collowner;
    6156             : 
    6157         308 :     query = createPQExpBuffer();
    6158             : 
    6159             :     /*
    6160             :      * find all collations, including builtin collations; we filter out
    6161             :      * system-defined collations at dump-out time.
    6162             :      */
    6163             : 
    6164         308 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, collname, "
    6165             :                          "collnamespace, "
    6166             :                          "collowner "
    6167             :                          "FROM pg_collation");
    6168             : 
    6169         308 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    6170             : 
    6171         308 :     ntups = PQntuples(res);
    6172             : 
    6173         308 :     collinfo = (CollInfo *) pg_malloc(ntups * sizeof(CollInfo));
    6174             : 
    6175         308 :     i_tableoid = PQfnumber(res, "tableoid");
    6176         308 :     i_oid = PQfnumber(res, "oid");
    6177         308 :     i_collname = PQfnumber(res, "collname");
    6178         308 :     i_collnamespace = PQfnumber(res, "collnamespace");
    6179         308 :     i_collowner = PQfnumber(res, "collowner");
    6180             : 
    6181      244766 :     for (i = 0; i < ntups; i++)
    6182             :     {
    6183      244458 :         collinfo[i].dobj.objType = DO_COLLATION;
    6184      244458 :         collinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    6185      244458 :         collinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    6186      244458 :         AssignDumpId(&collinfo[i].dobj);
    6187      244458 :         collinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_collname));
    6188      488916 :         collinfo[i].dobj.namespace =
    6189      244458 :             findNamespace(atooid(PQgetvalue(res, i, i_collnamespace)));
    6190      244458 :         collinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_collowner));
    6191             : 
    6192             :         /* Decide whether we want to dump it */
    6193      244458 :         selectDumpableObject(&(collinfo[i].dobj), fout);
    6194             :     }
    6195             : 
    6196         308 :     PQclear(res);
    6197             : 
    6198         308 :     destroyPQExpBuffer(query);
    6199         308 : }
    6200             : 
    6201             : /*
    6202             :  * getConversions:
    6203             :  *    get information about all conversions in the system catalogs
    6204             :  */
    6205             : void
    6206         308 : getConversions(Archive *fout)
    6207             : {
    6208             :     PGresult   *res;
    6209             :     int         ntups;
    6210             :     int         i;
    6211             :     PQExpBuffer query;
    6212             :     ConvInfo   *convinfo;
    6213             :     int         i_tableoid;
    6214             :     int         i_oid;
    6215             :     int         i_conname;
    6216             :     int         i_connamespace;
    6217             :     int         i_conowner;
    6218             : 
    6219         308 :     query = createPQExpBuffer();
    6220             : 
    6221             :     /*
    6222             :      * find all conversions, including builtin conversions; we filter out
    6223             :      * system-defined conversions at dump-out time.
    6224             :      */
    6225             : 
    6226         308 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, conname, "
    6227             :                          "connamespace, "
    6228             :                          "conowner "
    6229             :                          "FROM pg_conversion");
    6230             : 
    6231         308 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    6232             : 
    6233         308 :     ntups = PQntuples(res);
    6234             : 
    6235         308 :     convinfo = (ConvInfo *) pg_malloc(ntups * sizeof(ConvInfo));
    6236             : 
    6237         308 :     i_tableoid = PQfnumber(res, "tableoid");
    6238         308 :     i_oid = PQfnumber(res, "oid");
    6239         308 :     i_conname = PQfnumber(res, "conname");
    6240         308 :     i_connamespace = PQfnumber(res, "connamespace");
    6241         308 :     i_conowner = PQfnumber(res, "conowner");
    6242             : 
    6243       39818 :     for (i = 0; i < ntups; i++)
    6244             :     {
    6245       39510 :         convinfo[i].dobj.objType = DO_CONVERSION;
    6246       39510 :         convinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    6247       39510 :         convinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    6248       39510 :         AssignDumpId(&convinfo[i].dobj);
    6249       39510 :         convinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_conname));
    6250       79020 :         convinfo[i].dobj.namespace =
    6251       39510 :             findNamespace(atooid(PQgetvalue(res, i, i_connamespace)));
    6252       39510 :         convinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_conowner));
    6253             : 
    6254             :         /* Decide whether we want to dump it */
    6255       39510 :         selectDumpableObject(&(convinfo[i].dobj), fout);
    6256             :     }
    6257             : 
    6258         308 :     PQclear(res);
    6259             : 
    6260         308 :     destroyPQExpBuffer(query);
    6261         308 : }
    6262             : 
    6263             : /*
    6264             :  * getAccessMethods:
    6265             :  *    get information about all user-defined access methods
    6266             :  */
    6267             : void
    6268         308 : getAccessMethods(Archive *fout)
    6269             : {
    6270             :     PGresult   *res;
    6271             :     int         ntups;
    6272             :     int         i;
    6273             :     PQExpBuffer query;
    6274             :     AccessMethodInfo *aminfo;
    6275             :     int         i_tableoid;
    6276             :     int         i_oid;
    6277             :     int         i_amname;
    6278             :     int         i_amhandler;
    6279             :     int         i_amtype;
    6280             : 
    6281             :     /* Before 9.6, there are no user-defined access methods */
    6282         308 :     if (fout->remoteVersion < 90600)
    6283           0 :         return;
    6284             : 
    6285         308 :     query = createPQExpBuffer();
    6286             : 
    6287             :     /* Select all access methods from pg_am table */
    6288         308 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, amname, amtype, "
    6289             :                          "amhandler::pg_catalog.regproc AS amhandler "
    6290             :                          "FROM pg_am");
    6291             : 
    6292         308 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    6293             : 
    6294         308 :     ntups = PQntuples(res);
    6295             : 
    6296         308 :     aminfo = (AccessMethodInfo *) pg_malloc(ntups * sizeof(AccessMethodInfo));
    6297             : 
    6298         308 :     i_tableoid = PQfnumber(res, "tableoid");
    6299         308 :     i_oid = PQfnumber(res, "oid");
    6300         308 :     i_amname = PQfnumber(res, "amname");
    6301         308 :     i_amhandler = PQfnumber(res, "amhandler");
    6302         308 :     i_amtype = PQfnumber(res, "amtype");
    6303             : 
    6304        2700 :     for (i = 0; i < ntups; i++)
    6305             :     {
    6306        2392 :         aminfo[i].dobj.objType = DO_ACCESS_METHOD;
    6307        2392 :         aminfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    6308        2392 :         aminfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    6309        2392 :         AssignDumpId(&aminfo[i].dobj);
    6310        2392 :         aminfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_amname));
    6311        2392 :         aminfo[i].dobj.namespace = NULL;
    6312        2392 :         aminfo[i].amhandler = pg_strdup(PQgetvalue(res, i, i_amhandler));
    6313        2392 :         aminfo[i].amtype = *(PQgetvalue(res, i, i_amtype));
    6314             : 
    6315             :         /* Decide whether we want to dump it */
    6316        2392 :         selectDumpableAccessMethod(&(aminfo[i]), fout);
    6317             :     }
    6318             : 
    6319         308 :     PQclear(res);
    6320             : 
    6321         308 :     destroyPQExpBuffer(query);
    6322             : }
    6323             : 
    6324             : 
    6325             : /*
    6326             :  * getOpclasses:
    6327             :  *    get information about all opclasses in the system catalogs
    6328             :  */
    6329             : void
    6330         308 : getOpclasses(Archive *fout)
    6331             : {
    6332             :     PGresult   *res;
    6333             :     int         ntups;
    6334             :     int         i;
    6335         308 :     PQExpBuffer query = createPQExpBuffer();
    6336             :     OpclassInfo *opcinfo;
    6337             :     int         i_tableoid;
    6338             :     int         i_oid;
    6339             :     int         i_opcname;
    6340             :     int         i_opcnamespace;
    6341             :     int         i_opcowner;
    6342             : 
    6343             :     /*
    6344             :      * find all opclasses, including builtin opclasses; we filter out
    6345             :      * system-defined opclasses at dump-out time.
    6346             :      */
    6347             : 
    6348         308 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, opcname, "
    6349             :                          "opcnamespace, "
    6350             :                          "opcowner "
    6351             :                          "FROM pg_opclass");
    6352             : 
    6353         308 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    6354             : 
    6355         308 :     ntups = PQntuples(res);
    6356             : 
    6357         308 :     opcinfo = (OpclassInfo *) pg_malloc(ntups * sizeof(OpclassInfo));
    6358             : 
    6359         308 :     i_tableoid = PQfnumber(res, "tableoid");
    6360         308 :     i_oid = PQfnumber(res, "oid");
    6361         308 :     i_opcname = PQfnumber(res, "opcname");
    6362         308 :     i_opcnamespace = PQfnumber(res, "opcnamespace");
    6363         308 :     i_opcowner = PQfnumber(res, "opcowner");
    6364             : 
    6365       55124 :     for (i = 0; i < ntups; i++)
    6366             :     {
    6367       54816 :         opcinfo[i].dobj.objType = DO_OPCLASS;
    6368       54816 :         opcinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    6369       54816 :         opcinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    6370       54816 :         AssignDumpId(&opcinfo[i].dobj);
    6371       54816 :         opcinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_opcname));
    6372      109632 :         opcinfo[i].dobj.namespace =
    6373       54816 :             findNamespace(atooid(PQgetvalue(res, i, i_opcnamespace)));
    6374       54816 :         opcinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_opcowner));
    6375             : 
    6376             :         /* Decide whether we want to dump it */
    6377       54816 :         selectDumpableObject(&(opcinfo[i].dobj), fout);
    6378             :     }
    6379             : 
    6380         308 :     PQclear(res);
    6381             : 
    6382         308 :     destroyPQExpBuffer(query);
    6383         308 : }
    6384             : 
    6385             : /*
    6386             :  * getOpfamilies:
    6387             :  *    get information about all opfamilies in the system catalogs
    6388             :  */
    6389             : void
    6390         308 : getOpfamilies(Archive *fout)
    6391             : {
    6392             :     PGresult   *res;
    6393             :     int         ntups;
    6394             :     int         i;
    6395             :     PQExpBuffer query;
    6396             :     OpfamilyInfo *opfinfo;
    6397             :     int         i_tableoid;
    6398             :     int         i_oid;
    6399             :     int         i_opfname;
    6400             :     int         i_opfnamespace;
    6401             :     int         i_opfowner;
    6402             : 
    6403         308 :     query = createPQExpBuffer();
    6404             : 
    6405             :     /*
    6406             :      * find all opfamilies, including builtin opfamilies; we filter out
    6407             :      * system-defined opfamilies at dump-out time.
    6408             :      */
    6409             : 
    6410         308 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, opfname, "
    6411             :                          "opfnamespace, "
    6412             :                          "opfowner "
    6413             :                          "FROM pg_opfamily");
    6414             : 
    6415         308 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    6416             : 
    6417         308 :     ntups = PQntuples(res);
    6418             : 
    6419         308 :     opfinfo = (OpfamilyInfo *) pg_malloc(ntups * sizeof(OpfamilyInfo));
    6420             : 
    6421         308 :     i_tableoid = PQfnumber(res, "tableoid");
    6422         308 :     i_oid = PQfnumber(res, "oid");
    6423         308 :     i_opfname = PQfnumber(res, "opfname");
    6424         308 :     i_opfnamespace = PQfnumber(res, "opfnamespace");
    6425         308 :     i_opfowner = PQfnumber(res, "opfowner");
    6426             : 
    6427       45546 :     for (i = 0; i < ntups; i++)
    6428             :     {
    6429       45238 :         opfinfo[i].dobj.objType = DO_OPFAMILY;
    6430       45238 :         opfinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    6431       45238 :         opfinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    6432       45238 :         AssignDumpId(&opfinfo[i].dobj);
    6433       45238 :         opfinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_opfname));
    6434       90476 :         opfinfo[i].dobj.namespace =
    6435       45238 :             findNamespace(atooid(PQgetvalue(res, i, i_opfnamespace)));
    6436       45238 :         opfinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_opfowner));
    6437             : 
    6438             :         /* Decide whether we want to dump it */
    6439       45238 :         selectDumpableObject(&(opfinfo[i].dobj), fout);
    6440             :     }
    6441             : 
    6442         308 :     PQclear(res);
    6443             : 
    6444         308 :     destroyPQExpBuffer(query);
    6445         308 : }
    6446             : 
    6447             : /*
    6448             :  * getAggregates:
    6449             :  *    get information about all user-defined aggregates in the system catalogs
    6450             :  */
    6451             : void
    6452         308 : getAggregates(Archive *fout)
    6453             : {
    6454         308 :     DumpOptions *dopt = fout->dopt;
    6455             :     PGresult   *res;
    6456             :     int         ntups;
    6457             :     int         i;
    6458         308 :     PQExpBuffer query = createPQExpBuffer();
    6459             :     AggInfo    *agginfo;
    6460             :     int         i_tableoid;
    6461             :     int         i_oid;
    6462             :     int         i_aggname;
    6463             :     int         i_aggnamespace;
    6464             :     int         i_pronargs;
    6465             :     int         i_proargtypes;
    6466             :     int         i_proowner;
    6467             :     int         i_aggacl;
    6468             :     int         i_acldefault;
    6469             : 
    6470             :     /*
    6471             :      * Find all interesting aggregates.  See comment in getFuncs() for the
    6472             :      * rationale behind the filtering logic.
    6473             :      */
    6474         308 :     if (fout->remoteVersion >= 90600)
    6475             :     {
    6476             :         const char *agg_check;
    6477             : 
    6478         616 :         agg_check = (fout->remoteVersion >= 110000 ? "p.prokind = 'a'"
    6479         308 :                      : "p.proisagg");
    6480             : 
    6481         308 :         appendPQExpBuffer(query, "SELECT p.tableoid, p.oid, "
    6482             :                           "p.proname AS aggname, "
    6483             :                           "p.pronamespace AS aggnamespace, "
    6484             :                           "p.pronargs, p.proargtypes, "
    6485             :                           "p.proowner, "
    6486             :                           "p.proacl AS aggacl, "
    6487             :                           "acldefault('f', p.proowner) AS acldefault "
    6488             :                           "FROM pg_proc p "
    6489             :                           "LEFT JOIN pg_init_privs pip ON "
    6490             :                           "(p.oid = pip.objoid "
    6491             :                           "AND pip.classoid = 'pg_proc'::regclass "
    6492             :                           "AND pip.objsubid = 0) "
    6493             :                           "WHERE %s AND ("
    6494             :                           "p.pronamespace != "
    6495             :                           "(SELECT oid FROM pg_namespace "
    6496             :                           "WHERE nspname = 'pg_catalog') OR "
    6497             :                           "p.proacl IS DISTINCT FROM pip.initprivs",
    6498             :                           agg_check);
    6499         308 :         if (dopt->binary_upgrade)
    6500          28 :             appendPQExpBufferStr(query,
    6501             :                                  " OR EXISTS(SELECT 1 FROM pg_depend WHERE "
    6502             :                                  "classid = 'pg_proc'::regclass AND "
    6503             :                                  "objid = p.oid AND "
    6504             :                                  "refclassid = 'pg_extension'::regclass AND "
    6505             :                                  "deptype = 'e')");
    6506         308 :         appendPQExpBufferChar(query, ')');
    6507             :     }
    6508             :     else
    6509             :     {
    6510           0 :         appendPQExpBufferStr(query, "SELECT tableoid, oid, proname AS aggname, "
    6511             :                              "pronamespace AS aggnamespace, "
    6512             :                              "pronargs, proargtypes, "
    6513             :                              "proowner, "
    6514             :                              "proacl AS aggacl, "
    6515             :                              "acldefault('f', proowner) AS acldefault "
    6516             :                              "FROM pg_proc p "
    6517             :                              "WHERE proisagg AND ("
    6518             :                              "pronamespace != "
    6519             :                              "(SELECT oid FROM pg_namespace "
    6520             :                              "WHERE nspname = 'pg_catalog')");
    6521           0 :         if (dopt->binary_upgrade)
    6522           0 :             appendPQExpBufferStr(query,
    6523             :                                  " OR EXISTS(SELECT 1 FROM pg_depend WHERE "
    6524             :                                  "classid = 'pg_proc'::regclass AND "
    6525             :                                  "objid = p.oid AND "
    6526             :                                  "refclassid = 'pg_extension'::regclass AND "
    6527             :                                  "deptype = 'e')");
    6528           0 :         appendPQExpBufferChar(query, ')');
    6529             :     }
    6530             : 
    6531         308 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    6532             : 
    6533         308 :     ntups = PQntuples(res);
    6534             : 
    6535         308 :     agginfo = (AggInfo *) pg_malloc(ntups * sizeof(AggInfo));
    6536             : 
    6537         308 :     i_tableoid = PQfnumber(res, "tableoid");
    6538         308 :     i_oid = PQfnumber(res, "oid");
    6539         308 :     i_aggname = PQfnumber(res, "aggname");
    6540         308 :     i_aggnamespace = PQfnumber(res, "aggnamespace");
    6541         308 :     i_pronargs = PQfnumber(res, "pronargs");
    6542         308 :     i_proargtypes = PQfnumber(res, "proargtypes");
    6543         308 :     i_proowner = PQfnumber(res, "proowner");
    6544         308 :     i_aggacl = PQfnumber(res, "aggacl");
    6545         308 :     i_acldefault = PQfnumber(res, "acldefault");
    6546             : 
    6547        1102 :     for (i = 0; i < ntups; i++)
    6548             :     {
    6549         794 :         agginfo[i].aggfn.dobj.objType = DO_AGG;
    6550         794 :         agginfo[i].aggfn.dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    6551         794 :         agginfo[i].aggfn.dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    6552         794 :         AssignDumpId(&agginfo[i].aggfn.dobj);
    6553         794 :         agginfo[i].aggfn.dobj.name = pg_strdup(PQgetvalue(res, i, i_aggname));
    6554        1588 :         agginfo[i].aggfn.dobj.namespace =
    6555         794 :             findNamespace(atooid(PQgetvalue(res, i, i_aggnamespace)));
    6556         794 :         agginfo[i].aggfn.dacl.acl = pg_strdup(PQgetvalue(res, i, i_aggacl));
    6557         794 :         agginfo[i].aggfn.dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
    6558         794 :         agginfo[i].aggfn.dacl.privtype = 0;
    6559         794 :         agginfo[i].aggfn.dacl.initprivs = NULL;
    6560         794 :         agginfo[i].aggfn.rolname = getRoleName(PQgetvalue(res, i, i_proowner));
    6561         794 :         agginfo[i].aggfn.lang = InvalidOid; /* not currently interesting */
    6562         794 :         agginfo[i].aggfn.prorettype = InvalidOid;   /* not saved */
    6563         794 :         agginfo[i].aggfn.nargs = atoi(PQgetvalue(res, i, i_pronargs));
    6564         794 :         if (agginfo[i].aggfn.nargs == 0)
    6565         112 :             agginfo[i].aggfn.argtypes = NULL;
    6566             :         else
    6567             :         {
    6568         682 :             agginfo[i].aggfn.argtypes = (Oid *) pg_malloc(agginfo[i].aggfn.nargs * sizeof(Oid));
    6569         682 :             parseOidArray(PQgetvalue(res, i, i_proargtypes),
    6570         682 :                           agginfo[i].aggfn.argtypes,
    6571         682 :                           agginfo[i].aggfn.nargs);
    6572             :         }
    6573         794 :         agginfo[i].aggfn.postponed_def = false; /* might get set during sort */
    6574             : 
    6575             :         /* Decide whether we want to dump it */
    6576         794 :         selectDumpableObject(&(agginfo[i].aggfn.dobj), fout);
    6577             : 
    6578             :         /* Mark whether aggregate has an ACL */
    6579         794 :         if (!PQgetisnull(res, i, i_aggacl))
    6580          50 :             agginfo[i].aggfn.dobj.components |= DUMP_COMPONENT_ACL;
    6581             :     }
    6582             : 
    6583         308 :     PQclear(res);
    6584             : 
    6585         308 :     destroyPQExpBuffer(query);
    6586         308 : }
    6587             : 
    6588             : /*
    6589             :  * getFuncs:
    6590             :  *    get information about all user-defined functions in the system catalogs
    6591             :  */
    6592             : void
    6593         308 : getFuncs(Archive *fout)
    6594             : {
    6595         308 :     DumpOptions *dopt = fout->dopt;
    6596             :     PGresult   *res;
    6597             :     int         ntups;
    6598             :     int         i;
    6599         308 :     PQExpBuffer query = createPQExpBuffer();
    6600             :     FuncInfo   *finfo;
    6601             :     int         i_tableoid;
    6602             :     int         i_oid;
    6603             :     int         i_proname;
    6604             :     int         i_pronamespace;
    6605             :     int         i_proowner;
    6606             :     int         i_prolang;
    6607             :     int         i_pronargs;
    6608             :     int         i_proargtypes;
    6609             :     int         i_prorettype;
    6610             :     int         i_proacl;
    6611             :     int         i_acldefault;
    6612             : 
    6613             :     /*
    6614             :      * Find all interesting functions.  This is a bit complicated:
    6615             :      *
    6616             :      * 1. Always exclude aggregates; those are handled elsewhere.
    6617             :      *
    6618             :      * 2. Always exclude functions that are internally dependent on something
    6619             :      * else, since presumably those will be created as a result of creating
    6620             :      * the something else.  This currently acts only to suppress constructor
    6621             :      * functions for range types.  Note this is OK only because the
    6622             :      * constructors don't have any dependencies the range type doesn't have;
    6623             :      * otherwise we might not get creation ordering correct.
    6624             :      *
    6625             :      * 3. Otherwise, we normally exclude functions in pg_catalog.  However, if
    6626             :      * they're members of extensions and we are in binary-upgrade mode then
    6627             :      * include them, since we want to dump extension members individually in
    6628             :      * that mode.  Also, if they are used by casts or transforms then we need
    6629             :      * to gather the information about them, though they won't be dumped if
    6630             :      * they are built-in.  Also, in 9.6 and up, include functions in
    6631             :      * pg_catalog if they have an ACL different from what's shown in
    6632             :      * pg_init_privs (so we have to join to pg_init_privs; annoying).
    6633             :      */
    6634         308 :     if (fout->remoteVersion >= 90600)
    6635             :     {
    6636             :         const char *not_agg_check;
    6637             : 
    6638         616 :         not_agg_check = (fout->remoteVersion >= 110000 ? "p.prokind <> 'a'"
    6639         308 :                          : "NOT p.proisagg");
    6640             : 
    6641         308 :         appendPQExpBuffer(query,
    6642             :                           "SELECT p.tableoid, p.oid, p.proname, p.prolang, "
    6643             :                           "p.pronargs, p.proargtypes, p.prorettype, "
    6644             :                           "p.proacl, "
    6645             :                           "acldefault('f', p.proowner) AS acldefault, "
    6646             :                           "p.pronamespace, "
    6647             :                           "p.proowner "
    6648             :                           "FROM pg_proc p "
    6649             :                           "LEFT JOIN pg_init_privs pip ON "
    6650             :                           "(p.oid = pip.objoid "
    6651             :                           "AND pip.classoid = 'pg_proc'::regclass "
    6652             :                           "AND pip.objsubid = 0) "
    6653             :                           "WHERE %s"
    6654             :                           "\n  AND NOT EXISTS (SELECT 1 FROM pg_depend "
    6655             :                           "WHERE classid = 'pg_proc'::regclass AND "
    6656             :                           "objid = p.oid AND deptype = 'i')"
    6657             :                           "\n  AND ("
    6658             :                           "\n  pronamespace != "
    6659             :                           "(SELECT oid FROM pg_namespace "
    6660             :                           "WHERE nspname = 'pg_catalog')"
    6661             :                           "\n  OR EXISTS (SELECT 1 FROM pg_cast"
    6662             :                           "\n  WHERE pg_cast.oid > %u "
    6663             :                           "\n  AND p.oid = pg_cast.castfunc)"
    6664             :                           "\n  OR EXISTS (SELECT 1 FROM pg_transform"
    6665             :                           "\n  WHERE pg_transform.oid > %u AND "
    6666             :                           "\n  (p.oid = pg_transform.trffromsql"
    6667             :                           "\n  OR p.oid = pg_transform.trftosql))",
    6668             :                           not_agg_check,
    6669             :                           g_last_builtin_oid,
    6670             :                           g_last_builtin_oid);
    6671         308 :         if (dopt->binary_upgrade)
    6672          28 :             appendPQExpBufferStr(query,
    6673             :                                  "\n  OR EXISTS(SELECT 1 FROM pg_depend WHERE "
    6674             :                                  "classid = 'pg_proc'::regclass AND "
    6675             :                                  "objid = p.oid AND "
    6676             :                                  "refclassid = 'pg_extension'::regclass AND "
    6677             :                                  "deptype = 'e')");
    6678         308 :         appendPQExpBufferStr(query,
    6679             :                              "\n  OR p.proacl IS DISTINCT FROM pip.initprivs");
    6680         308 :         appendPQExpBufferChar(query, ')');
    6681             :     }
    6682             :     else
    6683             :     {
    6684           0 :         appendPQExpBuffer(query,
    6685             :                           "SELECT tableoid, oid, proname, prolang, "
    6686             :                           "pronargs, proargtypes, prorettype, proacl, "
    6687             :                           "acldefault('f', proowner) AS acldefault, "
    6688             :                           "pronamespace, "
    6689             :                           "proowner "
    6690             :                           "FROM pg_proc p "
    6691             :                           "WHERE NOT proisagg"
    6692             :                           "\n  AND NOT EXISTS (SELECT 1 FROM pg_depend "
    6693             :                           "WHERE classid = 'pg_proc'::regclass AND "
    6694             :                           "objid = p.oid AND deptype = 'i')"
    6695             :                           "\n  AND ("
    6696             :                           "\n  pronamespace != "
    6697             :                           "(SELECT oid FROM pg_namespace "
    6698             :                           "WHERE nspname = 'pg_catalog')"
    6699             :                           "\n  OR EXISTS (SELECT 1 FROM pg_cast"
    6700             :                           "\n  WHERE pg_cast.oid > '%u'::oid"
    6701             :                           "\n  AND p.oid = pg_cast.castfunc)",
    6702             :                           g_last_builtin_oid);
    6703             : 
    6704           0 :         if (fout->remoteVersion >= 90500)
    6705           0 :             appendPQExpBuffer(query,
    6706             :                               "\n  OR EXISTS (SELECT 1 FROM pg_transform"
    6707             :                               "\n  WHERE pg_transform.oid > '%u'::oid"
    6708             :                               "\n  AND (p.oid = pg_transform.trffromsql"
    6709             :                               "\n  OR p.oid = pg_transform.trftosql))",
    6710             :                               g_last_builtin_oid);
    6711             : 
    6712           0 :         if (dopt->binary_upgrade)
    6713           0 :             appendPQExpBufferStr(query,
    6714             :                                  "\n  OR EXISTS(SELECT 1 FROM pg_depend WHERE "
    6715             :                                  "classid = 'pg_proc'::regclass AND "
    6716             :                                  "objid = p.oid AND "
    6717             :                                  "refclassid = 'pg_extension'::regclass AND "
    6718             :                                  "deptype = 'e')");
    6719           0 :         appendPQExpBufferChar(query, ')');
    6720             :     }
    6721             : 
    6722         308 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    6723             : 
    6724         308 :     ntups = PQntuples(res);
    6725             : 
    6726         308 :     finfo = (FuncInfo *) pg_malloc0(ntups * sizeof(FuncInfo));
    6727             : 
    6728         308 :     i_tableoid = PQfnumber(res, "tableoid");
    6729         308 :     i_oid = PQfnumber(res, "oid");
    6730         308 :     i_proname = PQfnumber(res, "proname");
    6731         308 :     i_pronamespace = PQfnumber(res, "pronamespace");
    6732         308 :     i_proowner = PQfnumber(res, "proowner");
    6733         308 :     i_prolang = PQfnumber(res, "prolang");
    6734         308 :     i_pronargs = PQfnumber(res, "pronargs");
    6735         308 :     i_proargtypes = PQfnumber(res, "proargtypes");
    6736         308 :     i_prorettype = PQfnumber(res, "prorettype");
    6737         308 :     i_proacl = PQfnumber(res, "proacl");
    6738         308 :     i_acldefault = PQfnumber(res, "acldefault");
    6739             : 
    6740        8878 :     for (i = 0; i < ntups; i++)
    6741             :     {
    6742        8570 :         finfo[i].dobj.objType = DO_FUNC;
    6743        8570 :         finfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    6744        8570 :         finfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    6745        8570 :         AssignDumpId(&finfo[i].dobj);
    6746        8570 :         finfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_proname));
    6747       17140 :         finfo[i].dobj.namespace =
    6748        8570 :             findNamespace(atooid(PQgetvalue(res, i, i_pronamespace)));
    6749        8570 :         finfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_proacl));
    6750        8570 :         finfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
    6751        8570 :         finfo[i].dacl.privtype = 0;
    6752        8570 :         finfo[i].dacl.initprivs = NULL;
    6753        8570 :         finfo[i].rolname = getRoleName(PQgetvalue(res, i, i_proowner));
    6754        8570 :         finfo[i].lang = atooid(PQgetvalue(res, i, i_prolang));
    6755        8570 :         finfo[i].prorettype = atooid(PQgetvalue(res, i, i_prorettype));
    6756        8570 :         finfo[i].nargs = atoi(PQgetvalue(res, i, i_pronargs));
    6757        8570 :         if (finfo[i].nargs == 0)
    6758        2020 :             finfo[i].argtypes = NULL;
    6759             :         else
    6760             :         {
    6761        6550 :             finfo[i].argtypes = (Oid *) pg_malloc(finfo[i].nargs * sizeof(Oid));
    6762        6550 :             parseOidArray(PQgetvalue(res, i, i_proargtypes),
    6763        6550 :                           finfo[i].argtypes, finfo[i].nargs);
    6764             :         }
    6765        8570 :         finfo[i].postponed_def = false; /* might get set during sort */
    6766             : 
    6767             :         /* Decide whether we want to dump it */
    6768        8570 :         selectDumpableObject(&(finfo[i].dobj), fout);
    6769             : 
    6770             :         /* Mark whether function has an ACL */
    6771        8570 :         if (!PQgetisnull(res, i, i_proacl))
    6772         272 :             finfo[i].dobj.components |= DUMP_COMPONENT_ACL;
    6773             :     }
    6774             : 
    6775         308 :     PQclear(res);
    6776             : 
    6777         308 :     destroyPQExpBuffer(query);
    6778         308 : }
    6779             : 
    6780             : /*
    6781             :  * getTables
    6782             :  *    read all the tables (no indexes) in the system catalogs,
    6783             :  *    and return them as an array of TableInfo structures
    6784             :  *
    6785             :  * *numTables is set to the number of tables read in
    6786             :  */
    6787             : TableInfo *
    6788         310 : getTables(Archive *fout, int *numTables)
    6789             : {
    6790         310 :     DumpOptions *dopt = fout->dopt;
    6791             :     PGresult   *res;
    6792             :     int         ntups;
    6793             :     int         i;
    6794         310 :     PQExpBuffer query = createPQExpBuffer();
    6795             :     TableInfo  *tblinfo;
    6796             :     int         i_reltableoid;
    6797             :     int         i_reloid;
    6798             :     int         i_relname;
    6799             :     int         i_relnamespace;
    6800             :     int         i_relkind;
    6801             :     int         i_reltype;
    6802             :     int         i_relowner;
    6803             :     int         i_relchecks;
    6804             :     int         i_relhasindex;
    6805             :     int         i_relhasrules;
    6806             :     int         i_relpages;
    6807             :     int         i_toastpages;
    6808             :     int         i_owning_tab;
    6809             :     int         i_owning_col;
    6810             :     int         i_reltablespace;
    6811             :     int         i_relhasoids;
    6812             :     int         i_relhastriggers;
    6813             :     int         i_relpersistence;
    6814             :     int         i_relispopulated;
    6815             :     int         i_relreplident;
    6816             :     int         i_relrowsec;
    6817             :     int         i_relforcerowsec;
    6818             :     int         i_relfrozenxid;
    6819             :     int         i_toastfrozenxid;
    6820             :     int         i_toastoid;
    6821             :     int         i_relminmxid;
    6822             :     int         i_toastminmxid;
    6823             :     int         i_reloptions;
    6824             :     int         i_checkoption;
    6825             :     int         i_toastreloptions;
    6826             :     int         i_reloftype;
    6827             :     int         i_foreignserver;
    6828             :     int         i_amname;
    6829             :     int         i_is_identity_sequence;
    6830             :     int         i_relacl;
    6831             :     int         i_acldefault;
    6832             :     int         i_ispartition;
    6833             : 
    6834             :     /*
    6835             :      * Find all the tables and table-like objects.
    6836             :      *
    6837             :      * We must fetch all tables in this phase because otherwise we cannot
    6838             :      * correctly identify inherited columns, owned sequences, etc.
    6839             :      *
    6840             :      * We include system catalogs, so that we can work if a user table is
    6841             :      * defined to inherit from a system catalog (pretty weird, but...)
    6842             :      *
    6843             :      * Note: in this phase we should collect only a minimal amount of
    6844             :      * information about each table, basically just enough to decide if it is
    6845             :      * interesting.  In particular, since we do not yet have lock on any user
    6846             :      * table, we MUST NOT invoke any server-side data collection functions
    6847             :      * (for instance, pg_get_partkeydef()).  Those are likely to fail or give
    6848             :      * wrong answers if any concurrent DDL is happening.
    6849             :      */
    6850             : 
    6851         310 :     appendPQExpBufferStr(query,
    6852             :                          "SELECT c.tableoid, c.oid, c.relname, "
    6853             :                          "c.relnamespace, c.relkind, c.reltype, "
    6854             :                          "c.relowner, "
    6855             :                          "c.relchecks, "
    6856             :                          "c.relhasindex, c.relhasrules, c.relpages, "
    6857             :                          "c.relhastriggers, "
    6858             :                          "c.relpersistence, "
    6859             :                          "c.reloftype, "
    6860             :                          "c.relacl, "
    6861             :                          "acldefault(CASE WHEN c.relkind = " CppAsString2(RELKIND_SEQUENCE)
    6862             :                          " THEN 's'::\"char\" ELSE 'r'::\"char\" END, c.relowner) AS acldefault, "
    6863             :                          "CASE WHEN c.relkind = " CppAsString2(RELKIND_FOREIGN_TABLE) " THEN "
    6864             :                          "(SELECT ftserver FROM pg_catalog.pg_foreign_table WHERE ftrelid = c.oid) "
    6865             :                          "ELSE 0 END AS foreignserver, "
    6866             :                          "c.relfrozenxid, tc.relfrozenxid AS tfrozenxid, "
    6867             :                          "tc.oid AS toid, "
    6868             :                          "tc.relpages AS toastpages, "
    6869             :                          "tc.reloptions AS toast_reloptions, "
    6870             :                          "d.refobjid AS owning_tab, "
    6871             :                          "d.refobjsubid AS owning_col, "
    6872             :                          "tsp.spcname AS reltablespace, ");
    6873             : 
    6874         310 :     if (fout->remoteVersion >= 120000)
    6875         310 :         appendPQExpBufferStr(query,
    6876             :                              "false AS relhasoids, ");
    6877             :     else
    6878           0 :         appendPQExpBufferStr(query,
    6879             :                              "c.relhasoids, ");
    6880             : 
    6881         310 :     if (fout->remoteVersion >= 90300)
    6882         310 :         appendPQExpBufferStr(query,
    6883             :                              "c.relispopulated, ");
    6884             :     else
    6885           0 :         appendPQExpBufferStr(query,
    6886             :                              "'t' as relispopulated, ");
    6887             : 
    6888         310 :     if (fout->remoteVersion >= 90400)
    6889         310 :         appendPQExpBufferStr(query,
    6890             :                              "c.relreplident, ");
    6891             :     else
    6892           0 :         appendPQExpBufferStr(query,
    6893             :                              "'d' AS relreplident, ");
    6894             : 
    6895         310 :     if (fout->remoteVersion >= 90500)
    6896         310 :         appendPQExpBufferStr(query,
    6897             :                              "c.relrowsecurity, c.relforcerowsecurity, ");
    6898             :     else
    6899           0 :         appendPQExpBufferStr(query,
    6900             :                              "false AS relrowsecurity, "
    6901             :                              "false AS relforcerowsecurity, ");
    6902             : 
    6903         310 :     if (fout->remoteVersion >= 90300)
    6904         310 :         appendPQExpBufferStr(query,
    6905             :                              "c.relminmxid, tc.relminmxid AS tminmxid, ");
    6906             :     else
    6907           0 :         appendPQExpBufferStr(query,
    6908             :                              "0 AS relminmxid, 0 AS tminmxid, ");
    6909             : 
    6910         310 :     if (fout->remoteVersion >= 90300)
    6911         310 :         appendPQExpBufferStr(query,
    6912             :                              "array_remove(array_remove(c.reloptions,'check_option=local'),'check_option=cascaded') AS reloptions, "
    6913             :                              "CASE WHEN 'check_option=local' = ANY (c.reloptions) THEN 'LOCAL'::text "
    6914             :                              "WHEN 'check_option=cascaded' = ANY (c.reloptions) THEN 'CASCADED'::text ELSE NULL END AS checkoption, ");
    6915             :     else
    6916           0 :         appendPQExpBufferStr(query,
    6917             :                              "c.reloptions, NULL AS checkoption, ");
    6918             : 
    6919         310 :     if (fout->remoteVersion >= 90600)
    6920         310 :         appendPQExpBufferStr(query,
    6921             :                              "am.amname, ");
    6922             :     else
    6923           0 :         appendPQExpBufferStr(query,
    6924             :                              "NULL AS amname, ");
    6925             : 
    6926         310 :     if (fout->remoteVersion >= 90600)
    6927         310 :         appendPQExpBufferStr(query,
    6928             :                              "(d.deptype = 'i') IS TRUE AS is_identity_sequence, ");
    6929             :     else
    6930           0 :         appendPQExpBufferStr(query,
    6931             :                              "false AS is_identity_sequence, ");
    6932             : 
    6933         310 :     if (fout->remoteVersion >= 100000)
    6934         310 :         appendPQExpBufferStr(query,
    6935             :                              "c.relispartition AS ispartition ");
    6936             :     else
    6937           0 :         appendPQExpBufferStr(query,
    6938             :                              "false AS ispartition ");
    6939             : 
    6940             :     /*
    6941             :      * Left join to pg_depend to pick up dependency info linking sequences to
    6942             :      * their owning column, if any (note this dependency is AUTO except for
    6943             :      * identity sequences, where it's INTERNAL). Also join to pg_tablespace to
    6944             :      * collect the spcname.
    6945             :      */
    6946         310 :     appendPQExpBufferStr(query,
    6947             :                          "\nFROM pg_class c\n"
    6948             :                          "LEFT JOIN pg_depend d ON "
    6949             :                          "(c.relkind = " CppAsString2(RELKIND_SEQUENCE) " AND "
    6950             :                          "d.classid = 'pg_class'::regclass AND d.objid = c.oid AND "
    6951             :                          "d.objsubid = 0 AND "
    6952             :                          "d.refclassid = 'pg_class'::regclass AND d.deptype IN ('a', 'i'))\n"
    6953             :                          "LEFT JOIN pg_tablespace tsp ON (tsp.oid = c.reltablespace)\n");
    6954             : 
    6955             :     /*
    6956             :      * In 9.6 and up, left join to pg_am to pick up the amname.
    6957             :      */
    6958         310 :     if (fout->remoteVersion >= 90600)
    6959         310 :         appendPQExpBufferStr(query,
    6960             :                              "LEFT JOIN pg_am am ON (c.relam = am.oid)\n");
    6961             : 
    6962             :     /*
    6963             :      * We purposefully ignore toast OIDs for partitioned tables; the reason is
    6964             :      * that versions 10 and 11 have them, but later versions do not, so
    6965             :      * emitting them causes the upgrade to fail.
    6966             :      */
    6967         310 :     appendPQExpBufferStr(query,
    6968             :                          "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid"
    6969             :                          " AND tc.relkind = " CppAsString2(RELKIND_TOASTVALUE)
    6970             :                          " AND c.relkind <> " CppAsString2(RELKIND_PARTITIONED_TABLE) ")\n");
    6971             : 
    6972             :     /*
    6973             :      * Restrict to interesting relkinds (in particular, not indexes).  Not all
    6974             :      * relkinds are possible in older servers, but it's not worth the trouble
    6975             :      * to emit a version-dependent list.
    6976             :      *
    6977             :      * Composite-type table entries won't be dumped as such, but we have to
    6978             :      * make a DumpableObject for them so that we can track dependencies of the
    6979             :      * composite type (pg_depend entries for columns of the composite type
    6980             :      * link to the pg_class entry not the pg_type entry).
    6981             :      */
    6982         310 :     appendPQExpBufferStr(query,
    6983             :                          "WHERE c.relkind IN ("
    6984             :                          CppAsString2(RELKIND_RELATION) ", "
    6985             :                          CppAsString2(RELKIND_SEQUENCE) ", "
    6986             :                          CppAsString2(RELKIND_VIEW) ", "
    6987             :                          CppAsString2(RELKIND_COMPOSITE_TYPE) ", "
    6988             :                          CppAsString2(RELKIND_MATVIEW) ", "
    6989             :                          CppAsString2(RELKIND_FOREIGN_TABLE) ", "
    6990             :                          CppAsString2(RELKIND_PARTITIONED_TABLE) ")\n"
    6991             :                          "ORDER BY c.oid");
    6992             : 
    6993         310 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    6994             : 
    6995         310 :     ntups = PQntuples(res);
    6996             : 
    6997         310 :     *numTables = ntups;
    6998             : 
    6999             :     /*
    7000             :      * Extract data from result and lock dumpable tables.  We do the locking
    7001             :      * before anything else, to minimize the window wherein a table could
    7002             :      * disappear under us.
    7003             :      *
    7004             :      * Note that we have to save info about all tables here, even when dumping
    7005             :      * only one, because we don't yet know which tables might be inheritance
    7006             :      * ancestors of the target table.
    7007             :      */
    7008         310 :     tblinfo = (TableInfo *) pg_malloc0(ntups * sizeof(TableInfo));
    7009             : 
    7010         310 :     i_reltableoid = PQfnumber(res, "tableoid");
    7011         310 :     i_reloid = PQfnumber(res, "oid");
    7012         310 :     i_relname = PQfnumber(res, "relname");
    7013         310 :     i_relnamespace = PQfnumber(res, "relnamespace");
    7014         310 :     i_relkind = PQfnumber(res, "relkind");
    7015         310 :     i_reltype = PQfnumber(res, "reltype");
    7016         310 :     i_relowner = PQfnumber(res, "relowner");
    7017         310 :     i_relchecks = PQfnumber(res, "relchecks");
    7018         310 :     i_relhasindex = PQfnumber(res, "relhasindex");
    7019         310 :     i_relhasrules = PQfnumber(res, "relhasrules");
    7020         310 :     i_relpages = PQfnumber(res, "relpages");
    7021         310 :     i_toastpages = PQfnumber(res, "toastpages");
    7022         310 :     i_owning_tab = PQfnumber(res, "owning_tab");
    7023         310 :     i_owning_col = PQfnumber(res, "owning_col");
    7024         310 :     i_reltablespace = PQfnumber(res, "reltablespace");
    7025         310 :     i_relhasoids = PQfnumber(res, "relhasoids");
    7026         310 :     i_relhastriggers = PQfnumber(res, "relhastriggers");
    7027         310 :     i_relpersistence = PQfnumber(res, "relpersistence");
    7028         310 :     i_relispopulated = PQfnumber(res, "relispopulated");
    7029         310 :     i_relreplident = PQfnumber(res, "relreplident");
    7030         310 :     i_relrowsec = PQfnumber(res, "relrowsecurity");
    7031         310 :     i_relforcerowsec = PQfnumber(res, "relforcerowsecurity");
    7032         310 :     i_relfrozenxid = PQfnumber(res, "relfrozenxid");
    7033         310 :     i_toastfrozenxid = PQfnumber(res, "tfrozenxid");
    7034         310 :     i_toastoid = PQfnumber(res, "toid");
    7035         310 :     i_relminmxid = PQfnumber(res, "relminmxid");
    7036         310 :     i_toastminmxid = PQfnumber(res, "tminmxid");
    7037         310 :     i_reloptions = PQfnumber(res, "reloptions");
    7038         310 :     i_checkoption = PQfnumber(res, "checkoption");
    7039         310 :     i_toastreloptions = PQfnumber(res, "toast_reloptions");
    7040         310 :     i_reloftype = PQfnumber(res, "reloftype");
    7041         310 :     i_foreignserver = PQfnumber(res, "foreignserver");
    7042         310 :     i_amname = PQfnumber(res, "amname");
    7043         310 :     i_is_identity_sequence = PQfnumber(res, "is_identity_sequence");
    7044         310 :     i_relacl = PQfnumber(res, "relacl");
    7045         310 :     i_acldefault = PQfnumber(res, "acldefault");
    7046         310 :     i_ispartition = PQfnumber(res, "ispartition");
    7047             : 
    7048         310 :     if (dopt->lockWaitTimeout)
    7049             :     {
    7050             :         /*
    7051             :          * Arrange to fail instead of waiting forever for a table lock.
    7052             :          *
    7053             :          * NB: this coding assumes that the only queries issued within the
    7054             :          * following loop are LOCK TABLEs; else the timeout may be undesirably
    7055             :          * applied to other things too.
    7056             :          */
    7057           4 :         resetPQExpBuffer(query);
    7058           4 :         appendPQExpBufferStr(query, "SET statement_timeout = ");
    7059           4 :         appendStringLiteralConn(query, dopt->lockWaitTimeout, GetConnection(fout));
    7060           4 :         ExecuteSqlStatement(fout, query->data);
    7061             :     }
    7062             : 
    7063         310 :     resetPQExpBuffer(query);
    7064             : 
    7065       81750 :     for (i = 0; i < ntups; i++)
    7066             :     {
    7067       81440 :         tblinfo[i].dobj.objType = DO_TABLE;
    7068       81440 :         tblinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_reltableoid));
    7069       81440 :         tblinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_reloid));
    7070       81440 :         AssignDumpId(&tblinfo[i].dobj);
    7071       81440 :         tblinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_relname));
    7072      162880 :         tblinfo[i].dobj.namespace =
    7073       81440 :             findNamespace(atooid(PQgetvalue(res, i, i_relnamespace)));
    7074       81440 :         tblinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_relacl));
    7075       81440 :         tblinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
    7076       81440 :         tblinfo[i].dacl.privtype = 0;
    7077       81440 :         tblinfo[i].dacl.initprivs = NULL;
    7078       81440 :         tblinfo[i].relkind = *(PQgetvalue(res, i, i_relkind));
    7079       81440 :         tblinfo[i].reltype = atooid(PQgetvalue(res, i, i_reltype));
    7080       81440 :         tblinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_relowner));
    7081       81440 :         tblinfo[i].ncheck = atoi(PQgetvalue(res, i, i_relchecks));
    7082       81440 :         tblinfo[i].hasindex = (strcmp(PQgetvalue(res, i, i_relhasindex), "t") == 0);
    7083       81440 :         tblinfo[i].hasrules = (strcmp(PQgetvalue(res, i, i_relhasrules), "t") == 0);
    7084       81440 :         tblinfo[i].relpages = atoi(PQgetvalue(res, i, i_relpages));
    7085       81440 :         if (PQgetisnull(res, i, i_toastpages))
    7086       64190 :             tblinfo[i].toastpages = 0;
    7087             :         else
    7088       17250 :             tblinfo[i].toastpages = atoi(PQgetvalue(res, i, i_toastpages));
    7089       81440 :         if (PQgetisnull(res, i, i_owning_tab))
    7090             :         {
    7091       80692 :             tblinfo[i].owning_tab = InvalidOid;
    7092       80692 :             tblinfo[i].owning_col = 0;
    7093             :         }
    7094             :         else
    7095             :         {
    7096         748 :             tblinfo[i].owning_tab = atooid(PQgetvalue(res, i, i_owning_tab));
    7097         748 :             tblinfo[i].owning_col = atoi(PQgetvalue(res, i, i_owning_col));
    7098             :         }
    7099       81440 :         tblinfo[i].reltablespace = pg_strdup(PQgetvalue(res, i, i_reltablespace));
    7100       81440 :         tblinfo[i].hasoids = (strcmp(PQgetvalue(res, i, i_relhasoids), "t") == 0);
    7101       81440 :         tblinfo[i].hastriggers = (strcmp(PQgetvalue(res, i, i_relhastriggers), "t") == 0);
    7102       81440 :         tblinfo[i].relpersistence = *(PQgetvalue(res, i, i_relpersistence));
    7103       81440 :         tblinfo[i].relispopulated = (strcmp(PQgetvalue(res, i, i_relispopulated), "t") == 0);
    7104       81440 :         tblinfo[i].relreplident = *(PQgetvalue(res, i, i_relreplident));
    7105       81440 :         tblinfo[i].rowsec = (strcmp(PQgetvalue(res, i, i_relrowsec), "t") == 0);
    7106       81440 :         tblinfo[i].forcerowsec = (strcmp(PQgetvalue(res, i, i_relforcerowsec), "t") == 0);
    7107       81440 :         tblinfo[i].frozenxid = atooid(PQgetvalue(res, i, i_relfrozenxid));
    7108       81440 :         tblinfo[i].toast_frozenxid = atooid(PQgetvalue(res, i, i_toastfrozenxid));
    7109       81440 :         tblinfo[i].toast_oid = atooid(PQgetvalue(res, i, i_toastoid));
    7110       81440 :         tblinfo[i].minmxid = atooid(PQgetvalue(res, i, i_relminmxid));
    7111       81440 :         tblinfo[i].toast_minmxid = atooid(PQgetvalue(res, i, i_toastminmxid));
    7112       81440 :         tblinfo[i].reloptions = pg_strdup(PQgetvalue(res, i, i_reloptions));
    7113       81440 :         if (PQgetisnull(res, i, i_checkoption))
    7114       81352 :             tblinfo[i].checkoption = NULL;
    7115             :         else
    7116          88 :             tblinfo[i].checkoption = pg_strdup(PQgetvalue(res, i, i_checkoption));
    7117       81440 :         tblinfo[i].toast_reloptions = pg_strdup(PQgetvalue(res, i, i_toastreloptions));
    7118       81440 :         tblinfo[i].reloftype = atooid(PQgetvalue(res, i, i_reloftype));
    7119       81440 :         tblinfo[i].foreign_server = atooid(PQgetvalue(res, i, i_foreignserver));
    7120       81440 :         if (PQgetisnull(res, i, i_amname))
    7121       48084 :             tblinfo[i].amname = NULL;
    7122             :         else
    7123       33356 :             tblinfo[i].amname = pg_strdup(PQgetvalue(res, i, i_amname));
    7124       81440 :         tblinfo[i].is_identity_sequence = (strcmp(PQgetvalue(res, i, i_is_identity_sequence), "t") == 0);
    7125       81440 :         tblinfo[i].ispartition = (strcmp(PQgetvalue(res, i, i_ispartition), "t") == 0);
    7126             : 
    7127             :         /* other fields were zeroed above */
    7128             : 
    7129             :         /*
    7130             :          * Decide whether we want to dump this table.
    7131             :          */
    7132       81440 :         if (tblinfo[i].relkind == RELKIND_COMPOSITE_TYPE)
    7133         362 :             tblinfo[i].dobj.dump = DUMP_COMPONENT_NONE;
    7134             :         else
    7135       81078 :             selectDumpableTable(&tblinfo[i], fout);
    7136             : 
    7137             :         /*
    7138             :          * Now, consider the table "interesting" if we need to dump its
    7139             :          * definition or its data.  Later on, we'll skip a lot of data
    7140             :          * collection for uninteresting tables.
    7141             :          *
    7142             :          * Note: the "interesting" flag will also be set by flagInhTables for
    7143             :          * parents of interesting tables, so that we collect necessary
    7144             :          * inheritance info even when the parents are not themselves being
    7145             :          * dumped.  This is the main reason why we need an "interesting" flag
    7146             :          * that's separate from the components-to-dump bitmask.
    7147             :          */
    7148       81440 :         tblinfo[i].interesting = (tblinfo[i].dobj.dump &
    7149             :                                   (DUMP_COMPONENT_DEFINITION |
    7150       81440 :                                    DUMP_COMPONENT_DATA)) != 0;
    7151             : 
    7152       81440 :         tblinfo[i].dummy_view = false;  /* might get set during sort */
    7153       81440 :         tblinfo[i].postponed_def = false;   /* might get set during sort */
    7154             : 
    7155             :         /* Tables have data */
    7156       81440 :         tblinfo[i].dobj.components |= DUMP_COMPONENT_DATA;
    7157             : 
    7158             :         /* Mark whether table has an ACL */
    7159       81440 :         if (!PQgetisnull(res, i, i_relacl))
    7160       64352 :             tblinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
    7161       81440 :         tblinfo[i].hascolumnACLs = false;   /* may get set later */
    7162             : 
    7163             :         /*
    7164             :          * Read-lock target tables to make sure they aren't DROPPED or altered
    7165             :          * in schema before we get around to dumping them.
    7166             :          *
    7167             :          * Note that we don't explicitly lock parents of the target tables; we
    7168             :          * assume our lock on the child is enough to prevent schema
    7169             :          * alterations to parent tables.
    7170             :          *
    7171             :          * NOTE: it'd be kinda nice to lock other relations too, not only
    7172             :          * plain or partitioned tables, but the backend doesn't presently
    7173             :          * allow that.
    7174             :          *
    7175             :          * We only need to lock the table for certain components; see
    7176             :          * pg_dump.h
    7177             :          */
    7178       81440 :         if ((tblinfo[i].dobj.dump & DUMP_COMPONENTS_REQUIRING_LOCK) &&
    7179       12260 :             (tblinfo[i].relkind == RELKIND_RELATION ||
    7180        3626 :              tblinfo[i].relkind == RELKIND_PARTITIONED_TABLE))
    7181             :         {
    7182             :             /*
    7183             :              * Tables are locked in batches.  When dumping from a remote
    7184             :              * server this can save a significant amount of time by reducing
    7185             :              * the number of round trips.
    7186             :              */
    7187        9694 :             if (query->len == 0)
    7188         198 :                 appendPQExpBuffer(query, "LOCK TABLE %s",
    7189         198 :                                   fmtQualifiedDumpable(&tblinfo[i]));
    7190             :             else
    7191             :             {
    7192        9496 :                 appendPQExpBuffer(query, ", %s",
    7193        9496 :                                   fmtQualifiedDumpable(&tblinfo[i]));
    7194             : 
    7195             :                 /* Arbitrarily end a batch when query length reaches 100K. */
    7196        9496 :                 if (query->len >= 100000)
    7197             :                 {
    7198             :                     /* Lock another batch of tables. */
    7199           0 :                     appendPQExpBufferStr(query, " IN ACCESS SHARE MODE");
    7200           0 :                     ExecuteSqlStatement(fout, query->data);
    7201           0 :                     resetPQExpBuffer(query);
    7202             :                 }
    7203             :             }
    7204             :         }
    7205             :     }
    7206             : 
    7207         310 :     if (query->len != 0)
    7208             :     {
    7209             :         /* Lock the tables in the last batch. */
    7210         198 :         appendPQExpBufferStr(query, " IN ACCESS SHARE MODE");
    7211         198 :         ExecuteSqlStatement(fout, query->data);
    7212             :     }
    7213             : 
    7214         308 :     if (dopt->lockWaitTimeout)
    7215             :     {
    7216           4 :         ExecuteSqlStatement(fout, "SET statement_timeout = 0");
    7217             :     }
    7218             : 
    7219         308 :     PQclear(res);
    7220             : 
    7221         308 :     destroyPQExpBuffer(query);
    7222             : 
    7223         308 :     return tblinfo;
    7224             : }
    7225             : 
    7226             : /*
    7227             :  * getOwnedSeqs
    7228             :  *    identify owned sequences and mark them as dumpable if owning table is
    7229             :  *
    7230             :  * We used to do this in getTables(), but it's better to do it after the
    7231             :  * index used by findTableByOid() has been set up.
    7232             :  */
    7233             : void
    7234         308 : getOwnedSeqs(Archive *fout, TableInfo tblinfo[], int numTables)
    7235             : {
    7236             :     int         i;
    7237             : 
    7238             :     /*
    7239             :      * Force sequences that are "owned" by table columns to be dumped whenever
    7240             :      * their owning table is being dumped.
    7241             :      */
    7242       81230 :     for (i = 0; i < numTables; i++)
    7243             :     {
    7244       80922 :         TableInfo  *seqinfo = &tblinfo[i];
    7245             :         TableInfo  *owning_tab;
    7246             : 
    7247       80922 :         if (!OidIsValid(seqinfo->owning_tab))
    7248       80180 :             continue;           /* not an owned sequence */
    7249             : 
    7250         742 :         owning_tab = findTableByOid(seqinfo->owning_tab);
    7251         742 :         if (owning_tab == NULL)
    7252           0 :             pg_fatal("failed sanity check, parent table with OID %u of sequence with OID %u not found",
    7253             :                      seqinfo->owning_tab, seqinfo->dobj.catId.oid);
    7254             : 
    7255             :         /*
    7256             :          * For an identity sequence, dump exactly the same components for the
    7257             :          * sequence as for the owning table.  This is important because we
    7258             :          * treat the identity sequence as an integral part of the table.  For
    7259             :          * example, there is not any DDL command that allows creation of such
    7260             :          * a sequence independently of the table.
    7261             :          *
    7262             :          * For other owned sequences such as serial sequences, we need to dump
    7263             :          * the components that are being dumped for the table and any
    7264             :          * components that the sequence is explicitly marked with.
    7265             :          *
    7266             :          * We can't simply use the set of components which are being dumped
    7267             :          * for the table as the table might be in an extension (and only the
    7268             :          * non-extension components, eg: ACLs if changed, security labels, and
    7269             :          * policies, are being dumped) while the sequence is not (and
    7270             :          * therefore the definition and other components should also be
    7271             :          * dumped).
    7272             :          *
    7273             :          * If the sequence is part of the extension then it should be properly
    7274             :          * marked by checkExtensionMembership() and this will be a no-op as
    7275             :          * the table will be equivalently marked.
    7276             :          */
    7277         742 :         if (seqinfo->is_identity_sequence)
    7278         394 :             seqinfo->dobj.dump = owning_tab->dobj.dump;
    7279             :         else
    7280         348 :             seqinfo->dobj.dump |= owning_tab->dobj.dump;
    7281             : 
    7282             :         /* Make sure that necessary data is available if we're dumping it */
    7283         742 :         if (seqinfo->dobj.dump != DUMP_COMPONENT_NONE)
    7284             :         {
    7285         570 :             seqinfo->interesting = true;
    7286         570 :             owning_tab->interesting = true;
    7287             :         }
    7288             :     }
    7289         308 : }
    7290             : 
    7291             : /*
    7292             :  * getInherits
    7293             :  *    read all the inheritance information
    7294             :  * from the system catalogs return them in the InhInfo* structure
    7295             :  *
    7296             :  * numInherits is set to the number of pairs read in
    7297             :  */
    7298             : InhInfo *
    7299         308 : getInherits(Archive *fout, int *numInherits)
    7300             : {
    7301             :     PGresult   *res;
    7302             :     int         ntups;
    7303             :     int         i;
    7304         308 :     PQExpBuffer query = createPQExpBuffer();
    7305             :     InhInfo    *inhinfo;
    7306             : 
    7307             :     int         i_inhrelid;
    7308             :     int         i_inhparent;
    7309             : 
    7310             :     /* find all the inheritance information */
    7311         308 :     appendPQExpBufferStr(query, "SELECT inhrelid, inhparent FROM pg_inherits");
    7312             : 
    7313         308 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    7314             : 
    7315         308 :     ntups = PQntuples(res);
    7316             : 
    7317         308 :     *numInherits = ntups;
    7318             : 
    7319         308 :     inhinfo = (InhInfo *) pg_malloc(ntups * sizeof(InhInfo));
    7320             : 
    7321         308 :     i_inhrelid = PQfnumber(res, "inhrelid");
    7322         308 :     i_inhparent = PQfnumber(res, "inhparent");
    7323             : 
    7324        6096 :     for (i = 0; i < ntups; i++)
    7325             :     {
    7326        5788 :         inhinfo[i].inhrelid = atooid(PQgetvalue(res, i, i_inhrelid));
    7327        5788 :         inhinfo[i].inhparent = atooid(PQgetvalue(res, i, i_inhparent));
    7328             :     }
    7329             : 
    7330         308 :     PQclear(res);
    7331             : 
    7332         308 :     destroyPQExpBuffer(query);
    7333             : 
    7334         308 :     return inhinfo;
    7335             : }
    7336             : 
    7337             : /*
    7338             :  * getPartitioningInfo
    7339             :  *    get information about partitioning
    7340             :  *
    7341             :  * For the most part, we only collect partitioning info about tables we
    7342             :  * intend to dump.  However, this function has to consider all partitioned
    7343             :  * tables in the database, because we need to know about parents of partitions
    7344             :  * we are going to dump even if the parents themselves won't be dumped.
    7345             :  *
    7346             :  * Specifically, what we need to know is whether each partitioned table
    7347             :  * has an "unsafe" partitioning scheme that requires us to force
    7348             :  * load-via-partition-root mode for its children.  Currently the only case
    7349             :  * for which we force that is hash partitioning on enum columns, since the
    7350             :  * hash codes depend on enum value OIDs which won't be replicated across
    7351             :  * dump-and-reload.  There are other cases in which load-via-partition-root
    7352             :  * might be necessary, but we expect users to cope with them.
    7353             :  */
    7354             : void
    7355         308 : getPartitioningInfo(Archive *fout)
    7356             : {
    7357             :     PQExpBuffer query;
    7358             :     PGresult   *res;
    7359             :     int         ntups;
    7360             : 
    7361             :     /* hash partitioning didn't exist before v11 */
    7362         308 :     if (fout->remoteVersion < 110000)
    7363           0 :         return;
    7364             :     /* needn't bother if not dumping data */
    7365         308 :     if (!fout->dopt->dumpData)
    7366          32 :         return;
    7367             : 
    7368         276 :     query = createPQExpBuffer();
    7369             : 
    7370             :     /*
    7371             :      * Unsafe partitioning schemes are exactly those for which hash enum_ops
    7372             :      * appears among the partition opclasses.  We needn't check partstrat.
    7373             :      *
    7374             :      * Note that this query may well retrieve info about tables we aren't
    7375             :      * going to dump and hence have no lock on.  That's okay since we need not
    7376             :      * invoke any unsafe server-side functions.
    7377             :      */
    7378         276 :     appendPQExpBufferStr(query,
    7379             :                          "SELECT partrelid FROM pg_partitioned_table WHERE\n"
    7380             :                          "(SELECT c.oid FROM pg_opclass c JOIN pg_am a "
    7381             :                          "ON c.opcmethod = a.oid\n"
    7382             :                          "WHERE opcname = 'enum_ops' "
    7383             :                          "AND opcnamespace = 'pg_catalog'::regnamespace "
    7384             :                          "AND amname = 'hash') = ANY(partclass)");
    7385             : 
    7386         276 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    7387             : 
    7388         276 :     ntups = PQntuples(res);
    7389             : 
    7390         280 :     for (int i = 0; i < ntups; i++)
    7391             :     {
    7392           4 :         Oid         tabrelid = atooid(PQgetvalue(res, i, 0));
    7393             :         TableInfo  *tbinfo;
    7394             : 
    7395           4 :         tbinfo = findTableByOid(tabrelid);
    7396           4 :         if (tbinfo == NULL)
    7397           0 :             pg_fatal("failed sanity check, table OID %u appearing in pg_partitioned_table not found",
    7398             :                      tabrelid);
    7399           4 :         tbinfo->unsafe_partitions = true;
    7400             :     }
    7401             : 
    7402         276 :     PQclear(res);
    7403             : 
    7404         276 :     destroyPQExpBuffer(query);
    7405             : }
    7406             : 
    7407             : /*
    7408             :  * getIndexes
    7409             :  *    get information about every index on a dumpable table
    7410             :  *
    7411             :  * Note: index data is not returned directly to the caller, but it
    7412             :  * does get entered into the DumpableObject tables.
    7413             :  */
    7414             : void
    7415         308 : getIndexes(Archive *fout, TableInfo tblinfo[], int numTables)
    7416             : {
    7417         308 :     PQExpBuffer query = createPQExpBuffer();
    7418         308 :     PQExpBuffer tbloids = createPQExpBuffer();
    7419             :     PGresult   *res;
    7420             :     int         ntups;
    7421             :     int         curtblindx;
    7422             :     IndxInfo   *indxinfo;
    7423             :     int         i_tableoid,
    7424             :                 i_oid,
    7425             :                 i_indrelid,
    7426             :                 i_indexname,
    7427             :                 i_parentidx,
    7428             :                 i_indexdef,
    7429             :                 i_indnkeyatts,
    7430             :                 i_indnatts,
    7431             :                 i_indkey,
    7432             :                 i_indisclustered,
    7433             :                 i_indisreplident,
    7434             :                 i_indnullsnotdistinct,
    7435             :                 i_contype,
    7436             :                 i_conname,
    7437             :                 i_condeferrable,
    7438             :                 i_condeferred,
    7439             :                 i_conperiod,
    7440             :                 i_contableoid,
    7441             :                 i_conoid,
    7442             :                 i_condef,
    7443             :                 i_tablespace,
    7444             :                 i_indreloptions,
    7445             :                 i_indstatcols,
    7446             :                 i_indstatvals;
    7447             : 
    7448             :     /*
    7449             :      * We want to perform just one query against pg_index.  However, we
    7450             :      * mustn't try to select every row of the catalog and then sort it out on
    7451             :      * the client side, because some of the server-side functions we need
    7452             :      * would be unsafe to apply to tables we don't have lock on.  Hence, we
    7453             :      * build an array of the OIDs of tables we care about (and now have lock
    7454             :      * on!), and use a WHERE clause to constrain which rows are selected.
    7455             :      */
    7456         308 :     appendPQExpBufferChar(tbloids, '{');
    7457       81230 :     for (int i = 0; i < numTables; i++)
    7458             :     {
    7459       80922 :         TableInfo  *tbinfo = &tblinfo[i];
    7460             : 
    7461       80922 :         if (!tbinfo->hasindex)
    7462       56980 :             continue;
    7463             : 
    7464             :         /*
    7465             :          * We can ignore indexes of uninteresting tables.
    7466             :          */
    7467       23942 :         if (!tbinfo->interesting)
    7468       20360 :             continue;
    7469             : 
    7470             :         /* OK, we need info for this table */
    7471        3582 :         if (tbloids->len > 1) /* do we have more than the '{'? */
    7472        3430 :             appendPQExpBufferChar(tbloids, ',');
    7473        3582 :         appendPQExpBuffer(tbloids, "%u", tbinfo->dobj.catId.oid);
    7474             :     }
    7475         308 :     appendPQExpBufferChar(tbloids, '}');
    7476             : 
    7477         308 :     appendPQExpBufferStr(query,
    7478             :                          "SELECT t.tableoid, t.oid, i.indrelid, "
    7479             :                          "t.relname AS indexname, "
    7480             :                          "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
    7481             :                          "i.indkey, i.indisclustered, "
    7482             :                          "c.contype, c.conname, "
    7483             :                          "c.condeferrable, c.condeferred, "
    7484             :                          "c.tableoid AS contableoid, "
    7485             :                          "c.oid AS conoid, "
    7486             :                          "pg_catalog.pg_get_constraintdef(c.oid, false) AS condef, "
    7487             :                          "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
    7488             :                          "t.reloptions AS indreloptions, ");
    7489             : 
    7490             : 
    7491         308 :     if (fout->remoteVersion >= 90400)
    7492         308 :         appendPQExpBufferStr(query,
    7493             :                              "i.indisreplident, ");
    7494             :     else
    7495           0 :         appendPQExpBufferStr(query,
    7496             :                              "false AS indisreplident, ");
    7497             : 
    7498         308 :     if (fout->remoteVersion >= 110000)
    7499         308 :         appendPQExpBufferStr(query,
    7500             :                              "inh.inhparent AS parentidx, "
    7501             :                              "i.indnkeyatts AS indnkeyatts, "
    7502             :                              "i.indnatts AS indnatts, "
    7503             :                              "(SELECT pg_catalog.array_agg(attnum ORDER BY attnum) "
    7504             :                              "  FROM pg_catalog.pg_attribute "
    7505             :                              "  WHERE attrelid = i.indexrelid AND "
    7506             :                              "    attstattarget >= 0) AS indstatcols, "
    7507             :                              "(SELECT pg_catalog.array_agg(attstattarget ORDER BY attnum) "
    7508             :                              "  FROM pg_catalog.pg_attribute "
    7509             :                              "  WHERE attrelid = i.indexrelid AND "
    7510             :                              "    attstattarget >= 0) AS indstatvals, ");
    7511             :     else
    7512           0 :         appendPQExpBufferStr(query,
    7513             :                              "0 AS parentidx, "
    7514             :                              "i.indnatts AS indnkeyatts, "
    7515             :                              "i.indnatts AS indnatts, "
    7516             :                              "'' AS indstatcols, "
    7517             :                              "'' AS indstatvals, ");
    7518             : 
    7519         308 :     if (fout->remoteVersion >= 150000)
    7520         308 :         appendPQExpBufferStr(query,
    7521             :                              "i.indnullsnotdistinct, ");
    7522             :     else
    7523           0 :         appendPQExpBufferStr(query,
    7524             :                              "false AS indnullsnotdistinct, ");
    7525             : 
    7526         308 :     if (fout->remoteVersion >= 180000)
    7527         308 :         appendPQExpBufferStr(query,
    7528             :                              "c.conperiod ");
    7529             :     else
    7530           0 :         appendPQExpBufferStr(query,
    7531             :                              "NULL AS conperiod ");
    7532             : 
    7533             :     /*
    7534             :      * The point of the messy-looking outer join is to find a constraint that
    7535             :      * is related by an internal dependency link to the index. If we find one,
    7536             :      * create a CONSTRAINT entry linked to the INDEX entry.  We assume an
    7537             :      * index won't have more than one internal dependency.
    7538             :      *
    7539             :      * Note: the check on conrelid is redundant, but useful because that
    7540             :      * column is indexed while conindid is not.
    7541             :      */
    7542         308 :     if (fout->remoteVersion >= 110000)
    7543             :     {
    7544         308 :         appendPQExpBuffer(query,
    7545             :                           "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
    7546             :                           "JOIN pg_catalog.pg_index i ON (src.tbloid = i.indrelid) "
    7547             :                           "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
    7548             :                           "JOIN pg_catalog.pg_class t2 ON (t2.oid = i.indrelid) "
    7549             :                           "LEFT JOIN pg_catalog.pg_constraint c "
    7550             :                           "ON (i.indrelid = c.conrelid AND "
    7551             :                           "i.indexrelid = c.conindid AND "
    7552             :                           "c.contype IN ('p','u','x')) "
    7553             :                           "LEFT JOIN pg_catalog.pg_inherits inh "
    7554             :                           "ON (inh.inhrelid = indexrelid) "
    7555             :                           "WHERE (i.indisvalid OR t2.relkind = 'p') "
    7556             :                           "AND i.indisready "
    7557             :                           "ORDER BY i.indrelid, indexname",
    7558             :                           tbloids->data);
    7559             :     }
    7560             :     else
    7561             :     {
    7562             :         /*
    7563             :          * the test on indisready is necessary in 9.2, and harmless in
    7564             :          * earlier/later versions
    7565             :          */
    7566           0 :         appendPQExpBuffer(query,
    7567             :                           "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
    7568             :                           "JOIN pg_catalog.pg_index i ON (src.tbloid = i.indrelid) "
    7569             :                           "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
    7570             :                           "LEFT JOIN pg_catalog.pg_constraint c "
    7571             :                           "ON (i.indrelid = c.conrelid AND "
    7572             :                           "i.indexrelid = c.conindid AND "
    7573             :                           "c.contype IN ('p','u','x')) "
    7574             :                           "WHERE i.indisvalid AND i.indisready "
    7575             :                           "ORDER BY i.indrelid, indexname",
    7576             :                           tbloids->data);
    7577             :     }
    7578             : 
    7579         308 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    7580             : 
    7581         308 :     ntups = PQntuples(res);
    7582             : 
    7583         308 :     i_tableoid = PQfnumber(res, "tableoid");
    7584         308 :     i_oid = PQfnumber(res, "oid");
    7585         308 :     i_indrelid = PQfnumber(res, "indrelid");
    7586         308 :     i_indexname = PQfnumber(res, "indexname");
    7587         308 :     i_parentidx = PQfnumber(res, "parentidx");
    7588         308 :     i_indexdef = PQfnumber(res, "indexdef");
    7589         308 :     i_indnkeyatts = PQfnumber(res, "indnkeyatts");
    7590         308 :     i_indnatts = PQfnumber(res, "indnatts");
    7591         308 :     i_indkey = PQfnumber(res, "indkey");
    7592         308 :     i_indisclustered = PQfnumber(res, "indisclustered");
    7593         308 :     i_indisreplident = PQfnumber(res, "indisreplident");
    7594         308 :     i_indnullsnotdistinct = PQfnumber(res, "indnullsnotdistinct");
    7595         308 :     i_contype = PQfnumber(res, "contype");
    7596         308 :     i_conname = PQfnumber(res, "conname");
    7597         308 :     i_condeferrable = PQfnumber(res, "condeferrable");
    7598         308 :     i_condeferred = PQfnumber(res, "condeferred");
    7599         308 :     i_conperiod = PQfnumber(res, "conperiod");
    7600         308 :     i_contableoid = PQfnumber(res, "contableoid");
    7601         308 :     i_conoid = PQfnumber(res, "conoid");
    7602         308 :     i_condef = PQfnumber(res, "condef");
    7603         308 :     i_tablespace = PQfnumber(res, "tablespace");
    7604         308 :     i_indreloptions = PQfnumber(res, "indreloptions");
    7605         308 :     i_indstatcols = PQfnumber(res, "indstatcols");
    7606         308 :     i_indstatvals = PQfnumber(res, "indstatvals");
    7607             : 
    7608         308 :     indxinfo = (IndxInfo *) pg_malloc(ntups * sizeof(IndxInfo));
    7609             : 
    7610             :     /*
    7611             :      * Outer loop iterates once per table, not once per row.  Incrementing of
    7612             :      * j is handled by the inner loop.
    7613             :      */
    7614         308 :     curtblindx = -1;
    7615        3882 :     for (int j = 0; j < ntups;)
    7616             :     {
    7617        3574 :         Oid         indrelid = atooid(PQgetvalue(res, j, i_indrelid));
    7618        3574 :         TableInfo  *tbinfo = NULL;
    7619             :         int         numinds;
    7620             : 
    7621             :         /* Count rows for this table */
    7622        4758 :         for (numinds = 1; numinds < ntups - j; numinds++)
    7623        4606 :             if (atooid(PQgetvalue(res, j + numinds, i_indrelid)) != indrelid)
    7624        3422 :                 break;
    7625             : 
    7626             :         /*
    7627             :          * Locate the associated TableInfo; we rely on tblinfo[] being in OID
    7628             :          * order.
    7629             :          */
    7630       43156 :         while (++curtblindx < numTables)
    7631             :         {
    7632       43156 :             tbinfo = &tblinfo[curtblindx];
    7633       43156 :             if (tbinfo->dobj.catId.oid == indrelid)
    7634        3574 :                 break;
    7635             :         }
    7636        3574 :         if (curtblindx >= numTables)
    7637           0 :             pg_fatal("unrecognized table OID %u", indrelid);
    7638             :         /* cross-check that we only got requested tables */
    7639        3574 :         if (!tbinfo->hasindex ||
    7640        3574 :             !tbinfo->interesting)
    7641           0 :             pg_fatal("unexpected index data for table \"%s\"",
    7642             :                      tbinfo->dobj.name);
    7643             : 
    7644             :         /* Save data for this table */
    7645        3574 :         tbinfo->indexes = indxinfo + j;
    7646        3574 :         tbinfo->numIndexes = numinds;
    7647             : 
    7648        8332 :         for (int c = 0; c < numinds; c++, j++)
    7649             :         {
    7650             :             char        contype;
    7651             : 
    7652        4758 :             indxinfo[j].dobj.objType = DO_INDEX;
    7653        4758 :             indxinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
    7654        4758 :             indxinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
    7655        4758 :             AssignDumpId(&indxinfo[j].dobj);
    7656        4758 :             indxinfo[j].dobj.dump = tbinfo->dobj.dump;
    7657        4758 :             indxinfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_indexname));
    7658        4758 :             indxinfo[j].dobj.namespace = tbinfo->dobj.namespace;
    7659        4758 :             indxinfo[j].indextable = tbinfo;
    7660        4758 :             indxinfo[j].indexdef = pg_strdup(PQgetvalue(res, j, i_indexdef));
    7661        4758 :             indxinfo[j].indnkeyattrs = atoi(PQgetvalue(res, j, i_indnkeyatts));
    7662        4758 :             indxinfo[j].indnattrs = atoi(PQgetvalue(res, j, i_indnatts));
    7663        4758 :             indxinfo[j].tablespace = pg_strdup(PQgetvalue(res, j, i_tablespace));
    7664        4758 :             indxinfo[j].indreloptions = pg_strdup(PQgetvalue(res, j, i_indreloptions));
    7665        4758 :             indxinfo[j].indstatcols = pg_strdup(PQgetvalue(res, j, i_indstatcols));
    7666        4758 :             indxinfo[j].indstatvals = pg_strdup(PQgetvalue(res, j, i_indstatvals));
    7667        4758 :             indxinfo[j].indkeys = (Oid *) pg_malloc(indxinfo[j].indnattrs * sizeof(Oid));
    7668        4758 :             parseOidArray(PQgetvalue(res, j, i_indkey),
    7669        4758 :                           indxinfo[j].indkeys, indxinfo[j].indnattrs);
    7670        4758 :             indxinfo[j].indisclustered = (PQgetvalue(res, j, i_indisclustered)[0] == 't');
    7671        4758 :             indxinfo[j].indisreplident = (PQgetvalue(res, j, i_indisreplident)[0] == 't');
    7672        4758 :             indxinfo[j].indnullsnotdistinct = (PQgetvalue(res, j, i_indnullsnotdistinct)[0] == 't');
    7673        4758 :             indxinfo[j].parentidx = atooid(PQgetvalue(res, j, i_parentidx));
    7674        4758 :             indxinfo[j].partattaches = (SimplePtrList)
    7675             :             {
    7676             :                 NULL, NULL
    7677             :             };
    7678        4758 :             contype = *(PQgetvalue(res, j, i_contype));
    7679             : 
    7680        4758 :             if (contype == 'p' || contype == 'u' || contype == 'x')
    7681        2754 :             {
    7682             :                 /*
    7683             :                  * If we found a constraint matching the index, create an
    7684             :                  * entry for it.
    7685             :                  */
    7686             :                 ConstraintInfo *constrinfo;
    7687             : 
    7688        2754 :                 constrinfo = (ConstraintInfo *) pg_malloc(sizeof(ConstraintInfo));
    7689        2754 :                 constrinfo->dobj.objType = DO_CONSTRAINT;
    7690        2754 :                 constrinfo->dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_contableoid));
    7691        2754 :                 constrinfo->dobj.catId.oid = atooid(PQgetvalue(res, j, i_conoid));
    7692        2754 :                 AssignDumpId(&constrinfo->dobj);
    7693        2754 :                 constrinfo->dobj.dump = tbinfo->dobj.dump;
    7694        2754 :                 constrinfo->dobj.name = pg_strdup(PQgetvalue(res, j, i_conname));
    7695        2754 :                 constrinfo->dobj.namespace = tbinfo->dobj.namespace;
    7696        2754 :                 constrinfo->contable = tbinfo;
    7697        2754 :                 constrinfo->condomain = NULL;
    7698        2754 :                 constrinfo->contype = contype;
    7699        2754 :                 if (contype == 'x')
    7700          20 :                     constrinfo->condef = pg_strdup(PQgetvalue(res, j, i_condef));
    7701             :                 else
    7702        2734 :                     constrinfo->condef = NULL;
    7703        2754 :                 constrinfo->confrelid = InvalidOid;
    7704        2754 :                 constrinfo->conindex = indxinfo[j].dobj.dumpId;
    7705        2754 :                 constrinfo->condeferrable = *(PQgetvalue(res, j, i_condeferrable)) == 't';
    7706        2754 :                 constrinfo->condeferred = *(PQgetvalue(res, j, i_condeferred)) == 't';
    7707        2754 :                 constrinfo->conperiod = *(PQgetvalue(res, j, i_conperiod)) == 't';
    7708        2754 :                 constrinfo->conislocal = true;
    7709        2754 :                 constrinfo->separate = true;
    7710             : 
    7711        2754 :                 indxinfo[j].indexconstraint = constrinfo->dobj.dumpId;
    7712             :             }
    7713             :             else
    7714             :             {
    7715             :                 /* Plain secondary index */
    7716        2004 :                 indxinfo[j].indexconstraint = 0;
    7717             :             }
    7718             :         }
    7719             :     }
    7720             : 
    7721         308 :     PQclear(res);
    7722             : 
    7723         308 :     destroyPQExpBuffer(query);
    7724         308 :     destroyPQExpBuffer(tbloids);
    7725         308 : }
    7726             : 
    7727             : /*
    7728             :  * getExtendedStatistics
    7729             :  *    get information about extended-statistics objects.
    7730             :  *
    7731             :  * Note: extended statistics data is not returned directly to the caller, but
    7732             :  * it does get entered into the DumpableObject tables.
    7733             :  */
    7734             : void
    7735         308 : getExtendedStatistics(Archive *fout)
    7736             : {
    7737             :     PQExpBuffer query;
    7738             :     PGresult   *res;
    7739             :     StatsExtInfo *statsextinfo;
    7740             :     int         ntups;
    7741             :     int         i_tableoid;
    7742             :     int         i_oid;
    7743             :     int         i_stxname;
    7744             :     int         i_stxnamespace;
    7745             :     int         i_stxowner;
    7746             :     int         i_stxrelid;
    7747             :     int         i_stattarget;
    7748             :     int         i;
    7749             : 
    7750             :     /* Extended statistics were new in v10 */
    7751         308 :     if (fout->remoteVersion < 100000)
    7752           0 :         return;
    7753             : 
    7754         308 :     query = createPQExpBuffer();
    7755             : 
    7756         308 :     if (fout->remoteVersion < 130000)
    7757           0 :         appendPQExpBufferStr(query, "SELECT tableoid, oid, stxname, "
    7758             :                              "stxnamespace, stxowner, stxrelid, NULL AS stxstattarget "
    7759             :                              "FROM pg_catalog.pg_statistic_ext");
    7760             :     else
    7761         308 :         appendPQExpBufferStr(query, "SELECT tableoid, oid, stxname, "
    7762             :                              "stxnamespace, stxowner, stxrelid, stxstattarget "
    7763             :                              "FROM pg_catalog.pg_statistic_ext");
    7764             : 
    7765         308 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    7766             : 
    7767         308 :     ntups = PQntuples(res);
    7768             : 
    7769         308 :     i_tableoid = PQfnumber(res, "tableoid");
    7770         308 :     i_oid = PQfnumber(res, "oid");
    7771         308 :     i_stxname = PQfnumber(res, "stxname");
    7772         308 :     i_stxnamespace = PQfnumber(res, "stxnamespace");
    7773         308 :     i_stxowner = PQfnumber(res, "stxowner");
    7774         308 :     i_stxrelid = PQfnumber(res, "stxrelid");
    7775         308 :     i_stattarget = PQfnumber(res, "stxstattarget");
    7776             : 
    7777         308 :     statsextinfo = (StatsExtInfo *) pg_malloc(ntups * sizeof(StatsExtInfo));
    7778             : 
    7779         622 :     for (i = 0; i < ntups; i++)
    7780             :     {
    7781         314 :         statsextinfo[i].dobj.objType = DO_STATSEXT;
    7782         314 :         statsextinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    7783         314 :         statsextinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    7784         314 :         AssignDumpId(&statsextinfo[i].dobj);
    7785         314 :         statsextinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_stxname));
    7786         628 :         statsextinfo[i].dobj.namespace =
    7787         314 :             findNamespace(atooid(PQgetvalue(res, i, i_stxnamespace)));
    7788         314 :         statsextinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_stxowner));
    7789         628 :         statsextinfo[i].stattable =
    7790         314 :             findTableByOid(atooid(PQgetvalue(res, i, i_stxrelid)));
    7791         314 :         if (PQgetisnull(res, i, i_stattarget))
    7792         228 :             statsextinfo[i].stattarget = -1;
    7793             :         else
    7794          86 :             statsextinfo[i].stattarget = atoi(PQgetvalue(res, i, i_stattarget));
    7795             : 
    7796             :         /* Decide whether we want to dump it */
    7797         314 :         selectDumpableStatisticsObject(&(statsextinfo[i]), fout);
    7798             :     }
    7799             : 
    7800         308 :     PQclear(res);
    7801         308 :     destroyPQExpBuffer(query);
    7802             : }
    7803             : 
    7804             : /*
    7805             :  * getConstraints
    7806             :  *
    7807             :  * Get info about constraints on dumpable tables.
    7808             :  *
    7809             :  * Currently handles foreign keys only.
    7810             :  * Unique and primary key constraints are handled with indexes,
    7811             :  * while check constraints are processed in getTableAttrs().
    7812             :  */
    7813             : void
    7814         308 : getConstraints(Archive *fout, TableInfo tblinfo[], int numTables)
    7815             : {
    7816         308 :     PQExpBuffer query = createPQExpBuffer();
    7817         308 :     PQExpBuffer tbloids = createPQExpBuffer();
    7818             :     PGresult   *res;
    7819             :     int         ntups;
    7820             :     int         curtblindx;
    7821         308 :     TableInfo  *tbinfo = NULL;
    7822             :     ConstraintInfo *constrinfo;
    7823             :     int         i_contableoid,
    7824             :                 i_conoid,
    7825             :                 i_conrelid,
    7826             :                 i_conname,
    7827             :                 i_confrelid,
    7828             :                 i_conindid,
    7829             :                 i_condef;
    7830             : 
    7831             :     /*
    7832             :      * We want to perform just one query against pg_constraint.  However, we
    7833             :      * mustn't try to select every row of the catalog and then sort it out on
    7834             :      * the client side, because some of the server-side functions we need
    7835             :      * would be unsafe to apply to tables we don't have lock on.  Hence, we
    7836             :      * build an array of the OIDs of tables we care about (and now have lock
    7837             :      * on!), and use a WHERE clause to constrain which rows are selected.
    7838             :      */
    7839         308 :     appendPQExpBufferChar(tbloids, '{');
    7840       81230 :     for (int i = 0; i < numTables; i++)
    7841             :     {
    7842       80922 :         TableInfo  *tinfo = &tblinfo[i];
    7843             : 
    7844             :         /*
    7845             :          * For partitioned tables, foreign keys have no triggers so they must
    7846             :          * be included anyway in case some foreign keys are defined.
    7847             :          */
    7848       80922 :         if ((!tinfo->hastriggers &&
    7849       78740 :              tinfo->relkind != RELKIND_PARTITIONED_TABLE) ||
    7850        3134 :             !(tinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
    7851       78566 :             continue;
    7852             : 
    7853             :         /* OK, we need info for this table */
    7854        2356 :         if (tbloids->len > 1) /* do we have more than the '{'? */
    7855        2254 :             appendPQExpBufferChar(tbloids, ',');
    7856        2356 :         appendPQExpBuffer(tbloids, "%u", tinfo->dobj.catId.oid);
    7857             :     }
    7858         308 :     appendPQExpBufferChar(tbloids, '}');
    7859             : 
    7860         308 :     appendPQExpBufferStr(query,
    7861             :                          "SELECT c.tableoid, c.oid, "
    7862             :                          "conrelid, conname, confrelid, ");
    7863         308 :     if (fout->remoteVersion >= 110000)
    7864         308 :         appendPQExpBufferStr(query, "conindid, ");
    7865             :     else
    7866           0 :         appendPQExpBufferStr(query, "0 AS conindid, ");
    7867         308 :     appendPQExpBuffer(query,
    7868             :                       "pg_catalog.pg_get_constraintdef(c.oid) AS condef\n"
    7869             :                       "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
    7870             :                       "JOIN pg_catalog.pg_constraint c ON (src.tbloid = c.conrelid)\n"
    7871             :                       "WHERE contype = 'f' ",
    7872             :                       tbloids->data);
    7873         308 :     if (fout->remoteVersion >= 110000)
    7874         308 :         appendPQExpBufferStr(query,
    7875             :                              "AND conparentid = 0 ");
    7876         308 :     appendPQExpBufferStr(query,
    7877             :                          "ORDER BY conrelid, conname");
    7878             : 
    7879         308 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    7880             : 
    7881         308 :     ntups = PQntuples(res);
    7882             : 
    7883         308 :     i_contableoid = PQfnumber(res, "tableoid");
    7884         308 :     i_conoid = PQfnumber(res, "oid");
    7885         308 :     i_conrelid = PQfnumber(res, "conrelid");
    7886         308 :     i_conname = PQfnumber(res, "conname");
    7887         308 :     i_confrelid = PQfnumber(res, "confrelid");
    7888         308 :     i_conindid = PQfnumber(res, "conindid");
    7889         308 :     i_condef = PQfnumber(res, "condef");
    7890             : 
    7891         308 :     constrinfo = (ConstraintInfo *) pg_malloc(ntups * sizeof(ConstraintInfo));
    7892             : 
    7893         308 :     curtblindx = -1;
    7894         652 :     for (int j = 0; j < ntups; j++)
    7895             :     {
    7896         344 :         Oid         conrelid = atooid(PQgetvalue(res, j, i_conrelid));
    7897             :         TableInfo  *reftable;
    7898             : 
    7899             :         /*
    7900             :          * Locate the associated TableInfo; we rely on tblinfo[] being in OID
    7901             :          * order.
    7902             :          */
    7903         344 :         if (tbinfo == NULL || tbinfo->dobj.catId.oid != conrelid)
    7904             :         {
    7905       25128 :             while (++curtblindx < numTables)
    7906             :             {
    7907       25128 :                 tbinfo = &tblinfo[curtblindx];
    7908       25128 :                 if (tbinfo->dobj.catId.oid == conrelid)
    7909         324 :                     break;
    7910             :             }
    7911         324 :             if (curtblindx >= numTables)
    7912           0 :                 pg_fatal("unrecognized table OID %u", conrelid);
    7913             :         }
    7914             : 
    7915         344 :         constrinfo[j].dobj.objType = DO_FK_CONSTRAINT;
    7916         344 :         constrinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_contableoid));
    7917         344 :         constrinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_conoid));
    7918         344 :         AssignDumpId(&constrinfo[j].dobj);
    7919         344 :         constrinfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_conname));
    7920         344 :         constrinfo[j].dobj.namespace = tbinfo->dobj.namespace;
    7921         344 :         constrinfo[j].contable = tbinfo;
    7922         344 :         constrinfo[j].condomain = NULL;
    7923         344 :         constrinfo[j].contype = 'f';
    7924         344 :         constrinfo[j].condef = pg_strdup(PQgetvalue(res, j, i_condef));
    7925         344 :         constrinfo[j].confrelid = atooid(PQgetvalue(res, j, i_confrelid));
    7926         344 :         constrinfo[j].conindex = 0;
    7927         344 :         constrinfo[j].condeferrable = false;
    7928         344 :         constrinfo[j].condeferred = false;
    7929         344 :         constrinfo[j].conislocal = true;
    7930         344 :         constrinfo[j].separate = true;
    7931             : 
    7932             :         /*
    7933             :          * Restoring an FK that points to a partitioned table requires that
    7934             :          * all partition indexes have been attached beforehand. Ensure that
    7935             :          * happens by making the constraint depend on each index partition
    7936             :          * attach object.
    7937             :          */
    7938         344 :         reftable = findTableByOid(constrinfo[j].confrelid);
    7939         344 :         if (reftable && reftable->relkind == RELKIND_PARTITIONED_TABLE)
    7940             :         {
    7941          40 :             Oid         indexOid = atooid(PQgetvalue(res, j, i_conindid));
    7942             : 
    7943          40 :             if (indexOid != InvalidOid)
    7944             :             {
    7945          40 :                 for (int k = 0; k < reftable->numIndexes; k++)
    7946             :                 {
    7947             :                     IndxInfo   *refidx;
    7948             : 
    7949             :                     /* not our index? */
    7950          40 :                     if (reftable->indexes[k].dobj.catId.oid != indexOid)
    7951           0 :                         continue;
    7952             : 
    7953          40 :                     refidx = &reftable->indexes[k];
    7954          40 :                     addConstrChildIdxDeps(&constrinfo[j].dobj, refidx);
    7955          40 :                     break;
    7956             :                 }
    7957             :             }
    7958             :         }
    7959             :     }
    7960             : 
    7961         308 :     PQclear(res);
    7962             : 
    7963         308 :     destroyPQExpBuffer(query);
    7964         308 :     destroyPQExpBuffer(tbloids);
    7965         308 : }
    7966             : 
    7967             : /*
    7968             :  * addConstrChildIdxDeps
    7969             :  *
    7970             :  * Recursive subroutine for getConstraints
    7971             :  *
    7972             :  * Given an object representing a foreign key constraint and an index on the
    7973             :  * partitioned table it references, mark the constraint object as dependent
    7974             :  * on the DO_INDEX_ATTACH object of each index partition, recursively
    7975             :  * drilling down to their partitions if any.  This ensures that the FK is not
    7976             :  * restored until the index is fully marked valid.
    7977             :  */
    7978             : static void
    7979          90 : addConstrChildIdxDeps(DumpableObject *dobj, const IndxInfo *refidx)
    7980             : {
    7981             :     SimplePtrListCell *cell;
    7982             : 
    7983             :     Assert(dobj->objType == DO_FK_CONSTRAINT);
    7984             : 
    7985         310 :     for (cell = refidx->partattaches.head; cell; cell = cell->next)
    7986             :     {
    7987         220 :         IndexAttachInfo *attach = (IndexAttachInfo *) cell->ptr;
    7988             : 
    7989         220 :         addObjectDependency(dobj, attach->dobj.dumpId);
    7990             : 
    7991         220 :         if (attach->partitionIdx->partattaches.head != NULL)
    7992          50 :             addConstrChildIdxDeps(dobj, attach->partitionIdx);
    7993             :     }
    7994          90 : }
    7995             : 
    7996             : /*
    7997             :  * getDomainConstraints
    7998             :  *
    7999             :  * Get info about constraints on a domain.
    8000             :  */
    8001             : static void
    8002         272 : getDomainConstraints(Archive *fout, TypeInfo *tyinfo)
    8003             : {
    8004             :     int         i;
    8005             :     ConstraintInfo *constrinfo;
    8006         272 :     PQExpBuffer query = createPQExpBuffer();
    8007             :     PGresult   *res;
    8008             :     int         i_tableoid,
    8009             :                 i_oid,
    8010             :                 i_conname,
    8011             :                 i_consrc;
    8012             :     int         ntups;
    8013             : 
    8014         272 :     if (!fout->is_prepared[PREPQUERY_GETDOMAINCONSTRAINTS])
    8015             :     {
    8016             :         /* Set up query for constraint-specific details */
    8017          82 :         appendPQExpBufferStr(query,
    8018             :                              "PREPARE getDomainConstraints(pg_catalog.oid) AS\n"
    8019             :                              "SELECT tableoid, oid, conname, "
    8020             :                              "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
    8021             :                              "convalidated "
    8022             :                              "FROM pg_catalog.pg_constraint "
    8023             :                              "WHERE contypid = $1 AND contype = 'c' "
    8024             :                              "ORDER BY conname");
    8025             : 
    8026          82 :         ExecuteSqlStatement(fout, query->data);
    8027             : 
    8028          82 :         fout->is_prepared[PREPQUERY_GETDOMAINCONSTRAINTS] = true;
    8029             :     }
    8030             : 
    8031         272 :     printfPQExpBuffer(query,
    8032             :                       "EXECUTE getDomainConstraints('%u')",
    8033             :                       tyinfo->dobj.catId.oid);
    8034             : 
    8035         272 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    8036             : 
    8037         272 :     ntups = PQntuples(res);
    8038             : 
    8039         272 :     i_tableoid = PQfnumber(res, "tableoid");
    8040         272 :     i_oid = PQfnumber(res, "oid");
    8041         272 :     i_conname = PQfnumber(res, "conname");
    8042         272 :     i_consrc = PQfnumber(res, "consrc");
    8043             : 
    8044         272 :     constrinfo = (ConstraintInfo *) pg_malloc(ntups * sizeof(ConstraintInfo));
    8045             : 
    8046         272 :     tyinfo->nDomChecks = ntups;
    8047         272 :     tyinfo->domChecks = constrinfo;
    8048             : 
    8049         454 :     for (i = 0; i < ntups; i++)
    8050             :     {
    8051         182 :         bool        validated = PQgetvalue(res, i, 4)[0] == 't';
    8052             : 
    8053         182 :         constrinfo[i].dobj.objType = DO_CONSTRAINT;
    8054         182 :         constrinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    8055         182 :         constrinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    8056         182 :         AssignDumpId(&constrinfo[i].dobj);
    8057         182 :         constrinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_conname));
    8058         182 :         constrinfo[i].dobj.namespace = tyinfo->dobj.namespace;
    8059         182 :         constrinfo[i].contable = NULL;
    8060         182 :         constrinfo[i].condomain = tyinfo;
    8061         182 :         constrinfo[i].contype = 'c';
    8062         182 :         constrinfo[i].condef = pg_strdup(PQgetvalue(res, i, i_consrc));
    8063         182 :         constrinfo[i].confrelid = InvalidOid;
    8064         182 :         constrinfo[i].conindex = 0;
    8065         182 :         constrinfo[i].condeferrable = false;
    8066         182 :         constrinfo[i].condeferred = false;
    8067         182 :         constrinfo[i].conislocal = true;
    8068             : 
    8069         182 :         constrinfo[i].separate = !validated;
    8070             : 
    8071             :         /*
    8072             :          * Make the domain depend on the constraint, ensuring it won't be
    8073             :          * output till any constraint dependencies are OK.  If the constraint
    8074             :          * has not been validated, it's going to be dumped after the domain
    8075             :          * anyway, so this doesn't matter.
    8076             :          */
    8077         182 :         if (validated)
    8078         182 :             addObjectDependency(&tyinfo->dobj,
    8079         182 :                                 constrinfo[i].dobj.dumpId);
    8080             :     }
    8081             : 
    8082         272 :     PQclear(res);
    8083             : 
    8084         272 :     destroyPQExpBuffer(query);
    8085         272 : }
    8086             : 
    8087             : /*
    8088             :  * getRules
    8089             :  *    get basic information about every rule in the system
    8090             :  */
    8091             : void
    8092         308 : getRules(Archive *fout)
    8093             : {
    8094             :     PGresult   *res;
    8095             :     int         ntups;
    8096             :     int         i;
    8097         308 :     PQExpBuffer query = createPQExpBuffer();
    8098             :     RuleInfo   *ruleinfo;
    8099             :     int         i_tableoid;
    8100             :     int         i_oid;
    8101             :     int         i_rulename;
    8102             :     int         i_ruletable;
    8103             :     int         i_ev_type;
    8104             :     int         i_is_instead;
    8105             :     int         i_ev_enabled;
    8106             : 
    8107         308 :     appendPQExpBufferStr(query, "SELECT "
    8108             :                          "tableoid, oid, rulename, "
    8109             :                          "ev_class AS ruletable, ev_type, is_instead, "
    8110             :                          "ev_enabled "
    8111             :                          "FROM pg_rewrite "
    8112             :                          "ORDER BY oid");
    8113             : 
    8114         308 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    8115             : 
    8116         308 :     ntups = PQntuples(res);
    8117             : 
    8118         308 :     ruleinfo = (RuleInfo *) pg_malloc(ntups * sizeof(RuleInfo));
    8119             : 
    8120         308 :     i_tableoid = PQfnumber(res, "tableoid");
    8121         308 :     i_oid = PQfnumber(res, "oid");
    8122         308 :     i_rulename = PQfnumber(res, "rulename");
    8123         308 :     i_ruletable = PQfnumber(res, "ruletable");
    8124         308 :     i_ev_type = PQfnumber(res, "ev_type");
    8125         308 :     i_is_instead = PQfnumber(res, "is_instead");
    8126         308 :     i_ev_enabled = PQfnumber(res, "ev_enabled");
    8127             : 
    8128       47158 :     for (i = 0; i < ntups; i++)
    8129             :     {
    8130             :         Oid         ruletableoid;
    8131             : 
    8132       46850 :         ruleinfo[i].dobj.objType = DO_RULE;
    8133       46850 :         ruleinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    8134       46850 :         ruleinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    8135       46850 :         AssignDumpId(&ruleinfo[i].dobj);
    8136       46850 :         ruleinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_rulename));
    8137       46850 :         ruletableoid = atooid(PQgetvalue(res, i, i_ruletable));
    8138       46850 :         ruleinfo[i].ruletable = findTableByOid(ruletableoid);
    8139       46850 :         if (ruleinfo[i].ruletable == NULL)
    8140           0 :             pg_fatal("failed sanity check, parent table with OID %u of pg_rewrite entry with OID %u not found",
    8141             :                      ruletableoid, ruleinfo[i].dobj.catId.oid);
    8142       46850 :         ruleinfo[i].dobj.namespace = ruleinfo[i].ruletable->dobj.namespace;
    8143       46850 :         ruleinfo[i].dobj.dump = ruleinfo[i].ruletable->dobj.dump;
    8144       46850 :         ruleinfo[i].ev_type = *(PQgetvalue(res, i, i_ev_type));
    8145       46850 :         ruleinfo[i].is_instead = *(PQgetvalue(res, i, i_is_instead)) == 't';
    8146       46850 :         ruleinfo[i].ev_enabled = *(PQgetvalue(res, i, i_ev_enabled));
    8147       46850 :         if (ruleinfo[i].ruletable)
    8148             :         {
    8149             :             /*
    8150             :              * If the table is a view or materialized view, force its ON
    8151             :              * SELECT rule to be sorted before the view itself --- this
    8152             :              * ensures that any dependencies for the rule affect the table's
    8153             :              * positioning. Other rules are forced to appear after their
    8154             :              * table.
    8155             :              */
    8156       46850 :             if ((ruleinfo[i].ruletable->relkind == RELKIND_VIEW ||
    8157        1348 :                  ruleinfo[i].ruletable->relkind == RELKIND_MATVIEW) &&
    8158       46388 :                 ruleinfo[i].ev_type == '1' && ruleinfo[i].is_instead)
    8159             :             {
    8160       45688 :                 addObjectDependency(&ruleinfo[i].ruletable->dobj,
    8161       45688 :                                     ruleinfo[i].dobj.dumpId);
    8162             :                 /* We'll merge the rule into CREATE VIEW, if possible */
    8163       45688 :                 ruleinfo[i].separate = false;
    8164             :             }
    8165             :             else
    8166             :             {
    8167        1162 :                 addObjectDependency(&ruleinfo[i].dobj,
    8168        1162 :                                     ruleinfo[i].ruletable->dobj.dumpId);
    8169        1162 :                 ruleinfo[i].separate = true;
    8170             :             }
    8171             :         }
    8172             :         else
    8173           0 :             ruleinfo[i].separate = true;
    8174             :     }
    8175             : 
    8176         308 :     PQclear(res);
    8177             : 
    8178         308 :     destroyPQExpBuffer(query);
    8179         308 : }
    8180             : 
    8181             : /*
    8182             :  * getTriggers
    8183             :  *    get information about every trigger on a dumpable table
    8184             :  *
    8185             :  * Note: trigger data is not returned directly to the caller, but it
    8186             :  * does get entered into the DumpableObject tables.
    8187             :  */
    8188             : void
    8189         308 : getTriggers(Archive *fout, TableInfo tblinfo[], int numTables)
    8190             : {
    8191         308 :     PQExpBuffer query = createPQExpBuffer();
    8192         308 :     PQExpBuffer tbloids = createPQExpBuffer();
    8193             :     PGresult   *res;
    8194             :     int         ntups;
    8195             :     int         curtblindx;
    8196             :     TriggerInfo *tginfo;
    8197             :     int         i_tableoid,
    8198             :                 i_oid,
    8199             :                 i_tgrelid,
    8200             :                 i_tgname,
    8201             :                 i_tgenabled,
    8202             :                 i_tgispartition,
    8203             :                 i_tgdef;
    8204             : 
    8205             :     /*
    8206             :      * We want to perform just one query against pg_trigger.  However, we
    8207             :      * mustn't try to select every row of the catalog and then sort it out on
    8208             :      * the client side, because some of the server-side functions we need
    8209             :      * would be unsafe to apply to tables we don't have lock on.  Hence, we
    8210             :      * build an array of the OIDs of tables we care about (and now have lock
    8211             :      * on!), and use a WHERE clause to constrain which rows are selected.
    8212             :      */
    8213         308 :     appendPQExpBufferChar(tbloids, '{');
    8214       81230 :     for (int i = 0; i < numTables; i++)
    8215             :     {
    8216       80922 :         TableInfo  *tbinfo = &tblinfo[i];
    8217             : 
    8218       80922 :         if (!tbinfo->hastriggers ||
    8219        2182 :             !(tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
    8220       79260 :             continue;
    8221             : 
    8222             :         /* OK, we need info for this table */
    8223        1662 :         if (tbloids->len > 1) /* do we have more than the '{'? */
    8224        1564 :             appendPQExpBufferChar(tbloids, ',');
    8225        1662 :         appendPQExpBuffer(tbloids, "%u", tbinfo->dobj.catId.oid);
    8226             :     }
    8227         308 :     appendPQExpBufferChar(tbloids, '}');
    8228             : 
    8229         308 :     if (fout->remoteVersion >= 150000)
    8230             :     {
    8231             :         /*
    8232             :          * NB: think not to use pretty=true in pg_get_triggerdef.  It could
    8233             :          * result in non-forward-compatible dumps of WHEN clauses due to
    8234             :          * under-parenthesization.
    8235             :          *
    8236             :          * NB: We need to see partition triggers in case the tgenabled flag
    8237             :          * has been changed from the parent.
    8238             :          */
    8239         308 :         appendPQExpBuffer(query,
    8240             :                           "SELECT t.tgrelid, t.tgname, "
    8241             :                           "pg_catalog.pg_get_triggerdef(t.oid, false) AS tgdef, "
    8242             :                           "t.tgenabled, t.tableoid, t.oid, "
    8243             :                           "t.tgparentid <> 0 AS tgispartition\n"
    8244             :                           "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
    8245             :                           "JOIN pg_catalog.pg_trigger t ON (src.tbloid = t.tgrelid) "
    8246             :                           "LEFT JOIN pg_catalog.pg_trigger u ON (u.oid = t.tgparentid) "
    8247             :                           "WHERE ((NOT t.tgisinternal AND t.tgparentid = 0) "
    8248             :                           "OR t.tgenabled != u.tgenabled) "
    8249             :                           "ORDER BY t.tgrelid, t.tgname",
    8250             :                           tbloids->data);
    8251             :     }
    8252           0 :     else if (fout->remoteVersion >= 130000)
    8253             :     {
    8254             :         /*
    8255             :          * NB: think not to use pretty=true in pg_get_triggerdef.  It could
    8256             :          * result in non-forward-compatible dumps of WHEN clauses due to
    8257             :          * under-parenthesization.
    8258             :          *
    8259             :          * NB: We need to see tgisinternal triggers in partitions, in case the
    8260             :          * tgenabled flag has been changed from the parent.
    8261             :          */
    8262           0 :         appendPQExpBuffer(query,
    8263             :                           "SELECT t.tgrelid, t.tgname, "
    8264             :                           "pg_catalog.pg_get_triggerdef(t.oid, false) AS tgdef, "
    8265             :                           "t.tgenabled, t.tableoid, t.oid, t.tgisinternal as tgispartition\n"
    8266             :                           "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
    8267             :                           "JOIN pg_catalog.pg_trigger t ON (src.tbloid = t.tgrelid) "
    8268             :                           "LEFT JOIN pg_catalog.pg_trigger u ON (u.oid = t.tgparentid) "
    8269             :                           "WHERE (NOT t.tgisinternal OR t.tgenabled != u.tgenabled) "
    8270             :                           "ORDER BY t.tgrelid, t.tgname",
    8271             :                           tbloids->data);
    8272             :     }
    8273           0 :     else if (fout->remoteVersion >= 110000)
    8274             :     {
    8275             :         /*
    8276             :          * NB: We need to see tgisinternal triggers in partitions, in case the
    8277             :          * tgenabled flag has been changed from the parent. No tgparentid in
    8278             :          * version 11-12, so we have to match them via pg_depend.
    8279             :          *
    8280             :          * See above about pretty=true in pg_get_triggerdef.
    8281             :          */
    8282           0 :         appendPQExpBuffer(query,
    8283             :                           "SELECT t.tgrelid, t.tgname, "
    8284             :                           "pg_catalog.pg_get_triggerdef(t.oid, false) AS tgdef, "
    8285             :                           "t.tgenabled, t.tableoid, t.oid, t.tgisinternal as tgispartition "
    8286             :                           "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
    8287             :                           "JOIN pg_catalog.pg_trigger t ON (src.tbloid = t.tgrelid) "
    8288             :                           "LEFT JOIN pg_catalog.pg_depend AS d ON "
    8289             :                           " d.classid = 'pg_catalog.pg_trigger'::pg_catalog.regclass AND "
    8290             :                           " d.refclassid = 'pg_catalog.pg_trigger'::pg_catalog.regclass AND "
    8291             :                           " d.objid = t.oid "
    8292             :                           "LEFT JOIN pg_catalog.pg_trigger AS pt ON pt.oid = refobjid "
    8293             :                           "WHERE (NOT t.tgisinternal OR t.tgenabled != pt.tgenabled) "
    8294             :                           "ORDER BY t.tgrelid, t.tgname",
    8295             :                           tbloids->data);
    8296             :     }
    8297             :     else
    8298             :     {
    8299             :         /* See above about pretty=true in pg_get_triggerdef */
    8300           0 :         appendPQExpBuffer(query,
    8301             :                           "SELECT t.tgrelid, t.tgname, "
    8302             :                           "pg_catalog.pg_get_triggerdef(t.oid, false) AS tgdef, "
    8303             :                           "t.tgenabled, false as tgispartition, "
    8304             :                           "t.tableoid, t.oid "
    8305             :                           "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
    8306             :                           "JOIN pg_catalog.pg_trigger t ON (src.tbloid = t.tgrelid) "
    8307             :                           "WHERE NOT tgisinternal "
    8308             :                           "ORDER BY t.tgrelid, t.tgname",
    8309             :                           tbloids->data);
    8310             :     }
    8311             : 
    8312         308 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    8313             : 
    8314         308 :     ntups = PQntuples(res);
    8315             : 
    8316         308 :     i_tableoid = PQfnumber(res, "tableoid");
    8317         308 :     i_oid = PQfnumber(res, "oid");
    8318         308 :     i_tgrelid = PQfnumber(res, "tgrelid");
    8319         308 :     i_tgname = PQfnumber(res, "tgname");
    8320         308 :     i_tgenabled = PQfnumber(res, "tgenabled");
    8321         308 :     i_tgispartition = PQfnumber(res, "tgispartition");
    8322         308 :     i_tgdef = PQfnumber(res, "tgdef");
    8323             : 
    8324         308 :     tginfo = (TriggerInfo *) pg_malloc(ntups * sizeof(TriggerInfo));
    8325             : 
    8326             :     /*
    8327             :      * Outer loop iterates once per table, not once per row.  Incrementing of
    8328             :      * j is handled by the inner loop.
    8329             :      */
    8330         308 :     curtblindx = -1;
    8331         890 :     for (int j = 0; j < ntups;)
    8332             :     {
    8333         582 :         Oid         tgrelid = atooid(PQgetvalue(res, j, i_tgrelid));
    8334         582 :         TableInfo  *tbinfo = NULL;
    8335             :         int         numtrigs;
    8336             : 
    8337             :         /* Count rows for this table */
    8338         986 :         for (numtrigs = 1; numtrigs < ntups - j; numtrigs++)
    8339         888 :             if (atooid(PQgetvalue(res, j + numtrigs, i_tgrelid)) != tgrelid)
    8340         484 :                 break;
    8341             : 
    8342             :         /*
    8343             :          * Locate the associated TableInfo; we rely on tblinfo[] being in OID
    8344             :          * order.
    8345             :          */
    8346       30046 :         while (++curtblindx < numTables)
    8347             :         {
    8348       30046 :             tbinfo = &tblinfo[curtblindx];
    8349       30046 :             if (tbinfo->dobj.catId.oid == tgrelid)
    8350         582 :                 break;
    8351             :         }
    8352         582 :         if (curtblindx >= numTables)
    8353           0 :             pg_fatal("unrecognized table OID %u", tgrelid);
    8354             : 
    8355             :         /* Save data for this table */
    8356         582 :         tbinfo->triggers = tginfo + j;
    8357         582 :         tbinfo->numTriggers = numtrigs;
    8358             : 
    8359        1568 :         for (int c = 0; c < numtrigs; c++, j++)
    8360             :         {
    8361         986 :             tginfo[j].dobj.objType = DO_TRIGGER;
    8362         986 :             tginfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
    8363         986 :             tginfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
    8364         986 :             AssignDumpId(&tginfo[j].dobj);
    8365         986 :             tginfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_tgname));
    8366         986 :             tginfo[j].dobj.namespace = tbinfo->dobj.namespace;
    8367         986 :             tginfo[j].tgtable = tbinfo;
    8368         986 :             tginfo[j].tgenabled = *(PQgetvalue(res, j, i_tgenabled));
    8369         986 :             tginfo[j].tgispartition = *(PQgetvalue(res, j, i_tgispartition)) == 't';
    8370         986 :             tginfo[j].tgdef = pg_strdup(PQgetvalue(res, j, i_tgdef));
    8371             :         }
    8372             :     }
    8373             : 
    8374         308 :     PQclear(res);
    8375             : 
    8376         308 :     destroyPQExpBuffer(query);
    8377         308 :     destroyPQExpBuffer(tbloids);
    8378         308 : }
    8379             : 
    8380             : /*
    8381             :  * getEventTriggers
    8382             :  *    get information about event triggers
    8383             :  */
    8384             : void
    8385         308 : getEventTriggers(Archive *fout)
    8386             : {
    8387             :     int         i;
    8388             :     PQExpBuffer query;
    8389             :     PGresult   *res;
    8390             :     EventTriggerInfo *evtinfo;
    8391             :     int         i_tableoid,
    8392             :                 i_oid,
    8393             :                 i_evtname,
    8394             :                 i_evtevent,
    8395             :                 i_evtowner,
    8396             :                 i_evttags,
    8397             :                 i_evtfname,
    8398             :                 i_evtenabled;
    8399             :     int         ntups;
    8400             : 
    8401             :     /* Before 9.3, there are no event triggers */
    8402         308 :     if (fout->remoteVersion < 90300)
    8403           0 :         return;
    8404             : 
    8405         308 :     query = createPQExpBuffer();
    8406             : 
    8407         308 :     appendPQExpBufferStr(query,
    8408             :                          "SELECT e.tableoid, e.oid, evtname, evtenabled, "
    8409             :                          "evtevent, evtowner, "
    8410             :                          "array_to_string(array("
    8411             :                          "select quote_literal(x) "
    8412             :                          " from unnest(evttags) as t(x)), ', ') as evttags, "
    8413             :                          "e.evtfoid::regproc as evtfname "
    8414             :                          "FROM pg_event_trigger e "
    8415             :                          "ORDER BY e.oid");
    8416             : 
    8417         308 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    8418             : 
    8419         308 :     ntups = PQntuples(res);
    8420             : 
    8421         308 :     evtinfo = (EventTriggerInfo *) pg_malloc(ntups * sizeof(EventTriggerInfo));
    8422             : 
    8423         308 :     i_tableoid = PQfnumber(res, "tableoid");
    8424         308 :     i_oid = PQfnumber(res, "oid");
    8425         308 :     i_evtname = PQfnumber(res, "evtname");
    8426         308 :     i_evtevent = PQfnumber(res, "evtevent");
    8427         308 :     i_evtowner = PQfnumber(res, "evtowner");
    8428         308 :     i_evttags = PQfnumber(res, "evttags");
    8429         308 :     i_evtfname = PQfnumber(res, "evtfname");
    8430         308 :     i_evtenabled = PQfnumber(res, "evtenabled");
    8431             : 
    8432         408 :     for (i = 0; i < ntups; i++)
    8433             :     {
    8434         100 :         evtinfo[i].dobj.objType = DO_EVENT_TRIGGER;
    8435         100 :         evtinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    8436         100 :         evtinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    8437         100 :         AssignDumpId(&evtinfo[i].dobj);
    8438         100 :         evtinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_evtname));
    8439         100 :         evtinfo[i].evtname = pg_strdup(PQgetvalue(res, i, i_evtname));
    8440         100 :         evtinfo[i].evtevent = pg_strdup(PQgetvalue(res, i, i_evtevent));
    8441         100 :         evtinfo[i].evtowner = getRoleName(PQgetvalue(res, i, i_evtowner));
    8442         100 :         evtinfo[i].evttags = pg_strdup(PQgetvalue(res, i, i_evttags));
    8443         100 :         evtinfo[i].evtfname = pg_strdup(PQgetvalue(res, i, i_evtfname));
    8444         100 :         evtinfo[i].evtenabled = *(PQgetvalue(res, i, i_evtenabled));
    8445             : 
    8446             :         /* Decide whether we want to dump it */
    8447         100 :         selectDumpableObject(&(evtinfo[i].dobj), fout);
    8448             :     }
    8449             : 
    8450         308 :     PQclear(res);
    8451             : 
    8452         308 :     destroyPQExpBuffer(query);
    8453             : }
    8454             : 
    8455             : /*
    8456             :  * getProcLangs
    8457             :  *    get basic information about every procedural language in the system
    8458             :  *
    8459             :  * NB: this must run after getFuncs() because we assume we can do
    8460             :  * findFuncByOid().
    8461             :  */
    8462             : void
    8463         308 : getProcLangs(Archive *fout)
    8464             : {
    8465             :     PGresult   *res;
    8466             :     int         ntups;
    8467             :     int         i;
    8468         308 :     PQExpBuffer query = createPQExpBuffer();
    8469             :     ProcLangInfo *planginfo;
    8470             :     int         i_tableoid;
    8471             :     int         i_oid;
    8472             :     int         i_lanname;
    8473             :     int         i_lanpltrusted;
    8474             :     int         i_lanplcallfoid;
    8475             :     int         i_laninline;
    8476             :     int         i_lanvalidator;
    8477             :     int         i_lanacl;
    8478             :     int         i_acldefault;
    8479             :     int         i_lanowner;
    8480             : 
    8481         308 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, "
    8482             :                          "lanname, lanpltrusted, lanplcallfoid, "
    8483             :                          "laninline, lanvalidator, "
    8484             :                          "lanacl, "
    8485             :                          "acldefault('l', lanowner) AS acldefault, "
    8486             :                          "lanowner "
    8487             :                          "FROM pg_language "
    8488             :                          "WHERE lanispl "
    8489             :                          "ORDER BY oid");
    8490             : 
    8491         308 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    8492             : 
    8493         308 :     ntups = PQntuples(res);
    8494             : 
    8495         308 :     planginfo = (ProcLangInfo *) pg_malloc(ntups * sizeof(ProcLangInfo));
    8496             : 
    8497         308 :     i_tableoid = PQfnumber(res, "tableoid");
    8498         308 :     i_oid = PQfnumber(res, "oid");
    8499         308 :     i_lanname = PQfnumber(res, "lanname");
    8500         308 :     i_lanpltrusted = PQfnumber(res, "lanpltrusted");
    8501         308 :     i_lanplcallfoid = PQfnumber(res, "lanplcallfoid");
    8502         308 :     i_laninline = PQfnumber(res, "laninline");
    8503         308 :     i_lanvalidator = PQfnumber(res, "lanvalidator");
    8504         308 :     i_lanacl = PQfnumber(res, "lanacl");
    8505         308 :     i_acldefault = PQfnumber(res, "acldefault");
    8506         308 :     i_lanowner = PQfnumber(res, "lanowner");
    8507             : 
    8508         702 :     for (i = 0; i < ntups; i++)
    8509             :     {
    8510         394 :         planginfo[i].dobj.objType = DO_PROCLANG;
    8511         394 :         planginfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    8512         394 :         planginfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    8513         394 :         AssignDumpId(&planginfo[i].dobj);
    8514             : 
    8515         394 :         planginfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_lanname));
    8516         394 :         planginfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_lanacl));
    8517         394 :         planginfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
    8518         394 :         planginfo[i].dacl.privtype = 0;
    8519         394 :         planginfo[i].dacl.initprivs = NULL;
    8520         394 :         planginfo[i].lanpltrusted = *(PQgetvalue(res, i, i_lanpltrusted)) == 't';
    8521         394 :         planginfo[i].lanplcallfoid = atooid(PQgetvalue(res, i, i_lanplcallfoid));
    8522         394 :         planginfo[i].laninline = atooid(PQgetvalue(res, i, i_laninline));
    8523         394 :         planginfo[i].lanvalidator = atooid(PQgetvalue(res, i, i_lanvalidator));
    8524         394 :         planginfo[i].lanowner = getRoleName(PQgetvalue(res, i, i_lanowner));
    8525             : 
    8526             :         /* Decide whether we want to dump it */
    8527         394 :         selectDumpableProcLang(&(planginfo[i]), fout);
    8528             : 
    8529             :         /* Mark whether language has an ACL */
    8530         394 :         if (!PQgetisnull(res, i, i_lanacl))
    8531          86 :             planginfo[i].dobj.components |= DUMP_COMPONENT_ACL;
    8532             :     }
    8533             : 
    8534         308 :     PQclear(res);
    8535             : 
    8536         308 :     destroyPQExpBuffer(query);
    8537         308 : }
    8538             : 
    8539             : /*
    8540             :  * getCasts
    8541             :  *    get basic information about most casts in the system
    8542             :  *
    8543             :  * Skip casts from a range to its multirange, since we'll create those
    8544             :  * automatically.
    8545             :  */
    8546             : void
    8547         308 : getCasts(Archive *fout)
    8548             : {
    8549             :     PGresult   *res;
    8550             :     int         ntups;
    8551             :     int         i;
    8552         308 :     PQExpBuffer query = createPQExpBuffer();
    8553             :     CastInfo   *castinfo;
    8554             :     int         i_tableoid;
    8555             :     int         i_oid;
    8556             :     int         i_castsource;
    8557             :     int         i_casttarget;
    8558             :     int         i_castfunc;
    8559             :     int         i_castcontext;
    8560             :     int         i_castmethod;
    8561             : 
    8562         308 :     if (fout->remoteVersion >= 140000)
    8563             :     {
    8564         308 :         appendPQExpBufferStr(query, "SELECT tableoid, oid, "
    8565             :                              "castsource, casttarget, castfunc, castcontext, "
    8566             :                              "castmethod "
    8567             :                              "FROM pg_cast c "
    8568             :                              "WHERE NOT EXISTS ( "
    8569             :                              "SELECT 1 FROM pg_range r "
    8570             :                              "WHERE c.castsource = r.rngtypid "
    8571             :                              "AND c.casttarget = r.rngmultitypid "
    8572             :                              ") "
    8573             :                              "ORDER BY 3,4");
    8574             :     }
    8575             :     else
    8576             :     {
    8577           0 :         appendPQExpBufferStr(query, "SELECT tableoid, oid, "
    8578             :                              "castsource, casttarget, castfunc, castcontext, "
    8579             :                              "castmethod "
    8580             :                              "FROM pg_cast ORDER BY 3,4");
    8581             :     }
    8582             : 
    8583         308 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    8584             : 
    8585         308 :     ntups = PQntuples(res);
    8586             : 
    8587         308 :     castinfo = (CastInfo *) pg_malloc(ntups * sizeof(CastInfo));
    8588             : 
    8589         308 :     i_tableoid = PQfnumber(res, "tableoid");
    8590         308 :     i_oid = PQfnumber(res, "oid");
    8591         308 :     i_castsource = PQfnumber(res, "castsource");
    8592         308 :     i_casttarget = PQfnumber(res, "casttarget");
    8593         308 :     i_castfunc = PQfnumber(res, "castfunc");
    8594         308 :     i_castcontext = PQfnumber(res, "castcontext");
    8595         308 :     i_castmethod = PQfnumber(res, "castmethod");
    8596             : 
    8597       69162 :     for (i = 0; i < ntups; i++)
    8598             :     {
    8599             :         PQExpBufferData namebuf;
    8600             :         TypeInfo   *sTypeInfo;
    8601             :         TypeInfo   *tTypeInfo;
    8602             : 
    8603       68854 :         castinfo[i].dobj.objType = DO_CAST;
    8604       68854 :         castinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    8605       68854 :         castinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    8606       68854 :         AssignDumpId(&castinfo[i].dobj);
    8607       68854 :         castinfo[i].castsource = atooid(PQgetvalue(res, i, i_castsource));
    8608       68854 :         castinfo[i].casttarget = atooid(PQgetvalue(res, i, i_casttarget));
    8609       68854 :         castinfo[i].castfunc = atooid(PQgetvalue(res, i, i_castfunc));
    8610       68854 :         castinfo[i].castcontext = *(PQgetvalue(res, i, i_castcontext));
    8611       68854 :         castinfo[i].castmethod = *(PQgetvalue(res, i, i_castmethod));
    8612             : 
    8613             :         /*
    8614             :          * Try to name cast as concatenation of typnames.  This is only used
    8615             :          * for purposes of sorting.  If we fail to find either type, the name
    8616             :          * will be an empty string.
    8617             :          */
    8618       68854 :         initPQExpBuffer(&namebuf);
    8619       68854 :         sTypeInfo = findTypeByOid(castinfo[i].castsource);
    8620       68854 :         tTypeInfo = findTypeByOid(castinfo[i].casttarget);
    8621       68854 :         if (sTypeInfo && tTypeInfo)
    8622       68854 :             appendPQExpBuffer(&namebuf, "%s %s",
    8623             :                               sTypeInfo->dobj.name, tTypeInfo->dobj.name);
    8624       68854 :         castinfo[i].dobj.name = namebuf.data;
    8625             : 
    8626             :         /* Decide whether we want to dump it */
    8627       68854 :         selectDumpableCast(&(castinfo[i]), fout);
    8628             :     }
    8629             : 
    8630         308 :     PQclear(res);
    8631             : 
    8632         308 :     destroyPQExpBuffer(query);
    8633         308 : }
    8634             : 
    8635             : static char *
    8636         174 : get_language_name(Archive *fout, Oid langid)
    8637             : {
    8638             :     PQExpBuffer query;
    8639             :     PGresult   *res;
    8640             :     char       *lanname;
    8641             : 
    8642         174 :     query = createPQExpBuffer();
    8643         174 :     appendPQExpBuffer(query, "SELECT lanname FROM pg_language WHERE oid = %u", langid);
    8644         174 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
    8645         174 :     lanname = pg_strdup(fmtId(PQgetvalue(res, 0, 0)));
    8646         174 :     destroyPQExpBuffer(query);
    8647         174 :     PQclear(res);
    8648             : 
    8649         174 :     return lanname;
    8650             : }
    8651             : 
    8652             : /*
    8653             :  * getTransforms
    8654             :  *    get basic information about every transform in the system
    8655             :  */
    8656             : void
    8657         308 : getTransforms(Archive *fout)
    8658             : {
    8659             :     PGresult   *res;
    8660             :     int         ntups;
    8661             :     int         i;
    8662             :     PQExpBuffer query;
    8663             :     TransformInfo *transforminfo;
    8664             :     int         i_tableoid;
    8665             :     int         i_oid;
    8666             :     int         i_trftype;
    8667             :     int         i_trflang;
    8668             :     int         i_trffromsql;
    8669             :     int         i_trftosql;
    8670             : 
    8671             :     /* Transforms didn't exist pre-9.5 */
    8672         308 :     if (fout->remoteVersion < 90500)
    8673           0 :         return;
    8674             : 
    8675         308 :     query = createPQExpBuffer();
    8676             : 
    8677         308 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, "
    8678             :                          "trftype, trflang, trffromsql::oid, trftosql::oid "
    8679             :                          "FROM pg_transform "
    8680             :                          "ORDER BY 3,4");
    8681             : 
    8682         308 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    8683             : 
    8684         308 :     ntups = PQntuples(res);
    8685             : 
    8686         308 :     transforminfo = (TransformInfo *) pg_malloc(ntups * sizeof(TransformInfo));
    8687             : 
    8688         308 :     i_tableoid = PQfnumber(res, "tableoid");
    8689         308 :     i_oid = PQfnumber(res, "oid");
    8690         308 :     i_trftype = PQfnumber(res, "trftype");
    8691         308 :     i_trflang = PQfnumber(res, "trflang");
    8692         308 :     i_trffromsql = PQfnumber(res, "trffromsql");
    8693         308 :     i_trftosql = PQfnumber(res, "trftosql");
    8694             : 
    8695         408 :     for (i = 0; i < ntups; i++)
    8696             :     {
    8697             :         PQExpBufferData namebuf;
    8698             :         TypeInfo   *typeInfo;
    8699             :         char       *lanname;
    8700             : 
    8701         100 :         transforminfo[i].dobj.objType = DO_TRANSFORM;
    8702         100 :         transforminfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    8703         100 :         transforminfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    8704         100 :         AssignDumpId(&transforminfo[i].dobj);
    8705         100 :         transforminfo[i].trftype = atooid(PQgetvalue(res, i, i_trftype));
    8706         100 :         transforminfo[i].trflang = atooid(PQgetvalue(res, i, i_trflang));
    8707         100 :         transforminfo[i].trffromsql = atooid(PQgetvalue(res, i, i_trffromsql));
    8708         100 :         transforminfo[i].trftosql = atooid(PQgetvalue(res, i, i_trftosql));
    8709             : 
    8710             :         /*
    8711             :          * Try to name transform as concatenation of type and language name.
    8712             :          * This is only used for purposes of sorting.  If we fail to find
    8713             :          * either, the name will be an empty string.
    8714             :          */
    8715         100 :         initPQExpBuffer(&namebuf);
    8716         100 :         typeInfo = findTypeByOid(transforminfo[i].trftype);
    8717         100 :         lanname = get_language_name(fout, transforminfo[i].trflang);
    8718         100 :         if (typeInfo && lanname)
    8719         100 :             appendPQExpBuffer(&namebuf, "%s %s",
    8720             :                               typeInfo->dobj.name, lanname);
    8721         100 :         transforminfo[i].dobj.name = namebuf.data;
    8722         100 :         free(lanname);
    8723             : 
    8724             :         /* Decide whether we want to dump it */
    8725         100 :         selectDumpableObject(&(transforminfo[i].dobj), fout);
    8726             :     }
    8727             : 
    8728         308 :     PQclear(res);
    8729             : 
    8730         308 :     destroyPQExpBuffer(query);
    8731             : }
    8732             : 
    8733             : /*
    8734             :  * getTableAttrs -
    8735             :  *    for each interesting table, read info about its attributes
    8736             :  *    (names, types, default values, CHECK constraints, etc)
    8737             :  *
    8738             :  *  modifies tblinfo
    8739             :  */
    8740             : void
    8741         308 : getTableAttrs(Archive *fout, TableInfo *tblinfo, int numTables)
    8742             : {
    8743         308 :     DumpOptions *dopt = fout->dopt;
    8744         308 :     PQExpBuffer q = createPQExpBuffer();
    8745         308 :     PQExpBuffer tbloids = createPQExpBuffer();
    8746         308 :     PQExpBuffer checkoids = createPQExpBuffer();
    8747             :     PGresult   *res;
    8748             :     int         ntups;
    8749             :     int         curtblindx;
    8750             :     int         i_attrelid;
    8751             :     int         i_attnum;
    8752             :     int         i_attname;
    8753             :     int         i_atttypname;
    8754             :     int         i_attstattarget;
    8755             :     int         i_attstorage;
    8756             :     int         i_typstorage;
    8757             :     int         i_attidentity;
    8758             :     int         i_attgenerated;
    8759             :     int         i_attisdropped;
    8760             :     int         i_attlen;
    8761             :     int         i_attalign;
    8762             :     int         i_attislocal;
    8763             :     int         i_notnull_name;
    8764             :     int         i_notnull_noinherit;
    8765             :     int         i_notnull_islocal;
    8766             :     int         i_attoptions;
    8767             :     int         i_attcollation;
    8768             :     int         i_attcompression;
    8769             :     int         i_attfdwoptions;
    8770             :     int         i_attmissingval;
    8771             :     int         i_atthasdef;
    8772             : 
    8773             :     /*
    8774             :      * We want to perform just one query against pg_attribute, and then just
    8775             :      * one against pg_attrdef (for DEFAULTs) and two against pg_constraint
    8776             :      * (for CHECK constraints and for NOT NULL constraints).  However, we
    8777             :      * mustn't try to select every row of those catalogs and then sort it out
    8778             :      * on the client side, because some of the server-side functions we need
    8779             :      * would be unsafe to apply to tables we don't have lock on.  Hence, we
    8780             :      * build an array of the OIDs of tables we care about (and now have lock
    8781             :      * on!), and use a WHERE clause to constrain which rows are selected.
    8782             :      */
    8783         308 :     appendPQExpBufferChar(tbloids, '{');
    8784         308 :     appendPQExpBufferChar(checkoids, '{');
    8785       81230 :     for (int i = 0; i < numTables; i++)
    8786             :     {
    8787       80922 :         TableInfo  *tbinfo = &tblinfo[i];
    8788             : 
    8789             :         /* Don't bother to collect info for sequences */
    8790       80922 :         if (tbinfo->relkind == RELKIND_SEQUENCE)
    8791        1184 :             continue;
    8792             : 
    8793             :         /* Don't bother with uninteresting tables, either */
    8794       79738 :         if (!tbinfo->interesting)
    8795       68200 :             continue;
    8796             : 
    8797             :         /* OK, we need info for this table */
    8798       11538 :         if (tbloids->len > 1) /* do we have more than the '{'? */
    8799       11334 :             appendPQExpBufferChar(tbloids, ',');
    8800       11538 :         appendPQExpBuffer(tbloids, "%u", tbinfo->dobj.catId.oid);
    8801             : 
    8802       11538 :         if (tbinfo->ncheck > 0)
    8803             :         {
    8804             :             /* Also make a list of the ones with check constraints */
    8805         984 :             if (checkoids->len > 1) /* do we have more than the '{'? */
    8806         850 :                 appendPQExpBufferChar(checkoids, ',');
    8807         984 :             appendPQExpBuffer(checkoids, "%u", tbinfo->dobj.catId.oid);
    8808             :         }
    8809             :     }
    8810         308 :     appendPQExpBufferChar(tbloids, '}');
    8811         308 :     appendPQExpBufferChar(checkoids, '}');
    8812             : 
    8813             :     /*
    8814             :      * Find all the user attributes and their types.
    8815             :      *
    8816             :      * Since we only want to dump COLLATE clauses for attributes whose
    8817             :      * collation is different from their type's default, we use a CASE here to
    8818             :      * suppress uninteresting attcollations cheaply.
    8819             :      */
    8820         308 :     appendPQExpBufferStr(q,
    8821             :                          "SELECT\n"
    8822             :                          "a.attrelid,\n"
    8823             :                          "a.attnum,\n"
    8824             :                          "a.attname,\n"
    8825             :                          "a.attstattarget,\n"
    8826             :                          "a.attstorage,\n"
    8827             :                          "t.typstorage,\n"
    8828             :                          "a.atthasdef,\n"
    8829             :                          "a.attisdropped,\n"
    8830             :                          "a.attlen,\n"
    8831             :                          "a.attalign,\n"
    8832             :                          "a.attislocal,\n"
    8833             :                          "pg_catalog.format_type(t.oid, a.atttypmod) AS atttypname,\n"
    8834             :                          "array_to_string(a.attoptions, ', ') AS attoptions,\n"
    8835             :                          "CASE WHEN a.attcollation <> t.typcollation "
    8836             :                          "THEN a.attcollation ELSE 0 END AS attcollation,\n"
    8837             :                          "pg_catalog.array_to_string(ARRAY("
    8838             :                          "SELECT pg_catalog.quote_ident(option_name) || "
    8839             :                          "' ' || pg_catalog.quote_literal(option_value) "
    8840             :                          "FROM pg_catalog.pg_options_to_table(attfdwoptions) "
    8841             :                          "ORDER BY option_name"
    8842             :                          "), E',\n    ') AS attfdwoptions,\n");
    8843             : 
    8844             :     /*
    8845             :      * Find out any NOT NULL markings for each column.  In 18 and up we read
    8846             :      * pg_constraint to obtain the constraint name.  notnull_noinherit is set
    8847             :      * according to the NO INHERIT property.  For versions prior to 18, we
    8848             :      * store an empty string as the name when a constraint is marked as
    8849             :      * attnotnull (this cues dumpTableSchema to print the NOT NULL clause
    8850             :      * without a name); also, such cases are never NO INHERIT.
    8851             :      *
    8852             :      * We track in notnull_islocal whether the constraint was defined directly
    8853             :      * in this table or via an ancestor, for binary upgrade.  flagInhAttrs
    8854             :      * might modify this later for servers older than 18; it's also in charge
    8855             :      * of determining the correct inhcount.
    8856             :      */
    8857         308 :     if (fout->remoteVersion >= 180000)
    8858         308 :         appendPQExpBufferStr(q,
    8859             :                              "co.conname AS notnull_name,\n"
    8860             :                              "co.connoinherit AS notnull_noinherit,\n"
    8861             :                              "co.conislocal AS notnull_islocal,\n");
    8862             :     else
    8863           0 :         appendPQExpBufferStr(q,
    8864             :                              "CASE WHEN a.attnotnull THEN '' ELSE NULL END AS notnull_name,\n"
    8865             :                              "false AS notnull_noinherit,\n"
    8866             :                              "a.attislocal AS notnull_islocal,\n");
    8867             : 
    8868         308 :     if (fout->remoteVersion >= 140000)
    8869         308 :         appendPQExpBufferStr(q,
    8870             :                              "a.attcompression AS attcompression,\n");
    8871             :     else
    8872           0 :         appendPQExpBufferStr(q,
    8873             :                              "'' AS attcompression,\n");
    8874             : 
    8875         308 :     if (fout->remoteVersion >= 100000)
    8876         308 :         appendPQExpBufferStr(q,
    8877             :                              "a.attidentity,\n");
    8878             :     else
    8879           0 :         appendPQExpBufferStr(q,
    8880             :                              "'' AS attidentity,\n");
    8881             : 
    8882         308 :     if (fout->remoteVersion >= 110000)
    8883         308 :         appendPQExpBufferStr(q,
    8884             :                              "CASE WHEN a.atthasmissing AND NOT a.attisdropped "
    8885             :                              "THEN a.attmissingval ELSE null END AS attmissingval,\n");
    8886             :     else
    8887           0 :         appendPQExpBufferStr(q,
    8888             :                              "NULL AS attmissingval,\n");
    8889             : 
    8890         308 :     if (fout->remoteVersion >= 120000)
    8891         308 :         appendPQExpBufferStr(q,
    8892             :                              "a.attgenerated\n");
    8893             :     else
    8894           0 :         appendPQExpBufferStr(q,
    8895             :                              "'' AS attgenerated\n");
    8896             : 
    8897             :     /* need left join to pg_type to not fail on dropped columns ... */
    8898         308 :     appendPQExpBuffer(q,
    8899             :                       "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
    8900             :                       "JOIN pg_catalog.pg_attribute a ON (src.tbloid = a.attrelid) "
    8901             :                       "LEFT JOIN pg_catalog.pg_type t "
    8902             :                       "ON (a.atttypid = t.oid)\n",
    8903             :                       tbloids->data);
    8904             : 
    8905             :     /*
    8906             :      * In versions 18 and up, we need pg_constraint for explicit NOT NULL
    8907             :      * entries.  Also, we need to know if the NOT NULL for each column is
    8908             :      * backing a primary key.
    8909             :      */
    8910         308 :     if (fout->remoteVersion >= 180000)
    8911         308 :         appendPQExpBufferStr(q,
    8912             :                              " LEFT JOIN pg_catalog.pg_constraint co ON "
    8913             :                              "(a.attrelid = co.conrelid\n"
    8914             :                              "   AND co.contype = 'n' AND "
    8915             :                              "co.conkey = array[a.attnum])\n");
    8916             : 
    8917         308 :     appendPQExpBufferStr(q,
    8918             :                          "WHERE a.attnum > 0::pg_catalog.int2\n"
    8919             :                          "ORDER BY a.attrelid, a.attnum");
    8920             : 
    8921         308 :     res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
    8922             : 
    8923         308 :     ntups = PQntuples(res);
    8924             : 
    8925         308 :     i_attrelid = PQfnumber(res, "attrelid");
    8926         308 :     i_attnum = PQfnumber(res, "attnum");
    8927         308 :     i_attname = PQfnumber(res, "attname");
    8928         308 :     i_atttypname = PQfnumber(res, "atttypname");
    8929         308 :     i_attstattarget = PQfnumber(res, "attstattarget");
    8930         308 :     i_attstorage = PQfnumber(res, "attstorage");
    8931         308 :     i_typstorage = PQfnumber(res, "typstorage");
    8932         308 :     i_attidentity = PQfnumber(res, "attidentity");
    8933         308 :     i_attgenerated = PQfnumber(res, "attgenerated");
    8934         308 :     i_attisdropped = PQfnumber(res, "attisdropped");
    8935         308 :     i_attlen = PQfnumber(res, "attlen");
    8936         308 :     i_attalign = PQfnumber(res, "attalign");
    8937         308 :     i_attislocal = PQfnumber(res, "attislocal");
    8938         308 :     i_notnull_name = PQfnumber(res, "notnull_name");
    8939         308 :     i_notnull_noinherit = PQfnumber(res, "notnull_noinherit");
    8940         308 :     i_notnull_islocal = PQfnumber(res, "notnull_islocal");
    8941         308 :     i_attoptions = PQfnumber(res, "attoptions");
    8942         308 :     i_attcollation = PQfnumber(res, "attcollation");
    8943         308 :     i_attcompression = PQfnumber(res, "attcompression");
    8944         308 :     i_attfdwoptions = PQfnumber(res, "attfdwoptions");
    8945         308 :     i_attmissingval = PQfnumber(res, "attmissingval");
    8946         308 :     i_atthasdef = PQfnumber(res, "atthasdef");
    8947             : 
    8948             :     /* Within the next loop, we'll accumulate OIDs of tables with defaults */
    8949         308 :     resetPQExpBuffer(tbloids);
    8950         308 :     appendPQExpBufferChar(tbloids, '{');
    8951             : 
    8952             :     /*
    8953             :      * Outer loop iterates once per table, not once per row.  Incrementing of
    8954             :      * r is handled by the inner loop.
    8955             :      */
    8956         308 :     curtblindx = -1;
    8957       11582 :     for (int r = 0; r < ntups;)
    8958             :     {
    8959       11274 :         Oid         attrelid = atooid(PQgetvalue(res, r, i_attrelid));
    8960       11274 :         TableInfo  *tbinfo = NULL;
    8961             :         int         numatts;
    8962             :         bool        hasdefaults;
    8963             : 
    8964             :         /* Count rows for this table */
    8965       45178 :         for (numatts = 1; numatts < ntups - r; numatts++)
    8966       44980 :             if (atooid(PQgetvalue(res, r + numatts, i_attrelid)) != attrelid)
    8967       11076 :                 break;
    8968             : 
    8969             :         /*
    8970             :          * Locate the associated TableInfo; we rely on tblinfo[] being in OID
    8971             :          * order.
    8972             :          */
    8973       53766 :         while (++curtblindx < numTables)
    8974             :         {
    8975       53766 :             tbinfo = &tblinfo[curtblindx];
    8976       53766 :             if (tbinfo->dobj.catId.oid == attrelid)
    8977       11274 :                 break;
    8978             :         }
    8979       11274 :         if (curtblindx >= numTables)
    8980           0 :             pg_fatal("unrecognized table OID %u", attrelid);
    8981             :         /* cross-check that we only got requested tables */
    8982       11274 :         if (tbinfo->relkind == RELKIND_SEQUENCE ||
    8983       11274 :             !tbinfo->interesting)
    8984           0 :             pg_fatal("unexpected column data for table \"%s\"",
    8985             :                      tbinfo->dobj.name);
    8986             : 
    8987             :         /* Save data for this table */
    8988       11274 :         tbinfo->numatts = numatts;
    8989       11274 :         tbinfo->attnames = (char **) pg_malloc(numatts * sizeof(char *));
    8990       11274 :         tbinfo->atttypnames = (char **) pg_malloc(numatts * sizeof(char *));
    8991       11274 :         tbinfo->attstattarget = (int *) pg_malloc(numatts * sizeof(int));
    8992       11274 :         tbinfo->attstorage = (char *) pg_malloc(numatts * sizeof(char));
    8993       11274 :         tbinfo->typstorage = (char *) pg_malloc(numatts * sizeof(char));
    8994       11274 :         tbinfo->attidentity = (char *) pg_malloc(numatts * sizeof(char));
    8995       11274 :         tbinfo->attgenerated = (char *) pg_malloc(numatts * sizeof(char));
    8996       11274 :         tbinfo->attisdropped = (bool *) pg_malloc(numatts * sizeof(bool));
    8997       11274 :         tbinfo->attlen = (int *) pg_malloc(numatts * sizeof(int));
    8998       11274 :         tbinfo->attalign = (char *) pg_malloc(numatts * sizeof(char));
    8999       11274 :         tbinfo->attislocal = (bool *) pg_malloc(numatts * sizeof(bool));
    9000       11274 :         tbinfo->attoptions = (char **) pg_malloc(numatts * sizeof(char *));
    9001       11274 :         tbinfo->attcollation = (Oid *) pg_malloc(numatts * sizeof(Oid));
    9002       11274 :         tbinfo->attcompression = (char *) pg_malloc(numatts * sizeof(char));
    9003       11274 :         tbinfo->attfdwoptions = (char **) pg_malloc(numatts * sizeof(char *));
    9004       11274 :         tbinfo->attmissingval = (char **) pg_malloc(numatts * sizeof(char *));
    9005       11274 :         tbinfo->notnull_constrs = (char **) pg_malloc(numatts * sizeof(char *));
    9006       11274 :         tbinfo->notnull_noinh = (bool *) pg_malloc(numatts * sizeof(bool));
    9007       11274 :         tbinfo->notnull_islocal = (bool *) pg_malloc(numatts * sizeof(bool));
    9008       11274 :         tbinfo->attrdefs = (AttrDefInfo **) pg_malloc(numatts * sizeof(AttrDefInfo *));
    9009       11274 :         hasdefaults = false;
    9010             : 
    9011       56452 :         for (int j = 0; j < numatts; j++, r++)
    9012             :         {
    9013       45178 :             if (j + 1 != atoi(PQgetvalue(res, r, i_attnum)))
    9014           0 :                 pg_fatal("invalid column numbering in table \"%s\"",
    9015             :                          tbinfo->dobj.name);
    9016       45178 :             tbinfo->attnames[j] = pg_strdup(PQgetvalue(res, r, i_attname));
    9017       45178 :             tbinfo->atttypnames[j] = pg_strdup(PQgetvalue(res, r, i_atttypname));
    9018       45178 :             if (PQgetisnull(res, r, i_attstattarget))
    9019       45102 :                 tbinfo->attstattarget[j] = -1;
    9020             :             else
    9021          76 :                 tbinfo->attstattarget[j] = atoi(PQgetvalue(res, r, i_attstattarget));
    9022       45178 :             tbinfo->attstorage[j] = *(PQgetvalue(res, r, i_attstorage));
    9023       45178 :             tbinfo->typstorage[j] = *(PQgetvalue(res, r, i_typstorage));
    9024       45178 :             tbinfo->attidentity[j] = *(PQgetvalue(res, r, i_attidentity));
    9025       45178 :             tbinfo->attgenerated[j] = *(PQgetvalue(res, r, i_attgenerated));
    9026       45178 :             tbinfo->needs_override = tbinfo->needs_override || (tbinfo->attidentity[j] == ATTRIBUTE_IDENTITY_ALWAYS);
    9027       45178 :             tbinfo->attisdropped[j] = (PQgetvalue(res, r, i_attisdropped)[0] == 't');
    9028       45178 :             tbinfo->attlen[j] = atoi(PQgetvalue(res, r, i_attlen));
    9029       45178 :             tbinfo->attalign[j] = *(PQgetvalue(res, r, i_attalign));
    9030       45178 :             tbinfo->attislocal[j] = (PQgetvalue(res, r, i_attislocal)[0] == 't');
    9031             : 
    9032             :             /* Handle not-null constraint name and flags */
    9033       45178 :             determineNotNullFlags(fout, res, r,
    9034             :                                   tbinfo, j,
    9035             :                                   i_notnull_name, i_notnull_noinherit,
    9036             :                                   i_notnull_islocal);
    9037             : 
    9038       45178 :             tbinfo->attoptions[j] = pg_strdup(PQgetvalue(res, r, i_attoptions));
    9039       45178 :             tbinfo->attcollation[j] = atooid(PQgetvalue(res, r, i_attcollation));
    9040       45178 :             tbinfo->attcompression[j] = *(PQgetvalue(res, r, i_attcompression));
    9041       45178 :             tbinfo->attfdwoptions[j] = pg_strdup(PQgetvalue(res, r, i_attfdwoptions));
    9042       45178 :             tbinfo->attmissingval[j] = pg_strdup(PQgetvalue(res, r, i_attmissingval));
    9043       45178 :             tbinfo->attrdefs[j] = NULL; /* fix below */
    9044       45178 :             if (PQgetvalue(res, r, i_atthasdef)[0] == 't')
    9045        1726 :                 hasdefaults = true;
    9046             :         }
    9047             : 
    9048       11274 :         if (hasdefaults)
    9049             :         {
    9050             :             /* Collect OIDs of interesting tables that have defaults */
    9051        1430 :             if (tbloids->len > 1) /* do we have more than the '{'? */
    9052        1298 :                 appendPQExpBufferChar(tbloids, ',');
    9053        1430 :             appendPQExpBuffer(tbloids, "%u", tbinfo->dobj.catId.oid);
    9054             :         }
    9055             :     }
    9056             : 
    9057         308 :     PQclear(res);
    9058             : 
    9059             :     /*
    9060             :      * Now get info about column defaults.  This is skipped for a data-only
    9061             :      * dump, as it is only needed for table schemas.
    9062             :      */
    9063         308 :     if (dopt->dumpSchema && tbloids->len > 1)
    9064             :     {
    9065             :         AttrDefInfo *attrdefs;
    9066             :         int         numDefaults;
    9067         122 :         TableInfo  *tbinfo = NULL;
    9068             : 
    9069         122 :         pg_log_info("finding table default expressions");
    9070             : 
    9071         122 :         appendPQExpBufferChar(tbloids, '}');
    9072             : 
    9073         122 :         printfPQExpBuffer(q, "SELECT a.tableoid, a.oid, adrelid, adnum, "
    9074             :                           "pg_catalog.pg_get_expr(adbin, adrelid) AS adsrc\n"
    9075             :                           "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
    9076             :                           "JOIN pg_catalog.pg_attrdef a ON (src.tbloid = a.adrelid)\n"
    9077             :                           "ORDER BY a.adrelid, a.adnum",
    9078             :                           tbloids->data);
    9079             : 
    9080         122 :         res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
    9081             : 
    9082         122 :         numDefaults = PQntuples(res);
    9083         122 :         attrdefs = (AttrDefInfo *) pg_malloc(numDefaults * sizeof(AttrDefInfo));
    9084             : 
    9085         122 :         curtblindx = -1;
    9086        1766 :         for (int j = 0; j < numDefaults; j++)
    9087             :         {
    9088        1644 :             Oid         adtableoid = atooid(PQgetvalue(res, j, 0));
    9089        1644 :             Oid         adoid = atooid(PQgetvalue(res, j, 1));
    9090        1644 :             Oid         adrelid = atooid(PQgetvalue(res, j, 2));
    9091        1644 :             int         adnum = atoi(PQgetvalue(res, j, 3));
    9092        1644 :             char       *adsrc = PQgetvalue(res, j, 4);
    9093             : 
    9094             :             /*
    9095             :              * Locate the associated TableInfo; we rely on tblinfo[] being in
    9096             :              * OID order.
    9097             :              */
    9098        1644 :             if (tbinfo == NULL || tbinfo->dobj.catId.oid != adrelid)
    9099             :             {
    9100       36780 :                 while (++curtblindx < numTables)
    9101             :                 {
    9102       36780 :                     tbinfo = &tblinfo[curtblindx];
    9103       36780 :                     if (tbinfo->dobj.catId.oid == adrelid)
    9104        1360 :                         break;
    9105             :                 }
    9106        1360 :                 if (curtblindx >= numTables)
    9107           0 :                     pg_fatal("unrecognized table OID %u", adrelid);
    9108             :             }
    9109             : 
    9110        1644 :             if (adnum <= 0 || adnum > tbinfo->numatts)
    9111           0 :                 pg_fatal("invalid adnum value %d for table \"%s\"",
    9112             :                          adnum, tbinfo->dobj.name);
    9113             : 
    9114             :             /*
    9115             :              * dropped columns shouldn't have defaults, but just in case,
    9116             :              * ignore 'em
    9117             :              */
    9118        1644 :             if (tbinfo->attisdropped[adnum - 1])
    9119           0 :                 continue;
    9120             : 
    9121        1644 :             attrdefs[j].dobj.objType = DO_ATTRDEF;
    9122        1644 :             attrdefs[j].dobj.catId.tableoid = adtableoid;
    9123        1644 :             attrdefs[j].dobj.catId.oid = adoid;
    9124        1644 :             AssignDumpId(&attrdefs[j].dobj);
    9125        1644 :             attrdefs[j].adtable = tbinfo;
    9126        1644 :             attrdefs[j].adnum = adnum;
    9127        1644 :             attrdefs[j].adef_expr = pg_strdup(adsrc);
    9128             : 
    9129        1644 :             attrdefs[j].dobj.name = pg_strdup(tbinfo->dobj.name);
    9130        1644 :             attrdefs[j].dobj.namespace = tbinfo->dobj.namespace;
    9131             : 
    9132        1644 :             attrdefs[j].dobj.dump = tbinfo->dobj.dump;
    9133             : 
    9134             :             /*
    9135             :              * Figure out whether the default/generation expression should be
    9136             :              * dumped as part of the main CREATE TABLE (or similar) command or
    9137             :              * as a separate ALTER TABLE (or similar) command. The preference
    9138             :              * is to put it into the CREATE command, but in some cases that's
    9139             :              * not possible.
    9140             :              */
    9141        1644 :             if (tbinfo->attgenerated[adnum - 1])
    9142             :             {
    9143             :                 /*
    9144             :                  * Column generation expressions cannot be dumped separately,
    9145             :                  * because there is no syntax for it.  By setting separate to
    9146             :                  * false here we prevent the "default" from being processed as
    9147             :                  * its own dumpable object.  Later, flagInhAttrs() will mark
    9148             :                  * it as not to be dumped at all, if possible (that is, if it
    9149             :                  * can be inherited from a parent).
    9150             :                  */
    9151         690 :                 attrdefs[j].separate = false;
    9152             :             }
    9153         954 :             else if (tbinfo->relkind == RELKIND_VIEW)
    9154             :             {
    9155             :                 /*
    9156             :                  * Defaults on a VIEW must always be dumped as separate ALTER
    9157             :                  * TABLE commands.
    9158             :                  */
    9159          66 :                 attrdefs[j].separate = true;
    9160             :             }
    9161         888 :             else if (!shouldPrintColumn(dopt, tbinfo, adnum - 1))
    9162             :             {
    9163             :                 /* column will be suppressed, print default separately */
    9164           8 :                 attrdefs[j].separate = true;
    9165             :             }
    9166             :             else
    9167             :             {
    9168         880 :                 attrdefs[j].separate = false;
    9169             :             }
    9170             : 
    9171        1644 :             if (!attrdefs[j].separate)
    9172             :             {
    9173             :                 /*
    9174             :                  * Mark the default as needing to appear before the table, so
    9175             :                  * that any dependencies it has must be emitted before the
    9176             :                  * CREATE TABLE.  If this is not possible, we'll change to
    9177             :                  * "separate" mode while sorting dependencies.
    9178             :                  */
    9179        1570 :                 addObjectDependency(&tbinfo->dobj,
    9180        1570 :                                     attrdefs[j].dobj.dumpId);
    9181             :             }
    9182             : 
    9183        1644 :             tbinfo->attrdefs[adnum - 1] = &attrdefs[j];
    9184             :         }
    9185             : 
    9186         122 :         PQclear(res);
    9187             :     }
    9188             : 
    9189             :     /*
    9190             :      * Get info about table CHECK constraints.  This is skipped for a
    9191             :      * data-only dump, as it is only needed for table schemas.
    9192             :      */
    9193         308 :     if (dopt->dumpSchema && checkoids->len > 2)
    9194             :     {
    9195             :         ConstraintInfo *constrs;
    9196             :         int         numConstrs;
    9197             :         int         i_tableoid;
    9198             :         int         i_oid;
    9199             :         int         i_conrelid;
    9200             :         int         i_conname;
    9201             :         int         i_consrc;
    9202             :         int         i_conislocal;
    9203             :         int         i_convalidated;
    9204             : 
    9205         124 :         pg_log_info("finding table check constraints");
    9206             : 
    9207         124 :         resetPQExpBuffer(q);
    9208         124 :         appendPQExpBuffer(q,
    9209             :                           "SELECT c.tableoid, c.oid, conrelid, conname, "
    9210             :                           "pg_catalog.pg_get_constraintdef(c.oid) AS consrc, "
    9211             :                           "conislocal, convalidated "
    9212             :                           "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
    9213             :                           "JOIN pg_catalog.pg_constraint c ON (src.tbloid = c.conrelid)\n"
    9214             :                           "WHERE contype = 'c' "
    9215             :                           "ORDER BY c.conrelid, c.conname",
    9216             :                           checkoids->data);
    9217             : 
    9218         124 :         res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
    9219             : 
    9220         124 :         numConstrs = PQntuples(res);
    9221         124 :         constrs = (ConstraintInfo *) pg_malloc(numConstrs * sizeof(ConstraintInfo));
    9222             : 
    9223         124 :         i_tableoid = PQfnumber(res, "tableoid");
    9224         124 :         i_oid = PQfnumber(res, "oid");
    9225         124 :         i_conrelid = PQfnumber(res, "conrelid");
    9226         124 :         i_conname = PQfnumber(res, "conname");
    9227         124 :         i_consrc = PQfnumber(res, "consrc");
    9228         124 :         i_conislocal = PQfnumber(res, "conislocal");
    9229         124 :         i_convalidated = PQfnumber(res, "convalidated");
    9230             : 
    9231             :         /* As above, this loop iterates once per table, not once per row */
    9232         124 :         curtblindx = -1;
    9233        1054 :         for (int j = 0; j < numConstrs;)
    9234             :         {
    9235         930 :             Oid         conrelid = atooid(PQgetvalue(res, j, i_conrelid));
    9236         930 :             TableInfo  *tbinfo = NULL;
    9237             :             int         numcons;
    9238             : 
    9239             :             /* Count rows for this table */
    9240        1204 :             for (numcons = 1; numcons < numConstrs - j; numcons++)
    9241        1080 :                 if (atooid(PQgetvalue(res, j + numcons, i_conrelid)) != conrelid)
    9242         806 :                     break;
    9243             : 
    9244             :             /*
    9245             :              * Locate the associated TableInfo; we rely on tblinfo[] being in
    9246             :              * OID order.
    9247             :              */
    9248       35470 :             while (++curtblindx < numTables)
    9249             :             {
    9250       35470 :                 tbinfo = &tblinfo[curtblindx];
    9251       35470 :                 if (tbinfo->dobj.catId.oid == conrelid)
    9252         930 :                     break;
    9253             :             }
    9254         930 :             if (curtblindx >= numTables)
    9255           0 :                 pg_fatal("unrecognized table OID %u", conrelid);
    9256             : 
    9257         930 :             if (numcons != tbinfo->ncheck)
    9258             :             {
    9259           0 :                 pg_log_error(ngettext("expected %d check constraint on table \"%s\" but found %d",
    9260             :                                       "expected %d check constraints on table \"%s\" but found %d",
    9261             :                                       tbinfo->ncheck),
    9262             :                              tbinfo->ncheck, tbinfo->dobj.name, numcons);
    9263           0 :                 pg_log_error_hint("The system catalogs might be corrupted.");
    9264           0 :                 exit_nicely(1);
    9265             :             }
    9266             : 
    9267         930 :             tbinfo->checkexprs = constrs + j;
    9268             : 
    9269        2134 :             for (int c = 0; c < numcons; c++, j++)
    9270             :             {
    9271        1204 :                 bool        validated = PQgetvalue(res, j, i_convalidated)[0] == 't';
    9272             : 
    9273        1204 :                 constrs[j].dobj.objType = DO_CONSTRAINT;
    9274        1204 :                 constrs[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
    9275        1204 :                 constrs[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
    9276        1204 :                 AssignDumpId(&constrs[j].dobj);
    9277        1204 :                 constrs[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_conname));
    9278        1204 :                 constrs[j].dobj.namespace = tbinfo->dobj.namespace;
    9279        1204 :                 constrs[j].contable = tbinfo;
    9280        1204 :                 constrs[j].condomain = NULL;
    9281        1204 :                 constrs[j].contype = 'c';
    9282        1204 :                 constrs[j].condef = pg_strdup(PQgetvalue(res, j, i_consrc));
    9283        1204 :                 constrs[j].confrelid = InvalidOid;
    9284        1204 :                 constrs[j].conindex = 0;
    9285        1204 :                 constrs[j].condeferrable = false;
    9286        1204 :                 constrs[j].condeferred = false;
    9287        1204 :                 constrs[j].conislocal = (PQgetvalue(res, j, i_conislocal)[0] == 't');
    9288             : 
    9289             :                 /*
    9290             :                  * An unvalidated constraint needs to be dumped separately, so
    9291             :                  * that potentially-violating existing data is loaded before
    9292             :                  * the constraint.
    9293             :                  */
    9294        1204 :                 constrs[j].separate = !validated;
    9295             : 
    9296        1204 :                 constrs[j].dobj.dump = tbinfo->dobj.dump;
    9297             : 
    9298             :                 /*
    9299             :                  * Mark the constraint as needing to appear before the table
    9300             :                  * --- this is so that any other dependencies of the
    9301             :                  * constraint will be emitted before we try to create the
    9302             :                  * table.  If the constraint is to be dumped separately, it
    9303             :                  * will be dumped after data is loaded anyway, so don't do it.
    9304             :                  * (There's an automatic dependency in the opposite direction
    9305             :                  * anyway, so don't need to add one manually here.)
    9306             :                  */
    9307        1204 :                 if (!constrs[j].separate)
    9308        1084 :                     addObjectDependency(&tbinfo->dobj,
    9309        1084 :                                         constrs[j].dobj.dumpId);
    9310             : 
    9311             :                 /*
    9312             :                  * We will detect later whether the constraint must be split
    9313             :                  * out from the table definition.
    9314             :                  */
    9315             :             }
    9316             :         }
    9317             : 
    9318         124 :         PQclear(res);
    9319             :     }
    9320             : 
    9321         308 :     destroyPQExpBuffer(q);
    9322         308 :     destroyPQExpBuffer(tbloids);
    9323         308 :     destroyPQExpBuffer(checkoids);
    9324         308 : }
    9325             : 
    9326             : /*
    9327             :  * Based on the getTableAttrs query's row corresponding to one column, set
    9328             :  * the name and flags to handle a not-null constraint for that column in
    9329             :  * the tbinfo struct.
    9330             :  *
    9331             :  * Result row 'r' is for tbinfo's attribute 'j'.
    9332             :  *
    9333             :  * There are three possibilities:
    9334             :  * 1) the column has no not-null constraints. In that case, ->notnull_constrs
    9335             :  *    (the constraint name) remains NULL.
    9336             :  * 2) The column has a constraint with no name (this is the case when
    9337             :  *    constraints come from pre-18 servers).  In this case, ->notnull_constrs
    9338             :  *    is set to the empty string; dumpTableSchema will print just "NOT NULL".
    9339             :  * 3) The column has a constraint with a known name; in that case
    9340             :  *    notnull_constrs carries that name and dumpTableSchema will print
    9341             :  *    "CONSTRAINT the_name NOT NULL".  However, if the name is the default
    9342             :  *    (table_column_not_null), there's no need to print that name in the dump,
    9343             :  *    so notnull_constrs is set to the empty string and it behaves as the case
    9344             :  *    above.
    9345             :  *
    9346             :  * In a child table that inherits from a parent already containing NOT NULL
    9347             :  * constraints and the columns in the child don't have their own NOT NULL
    9348             :  * declarations, we suppress printing constraints in the child: the
    9349             :  * constraints are acquired at the point where the child is attached to the
    9350             :  * parent.  This is tracked in ->notnull_islocal (which is set in flagInhAttrs
    9351             :  * for servers pre-18).
    9352             :  *
    9353             :  * Any of these constraints might have the NO INHERIT bit.  If so we set
    9354             :  * ->notnull_noinh and NO INHERIT will be printed by dumpTableSchema.
    9355             :  *
    9356             :  * In case 3 above, the name comparison is a bit of a hack; it actually fails
    9357             :  * to do the right thing in all but the trivial case.  However, the downside
    9358             :  * of getting it wrong is simply that the name is printed rather than
    9359             :  * suppressed, so it's not a big deal.
    9360             :  */
    9361             : static void
    9362       45178 : determineNotNullFlags(Archive *fout, PGresult *res, int r,
    9363             :                       TableInfo *tbinfo, int j,
    9364             :                       int i_notnull_name, int i_notnull_noinherit,
    9365             :                       int i_notnull_islocal)
    9366             : {
    9367       45178 :     DumpOptions *dopt = fout->dopt;
    9368             : 
    9369             :     /*
    9370             :      * notnull_noinh is straight from the query result. notnull_islocal also,
    9371             :      * though flagInhAttrs may change that one later in versions < 18.
    9372             :      */
    9373       45178 :     tbinfo->notnull_noinh[j] = PQgetvalue(res, r, i_notnull_noinherit)[0] == 't';
    9374       45178 :     tbinfo->notnull_islocal[j] = PQgetvalue(res, r, i_notnull_islocal)[0] == 't';
    9375             : 
    9376             :     /*
    9377             :      * Determine a constraint name to use.  If the column is not marked not-
    9378             :      * null, we set NULL which cues ... to do nothing.  An empty string says
    9379             :      * to print an unnamed NOT NULL, and anything else is a constraint name to
    9380             :      * use.
    9381             :      */
    9382       45178 :     if (fout->remoteVersion < 180000)
    9383             :     {
    9384             :         /*
    9385             :          * < 18 doesn't have not-null names, so an unnamed constraint is
    9386             :          * sufficient.
    9387             :          */
    9388           0 :         if (PQgetisnull(res, r, i_notnull_name))
    9389           0 :             tbinfo->notnull_constrs[j] = NULL;
    9390             :         else
    9391           0 :             tbinfo->notnull_constrs[j] = "";
    9392             :     }
    9393             :     else
    9394             :     {
    9395       45178 :         if (PQgetisnull(res, r, i_notnull_name))
    9396       40894 :             tbinfo->notnull_constrs[j] = NULL;
    9397             :         else
    9398             :         {
    9399             :             /*
    9400             :              * In binary upgrade of inheritance child tables, must have a
    9401             :              * constraint name that we can UPDATE later.
    9402             :              */
    9403        4284 :             if (dopt->binary_upgrade &&
    9404         480 :                 !tbinfo->ispartition &&
    9405         344 :                 !tbinfo->notnull_islocal)
    9406             :             {
    9407           0 :                 tbinfo->notnull_constrs[j] =
    9408           0 :                     pstrdup(PQgetvalue(res, r, i_notnull_name));
    9409             :             }
    9410             :             else
    9411             :             {
    9412             :                 char       *default_name;
    9413             : 
    9414             :                 /* XXX should match ChooseConstraintName better */
    9415        4284 :                 default_name = psprintf("%s_%s_not_null", tbinfo->dobj.name,
    9416        4284 :                                         tbinfo->attnames[j]);
    9417        4284 :                 if (strcmp(default_name,
    9418        4284 :                            PQgetvalue(res, r, i_notnull_name)) == 0)
    9419        2898 :                     tbinfo->notnull_constrs[j] = "";
    9420             :                 else
    9421             :                 {
    9422        1386 :                     tbinfo->notnull_constrs[j] =
    9423        1386 :                         pstrdup(PQgetvalue(res, r, i_notnull_name));
    9424             :                 }
    9425             :             }
    9426             :         }
    9427             :     }
    9428       45178 : }
    9429             : 
    9430             : /*
    9431             :  * Test whether a column should be printed as part of table's CREATE TABLE.
    9432             :  * Column number is zero-based.
    9433             :  *
    9434             :  * Normally this is always true, but it's false for dropped columns, as well
    9435             :  * as those that were inherited without any local definition.  (If we print
    9436             :  * such a column it will mistakenly get pg_attribute.attislocal set to true.)
    9437             :  * For partitions, it's always true, because we want the partitions to be
    9438             :  * created independently and ATTACH PARTITION used afterwards.
    9439             :  *
    9440             :  * In binary_upgrade mode, we must print all columns and fix the attislocal/
    9441             :  * attisdropped state later, so as to keep control of the physical column
    9442             :  * order.
    9443             :  *
    9444             :  * This function exists because there are scattered nonobvious places that
    9445             :  * must be kept in sync with this decision.
    9446             :  */
    9447             : bool
    9448       75350 : shouldPrintColumn(const DumpOptions *dopt, const TableInfo *tbinfo, int colno)
    9449             : {
    9450       75350 :     if (dopt->binary_upgrade)
    9451       11628 :         return true;
    9452       63722 :     if (tbinfo->attisdropped[colno])
    9453        1376 :         return false;
    9454       62346 :     return (tbinfo->attislocal[colno] || tbinfo->ispartition);
    9455             : }
    9456             : 
    9457             : 
    9458             : /*
    9459             :  * getTSParsers:
    9460             :  *    get information about all text search parsers in the system catalogs
    9461             :  */
    9462             : void
    9463         308 : getTSParsers(Archive *fout)
    9464             : {
    9465             :     PGresult   *res;
    9466             :     int         ntups;
    9467             :     int         i;
    9468             :     PQExpBuffer query;
    9469             :     TSParserInfo *prsinfo;
    9470             :     int         i_tableoid;
    9471             :     int         i_oid;
    9472             :     int         i_prsname;
    9473             :     int         i_prsnamespace;
    9474             :     int         i_prsstart;
    9475             :     int         i_prstoken;
    9476             :     int         i_prsend;
    9477             :     int         i_prsheadline;
    9478             :     int         i_prslextype;
    9479             : 
    9480         308 :     query = createPQExpBuffer();
    9481             : 
    9482             :     /*
    9483             :      * find all text search objects, including builtin ones; we filter out
    9484             :      * system-defined objects at dump-out time.
    9485             :      */
    9486             : 
    9487         308 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, prsname, prsnamespace, "
    9488             :                          "prsstart::oid, prstoken::oid, "
    9489             :                          "prsend::oid, prsheadline::oid, prslextype::oid "
    9490             :                          "FROM pg_ts_parser");
    9491             : 
    9492         308 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    9493             : 
    9494         308 :     ntups = PQntuples(res);
    9495             : 
    9496         308 :     prsinfo = (TSParserInfo *) pg_malloc(ntups * sizeof(TSParserInfo));
    9497             : 
    9498         308 :     i_tableoid = PQfnumber(res, "tableoid");
    9499         308 :     i_oid = PQfnumber(res, "oid");
    9500         308 :     i_prsname = PQfnumber(res, "prsname");
    9501         308 :     i_prsnamespace = PQfnumber(res, "prsnamespace");
    9502         308 :     i_prsstart = PQfnumber(res, "prsstart");
    9503         308 :     i_prstoken = PQfnumber(res, "prstoken");
    9504         308 :     i_prsend = PQfnumber(res, "prsend");
    9505         308 :     i_prsheadline = PQfnumber(res, "prsheadline");
    9506         308 :     i_prslextype = PQfnumber(res, "prslextype");
    9507             : 
    9508         702 :     for (i = 0; i < ntups; i++)
    9509             :     {
    9510         394 :         prsinfo[i].dobj.objType = DO_TSPARSER;
    9511         394 :         prsinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    9512         394 :         prsinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    9513         394 :         AssignDumpId(&prsinfo[i].dobj);
    9514         394 :         prsinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_prsname));
    9515         788 :         prsinfo[i].dobj.namespace =
    9516         394 :             findNamespace(atooid(PQgetvalue(res, i, i_prsnamespace)));
    9517         394 :         prsinfo[i].prsstart = atooid(PQgetvalue(res, i, i_prsstart));
    9518         394 :         prsinfo[i].prstoken = atooid(PQgetvalue(res, i, i_prstoken));
    9519         394 :         prsinfo[i].prsend = atooid(PQgetvalue(res, i, i_prsend));
    9520         394 :         prsinfo[i].prsheadline = atooid(PQgetvalue(res, i, i_prsheadline));
    9521         394 :         prsinfo[i].prslextype = atooid(PQgetvalue(res, i, i_prslextype));
    9522             : 
    9523             :         /* Decide whether we want to dump it */
    9524         394 :         selectDumpableObject(&(prsinfo[i].dobj), fout);
    9525             :     }
    9526             : 
    9527         308 :     PQclear(res);
    9528             : 
    9529         308 :     destroyPQExpBuffer(query);
    9530         308 : }
    9531             : 
    9532             : /*
    9533             :  * getTSDictionaries:
    9534             :  *    get information about all text search dictionaries in the system catalogs
    9535             :  */
    9536             : void
    9537         308 : getTSDictionaries(Archive *fout)
    9538             : {
    9539             :     PGresult   *res;
    9540             :     int         ntups;
    9541             :     int         i;
    9542             :     PQExpBuffer query;
    9543             :     TSDictInfo *dictinfo;
    9544             :     int         i_tableoid;
    9545             :     int         i_oid;
    9546             :     int         i_dictname;
    9547             :     int         i_dictnamespace;
    9548             :     int         i_dictowner;
    9549             :     int         i_dicttemplate;
    9550             :     int         i_dictinitoption;
    9551             : 
    9552         308 :     query = createPQExpBuffer();
    9553             : 
    9554         308 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, dictname, "
    9555             :                          "dictnamespace, dictowner, "
    9556             :                          "dicttemplate, dictinitoption "
    9557             :                          "FROM pg_ts_dict");
    9558             : 
    9559         308 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    9560             : 
    9561         308 :     ntups = PQntuples(res);
    9562             : 
    9563         308 :     dictinfo = (TSDictInfo *) pg_malloc(ntups * sizeof(TSDictInfo));
    9564             : 
    9565         308 :     i_tableoid = PQfnumber(res, "tableoid");
    9566         308 :     i_oid = PQfnumber(res, "oid");
    9567         308 :     i_dictname = PQfnumber(res, "dictname");
    9568         308 :     i_dictnamespace = PQfnumber(res, "dictnamespace");
    9569         308 :     i_dictowner = PQfnumber(res, "dictowner");
    9570         308 :     i_dictinitoption = PQfnumber(res, "dictinitoption");
    9571         308 :     i_dicttemplate = PQfnumber(res, "dicttemplate");
    9572             : 
    9573        9452 :     for (i = 0; i < ntups; i++)
    9574             :     {
    9575        9144 :         dictinfo[i].dobj.objType = DO_TSDICT;
    9576        9144 :         dictinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    9577        9144 :         dictinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    9578        9144 :         AssignDumpId(&dictinfo[i].dobj);
    9579        9144 :         dictinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_dictname));
    9580       18288 :         dictinfo[i].dobj.namespace =
    9581        9144 :             findNamespace(atooid(PQgetvalue(res, i, i_dictnamespace)));
    9582        9144 :         dictinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_dictowner));
    9583        9144 :         dictinfo[i].dicttemplate = atooid(PQgetvalue(res, i, i_dicttemplate));
    9584        9144 :         if (PQgetisnull(res, i, i_dictinitoption))
    9585         394 :             dictinfo[i].dictinitoption = NULL;
    9586             :         else
    9587        8750 :             dictinfo[i].dictinitoption = pg_strdup(PQgetvalue(res, i, i_dictinitoption));
    9588             : 
    9589             :         /* Decide whether we want to dump it */
    9590        9144 :         selectDumpableObject(&(dictinfo[i].dobj), fout);
    9591             :     }
    9592             : 
    9593         308 :     PQclear(res);
    9594             : 
    9595         308 :     destroyPQExpBuffer(query);
    9596         308 : }
    9597             : 
    9598             : /*
    9599             :  * getTSTemplates:
    9600             :  *    get information about all text search templates in the system catalogs
    9601             :  */
    9602             : void
    9603         308 : getTSTemplates(Archive *fout)
    9604             : {
    9605             :     PGresult   *res;
    9606             :     int         ntups;
    9607             :     int         i;
    9608             :     PQExpBuffer query;
    9609             :     TSTemplateInfo *tmplinfo;
    9610             :     int         i_tableoid;
    9611             :     int         i_oid;
    9612             :     int         i_tmplname;
    9613             :     int         i_tmplnamespace;
    9614             :     int         i_tmplinit;
    9615             :     int         i_tmpllexize;
    9616             : 
    9617         308 :     query = createPQExpBuffer();
    9618             : 
    9619         308 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, tmplname, "
    9620             :                          "tmplnamespace, tmplinit::oid, tmpllexize::oid "
    9621             :                          "FROM pg_ts_template");
    9622             : 
    9623         308 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    9624             : 
    9625         308 :     ntups = PQntuples(res);
    9626             : 
    9627         308 :     tmplinfo = (TSTemplateInfo *) pg_malloc(ntups * sizeof(TSTemplateInfo));
    9628             : 
    9629         308 :     i_tableoid = PQfnumber(res, "tableoid");
    9630         308 :     i_oid = PQfnumber(res, "oid");
    9631         308 :     i_tmplname = PQfnumber(res, "tmplname");
    9632         308 :     i_tmplnamespace = PQfnumber(res, "tmplnamespace");
    9633         308 :     i_tmplinit = PQfnumber(res, "tmplinit");
    9634         308 :     i_tmpllexize = PQfnumber(res, "tmpllexize");
    9635             : 
    9636        1934 :     for (i = 0; i < ntups; i++)
    9637             :     {
    9638        1626 :         tmplinfo[i].dobj.objType = DO_TSTEMPLATE;
    9639        1626 :         tmplinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    9640        1626 :         tmplinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    9641        1626 :         AssignDumpId(&tmplinfo[i].dobj);
    9642        1626 :         tmplinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_tmplname));
    9643        3252 :         tmplinfo[i].dobj.namespace =
    9644        1626 :             findNamespace(atooid(PQgetvalue(res, i, i_tmplnamespace)));
    9645        1626 :         tmplinfo[i].tmplinit = atooid(PQgetvalue(res, i, i_tmplinit));
    9646        1626 :         tmplinfo[i].tmpllexize = atooid(PQgetvalue(res, i, i_tmpllexize));
    9647             : 
    9648             :         /* Decide whether we want to dump it */
    9649        1626 :         selectDumpableObject(&(tmplinfo[i].dobj), fout);
    9650             :     }
    9651             : 
    9652         308 :     PQclear(res);
    9653             : 
    9654         308 :     destroyPQExpBuffer(query);
    9655         308 : }
    9656             : 
    9657             : /*
    9658             :  * getTSConfigurations:
    9659             :  *    get information about all text search configurations
    9660             :  */
    9661             : void
    9662         308 : getTSConfigurations(Archive *fout)
    9663             : {
    9664             :     PGresult   *res;
    9665             :     int         ntups;
    9666             :     int         i;
    9667             :     PQExpBuffer query;
    9668             :     TSConfigInfo *cfginfo;
    9669             :     int         i_tableoid;
    9670             :     int         i_oid;
    9671             :     int         i_cfgname;
    9672             :     int         i_cfgnamespace;
    9673             :     int         i_cfgowner;
    9674             :     int         i_cfgparser;
    9675             : 
    9676         308 :     query = createPQExpBuffer();
    9677             : 
    9678         308 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, cfgname, "
    9679             :                          "cfgnamespace, cfgowner, cfgparser "
    9680             :                          "FROM pg_ts_config");
    9681             : 
    9682         308 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    9683             : 
    9684         308 :     ntups = PQntuples(res);
    9685             : 
    9686         308 :     cfginfo = (TSConfigInfo *) pg_malloc(ntups * sizeof(TSConfigInfo));
    9687             : 
    9688         308 :     i_tableoid = PQfnumber(res, "tableoid");
    9689         308 :     i_oid = PQfnumber(res, "oid");
    9690         308 :     i_cfgname = PQfnumber(res, "cfgname");
    9691         308 :     i_cfgnamespace = PQfnumber(res, "cfgnamespace");
    9692         308 :     i_cfgowner = PQfnumber(res, "cfgowner");
    9693         308 :     i_cfgparser = PQfnumber(res, "cfgparser");
    9694             : 
    9695        9382 :     for (i = 0; i < ntups; i++)
    9696             :     {
    9697        9074 :         cfginfo[i].dobj.objType = DO_TSCONFIG;
    9698        9074 :         cfginfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    9699        9074 :         cfginfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    9700        9074 :         AssignDumpId(&cfginfo[i].dobj);
    9701        9074 :         cfginfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_cfgname));
    9702       18148 :         cfginfo[i].dobj.namespace =
    9703        9074 :             findNamespace(atooid(PQgetvalue(res, i, i_cfgnamespace)));
    9704        9074 :         cfginfo[i].rolname = getRoleName(PQgetvalue(res, i, i_cfgowner));
    9705        9074 :         cfginfo[i].cfgparser = atooid(PQgetvalue(res, i, i_cfgparser));
    9706             : 
    9707             :         /* Decide whether we want to dump it */
    9708        9074 :         selectDumpableObject(&(cfginfo[i].dobj), fout);
    9709             :     }
    9710             : 
    9711         308 :     PQclear(res);
    9712             : 
    9713         308 :     destroyPQExpBuffer(query);
    9714         308 : }
    9715             : 
    9716             : /*
    9717             :  * getForeignDataWrappers:
    9718             :  *    get information about all foreign-data wrappers in the system catalogs
    9719             :  */
    9720             : void
    9721         308 : getForeignDataWrappers(Archive *fout)
    9722             : {
    9723             :     PGresult   *res;
    9724             :     int         ntups;
    9725             :     int         i;
    9726             :     PQExpBuffer query;
    9727             :     FdwInfo    *fdwinfo;
    9728             :     int         i_tableoid;
    9729             :     int         i_oid;
    9730             :     int         i_fdwname;
    9731             :     int         i_fdwowner;
    9732             :     int         i_fdwhandler;
    9733             :     int         i_fdwvalidator;
    9734             :     int         i_fdwacl;
    9735             :     int         i_acldefault;
    9736             :     int         i_fdwoptions;
    9737             : 
    9738         308 :     query = createPQExpBuffer();
    9739             : 
    9740         308 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, fdwname, "
    9741             :                          "fdwowner, "
    9742             :                          "fdwhandler::pg_catalog.regproc, "
    9743             :                          "fdwvalidator::pg_catalog.regproc, "
    9744             :                          "fdwacl, "
    9745             :                          "acldefault('F', fdwowner) AS acldefault, "
    9746             :                          "array_to_string(ARRAY("
    9747             :                          "SELECT quote_ident(option_name) || ' ' || "
    9748             :                          "quote_literal(option_value) "
    9749             :                          "FROM pg_options_to_table(fdwoptions) "
    9750             :                          "ORDER BY option_name"
    9751             :                          "), E',\n    ') AS fdwoptions "
    9752             :                          "FROM pg_foreign_data_wrapper");
    9753             : 
    9754         308 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    9755             : 
    9756         308 :     ntups = PQntuples(res);
    9757             : 
    9758         308 :     fdwinfo = (FdwInfo *) pg_malloc(ntups * sizeof(FdwInfo));
    9759             : 
    9760         308 :     i_tableoid = PQfnumber(res, "tableoid");
    9761         308 :     i_oid = PQfnumber(res, "oid");
    9762         308 :     i_fdwname = PQfnumber(res, "fdwname");
    9763         308 :     i_fdwowner = PQfnumber(res, "fdwowner");
    9764         308 :     i_fdwhandler = PQfnumber(res, "fdwhandler");
    9765         308 :     i_fdwvalidator = PQfnumber(res, "fdwvalidator");
    9766         308 :     i_fdwacl = PQfnumber(res, "fdwacl");
    9767         308 :     i_acldefault = PQfnumber(res, "acldefault");
    9768         308 :     i_fdwoptions = PQfnumber(res, "fdwoptions");
    9769             : 
    9770         446 :     for (i = 0; i < ntups; i++)
    9771             :     {
    9772         138 :         fdwinfo[i].dobj.objType = DO_FDW;
    9773         138 :         fdwinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    9774         138 :         fdwinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    9775         138 :         AssignDumpId(&fdwinfo[i].dobj);
    9776         138 :         fdwinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_fdwname));
    9777         138 :         fdwinfo[i].dobj.namespace = NULL;
    9778         138 :         fdwinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_fdwacl));
    9779         138 :         fdwinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
    9780         138 :         fdwinfo[i].dacl.privtype = 0;
    9781         138 :         fdwinfo[i].dacl.initprivs = NULL;
    9782         138 :         fdwinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_fdwowner));
    9783         138 :         fdwinfo[i].fdwhandler = pg_strdup(PQgetvalue(res, i, i_fdwhandler));
    9784         138 :         fdwinfo[i].fdwvalidator = pg_strdup(PQgetvalue(res, i, i_fdwvalidator));
    9785         138 :         fdwinfo[i].fdwoptions = pg_strdup(PQgetvalue(res, i, i_fdwoptions));
    9786             : 
    9787             :         /* Decide whether we want to dump it */
    9788         138 :         selectDumpableObject(&(fdwinfo[i].dobj), fout);
    9789             : 
    9790             :         /* Mark whether FDW has an ACL */
    9791         138 :         if (!PQgetisnull(res, i, i_fdwacl))
    9792          86 :             fdwinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
    9793             :     }
    9794             : 
    9795         308 :     PQclear(res);
    9796             : 
    9797         308 :     destroyPQExpBuffer(query);
    9798         308 : }
    9799             : 
    9800             : /*
    9801             :  * getForeignServers:
    9802             :  *    get information about all foreign servers in the system catalogs
    9803             :  */
    9804             : void
    9805         308 : getForeignServers(Archive *fout)
    9806             : {
    9807             :     PGresult   *res;
    9808             :     int         ntups;
    9809             :     int         i;
    9810             :     PQExpBuffer query;
    9811             :     ForeignServerInfo *srvinfo;
    9812             :     int         i_tableoid;
    9813             :     int         i_oid;
    9814             :     int         i_srvname;
    9815             :     int         i_srvowner;
    9816             :     int         i_srvfdw;
    9817             :     int         i_srvtype;
    9818             :     int         i_srvversion;
    9819             :     int         i_srvacl;
    9820             :     int         i_acldefault;
    9821             :     int         i_srvoptions;
    9822             : 
    9823         308 :     query = createPQExpBuffer();
    9824             : 
    9825         308 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, srvname, "
    9826             :                          "srvowner, "
    9827             :                          "srvfdw, srvtype, srvversion, srvacl, "
    9828             :                          "acldefault('S', srvowner) AS acldefault, "
    9829             :                          "array_to_string(ARRAY("
    9830             :                          "SELECT quote_ident(option_name) || ' ' || "
    9831             :                          "quote_literal(option_value) "
    9832             :                          "FROM pg_options_to_table(srvoptions) "
    9833             :                          "ORDER BY option_name"
    9834             :                          "), E',\n    ') AS srvoptions "
    9835             :                          "FROM pg_foreign_server");
    9836             : 
    9837         308 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    9838             : 
    9839         308 :     ntups = PQntuples(res);
    9840             : 
    9841         308 :     srvinfo = (ForeignServerInfo *) pg_malloc(ntups * sizeof(ForeignServerInfo));
    9842             : 
    9843         308 :     i_tableoid = PQfnumber(res, "tableoid");
    9844         308 :     i_oid = PQfnumber(res, "oid");
    9845         308 :     i_srvname = PQfnumber(res, "srvname");
    9846         308 :     i_srvowner = PQfnumber(res, "srvowner");
    9847         308 :     i_srvfdw = PQfnumber(res, "srvfdw");
    9848         308 :     i_srvtype = PQfnumber(res, "srvtype");
    9849         308 :     i_srvversion = PQfnumber(res, "srvversion");
    9850         308 :     i_srvacl = PQfnumber(res, "srvacl");
    9851         308 :     i_acldefault = PQfnumber(res, "acldefault");
    9852         308 :     i_srvoptions = PQfnumber(res, "srvoptions");
    9853             : 
    9854         454 :     for (i = 0; i < ntups; i++)
    9855             :     {
    9856         146 :         srvinfo[i].dobj.objType = DO_FOREIGN_SERVER;
    9857         146 :         srvinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    9858         146 :         srvinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    9859         146 :         AssignDumpId(&srvinfo[i].dobj);
    9860         146 :         srvinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_srvname));
    9861         146 :         srvinfo[i].dobj.namespace = NULL;
    9862         146 :         srvinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_srvacl));
    9863         146 :         srvinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
    9864         146 :         srvinfo[i].dacl.privtype = 0;
    9865         146 :         srvinfo[i].dacl.initprivs = NULL;
    9866         146 :         srvinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_srvowner));
    9867         146 :         srvinfo[i].srvfdw = atooid(PQgetvalue(res, i, i_srvfdw));
    9868         146 :         srvinfo[i].srvtype = pg_strdup(PQgetvalue(res, i, i_srvtype));
    9869         146 :         srvinfo[i].srvversion = pg_strdup(PQgetvalue(res, i, i_srvversion));
    9870         146 :         srvinfo[i].srvoptions = pg_strdup(PQgetvalue(res, i, i_srvoptions));
    9871             : 
    9872             :         /* Decide whether we want to dump it */
    9873         146 :         selectDumpableObject(&(srvinfo[i].dobj), fout);
    9874             : 
    9875             :         /* Servers have user mappings */
    9876         146 :         srvinfo[i].dobj.components |= DUMP_COMPONENT_USERMAP;
    9877             : 
    9878             :         /* Mark whether server has an ACL */
    9879         146 :         if (!PQgetisnull(res, i, i_srvacl))
    9880          86 :             srvinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
    9881             :     }
    9882             : 
    9883         308 :     PQclear(res);
    9884             : 
    9885         308 :     destroyPQExpBuffer(query);
    9886         308 : }
    9887             : 
    9888             : /*
    9889             :  * getDefaultACLs:
    9890             :  *    get information about all default ACL information in the system catalogs
    9891             :  */
    9892             : void
    9893         308 : getDefaultACLs(Archive *fout)
    9894             : {
    9895         308 :     DumpOptions *dopt = fout->dopt;
    9896             :     DefaultACLInfo *daclinfo;
    9897             :     PQExpBuffer query;
    9898             :     PGresult   *res;
    9899             :     int         i_oid;
    9900             :     int         i_tableoid;
    9901             :     int         i_defaclrole;
    9902             :     int         i_defaclnamespace;
    9903             :     int         i_defaclobjtype;
    9904             :     int         i_defaclacl;
    9905             :     int         i_acldefault;
    9906             :     int         i,
    9907             :                 ntups;
    9908             : 
    9909         308 :     query = createPQExpBuffer();
    9910             : 
    9911             :     /*
    9912             :      * Global entries (with defaclnamespace=0) replace the hard-wired default
    9913             :      * ACL for their object type.  We should dump them as deltas from the
    9914             :      * default ACL, since that will be used as a starting point for
    9915             :      * interpreting the ALTER DEFAULT PRIVILEGES commands.  On the other hand,
    9916             :      * non-global entries can only add privileges not revoke them.  We must
    9917             :      * dump those as-is (i.e., as deltas from an empty ACL).
    9918             :      *
    9919             :      * We can use defaclobjtype as the object type for acldefault(), except
    9920             :      * for the case of 'S' (DEFACLOBJ_SEQUENCE) which must be converted to
    9921             :      * 's'.
    9922             :      */
    9923         308 :     appendPQExpBufferStr(query,
    9924             :                          "SELECT oid, tableoid, "
    9925             :                          "defaclrole, "
    9926             :                          "defaclnamespace, "
    9927             :                          "defaclobjtype, "
    9928             :                          "defaclacl, "
    9929             :                          "CASE WHEN defaclnamespace = 0 THEN "
    9930             :                          "acldefault(CASE WHEN defaclobjtype = 'S' "
    9931             :                          "THEN 's'::\"char\" ELSE defaclobjtype END, "
    9932             :                          "defaclrole) ELSE '{}' END AS acldefault "
    9933             :                          "FROM pg_default_acl");
    9934             : 
    9935         308 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    9936             : 
    9937         308 :     ntups = PQntuples(res);
    9938             : 
    9939         308 :     daclinfo = (DefaultACLInfo *) pg_malloc(ntups * sizeof(DefaultACLInfo));
    9940             : 
    9941         308 :     i_oid = PQfnumber(res, "oid");
    9942         308 :     i_tableoid = PQfnumber(res, "tableoid");
    9943         308 :     i_defaclrole = PQfnumber(res, "defaclrole");
    9944         308 :     i_defaclnamespace = PQfnumber(res, "defaclnamespace");
    9945         308 :     i_defaclobjtype = PQfnumber(res, "defaclobjtype");
    9946         308 :     i_defaclacl = PQfnumber(res, "defaclacl");
    9947         308 :     i_acldefault = PQfnumber(res, "acldefault");
    9948             : 
    9949         652 :     for (i = 0; i < ntups; i++)
    9950             :     {
    9951         344 :         Oid         nspid = atooid(PQgetvalue(res, i, i_defaclnamespace));
    9952             : 
    9953         344 :         daclinfo[i].dobj.objType = DO_DEFAULT_ACL;
    9954         344 :         daclinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    9955         344 :         daclinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    9956         344 :         AssignDumpId(&daclinfo[i].dobj);
    9957             :         /* cheesy ... is it worth coming up with a better object name? */
    9958         344 :         daclinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_defaclobjtype));
    9959             : 
    9960         344 :         if (nspid != InvalidOid)
    9961         172 :             daclinfo[i].dobj.namespace = findNamespace(nspid);
    9962             :         else
    9963         172 :             daclinfo[i].dobj.namespace = NULL;
    9964             : 
    9965         344 :         daclinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_defaclacl));
    9966         344 :         daclinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
    9967         344 :         daclinfo[i].dacl.privtype = 0;
    9968         344 :         daclinfo[i].dacl.initprivs = NULL;
    9969         344 :         daclinfo[i].defaclrole = getRoleName(PQgetvalue(res, i, i_defaclrole));
    9970         344 :         daclinfo[i].defaclobjtype = *(PQgetvalue(res, i, i_defaclobjtype));
    9971             : 
    9972             :         /* Default ACLs are ACLs, of course */
    9973         344 :         daclinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
    9974             : 
    9975             :         /* Decide whether we want to dump it */
    9976         344 :         selectDumpableDefaultACL(&(daclinfo[i]), dopt);
    9977             :     }
    9978             : 
    9979         308 :     PQclear(res);
    9980             : 
    9981         308 :     destroyPQExpBuffer(query);
    9982         308 : }
    9983             : 
    9984             : /*
    9985             :  * getRoleName -- look up the name of a role, given its OID
    9986             :  *
    9987             :  * In current usage, we don't expect failures, so error out for a bad OID.
    9988             :  */
    9989             : static const char *
    9990      966250 : getRoleName(const char *roleoid_str)
    9991             : {
    9992      966250 :     Oid         roleoid = atooid(roleoid_str);
    9993             : 
    9994             :     /*
    9995             :      * Do binary search to find the appropriate item.
    9996             :      */
    9997      966250 :     if (nrolenames > 0)
    9998             :     {
    9999      966250 :         RoleNameItem *low = &rolenames[0];
   10000      966250 :         RoleNameItem *high = &rolenames[nrolenames - 1];
   10001             : 
   10002     3865032 :         while (low <= high)
   10003             :         {
   10004     3865032 :             RoleNameItem *middle = low + (high - low) / 2;
   10005             : 
   10006     3865032 :             if (roleoid < middle->roleoid)
   10007     2896692 :                 high = middle - 1;
   10008      968340 :             else if (roleoid > middle->roleoid)
   10009        2090 :                 low = middle + 1;
   10010             :             else
   10011      966250 :                 return middle->rolename; /* found a match */
   10012             :         }
   10013             :     }
   10014             : 
   10015           0 :     pg_fatal("role with OID %u does not exist", roleoid);
   10016             :     return NULL;                /* keep compiler quiet */
   10017             : }
   10018             : 
   10019             : /*
   10020             :  * collectRoleNames --
   10021             :  *
   10022             :  * Construct a table of all known roles.
   10023             :  * The table is sorted by OID for speed in lookup.
   10024             :  */
   10025             : static void
   10026         310 : collectRoleNames(Archive *fout)
   10027             : {
   10028             :     PGresult   *res;
   10029             :     const char *query;
   10030             :     int         i;
   10031             : 
   10032         310 :     query = "SELECT oid, rolname FROM pg_catalog.pg_roles ORDER BY 1";
   10033             : 
   10034         310 :     res = ExecuteSqlQuery(fout, query, PGRES_TUPLES_OK);
   10035             : 
   10036         310 :     nrolenames = PQntuples(res);
   10037             : 
   10038         310 :     rolenames = (RoleNameItem *) pg_malloc(nrolenames * sizeof(RoleNameItem));
   10039             : 
   10040        5980 :     for (i = 0; i < nrolenames; i++)
   10041             :     {
   10042        5670 :         rolenames[i].roleoid = atooid(PQgetvalue(res, i, 0));
   10043        5670 :         rolenames[i].rolename = pg_strdup(PQgetvalue(res, i, 1));
   10044             :     }
   10045             : 
   10046         310 :     PQclear(res);
   10047         310 : }
   10048             : 
   10049             : /*
   10050             :  * getAdditionalACLs
   10051             :  *
   10052             :  * We have now created all the DumpableObjects, and collected the ACL data
   10053             :  * that appears in the directly-associated catalog entries.  However, there's
   10054             :  * more ACL-related info to collect.  If any of a table's columns have ACLs,
   10055             :  * we must set the TableInfo's DUMP_COMPONENT_ACL components flag, as well as
   10056             :  * its hascolumnACLs flag (we won't store the ACLs themselves here, though).
   10057             :  * Also, in versions having the pg_init_privs catalog, read that and load the
   10058             :  * information into the relevant DumpableObjects.
   10059             :  */
   10060             : static void
   10061         304 : getAdditionalACLs(Archive *fout)
   10062             : {
   10063         304 :     PQExpBuffer query = createPQExpBuffer();
   10064             :     PGresult   *res;
   10065             :     int         ntups,
   10066             :                 i;
   10067             : 
   10068             :     /* Check for per-column ACLs */
   10069         304 :     appendPQExpBufferStr(query,
   10070             :                          "SELECT DISTINCT attrelid FROM pg_attribute "
   10071             :                          "WHERE attacl IS NOT NULL");
   10072             : 
   10073         304 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   10074             : 
   10075         304 :     ntups = PQntuples(res);
   10076         936 :     for (i = 0; i < ntups; i++)
   10077             :     {
   10078         632 :         Oid         relid = atooid(PQgetvalue(res, i, 0));
   10079             :         TableInfo  *tblinfo;
   10080             : 
   10081         632 :         tblinfo = findTableByOid(relid);
   10082             :         /* OK to ignore tables we haven't got a DumpableObject for */
   10083         632 :         if (tblinfo)
   10084             :         {
   10085         632 :             tblinfo->dobj.components |= DUMP_COMPONENT_ACL;
   10086         632 :             tblinfo->hascolumnACLs = true;
   10087             :         }
   10088             :     }
   10089         304 :     PQclear(res);
   10090             : 
   10091             :     /* Fetch initial-privileges data */
   10092         304 :     if (fout->remoteVersion >= 90600)
   10093             :     {
   10094         304 :         printfPQExpBuffer(query,
   10095             :                           "SELECT objoid, classoid, objsubid, privtype, initprivs "
   10096             :                           "FROM pg_init_privs");
   10097             : 
   10098         304 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   10099             : 
   10100         304 :         ntups = PQntuples(res);
   10101       69320 :         for (i = 0; i < ntups; i++)
   10102             :         {
   10103       69016 :             Oid         objoid = atooid(PQgetvalue(res, i, 0));
   10104       69016 :             Oid         classoid = atooid(PQgetvalue(res, i, 1));
   10105       69016 :             int         objsubid = atoi(PQgetvalue(res, i, 2));
   10106       69016 :             char        privtype = *(PQgetvalue(res, i, 3));
   10107       69016 :             char       *initprivs = PQgetvalue(res, i, 4);
   10108             :             CatalogId   objId;
   10109             :             DumpableObject *dobj;
   10110             : 
   10111       69016 :             objId.tableoid = classoid;
   10112       69016 :             objId.oid = objoid;
   10113       69016 :             dobj = findObjectByCatalogId(objId);
   10114             :             /* OK to ignore entries we haven't got a DumpableObject for */
   10115       69016 :             if (dobj)
   10116             :             {
   10117             :                 /* Cope with sub-object initprivs */
   10118       49644 :                 if (objsubid != 0)
   10119             :                 {
   10120        5216 :                     if (dobj->objType == DO_TABLE)
   10121             :                     {
   10122             :                         /* For a column initprivs, set the table's ACL flags */
   10123        5216 :                         dobj->components |= DUMP_COMPONENT_ACL;
   10124        5216 :                         ((TableInfo *) dobj)->hascolumnACLs = true;
   10125             :                     }
   10126             :                     else
   10127           0 :                         pg_log_warning("unsupported pg_init_privs entry: %u %u %d",
   10128             :                                        classoid, objoid, objsubid);
   10129        5512 :                     continue;
   10130             :                 }
   10131             : 
   10132             :                 /*
   10133             :                  * We ignore any pg_init_privs.initprivs entry for the public
   10134             :                  * schema, as explained in getNamespaces().
   10135             :                  */
   10136       44428 :                 if (dobj->objType == DO_NAMESPACE &&
   10137         600 :                     strcmp(dobj->name, "public") == 0)
   10138         296 :                     continue;
   10139             : 
   10140             :                 /* Else it had better be of a type we think has ACLs */
   10141       44132 :                 if (dobj->objType == DO_NAMESPACE ||
   10142       43828 :                     dobj->objType == DO_TYPE ||
   10143       43780 :                     dobj->objType == DO_FUNC ||
   10144       43600 :                     dobj->objType == DO_AGG ||
   10145       43552 :                     dobj->objType == DO_TABLE ||
   10146           0 :                     dobj->objType == DO_PROCLANG ||
   10147           0 :                     dobj->objType == DO_FDW ||
   10148           0 :                     dobj->objType == DO_FOREIGN_SERVER)
   10149       44132 :                 {
   10150       44132 :                     DumpableObjectWithAcl *daobj = (DumpableObjectWithAcl *) dobj;
   10151             : 
   10152       44132 :                     daobj->dacl.privtype = privtype;
   10153       44132 :                     daobj->dacl.initprivs = pstrdup(initprivs);
   10154             :                 }
   10155             :                 else
   10156           0 :                     pg_log_warning("unsupported pg_init_privs entry: %u %u %d",
   10157             :                                    classoid, objoid, objsubid);
   10158             :             }
   10159             :         }
   10160         304 :         PQclear(res);
   10161             :     }
   10162             : 
   10163         304 :     destroyPQExpBuffer(query);
   10164         304 : }
   10165             : 
   10166             : /*
   10167             :  * dumpCommentExtended --
   10168             :  *
   10169             :  * This routine is used to dump any comments associated with the
   10170             :  * object handed to this routine. The routine takes the object type
   10171             :  * and object name (ready to print, except for schema decoration), plus
   10172             :  * the namespace and owner of the object (for labeling the ArchiveEntry),
   10173             :  * plus catalog ID and subid which are the lookup key for pg_description,
   10174             :  * plus the dump ID for the object (for setting a dependency).
   10175             :  * If a matching pg_description entry is found, it is dumped.
   10176             :  *
   10177             :  * Note: in some cases, such as comments for triggers and rules, the "type"
   10178             :  * string really looks like, e.g., "TRIGGER name ON".  This is a bit of a hack
   10179             :  * but it doesn't seem worth complicating the API for all callers to make
   10180             :  * it cleaner.
   10181             :  *
   10182             :  * Note: although this routine takes a dumpId for dependency purposes,
   10183             :  * that purpose is just to mark the dependency in the emitted dump file
   10184             :  * for possible future use by pg_restore.  We do NOT use it for determining
   10185             :  * ordering of the comment in the dump file, because this routine is called
   10186             :  * after dependency sorting occurs.  This routine should be called just after
   10187             :  * calling ArchiveEntry() for the specified object.
   10188             :  */
   10189             : static void
   10190       12546 : dumpCommentExtended(Archive *fout, const char *type,
   10191             :                     const char *name, const char *namespace,
   10192             :                     const char *owner, CatalogId catalogId,
   10193             :                     int subid, DumpId dumpId,
   10194             :                     const char *initdb_comment)
   10195             : {
   10196       12546 :     DumpOptions *dopt = fout->dopt;
   10197             :     CommentItem *comments;
   10198             :     int         ncomments;
   10199             : 
   10200             :     /* do nothing, if --no-comments is supplied */
   10201       12546 :     if (dopt->no_comments)
   10202           0 :         return;
   10203             : 
   10204             :     /* Comments are schema not data ... except LO comments are data */
   10205       12546 :     if (strcmp(type, "LARGE OBJECT") != 0)
   10206             :     {
   10207       12448 :         if (!dopt->dumpSchema)
   10208           0 :             return;
   10209             :     }
   10210             :     else
   10211             :     {
   10212             :         /* We do dump LO comments in binary-upgrade mode */
   10213          98 :         if (!dopt->dumpData && !dopt->binary_upgrade)
   10214           0 :             return;
   10215             :     }
   10216             : 
   10217             :     /* Search for comments associated with catalogId, using table */
   10218       12546 :     ncomments = findComments(catalogId.tableoid, catalogId.oid,
   10219             :                              &comments);
   10220             : 
   10221             :     /* Is there one matching the subid? */
   10222       12546 :     while (ncomments > 0)
   10223             :     {
   10224       12462 :         if (comments->objsubid == subid)
   10225       12462 :             break;
   10226           0 :         comments++;
   10227           0 :         ncomments--;
   10228             :     }
   10229             : 
   10230       12546 :     if (initdb_comment != NULL)
   10231             :     {
   10232             :         static CommentItem empty_comment = {.descr = ""};
   10233             : 
   10234             :         /*
   10235             :          * initdb creates this object with a comment.  Skip dumping the
   10236             :          * initdb-provided comment, which would complicate matters for
   10237             :          * non-superuser use of pg_dump.  When the DBA has removed initdb's
   10238             :          * comment, replicate that.
   10239             :          */
   10240         220 :         if (ncomments == 0)
   10241             :         {
   10242           8 :             comments = &empty_comment;
   10243           8 :             ncomments = 1;
   10244             :         }
   10245         212 :         else if (strcmp(comments->descr, initdb_comment) == 0)
   10246         212 :             ncomments = 0;
   10247             :     }
   10248             : 
   10249             :     /* If a comment exists, build COMMENT ON statement */
   10250       12546 :     if (ncomments > 0)
   10251             :     {
   10252       12258 :         PQExpBuffer query = createPQExpBuffer();
   10253       12258 :         PQExpBuffer tag = createPQExpBuffer();
   10254             : 
   10255       12258 :         appendPQExpBuffer(query, "COMMENT ON %s ", type);
   10256       12258 :         if (namespace && *namespace)
   10257       11964 :             appendPQExpBuffer(query, "%s.", fmtId(namespace));
   10258       12258 :         appendPQExpBuffer(query, "%s IS ", name);
   10259       12258 :         appendStringLiteralAH(query, comments->descr, fout);
   10260       12258 :         appendPQExpBufferStr(query, ";\n");
   10261             : 
   10262       12258 :         appendPQExpBuffer(tag, "%s %s", type, name);
   10263             : 
   10264             :         /*
   10265             :          * We mark comments as SECTION_NONE because they really belong in the
   10266             :          * same section as their parent, whether that is pre-data or
   10267             :          * post-data.
   10268             :          */
   10269       12258 :         ArchiveEntry(fout, nilCatalogId, createDumpId(),
   10270       12258 :                      ARCHIVE_OPTS(.tag = tag->data,
   10271             :                                   .namespace = namespace,
   10272             :                                   .owner = owner,
   10273             :                                   .description = "COMMENT",
   10274             :                                   .section = SECTION_NONE,
   10275             :                                   .createStmt = query->data,
   10276             :                                   .deps = &dumpId,
   10277             :                                   .nDeps = 1));
   10278             : 
   10279       12258 :         destroyPQExpBuffer(query);
   10280       12258 :         destroyPQExpBuffer(tag);
   10281             :     }
   10282             : }
   10283             : 
   10284             : /*
   10285             :  * dumpComment --
   10286             :  *
   10287             :  * Typical simplification of the above function.
   10288             :  */
   10289             : static inline void
   10290       12292 : dumpComment(Archive *fout, const char *type,
   10291             :             const char *name, const char *namespace,
   10292             :             const char *owner, CatalogId catalogId,
   10293             :             int subid, DumpId dumpId)
   10294             : {
   10295       12292 :     dumpCommentExtended(fout, type, name, namespace, owner,
   10296             :                         catalogId, subid, dumpId, NULL);
   10297       12292 : }
   10298             : 
   10299             : /*
   10300             :  * dumpTableComment --
   10301             :  *
   10302             :  * As above, but dump comments for both the specified table (or view)
   10303             :  * and its columns.
   10304             :  */
   10305             : static void
   10306         152 : dumpTableComment(Archive *fout, const TableInfo *tbinfo,
   10307             :                  const char *reltypename)
   10308             : {
   10309         152 :     DumpOptions *dopt = fout->dopt;
   10310             :     CommentItem *comments;
   10311             :     int         ncomments;
   10312             :     PQExpBuffer query;
   10313             :     PQExpBuffer tag;
   10314             : 
   10315             :     /* do nothing, if --no-comments is supplied */
   10316         152 :     if (dopt->no_comments)
   10317           0 :         return;
   10318             : 
   10319             :     /* Comments are SCHEMA not data */
   10320         152 :     if (!dopt->dumpSchema)
   10321           0 :         return;
   10322             : 
   10323             :     /* Search for comments associated with relation, using table */
   10324         152 :     ncomments = findComments(tbinfo->dobj.catId.tableoid,
   10325             :                              tbinfo->dobj.catId.oid,
   10326             :                              &comments);
   10327             : 
   10328             :     /* If comments exist, build COMMENT ON statements */
   10329         152 :     if (ncomments <= 0)
   10330           0 :         return;
   10331             : 
   10332         152 :     query = createPQExpBuffer();
   10333         152 :     tag = createPQExpBuffer();
   10334             : 
   10335         436 :     while (ncomments > 0)
   10336             :     {
   10337         284 :         const char *descr = comments->descr;
   10338         284 :         int         objsubid = comments->objsubid;
   10339             : 
   10340         284 :         if (objsubid == 0)
   10341             :         {
   10342          66 :             resetPQExpBuffer(tag);
   10343          66 :             appendPQExpBuffer(tag, "%s %s", reltypename,
   10344          66 :                               fmtId(tbinfo->dobj.name));
   10345             : 
   10346          66 :             resetPQExpBuffer(query);
   10347          66 :             appendPQExpBuffer(query, "COMMENT ON %s %s IS ", reltypename,
   10348          66 :                               fmtQualifiedDumpable(tbinfo));
   10349          66 :             appendStringLiteralAH(query, descr, fout);
   10350          66 :             appendPQExpBufferStr(query, ";\n");
   10351             : 
   10352          66 :             ArchiveEntry(fout, nilCatalogId, createDumpId(),
   10353          66 :                          ARCHIVE_OPTS(.tag = tag->data,
   10354             :                                       .namespace = tbinfo->dobj.namespace->dobj.name,
   10355             :                                       .owner = tbinfo->rolname,
   10356             :                                       .description = "COMMENT",
   10357             :                                       .section = SECTION_NONE,
   10358             :                                       .createStmt = query->data,
   10359             :                                       .deps = &(tbinfo->dobj.dumpId),
   10360             :                                       .nDeps = 1));
   10361             :         }
   10362         218 :         else if (objsubid > 0 && objsubid <= tbinfo->numatts)
   10363             :         {
   10364         218 :             resetPQExpBuffer(tag);
   10365         218 :             appendPQExpBuffer(tag, "COLUMN %s.",
   10366         218 :                               fmtId(tbinfo->dobj.name));
   10367         218 :             appendPQExpBufferStr(tag, fmtId(tbinfo->attnames[objsubid - 1]));
   10368             : 
   10369         218 :             resetPQExpBuffer(query);
   10370         218 :             appendPQExpBuffer(query, "COMMENT ON COLUMN %s.",
   10371         218 :                               fmtQualifiedDumpable(tbinfo));
   10372         218 :             appendPQExpBuffer(query, "%s IS ",
   10373         218 :                               fmtId(tbinfo->attnames[objsubid - 1]));
   10374         218 :             appendStringLiteralAH(query, descr, fout);
   10375         218 :             appendPQExpBufferStr(query, ";\n");
   10376             : 
   10377         218 :             ArchiveEntry(fout, nilCatalogId, createDumpId(),
   10378         218 :                          ARCHIVE_OPTS(.tag = tag->data,
   10379             :                                       .namespace = tbinfo->dobj.namespace->dobj.name,
   10380             :                                       .owner = tbinfo->rolname,
   10381             :                                       .description = "COMMENT",
   10382             :                                       .section = SECTION_NONE,
   10383             :                                       .createStmt = query->data,
   10384             :                                       .deps = &(tbinfo->dobj.dumpId),
   10385             :                                       .nDeps = 1));
   10386             :         }
   10387             : 
   10388         284 :         comments++;
   10389         284 :         ncomments--;
   10390             :     }
   10391             : 
   10392         152 :     destroyPQExpBuffer(query);
   10393         152 :     destroyPQExpBuffer(tag);
   10394             : }
   10395             : 
   10396             : /*
   10397             :  * findComments --
   10398             :  *
   10399             :  * Find the comment(s), if any, associated with the given object.  All the
   10400             :  * objsubid values associated with the given classoid/objoid are found with
   10401             :  * one search.
   10402             :  */
   10403             : static int
   10404       12764 : findComments(Oid classoid, Oid objoid, CommentItem **items)
   10405             : {
   10406       12764 :     CommentItem *middle = NULL;
   10407             :     CommentItem *low;
   10408             :     CommentItem *high;
   10409             :     int         nmatch;
   10410             : 
   10411             :     /*
   10412             :      * Do binary search to find some item matching the object.
   10413             :      */
   10414       12764 :     low = &comments[0];
   10415       12764 :     high = &comments[ncomments - 1];
   10416      127038 :     while (low <= high)
   10417             :     {
   10418      126954 :         middle = low + (high - low) / 2;
   10419             : 
   10420      126954 :         if (classoid < middle->classoid)
   10421       13118 :             high = middle - 1;
   10422      113836 :         else if (classoid > middle->classoid)
   10423       13894 :             low = middle + 1;
   10424       99942 :         else if (objoid < middle->objoid)
   10425       42132 :             high = middle - 1;
   10426       57810 :         else if (objoid > middle->objoid)
   10427       45130 :             low = middle + 1;
   10428             :         else
   10429       12680 :             break;              /* found a match */
   10430             :     }
   10431             : 
   10432       12764 :     if (low > high)              /* no matches */
   10433             :     {
   10434          84 :         *items = NULL;
   10435          84 :         return 0;
   10436             :     }
   10437             : 
   10438             :     /*
   10439             :      * Now determine how many items match the object.  The search loop
   10440             :      * invariant still holds: only items between low and high inclusive could
   10441             :      * match.
   10442             :      */
   10443       12680 :     nmatch = 1;
   10444       12680 :     while (middle > low)
   10445             :     {
   10446        5814 :         if (classoid != middle[-1].classoid ||
   10447        5642 :             objoid != middle[-1].objoid)
   10448             :             break;
   10449           0 :         middle--;
   10450           0 :         nmatch++;
   10451             :     }
   10452             : 
   10453       12680 :     *items = middle;
   10454             : 
   10455       12680 :     middle += nmatch;
   10456       12812 :     while (middle <= high)
   10457             :     {
   10458        6728 :         if (classoid != middle->classoid ||
   10459        6256 :             objoid != middle->objoid)
   10460             :             break;
   10461         132 :         middle++;
   10462         132 :         nmatch++;
   10463             :     }
   10464             : 
   10465       12680 :     return nmatch;
   10466             : }
   10467             : 
   10468             : /*
   10469             :  * collectComments --
   10470             :  *
   10471             :  * Construct a table of all comments available for database objects;
   10472             :  * also set the has-comment component flag for each relevant object.
   10473             :  *
   10474             :  * We used to do per-object queries for the comments, but it's much faster
   10475             :  * to pull them all over at once, and on most databases the memory cost
   10476             :  * isn't high.
   10477             :  *
   10478             :  * The table is sorted by classoid/objid/objsubid for speed in lookup.
   10479             :  */
   10480             : static void
   10481         308 : collectComments(Archive *fout)
   10482             : {
   10483             :     PGresult   *res;
   10484             :     PQExpBuffer query;
   10485             :     int         i_description;
   10486             :     int         i_classoid;
   10487             :     int         i_objoid;
   10488             :     int         i_objsubid;
   10489             :     int         ntups;
   10490             :     int         i;
   10491             :     DumpableObject *dobj;
   10492             : 
   10493         308 :     query = createPQExpBuffer();
   10494             : 
   10495         308 :     appendPQExpBufferStr(query, "SELECT description, classoid, objoid, objsubid "
   10496             :                          "FROM pg_catalog.pg_description "
   10497             :                          "ORDER BY classoid, objoid, objsubid");
   10498             : 
   10499         308 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   10500             : 
   10501             :     /* Construct lookup table containing OIDs in numeric form */
   10502             : 
   10503         308 :     i_description = PQfnumber(res, "description");
   10504         308 :     i_classoid = PQfnumber(res, "classoid");
   10505         308 :     i_objoid = PQfnumber(res, "objoid");
   10506         308 :     i_objsubid = PQfnumber(res, "objsubid");
   10507             : 
   10508         308 :     ntups = PQntuples(res);
   10509             : 
   10510         308 :     comments = (CommentItem *) pg_malloc(ntups * sizeof(CommentItem));
   10511         308 :     ncomments = 0;
   10512         308 :     dobj = NULL;
   10513             : 
   10514     1621102 :     for (i = 0; i < ntups; i++)
   10515             :     {
   10516             :         CatalogId   objId;
   10517             :         int         subid;
   10518             : 
   10519     1620794 :         objId.tableoid = atooid(PQgetvalue(res, i, i_classoid));
   10520     1620794 :         objId.oid = atooid(PQgetvalue(res, i, i_objoid));
   10521     1620794 :         subid = atoi(PQgetvalue(res, i, i_objsubid));
   10522             : 
   10523             :         /* We needn't remember comments that don't match any dumpable object */
   10524     1620794 :         if (dobj == NULL ||
   10525      583810 :             dobj->catId.tableoid != objId.tableoid ||
   10526      579972 :             dobj->catId.oid != objId.oid)
   10527     1620622 :             dobj = findObjectByCatalogId(objId);
   10528     1620794 :         if (dobj == NULL)
   10529     1036688 :             continue;
   10530             : 
   10531             :         /*
   10532             :          * Comments on columns of composite types are linked to the type's
   10533             :          * pg_class entry, but we need to set the DUMP_COMPONENT_COMMENT flag
   10534             :          * in the type's own DumpableObject.
   10535             :          */
   10536      584106 :         if (subid != 0 && dobj->objType == DO_TABLE &&
   10537         372 :             ((TableInfo *) dobj)->relkind == RELKIND_COMPOSITE_TYPE)
   10538          86 :         {
   10539             :             TypeInfo   *cTypeInfo;
   10540             : 
   10541          86 :             cTypeInfo = findTypeByOid(((TableInfo *) dobj)->reltype);
   10542          86 :             if (cTypeInfo)
   10543          86 :                 cTypeInfo->dobj.components |= DUMP_COMPONENT_COMMENT;
   10544             :         }
   10545             :         else
   10546      584020 :             dobj->components |= DUMP_COMPONENT_COMMENT;
   10547             : 
   10548      584106 :         comments[ncomments].descr = pg_strdup(PQgetvalue(res, i, i_description));
   10549      584106 :         comments[ncomments].classoid = objId.tableoid;
   10550      584106 :         comments[ncomments].objoid = objId.oid;
   10551      584106 :         comments[ncomments].objsubid = subid;
   10552      584106 :         ncomments++;
   10553             :     }
   10554             : 
   10555         308 :     PQclear(res);
   10556         308 :     destroyPQExpBuffer(query);
   10557         308 : }
   10558             : 
   10559             : /*
   10560             :  * dumpDumpableObject
   10561             :  *
   10562             :  * This routine and its subsidiaries are responsible for creating
   10563             :  * ArchiveEntries (TOC objects) for each object to be dumped.
   10564             :  */
   10565             : static void
   10566     1126292 : dumpDumpableObject(Archive *fout, DumpableObject *dobj)
   10567             : {
   10568             :     /*
   10569             :      * Clear any dump-request bits for components that don't exist for this
   10570             :      * object.  (This makes it safe to initially use DUMP_COMPONENT_ALL as the
   10571             :      * request for every kind of object.)
   10572             :      */
   10573     1126292 :     dobj->dump &= dobj->components;
   10574             : 
   10575             :     /* Now, short-circuit if there's nothing to be done here. */
   10576     1126292 :     if (dobj->dump == 0)
   10577     1000684 :         return;
   10578             : 
   10579      125608 :     switch (dobj->objType)
   10580             :     {
   10581         784 :         case DO_NAMESPACE:
   10582         784 :             dumpNamespace(fout, (const NamespaceInfo *) dobj);
   10583         784 :             break;
   10584          38 :         case DO_EXTENSION:
   10585          38 :             dumpExtension(fout, (const ExtensionInfo *) dobj);
   10586          38 :             break;
   10587        1672 :         case DO_TYPE:
   10588        1672 :             dumpType(fout, (const TypeInfo *) dobj);
   10589        1672 :             break;
   10590         142 :         case DO_SHELL_TYPE:
   10591         142 :             dumpShellType(fout, (const ShellTypeInfo *) dobj);
   10592         142 :             break;
   10593        3566 :         case DO_FUNC:
   10594        3566 :             dumpFunc(fout, (const FuncInfo *) dobj);
   10595        3566 :             break;
   10596         580 :         case DO_AGG:
   10597         580 :             dumpAgg(fout, (const AggInfo *) dobj);
   10598         580 :             break;
   10599        5004 :         case DO_OPERATOR:
   10600        5004 :             dumpOpr(fout, (const OprInfo *) dobj);
   10601        5004 :             break;
   10602         152 :         case DO_ACCESS_METHOD:
   10603         152 :             dumpAccessMethod(fout, (const AccessMethodInfo *) dobj);
   10604         152 :             break;
   10605        1308 :         case DO_OPCLASS:
   10606        1308 :             dumpOpclass(fout, (const OpclassInfo *) dobj);
   10607        1308 :             break;
   10608        1090 :         case DO_OPFAMILY:
   10609        1090 :             dumpOpfamily(fout, (const OpfamilyInfo *) dobj);
   10610        1090 :             break;
   10611        4928 :         case DO_COLLATION:
   10612        4928 :             dumpCollation(fout, (const CollInfo *) dobj);
   10613        4928 :             break;
   10614         840 :         case DO_CONVERSION:
   10615         840 :             dumpConversion(fout, (const ConvInfo *) dobj);
   10616         840 :             break;
   10617       49984 :         case DO_TABLE:
   10618       49984 :             dumpTable(fout, (const TableInfo *) dobj);
   10619       49984 :             break;
   10620        2496 :         case DO_TABLE_ATTACH:
   10621        2496 :             dumpTableAttach(fout, (const TableAttachInfo *) dobj);
   10622        2496 :             break;
   10623        1520 :         case DO_ATTRDEF:
   10624        1520 :             dumpAttrDef(fout, (const AttrDefInfo *) dobj);
   10625        1520 :             break;
   10626        4740 :         case DO_INDEX:
   10627        4740 :             dumpIndex(fout, (const IndxInfo *) dobj);
   10628        4740 :             break;
   10629        1096 :         case DO_INDEX_ATTACH:
   10630        1096 :             dumpIndexAttach(fout, (const IndexAttachInfo *) dobj);
   10631        1096 :             break;
   10632         254 :         case DO_STATSEXT:
   10633         254 :             dumpStatisticsExt(fout, (const StatsExtInfo *) dobj);
   10634         254 :             break;
   10635         676 :         case DO_REFRESH_MATVIEW:
   10636         676 :             refreshMatViewData(fout, (const TableDataInfo *) dobj);
   10637         676 :             break;
   10638        2150 :         case DO_RULE:
   10639        2150 :             dumpRule(fout, (const RuleInfo *) dobj);
   10640        2150 :             break;
   10641         986 :         case DO_TRIGGER:
   10642         986 :             dumpTrigger(fout, (const TriggerInfo *) dobj);
   10643         986 :             break;
   10644          80 :         case DO_EVENT_TRIGGER:
   10645          80 :             dumpEventTrigger(fout, (const EventTriggerInfo *) dobj);
   10646          80 :             break;
   10647        4052 :         case DO_CONSTRAINT:
   10648        4052 :             dumpConstraint(fout, (const ConstraintInfo *) dobj);
   10649        4052 :             break;
   10650         344 :         case DO_FK_CONSTRAINT:
   10651         344 :             dumpConstraint(fout, (const ConstraintInfo *) dobj);
   10652         344 :             break;
   10653         156 :         case DO_PROCLANG:
   10654         156 :             dumpProcLang(fout, (const ProcLangInfo *) dobj);
   10655         156 :             break;
   10656         130 :         case DO_CAST:
   10657         130 :             dumpCast(fout, (const CastInfo *) dobj);
   10658         130 :             break;
   10659          80 :         case DO_TRANSFORM:
   10660          80 :             dumpTransform(fout, (const TransformInfo *) dobj);
   10661          80 :             break;
   10662         728 :         case DO_SEQUENCE_SET:
   10663         728 :             dumpSequenceData(fout, (const TableDataInfo *) dobj);
   10664         728 :             break;
   10665        7300 :         case DO_TABLE_DATA:
   10666        7300 :             dumpTableData(fout, (const TableDataInfo *) dobj);
   10667        7300 :             break;
   10668       24714 :         case DO_DUMMY_TYPE:
   10669             :             /* table rowtypes and array types are never dumped separately */
   10670       24714 :             break;
   10671          78 :         case DO_TSPARSER:
   10672          78 :             dumpTSParser(fout, (const TSParserInfo *) dobj);
   10673          78 :             break;
   10674         336 :         case DO_TSDICT:
   10675         336 :             dumpTSDictionary(fout, (const TSDictInfo *) dobj);
   10676         336 :             break;
   10677         102 :         case DO_TSTEMPLATE:
   10678         102 :             dumpTSTemplate(fout, (const TSTemplateInfo *) dobj);
   10679         102 :             break;
   10680         286 :         case DO_TSCONFIG:
   10681         286 :             dumpTSConfig(fout, (const TSConfigInfo *) dobj);
   10682         286 :             break;
   10683         100 :         case DO_FDW:
   10684         100 :             dumpForeignDataWrapper(fout, (const FdwInfo *) dobj);
   10685         100 :             break;
   10686         108 :         case DO_FOREIGN_SERVER:
   10687         108 :             dumpForeignServer(fout, (const ForeignServerInfo *) dobj);
   10688         108 :             break;
   10689         284 :         case DO_DEFAULT_ACL:
   10690         284 :             dumpDefaultACL(fout, (const DefaultACLInfo *) dobj);
   10691         284 :             break;
   10692         146 :         case DO_LARGE_OBJECT:
   10693         146 :             dumpLO(fout, (const LoInfo *) dobj);
   10694         146 :             break;
   10695         146 :         case DO_LARGE_OBJECT_DATA:
   10696         146 :             if (dobj->dump & DUMP_COMPONENT_DATA)
   10697             :             {
   10698             :                 LoInfo     *loinfo;
   10699             :                 TocEntry   *te;
   10700             : 
   10701         146 :                 loinfo = (LoInfo *) findObjectByDumpId(dobj->dependencies[0]);
   10702         146 :                 if (loinfo == NULL)
   10703           0 :                     pg_fatal("missing metadata for large objects \"%s\"",
   10704             :                              dobj->name);
   10705             : 
   10706         146 :                 te = ArchiveEntry(fout, dobj->catId, dobj->dumpId,
   10707         146 :                                   ARCHIVE_OPTS(.tag = dobj->name,
   10708             :                                                .owner = loinfo->rolname,
   10709             :                                                .description = "BLOBS",
   10710             :                                                .section = SECTION_DATA,
   10711             :                                                .deps = dobj->dependencies,
   10712             :                                                .nDeps = dobj->nDeps,
   10713             :                                                .dumpFn = dumpLOs,
   10714             :                                                .dumpArg = loinfo));
   10715             : 
   10716             :                 /*
   10717             :                  * Set the TocEntry's dataLength in case we are doing a
   10718             :                  * parallel dump and want to order dump jobs by table size.
   10719             :                  * (We need some size estimate for every TocEntry with a
   10720             :                  * DataDumper function.)  We don't currently have any cheap
   10721             :                  * way to estimate the size of LOs, but fortunately it doesn't
   10722             :                  * matter too much as long as we get large batches of LOs
   10723             :                  * processed reasonably early.  Assume 8K per blob.
   10724             :                  */
   10725         146 :                 te->dataLength = loinfo->numlos * (pgoff_t) 8192;
   10726             :             }
   10727         146 :             break;
   10728         638 :         case DO_POLICY:
   10729         638 :             dumpPolicy(fout, (const PolicyInfo *) dobj);
   10730         638 :             break;
   10731         352 :         case DO_PUBLICATION:
   10732         352 :             dumpPublication(fout, (const PublicationInfo *) dobj);
   10733         352 :             break;
   10734         470 :         case DO_PUBLICATION_REL:
   10735         470 :             dumpPublicationTable(fout, (const PublicationRelInfo *) dobj);
   10736         470 :             break;
   10737         138 :         case DO_PUBLICATION_TABLE_IN_SCHEMA:
   10738         138 :             dumpPublicationNamespace(fout,
   10739             :                                      (const PublicationSchemaInfo *) dobj);
   10740         138 :             break;
   10741         214 :         case DO_SUBSCRIPTION:
   10742         214 :             dumpSubscription(fout, (const SubscriptionInfo *) dobj);
   10743         214 :             break;
   10744           4 :         case DO_SUBSCRIPTION_REL:
   10745           4 :             dumpSubscriptionTable(fout, (const SubRelInfo *) dobj);
   10746           4 :             break;
   10747         616 :         case DO_PRE_DATA_BOUNDARY:
   10748             :         case DO_POST_DATA_BOUNDARY:
   10749             :             /* never dumped, nothing to do */
   10750         616 :             break;
   10751             :     }
   10752             : }
   10753             : 
   10754             : /*
   10755             :  * dumpNamespace
   10756             :  *    writes out to fout the queries to recreate a user-defined namespace
   10757             :  */
   10758             : static void
   10759         784 : dumpNamespace(Archive *fout, const NamespaceInfo *nspinfo)
   10760             : {
   10761         784 :     DumpOptions *dopt = fout->dopt;
   10762             :     PQExpBuffer q;
   10763             :     PQExpBuffer delq;
   10764             :     char       *qnspname;
   10765             : 
   10766             :     /* Do nothing if not dumping schema */
   10767         784 :     if (!dopt->dumpSchema)
   10768          32 :         return;
   10769             : 
   10770         752 :     q = createPQExpBuffer();
   10771         752 :     delq = createPQExpBuffer();
   10772             : 
   10773         752 :     qnspname = pg_strdup(fmtId(nspinfo->dobj.name));
   10774             : 
   10775         752 :     if (nspinfo->create)
   10776             :     {
   10777         508 :         appendPQExpBuffer(delq, "DROP SCHEMA %s;\n", qnspname);
   10778         508 :         appendPQExpBuffer(q, "CREATE SCHEMA %s;\n", qnspname);
   10779             :     }
   10780             :     else
   10781             :     {
   10782             :         /* see selectDumpableNamespace() */
   10783         244 :         appendPQExpBufferStr(delq,
   10784             :                              "-- *not* dropping schema, since initdb creates it\n");
   10785         244 :         appendPQExpBufferStr(q,
   10786             :                              "-- *not* creating schema, since initdb creates it\n");
   10787             :     }
   10788             : 
   10789         752 :     if (dopt->binary_upgrade)
   10790          82 :         binary_upgrade_extension_member(q, &nspinfo->dobj,
   10791             :                                         "SCHEMA", qnspname, NULL);
   10792             : 
   10793         752 :     if (nspinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   10794         326 :         ArchiveEntry(fout, nspinfo->dobj.catId, nspinfo->dobj.dumpId,
   10795         326 :                      ARCHIVE_OPTS(.tag = nspinfo->dobj.name,
   10796             :                                   .owner = nspinfo->rolname,
   10797             :                                   .description = "SCHEMA",
   10798             :                                   .section = SECTION_PRE_DATA,
   10799             :                                   .createStmt = q->data,
   10800             :                                   .dropStmt = delq->data));
   10801             : 
   10802             :     /* Dump Schema Comments and Security Labels */
   10803         752 :     if (nspinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   10804             :     {
   10805         254 :         const char *initdb_comment = NULL;
   10806             : 
   10807         254 :         if (!nspinfo->create && strcmp(qnspname, "public") == 0)
   10808         220 :             initdb_comment = "standard public schema";
   10809         254 :         dumpCommentExtended(fout, "SCHEMA", qnspname,
   10810             :                             NULL, nspinfo->rolname,
   10811             :                             nspinfo->dobj.catId, 0, nspinfo->dobj.dumpId,
   10812             :                             initdb_comment);
   10813             :     }
   10814             : 
   10815         752 :     if (nspinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
   10816           0 :         dumpSecLabel(fout, "SCHEMA", qnspname,
   10817             :                      NULL, nspinfo->rolname,
   10818             :                      nspinfo->dobj.catId, 0, nspinfo->dobj.dumpId);
   10819             : 
   10820         752 :     if (nspinfo->dobj.dump & DUMP_COMPONENT_ACL)
   10821         586 :         dumpACL(fout, nspinfo->dobj.dumpId, InvalidDumpId, "SCHEMA",
   10822             :                 qnspname, NULL, NULL,
   10823             :                 NULL, nspinfo->rolname, &nspinfo->dacl);
   10824             : 
   10825         752 :     free(qnspname);
   10826             : 
   10827         752 :     destroyPQExpBuffer(q);
   10828         752 :     destroyPQExpBuffer(delq);
   10829             : }
   10830             : 
   10831             : /*
   10832             :  * dumpExtension
   10833             :  *    writes out to fout the queries to recreate an extension
   10834             :  */
   10835             : static void
   10836          38 : dumpExtension(Archive *fout, const ExtensionInfo *extinfo)
   10837             : {
   10838          38 :     DumpOptions *dopt = fout->dopt;
   10839             :     PQExpBuffer q;
   10840             :     PQExpBuffer delq;
   10841             :     char       *qextname;
   10842             : 
   10843             :     /* Do nothing if not dumping schema */
   10844          38 :     if (!dopt->dumpSchema)
   10845           2 :         return;
   10846             : 
   10847          36 :     q = createPQExpBuffer();
   10848          36 :     delq = createPQExpBuffer();
   10849             : 
   10850          36 :     qextname = pg_strdup(fmtId(extinfo->dobj.name));
   10851             : 
   10852          36 :     appendPQExpBuffer(delq, "DROP EXTENSION %s;\n", qextname);
   10853             : 
   10854          36 :     if (!dopt->binary_upgrade)
   10855             :     {
   10856             :         /*
   10857             :          * In a regular dump, we simply create the extension, intentionally
   10858             :          * not specifying a version, so that the destination installation's
   10859             :          * default version is used.
   10860             :          *
   10861             :          * Use of IF NOT EXISTS here is unlike our behavior for other object
   10862             :          * types; but there are various scenarios in which it's convenient to
   10863             :          * manually create the desired extension before restoring, so we
   10864             :          * prefer to allow it to exist already.
   10865             :          */
   10866          34 :         appendPQExpBuffer(q, "CREATE EXTENSION IF NOT EXISTS %s WITH SCHEMA %s;\n",
   10867          34 :                           qextname, fmtId(extinfo->namespace));
   10868             :     }
   10869             :     else
   10870             :     {
   10871             :         /*
   10872             :          * In binary-upgrade mode, it's critical to reproduce the state of the
   10873             :          * database exactly, so our procedure is to create an empty extension,
   10874             :          * restore all the contained objects normally, and add them to the
   10875             :          * extension one by one.  This function performs just the first of
   10876             :          * those steps.  binary_upgrade_extension_member() takes care of
   10877             :          * adding member objects as they're created.
   10878             :          */
   10879             :         int         i;
   10880             :         int         n;
   10881             : 
   10882           2 :         appendPQExpBufferStr(q, "-- For binary upgrade, create an empty extension and insert objects into it\n");
   10883             : 
   10884             :         /*
   10885             :          * We unconditionally create the extension, so we must drop it if it
   10886             :          * exists.  This could happen if the user deleted 'plpgsql' and then
   10887             :          * readded it, causing its oid to be greater than g_last_builtin_oid.
   10888             :          */
   10889           2 :         appendPQExpBuffer(q, "DROP EXTENSION IF EXISTS %s;\n", qextname);
   10890             : 
   10891           2 :         appendPQExpBufferStr(q,
   10892             :                              "SELECT pg_catalog.binary_upgrade_create_empty_extension(");
   10893           2 :         appendStringLiteralAH(q, extinfo->dobj.name, fout);
   10894           2 :         appendPQExpBufferStr(q, ", ");
   10895           2 :         appendStringLiteralAH(q, extinfo->namespace, fout);
   10896           2 :         appendPQExpBufferStr(q, ", ");
   10897           2 :         appendPQExpBuffer(q, "%s, ", extinfo->relocatable ? "true" : "false");
   10898           2 :         appendStringLiteralAH(q, extinfo->extversion, fout);
   10899           2 :         appendPQExpBufferStr(q, ", ");
   10900             : 
   10901             :         /*
   10902             :          * Note that we're pushing extconfig (an OID array) back into
   10903             :          * pg_extension exactly as-is.  This is OK because pg_class OIDs are
   10904             :          * preserved in binary upgrade.
   10905             :          */
   10906           2 :         if (strlen(extinfo->extconfig) > 2)
   10907           2 :             appendStringLiteralAH(q, extinfo->extconfig, fout);
   10908             :         else
   10909           0 :             appendPQExpBufferStr(q, "NULL");
   10910           2 :         appendPQExpBufferStr(q, ", ");
   10911           2 :         if (strlen(extinfo->extcondition) > 2)
   10912           2 :             appendStringLiteralAH(q, extinfo->extcondition, fout);
   10913             :         else
   10914           0 :             appendPQExpBufferStr(q, "NULL");
   10915           2 :         appendPQExpBufferStr(q, ", ");
   10916           2 :         appendPQExpBufferStr(q, "ARRAY[");
   10917           2 :         n = 0;
   10918           4 :         for (i = 0; i < extinfo->dobj.nDeps; i++)
   10919             :         {
   10920             :             DumpableObject *extobj;
   10921             : 
   10922           2 :             extobj = findObjectByDumpId(extinfo->dobj.dependencies[i]);
   10923           2 :             if (extobj && extobj->objType == DO_EXTENSION)
   10924             :             {
   10925           0 :                 if (n++ > 0)
   10926           0 :                     appendPQExpBufferChar(q, ',');
   10927           0 :                 appendStringLiteralAH(q, extobj->name, fout);
   10928             :             }
   10929             :         }
   10930           2 :         appendPQExpBufferStr(q, "]::pg_catalog.text[]");
   10931           2 :         appendPQExpBufferStr(q, ");\n");
   10932             :     }
   10933             : 
   10934          36 :     if (extinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   10935          36 :         ArchiveEntry(fout, extinfo->dobj.catId, extinfo->dobj.dumpId,
   10936          36 :                      ARCHIVE_OPTS(.tag = extinfo->dobj.name,
   10937             :                                   .description = "EXTENSION",
   10938             :                                   .section = SECTION_PRE_DATA,
   10939             :                                   .createStmt = q->data,
   10940             :                                   .dropStmt = delq->data));
   10941             : 
   10942             :     /* Dump Extension Comments and Security Labels */
   10943          36 :     if (extinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   10944          36 :         dumpComment(fout, "EXTENSION", qextname,
   10945             :                     NULL, "",
   10946             :                     extinfo->dobj.catId, 0, extinfo->dobj.dumpId);
   10947             : 
   10948          36 :     if (extinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
   10949           0 :         dumpSecLabel(fout, "EXTENSION", qextname,
   10950             :                      NULL, "",
   10951             :                      extinfo->dobj.catId, 0, extinfo->dobj.dumpId);
   10952             : 
   10953          36 :     free(qextname);
   10954             : 
   10955          36 :     destroyPQExpBuffer(q);
   10956          36 :     destroyPQExpBuffer(delq);
   10957             : }
   10958             : 
   10959             : /*
   10960             :  * dumpType
   10961             :  *    writes out to fout the queries to recreate a user-defined type
   10962             :  */
   10963             : static void
   10964        1672 : dumpType(Archive *fout, const TypeInfo *tyinfo)
   10965             : {
   10966        1672 :     DumpOptions *dopt = fout->dopt;
   10967             : 
   10968             :     /* Do nothing if not dumping schema */
   10969        1672 :     if (!dopt->dumpSchema)
   10970          44 :         return;
   10971             : 
   10972             :     /* Dump out in proper style */
   10973        1628 :     if (tyinfo->typtype == TYPTYPE_BASE)
   10974         556 :         dumpBaseType(fout, tyinfo);
   10975        1072 :     else if (tyinfo->typtype == TYPTYPE_DOMAIN)
   10976         266 :         dumpDomain(fout, tyinfo);
   10977         806 :     else if (tyinfo->typtype == TYPTYPE_COMPOSITE)
   10978         262 :         dumpCompositeType(fout, tyinfo);
   10979         544 :     else if (tyinfo->typtype == TYPTYPE_ENUM)
   10980         110 :         dumpEnumType(fout, tyinfo);
   10981         434 :     else if (tyinfo->typtype == TYPTYPE_RANGE)
   10982         208 :         dumpRangeType(fout, tyinfo);
   10983         226 :     else if (tyinfo->typtype == TYPTYPE_PSEUDO && !tyinfo->isDefined)
   10984          76 :         dumpUndefinedType(fout, tyinfo);
   10985             :     else
   10986         150 :         pg_log_warning("typtype of data type \"%s\" appears to be invalid",
   10987             :                        tyinfo->dobj.name);
   10988             : }
   10989             : 
   10990             : /*
   10991             :  * dumpEnumType
   10992             :  *    writes out to fout the queries to recreate a user-defined enum type
   10993             :  */
   10994             : static void
   10995         110 : dumpEnumType(Archive *fout, const TypeInfo *tyinfo)
   10996             : {
   10997         110 :     DumpOptions *dopt = fout->dopt;
   10998         110 :     PQExpBuffer q = createPQExpBuffer();
   10999         110 :     PQExpBuffer delq = createPQExpBuffer();
   11000         110 :     PQExpBuffer query = createPQExpBuffer();
   11001             :     PGresult   *res;
   11002             :     int         num,
   11003             :                 i;
   11004             :     Oid         enum_oid;
   11005             :     char       *qtypname;
   11006             :     char       *qualtypname;
   11007             :     char       *label;
   11008             :     int         i_enumlabel;
   11009             :     int         i_oid;
   11010             : 
   11011         110 :     if (!fout->is_prepared[PREPQUERY_DUMPENUMTYPE])
   11012             :     {
   11013             :         /* Set up query for enum-specific details */
   11014          80 :         appendPQExpBufferStr(query,
   11015             :                              "PREPARE dumpEnumType(pg_catalog.oid) AS\n"
   11016             :                              "SELECT oid, enumlabel "
   11017             :                              "FROM pg_catalog.pg_enum "
   11018             :                              "WHERE enumtypid = $1 "
   11019             :                              "ORDER BY enumsortorder");
   11020             : 
   11021          80 :         ExecuteSqlStatement(fout, query->data);
   11022             : 
   11023          80 :         fout->is_prepared[PREPQUERY_DUMPENUMTYPE] = true;
   11024             :     }
   11025             : 
   11026         110 :     printfPQExpBuffer(query,
   11027             :                       "EXECUTE dumpEnumType('%u')",
   11028             :                       tyinfo->dobj.catId.oid);
   11029             : 
   11030         110 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   11031             : 
   11032         110 :     num = PQntuples(res);
   11033             : 
   11034         110 :     qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
   11035         110 :     qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
   11036             : 
   11037             :     /*
   11038             :      * CASCADE shouldn't be required here as for normal types since the I/O
   11039             :      * functions are generic and do not get dropped.
   11040             :      */
   11041         110 :     appendPQExpBuffer(delq, "DROP TYPE %s;\n", qualtypname);
   11042             : 
   11043         110 :     if (dopt->binary_upgrade)
   11044          10 :         binary_upgrade_set_type_oids_by_type_oid(fout, q,
   11045             :                                                  tyinfo->dobj.catId.oid,
   11046             :                                                  false, false);
   11047             : 
   11048         110 :     appendPQExpBuffer(q, "CREATE TYPE %s AS ENUM (",
   11049             :                       qualtypname);
   11050             : 
   11051         110 :     if (!dopt->binary_upgrade)
   11052             :     {
   11053         100 :         i_enumlabel = PQfnumber(res, "enumlabel");
   11054             : 
   11055             :         /* Labels with server-assigned oids */
   11056         732 :         for (i = 0; i < num; i++)
   11057             :         {
   11058         632 :             label = PQgetvalue(res, i, i_enumlabel);
   11059         632 :             if (i > 0)
   11060         532 :                 appendPQExpBufferChar(q, ',');
   11061         632 :             appendPQExpBufferStr(q, "\n    ");
   11062         632 :             appendStringLiteralAH(q, label, fout);
   11063             :         }
   11064             :     }
   11065             : 
   11066         110 :     appendPQExpBufferStr(q, "\n);\n");
   11067             : 
   11068         110 :     if (dopt->binary_upgrade)
   11069             :     {
   11070          10 :         i_oid = PQfnumber(res, "oid");
   11071          10 :         i_enumlabel = PQfnumber(res, "enumlabel");
   11072             : 
   11073             :         /* Labels with dump-assigned (preserved) oids */
   11074         116 :         for (i = 0; i < num; i++)
   11075             :         {
   11076         106 :             enum_oid = atooid(PQgetvalue(res, i, i_oid));
   11077         106 :             label = PQgetvalue(res, i, i_enumlabel);
   11078             : 
   11079         106 :             if (i == 0)
   11080          10 :                 appendPQExpBufferStr(q, "\n-- For binary upgrade, must preserve pg_enum oids\n");
   11081         106 :             appendPQExpBuffer(q,
   11082             :                               "SELECT pg_catalog.binary_upgrade_set_next_pg_enum_oid('%u'::pg_catalog.oid);\n",
   11083             :                               enum_oid);
   11084         106 :             appendPQExpBuffer(q, "ALTER TYPE %s ADD VALUE ", qualtypname);
   11085         106 :             appendStringLiteralAH(q, label, fout);
   11086         106 :             appendPQExpBufferStr(q, ";\n\n");
   11087             :         }
   11088             :     }
   11089             : 
   11090         110 :     if (dopt->binary_upgrade)
   11091          10 :         binary_upgrade_extension_member(q, &tyinfo->dobj,
   11092             :                                         "TYPE", qtypname,
   11093          10 :                                         tyinfo->dobj.namespace->dobj.name);
   11094             : 
   11095         110 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   11096         110 :         ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
   11097         110 :                      ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
   11098             :                                   .namespace = tyinfo->dobj.namespace->dobj.name,
   11099             :                                   .owner = tyinfo->rolname,
   11100             :                                   .description = "TYPE",
   11101             :                                   .section = SECTION_PRE_DATA,
   11102             :                                   .createStmt = q->data,
   11103             :                                   .dropStmt = delq->data));
   11104             : 
   11105             :     /* Dump Type Comments and Security Labels */
   11106         110 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   11107          66 :         dumpComment(fout, "TYPE", qtypname,
   11108          66 :                     tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
   11109             :                     tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
   11110             : 
   11111         110 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
   11112           0 :         dumpSecLabel(fout, "TYPE", qtypname,
   11113           0 :                      tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
   11114             :                      tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
   11115             : 
   11116         110 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
   11117          66 :         dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
   11118             :                 qtypname, NULL,
   11119          66 :                 tyinfo->dobj.namespace->dobj.name,
   11120             :                 NULL, tyinfo->rolname, &tyinfo->dacl);
   11121             : 
   11122         110 :     PQclear(res);
   11123         110 :     destroyPQExpBuffer(q);
   11124         110 :     destroyPQExpBuffer(delq);
   11125         110 :     destroyPQExpBuffer(query);
   11126         110 :     free(qtypname);
   11127         110 :     free(qualtypname);
   11128         110 : }
   11129             : 
   11130             : /*
   11131             :  * dumpRangeType
   11132             :  *    writes out to fout the queries to recreate a user-defined range type
   11133             :  */
   11134             : static void
   11135         208 : dumpRangeType(Archive *fout, const TypeInfo *tyinfo)
   11136             : {
   11137         208 :     DumpOptions *dopt = fout->dopt;
   11138         208 :     PQExpBuffer q = createPQExpBuffer();
   11139         208 :     PQExpBuffer delq = createPQExpBuffer();
   11140         208 :     PQExpBuffer query = createPQExpBuffer();
   11141             :     PGresult   *res;
   11142             :     Oid         collationOid;
   11143             :     char       *qtypname;
   11144             :     char       *qualtypname;
   11145             :     char       *procname;
   11146             : 
   11147         208 :     if (!fout->is_prepared[PREPQUERY_DUMPRANGETYPE])
   11148             :     {
   11149             :         /* Set up query for range-specific details */
   11150          82 :         appendPQExpBufferStr(query,
   11151             :                              "PREPARE dumpRangeType(pg_catalog.oid) AS\n");
   11152             : 
   11153          82 :         appendPQExpBufferStr(query,
   11154             :                              "SELECT ");
   11155             : 
   11156          82 :         if (fout->remoteVersion >= 140000)
   11157          82 :             appendPQExpBufferStr(query,
   11158             :                                  "pg_catalog.format_type(rngmultitypid, NULL) AS rngmultitype, ");
   11159             :         else
   11160           0 :             appendPQExpBufferStr(query,
   11161             :                                  "NULL AS rngmultitype, ");
   11162             : 
   11163          82 :         appendPQExpBufferStr(query,
   11164             :                              "pg_catalog.format_type(rngsubtype, NULL) AS rngsubtype, "
   11165             :                              "opc.opcname AS opcname, "
   11166             :                              "(SELECT nspname FROM pg_catalog.pg_namespace nsp "
   11167             :                              "  WHERE nsp.oid = opc.opcnamespace) AS opcnsp, "
   11168             :                              "opc.opcdefault, "
   11169             :                              "CASE WHEN rngcollation = st.typcollation THEN 0 "
   11170             :                              "     ELSE rngcollation END AS collation, "
   11171             :                              "rngcanonical, rngsubdiff "
   11172             :                              "FROM pg_catalog.pg_range r, pg_catalog.pg_type st, "
   11173             :                              "     pg_catalog.pg_opclass opc "
   11174             :                              "WHERE st.oid = rngsubtype AND opc.oid = rngsubopc AND "
   11175             :                              "rngtypid = $1");
   11176             : 
   11177          82 :         ExecuteSqlStatement(fout, query->data);
   11178             : 
   11179          82 :         fout->is_prepared[PREPQUERY_DUMPRANGETYPE] = true;
   11180             :     }
   11181             : 
   11182         208 :     printfPQExpBuffer(query,
   11183             :                       "EXECUTE dumpRangeType('%u')",
   11184             :                       tyinfo->dobj.catId.oid);
   11185             : 
   11186         208 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   11187             : 
   11188         208 :     qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
   11189         208 :     qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
   11190             : 
   11191             :     /*
   11192             :      * CASCADE shouldn't be required here as for normal types since the I/O
   11193             :      * functions are generic and do not get dropped.
   11194             :      */
   11195         208 :     appendPQExpBuffer(delq, "DROP TYPE %s;\n", qualtypname);
   11196             : 
   11197         208 :     if (dopt->binary_upgrade)
   11198          12 :         binary_upgrade_set_type_oids_by_type_oid(fout, q,
   11199             :                                                  tyinfo->dobj.catId.oid,
   11200             :                                                  false, true);
   11201             : 
   11202         208 :     appendPQExpBuffer(q, "CREATE TYPE %s AS RANGE (",
   11203             :                       qualtypname);
   11204             : 
   11205         208 :     appendPQExpBuffer(q, "\n    subtype = %s",
   11206             :                       PQgetvalue(res, 0, PQfnumber(res, "rngsubtype")));
   11207             : 
   11208         208 :     if (!PQgetisnull(res, 0, PQfnumber(res, "rngmultitype")))
   11209         208 :         appendPQExpBuffer(q, ",\n    multirange_type_name = %s",
   11210             :                           PQgetvalue(res, 0, PQfnumber(res, "rngmultitype")));
   11211             : 
   11212             :     /* print subtype_opclass only if not default for subtype */
   11213         208 :     if (PQgetvalue(res, 0, PQfnumber(res, "opcdefault"))[0] != 't')
   11214             :     {
   11215          66 :         char       *opcname = PQgetvalue(res, 0, PQfnumber(res, "opcname"));
   11216          66 :         char       *nspname = PQgetvalue(res, 0, PQfnumber(res, "opcnsp"));
   11217             : 
   11218          66 :         appendPQExpBuffer(q, ",\n    subtype_opclass = %s.",
   11219             :                           fmtId(nspname));
   11220          66 :         appendPQExpBufferStr(q, fmtId(opcname));
   11221             :     }
   11222             : 
   11223         208 :     collationOid = atooid(PQgetvalue(res, 0, PQfnumber(res, "collation")));
   11224         208 :     if (OidIsValid(collationOid))
   11225             :     {
   11226          76 :         CollInfo   *coll = findCollationByOid(collationOid);
   11227             : 
   11228          76 :         if (coll)
   11229          76 :             appendPQExpBuffer(q, ",\n    collation = %s",
   11230          76 :                               fmtQualifiedDumpable(coll));
   11231             :     }
   11232             : 
   11233         208 :     procname = PQgetvalue(res, 0, PQfnumber(res, "rngcanonical"));
   11234         208 :     if (strcmp(procname, "-") != 0)
   11235          18 :         appendPQExpBuffer(q, ",\n    canonical = %s", procname);
   11236             : 
   11237         208 :     procname = PQgetvalue(res, 0, PQfnumber(res, "rngsubdiff"));
   11238         208 :     if (strcmp(procname, "-") != 0)
   11239          46 :         appendPQExpBuffer(q, ",\n    subtype_diff = %s", procname);
   11240             : 
   11241         208 :     appendPQExpBufferStr(q, "\n);\n");
   11242             : 
   11243         208 :     if (dopt->binary_upgrade)
   11244          12 :         binary_upgrade_extension_member(q, &tyinfo->dobj,
   11245             :                                         "TYPE", qtypname,
   11246          12 :                                         tyinfo->dobj.namespace->dobj.name);
   11247             : 
   11248         208 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   11249         208 :         ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
   11250         208 :                      ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
   11251             :                                   .namespace = tyinfo->dobj.namespace->dobj.name,
   11252             :                                   .owner = tyinfo->rolname,
   11253             :                                   .description = "TYPE",
   11254             :                                   .section = SECTION_PRE_DATA,
   11255             :                                   .createStmt = q->data,
   11256             :                                   .dropStmt = delq->data));
   11257             : 
   11258             :     /* Dump Type Comments and Security Labels */
   11259         208 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   11260         102 :         dumpComment(fout, "TYPE", qtypname,
   11261         102 :                     tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
   11262             :                     tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
   11263             : 
   11264         208 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
   11265           0 :         dumpSecLabel(fout, "TYPE", qtypname,
   11266           0 :                      tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
   11267             :                      tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
   11268             : 
   11269         208 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
   11270          66 :         dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
   11271             :                 qtypname, NULL,
   11272          66 :                 tyinfo->dobj.namespace->dobj.name,
   11273             :                 NULL, tyinfo->rolname, &tyinfo->dacl);
   11274             : 
   11275         208 :     PQclear(res);
   11276         208 :     destroyPQExpBuffer(q);
   11277         208 :     destroyPQExpBuffer(delq);
   11278         208 :     destroyPQExpBuffer(query);
   11279         208 :     free(qtypname);
   11280         208 :     free(qualtypname);
   11281         208 : }
   11282             : 
   11283             : /*
   11284             :  * dumpUndefinedType
   11285             :  *    writes out to fout the queries to recreate a !typisdefined type
   11286             :  *
   11287             :  * This is a shell type, but we use different terminology to distinguish
   11288             :  * this case from where we have to emit a shell type definition to break
   11289             :  * circular dependencies.  An undefined type shouldn't ever have anything
   11290             :  * depending on it.
   11291             :  */
   11292             : static void
   11293          76 : dumpUndefinedType(Archive *fout, const TypeInfo *tyinfo)
   11294             : {
   11295          76 :     DumpOptions *dopt = fout->dopt;
   11296          76 :     PQExpBuffer q = createPQExpBuffer();
   11297          76 :     PQExpBuffer delq = createPQExpBuffer();
   11298             :     char       *qtypname;
   11299             :     char       *qualtypname;
   11300             : 
   11301          76 :     qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
   11302          76 :     qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
   11303             : 
   11304          76 :     appendPQExpBuffer(delq, "DROP TYPE %s;\n", qualtypname);
   11305             : 
   11306          76 :     if (dopt->binary_upgrade)
   11307           4 :         binary_upgrade_set_type_oids_by_type_oid(fout, q,
   11308             :                                                  tyinfo->dobj.catId.oid,
   11309             :                                                  false, false);
   11310             : 
   11311          76 :     appendPQExpBuffer(q, "CREATE TYPE %s;\n",
   11312             :                       qualtypname);
   11313             : 
   11314          76 :     if (dopt->binary_upgrade)
   11315           4 :         binary_upgrade_extension_member(q, &tyinfo->dobj,
   11316             :                                         "TYPE", qtypname,
   11317           4 :                                         tyinfo->dobj.namespace->dobj.name);
   11318             : 
   11319          76 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   11320          76 :         ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
   11321          76 :                      ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
   11322             :                                   .namespace = tyinfo->dobj.namespace->dobj.name,
   11323             :                                   .owner = tyinfo->rolname,
   11324             :                                   .description = "TYPE",
   11325             :                                   .section = SECTION_PRE_DATA,
   11326             :                                   .createStmt = q->data,
   11327             :                                   .dropStmt = delq->data));
   11328             : 
   11329             :     /* Dump Type Comments and Security Labels */
   11330          76 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   11331          66 :         dumpComment(fout, "TYPE", qtypname,
   11332          66 :                     tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
   11333             :                     tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
   11334             : 
   11335          76 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
   11336           0 :         dumpSecLabel(fout, "TYPE", qtypname,
   11337           0 :                      tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
   11338             :                      tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
   11339             : 
   11340          76 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
   11341           0 :         dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
   11342             :                 qtypname, NULL,
   11343           0 :                 tyinfo->dobj.namespace->dobj.name,
   11344             :                 NULL, tyinfo->rolname, &tyinfo->dacl);
   11345             : 
   11346          76 :     destroyPQExpBuffer(q);
   11347          76 :     destroyPQExpBuffer(delq);
   11348          76 :     free(qtypname);
   11349          76 :     free(qualtypname);
   11350          76 : }
   11351             : 
   11352             : /*
   11353             :  * dumpBaseType
   11354             :  *    writes out to fout the queries to recreate a user-defined base type
   11355             :  */
   11356             : static void
   11357         556 : dumpBaseType(Archive *fout, const TypeInfo *tyinfo)
   11358             : {
   11359         556 :     DumpOptions *dopt = fout->dopt;
   11360         556 :     PQExpBuffer q = createPQExpBuffer();
   11361         556 :     PQExpBuffer delq = createPQExpBuffer();
   11362         556 :     PQExpBuffer query = createPQExpBuffer();
   11363             :     PGresult   *res;
   11364             :     char       *qtypname;
   11365             :     char       *qualtypname;
   11366             :     char       *typlen;
   11367             :     char       *typinput;
   11368             :     char       *typoutput;
   11369             :     char       *typreceive;
   11370             :     char       *typsend;
   11371             :     char       *typmodin;
   11372             :     char       *typmodout;
   11373             :     char       *typanalyze;
   11374             :     char       *typsubscript;
   11375             :     Oid         typreceiveoid;
   11376             :     Oid         typsendoid;
   11377             :     Oid         typmodinoid;
   11378             :     Oid         typmodoutoid;
   11379             :     Oid         typanalyzeoid;
   11380             :     Oid         typsubscriptoid;
   11381             :     char       *typcategory;
   11382             :     char       *typispreferred;
   11383             :     char       *typdelim;
   11384             :     char       *typbyval;
   11385             :     char       *typalign;
   11386             :     char       *typstorage;
   11387             :     char       *typcollatable;
   11388             :     char       *typdefault;
   11389         556 :     bool        typdefault_is_literal = false;
   11390             : 
   11391         556 :     if (!fout->is_prepared[PREPQUERY_DUMPBASETYPE])
   11392             :     {
   11393             :         /* Set up query for type-specific details */
   11394          82 :         appendPQExpBufferStr(query,
   11395             :                              "PREPARE dumpBaseType(pg_catalog.oid) AS\n"
   11396             :                              "SELECT typlen, "
   11397             :                              "typinput, typoutput, typreceive, typsend, "
   11398             :                              "typreceive::pg_catalog.oid AS typreceiveoid, "
   11399             :                              "typsend::pg_catalog.oid AS typsendoid, "
   11400             :                              "typanalyze, "
   11401             :                              "typanalyze::pg_catalog.oid AS typanalyzeoid, "
   11402             :                              "typdelim, typbyval, typalign, typstorage, "
   11403             :                              "typmodin, typmodout, "
   11404             :                              "typmodin::pg_catalog.oid AS typmodinoid, "
   11405             :                              "typmodout::pg_catalog.oid AS typmodoutoid, "
   11406             :                              "typcategory, typispreferred, "
   11407             :                              "(typcollation <> 0) AS typcollatable, "
   11408             :                              "pg_catalog.pg_get_expr(typdefaultbin, 0) AS typdefaultbin, typdefault, ");
   11409             : 
   11410          82 :         if (fout->remoteVersion >= 140000)
   11411          82 :             appendPQExpBufferStr(query,
   11412             :                                  "typsubscript, "
   11413             :                                  "typsubscript::pg_catalog.oid AS typsubscriptoid ");
   11414             :         else
   11415           0 :             appendPQExpBufferStr(query,
   11416             :                                  "'-' AS typsubscript, 0 AS typsubscriptoid ");
   11417             : 
   11418          82 :         appendPQExpBufferStr(query, "FROM pg_catalog.pg_type "
   11419             :                              "WHERE oid = $1");
   11420             : 
   11421          82 :         ExecuteSqlStatement(fout, query->data);
   11422             : 
   11423          82 :         fout->is_prepared[PREPQUERY_DUMPBASETYPE] = true;
   11424             :     }
   11425             : 
   11426         556 :     printfPQExpBuffer(query,
   11427             :                       "EXECUTE dumpBaseType('%u')",
   11428             :                       tyinfo->dobj.catId.oid);
   11429             : 
   11430         556 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   11431             : 
   11432         556 :     typlen = PQgetvalue(res, 0, PQfnumber(res, "typlen"));
   11433         556 :     typinput = PQgetvalue(res, 0, PQfnumber(res, "typinput"));
   11434         556 :     typoutput = PQgetvalue(res, 0, PQfnumber(res, "typoutput"));
   11435         556 :     typreceive = PQgetvalue(res, 0, PQfnumber(res, "typreceive"));
   11436         556 :     typsend = PQgetvalue(res, 0, PQfnumber(res, "typsend"));
   11437         556 :     typmodin = PQgetvalue(res, 0, PQfnumber(res, "typmodin"));
   11438         556 :     typmodout = PQgetvalue(res, 0, PQfnumber(res, "typmodout"));
   11439         556 :     typanalyze = PQgetvalue(res, 0, PQfnumber(res, "typanalyze"));
   11440         556 :     typsubscript = PQgetvalue(res, 0, PQfnumber(res, "typsubscript"));
   11441         556 :     typreceiveoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typreceiveoid")));
   11442         556 :     typsendoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typsendoid")));
   11443         556 :     typmodinoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typmodinoid")));
   11444         556 :     typmodoutoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typmodoutoid")));
   11445         556 :     typanalyzeoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typanalyzeoid")));
   11446         556 :     typsubscriptoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typsubscriptoid")));
   11447         556 :     typcategory = PQgetvalue(res, 0, PQfnumber(res, "typcategory"));
   11448         556 :     typispreferred = PQgetvalue(res, 0, PQfnumber(res, "typispreferred"));
   11449         556 :     typdelim = PQgetvalue(res, 0, PQfnumber(res, "typdelim"));
   11450         556 :     typbyval = PQgetvalue(res, 0, PQfnumber(res, "typbyval"));
   11451         556 :     typalign = PQgetvalue(res, 0, PQfnumber(res, "typalign"));
   11452         556 :     typstorage = PQgetvalue(res, 0, PQfnumber(res, "typstorage"));
   11453         556 :     typcollatable = PQgetvalue(res, 0, PQfnumber(res, "typcollatable"));
   11454         556 :     if (!PQgetisnull(res, 0, PQfnumber(res, "typdefaultbin")))
   11455           0 :         typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefaultbin"));
   11456         556 :     else if (!PQgetisnull(res, 0, PQfnumber(res, "typdefault")))
   11457             :     {
   11458          86 :         typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefault"));
   11459          86 :         typdefault_is_literal = true;   /* it needs quotes */
   11460             :     }
   11461             :     else
   11462         470 :         typdefault = NULL;
   11463             : 
   11464         556 :     qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
   11465         556 :     qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
   11466             : 
   11467             :     /*
   11468             :      * The reason we include CASCADE is that the circular dependency between
   11469             :      * the type and its I/O functions makes it impossible to drop the type any
   11470             :      * other way.
   11471             :      */
   11472         556 :     appendPQExpBuffer(delq, "DROP TYPE %s CASCADE;\n", qualtypname);
   11473             : 
   11474             :     /*
   11475             :      * We might already have a shell type, but setting pg_type_oid is
   11476             :      * harmless, and in any case we'd better set the array type OID.
   11477             :      */
   11478         556 :     if (dopt->binary_upgrade)
   11479          16 :         binary_upgrade_set_type_oids_by_type_oid(fout, q,
   11480             :                                                  tyinfo->dobj.catId.oid,
   11481             :                                                  false, false);
   11482             : 
   11483         556 :     appendPQExpBuffer(q,
   11484             :                       "CREATE TYPE %s (\n"
   11485             :                       "    INTERNALLENGTH = %s",
   11486             :                       qualtypname,
   11487         556 :                       (strcmp(typlen, "-1") == 0) ? "variable" : typlen);
   11488             : 
   11489             :     /* regproc result is sufficiently quoted already */
   11490         556 :     appendPQExpBuffer(q, ",\n    INPUT = %s", typinput);
   11491         556 :     appendPQExpBuffer(q, ",\n    OUTPUT = %s", typoutput);
   11492         556 :     if (OidIsValid(typreceiveoid))
   11493         408 :         appendPQExpBuffer(q, ",\n    RECEIVE = %s", typreceive);
   11494         556 :     if (OidIsValid(typsendoid))
   11495         408 :         appendPQExpBuffer(q, ",\n    SEND = %s", typsend);
   11496         556 :     if (OidIsValid(typmodinoid))
   11497          70 :         appendPQExpBuffer(q, ",\n    TYPMOD_IN = %s", typmodin);
   11498         556 :     if (OidIsValid(typmodoutoid))
   11499          70 :         appendPQExpBuffer(q, ",\n    TYPMOD_OUT = %s", typmodout);
   11500         556 :     if (OidIsValid(typanalyzeoid))
   11501           6 :         appendPQExpBuffer(q, ",\n    ANALYZE = %s", typanalyze);
   11502             : 
   11503         556 :     if (strcmp(typcollatable, "t") == 0)
   11504          60 :         appendPQExpBufferStr(q, ",\n    COLLATABLE = true");
   11505             : 
   11506         556 :     if (typdefault != NULL)
   11507             :     {
   11508          86 :         appendPQExpBufferStr(q, ",\n    DEFAULT = ");
   11509          86 :         if (typdefault_is_literal)
   11510          86 :             appendStringLiteralAH(q, typdefault, fout);
   11511             :         else
   11512           0 :             appendPQExpBufferStr(q, typdefault);
   11513             :     }
   11514             : 
   11515         556 :     if (OidIsValid(typsubscriptoid))
   11516          58 :         appendPQExpBuffer(q, ",\n    SUBSCRIPT = %s", typsubscript);
   11517             : 
   11518         556 :     if (OidIsValid(tyinfo->typelem))
   11519          52 :         appendPQExpBuffer(q, ",\n    ELEMENT = %s",
   11520             :                           getFormattedTypeName(fout, tyinfo->typelem,
   11521             :                                                zeroIsError));
   11522             : 
   11523         556 :     if (strcmp(typcategory, "U") != 0)
   11524             :     {
   11525         310 :         appendPQExpBufferStr(q, ",\n    CATEGORY = ");
   11526         310 :         appendStringLiteralAH(q, typcategory, fout);
   11527             :     }
   11528             : 
   11529         556 :     if (strcmp(typispreferred, "t") == 0)
   11530          58 :         appendPQExpBufferStr(q, ",\n    PREFERRED = true");
   11531             : 
   11532         556 :     if (typdelim && strcmp(typdelim, ",") != 0)
   11533             :     {
   11534           6 :         appendPQExpBufferStr(q, ",\n    DELIMITER = ");
   11535           6 :         appendStringLiteralAH(q, typdelim, fout);
   11536             :     }
   11537             : 
   11538         556 :     if (*typalign == TYPALIGN_CHAR)
   11539          24 :         appendPQExpBufferStr(q, ",\n    ALIGNMENT = char");
   11540         532 :     else if (*typalign == TYPALIGN_SHORT)
   11541          12 :         appendPQExpBufferStr(q, ",\n    ALIGNMENT = int2");
   11542         520 :     else if (*typalign == TYPALIGN_INT)
   11543         370 :         appendPQExpBufferStr(q, ",\n    ALIGNMENT = int4");
   11544         150 :     else if (*typalign == TYPALIGN_DOUBLE)
   11545         150 :         appendPQExpBufferStr(q, ",\n    ALIGNMENT = double");
   11546             : 
   11547         556 :     if (*typstorage == TYPSTORAGE_PLAIN)
   11548         406 :         appendPQExpBufferStr(q, ",\n    STORAGE = plain");
   11549         150 :     else if (*typstorage == TYPSTORAGE_EXTERNAL)
   11550           0 :         appendPQExpBufferStr(q, ",\n    STORAGE = external");
   11551         150 :     else if (*typstorage == TYPSTORAGE_EXTENDED)
   11552         132 :         appendPQExpBufferStr(q, ",\n    STORAGE = extended");
   11553          18 :     else if (*typstorage == TYPSTORAGE_MAIN)
   11554          18 :         appendPQExpBufferStr(q, ",\n    STORAGE = main");
   11555             : 
   11556         556 :     if (strcmp(typbyval, "t") == 0)
   11557         264 :         appendPQExpBufferStr(q, ",\n    PASSEDBYVALUE");
   11558             : 
   11559         556 :     appendPQExpBufferStr(q, "\n);\n");
   11560             : 
   11561         556 :     if (dopt->binary_upgrade)
   11562          16 :         binary_upgrade_extension_member(q, &tyinfo->dobj,
   11563             :                                         "TYPE", qtypname,
   11564          16 :                                         tyinfo->dobj.namespace->dobj.name);
   11565             : 
   11566         556 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   11567         556 :         ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
   11568         556 :                      ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
   11569             :                                   .namespace = tyinfo->dobj.namespace->dobj.name,
   11570             :                                   .owner = tyinfo->rolname,
   11571             :                                   .description = "TYPE",
   11572             :                                   .section = SECTION_PRE_DATA,
   11573             :                                   .createStmt = q->data,
   11574             :                                   .dropStmt = delq->data));
   11575             : 
   11576             :     /* Dump Type Comments and Security Labels */
   11577         556 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   11578         486 :         dumpComment(fout, "TYPE", qtypname,
   11579         486 :                     tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
   11580             :                     tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
   11581             : 
   11582         556 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
   11583           0 :         dumpSecLabel(fout, "TYPE", qtypname,
   11584           0 :                      tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
   11585             :                      tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
   11586             : 
   11587         556 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
   11588          66 :         dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
   11589             :                 qtypname, NULL,
   11590          66 :                 tyinfo->dobj.namespace->dobj.name,
   11591             :                 NULL, tyinfo->rolname, &tyinfo->dacl);
   11592             : 
   11593         556 :     PQclear(res);
   11594         556 :     destroyPQExpBuffer(q);
   11595         556 :     destroyPQExpBuffer(delq);
   11596         556 :     destroyPQExpBuffer(query);
   11597         556 :     free(qtypname);
   11598         556 :     free(qualtypname);
   11599         556 : }
   11600             : 
   11601             : /*
   11602             :  * dumpDomain
   11603             :  *    writes out to fout the queries to recreate a user-defined domain
   11604             :  */
   11605             : static void
   11606         266 : dumpDomain(Archive *fout, const TypeInfo *tyinfo)
   11607             : {
   11608         266 :     DumpOptions *dopt = fout->dopt;
   11609         266 :     PQExpBuffer q = createPQExpBuffer();
   11610         266 :     PQExpBuffer delq = createPQExpBuffer();
   11611         266 :     PQExpBuffer query = createPQExpBuffer();
   11612             :     PGresult   *res;
   11613             :     int         i;
   11614             :     char       *qtypname;
   11615             :     char       *qualtypname;
   11616             :     char       *typnotnull;
   11617             :     char       *typdefn;
   11618             :     char       *typdefault;
   11619             :     Oid         typcollation;
   11620         266 :     bool        typdefault_is_literal = false;
   11621             : 
   11622         266 :     if (!fout->is_prepared[PREPQUERY_DUMPDOMAIN])
   11623             :     {
   11624             :         /* Set up query for domain-specific details */
   11625          76 :         appendPQExpBufferStr(query,
   11626             :                              "PREPARE dumpDomain(pg_catalog.oid) AS\n");
   11627             : 
   11628          76 :         appendPQExpBufferStr(query, "SELECT t.typnotnull, "
   11629             :                              "pg_catalog.format_type(t.typbasetype, t.typtypmod) AS typdefn, "
   11630             :                              "pg_catalog.pg_get_expr(t.typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, "
   11631             :                              "t.typdefault, "
   11632             :                              "CASE WHEN t.typcollation <> u.typcollation "
   11633             :                              "THEN t.typcollation ELSE 0 END AS typcollation "
   11634             :                              "FROM pg_catalog.pg_type t "
   11635             :                              "LEFT JOIN pg_catalog.pg_type u ON (t.typbasetype = u.oid) "
   11636             :                              "WHERE t.oid = $1");
   11637             : 
   11638          76 :         ExecuteSqlStatement(fout, query->data);
   11639             : 
   11640          76 :         fout->is_prepared[PREPQUERY_DUMPDOMAIN] = true;
   11641             :     }
   11642             : 
   11643         266 :     printfPQExpBuffer(query,
   11644             :                       "EXECUTE dumpDomain('%u')",
   11645             :                       tyinfo->dobj.catId.oid);
   11646             : 
   11647         266 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   11648             : 
   11649         266 :     typnotnull = PQgetvalue(res, 0, PQfnumber(res, "typnotnull"));
   11650         266 :     typdefn = PQgetvalue(res, 0, PQfnumber(res, "typdefn"));
   11651         266 :     if (!PQgetisnull(res, 0, PQfnumber(res, "typdefaultbin")))
   11652          76 :         typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefaultbin"));
   11653         190 :     else if (!PQgetisnull(res, 0, PQfnumber(res, "typdefault")))
   11654             :     {
   11655           0 :         typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefault"));
   11656           0 :         typdefault_is_literal = true;   /* it needs quotes */
   11657             :     }
   11658             :     else
   11659         190 :         typdefault = NULL;
   11660         266 :     typcollation = atooid(PQgetvalue(res, 0, PQfnumber(res, "typcollation")));
   11661             : 
   11662         266 :     if (dopt->binary_upgrade)
   11663          42 :         binary_upgrade_set_type_oids_by_type_oid(fout, q,
   11664             :                                                  tyinfo->dobj.catId.oid,
   11665             :                                                  true,  /* force array type */
   11666             :                                                  false);    /* force multirange type */
   11667             : 
   11668         266 :     qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
   11669         266 :     qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
   11670             : 
   11671         266 :     appendPQExpBuffer(q,
   11672             :                       "CREATE DOMAIN %s AS %s",
   11673             :                       qualtypname,
   11674             :                       typdefn);
   11675             : 
   11676             :     /* Print collation only if different from base type's collation */
   11677         266 :     if (OidIsValid(typcollation))
   11678             :     {
   11679             :         CollInfo   *coll;
   11680             : 
   11681          66 :         coll = findCollationByOid(typcollation);
   11682          66 :         if (coll)
   11683          66 :             appendPQExpBuffer(q, " COLLATE %s", fmtQualifiedDumpable(coll));
   11684             :     }
   11685             : 
   11686         266 :     if (typnotnull[0] == 't')
   11687          30 :         appendPQExpBufferStr(q, " NOT NULL");
   11688             : 
   11689         266 :     if (typdefault != NULL)
   11690             :     {
   11691          76 :         appendPQExpBufferStr(q, " DEFAULT ");
   11692          76 :         if (typdefault_is_literal)
   11693           0 :             appendStringLiteralAH(q, typdefault, fout);
   11694             :         else
   11695          76 :             appendPQExpBufferStr(q, typdefault);
   11696             :     }
   11697             : 
   11698         266 :     PQclear(res);
   11699             : 
   11700             :     /*
   11701             :      * Add any CHECK constraints for the domain
   11702             :      */
   11703         442 :     for (i = 0; i < tyinfo->nDomChecks; i++)
   11704             :     {
   11705         176 :         ConstraintInfo *domcheck = &(tyinfo->domChecks[i]);
   11706             : 
   11707         176 :         if (!domcheck->separate)
   11708         176 :             appendPQExpBuffer(q, "\n\tCONSTRAINT %s %s",
   11709         176 :                               fmtId(domcheck->dobj.name), domcheck->condef);
   11710             :     }
   11711             : 
   11712         266 :     appendPQExpBufferStr(q, ";\n");
   11713             : 
   11714         266 :     appendPQExpBuffer(delq, "DROP DOMAIN %s;\n", qualtypname);
   11715             : 
   11716         266 :     if (dopt->binary_upgrade)
   11717          42 :         binary_upgrade_extension_member(q, &tyinfo->dobj,
   11718             :                                         "DOMAIN", qtypname,
   11719          42 :                                         tyinfo->dobj.namespace->dobj.name);
   11720             : 
   11721         266 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   11722         266 :         ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
   11723         266 :                      ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
   11724             :                                   .namespace = tyinfo->dobj.namespace->dobj.name,
   11725             :                                   .owner = tyinfo->rolname,
   11726             :                                   .description = "DOMAIN",
   11727             :                                   .section = SECTION_PRE_DATA,
   11728             :                                   .createStmt = q->data,
   11729             :                                   .dropStmt = delq->data));
   11730             : 
   11731             :     /* Dump Domain Comments and Security Labels */
   11732         266 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   11733           0 :         dumpComment(fout, "DOMAIN", qtypname,
   11734           0 :                     tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
   11735             :                     tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
   11736             : 
   11737         266 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
   11738           0 :         dumpSecLabel(fout, "DOMAIN", qtypname,
   11739           0 :                      tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
   11740             :                      tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
   11741             : 
   11742         266 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
   11743          66 :         dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
   11744             :                 qtypname, NULL,
   11745          66 :                 tyinfo->dobj.namespace->dobj.name,
   11746             :                 NULL, tyinfo->rolname, &tyinfo->dacl);
   11747             : 
   11748             :     /* Dump any per-constraint comments */
   11749         442 :     for (i = 0; i < tyinfo->nDomChecks; i++)
   11750             :     {
   11751         176 :         ConstraintInfo *domcheck = &(tyinfo->domChecks[i]);
   11752         176 :         PQExpBuffer conprefix = createPQExpBuffer();
   11753             : 
   11754         176 :         appendPQExpBuffer(conprefix, "CONSTRAINT %s ON DOMAIN",
   11755         176 :                           fmtId(domcheck->dobj.name));
   11756             : 
   11757         176 :         if (domcheck->dobj.dump & DUMP_COMPONENT_COMMENT)
   11758          66 :             dumpComment(fout, conprefix->data, qtypname,
   11759          66 :                         tyinfo->dobj.namespace->dobj.name,
   11760             :                         tyinfo->rolname,
   11761             :                         domcheck->dobj.catId, 0, tyinfo->dobj.dumpId);
   11762             : 
   11763         176 :         destroyPQExpBuffer(conprefix);
   11764             :     }
   11765             : 
   11766         266 :     destroyPQExpBuffer(q);
   11767         266 :     destroyPQExpBuffer(delq);
   11768         266 :     destroyPQExpBuffer(query);
   11769         266 :     free(qtypname);
   11770         266 :     free(qualtypname);
   11771         266 : }
   11772             : 
   11773             : /*
   11774             :  * dumpCompositeType
   11775             :  *    writes out to fout the queries to recreate a user-defined stand-alone
   11776             :  *    composite type
   11777             :  */
   11778             : static void
   11779         262 : dumpCompositeType(Archive *fout, const TypeInfo *tyinfo)
   11780             : {
   11781         262 :     DumpOptions *dopt = fout->dopt;
   11782         262 :     PQExpBuffer q = createPQExpBuffer();
   11783         262 :     PQExpBuffer dropped = createPQExpBuffer();
   11784         262 :     PQExpBuffer delq = createPQExpBuffer();
   11785         262 :     PQExpBuffer query = createPQExpBuffer();
   11786             :     PGresult   *res;
   11787             :     char       *qtypname;
   11788             :     char       *qualtypname;
   11789             :     int         ntups;
   11790             :     int         i_attname;
   11791             :     int         i_atttypdefn;
   11792             :     int         i_attlen;
   11793             :     int         i_attalign;
   11794             :     int         i_attisdropped;
   11795             :     int         i_attcollation;
   11796             :     int         i;
   11797             :     int         actual_atts;
   11798             : 
   11799         262 :     if (!fout->is_prepared[PREPQUERY_DUMPCOMPOSITETYPE])
   11800             :     {
   11801             :         /*
   11802             :          * Set up query for type-specific details.
   11803             :          *
   11804             :          * Since we only want to dump COLLATE clauses for attributes whose
   11805             :          * collation is different from their type's default, we use a CASE
   11806             :          * here to suppress uninteresting attcollations cheaply.  atttypid
   11807             :          * will be 0 for dropped columns; collation does not matter for those.
   11808             :          */
   11809         112 :         appendPQExpBufferStr(query,
   11810             :                              "PREPARE dumpCompositeType(pg_catalog.oid) AS\n"
   11811             :                              "SELECT a.attname, a.attnum, "
   11812             :                              "pg_catalog.format_type(a.atttypid, a.atttypmod) AS atttypdefn, "
   11813             :                              "a.attlen, a.attalign, a.attisdropped, "
   11814             :                              "CASE WHEN a.attcollation <> at.typcollation "
   11815             :                              "THEN a.attcollation ELSE 0 END AS attcollation "
   11816             :                              "FROM pg_catalog.pg_type ct "
   11817             :                              "JOIN pg_catalog.pg_attribute a ON a.attrelid = ct.typrelid "
   11818             :                              "LEFT JOIN pg_catalog.pg_type at ON at.oid = a.atttypid "
   11819             :                              "WHERE ct.oid = $1 "
   11820             :                              "ORDER BY a.attnum");
   11821             : 
   11822         112 :         ExecuteSqlStatement(fout, query->data);
   11823             : 
   11824         112 :         fout->is_prepared[PREPQUERY_DUMPCOMPOSITETYPE] = true;
   11825             :     }
   11826             : 
   11827         262 :     printfPQExpBuffer(query,
   11828             :                       "EXECUTE dumpCompositeType('%u')",
   11829             :                       tyinfo->dobj.catId.oid);
   11830             : 
   11831         262 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   11832             : 
   11833         262 :     ntups = PQntuples(res);
   11834             : 
   11835         262 :     i_attname = PQfnumber(res, "attname");
   11836         262 :     i_atttypdefn = PQfnumber(res, "atttypdefn");
   11837         262 :     i_attlen = PQfnumber(res, "attlen");
   11838         262 :     i_attalign = PQfnumber(res, "attalign");
   11839         262 :     i_attisdropped = PQfnumber(res, "attisdropped");
   11840         262 :     i_attcollation = PQfnumber(res, "attcollation");
   11841             : 
   11842         262 :     if (dopt->binary_upgrade)
   11843             :     {
   11844          36 :         binary_upgrade_set_type_oids_by_type_oid(fout, q,
   11845             :                                                  tyinfo->dobj.catId.oid,
   11846             :                                                  false, false);
   11847          36 :         binary_upgrade_set_pg_class_oids(fout, q, tyinfo->typrelid);
   11848             :     }
   11849             : 
   11850         262 :     qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
   11851         262 :     qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
   11852             : 
   11853         262 :     appendPQExpBuffer(q, "CREATE TYPE %s AS (",
   11854             :                       qualtypname);
   11855             : 
   11856         262 :     actual_atts = 0;
   11857         830 :     for (i = 0; i < ntups; i++)
   11858             :     {
   11859             :         char       *attname;
   11860             :         char       *atttypdefn;
   11861             :         char       *attlen;
   11862             :         char       *attalign;
   11863             :         bool        attisdropped;
   11864             :         Oid         attcollation;
   11865             : 
   11866         568 :         attname = PQgetvalue(res, i, i_attname);
   11867         568 :         atttypdefn = PQgetvalue(res, i, i_atttypdefn);
   11868         568 :         attlen = PQgetvalue(res, i, i_attlen);
   11869         568 :         attalign = PQgetvalue(res, i, i_attalign);
   11870         568 :         attisdropped = (PQgetvalue(res, i, i_attisdropped)[0] == 't');
   11871         568 :         attcollation = atooid(PQgetvalue(res, i, i_attcollation));
   11872             : 
   11873         568 :         if (attisdropped && !dopt->binary_upgrade)
   11874          16 :             continue;
   11875             : 
   11876             :         /* Format properly if not first attr */
   11877         552 :         if (actual_atts++ > 0)
   11878         290 :             appendPQExpBufferChar(q, ',');
   11879         552 :         appendPQExpBufferStr(q, "\n\t");
   11880             : 
   11881         552 :         if (!attisdropped)
   11882             :         {
   11883         548 :             appendPQExpBuffer(q, "%s %s", fmtId(attname), atttypdefn);
   11884             : 
   11885             :             /* Add collation if not default for the column type */
   11886         548 :             if (OidIsValid(attcollation))
   11887             :             {
   11888             :                 CollInfo   *coll;
   11889             : 
   11890           0 :                 coll = findCollationByOid(attcollation);
   11891           0 :                 if (coll)
   11892           0 :                     appendPQExpBuffer(q, " COLLATE %s",
   11893           0 :                                       fmtQualifiedDumpable(coll));
   11894             :             }
   11895             :         }
   11896             :         else
   11897             :         {
   11898             :             /*
   11899             :              * This is a dropped attribute and we're in binary_upgrade mode.
   11900             :              * Insert a placeholder for it in the CREATE TYPE command, and set
   11901             :              * length and alignment with direct UPDATE to the catalogs
   11902             :              * afterwards. See similar code in dumpTableSchema().
   11903             :              */
   11904           4 :             appendPQExpBuffer(q, "%s INTEGER /* dummy */", fmtId(attname));
   11905             : 
   11906             :             /* stash separately for insertion after the CREATE TYPE */
   11907           4 :             appendPQExpBufferStr(dropped,
   11908             :                                  "\n-- For binary upgrade, recreate dropped column.\n");
   11909           4 :             appendPQExpBuffer(dropped, "UPDATE pg_catalog.pg_attribute\n"
   11910             :                               "SET attlen = %s, "
   11911             :                               "attalign = '%s', attbyval = false\n"
   11912             :                               "WHERE attname = ", attlen, attalign);
   11913           4 :             appendStringLiteralAH(dropped, attname, fout);
   11914           4 :             appendPQExpBufferStr(dropped, "\n  AND attrelid = ");
   11915           4 :             appendStringLiteralAH(dropped, qualtypname, fout);
   11916           4 :             appendPQExpBufferStr(dropped, "::pg_catalog.regclass;\n");
   11917             : 
   11918           4 :             appendPQExpBuffer(dropped, "ALTER TYPE %s ",
   11919             :                               qualtypname);
   11920           4 :             appendPQExpBuffer(dropped, "DROP ATTRIBUTE %s;\n",
   11921             :                               fmtId(attname));
   11922             :         }
   11923             :     }
   11924         262 :     appendPQExpBufferStr(q, "\n);\n");
   11925         262 :     appendPQExpBufferStr(q, dropped->data);
   11926             : 
   11927         262 :     appendPQExpBuffer(delq, "DROP TYPE %s;\n", qualtypname);
   11928             : 
   11929         262 :     if (dopt->binary_upgrade)
   11930          36 :         binary_upgrade_extension_member(q, &tyinfo->dobj,
   11931             :                                         "TYPE", qtypname,
   11932          36 :                                         tyinfo->dobj.namespace->dobj.name);
   11933             : 
   11934         262 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   11935         228 :         ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
   11936         228 :                      ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
   11937             :                                   .namespace = tyinfo->dobj.namespace->dobj.name,
   11938             :                                   .owner = tyinfo->rolname,
   11939             :                                   .description = "TYPE",
   11940             :                                   .section = SECTION_PRE_DATA,
   11941             :                                   .createStmt = q->data,
   11942             :                                   .dropStmt = delq->data));
   11943             : 
   11944             : 
   11945             :     /* Dump Type Comments and Security Labels */
   11946         262 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   11947          66 :         dumpComment(fout, "TYPE", qtypname,
   11948          66 :                     tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
   11949             :                     tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
   11950             : 
   11951         262 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
   11952           0 :         dumpSecLabel(fout, "TYPE", qtypname,
   11953           0 :                      tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
   11954             :                      tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
   11955             : 
   11956         262 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
   11957          36 :         dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
   11958             :                 qtypname, NULL,
   11959          36 :                 tyinfo->dobj.namespace->dobj.name,
   11960             :                 NULL, tyinfo->rolname, &tyinfo->dacl);
   11961             : 
   11962             :     /* Dump any per-column comments */
   11963         262 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   11964          66 :         dumpCompositeTypeColComments(fout, tyinfo, res);
   11965             : 
   11966         262 :     PQclear(res);
   11967         262 :     destroyPQExpBuffer(q);
   11968         262 :     destroyPQExpBuffer(dropped);
   11969         262 :     destroyPQExpBuffer(delq);
   11970         262 :     destroyPQExpBuffer(query);
   11971         262 :     free(qtypname);
   11972         262 :     free(qualtypname);
   11973         262 : }
   11974             : 
   11975             : /*
   11976             :  * dumpCompositeTypeColComments
   11977             :  *    writes out to fout the queries to recreate comments on the columns of
   11978             :  *    a user-defined stand-alone composite type.
   11979             :  *
   11980             :  * The caller has already made a query to collect the names and attnums
   11981             :  * of the type's columns, so we just pass that result into here rather
   11982             :  * than reading them again.
   11983             :  */
   11984             : static void
   11985          66 : dumpCompositeTypeColComments(Archive *fout, const TypeInfo *tyinfo,
   11986             :                              PGresult *res)
   11987             : {
   11988             :     CommentItem *comments;
   11989             :     int         ncomments;
   11990             :     PQExpBuffer query;
   11991             :     PQExpBuffer target;
   11992             :     int         i;
   11993             :     int         ntups;
   11994             :     int         i_attname;
   11995             :     int         i_attnum;
   11996             :     int         i_attisdropped;
   11997             : 
   11998             :     /* do nothing, if --no-comments is supplied */
   11999          66 :     if (fout->dopt->no_comments)
   12000           0 :         return;
   12001             : 
   12002             :     /* Search for comments associated with type's pg_class OID */
   12003          66 :     ncomments = findComments(RelationRelationId, tyinfo->typrelid,
   12004             :                              &comments);
   12005             : 
   12006             :     /* If no comments exist, we're done */
   12007          66 :     if (ncomments <= 0)
   12008           0 :         return;
   12009             : 
   12010             :     /* Build COMMENT ON statements */
   12011          66 :     query = createPQExpBuffer();
   12012          66 :     target = createPQExpBuffer();
   12013             : 
   12014          66 :     ntups = PQntuples(res);
   12015          66 :     i_attnum = PQfnumber(res, "attnum");
   12016          66 :     i_attname = PQfnumber(res, "attname");
   12017          66 :     i_attisdropped = PQfnumber(res, "attisdropped");
   12018         132 :     while (ncomments > 0)
   12019             :     {
   12020             :         const char *attname;
   12021             : 
   12022          66 :         attname = NULL;
   12023          66 :         for (i = 0; i < ntups; i++)
   12024             :         {
   12025          66 :             if (atoi(PQgetvalue(res, i, i_attnum)) == comments->objsubid &&
   12026          66 :                 PQgetvalue(res, i, i_attisdropped)[0] != 't')
   12027             :             {
   12028          66 :                 attname = PQgetvalue(res, i, i_attname);
   12029          66 :                 break;
   12030             :             }
   12031             :         }
   12032          66 :         if (attname)            /* just in case we don't find it */
   12033             :         {
   12034          66 :             const char *descr = comments->descr;
   12035             : 
   12036          66 :             resetPQExpBuffer(target);
   12037          66 :             appendPQExpBuffer(target, "COLUMN %s.",
   12038          66 :                               fmtId(tyinfo->dobj.name));
   12039          66 :             appendPQExpBufferStr(target, fmtId(attname));
   12040             : 
   12041          66 :             resetPQExpBuffer(query);
   12042          66 :             appendPQExpBuffer(query, "COMMENT ON COLUMN %s.",
   12043          66 :                               fmtQualifiedDumpable(tyinfo));
   12044          66 :             appendPQExpBuffer(query, "%s IS ", fmtId(attname));
   12045          66 :             appendStringLiteralAH(query, descr, fout);
   12046          66 :             appendPQExpBufferStr(query, ";\n");
   12047             : 
   12048          66 :             ArchiveEntry(fout, nilCatalogId, createDumpId(),
   12049          66 :                          ARCHIVE_OPTS(.tag = target->data,
   12050             :                                       .namespace = tyinfo->dobj.namespace->dobj.name,
   12051             :                                       .owner = tyinfo->rolname,
   12052             :                                       .description = "COMMENT",
   12053             :                                       .section = SECTION_NONE,
   12054             :                                       .createStmt = query->data,
   12055             :                                       .deps = &(tyinfo->dobj.dumpId),
   12056             :                                       .nDeps = 1));
   12057             :         }
   12058             : 
   12059          66 :         comments++;
   12060          66 :         ncomments--;
   12061             :     }
   12062             : 
   12063          66 :     destroyPQExpBuffer(query);
   12064          66 :     destroyPQExpBuffer(target);
   12065             : }
   12066             : 
   12067             : /*
   12068             :  * dumpShellType
   12069             :  *    writes out to fout the queries to create a shell type
   12070             :  *
   12071             :  * We dump a shell definition in advance of the I/O functions for the type.
   12072             :  */
   12073             : static void
   12074         142 : dumpShellType(Archive *fout, const ShellTypeInfo *stinfo)
   12075             : {
   12076         142 :     DumpOptions *dopt = fout->dopt;
   12077             :     PQExpBuffer q;
   12078             : 
   12079             :     /* Do nothing if not dumping schema */
   12080         142 :     if (!dopt->dumpSchema)
   12081           6 :         return;
   12082             : 
   12083         136 :     q = createPQExpBuffer();
   12084             : 
   12085             :     /*
   12086             :      * Note the lack of a DROP command for the shell type; any required DROP
   12087             :      * is driven off the base type entry, instead.  This interacts with
   12088             :      * _printTocEntry()'s use of the presence of a DROP command to decide
   12089             :      * whether an entry needs an ALTER OWNER command.  We don't want to alter
   12090             :      * the shell type's owner immediately on creation; that should happen only
   12091             :      * after it's filled in, otherwise the backend complains.
   12092             :      */
   12093             : 
   12094         136 :     if (dopt->binary_upgrade)
   12095          16 :         binary_upgrade_set_type_oids_by_type_oid(fout, q,
   12096          16 :                                                  stinfo->baseType->dobj.catId.oid,
   12097             :                                                  false, false);
   12098             : 
   12099         136 :     appendPQExpBuffer(q, "CREATE TYPE %s;\n",
   12100         136 :                       fmtQualifiedDumpable(stinfo));
   12101             : 
   12102         136 :     if (stinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   12103         136 :         ArchiveEntry(fout, stinfo->dobj.catId, stinfo->dobj.dumpId,
   12104         136 :                      ARCHIVE_OPTS(.tag = stinfo->dobj.name,
   12105             :                                   .namespace = stinfo->dobj.namespace->dobj.name,
   12106             :                                   .owner = stinfo->baseType->rolname,
   12107             :                                   .description = "SHELL TYPE",
   12108             :                                   .section = SECTION_PRE_DATA,
   12109             :                                   .createStmt = q->data));
   12110             : 
   12111         136 :     destroyPQExpBuffer(q);
   12112             : }
   12113             : 
   12114             : /*
   12115             :  * dumpProcLang
   12116             :  *        writes out to fout the queries to recreate a user-defined
   12117             :  *        procedural language
   12118             :  */
   12119             : static void
   12120         156 : dumpProcLang(Archive *fout, const ProcLangInfo *plang)
   12121             : {
   12122         156 :     DumpOptions *dopt = fout->dopt;
   12123             :     PQExpBuffer defqry;
   12124             :     PQExpBuffer delqry;
   12125             :     bool        useParams;
   12126             :     char       *qlanname;
   12127             :     FuncInfo   *funcInfo;
   12128         156 :     FuncInfo   *inlineInfo = NULL;
   12129         156 :     FuncInfo   *validatorInfo = NULL;
   12130             : 
   12131             :     /* Do nothing if not dumping schema */
   12132         156 :     if (!dopt->dumpSchema)
   12133          14 :         return;
   12134             : 
   12135             :     /*
   12136             :      * Try to find the support function(s).  It is not an error if we don't
   12137             :      * find them --- if the functions are in the pg_catalog schema, as is
   12138             :      * standard in 8.1 and up, then we won't have loaded them. (In this case
   12139             :      * we will emit a parameterless CREATE LANGUAGE command, which will
   12140             :      * require PL template knowledge in the backend to reload.)
   12141             :      */
   12142             : 
   12143         142 :     funcInfo = findFuncByOid(plang->lanplcallfoid);
   12144         142 :     if (funcInfo != NULL && !funcInfo->dobj.dump)
   12145           4 :         funcInfo = NULL;        /* treat not-dumped same as not-found */
   12146             : 
   12147         142 :     if (OidIsValid(plang->laninline))
   12148             :     {
   12149          78 :         inlineInfo = findFuncByOid(plang->laninline);
   12150          78 :         if (inlineInfo != NULL && !inlineInfo->dobj.dump)
   12151           2 :             inlineInfo = NULL;
   12152             :     }
   12153             : 
   12154         142 :     if (OidIsValid(plang->lanvalidator))
   12155             :     {
   12156          78 :         validatorInfo = findFuncByOid(plang->lanvalidator);
   12157          78 :         if (validatorInfo != NULL && !validatorInfo->dobj.dump)
   12158           2 :             validatorInfo = NULL;
   12159             :     }
   12160             : 
   12161             :     /*
   12162             :      * If the functions are dumpable then emit a complete CREATE LANGUAGE with
   12163             :      * parameters.  Otherwise, we'll write a parameterless command, which will
   12164             :      * be interpreted as CREATE EXTENSION.
   12165             :      */
   12166          62 :     useParams = (funcInfo != NULL &&
   12167         266 :                  (inlineInfo != NULL || !OidIsValid(plang->laninline)) &&
   12168          62 :                  (validatorInfo != NULL || !OidIsValid(plang->lanvalidator)));
   12169             : 
   12170         142 :     defqry = createPQExpBuffer();
   12171         142 :     delqry = createPQExpBuffer();
   12172             : 
   12173         142 :     qlanname = pg_strdup(fmtId(plang->dobj.name));
   12174             : 
   12175         142 :     appendPQExpBuffer(delqry, "DROP PROCEDURAL LANGUAGE %s;\n",
   12176             :                       qlanname);
   12177             : 
   12178         142 :     if (useParams)
   12179             :     {
   12180          62 :         appendPQExpBuffer(defqry, "CREATE %sPROCEDURAL LANGUAGE %s",
   12181          62 :                           plang->lanpltrusted ? "TRUSTED " : "",
   12182             :                           qlanname);
   12183          62 :         appendPQExpBuffer(defqry, " HANDLER %s",
   12184          62 :                           fmtQualifiedDumpable(funcInfo));
   12185          62 :         if (OidIsValid(plang->laninline))
   12186           0 :             appendPQExpBuffer(defqry, " INLINE %s",
   12187           0 :                               fmtQualifiedDumpable(inlineInfo));
   12188          62 :         if (OidIsValid(plang->lanvalidator))
   12189           0 :             appendPQExpBuffer(defqry, " VALIDATOR %s",
   12190           0 :                               fmtQualifiedDumpable(validatorInfo));
   12191             :     }
   12192             :     else
   12193             :     {
   12194             :         /*
   12195             :          * If not dumping parameters, then use CREATE OR REPLACE so that the
   12196             :          * command will not fail if the language is preinstalled in the target
   12197             :          * database.
   12198             :          *
   12199             :          * Modern servers will interpret this as CREATE EXTENSION IF NOT
   12200             :          * EXISTS; perhaps we should emit that instead?  But it might just add
   12201             :          * confusion.
   12202             :          */
   12203          80 :         appendPQExpBuffer(defqry, "CREATE OR REPLACE PROCEDURAL LANGUAGE %s",
   12204             :                           qlanname);
   12205             :     }
   12206         142 :     appendPQExpBufferStr(defqry, ";\n");
   12207             : 
   12208         142 :     if (dopt->binary_upgrade)
   12209           4 :         binary_upgrade_extension_member(defqry, &plang->dobj,
   12210             :                                         "LANGUAGE", qlanname, NULL);
   12211             : 
   12212         142 :     if (plang->dobj.dump & DUMP_COMPONENT_DEFINITION)
   12213          64 :         ArchiveEntry(fout, plang->dobj.catId, plang->dobj.dumpId,
   12214          64 :                      ARCHIVE_OPTS(.tag = plang->dobj.name,
   12215             :                                   .owner = plang->lanowner,
   12216             :                                   .description = "PROCEDURAL LANGUAGE",
   12217             :                                   .section = SECTION_PRE_DATA,
   12218             :                                   .createStmt = defqry->data,
   12219             :                                   .dropStmt = delqry->data,
   12220             :                                   ));
   12221             : 
   12222             :     /* Dump Proc Lang Comments and Security Labels */
   12223         142 :     if (plang->dobj.dump & DUMP_COMPONENT_COMMENT)
   12224           0 :         dumpComment(fout, "LANGUAGE", qlanname,
   12225             :                     NULL, plang->lanowner,
   12226             :                     plang->dobj.catId, 0, plang->dobj.dumpId);
   12227             : 
   12228         142 :     if (plang->dobj.dump & DUMP_COMPONENT_SECLABEL)
   12229           0 :         dumpSecLabel(fout, "LANGUAGE", qlanname,
   12230             :                      NULL, plang->lanowner,
   12231             :                      plang->dobj.catId, 0, plang->dobj.dumpId);
   12232             : 
   12233         142 :     if (plang->lanpltrusted && plang->dobj.dump & DUMP_COMPONENT_ACL)
   12234          78 :         dumpACL(fout, plang->dobj.dumpId, InvalidDumpId, "LANGUAGE",
   12235             :                 qlanname, NULL, NULL,
   12236             :                 NULL, plang->lanowner, &plang->dacl);
   12237             : 
   12238         142 :     free(qlanname);
   12239             : 
   12240         142 :     destroyPQExpBuffer(defqry);
   12241         142 :     destroyPQExpBuffer(delqry);
   12242             : }
   12243             : 
   12244             : /*
   12245             :  * format_function_arguments: generate function name and argument list
   12246             :  *
   12247             :  * This is used when we can rely on pg_get_function_arguments to format
   12248             :  * the argument list.  Note, however, that pg_get_function_arguments
   12249             :  * does not special-case zero-argument aggregates.
   12250             :  */
   12251             : static char *
   12252        8148 : format_function_arguments(const FuncInfo *finfo, const char *funcargs, bool is_agg)
   12253             : {
   12254             :     PQExpBufferData fn;
   12255             : 
   12256        8148 :     initPQExpBuffer(&fn);
   12257        8148 :     appendPQExpBufferStr(&fn, fmtId(finfo->dobj.name));
   12258        8148 :     if (is_agg && finfo->nargs == 0)
   12259         160 :         appendPQExpBufferStr(&fn, "(*)");
   12260             :     else
   12261        7988 :         appendPQExpBuffer(&fn, "(%s)", funcargs);
   12262        8148 :     return fn.data;
   12263             : }
   12264             : 
   12265             : /*
   12266             :  * format_function_signature: generate function name and argument list
   12267             :  *
   12268             :  * Only a minimal list of input argument types is generated; this is
   12269             :  * sufficient to reference the function, but not to define it.
   12270             :  *
   12271             :  * If honor_quotes is false then the function name is never quoted.
   12272             :  * This is appropriate for use in TOC tags, but not in SQL commands.
   12273             :  */
   12274             : static char *
   12275        4296 : format_function_signature(Archive *fout, const FuncInfo *finfo, bool honor_quotes)
   12276             : {
   12277             :     PQExpBufferData fn;
   12278             :     int         j;
   12279             : 
   12280        4296 :     initPQExpBuffer(&fn);
   12281        4296 :     if (honor_quotes)
   12282         794 :         appendPQExpBuffer(&fn, "%s(", fmtId(finfo->dobj.name));
   12283             :     else
   12284        3502 :         appendPQExpBuffer(&fn, "%s(", finfo->dobj.name);
   12285        7904 :     for (j = 0; j < finfo->nargs; j++)
   12286             :     {
   12287        3608 :         if (j > 0)
   12288         844 :             appendPQExpBufferStr(&fn, ", ");
   12289             : 
   12290        3608 :         appendPQExpBufferStr(&fn,
   12291        3608 :                              getFormattedTypeName(fout, finfo->argtypes[j],
   12292             :                                                   zeroIsError));
   12293             :     }
   12294        4296 :     appendPQExpBufferChar(&fn, ')');
   12295        4296 :     return fn.data;
   12296             : }
   12297             : 
   12298             : 
   12299             : /*
   12300             :  * dumpFunc:
   12301             :  *    dump out one function
   12302             :  */
   12303             : static void
   12304        3566 : dumpFunc(Archive *fout, const FuncInfo *finfo)
   12305             : {
   12306        3566 :     DumpOptions *dopt = fout->dopt;
   12307             :     PQExpBuffer query;
   12308             :     PQExpBuffer q;
   12309             :     PQExpBuffer delqry;
   12310             :     PQExpBuffer asPart;
   12311             :     PGresult   *res;
   12312             :     char       *funcsig;        /* identity signature */
   12313        3566 :     char       *funcfullsig = NULL; /* full signature */
   12314             :     char       *funcsig_tag;
   12315             :     char       *qual_funcsig;
   12316             :     char       *proretset;
   12317             :     char       *prosrc;
   12318             :     char       *probin;
   12319             :     char       *prosqlbody;
   12320             :     char       *funcargs;
   12321             :     char       *funciargs;
   12322             :     char       *funcresult;
   12323             :     char       *protrftypes;
   12324             :     char       *prokind;
   12325             :     char       *provolatile;
   12326             :     char       *proisstrict;
   12327             :     char       *prosecdef;
   12328             :     char       *proleakproof;
   12329             :     char       *proconfig;
   12330             :     char       *procost;
   12331             :     char       *prorows;
   12332             :     char       *prosupport;
   12333             :     char       *proparallel;
   12334             :     char       *lanname;
   12335        3566 :     char      **configitems = NULL;
   12336        3566 :     int         nconfigitems = 0;
   12337             :     const char *keyword;
   12338             : 
   12339             :     /* Do nothing if not dumping schema */
   12340        3566 :     if (!dopt->dumpSchema)
   12341          64 :         return;
   12342             : 
   12343        3502 :     query = createPQExpBuffer();
   12344        3502 :     q = createPQExpBuffer();
   12345        3502 :     delqry = createPQExpBuffer();
   12346        3502 :     asPart = createPQExpBuffer();
   12347             : 
   12348        3502 :     if (!fout->is_prepared[PREPQUERY_DUMPFUNC])
   12349             :     {
   12350             :         /* Set up query for function-specific details */
   12351         124 :         appendPQExpBufferStr(query,
   12352             :                              "PREPARE dumpFunc(pg_catalog.oid) AS\n");
   12353             : 
   12354         124 :         appendPQExpBufferStr(query,
   12355             :                              "SELECT\n"
   12356             :                              "proretset,\n"
   12357             :                              "prosrc,\n"
   12358             :                              "probin,\n"
   12359             :                              "provolatile,\n"
   12360             :                              "proisstrict,\n"
   12361             :                              "prosecdef,\n"
   12362             :                              "lanname,\n"
   12363             :                              "proconfig,\n"
   12364             :                              "procost,\n"
   12365             :                              "prorows,\n"
   12366             :                              "pg_catalog.pg_get_function_arguments(p.oid) AS funcargs,\n"
   12367             :                              "pg_catalog.pg_get_function_identity_arguments(p.oid) AS funciargs,\n"
   12368             :                              "pg_catalog.pg_get_function_result(p.oid) AS funcresult,\n"
   12369             :                              "proleakproof,\n");
   12370             : 
   12371         124 :         if (fout->remoteVersion >= 90500)
   12372         124 :             appendPQExpBufferStr(query,
   12373             :                                  "array_to_string(protrftypes, ' ') AS protrftypes,\n");
   12374             :         else
   12375           0 :             appendPQExpBufferStr(query,
   12376             :                                  "NULL AS protrftypes,\n");
   12377             : 
   12378         124 :         if (fout->remoteVersion >= 90600)
   12379         124 :             appendPQExpBufferStr(query,
   12380             :                                  "proparallel,\n");
   12381             :         else
   12382           0 :             appendPQExpBufferStr(query,
   12383             :                                  "'u' AS proparallel,\n");
   12384             : 
   12385         124 :         if (fout->remoteVersion >= 110000)
   12386         124 :             appendPQExpBufferStr(query,
   12387             :                                  "prokind,\n");
   12388             :         else
   12389           0 :             appendPQExpBufferStr(query,
   12390             :                                  "CASE WHEN proiswindow THEN 'w' ELSE 'f' END AS prokind,\n");
   12391             : 
   12392         124 :         if (fout->remoteVersion >= 120000)
   12393         124 :             appendPQExpBufferStr(query,
   12394             :                                  "prosupport,\n");
   12395             :         else
   12396           0 :             appendPQExpBufferStr(query,
   12397             :                                  "'-' AS prosupport,\n");
   12398             : 
   12399         124 :         if (fout->remoteVersion >= 140000)
   12400         124 :             appendPQExpBufferStr(query,
   12401             :                                  "pg_get_function_sqlbody(p.oid) AS prosqlbody\n");
   12402             :         else
   12403           0 :             appendPQExpBufferStr(query,
   12404             :                                  "NULL AS prosqlbody\n");
   12405             : 
   12406         124 :         appendPQExpBufferStr(query,
   12407             :                              "FROM pg_catalog.pg_proc p, pg_catalog.pg_language l\n"
   12408             :                              "WHERE p.oid = $1 "
   12409             :                              "AND l.oid = p.prolang");
   12410             : 
   12411         124 :         ExecuteSqlStatement(fout, query->data);
   12412             : 
   12413         124 :         fout->is_prepared[PREPQUERY_DUMPFUNC] = true;
   12414             :     }
   12415             : 
   12416        3502 :     printfPQExpBuffer(query,
   12417             :                       "EXECUTE dumpFunc('%u')",
   12418             :                       finfo->dobj.catId.oid);
   12419             : 
   12420        3502 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   12421             : 
   12422        3502 :     proretset = PQgetvalue(res, 0, PQfnumber(res, "proretset"));
   12423        3502 :     if (PQgetisnull(res, 0, PQfnumber(res, "prosqlbody")))
   12424             :     {
   12425        3404 :         prosrc = PQgetvalue(res, 0, PQfnumber(res, "prosrc"));
   12426        3404 :         probin = PQgetvalue(res, 0, PQfnumber(res, "probin"));
   12427        3404 :         prosqlbody = NULL;
   12428             :     }
   12429             :     else
   12430             :     {
   12431          98 :         prosrc = NULL;
   12432          98 :         probin = NULL;
   12433          98 :         prosqlbody = PQgetvalue(res, 0, PQfnumber(res, "prosqlbody"));
   12434             :     }
   12435        3502 :     funcargs = PQgetvalue(res, 0, PQfnumber(res, "funcargs"));
   12436        3502 :     funciargs = PQgetvalue(res, 0, PQfnumber(res, "funciargs"));
   12437        3502 :     funcresult = PQgetvalue(res, 0, PQfnumber(res, "funcresult"));
   12438        3502 :     protrftypes = PQgetvalue(res, 0, PQfnumber(res, "protrftypes"));
   12439        3502 :     prokind = PQgetvalue(res, 0, PQfnumber(res, "prokind"));
   12440        3502 :     provolatile = PQgetvalue(res, 0, PQfnumber(res, "provolatile"));
   12441        3502 :     proisstrict = PQgetvalue(res, 0, PQfnumber(res, "proisstrict"));
   12442        3502 :     prosecdef = PQgetvalue(res, 0, PQfnumber(res, "prosecdef"));
   12443        3502 :     proleakproof = PQgetvalue(res, 0, PQfnumber(res, "proleakproof"));
   12444        3502 :     proconfig = PQgetvalue(res, 0, PQfnumber(res, "proconfig"));
   12445        3502 :     procost = PQgetvalue(res, 0, PQfnumber(res, "procost"));
   12446        3502 :     prorows = PQgetvalue(res, 0, PQfnumber(res, "prorows"));
   12447        3502 :     prosupport = PQgetvalue(res, 0, PQfnumber(res, "prosupport"));
   12448        3502 :     proparallel = PQgetvalue(res, 0, PQfnumber(res, "proparallel"));
   12449        3502 :     lanname = PQgetvalue(res, 0, PQfnumber(res, "lanname"));
   12450             : 
   12451             :     /*
   12452             :      * See backend/commands/functioncmds.c for details of how the 'AS' clause
   12453             :      * is used.
   12454             :      */
   12455        3502 :     if (prosqlbody)
   12456             :     {
   12457          98 :         appendPQExpBufferStr(asPart, prosqlbody);
   12458             :     }
   12459        3404 :     else if (probin[0] != '\0')
   12460             :     {
   12461         286 :         appendPQExpBufferStr(asPart, "AS ");
   12462         286 :         appendStringLiteralAH(asPart, probin, fout);
   12463         286 :         if (prosrc[0] != '\0')
   12464             :         {
   12465         286 :             appendPQExpBufferStr(asPart, ", ");
   12466             : 
   12467             :             /*
   12468             :              * where we have bin, use dollar quoting if allowed and src
   12469             :              * contains quote or backslash; else use regular quoting.
   12470             :              */
   12471         286 :             if (dopt->disable_dollar_quoting ||
   12472         286 :                 (strchr(prosrc, '\'') == NULL && strchr(prosrc, '\\') == NULL))
   12473         286 :                 appendStringLiteralAH(asPart, prosrc, fout);
   12474             :             else
   12475           0 :                 appendStringLiteralDQ(asPart, prosrc, NULL);
   12476             :         }
   12477             :     }
   12478             :     else
   12479             :     {
   12480        3118 :         appendPQExpBufferStr(asPart, "AS ");
   12481             :         /* with no bin, dollar quote src unconditionally if allowed */
   12482        3118 :         if (dopt->disable_dollar_quoting)
   12483           0 :             appendStringLiteralAH(asPart, prosrc, fout);
   12484             :         else
   12485        3118 :             appendStringLiteralDQ(asPart, prosrc, NULL);
   12486             :     }
   12487             : 
   12488        3502 :     if (*proconfig)
   12489             :     {
   12490          30 :         if (!parsePGArray(proconfig, &configitems, &nconfigitems))
   12491           0 :             pg_fatal("could not parse %s array", "proconfig");
   12492             :     }
   12493             :     else
   12494             :     {
   12495        3472 :         configitems = NULL;
   12496        3472 :         nconfigitems = 0;
   12497             :     }
   12498             : 
   12499        3502 :     funcfullsig = format_function_arguments(finfo, funcargs, false);
   12500        3502 :     funcsig = format_function_arguments(finfo, funciargs, false);
   12501             : 
   12502        3502 :     funcsig_tag = format_function_signature(fout, finfo, false);
   12503             : 
   12504        3502 :     qual_funcsig = psprintf("%s.%s",
   12505        3502 :                             fmtId(finfo->dobj.namespace->dobj.name),
   12506             :                             funcsig);
   12507             : 
   12508        3502 :     if (prokind[0] == PROKIND_PROCEDURE)
   12509         186 :         keyword = "PROCEDURE";
   12510             :     else
   12511        3316 :         keyword = "FUNCTION"; /* works for window functions too */
   12512             : 
   12513        3502 :     appendPQExpBuffer(delqry, "DROP %s %s;\n",
   12514             :                       keyword, qual_funcsig);
   12515             : 
   12516        7004 :     appendPQExpBuffer(q, "CREATE %s %s.%s",
   12517             :                       keyword,
   12518        3502 :                       fmtId(finfo->dobj.namespace->dobj.name),
   12519             :                       funcfullsig ? funcfullsig :
   12520             :                       funcsig);
   12521             : 
   12522        3502 :     if (prokind[0] == PROKIND_PROCEDURE)
   12523             :          /* no result type to output */ ;
   12524        3316 :     else if (funcresult)
   12525        3316 :         appendPQExpBuffer(q, " RETURNS %s", funcresult);
   12526             :     else
   12527           0 :         appendPQExpBuffer(q, " RETURNS %s%s",
   12528           0 :                           (proretset[0] == 't') ? "SETOF " : "",
   12529             :                           getFormattedTypeName(fout, finfo->prorettype,
   12530             :                                                zeroIsError));
   12531             : 
   12532        3502 :     appendPQExpBuffer(q, "\n    LANGUAGE %s", fmtId(lanname));
   12533             : 
   12534        3502 :     if (*protrftypes)
   12535             :     {
   12536           0 :         Oid        *typeids = pg_malloc(FUNC_MAX_ARGS * sizeof(Oid));
   12537             :         int         i;
   12538             : 
   12539           0 :         appendPQExpBufferStr(q, " TRANSFORM ");
   12540           0 :         parseOidArray(protrftypes, typeids, FUNC_MAX_ARGS);
   12541           0 :         for (i = 0; typeids[i]; i++)
   12542             :         {
   12543           0 :             if (i != 0)
   12544           0 :                 appendPQExpBufferStr(q, ", ");
   12545           0 :             appendPQExpBuffer(q, "FOR TYPE %s",
   12546           0 :                               getFormattedTypeName(fout, typeids[i], zeroAsNone));
   12547             :         }
   12548             : 
   12549           0 :         free(typeids);
   12550             :     }
   12551             : 
   12552        3502 :     if (prokind[0] == PROKIND_WINDOW)
   12553          10 :         appendPQExpBufferStr(q, " WINDOW");
   12554             : 
   12555        3502 :     if (provolatile[0] != PROVOLATILE_VOLATILE)
   12556             :     {
   12557         696 :         if (provolatile[0] == PROVOLATILE_IMMUTABLE)
   12558         664 :             appendPQExpBufferStr(q, " IMMUTABLE");
   12559          32 :         else if (provolatile[0] == PROVOLATILE_STABLE)
   12560          32 :             appendPQExpBufferStr(q, " STABLE");
   12561           0 :         else if (provolatile[0] != PROVOLATILE_VOLATILE)
   12562           0 :             pg_fatal("unrecognized provolatile value for function \"%s\"",
   12563             :                      finfo->dobj.name);
   12564             :     }
   12565             : 
   12566        3502 :     if (proisstrict[0] == 't')
   12567         702 :         appendPQExpBufferStr(q, " STRICT");
   12568             : 
   12569        3502 :     if (prosecdef[0] == 't')
   12570           0 :         appendPQExpBufferStr(q, " SECURITY DEFINER");
   12571             : 
   12572        3502 :     if (proleakproof[0] == 't')
   12573          20 :         appendPQExpBufferStr(q, " LEAKPROOF");
   12574             : 
   12575             :     /*
   12576             :      * COST and ROWS are emitted only if present and not default, so as not to
   12577             :      * break backwards-compatibility of the dump without need.  Keep this code
   12578             :      * in sync with the defaults in functioncmds.c.
   12579             :      */
   12580        3502 :     if (strcmp(procost, "0") != 0)
   12581             :     {
   12582        3502 :         if (strcmp(lanname, "internal") == 0 || strcmp(lanname, "c") == 0)
   12583             :         {
   12584             :             /* default cost is 1 */
   12585         752 :             if (strcmp(procost, "1") != 0)
   12586           0 :                 appendPQExpBuffer(q, " COST %s", procost);
   12587             :         }
   12588             :         else
   12589             :         {
   12590             :             /* default cost is 100 */
   12591        2750 :             if (strcmp(procost, "100") != 0)
   12592          12 :                 appendPQExpBuffer(q, " COST %s", procost);
   12593             :         }
   12594             :     }
   12595        3502 :     if (proretset[0] == 't' &&
   12596         376 :         strcmp(prorows, "0") != 0 && strcmp(prorows, "1000") != 0)
   12597           0 :         appendPQExpBuffer(q, " ROWS %s", prorows);
   12598             : 
   12599        3502 :     if (strcmp(prosupport, "-") != 0)
   12600             :     {
   12601             :         /* We rely on regprocout to provide quoting and qualification */
   12602          86 :         appendPQExpBuffer(q, " SUPPORT %s", prosupport);
   12603             :     }
   12604             : 
   12605        3502 :     if (proparallel[0] != PROPARALLEL_UNSAFE)
   12606             :     {
   12607         236 :         if (proparallel[0] == PROPARALLEL_SAFE)
   12608         226 :             appendPQExpBufferStr(q, " PARALLEL SAFE");
   12609          10 :         else if (proparallel[0] == PROPARALLEL_RESTRICTED)
   12610          10 :             appendPQExpBufferStr(q, " PARALLEL RESTRICTED");
   12611           0 :         else if (proparallel[0] != PROPARALLEL_UNSAFE)
   12612           0 :             pg_fatal("unrecognized proparallel value for function \"%s\"",
   12613             :                      finfo->dobj.name);
   12614             :     }
   12615             : 
   12616        3572 :     for (int i = 0; i < nconfigitems; i++)
   12617             :     {
   12618             :         /* we feel free to scribble on configitems[] here */
   12619          70 :         char       *configitem = configitems[i];
   12620             :         char       *pos;
   12621             : 
   12622          70 :         pos = strchr(configitem, '=');
   12623          70 :         if (pos == NULL)
   12624           0 :             continue;
   12625          70 :         *pos++ = '\0';
   12626          70 :         appendPQExpBuffer(q, "\n    SET %s TO ", fmtId(configitem));
   12627             : 
   12628             :         /*
   12629             :          * Variables that are marked GUC_LIST_QUOTE were already fully quoted
   12630             :          * by flatten_set_variable_args() before they were put into the
   12631             :          * proconfig array.  However, because the quoting rules used there
   12632             :          * aren't exactly like SQL's, we have to break the list value apart
   12633             :          * and then quote the elements as string literals.  (The elements may
   12634             :          * be double-quoted as-is, but we can't just feed them to the SQL
   12635             :          * parser; it would do the wrong thing with elements that are
   12636             :          * zero-length or longer than NAMEDATALEN.)
   12637             :          *
   12638             :          * Variables that are not so marked should just be emitted as simple
   12639             :          * string literals.  If the variable is not known to
   12640             :          * variable_is_guc_list_quote(), we'll do that; this makes it unsafe
   12641             :          * to use GUC_LIST_QUOTE for extension variables.
   12642             :          */
   12643          70 :         if (variable_is_guc_list_quote(configitem))
   12644             :         {
   12645             :             char      **namelist;
   12646             :             char      **nameptr;
   12647             : 
   12648             :             /* Parse string into list of identifiers */
   12649             :             /* this shouldn't fail really */
   12650          20 :             if (SplitGUCList(pos, ',', &namelist))
   12651             :             {
   12652          70 :                 for (nameptr = namelist; *nameptr; nameptr++)
   12653             :                 {
   12654          50 :                     if (nameptr != namelist)
   12655          30 :                         appendPQExpBufferStr(q, ", ");
   12656          50 :                     appendStringLiteralAH(q, *nameptr, fout);
   12657             :                 }
   12658             :             }
   12659          20 :             pg_free(namelist);
   12660             :         }
   12661             :         else
   12662          50 :             appendStringLiteralAH(q, pos, fout);
   12663             :     }
   12664             : 
   12665        3502 :     appendPQExpBuffer(q, "\n    %s;\n", asPart->data);
   12666             : 
   12667        3502 :     append_depends_on_extension(fout, q, &finfo->dobj,
   12668             :                                 "pg_catalog.pg_proc", keyword,
   12669             :                                 qual_funcsig);
   12670             : 
   12671        3502 :     if (dopt->binary_upgrade)
   12672         572 :         binary_upgrade_extension_member(q, &finfo->dobj,
   12673             :                                         keyword, funcsig,
   12674         572 :                                         finfo->dobj.namespace->dobj.name);
   12675             : 
   12676        3502 :     if (finfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   12677        3306 :         ArchiveEntry(fout, finfo->dobj.catId, finfo->dobj.dumpId,
   12678        3306 :                      ARCHIVE_OPTS(.tag = funcsig_tag,
   12679             :                                   .namespace = finfo->dobj.namespace->dobj.name,
   12680             :                                   .owner = finfo->rolname,
   12681             :                                   .description = keyword,
   12682             :                                   .section = finfo->postponed_def ?
   12683             :                                   SECTION_POST_DATA : SECTION_PRE_DATA,
   12684             :                                   .createStmt = q->data,
   12685             :                                   .dropStmt = delqry->data));
   12686             : 
   12687             :     /* Dump Function Comments and Security Labels */
   12688        3502 :     if (finfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   12689          18 :         dumpComment(fout, keyword, funcsig,
   12690          18 :                     finfo->dobj.namespace->dobj.name, finfo->rolname,
   12691             :                     finfo->dobj.catId, 0, finfo->dobj.dumpId);
   12692             : 
   12693        3502 :     if (finfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
   12694           0 :         dumpSecLabel(fout, keyword, funcsig,
   12695           0 :                      finfo->dobj.namespace->dobj.name, finfo->rolname,
   12696             :                      finfo->dobj.catId, 0, finfo->dobj.dumpId);
   12697             : 
   12698        3502 :     if (finfo->dobj.dump & DUMP_COMPONENT_ACL)
   12699         204 :         dumpACL(fout, finfo->dobj.dumpId, InvalidDumpId, keyword,
   12700             :                 funcsig, NULL,
   12701         204 :                 finfo->dobj.namespace->dobj.name,
   12702             :                 NULL, finfo->rolname, &finfo->dacl);
   12703             : 
   12704        3502 :     PQclear(res);
   12705             : 
   12706        3502 :     destroyPQExpBuffer(query);
   12707        3502 :     destroyPQExpBuffer(q);
   12708        3502 :     destroyPQExpBuffer(delqry);
   12709        3502 :     destroyPQExpBuffer(asPart);
   12710        3502 :     free(funcsig);
   12711        3502 :     free(funcfullsig);
   12712        3502 :     free(funcsig_tag);
   12713        3502 :     free(qual_funcsig);
   12714        3502 :     free(configitems);
   12715             : }
   12716             : 
   12717             : 
   12718             : /*
   12719             :  * Dump a user-defined cast
   12720             :  */
   12721             : static void
   12722         130 : dumpCast(Archive *fout, const CastInfo *cast)
   12723             : {
   12724         130 :     DumpOptions *dopt = fout->dopt;
   12725             :     PQExpBuffer defqry;
   12726             :     PQExpBuffer delqry;
   12727             :     PQExpBuffer labelq;
   12728             :     PQExpBuffer castargs;
   12729         130 :     FuncInfo   *funcInfo = NULL;
   12730             :     const char *sourceType;
   12731             :     const char *targetType;
   12732             : 
   12733             :     /* Do nothing if not dumping schema */
   12734         130 :     if (!dopt->dumpSchema)
   12735           6 :         return;
   12736             : 
   12737             :     /* Cannot dump if we don't have the cast function's info */
   12738         124 :     if (OidIsValid(cast->castfunc))
   12739             :     {
   12740          74 :         funcInfo = findFuncByOid(cast->castfunc);
   12741          74 :         if (funcInfo == NULL)
   12742           0 :             pg_fatal("could not find function definition for function with OID %u",
   12743             :                      cast->castfunc);
   12744             :     }
   12745             : 
   12746         124 :     defqry = createPQExpBuffer();
   12747         124 :     delqry = createPQExpBuffer();
   12748         124 :     labelq = createPQExpBuffer();
   12749         124 :     castargs = createPQExpBuffer();
   12750             : 
   12751         124 :     sourceType = getFormattedTypeName(fout, cast->castsource, zeroAsNone);
   12752         124 :     targetType = getFormattedTypeName(fout, cast->casttarget, zeroAsNone);
   12753         124 :     appendPQExpBuffer(delqry, "DROP CAST (%s AS %s);\n",
   12754             :                       sourceType, targetType);
   12755             : 
   12756         124 :     appendPQExpBuffer(defqry, "CREATE CAST (%s AS %s) ",
   12757             :                       sourceType, targetType);
   12758             : 
   12759         124 :     switch (cast->castmethod)
   12760             :     {
   12761          50 :         case COERCION_METHOD_BINARY:
   12762          50 :             appendPQExpBufferStr(defqry, "WITHOUT FUNCTION");
   12763          50 :             break;
   12764           0 :         case COERCION_METHOD_INOUT:
   12765           0 :             appendPQExpBufferStr(defqry, "WITH INOUT");
   12766           0 :             break;
   12767          74 :         case COERCION_METHOD_FUNCTION:
   12768          74 :             if (funcInfo)
   12769             :             {
   12770          74 :                 char       *fsig = format_function_signature(fout, funcInfo, true);
   12771             : 
   12772             :                 /*
   12773             :                  * Always qualify the function name (format_function_signature
   12774             :                  * won't qualify it).
   12775             :                  */
   12776          74 :                 appendPQExpBuffer(defqry, "WITH FUNCTION %s.%s",
   12777          74 :                                   fmtId(funcInfo->dobj.namespace->dobj.name), fsig);
   12778          74 :                 free(fsig);
   12779             :             }
   12780             :             else
   12781           0 :                 pg_log_warning("bogus value in pg_cast.castfunc or pg_cast.castmethod field");
   12782          74 :             break;
   12783           0 :         default:
   12784           0 :             pg_log_warning("bogus value in pg_cast.castmethod field");
   12785             :     }
   12786             : 
   12787         124 :     if (cast->castcontext == 'a')
   12788          64 :         appendPQExpBufferStr(defqry, " AS ASSIGNMENT");
   12789          60 :     else if (cast->castcontext == 'i')
   12790          20 :         appendPQExpBufferStr(defqry, " AS IMPLICIT");
   12791         124 :     appendPQExpBufferStr(defqry, ";\n");
   12792             : 
   12793         124 :     appendPQExpBuffer(labelq, "CAST (%s AS %s)",
   12794             :                       sourceType, targetType);
   12795             : 
   12796         124 :     appendPQExpBuffer(castargs, "(%s AS %s)",
   12797             :                       sourceType, targetType);
   12798             : 
   12799         124 :     if (dopt->binary_upgrade)
   12800          14 :         binary_upgrade_extension_member(defqry, &cast->dobj,
   12801          14 :                                         "CAST", castargs->data, NULL);
   12802             : 
   12803         124 :     if (cast->dobj.dump & DUMP_COMPONENT_DEFINITION)
   12804         124 :         ArchiveEntry(fout, cast->dobj.catId, cast->dobj.dumpId,
   12805         124 :                      ARCHIVE_OPTS(.tag = labelq->data,
   12806             :                                   .description = "CAST",
   12807             :                                   .section = SECTION_PRE_DATA,
   12808             :                                   .createStmt = defqry->data,
   12809             :                                   .dropStmt = delqry->data));
   12810             : 
   12811             :     /* Dump Cast Comments */
   12812         124 :     if (cast->dobj.dump & DUMP_COMPONENT_COMMENT)
   12813           0 :         dumpComment(fout, "CAST", castargs->data,
   12814             :                     NULL, "",
   12815             :                     cast->dobj.catId, 0, cast->dobj.dumpId);
   12816             : 
   12817         124 :     destroyPQExpBuffer(defqry);
   12818         124 :     destroyPQExpBuffer(delqry);
   12819         124 :     destroyPQExpBuffer(labelq);
   12820         124 :     destroyPQExpBuffer(castargs);
   12821             : }
   12822             : 
   12823             : /*
   12824             :  * Dump a transform
   12825             :  */
   12826             : static void
   12827          80 : dumpTransform(Archive *fout, const TransformInfo *transform)
   12828             : {
   12829          80 :     DumpOptions *dopt = fout->dopt;
   12830             :     PQExpBuffer defqry;
   12831             :     PQExpBuffer delqry;
   12832             :     PQExpBuffer labelq;
   12833             :     PQExpBuffer transformargs;
   12834          80 :     FuncInfo   *fromsqlFuncInfo = NULL;
   12835          80 :     FuncInfo   *tosqlFuncInfo = NULL;
   12836             :     char       *lanname;
   12837             :     const char *transformType;
   12838             : 
   12839             :     /* Do nothing if not dumping schema */
   12840          80 :     if (!dopt->dumpSchema)
   12841           6 :         return;
   12842             : 
   12843             :     /* Cannot dump if we don't have the transform functions' info */
   12844          74 :     if (OidIsValid(transform->trffromsql))
   12845             :     {
   12846          74 :         fromsqlFuncInfo = findFuncByOid(transform->trffromsql);
   12847          74 :         if (fromsqlFuncInfo == NULL)
   12848           0 :             pg_fatal("could not find function definition for function with OID %u",
   12849             :                      transform->trffromsql);
   12850             :     }
   12851          74 :     if (OidIsValid(transform->trftosql))
   12852             :     {
   12853          74 :         tosqlFuncInfo = findFuncByOid(transform->trftosql);
   12854          74 :         if (tosqlFuncInfo == NULL)
   12855           0 :             pg_fatal("could not find function definition for function with OID %u",
   12856             :                      transform->trftosql);
   12857             :     }
   12858             : 
   12859          74 :     defqry = createPQExpBuffer();
   12860          74 :     delqry = createPQExpBuffer();
   12861          74 :     labelq = createPQExpBuffer();
   12862          74 :     transformargs = createPQExpBuffer();
   12863             : 
   12864          74 :     lanname = get_language_name(fout, transform->trflang);
   12865          74 :     transformType = getFormattedTypeName(fout, transform->trftype, zeroAsNone);
   12866             : 
   12867          74 :     appendPQExpBuffer(delqry, "DROP TRANSFORM FOR %s LANGUAGE %s;\n",
   12868             :                       transformType, lanname);
   12869             : 
   12870          74 :     appendPQExpBuffer(defqry, "CREATE TRANSFORM FOR %s LANGUAGE %s (",
   12871             :                       transformType, lanname);
   12872             : 
   12873          74 :     if (!transform->trffromsql && !transform->trftosql)
   12874           0 :         pg_log_warning("bogus transform definition, at least one of trffromsql and trftosql should be nonzero");
   12875             : 
   12876          74 :     if (transform->trffromsql)
   12877             :     {
   12878          74 :         if (fromsqlFuncInfo)
   12879             :         {
   12880          74 :             char       *fsig = format_function_signature(fout, fromsqlFuncInfo, true);
   12881             : 
   12882             :             /*
   12883             :              * Always qualify the function name (format_function_signature
   12884             :              * won't qualify it).
   12885             :              */
   12886          74 :             appendPQExpBuffer(defqry, "FROM SQL WITH FUNCTION %s.%s",
   12887          74 :                               fmtId(fromsqlFuncInfo->dobj.namespace->dobj.name), fsig);
   12888          74 :             free(fsig);
   12889             :         }
   12890             :         else
   12891           0 :             pg_log_warning("bogus value in pg_transform.trffromsql field");
   12892             :     }
   12893             : 
   12894          74 :     if (transform->trftosql)
   12895             :     {
   12896          74 :         if (transform->trffromsql)
   12897          74 :             appendPQExpBufferStr(defqry, ", ");
   12898             : 
   12899          74 :         if (tosqlFuncInfo)
   12900             :         {
   12901          74 :             char       *fsig = format_function_signature(fout, tosqlFuncInfo, true);
   12902             : 
   12903             :             /*
   12904             :              * Always qualify the function name (format_function_signature
   12905             :              * won't qualify it).
   12906             :              */
   12907          74 :             appendPQExpBuffer(defqry, "TO SQL WITH FUNCTION %s.%s",
   12908          74 :                               fmtId(tosqlFuncInfo->dobj.namespace->dobj.name), fsig);
   12909          74 :             free(fsig);
   12910             :         }
   12911             :         else
   12912           0 :             pg_log_warning("bogus value in pg_transform.trftosql field");
   12913             :     }
   12914             : 
   12915          74 :     appendPQExpBufferStr(defqry, ");\n");
   12916             : 
   12917          74 :     appendPQExpBuffer(labelq, "TRANSFORM FOR %s LANGUAGE %s",
   12918             :                       transformType, lanname);
   12919             : 
   12920          74 :     appendPQExpBuffer(transformargs, "FOR %s LANGUAGE %s",
   12921             :                       transformType, lanname);
   12922             : 
   12923          74 :     if (dopt->binary_upgrade)
   12924           4 :         binary_upgrade_extension_member(defqry, &transform->dobj,
   12925           4 :                                         "TRANSFORM", transformargs->data, NULL);
   12926             : 
   12927          74 :     if (transform->dobj.dump & DUMP_COMPONENT_DEFINITION)
   12928          74 :         ArchiveEntry(fout, transform->dobj.catId, transform->dobj.dumpId,
   12929          74 :                      ARCHIVE_OPTS(.tag = labelq->data,
   12930             :                                   .description = "TRANSFORM",
   12931             :                                   .section = SECTION_PRE_DATA,
   12932             :                                   .createStmt = defqry->data,
   12933             :                                   .dropStmt = delqry->data,
   12934             :                                   .deps = transform->dobj.dependencies,
   12935             :                                   .nDeps = transform->dobj.nDeps));
   12936             : 
   12937             :     /* Dump Transform Comments */
   12938          74 :     if (transform->dobj.dump & DUMP_COMPONENT_COMMENT)
   12939           0 :         dumpComment(fout, "TRANSFORM", transformargs->data,
   12940             :                     NULL, "",
   12941             :                     transform->dobj.catId, 0, transform->dobj.dumpId);
   12942             : 
   12943          74 :     free(lanname);
   12944          74 :     destroyPQExpBuffer(defqry);
   12945          74 :     destroyPQExpBuffer(delqry);
   12946          74 :     destroyPQExpBuffer(labelq);
   12947          74 :     destroyPQExpBuffer(transformargs);
   12948             : }
   12949             : 
   12950             : 
   12951             : /*
   12952             :  * dumpOpr
   12953             :  *    write out a single operator definition
   12954             :  */
   12955             : static void
   12956        5004 : dumpOpr(Archive *fout, const OprInfo *oprinfo)
   12957             : {
   12958        5004 :     DumpOptions *dopt = fout->dopt;
   12959             :     PQExpBuffer query;
   12960             :     PQExpBuffer q;
   12961             :     PQExpBuffer delq;
   12962             :     PQExpBuffer oprid;
   12963             :     PQExpBuffer details;
   12964             :     PGresult   *res;
   12965             :     int         i_oprkind;
   12966             :     int         i_oprcode;
   12967             :     int         i_oprleft;
   12968             :     int         i_oprright;
   12969             :     int         i_oprcom;
   12970             :     int         i_oprnegate;
   12971             :     int         i_oprrest;
   12972             :     int         i_oprjoin;
   12973             :     int         i_oprcanmerge;
   12974             :     int         i_oprcanhash;
   12975             :     char       *oprkind;
   12976             :     char       *oprcode;
   12977             :     char       *oprleft;
   12978             :     char       *oprright;
   12979             :     char       *oprcom;
   12980             :     char       *oprnegate;
   12981             :     char       *oprrest;
   12982             :     char       *oprjoin;
   12983             :     char       *oprcanmerge;
   12984             :     char       *oprcanhash;
   12985             :     char       *oprregproc;
   12986             :     char       *oprref;
   12987             : 
   12988             :     /* Do nothing if not dumping schema */
   12989        5004 :     if (!dopt->dumpSchema)
   12990           6 :         return;
   12991             : 
   12992             :     /*
   12993             :      * some operators are invalid because they were the result of user
   12994             :      * defining operators before commutators exist
   12995             :      */
   12996        4998 :     if (!OidIsValid(oprinfo->oprcode))
   12997          28 :         return;
   12998             : 
   12999        4970 :     query = createPQExpBuffer();
   13000        4970 :     q = createPQExpBuffer();
   13001        4970 :     delq = createPQExpBuffer();
   13002        4970 :     oprid = createPQExpBuffer();
   13003        4970 :     details = createPQExpBuffer();
   13004             : 
   13005        4970 :     if (!fout->is_prepared[PREPQUERY_DUMPOPR])
   13006             :     {
   13007             :         /* Set up query for operator-specific details */
   13008          82 :         appendPQExpBufferStr(query,
   13009             :                              "PREPARE dumpOpr(pg_catalog.oid) AS\n"
   13010             :                              "SELECT oprkind, "
   13011             :                              "oprcode::pg_catalog.regprocedure, "
   13012             :                              "oprleft::pg_catalog.regtype, "
   13013             :                              "oprright::pg_catalog.regtype, "
   13014             :                              "oprcom, "
   13015             :                              "oprnegate, "
   13016             :                              "oprrest::pg_catalog.regprocedure, "
   13017             :                              "oprjoin::pg_catalog.regprocedure, "
   13018             :                              "oprcanmerge, oprcanhash "
   13019             :                              "FROM pg_catalog.pg_operator "
   13020             :                              "WHERE oid = $1");
   13021             : 
   13022          82 :         ExecuteSqlStatement(fout, query->data);
   13023             : 
   13024          82 :         fout->is_prepared[PREPQUERY_DUMPOPR] = true;
   13025             :     }
   13026             : 
   13027        4970 :     printfPQExpBuffer(query,
   13028             :                       "EXECUTE dumpOpr('%u')",
   13029             :                       oprinfo->dobj.catId.oid);
   13030             : 
   13031        4970 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   13032             : 
   13033        4970 :     i_oprkind = PQfnumber(res, "oprkind");
   13034        4970 :     i_oprcode = PQfnumber(res, "oprcode");
   13035        4970 :     i_oprleft = PQfnumber(res, "oprleft");
   13036        4970 :     i_oprright = PQfnumber(res, "oprright");
   13037        4970 :     i_oprcom = PQfnumber(res, "oprcom");
   13038        4970 :     i_oprnegate = PQfnumber(res, "oprnegate");
   13039        4970 :     i_oprrest = PQfnumber(res, "oprrest");
   13040        4970 :     i_oprjoin = PQfnumber(res, "oprjoin");
   13041        4970 :     i_oprcanmerge = PQfnumber(res, "oprcanmerge");
   13042        4970 :     i_oprcanhash = PQfnumber(res, "oprcanhash");
   13043             : 
   13044        4970 :     oprkind = PQgetvalue(res, 0, i_oprkind);
   13045        4970 :     oprcode = PQgetvalue(res, 0, i_oprcode);
   13046        4970 :     oprleft = PQgetvalue(res, 0, i_oprleft);
   13047        4970 :     oprright = PQgetvalue(res, 0, i_oprright);
   13048        4970 :     oprcom = PQgetvalue(res, 0, i_oprcom);
   13049        4970 :     oprnegate = PQgetvalue(res, 0, i_oprnegate);
   13050        4970 :     oprrest = PQgetvalue(res, 0, i_oprrest);
   13051        4970 :     oprjoin = PQgetvalue(res, 0, i_oprjoin);
   13052        4970 :     oprcanmerge = PQgetvalue(res, 0, i_oprcanmerge);
   13053        4970 :     oprcanhash = PQgetvalue(res, 0, i_oprcanhash);
   13054             : 
   13055             :     /* In PG14 upwards postfix operator support does not exist anymore. */
   13056        4970 :     if (strcmp(oprkind, "r") == 0)
   13057           0 :         pg_log_warning("postfix operators are not supported anymore (operator \"%s\")",
   13058             :                        oprcode);
   13059             : 
   13060        4970 :     oprregproc = convertRegProcReference(oprcode);
   13061        4970 :     if (oprregproc)
   13062             :     {
   13063        4970 :         appendPQExpBuffer(details, "    FUNCTION = %s", oprregproc);
   13064        4970 :         free(oprregproc);
   13065             :     }
   13066             : 
   13067        4970 :     appendPQExpBuffer(oprid, "%s (",
   13068             :                       oprinfo->dobj.name);
   13069             : 
   13070             :     /*
   13071             :      * right unary means there's a left arg and left unary means there's a
   13072             :      * right arg.  (Although the "r" case is dead code for PG14 and later,
   13073             :      * continue to support it in case we're dumping from an old server.)
   13074             :      */
   13075        4970 :     if (strcmp(oprkind, "r") == 0 ||
   13076        4970 :         strcmp(oprkind, "b") == 0)
   13077             :     {
   13078        4684 :         appendPQExpBuffer(details, ",\n    LEFTARG = %s", oprleft);
   13079        4684 :         appendPQExpBufferStr(oprid, oprleft);
   13080             :     }
   13081             :     else
   13082         286 :         appendPQExpBufferStr(oprid, "NONE");
   13083             : 
   13084        4970 :     if (strcmp(oprkind, "l") == 0 ||
   13085        4684 :         strcmp(oprkind, "b") == 0)
   13086             :     {
   13087        4970 :         appendPQExpBuffer(details, ",\n    RIGHTARG = %s", oprright);
   13088        4970 :         appendPQExpBuffer(oprid, ", %s)", oprright);
   13089             :     }
   13090             :     else
   13091           0 :         appendPQExpBufferStr(oprid, ", NONE)");
   13092             : 
   13093        4970 :     oprref = getFormattedOperatorName(oprcom);
   13094        4970 :     if (oprref)
   13095             :     {
   13096        3322 :         appendPQExpBuffer(details, ",\n    COMMUTATOR = %s", oprref);
   13097        3322 :         free(oprref);
   13098             :     }
   13099             : 
   13100        4970 :     oprref = getFormattedOperatorName(oprnegate);
   13101        4970 :     if (oprref)
   13102             :     {
   13103        2326 :         appendPQExpBuffer(details, ",\n    NEGATOR = %s", oprref);
   13104        2326 :         free(oprref);
   13105             :     }
   13106             : 
   13107        4970 :     if (strcmp(oprcanmerge, "t") == 0)
   13108         370 :         appendPQExpBufferStr(details, ",\n    MERGES");
   13109             : 
   13110        4970 :     if (strcmp(oprcanhash, "t") == 0)
   13111         276 :         appendPQExpBufferStr(details, ",\n    HASHES");
   13112             : 
   13113        4970 :     oprregproc = convertRegProcReference(oprrest);
   13114        4970 :     if (oprregproc)
   13115             :     {
   13116        3028 :         appendPQExpBuffer(details, ",\n    RESTRICT = %s", oprregproc);
   13117        3028 :         free(oprregproc);
   13118             :     }
   13119             : 
   13120        4970 :     oprregproc = convertRegProcReference(oprjoin);
   13121        4970 :     if (oprregproc)
   13122             :     {
   13123        3028 :         appendPQExpBuffer(details, ",\n    JOIN = %s", oprregproc);
   13124        3028 :         free(oprregproc);
   13125             :     }
   13126             : 
   13127        4970 :     appendPQExpBuffer(delq, "DROP OPERATOR %s.%s;\n",
   13128        4970 :                       fmtId(oprinfo->dobj.namespace->dobj.name),
   13129             :                       oprid->data);
   13130             : 
   13131        4970 :     appendPQExpBuffer(q, "CREATE OPERATOR %s.%s (\n%s\n);\n",
   13132        4970 :                       fmtId(oprinfo->dobj.namespace->dobj.name),
   13133             :                       oprinfo->dobj.name, details->data);
   13134             : 
   13135        4970 :     if (dopt->binary_upgrade)
   13136          24 :         binary_upgrade_extension_member(q, &oprinfo->dobj,
   13137          24 :                                         "OPERATOR", oprid->data,
   13138          24 :                                         oprinfo->dobj.namespace->dobj.name);
   13139             : 
   13140        4970 :     if (oprinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   13141        4970 :         ArchiveEntry(fout, oprinfo->dobj.catId, oprinfo->dobj.dumpId,
   13142        4970 :                      ARCHIVE_OPTS(.tag = oprinfo->dobj.name,
   13143             :                                   .namespace = oprinfo->dobj.namespace->dobj.name,
   13144             :                                   .owner = oprinfo->rolname,
   13145             :                                   .description = "OPERATOR",
   13146             :                                   .section = SECTION_PRE_DATA,
   13147             :                                   .createStmt = q->data,
   13148             :                                   .dropStmt = delq->data));
   13149             : 
   13150             :     /* Dump Operator Comments */
   13151        4970 :     if (oprinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   13152        4794 :         dumpComment(fout, "OPERATOR", oprid->data,
   13153        4794 :                     oprinfo->dobj.namespace->dobj.name, oprinfo->rolname,
   13154             :                     oprinfo->dobj.catId, 0, oprinfo->dobj.dumpId);
   13155             : 
   13156        4970 :     PQclear(res);
   13157             : 
   13158        4970 :     destroyPQExpBuffer(query);
   13159        4970 :     destroyPQExpBuffer(q);
   13160        4970 :     destroyPQExpBuffer(delq);
   13161        4970 :     destroyPQExpBuffer(oprid);
   13162        4970 :     destroyPQExpBuffer(details);
   13163             : }
   13164             : 
   13165             : /*
   13166             :  * Convert a function reference obtained from pg_operator
   13167             :  *
   13168             :  * Returns allocated string of what to print, or NULL if function references
   13169             :  * is InvalidOid. Returned string is expected to be free'd by the caller.
   13170             :  *
   13171             :  * The input is a REGPROCEDURE display; we have to strip the argument-types
   13172             :  * part.
   13173             :  */
   13174             : static char *
   13175       14910 : convertRegProcReference(const char *proc)
   13176             : {
   13177             :     char       *name;
   13178             :     char       *paren;
   13179             :     bool        inquote;
   13180             : 
   13181             :     /* In all cases "-" means a null reference */
   13182       14910 :     if (strcmp(proc, "-") == 0)
   13183        3884 :         return NULL;
   13184             : 
   13185       11026 :     name = pg_strdup(proc);
   13186             :     /* find non-double-quoted left paren */
   13187       11026 :     inquote = false;
   13188      132878 :     for (paren = name; *paren; paren++)
   13189             :     {
   13190      132878 :         if (*paren == '(' && !inquote)
   13191             :         {
   13192       11026 :             *paren = '\0';
   13193       11026 :             break;
   13194             :         }
   13195      121852 :         if (*paren == '"')
   13196         100 :             inquote = !inquote;
   13197             :     }
   13198       11026 :     return name;
   13199             : }
   13200             : 
   13201             : /*
   13202             :  * getFormattedOperatorName - retrieve the operator name for the
   13203             :  * given operator OID (presented in string form).
   13204             :  *
   13205             :  * Returns an allocated string, or NULL if the given OID is invalid.
   13206             :  * Caller is responsible for free'ing result string.
   13207             :  *
   13208             :  * What we produce has the format "OPERATOR(schema.oprname)".  This is only
   13209             :  * useful in commands where the operator's argument types can be inferred from
   13210             :  * context.  We always schema-qualify the name, though.  The predecessor to
   13211             :  * this code tried to skip the schema qualification if possible, but that led
   13212             :  * to wrong results in corner cases, such as if an operator and its negator
   13213             :  * are in different schemas.
   13214             :  */
   13215             : static char *
   13216       10512 : getFormattedOperatorName(const char *oproid)
   13217             : {
   13218             :     OprInfo    *oprInfo;
   13219             : 
   13220             :     /* In all cases "0" means a null reference */
   13221       10512 :     if (strcmp(oproid, "0") == 0)
   13222        4864 :         return NULL;
   13223             : 
   13224        5648 :     oprInfo = findOprByOid(atooid(oproid));
   13225        5648 :     if (oprInfo == NULL)
   13226             :     {
   13227           0 :         pg_log_warning("could not find operator with OID %s",
   13228             :                        oproid);
   13229           0 :         return NULL;
   13230             :     }
   13231             : 
   13232        5648 :     return psprintf("OPERATOR(%s.%s)",
   13233        5648 :                     fmtId(oprInfo->dobj.namespace->dobj.name),
   13234             :                     oprInfo->dobj.name);
   13235             : }
   13236             : 
   13237             : /*
   13238             :  * Convert a function OID obtained from pg_ts_parser or pg_ts_template
   13239             :  *
   13240             :  * It is sufficient to use REGPROC rather than REGPROCEDURE, since the
   13241             :  * argument lists of these functions are predetermined.  Note that the
   13242             :  * caller should ensure we are in the proper schema, because the results
   13243             :  * are search path dependent!
   13244             :  */
   13245             : static char *
   13246         420 : convertTSFunction(Archive *fout, Oid funcOid)
   13247             : {
   13248             :     char       *result;
   13249             :     char        query[128];
   13250             :     PGresult   *res;
   13251             : 
   13252         420 :     snprintf(query, sizeof(query),
   13253             :              "SELECT '%u'::pg_catalog.regproc", funcOid);
   13254         420 :     res = ExecuteSqlQueryForSingleRow(fout, query);
   13255             : 
   13256         420 :     result = pg_strdup(PQgetvalue(res, 0, 0));
   13257             : 
   13258         420 :     PQclear(res);
   13259             : 
   13260         420 :     return result;
   13261             : }
   13262             : 
   13263             : /*
   13264             :  * dumpAccessMethod
   13265             :  *    write out a single access method definition
   13266             :  */
   13267             : static void
   13268         152 : dumpAccessMethod(Archive *fout, const AccessMethodInfo *aminfo)
   13269             : {
   13270         152 :     DumpOptions *dopt = fout->dopt;
   13271             :     PQExpBuffer q;
   13272             :     PQExpBuffer delq;
   13273             :     char       *qamname;
   13274             : 
   13275             :     /* Do nothing if not dumping schema */
   13276         152 :     if (!dopt->dumpSchema)
   13277          12 :         return;
   13278             : 
   13279         140 :     q = createPQExpBuffer();
   13280         140 :     delq = createPQExpBuffer();
   13281             : 
   13282         140 :     qamname = pg_strdup(fmtId(aminfo->dobj.name));
   13283             : 
   13284         140 :     appendPQExpBuffer(q, "CREATE ACCESS METHOD %s ", qamname);
   13285             : 
   13286         140 :     switch (aminfo->amtype)
   13287             :     {
   13288          66 :         case AMTYPE_INDEX:
   13289          66 :             appendPQExpBufferStr(q, "TYPE INDEX ");
   13290          66 :             break;
   13291          74 :         case AMTYPE_TABLE:
   13292          74 :             appendPQExpBufferStr(q, "TYPE TABLE ");
   13293          74 :             break;
   13294           0 :         default:
   13295           0 :             pg_log_warning("invalid type \"%c\" of access method \"%s\"",
   13296             :                            aminfo->amtype, qamname);
   13297           0 :             destroyPQExpBuffer(q);
   13298           0 :             destroyPQExpBuffer(delq);
   13299           0 :             free(qamname);
   13300           0 :             return;
   13301             :     }
   13302             : 
   13303         140 :     appendPQExpBuffer(q, "HANDLER %s;\n", aminfo->amhandler);
   13304             : 
   13305         140 :     appendPQExpBuffer(delq, "DROP ACCESS METHOD %s;\n",
   13306             :                       qamname);
   13307             : 
   13308         140 :     if (dopt->binary_upgrade)
   13309           8 :         binary_upgrade_extension_member(q, &aminfo->dobj,
   13310             :                                         "ACCESS METHOD", qamname, NULL);
   13311             : 
   13312         140 :     if (aminfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   13313         140 :         ArchiveEntry(fout, aminfo->dobj.catId, aminfo->dobj.dumpId,
   13314         140 :                      ARCHIVE_OPTS(.tag = aminfo->dobj.name,
   13315             :                                   .description = "ACCESS METHOD",
   13316             :                                   .section = SECTION_PRE_DATA,
   13317             :                                   .createStmt = q->data,
   13318             :                                   .dropStmt = delq->data));
   13319             : 
   13320             :     /* Dump Access Method Comments */
   13321         140 :     if (aminfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   13322           0 :         dumpComment(fout, "ACCESS METHOD", qamname,
   13323             :                     NULL, "",
   13324             :                     aminfo->dobj.catId, 0, aminfo->dobj.dumpId);
   13325             : 
   13326         140 :     destroyPQExpBuffer(q);
   13327         140 :     destroyPQExpBuffer(delq);
   13328         140 :     free(qamname);
   13329             : }
   13330             : 
   13331             : /*
   13332             :  * dumpOpclass
   13333             :  *    write out a single operator class definition
   13334             :  */
   13335             : static void
   13336        1308 : dumpOpclass(Archive *fout, const OpclassInfo *opcinfo)
   13337             : {
   13338        1308 :     DumpOptions *dopt = fout->dopt;
   13339             :     PQExpBuffer query;
   13340             :     PQExpBuffer q;
   13341             :     PQExpBuffer delq;
   13342             :     PQExpBuffer nameusing;
   13343             :     PGresult   *res;
   13344             :     int         ntups;
   13345             :     int         i_opcintype;
   13346             :     int         i_opckeytype;
   13347             :     int         i_opcdefault;
   13348             :     int         i_opcfamily;
   13349             :     int         i_opcfamilyname;
   13350             :     int         i_opcfamilynsp;
   13351             :     int         i_amname;
   13352             :     int         i_amopstrategy;
   13353             :     int         i_amopopr;
   13354             :     int         i_sortfamily;
   13355             :     int         i_sortfamilynsp;
   13356             :     int         i_amprocnum;
   13357             :     int         i_amproc;
   13358             :     int         i_amproclefttype;
   13359             :     int         i_amprocrighttype;
   13360             :     char       *opcintype;
   13361             :     char       *opckeytype;
   13362             :     char       *opcdefault;
   13363             :     char       *opcfamily;
   13364             :     char       *opcfamilyname;
   13365             :     char       *opcfamilynsp;
   13366             :     char       *amname;
   13367             :     char       *amopstrategy;
   13368             :     char       *amopopr;
   13369             :     char       *sortfamily;
   13370             :     char       *sortfamilynsp;
   13371             :     char       *amprocnum;
   13372             :     char       *amproc;
   13373             :     char       *amproclefttype;
   13374             :     char       *amprocrighttype;
   13375             :     bool        needComma;
   13376             :     int         i;
   13377             : 
   13378             :     /* Do nothing if not dumping schema */
   13379        1308 :     if (!dopt->dumpSchema)
   13380          18 :         return;
   13381             : 
   13382        1290 :     query = createPQExpBuffer();
   13383        1290 :     q = createPQExpBuffer();
   13384        1290 :     delq = createPQExpBuffer();
   13385        1290 :     nameusing = createPQExpBuffer();
   13386             : 
   13387             :     /* Get additional fields from the pg_opclass row */
   13388        1290 :     appendPQExpBuffer(query, "SELECT opcintype::pg_catalog.regtype, "
   13389             :                       "opckeytype::pg_catalog.regtype, "
   13390             :                       "opcdefault, opcfamily, "
   13391             :                       "opfname AS opcfamilyname, "
   13392             :                       "nspname AS opcfamilynsp, "
   13393             :                       "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opcmethod) AS amname "
   13394             :                       "FROM pg_catalog.pg_opclass c "
   13395             :                       "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = opcfamily "
   13396             :                       "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
   13397             :                       "WHERE c.oid = '%u'::pg_catalog.oid",
   13398             :                       opcinfo->dobj.catId.oid);
   13399             : 
   13400        1290 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   13401             : 
   13402        1290 :     i_opcintype = PQfnumber(res, "opcintype");
   13403        1290 :     i_opckeytype = PQfnumber(res, "opckeytype");
   13404        1290 :     i_opcdefault = PQfnumber(res, "opcdefault");
   13405        1290 :     i_opcfamily = PQfnumber(res, "opcfamily");
   13406        1290 :     i_opcfamilyname = PQfnumber(res, "opcfamilyname");
   13407        1290 :     i_opcfamilynsp = PQfnumber(res, "opcfamilynsp");
   13408        1290 :     i_amname = PQfnumber(res, "amname");
   13409             : 
   13410             :     /* opcintype may still be needed after we PQclear res */
   13411        1290 :     opcintype = pg_strdup(PQgetvalue(res, 0, i_opcintype));
   13412        1290 :     opckeytype = PQgetvalue(res, 0, i_opckeytype);
   13413        1290 :     opcdefault = PQgetvalue(res, 0, i_opcdefault);
   13414             :     /* opcfamily will still be needed after we PQclear res */
   13415        1290 :     opcfamily = pg_strdup(PQgetvalue(res, 0, i_opcfamily));
   13416        1290 :     opcfamilyname = PQgetvalue(res, 0, i_opcfamilyname);
   13417        1290 :     opcfamilynsp = PQgetvalue(res, 0, i_opcfamilynsp);
   13418             :     /* amname will still be needed after we PQclear res */
   13419        1290 :     amname = pg_strdup(PQgetvalue(res, 0, i_amname));
   13420             : 
   13421        1290 :     appendPQExpBuffer(delq, "DROP OPERATOR CLASS %s",
   13422        1290 :                       fmtQualifiedDumpable(opcinfo));
   13423        1290 :     appendPQExpBuffer(delq, " USING %s;\n",
   13424             :                       fmtId(amname));
   13425             : 
   13426             :     /* Build the fixed portion of the CREATE command */
   13427        1290 :     appendPQExpBuffer(q, "CREATE OPERATOR CLASS %s\n    ",
   13428        1290 :                       fmtQualifiedDumpable(opcinfo));
   13429        1290 :     if (strcmp(opcdefault, "t") == 0)
   13430         714 :         appendPQExpBufferStr(q, "DEFAULT ");
   13431        1290 :     appendPQExpBuffer(q, "FOR TYPE %s USING %s",
   13432             :                       opcintype,
   13433             :                       fmtId(amname));
   13434        1290 :     if (strlen(opcfamilyname) > 0)
   13435             :     {
   13436        1290 :         appendPQExpBufferStr(q, " FAMILY ");
   13437        1290 :         appendPQExpBuffer(q, "%s.", fmtId(opcfamilynsp));
   13438        1290 :         appendPQExpBufferStr(q, fmtId(opcfamilyname));
   13439             :     }
   13440        1290 :     appendPQExpBufferStr(q, " AS\n    ");
   13441             : 
   13442        1290 :     needComma = false;
   13443             : 
   13444        1290 :     if (strcmp(opckeytype, "-") != 0)
   13445             :     {
   13446         504 :         appendPQExpBuffer(q, "STORAGE %s",
   13447             :                           opckeytype);
   13448         504 :         needComma = true;
   13449             :     }
   13450             : 
   13451        1290 :     PQclear(res);
   13452             : 
   13453             :     /*
   13454             :      * Now fetch and print the OPERATOR entries (pg_amop rows).
   13455             :      *
   13456             :      * Print only those opfamily members that are tied to the opclass by
   13457             :      * pg_depend entries.
   13458             :      */
   13459        1290 :     resetPQExpBuffer(query);
   13460        1290 :     appendPQExpBuffer(query, "SELECT amopstrategy, "
   13461             :                       "amopopr::pg_catalog.regoperator, "
   13462             :                       "opfname AS sortfamily, "
   13463             :                       "nspname AS sortfamilynsp "
   13464             :                       "FROM pg_catalog.pg_amop ao JOIN pg_catalog.pg_depend ON "
   13465             :                       "(classid = 'pg_catalog.pg_amop'::pg_catalog.regclass AND objid = ao.oid) "
   13466             :                       "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = amopsortfamily "
   13467             :                       "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
   13468             :                       "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
   13469             :                       "AND refobjid = '%u'::pg_catalog.oid "
   13470             :                       "AND amopfamily = '%s'::pg_catalog.oid "
   13471             :                       "ORDER BY amopstrategy",
   13472             :                       opcinfo->dobj.catId.oid,
   13473             :                       opcfamily);
   13474             : 
   13475        1290 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   13476             : 
   13477        1290 :     ntups = PQntuples(res);
   13478             : 
   13479        1290 :     i_amopstrategy = PQfnumber(res, "amopstrategy");
   13480        1290 :     i_amopopr = PQfnumber(res, "amopopr");
   13481        1290 :     i_sortfamily = PQfnumber(res, "sortfamily");
   13482        1290 :     i_sortfamilynsp = PQfnumber(res, "sortfamilynsp");
   13483             : 
   13484        1706 :     for (i = 0; i < ntups; i++)
   13485             :     {
   13486         416 :         amopstrategy = PQgetvalue(res, i, i_amopstrategy);
   13487         416 :         amopopr = PQgetvalue(res, i, i_amopopr);
   13488         416 :         sortfamily = PQgetvalue(res, i, i_sortfamily);
   13489         416 :         sortfamilynsp = PQgetvalue(res, i, i_sortfamilynsp);
   13490             : 
   13491         416 :         if (needComma)
   13492         264 :             appendPQExpBufferStr(q, " ,\n    ");
   13493             : 
   13494         416 :         appendPQExpBuffer(q, "OPERATOR %s %s",
   13495             :                           amopstrategy, amopopr);
   13496             : 
   13497         416 :         if (strlen(sortfamily) > 0)
   13498             :         {
   13499           0 :             appendPQExpBufferStr(q, " FOR ORDER BY ");
   13500           0 :             appendPQExpBuffer(q, "%s.", fmtId(sortfamilynsp));
   13501           0 :             appendPQExpBufferStr(q, fmtId(sortfamily));
   13502             :         }
   13503             : 
   13504         416 :         needComma = true;
   13505             :     }
   13506             : 
   13507        1290 :     PQclear(res);
   13508             : 
   13509             :     /*
   13510             :      * Now fetch and print the FUNCTION entries (pg_amproc rows).
   13511             :      *
   13512             :      * Print only those opfamily members that are tied to the opclass by
   13513             :      * pg_depend entries.
   13514             :      *
   13515             :      * We print the amproclefttype/amprocrighttype even though in most cases
   13516             :      * the backend could deduce the right values, because of the corner case
   13517             :      * of a btree sort support function for a cross-type comparison.
   13518             :      */
   13519        1290 :     resetPQExpBuffer(query);
   13520             : 
   13521        1290 :     appendPQExpBuffer(query, "SELECT amprocnum, "
   13522             :                       "amproc::pg_catalog.regprocedure, "
   13523             :                       "amproclefttype::pg_catalog.regtype, "
   13524             :                       "amprocrighttype::pg_catalog.regtype "
   13525             :                       "FROM pg_catalog.pg_amproc ap, pg_catalog.pg_depend "
   13526             :                       "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
   13527             :                       "AND refobjid = '%u'::pg_catalog.oid "
   13528             :                       "AND classid = 'pg_catalog.pg_amproc'::pg_catalog.regclass "
   13529             :                       "AND objid = ap.oid "
   13530             :                       "ORDER BY amprocnum",
   13531             :                       opcinfo->dobj.catId.oid);
   13532             : 
   13533        1290 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   13534             : 
   13535        1290 :     ntups = PQntuples(res);
   13536             : 
   13537        1290 :     i_amprocnum = PQfnumber(res, "amprocnum");
   13538        1290 :     i_amproc = PQfnumber(res, "amproc");
   13539        1290 :     i_amproclefttype = PQfnumber(res, "amproclefttype");
   13540        1290 :     i_amprocrighttype = PQfnumber(res, "amprocrighttype");
   13541             : 
   13542        1356 :     for (i = 0; i < ntups; i++)
   13543             :     {
   13544          66 :         amprocnum = PQgetvalue(res, i, i_amprocnum);
   13545          66 :         amproc = PQgetvalue(res, i, i_amproc);
   13546          66 :         amproclefttype = PQgetvalue(res, i, i_amproclefttype);
   13547          66 :         amprocrighttype = PQgetvalue(res, i, i_amprocrighttype);
   13548             : 
   13549          66 :         if (needComma)
   13550          66 :             appendPQExpBufferStr(q, " ,\n    ");
   13551             : 
   13552          66 :         appendPQExpBuffer(q, "FUNCTION %s", amprocnum);
   13553             : 
   13554          66 :         if (*amproclefttype && *amprocrighttype)
   13555          66 :             appendPQExpBuffer(q, " (%s, %s)", amproclefttype, amprocrighttype);
   13556             : 
   13557          66 :         appendPQExpBuffer(q, " %s", amproc);
   13558             : 
   13559          66 :         needComma = true;
   13560             :     }
   13561             : 
   13562        1290 :     PQclear(res);
   13563             : 
   13564             :     /*
   13565             :      * If needComma is still false it means we haven't added anything after
   13566             :      * the AS keyword.  To avoid printing broken SQL, append a dummy STORAGE
   13567             :      * clause with the same datatype.  This isn't sanctioned by the
   13568             :      * documentation, but actually DefineOpClass will treat it as a no-op.
   13569             :      */
   13570        1290 :     if (!needComma)
   13571         634 :         appendPQExpBuffer(q, "STORAGE %s", opcintype);
   13572             : 
   13573        1290 :     appendPQExpBufferStr(q, ";\n");
   13574             : 
   13575        1290 :     appendPQExpBufferStr(nameusing, fmtId(opcinfo->dobj.name));
   13576        1290 :     appendPQExpBuffer(nameusing, " USING %s",
   13577             :                       fmtId(amname));
   13578             : 
   13579        1290 :     if (dopt->binary_upgrade)
   13580          12 :         binary_upgrade_extension_member(q, &opcinfo->dobj,
   13581          12 :                                         "OPERATOR CLASS", nameusing->data,
   13582          12 :                                         opcinfo->dobj.namespace->dobj.name);
   13583             : 
   13584        1290 :     if (opcinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   13585        1290 :         ArchiveEntry(fout, opcinfo->dobj.catId, opcinfo->dobj.dumpId,
   13586        1290 :                      ARCHIVE_OPTS(.tag = opcinfo->dobj.name,
   13587             :                                   .namespace = opcinfo->dobj.namespace->dobj.name,
   13588             :                                   .owner = opcinfo->rolname,
   13589             :                                   .description = "OPERATOR CLASS",
   13590             :                                   .section = SECTION_PRE_DATA,
   13591             :                                   .createStmt = q->data,
   13592             :                                   .dropStmt = delq->data));
   13593             : 
   13594             :     /* Dump Operator Class Comments */
   13595        1290 :     if (opcinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   13596           0 :         dumpComment(fout, "OPERATOR CLASS", nameusing->data,
   13597           0 :                     opcinfo->dobj.namespace->dobj.name, opcinfo->rolname,
   13598             :                     opcinfo->dobj.catId, 0, opcinfo->dobj.dumpId);
   13599             : 
   13600        1290 :     free(opcintype);
   13601        1290 :     free(opcfamily);
   13602        1290 :     free(amname);
   13603        1290 :     destroyPQExpBuffer(query);
   13604        1290 :     destroyPQExpBuffer(q);
   13605        1290 :     destroyPQExpBuffer(delq);
   13606        1290 :     destroyPQExpBuffer(nameusing);
   13607             : }
   13608             : 
   13609             : /*
   13610             :  * dumpOpfamily
   13611             :  *    write out a single operator family definition
   13612             :  *
   13613             :  * Note: this also dumps any "loose" operator members that aren't bound to a
   13614             :  * specific opclass within the opfamily.
   13615             :  */
   13616             : static void
   13617        1090 : dumpOpfamily(Archive *fout, const OpfamilyInfo *opfinfo)
   13618             : {
   13619        1090 :     DumpOptions *dopt = fout->dopt;
   13620             :     PQExpBuffer query;
   13621             :     PQExpBuffer q;
   13622             :     PQExpBuffer delq;
   13623             :     PQExpBuffer nameusing;
   13624             :     PGresult   *res;
   13625             :     PGresult   *res_ops;
   13626             :     PGresult   *res_procs;
   13627             :     int         ntups;
   13628             :     int         i_amname;
   13629             :     int         i_amopstrategy;
   13630             :     int         i_amopopr;
   13631             :     int         i_sortfamily;
   13632             :     int         i_sortfamilynsp;
   13633             :     int         i_amprocnum;
   13634             :     int         i_amproc;
   13635             :     int         i_amproclefttype;
   13636             :     int         i_amprocrighttype;
   13637             :     char       *amname;
   13638             :     char       *amopstrategy;
   13639             :     char       *amopopr;
   13640             :     char       *sortfamily;
   13641             :     char       *sortfamilynsp;
   13642             :     char       *amprocnum;
   13643             :     char       *amproc;
   13644             :     char       *amproclefttype;
   13645             :     char       *amprocrighttype;
   13646             :     bool        needComma;
   13647             :     int         i;
   13648             : 
   13649             :     /* Do nothing if not dumping schema */
   13650        1090 :     if (!dopt->dumpSchema)
   13651          12 :         return;
   13652             : 
   13653        1078 :     query = createPQExpBuffer();
   13654        1078 :     q = createPQExpBuffer();
   13655        1078 :     delq = createPQExpBuffer();
   13656        1078 :     nameusing = createPQExpBuffer();
   13657             : 
   13658             :     /*
   13659             :      * Fetch only those opfamily members that are tied directly to the
   13660             :      * opfamily by pg_depend entries.
   13661             :      */
   13662        1078 :     appendPQExpBuffer(query, "SELECT amopstrategy, "
   13663             :                       "amopopr::pg_catalog.regoperator, "
   13664             :                       "opfname AS sortfamily, "
   13665             :                       "nspname AS sortfamilynsp "
   13666             :                       "FROM pg_catalog.pg_amop ao JOIN pg_catalog.pg_depend ON "
   13667             :                       "(classid = 'pg_catalog.pg_amop'::pg_catalog.regclass AND objid = ao.oid) "
   13668             :                       "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = amopsortfamily "
   13669             :                       "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
   13670             :                       "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
   13671             :                       "AND refobjid = '%u'::pg_catalog.oid "
   13672             :                       "AND amopfamily = '%u'::pg_catalog.oid "
   13673             :                       "ORDER BY amopstrategy",
   13674             :                       opfinfo->dobj.catId.oid,
   13675             :                       opfinfo->dobj.catId.oid);
   13676             : 
   13677        1078 :     res_ops = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   13678             : 
   13679        1078 :     resetPQExpBuffer(query);
   13680             : 
   13681        1078 :     appendPQExpBuffer(query, "SELECT amprocnum, "
   13682             :                       "amproc::pg_catalog.regprocedure, "
   13683             :                       "amproclefttype::pg_catalog.regtype, "
   13684             :                       "amprocrighttype::pg_catalog.regtype "
   13685             :                       "FROM pg_catalog.pg_amproc ap, pg_catalog.pg_depend "
   13686             :                       "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
   13687             :                       "AND refobjid = '%u'::pg_catalog.oid "
   13688             :                       "AND classid = 'pg_catalog.pg_amproc'::pg_catalog.regclass "
   13689             :                       "AND objid = ap.oid "
   13690             :                       "ORDER BY amprocnum",
   13691             :                       opfinfo->dobj.catId.oid);
   13692             : 
   13693        1078 :     res_procs = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   13694             : 
   13695             :     /* Get additional fields from the pg_opfamily row */
   13696        1078 :     resetPQExpBuffer(query);
   13697             : 
   13698        1078 :     appendPQExpBuffer(query, "SELECT "
   13699             :                       "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opfmethod) AS amname "
   13700             :                       "FROM pg_catalog.pg_opfamily "
   13701             :                       "WHERE oid = '%u'::pg_catalog.oid",
   13702             :                       opfinfo->dobj.catId.oid);
   13703             : 
   13704        1078 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   13705             : 
   13706        1078 :     i_amname = PQfnumber(res, "amname");
   13707             : 
   13708             :     /* amname will still be needed after we PQclear res */
   13709        1078 :     amname = pg_strdup(PQgetvalue(res, 0, i_amname));
   13710             : 
   13711        1078 :     appendPQExpBuffer(delq, "DROP OPERATOR FAMILY %s",
   13712        1078 :                       fmtQualifiedDumpable(opfinfo));
   13713        1078 :     appendPQExpBuffer(delq, " USING %s;\n",
   13714             :                       fmtId(amname));
   13715             : 
   13716             :     /* Build the fixed portion of the CREATE command */
   13717        1078 :     appendPQExpBuffer(q, "CREATE OPERATOR FAMILY %s",
   13718        1078 :                       fmtQualifiedDumpable(opfinfo));
   13719        1078 :     appendPQExpBuffer(q, " USING %s;\n",
   13720             :                       fmtId(amname));
   13721             : 
   13722        1078 :     PQclear(res);
   13723             : 
   13724             :     /* Do we need an ALTER to add loose members? */
   13725        1078 :     if (PQntuples(res_ops) > 0 || PQntuples(res_procs) > 0)
   13726             :     {
   13727          96 :         appendPQExpBuffer(q, "ALTER OPERATOR FAMILY %s",
   13728          96 :                           fmtQualifiedDumpable(opfinfo));
   13729          96 :         appendPQExpBuffer(q, " USING %s ADD\n    ",
   13730             :                           fmtId(amname));
   13731             : 
   13732          96 :         needComma = false;
   13733             : 
   13734             :         /*
   13735             :          * Now fetch and print the OPERATOR entries (pg_amop rows).
   13736             :          */
   13737          96 :         ntups = PQntuples(res_ops);
   13738             : 
   13739          96 :         i_amopstrategy = PQfnumber(res_ops, "amopstrategy");
   13740          96 :         i_amopopr = PQfnumber(res_ops, "amopopr");
   13741          96 :         i_sortfamily = PQfnumber(res_ops, "sortfamily");
   13742          96 :         i_sortfamilynsp = PQfnumber(res_ops, "sortfamilynsp");
   13743             : 
   13744         426 :         for (i = 0; i < ntups; i++)
   13745             :         {
   13746         330 :             amopstrategy = PQgetvalue(res_ops, i, i_amopstrategy);
   13747         330 :             amopopr = PQgetvalue(res_ops, i, i_amopopr);
   13748         330 :             sortfamily = PQgetvalue(res_ops, i, i_sortfamily);
   13749         330 :             sortfamilynsp = PQgetvalue(res_ops, i, i_sortfamilynsp);
   13750             : 
   13751         330 :             if (needComma)
   13752         264 :                 appendPQExpBufferStr(q, " ,\n    ");
   13753             : 
   13754         330 :             appendPQExpBuffer(q, "OPERATOR %s %s",
   13755             :                               amopstrategy, amopopr);
   13756             : 
   13757         330 :             if (strlen(sortfamily) > 0)
   13758             :             {
   13759           0 :                 appendPQExpBufferStr(q, " FOR ORDER BY ");
   13760           0 :                 appendPQExpBuffer(q, "%s.", fmtId(sortfamilynsp));
   13761           0 :                 appendPQExpBufferStr(q, fmtId(sortfamily));
   13762             :             }
   13763             : 
   13764         330 :             needComma = true;
   13765             :         }
   13766             : 
   13767             :         /*
   13768             :          * Now fetch and print the FUNCTION entries (pg_amproc rows).
   13769             :          */
   13770          96 :         ntups = PQntuples(res_procs);
   13771             : 
   13772          96 :         i_amprocnum = PQfnumber(res_procs, "amprocnum");
   13773          96 :         i_amproc = PQfnumber(res_procs, "amproc");
   13774          96 :         i_amproclefttype = PQfnumber(res_procs, "amproclefttype");
   13775          96 :         i_amprocrighttype = PQfnumber(res_procs, "amprocrighttype");
   13776             : 
   13777         456 :         for (i = 0; i < ntups; i++)
   13778             :         {
   13779         360 :             amprocnum = PQgetvalue(res_procs, i, i_amprocnum);
   13780         360 :             amproc = PQgetvalue(res_procs, i, i_amproc);
   13781         360 :             amproclefttype = PQgetvalue(res_procs, i, i_amproclefttype);
   13782         360 :             amprocrighttype = PQgetvalue(res_procs, i, i_amprocrighttype);
   13783             : 
   13784         360 :             if (needComma)
   13785         330 :                 appendPQExpBufferStr(q, " ,\n    ");
   13786             : 
   13787         360 :             appendPQExpBuffer(q, "FUNCTION %s (%s, %s) %s",
   13788             :                               amprocnum, amproclefttype, amprocrighttype,
   13789             :                               amproc);
   13790             : 
   13791         360 :             needComma = true;
   13792             :         }
   13793             : 
   13794          96 :         appendPQExpBufferStr(q, ";\n");
   13795             :     }
   13796             : 
   13797        1078 :     appendPQExpBufferStr(nameusing, fmtId(opfinfo->dobj.name));
   13798        1078 :     appendPQExpBuffer(nameusing, " USING %s",
   13799             :                       fmtId(amname));
   13800             : 
   13801        1078 :     if (dopt->binary_upgrade)
   13802          18 :         binary_upgrade_extension_member(q, &opfinfo->dobj,
   13803          18 :                                         "OPERATOR FAMILY", nameusing->data,
   13804          18 :                                         opfinfo->dobj.namespace->dobj.name);
   13805             : 
   13806        1078 :     if (opfinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   13807        1078 :         ArchiveEntry(fout, opfinfo->dobj.catId, opfinfo->dobj.dumpId,
   13808        1078 :                      ARCHIVE_OPTS(.tag = opfinfo->dobj.name,
   13809             :                                   .namespace = opfinfo->dobj.namespace->dobj.name,
   13810             :                                   .owner = opfinfo->rolname,
   13811             :                                   .description = "OPERATOR FAMILY",
   13812             :                                   .section = SECTION_PRE_DATA,
   13813             :                                   .createStmt = q->data,
   13814             :                                   .dropStmt = delq->data));
   13815             : 
   13816             :     /* Dump Operator Family Comments */
   13817        1078 :     if (opfinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   13818           0 :         dumpComment(fout, "OPERATOR FAMILY", nameusing->data,
   13819           0 :                     opfinfo->dobj.namespace->dobj.name, opfinfo->rolname,
   13820             :                     opfinfo->dobj.catId, 0, opfinfo->dobj.dumpId);
   13821             : 
   13822        1078 :     free(amname);
   13823        1078 :     PQclear(res_ops);
   13824        1078 :     PQclear(res_procs);
   13825        1078 :     destroyPQExpBuffer(query);
   13826        1078 :     destroyPQExpBuffer(q);
   13827        1078 :     destroyPQExpBuffer(delq);
   13828        1078 :     destroyPQExpBuffer(nameusing);
   13829             : }
   13830             : 
   13831             : /*
   13832             :  * dumpCollation
   13833             :  *    write out a single collation definition
   13834             :  */
   13835             : static void
   13836        4928 : dumpCollation(Archive *fout, const CollInfo *collinfo)
   13837             : {
   13838        4928 :     DumpOptions *dopt = fout->dopt;
   13839             :     PQExpBuffer query;
   13840             :     PQExpBuffer q;
   13841             :     PQExpBuffer delq;
   13842             :     char       *qcollname;
   13843             :     PGresult   *res;
   13844             :     int         i_collprovider;
   13845             :     int         i_collisdeterministic;
   13846             :     int         i_collcollate;
   13847             :     int         i_collctype;
   13848             :     int         i_colllocale;
   13849             :     int         i_collicurules;
   13850             :     const char *collprovider;
   13851             :     const char *collcollate;
   13852             :     const char *collctype;
   13853             :     const char *colllocale;
   13854             :     const char *collicurules;
   13855             : 
   13856             :     /* Do nothing if not dumping schema */
   13857        4928 :     if (!dopt->dumpSchema)
   13858          12 :         return;
   13859             : 
   13860        4916 :     query = createPQExpBuffer();
   13861        4916 :     q = createPQExpBuffer();
   13862        4916 :     delq = createPQExpBuffer();
   13863             : 
   13864        4916 :     qcollname = pg_strdup(fmtId(collinfo->dobj.name));
   13865             : 
   13866             :     /* Get collation-specific details */
   13867        4916 :     appendPQExpBufferStr(query, "SELECT ");
   13868             : 
   13869        4916 :     if (fout->remoteVersion >= 100000)
   13870        4916 :         appendPQExpBufferStr(query,
   13871             :                              "collprovider, "
   13872             :                              "collversion, ");
   13873             :     else
   13874           0 :         appendPQExpBufferStr(query,
   13875             :                              "'c' AS collprovider, "
   13876             :                              "NULL AS collversion, ");
   13877             : 
   13878        4916 :     if (fout->remoteVersion >= 120000)
   13879        4916 :         appendPQExpBufferStr(query,
   13880             :                              "collisdeterministic, ");
   13881             :     else
   13882           0 :         appendPQExpBufferStr(query,
   13883             :                              "true AS collisdeterministic, ");
   13884             : 
   13885        4916 :     if (fout->remoteVersion >= 170000)
   13886        4916 :         appendPQExpBufferStr(query,
   13887             :                              "colllocale, ");
   13888           0 :     else if (fout->remoteVersion >= 150000)
   13889           0 :         appendPQExpBufferStr(query,
   13890             :                              "colliculocale AS colllocale, ");
   13891             :     else
   13892           0 :         appendPQExpBufferStr(query,
   13893             :                              "NULL AS colllocale, ");
   13894             : 
   13895        4916 :     if (fout->remoteVersion >= 160000)
   13896        4916 :         appendPQExpBufferStr(query,
   13897             :                              "collicurules, ");
   13898             :     else
   13899           0 :         appendPQExpBufferStr(query,
   13900             :                              "NULL AS collicurules, ");
   13901             : 
   13902        4916 :     appendPQExpBuffer(query,
   13903             :                       "collcollate, "
   13904             :                       "collctype "
   13905             :                       "FROM pg_catalog.pg_collation c "
   13906             :                       "WHERE c.oid = '%u'::pg_catalog.oid",
   13907             :                       collinfo->dobj.catId.oid);
   13908             : 
   13909        4916 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   13910             : 
   13911        4916 :     i_collprovider = PQfnumber(res, "collprovider");
   13912        4916 :     i_collisdeterministic = PQfnumber(res, "collisdeterministic");
   13913        4916 :     i_collcollate = PQfnumber(res, "collcollate");
   13914        4916 :     i_collctype = PQfnumber(res, "collctype");
   13915        4916 :     i_colllocale = PQfnumber(res, "colllocale");
   13916        4916 :     i_collicurules = PQfnumber(res, "collicurules");
   13917             : 
   13918        4916 :     collprovider = PQgetvalue(res, 0, i_collprovider);
   13919             : 
   13920        4916 :     if (!PQgetisnull(res, 0, i_collcollate))
   13921          94 :         collcollate = PQgetvalue(res, 0, i_collcollate);
   13922             :     else
   13923        4822 :         collcollate = NULL;
   13924             : 
   13925        4916 :     if (!PQgetisnull(res, 0, i_collctype))
   13926          94 :         collctype = PQgetvalue(res, 0, i_collctype);
   13927             :     else
   13928        4822 :         collctype = NULL;
   13929             : 
   13930             :     /*
   13931             :      * Before version 15, collcollate and collctype were of type NAME and
   13932             :      * non-nullable. Treat empty strings as NULL for consistency.
   13933             :      */
   13934        4916 :     if (fout->remoteVersion < 150000)
   13935             :     {
   13936           0 :         if (collcollate[0] == '\0')
   13937           0 :             collcollate = NULL;
   13938           0 :         if (collctype[0] == '\0')
   13939           0 :             collctype = NULL;
   13940             :     }
   13941             : 
   13942        4916 :     if (!PQgetisnull(res, 0, i_colllocale))
   13943        4816 :         colllocale = PQgetvalue(res, 0, i_colllocale);
   13944             :     else
   13945         100 :         colllocale = NULL;
   13946             : 
   13947        4916 :     if (!PQgetisnull(res, 0, i_collicurules))
   13948           0 :         collicurules = PQgetvalue(res, 0, i_collicurules);
   13949             :     else
   13950        4916 :         collicurules = NULL;
   13951             : 
   13952        4916 :     appendPQExpBuffer(delq, "DROP COLLATION %s;\n",
   13953        4916 :                       fmtQualifiedDumpable(collinfo));
   13954             : 
   13955        4916 :     appendPQExpBuffer(q, "CREATE COLLATION %s (",
   13956        4916 :                       fmtQualifiedDumpable(collinfo));
   13957             : 
   13958        4916 :     appendPQExpBufferStr(q, "provider = ");
   13959        4916 :     if (collprovider[0] == 'b')
   13960          38 :         appendPQExpBufferStr(q, "builtin");
   13961        4878 :     else if (collprovider[0] == 'c')
   13962          94 :         appendPQExpBufferStr(q, "libc");
   13963        4784 :     else if (collprovider[0] == 'i')
   13964        4778 :         appendPQExpBufferStr(q, "icu");
   13965           6 :     else if (collprovider[0] == 'd')
   13966             :         /* to allow dumping pg_catalog; not accepted on input */
   13967           6 :         appendPQExpBufferStr(q, "default");
   13968             :     else
   13969           0 :         pg_fatal("unrecognized collation provider: %s",
   13970             :                  collprovider);
   13971             : 
   13972        4916 :     if (strcmp(PQgetvalue(res, 0, i_collisdeterministic), "f") == 0)
   13973           0 :         appendPQExpBufferStr(q, ", deterministic = false");
   13974             : 
   13975        4916 :     if (collprovider[0] == 'd')
   13976             :     {
   13977           6 :         if (collcollate || collctype || colllocale || collicurules)
   13978           0 :             pg_log_warning("invalid collation \"%s\"", qcollname);
   13979             : 
   13980             :         /* no locale -- the default collation cannot be reloaded anyway */
   13981             :     }
   13982        4910 :     else if (collprovider[0] == 'b')
   13983             :     {
   13984          38 :         if (collcollate || collctype || !colllocale || collicurules)
   13985           0 :             pg_log_warning("invalid collation \"%s\"", qcollname);
   13986             : 
   13987          38 :         appendPQExpBufferStr(q, ", locale = ");
   13988          38 :         appendStringLiteralAH(q, colllocale ? colllocale : "",
   13989             :                               fout);
   13990             :     }
   13991        4872 :     else if (collprovider[0] == 'i')
   13992             :     {
   13993        4778 :         if (fout->remoteVersion >= 150000)
   13994             :         {
   13995        4778 :             if (collcollate || collctype || !colllocale)
   13996           0 :                 pg_log_warning("invalid collation \"%s\"", qcollname);
   13997             : 
   13998        4778 :             appendPQExpBufferStr(q, ", locale = ");
   13999        4778 :             appendStringLiteralAH(q, colllocale ? colllocale : "",
   14000             :                                   fout);
   14001             :         }
   14002             :         else
   14003             :         {
   14004           0 :             if (!collcollate || !collctype || colllocale ||
   14005           0 :                 strcmp(collcollate, collctype) != 0)
   14006           0 :                 pg_log_warning("invalid collation \"%s\"", qcollname);
   14007             : 
   14008           0 :             appendPQExpBufferStr(q, ", locale = ");
   14009           0 :             appendStringLiteralAH(q, collcollate ? collcollate : "", fout);
   14010             :         }
   14011             : 
   14012        4778 :         if (collicurules)
   14013             :         {
   14014           0 :             appendPQExpBufferStr(q, ", rules = ");
   14015           0 :             appendStringLiteralAH(q, collicurules ? collicurules : "", fout);
   14016             :         }
   14017             :     }
   14018          94 :     else if (collprovider[0] == 'c')
   14019             :     {
   14020          94 :         if (colllocale || collicurules || !collcollate || !collctype)
   14021           0 :             pg_log_warning("invalid collation \"%s\"", qcollname);
   14022             : 
   14023          94 :         if (collcollate && collctype && strcmp(collcollate, collctype) == 0)
   14024             :         {
   14025          94 :             appendPQExpBufferStr(q, ", locale = ");
   14026          94 :             appendStringLiteralAH(q, collcollate ? collcollate : "", fout);
   14027             :         }
   14028             :         else
   14029             :         {
   14030           0 :             appendPQExpBufferStr(q, ", lc_collate = ");
   14031           0 :             appendStringLiteralAH(q, collcollate ? collcollate : "", fout);
   14032           0 :             appendPQExpBufferStr(q, ", lc_ctype = ");
   14033           0 :             appendStringLiteralAH(q, collctype ? collctype : "", fout);
   14034             :         }
   14035             :     }
   14036             :     else
   14037           0 :         pg_fatal("unrecognized collation provider: %s", collprovider);
   14038             : 
   14039             :     /*
   14040             :      * For binary upgrade, carry over the collation version.  For normal
   14041             :      * dump/restore, omit the version, so that it is computed upon restore.
   14042             :      */
   14043        4916 :     if (dopt->binary_upgrade)
   14044             :     {
   14045             :         int         i_collversion;
   14046             : 
   14047          10 :         i_collversion = PQfnumber(res, "collversion");
   14048          10 :         if (!PQgetisnull(res, 0, i_collversion))
   14049             :         {
   14050           8 :             appendPQExpBufferStr(q, ", version = ");
   14051           8 :             appendStringLiteralAH(q,
   14052             :                                   PQgetvalue(res, 0, i_collversion),
   14053             :                                   fout);
   14054             :         }
   14055             :     }
   14056             : 
   14057        4916 :     appendPQExpBufferStr(q, ");\n");
   14058             : 
   14059        4916 :     if (dopt->binary_upgrade)
   14060          10 :         binary_upgrade_extension_member(q, &collinfo->dobj,
   14061             :                                         "COLLATION", qcollname,
   14062          10 :                                         collinfo->dobj.namespace->dobj.name);
   14063             : 
   14064        4916 :     if (collinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   14065        4916 :         ArchiveEntry(fout, collinfo->dobj.catId, collinfo->dobj.dumpId,
   14066        4916 :                      ARCHIVE_OPTS(.tag = collinfo->dobj.name,
   14067             :                                   .namespace = collinfo->dobj.namespace->dobj.name,
   14068             :                                   .owner = collinfo->rolname,
   14069             :                                   .description = "COLLATION",
   14070             :                                   .section = SECTION_PRE_DATA,
   14071             :                                   .createStmt = q->data,
   14072             :                                   .dropStmt = delq->data));
   14073             : 
   14074             :     /* Dump Collation Comments */
   14075        4916 :     if (collinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   14076        4738 :         dumpComment(fout, "COLLATION", qcollname,
   14077        4738 :                     collinfo->dobj.namespace->dobj.name, collinfo->rolname,
   14078             :                     collinfo->dobj.catId, 0, collinfo->dobj.dumpId);
   14079             : 
   14080        4916 :     PQclear(res);
   14081             : 
   14082        4916 :     destroyPQExpBuffer(query);
   14083        4916 :     destroyPQExpBuffer(q);
   14084        4916 :     destroyPQExpBuffer(delq);
   14085        4916 :     free(qcollname);
   14086             : }
   14087             : 
   14088             : /*
   14089             :  * dumpConversion
   14090             :  *    write out a single conversion definition
   14091             :  */
   14092             : static void
   14093         840 : dumpConversion(Archive *fout, const ConvInfo *convinfo)
   14094             : {
   14095         840 :     DumpOptions *dopt = fout->dopt;
   14096             :     PQExpBuffer query;
   14097             :     PQExpBuffer q;
   14098             :     PQExpBuffer delq;
   14099             :     char       *qconvname;
   14100             :     PGresult   *res;
   14101             :     int         i_conforencoding;
   14102             :     int         i_contoencoding;
   14103             :     int         i_conproc;
   14104             :     int         i_condefault;
   14105             :     const char *conforencoding;
   14106             :     const char *contoencoding;
   14107             :     const char *conproc;
   14108             :     bool        condefault;
   14109             : 
   14110             :     /* Do nothing if not dumping schema */
   14111         840 :     if (!dopt->dumpSchema)
   14112           6 :         return;
   14113             : 
   14114         834 :     query = createPQExpBuffer();
   14115         834 :     q = createPQExpBuffer();
   14116         834 :     delq = createPQExpBuffer();
   14117             : 
   14118         834 :     qconvname = pg_strdup(fmtId(convinfo->dobj.name));
   14119             : 
   14120             :     /* Get conversion-specific details */
   14121         834 :     appendPQExpBuffer(query, "SELECT "
   14122             :                       "pg_catalog.pg_encoding_to_char(conforencoding) AS conforencoding, "
   14123             :                       "pg_catalog.pg_encoding_to_char(contoencoding) AS contoencoding, "
   14124             :                       "conproc, condefault "
   14125             :                       "FROM pg_catalog.pg_conversion c "
   14126             :                       "WHERE c.oid = '%u'::pg_catalog.oid",
   14127             :                       convinfo->dobj.catId.oid);
   14128             : 
   14129         834 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   14130             : 
   14131         834 :     i_conforencoding = PQfnumber(res, "conforencoding");
   14132         834 :     i_contoencoding = PQfnumber(res, "contoencoding");
   14133         834 :     i_conproc = PQfnumber(res, "conproc");
   14134         834 :     i_condefault = PQfnumber(res, "condefault");
   14135             : 
   14136         834 :     conforencoding = PQgetvalue(res, 0, i_conforencoding);
   14137         834 :     contoencoding = PQgetvalue(res, 0, i_contoencoding);
   14138         834 :     conproc = PQgetvalue(res, 0, i_conproc);
   14139         834 :     condefault = (PQgetvalue(res, 0, i_condefault)[0] == 't');
   14140             : 
   14141         834 :     appendPQExpBuffer(delq, "DROP CONVERSION %s;\n",
   14142         834 :                       fmtQualifiedDumpable(convinfo));
   14143             : 
   14144         834 :     appendPQExpBuffer(q, "CREATE %sCONVERSION %s FOR ",
   14145             :                       (condefault) ? "DEFAULT " : "",
   14146         834 :                       fmtQualifiedDumpable(convinfo));
   14147         834 :     appendStringLiteralAH(q, conforencoding, fout);
   14148         834 :     appendPQExpBufferStr(q, " TO ");
   14149         834 :     appendStringLiteralAH(q, contoencoding, fout);
   14150             :     /* regproc output is already sufficiently quoted */
   14151         834 :     appendPQExpBuffer(q, " FROM %s;\n", conproc);
   14152             : 
   14153         834 :     if (dopt->binary_upgrade)
   14154           2 :         binary_upgrade_extension_member(q, &convinfo->dobj,
   14155             :                                         "CONVERSION", qconvname,
   14156           2 :                                         convinfo->dobj.namespace->dobj.name);
   14157             : 
   14158         834 :     if (convinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   14159         834 :         ArchiveEntry(fout, convinfo->dobj.catId, convinfo->dobj.dumpId,
   14160         834 :                      ARCHIVE_OPTS(.tag = convinfo->dobj.name,
   14161             :                                   .namespace = convinfo->dobj.namespace->dobj.name,
   14162             :                                   .owner = convinfo->rolname,
   14163             :                                   .description = "CONVERSION",
   14164             :                                   .section = SECTION_PRE_DATA,
   14165             :                                   .createStmt = q->data,
   14166             :                                   .dropStmt = delq->data));
   14167             : 
   14168             :     /* Dump Conversion Comments */
   14169         834 :     if (convinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   14170         834 :         dumpComment(fout, "CONVERSION", qconvname,
   14171         834 :                     convinfo->dobj.namespace->dobj.name, convinfo->rolname,
   14172             :                     convinfo->dobj.catId, 0, convinfo->dobj.dumpId);
   14173             : 
   14174         834 :     PQclear(res);
   14175             : 
   14176         834 :     destroyPQExpBuffer(query);
   14177         834 :     destroyPQExpBuffer(q);
   14178         834 :     destroyPQExpBuffer(delq);
   14179         834 :     free(qconvname);
   14180             : }
   14181             : 
   14182             : /*
   14183             :  * format_aggregate_signature: generate aggregate name and argument list
   14184             :  *
   14185             :  * The argument type names are qualified if needed.  The aggregate name
   14186             :  * is never qualified.
   14187             :  */
   14188             : static char *
   14189         572 : format_aggregate_signature(const AggInfo *agginfo, Archive *fout, bool honor_quotes)
   14190             : {
   14191             :     PQExpBufferData buf;
   14192             :     int         j;
   14193             : 
   14194         572 :     initPQExpBuffer(&buf);
   14195         572 :     if (honor_quotes)
   14196           0 :         appendPQExpBufferStr(&buf, fmtId(agginfo->aggfn.dobj.name));
   14197             :     else
   14198         572 :         appendPQExpBufferStr(&buf, agginfo->aggfn.dobj.name);
   14199             : 
   14200         572 :     if (agginfo->aggfn.nargs == 0)
   14201          80 :         appendPQExpBufferStr(&buf, "(*)");
   14202             :     else
   14203             :     {
   14204         492 :         appendPQExpBufferChar(&buf, '(');
   14205        1074 :         for (j = 0; j < agginfo->aggfn.nargs; j++)
   14206         582 :             appendPQExpBuffer(&buf, "%s%s",
   14207             :                               (j > 0) ? ", " : "",
   14208             :                               getFormattedTypeName(fout,
   14209         582 :                                                    agginfo->aggfn.argtypes[j],
   14210             :                                                    zeroIsError));
   14211         492 :         appendPQExpBufferChar(&buf, ')');
   14212             :     }
   14213         572 :     return buf.data;
   14214             : }
   14215             : 
   14216             : /*
   14217             :  * dumpAgg
   14218             :  *    write out a single aggregate definition
   14219             :  */
   14220             : static void
   14221         580 : dumpAgg(Archive *fout, const AggInfo *agginfo)
   14222             : {
   14223         580 :     DumpOptions *dopt = fout->dopt;
   14224             :     PQExpBuffer query;
   14225             :     PQExpBuffer q;
   14226             :     PQExpBuffer delq;
   14227             :     PQExpBuffer details;
   14228             :     char       *aggsig;         /* identity signature */
   14229         580 :     char       *aggfullsig = NULL;  /* full signature */
   14230             :     char       *aggsig_tag;
   14231             :     PGresult   *res;
   14232             :     int         i_agginitval;
   14233             :     int         i_aggminitval;
   14234             :     const char *aggtransfn;
   14235             :     const char *aggfinalfn;
   14236             :     const char *aggcombinefn;
   14237             :     const char *aggserialfn;
   14238             :     const char *aggdeserialfn;
   14239             :     const char *aggmtransfn;
   14240             :     const char *aggminvtransfn;
   14241             :     const char *aggmfinalfn;
   14242             :     bool        aggfinalextra;
   14243             :     bool        aggmfinalextra;
   14244             :     char        aggfinalmodify;
   14245             :     char        aggmfinalmodify;
   14246             :     const char *aggsortop;
   14247             :     char       *aggsortconvop;
   14248             :     char        aggkind;
   14249             :     const char *aggtranstype;
   14250             :     const char *aggtransspace;
   14251             :     const char *aggmtranstype;
   14252             :     const char *aggmtransspace;
   14253             :     const char *agginitval;
   14254             :     const char *aggminitval;
   14255             :     const char *proparallel;
   14256             :     char        defaultfinalmodify;
   14257             : 
   14258             :     /* Do nothing if not dumping schema */
   14259         580 :     if (!dopt->dumpSchema)
   14260           8 :         return;
   14261             : 
   14262         572 :     query = createPQExpBuffer();
   14263         572 :     q = createPQExpBuffer();
   14264         572 :     delq = createPQExpBuffer();
   14265         572 :     details = createPQExpBuffer();
   14266             : 
   14267         572 :     if (!fout->is_prepared[PREPQUERY_DUMPAGG])
   14268             :     {
   14269             :         /* Set up query for aggregate-specific details */
   14270         112 :         appendPQExpBufferStr(query,
   14271             :                              "PREPARE dumpAgg(pg_catalog.oid) AS\n");
   14272             : 
   14273         112 :         appendPQExpBufferStr(query,
   14274             :                              "SELECT "
   14275             :                              "aggtransfn,\n"
   14276             :                              "aggfinalfn,\n"
   14277             :                              "aggtranstype::pg_catalog.regtype,\n"
   14278             :                              "agginitval,\n"
   14279             :                              "aggsortop,\n"
   14280             :                              "pg_catalog.pg_get_function_arguments(p.oid) AS funcargs,\n"
   14281             :                              "pg_catalog.pg_get_function_identity_arguments(p.oid) AS funciargs,\n");
   14282             : 
   14283         112 :         if (fout->remoteVersion >= 90400)
   14284         112 :             appendPQExpBufferStr(query,
   14285             :                                  "aggkind,\n"
   14286             :                                  "aggmtransfn,\n"
   14287             :                                  "aggminvtransfn,\n"
   14288             :                                  "aggmfinalfn,\n"
   14289             :                                  "aggmtranstype::pg_catalog.regtype,\n"
   14290             :                                  "aggfinalextra,\n"
   14291             :                                  "aggmfinalextra,\n"
   14292             :                                  "aggtransspace,\n"
   14293             :                                  "aggmtransspace,\n"
   14294             :                                  "aggminitval,\n");
   14295             :         else
   14296           0 :             appendPQExpBufferStr(query,
   14297             :                                  "'n' AS aggkind,\n"
   14298             :                                  "'-' AS aggmtransfn,\n"
   14299             :                                  "'-' AS aggminvtransfn,\n"
   14300             :                                  "'-' AS aggmfinalfn,\n"
   14301             :                                  "0 AS aggmtranstype,\n"
   14302             :                                  "false AS aggfinalextra,\n"
   14303             :                                  "false AS aggmfinalextra,\n"
   14304             :                                  "0 AS aggtransspace,\n"
   14305             :                                  "0 AS aggmtransspace,\n"
   14306             :                                  "NULL AS aggminitval,\n");
   14307             : 
   14308         112 :         if (fout->remoteVersion >= 90600)
   14309         112 :             appendPQExpBufferStr(query,
   14310             :                                  "aggcombinefn,\n"
   14311             :                                  "aggserialfn,\n"
   14312             :                                  "aggdeserialfn,\n"
   14313             :                                  "proparallel,\n");
   14314             :         else
   14315           0 :             appendPQExpBufferStr(query,
   14316             :                                  "'-' AS aggcombinefn,\n"
   14317             :                                  "'-' AS aggserialfn,\n"
   14318             :                                  "'-' AS aggdeserialfn,\n"
   14319             :                                  "'u' AS proparallel,\n");
   14320             : 
   14321         112 :         if (fout->remoteVersion >= 110000)
   14322         112 :             appendPQExpBufferStr(query,
   14323             :                                  "aggfinalmodify,\n"
   14324             :                                  "aggmfinalmodify\n");
   14325             :         else
   14326           0 :             appendPQExpBufferStr(query,
   14327             :                                  "'0' AS aggfinalmodify,\n"
   14328             :                                  "'0' AS aggmfinalmodify\n");
   14329             : 
   14330         112 :         appendPQExpBufferStr(query,
   14331             :                              "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
   14332             :                              "WHERE a.aggfnoid = p.oid "
   14333             :                              "AND p.oid = $1");
   14334             : 
   14335         112 :         ExecuteSqlStatement(fout, query->data);
   14336             : 
   14337         112 :         fout->is_prepared[PREPQUERY_DUMPAGG] = true;
   14338             :     }
   14339             : 
   14340         572 :     printfPQExpBuffer(query,
   14341             :                       "EXECUTE dumpAgg('%u')",
   14342             :                       agginfo->aggfn.dobj.catId.oid);
   14343             : 
   14344         572 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   14345             : 
   14346         572 :     i_agginitval = PQfnumber(res, "agginitval");
   14347         572 :     i_aggminitval = PQfnumber(res, "aggminitval");
   14348             : 
   14349         572 :     aggtransfn = PQgetvalue(res, 0, PQfnumber(res, "aggtransfn"));
   14350         572 :     aggfinalfn = PQgetvalue(res, 0, PQfnumber(res, "aggfinalfn"));
   14351         572 :     aggcombinefn = PQgetvalue(res, 0, PQfnumber(res, "aggcombinefn"));
   14352         572 :     aggserialfn = PQgetvalue(res, 0, PQfnumber(res, "aggserialfn"));
   14353         572 :     aggdeserialfn = PQgetvalue(res, 0, PQfnumber(res, "aggdeserialfn"));
   14354         572 :     aggmtransfn = PQgetvalue(res, 0, PQfnumber(res, "aggmtransfn"));
   14355         572 :     aggminvtransfn = PQgetvalue(res, 0, PQfnumber(res, "aggminvtransfn"));
   14356         572 :     aggmfinalfn = PQgetvalue(res, 0, PQfnumber(res, "aggmfinalfn"));
   14357         572 :     aggfinalextra = (PQgetvalue(res, 0, PQfnumber(res, "aggfinalextra"))[0] == 't');
   14358         572 :     aggmfinalextra = (PQgetvalue(res, 0, PQfnumber(res, "aggmfinalextra"))[0] == 't');
   14359         572 :     aggfinalmodify = PQgetvalue(res, 0, PQfnumber(res, "aggfinalmodify"))[0];
   14360         572 :     aggmfinalmodify = PQgetvalue(res, 0, PQfnumber(res, "aggmfinalmodify"))[0];
   14361         572 :     aggsortop = PQgetvalue(res, 0, PQfnumber(res, "aggsortop"));
   14362         572 :     aggkind = PQgetvalue(res, 0, PQfnumber(res, "aggkind"))[0];
   14363         572 :     aggtranstype = PQgetvalue(res, 0, PQfnumber(res, "aggtranstype"));
   14364         572 :     aggtransspace = PQgetvalue(res, 0, PQfnumber(res, "aggtransspace"));
   14365         572 :     aggmtranstype = PQgetvalue(res, 0, PQfnumber(res, "aggmtranstype"));
   14366         572 :     aggmtransspace = PQgetvalue(res, 0, PQfnumber(res, "aggmtransspace"));
   14367         572 :     agginitval = PQgetvalue(res, 0, i_agginitval);
   14368         572 :     aggminitval = PQgetvalue(res, 0, i_aggminitval);
   14369         572 :     proparallel = PQgetvalue(res, 0, PQfnumber(res, "proparallel"));
   14370             : 
   14371             :     {
   14372             :         char       *funcargs;
   14373             :         char       *funciargs;
   14374             : 
   14375         572 :         funcargs = PQgetvalue(res, 0, PQfnumber(res, "funcargs"));
   14376         572 :         funciargs = PQgetvalue(res, 0, PQfnumber(res, "funciargs"));
   14377         572 :         aggfullsig = format_function_arguments(&agginfo->aggfn, funcargs, true);
   14378         572 :         aggsig = format_function_arguments(&agginfo->aggfn, funciargs, true);
   14379             :     }
   14380             : 
   14381         572 :     aggsig_tag = format_aggregate_signature(agginfo, fout, false);
   14382             : 
   14383             :     /* identify default modify flag for aggkind (must match DefineAggregate) */
   14384         572 :     defaultfinalmodify = (aggkind == AGGKIND_NORMAL) ? AGGMODIFY_READ_ONLY : AGGMODIFY_READ_WRITE;
   14385             :     /* replace omitted flags for old versions */
   14386         572 :     if (aggfinalmodify == '0')
   14387           0 :         aggfinalmodify = defaultfinalmodify;
   14388         572 :     if (aggmfinalmodify == '0')
   14389           0 :         aggmfinalmodify = defaultfinalmodify;
   14390             : 
   14391             :     /* regproc and regtype output is already sufficiently quoted */
   14392         572 :     appendPQExpBuffer(details, "    SFUNC = %s,\n    STYPE = %s",
   14393             :                       aggtransfn, aggtranstype);
   14394             : 
   14395         572 :     if (strcmp(aggtransspace, "0") != 0)
   14396             :     {
   14397          10 :         appendPQExpBuffer(details, ",\n    SSPACE = %s",
   14398             :                           aggtransspace);
   14399             :     }
   14400             : 
   14401         572 :     if (!PQgetisnull(res, 0, i_agginitval))
   14402             :     {
   14403         416 :         appendPQExpBufferStr(details, ",\n    INITCOND = ");
   14404         416 :         appendStringLiteralAH(details, agginitval, fout);
   14405             :     }
   14406             : 
   14407         572 :     if (strcmp(aggfinalfn, "-") != 0)
   14408             :     {
   14409         266 :         appendPQExpBuffer(details, ",\n    FINALFUNC = %s",
   14410             :                           aggfinalfn);
   14411         266 :         if (aggfinalextra)
   14412          20 :             appendPQExpBufferStr(details, ",\n    FINALFUNC_EXTRA");
   14413         266 :         if (aggfinalmodify != defaultfinalmodify)
   14414             :         {
   14415          66 :             switch (aggfinalmodify)
   14416             :             {
   14417           0 :                 case AGGMODIFY_READ_ONLY:
   14418           0 :                     appendPQExpBufferStr(details, ",\n    FINALFUNC_MODIFY = READ_ONLY");
   14419           0 :                     break;
   14420          66 :                 case AGGMODIFY_SHAREABLE:
   14421          66 :                     appendPQExpBufferStr(details, ",\n    FINALFUNC_MODIFY = SHAREABLE");
   14422          66 :                     break;
   14423           0 :                 case AGGMODIFY_READ_WRITE:
   14424           0 :                     appendPQExpBufferStr(details, ",\n    FINALFUNC_MODIFY = READ_WRITE");
   14425           0 :                     break;
   14426           0 :                 default:
   14427           0 :                     pg_fatal("unrecognized aggfinalmodify value for aggregate \"%s\"",
   14428             :                              agginfo->aggfn.dobj.name);
   14429             :                     break;
   14430             :             }
   14431         506 :         }
   14432             :     }
   14433             : 
   14434         572 :     if (strcmp(aggcombinefn, "-") != 0)
   14435           0 :         appendPQExpBuffer(details, ",\n    COMBINEFUNC = %s", aggcombinefn);
   14436             : 
   14437         572 :     if (strcmp(aggserialfn, "-") != 0)
   14438           0 :         appendPQExpBuffer(details, ",\n    SERIALFUNC = %s", aggserialfn);
   14439             : 
   14440         572 :     if (strcmp(aggdeserialfn, "-") != 0)
   14441           0 :         appendPQExpBuffer(details, ",\n    DESERIALFUNC = %s", aggdeserialfn);
   14442             : 
   14443         572 :     if (strcmp(aggmtransfn, "-") != 0)
   14444             :     {
   14445          60 :         appendPQExpBuffer(details, ",\n    MSFUNC = %s,\n    MINVFUNC = %s,\n    MSTYPE = %s",
   14446             :                           aggmtransfn,
   14447             :                           aggminvtransfn,
   14448             :                           aggmtranstype);
   14449             :     }
   14450             : 
   14451         572 :     if (strcmp(aggmtransspace, "0") != 0)
   14452             :     {
   14453           0 :         appendPQExpBuffer(details, ",\n    MSSPACE = %s",
   14454             :                           aggmtransspace);
   14455             :     }
   14456             : 
   14457         572 :     if (!PQgetisnull(res, 0, i_aggminitval))
   14458             :     {
   14459          20 :         appendPQExpBufferStr(details, ",\n    MINITCOND = ");
   14460          20 :         appendStringLiteralAH(details, aggminitval, fout);
   14461             :     }
   14462             : 
   14463         572 :     if (strcmp(aggmfinalfn, "-") != 0)
   14464             :     {
   14465           0 :         appendPQExpBuffer(details, ",\n    MFINALFUNC = %s",
   14466             :                           aggmfinalfn);
   14467           0 :         if (aggmfinalextra)
   14468           0 :             appendPQExpBufferStr(details, ",\n    MFINALFUNC_EXTRA");
   14469           0 :         if (aggmfinalmodify != defaultfinalmodify)
   14470             :         {
   14471           0 :             switch (aggmfinalmodify)
   14472             :             {
   14473           0 :                 case AGGMODIFY_READ_ONLY:
   14474           0 :                     appendPQExpBufferStr(details, ",\n    MFINALFUNC_MODIFY = READ_ONLY");
   14475           0 :                     break;
   14476           0 :                 case AGGMODIFY_SHAREABLE:
   14477           0 :                     appendPQExpBufferStr(details, ",\n    MFINALFUNC_MODIFY = SHAREABLE");
   14478           0 :                     break;
   14479           0 :                 case AGGMODIFY_READ_WRITE:
   14480           0 :                     appendPQExpBufferStr(details, ",\n    MFINALFUNC_MODIFY = READ_WRITE");
   14481           0 :                     break;
   14482           0 :                 default:
   14483           0 :                     pg_fatal("unrecognized aggmfinalmodify value for aggregate \"%s\"",
   14484             :                              agginfo->aggfn.dobj.name);
   14485             :                     break;
   14486             :             }
   14487         572 :         }
   14488             :     }
   14489             : 
   14490         572 :     aggsortconvop = getFormattedOperatorName(aggsortop);
   14491         572 :     if (aggsortconvop)
   14492             :     {
   14493           0 :         appendPQExpBuffer(details, ",\n    SORTOP = %s",
   14494             :                           aggsortconvop);
   14495           0 :         free(aggsortconvop);
   14496             :     }
   14497             : 
   14498         572 :     if (aggkind == AGGKIND_HYPOTHETICAL)
   14499          10 :         appendPQExpBufferStr(details, ",\n    HYPOTHETICAL");
   14500             : 
   14501         572 :     if (proparallel[0] != PROPARALLEL_UNSAFE)
   14502             :     {
   14503          10 :         if (proparallel[0] == PROPARALLEL_SAFE)
   14504          10 :             appendPQExpBufferStr(details, ",\n    PARALLEL = safe");
   14505           0 :         else if (proparallel[0] == PROPARALLEL_RESTRICTED)
   14506           0 :             appendPQExpBufferStr(details, ",\n    PARALLEL = restricted");
   14507           0 :         else if (proparallel[0] != PROPARALLEL_UNSAFE)
   14508           0 :             pg_fatal("unrecognized proparallel value for function \"%s\"",
   14509             :                      agginfo->aggfn.dobj.name);
   14510             :     }
   14511             : 
   14512         572 :     appendPQExpBuffer(delq, "DROP AGGREGATE %s.%s;\n",
   14513         572 :                       fmtId(agginfo->aggfn.dobj.namespace->dobj.name),
   14514             :                       aggsig);
   14515             : 
   14516        1144 :     appendPQExpBuffer(q, "CREATE AGGREGATE %s.%s (\n%s\n);\n",
   14517         572 :                       fmtId(agginfo->aggfn.dobj.namespace->dobj.name),
   14518             :                       aggfullsig ? aggfullsig : aggsig, details->data);
   14519             : 
   14520         572 :     if (dopt->binary_upgrade)
   14521          98 :         binary_upgrade_extension_member(q, &agginfo->aggfn.dobj,
   14522             :                                         "AGGREGATE", aggsig,
   14523          98 :                                         agginfo->aggfn.dobj.namespace->dobj.name);
   14524             : 
   14525         572 :     if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_DEFINITION)
   14526         538 :         ArchiveEntry(fout, agginfo->aggfn.dobj.catId,
   14527             :                      agginfo->aggfn.dobj.dumpId,
   14528         538 :                      ARCHIVE_OPTS(.tag = aggsig_tag,
   14529             :                                   .namespace = agginfo->aggfn.dobj.namespace->dobj.name,
   14530             :                                   .owner = agginfo->aggfn.rolname,
   14531             :                                   .description = "AGGREGATE",
   14532             :                                   .section = SECTION_PRE_DATA,
   14533             :                                   .createStmt = q->data,
   14534             :                                   .dropStmt = delq->data));
   14535             : 
   14536             :     /* Dump Aggregate Comments */
   14537         572 :     if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_COMMENT)
   14538          20 :         dumpComment(fout, "AGGREGATE", aggsig,
   14539          20 :                     agginfo->aggfn.dobj.namespace->dobj.name,
   14540             :                     agginfo->aggfn.rolname,
   14541             :                     agginfo->aggfn.dobj.catId, 0, agginfo->aggfn.dobj.dumpId);
   14542             : 
   14543         572 :     if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_SECLABEL)
   14544           0 :         dumpSecLabel(fout, "AGGREGATE", aggsig,
   14545           0 :                      agginfo->aggfn.dobj.namespace->dobj.name,
   14546             :                      agginfo->aggfn.rolname,
   14547             :                      agginfo->aggfn.dobj.catId, 0, agginfo->aggfn.dobj.dumpId);
   14548             : 
   14549             :     /*
   14550             :      * Since there is no GRANT ON AGGREGATE syntax, we have to make the ACL
   14551             :      * command look like a function's GRANT; in particular this affects the
   14552             :      * syntax for zero-argument aggregates and ordered-set aggregates.
   14553             :      */
   14554         572 :     free(aggsig);
   14555             : 
   14556         572 :     aggsig = format_function_signature(fout, &agginfo->aggfn, true);
   14557             : 
   14558         572 :     if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_ACL)
   14559          36 :         dumpACL(fout, agginfo->aggfn.dobj.dumpId, InvalidDumpId,
   14560             :                 "FUNCTION", aggsig, NULL,
   14561          36 :                 agginfo->aggfn.dobj.namespace->dobj.name,
   14562             :                 NULL, agginfo->aggfn.rolname, &agginfo->aggfn.dacl);
   14563             : 
   14564         572 :     free(aggsig);
   14565         572 :     free(aggfullsig);
   14566         572 :     free(aggsig_tag);
   14567             : 
   14568         572 :     PQclear(res);
   14569             : 
   14570         572 :     destroyPQExpBuffer(query);
   14571         572 :     destroyPQExpBuffer(q);
   14572         572 :     destroyPQExpBuffer(delq);
   14573         572 :     destroyPQExpBuffer(details);
   14574             : }
   14575             : 
   14576             : /*
   14577             :  * dumpTSParser
   14578             :  *    write out a single text search parser
   14579             :  */
   14580             : static void
   14581          78 : dumpTSParser(Archive *fout, const TSParserInfo *prsinfo)
   14582             : {
   14583          78 :     DumpOptions *dopt = fout->dopt;
   14584             :     PQExpBuffer q;
   14585             :     PQExpBuffer delq;
   14586             :     char       *qprsname;
   14587             : 
   14588             :     /* Do nothing if not dumping schema */
   14589          78 :     if (!dopt->dumpSchema)
   14590           6 :         return;
   14591             : 
   14592          72 :     q = createPQExpBuffer();
   14593          72 :     delq = createPQExpBuffer();
   14594             : 
   14595          72 :     qprsname = pg_strdup(fmtId(prsinfo->dobj.name));
   14596             : 
   14597          72 :     appendPQExpBuffer(q, "CREATE TEXT SEARCH PARSER %s (\n",
   14598          72 :                       fmtQualifiedDumpable(prsinfo));
   14599             : 
   14600          72 :     appendPQExpBuffer(q, "    START = %s,\n",
   14601             :                       convertTSFunction(fout, prsinfo->prsstart));
   14602          72 :     appendPQExpBuffer(q, "    GETTOKEN = %s,\n",
   14603             :                       convertTSFunction(fout, prsinfo->prstoken));
   14604          72 :     appendPQExpBuffer(q, "    END = %s,\n",
   14605             :                       convertTSFunction(fout, prsinfo->prsend));
   14606          72 :     if (prsinfo->prsheadline != InvalidOid)
   14607           6 :         appendPQExpBuffer(q, "    HEADLINE = %s,\n",
   14608             :                           convertTSFunction(fout, prsinfo->prsheadline));
   14609          72 :     appendPQExpBuffer(q, "    LEXTYPES = %s );\n",
   14610             :                       convertTSFunction(fout, prsinfo->prslextype));
   14611             : 
   14612          72 :     appendPQExpBuffer(delq, "DROP TEXT SEARCH PARSER %s;\n",
   14613          72 :                       fmtQualifiedDumpable(prsinfo));
   14614             : 
   14615          72 :     if (dopt->binary_upgrade)
   14616           2 :         binary_upgrade_extension_member(q, &prsinfo->dobj,
   14617             :                                         "TEXT SEARCH PARSER", qprsname,
   14618           2 :                                         prsinfo->dobj.namespace->dobj.name);
   14619             : 
   14620          72 :     if (prsinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   14621          72 :         ArchiveEntry(fout, prsinfo->dobj.catId, prsinfo->dobj.dumpId,
   14622          72 :                      ARCHIVE_OPTS(.tag = prsinfo->dobj.name,
   14623             :                                   .namespace = prsinfo->dobj.namespace->dobj.name,
   14624             :                                   .description = "TEXT SEARCH PARSER",
   14625             :                                   .section = SECTION_PRE_DATA,
   14626             :                                   .createStmt = q->data,
   14627             :                                   .dropStmt = delq->data));
   14628             : 
   14629             :     /* Dump Parser Comments */
   14630          72 :     if (prsinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   14631          72 :         dumpComment(fout, "TEXT SEARCH PARSER", qprsname,
   14632          72 :                     prsinfo->dobj.namespace->dobj.name, "",
   14633             :                     prsinfo->dobj.catId, 0, prsinfo->dobj.dumpId);
   14634             : 
   14635          72 :     destroyPQExpBuffer(q);
   14636          72 :     destroyPQExpBuffer(delq);
   14637          72 :     free(qprsname);
   14638             : }
   14639             : 
   14640             : /*
   14641             :  * dumpTSDictionary
   14642             :  *    write out a single text search dictionary
   14643             :  */
   14644             : static void
   14645         336 : dumpTSDictionary(Archive *fout, const TSDictInfo *dictinfo)
   14646             : {
   14647         336 :     DumpOptions *dopt = fout->dopt;
   14648             :     PQExpBuffer q;
   14649             :     PQExpBuffer delq;
   14650             :     PQExpBuffer query;
   14651             :     char       *qdictname;
   14652             :     PGresult   *res;
   14653             :     char       *nspname;
   14654             :     char       *tmplname;
   14655             : 
   14656             :     /* Do nothing if not dumping schema */
   14657         336 :     if (!dopt->dumpSchema)
   14658           6 :         return;
   14659             : 
   14660         330 :     q = createPQExpBuffer();
   14661         330 :     delq = createPQExpBuffer();
   14662         330 :     query = createPQExpBuffer();
   14663             : 
   14664         330 :     qdictname = pg_strdup(fmtId(dictinfo->dobj.name));
   14665             : 
   14666             :     /* Fetch name and namespace of the dictionary's template */
   14667         330 :     appendPQExpBuffer(query, "SELECT nspname, tmplname "
   14668             :                       "FROM pg_ts_template p, pg_namespace n "
   14669             :                       "WHERE p.oid = '%u' AND n.oid = tmplnamespace",
   14670             :                       dictinfo->dicttemplate);
   14671         330 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   14672         330 :     nspname = PQgetvalue(res, 0, 0);
   14673         330 :     tmplname = PQgetvalue(res, 0, 1);
   14674             : 
   14675         330 :     appendPQExpBuffer(q, "CREATE TEXT SEARCH DICTIONARY %s (\n",
   14676         330 :                       fmtQualifiedDumpable(dictinfo));
   14677             : 
   14678         330 :     appendPQExpBufferStr(q, "    TEMPLATE = ");
   14679         330 :     appendPQExpBuffer(q, "%s.", fmtId(nspname));
   14680         330 :     appendPQExpBufferStr(q, fmtId(tmplname));
   14681             : 
   14682         330 :     PQclear(res);
   14683             : 
   14684             :     /* the dictinitoption can be dumped straight into the command */
   14685         330 :     if (dictinfo->dictinitoption)
   14686         258 :         appendPQExpBuffer(q, ",\n    %s", dictinfo->dictinitoption);
   14687             : 
   14688         330 :     appendPQExpBufferStr(q, " );\n");
   14689             : 
   14690         330 :     appendPQExpBuffer(delq, "DROP TEXT SEARCH DICTIONARY %s;\n",
   14691         330 :                       fmtQualifiedDumpable(dictinfo));
   14692             : 
   14693         330 :     if (dopt->binary_upgrade)
   14694          20 :         binary_upgrade_extension_member(q, &dictinfo->dobj,
   14695             :                                         "TEXT SEARCH DICTIONARY", qdictname,
   14696          20 :                                         dictinfo->dobj.namespace->dobj.name);
   14697             : 
   14698         330 :     if (dictinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   14699         330 :         ArchiveEntry(fout, dictinfo->dobj.catId, dictinfo->dobj.dumpId,
   14700         330 :                      ARCHIVE_OPTS(.tag = dictinfo->dobj.name,
   14701             :                                   .namespace = dictinfo->dobj.namespace->dobj.name,
   14702             :                                   .owner = dictinfo->rolname,
   14703             :                                   .description = "TEXT SEARCH DICTIONARY",
   14704             :                                   .section = SECTION_PRE_DATA,
   14705             :                                   .createStmt = q->data,
   14706             :                                   .dropStmt = delq->data));
   14707             : 
   14708             :     /* Dump Dictionary Comments */
   14709         330 :     if (dictinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   14710         240 :         dumpComment(fout, "TEXT SEARCH DICTIONARY", qdictname,
   14711         240 :                     dictinfo->dobj.namespace->dobj.name, dictinfo->rolname,
   14712             :                     dictinfo->dobj.catId, 0, dictinfo->dobj.dumpId);
   14713             : 
   14714         330 :     destroyPQExpBuffer(q);
   14715         330 :     destroyPQExpBuffer(delq);
   14716         330 :     destroyPQExpBuffer(query);
   14717         330 :     free(qdictname);
   14718             : }
   14719             : 
   14720             : /*
   14721             :  * dumpTSTemplate
   14722             :  *    write out a single text search template
   14723             :  */
   14724             : static void
   14725         102 : dumpTSTemplate(Archive *fout, const TSTemplateInfo *tmplinfo)
   14726             : {
   14727         102 :     DumpOptions *dopt = fout->dopt;
   14728             :     PQExpBuffer q;
   14729             :     PQExpBuffer delq;
   14730             :     char       *qtmplname;
   14731             : 
   14732             :     /* Do nothing if not dumping schema */
   14733         102 :     if (!dopt->dumpSchema)
   14734           6 :         return;
   14735             : 
   14736          96 :     q = createPQExpBuffer();
   14737          96 :     delq = createPQExpBuffer();
   14738             : 
   14739          96 :     qtmplname = pg_strdup(fmtId(tmplinfo->dobj.name));
   14740             : 
   14741          96 :     appendPQExpBuffer(q, "CREATE TEXT SEARCH TEMPLATE %s (\n",
   14742          96 :                       fmtQualifiedDumpable(tmplinfo));
   14743             : 
   14744          96 :     if (tmplinfo->tmplinit != InvalidOid)
   14745          30 :         appendPQExpBuffer(q, "    INIT = %s,\n",
   14746             :                           convertTSFunction(fout, tmplinfo->tmplinit));
   14747          96 :     appendPQExpBuffer(q, "    LEXIZE = %s );\n",
   14748             :                       convertTSFunction(fout, tmplinfo->tmpllexize));
   14749             : 
   14750          96 :     appendPQExpBuffer(delq, "DROP TEXT SEARCH TEMPLATE %s;\n",
   14751          96 :                       fmtQualifiedDumpable(tmplinfo));
   14752             : 
   14753          96 :     if (dopt->binary_upgrade)
   14754           2 :         binary_upgrade_extension_member(q, &tmplinfo->dobj,
   14755             :                                         "TEXT SEARCH TEMPLATE", qtmplname,
   14756           2 :                                         tmplinfo->dobj.namespace->dobj.name);
   14757             : 
   14758          96 :     if (tmplinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   14759          96 :         ArchiveEntry(fout, tmplinfo->dobj.catId, tmplinfo->dobj.dumpId,
   14760          96 :                      ARCHIVE_OPTS(.tag = tmplinfo->dobj.name,
   14761             :                                   .namespace = tmplinfo->dobj.namespace->dobj.name,
   14762             :                                   .description = "TEXT SEARCH TEMPLATE",
   14763             :                                   .section = SECTION_PRE_DATA,
   14764             :                                   .createStmt = q->data,
   14765             :                                   .dropStmt = delq->data));
   14766             : 
   14767             :     /* Dump Template Comments */
   14768          96 :     if (tmplinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   14769          96 :         dumpComment(fout, "TEXT SEARCH TEMPLATE", qtmplname,
   14770          96 :                     tmplinfo->dobj.namespace->dobj.name, "",
   14771             :                     tmplinfo->dobj.catId, 0, tmplinfo->dobj.dumpId);
   14772             : 
   14773          96 :     destroyPQExpBuffer(q);
   14774          96 :     destroyPQExpBuffer(delq);
   14775          96 :     free(qtmplname);
   14776             : }
   14777             : 
   14778             : /*
   14779             :  * dumpTSConfig
   14780             :  *    write out a single text search configuration
   14781             :  */
   14782             : static void
   14783         286 : dumpTSConfig(Archive *fout, const TSConfigInfo *cfginfo)
   14784             : {
   14785         286 :     DumpOptions *dopt = fout->dopt;
   14786             :     PQExpBuffer q;
   14787             :     PQExpBuffer delq;
   14788             :     PQExpBuffer query;
   14789             :     char       *qcfgname;
   14790             :     PGresult   *res;
   14791             :     char       *nspname;
   14792             :     char       *prsname;
   14793             :     int         ntups,
   14794             :                 i;
   14795             :     int         i_tokenname;
   14796             :     int         i_dictname;
   14797             : 
   14798             :     /* Do nothing if not dumping schema */
   14799         286 :     if (!dopt->dumpSchema)
   14800           6 :         return;
   14801             : 
   14802         280 :     q = createPQExpBuffer();
   14803         280 :     delq = createPQExpBuffer();
   14804         280 :     query = createPQExpBuffer();
   14805             : 
   14806         280 :     qcfgname = pg_strdup(fmtId(cfginfo->dobj.name));
   14807             : 
   14808             :     /* Fetch name and namespace of the config's parser */
   14809         280 :     appendPQExpBuffer(query, "SELECT nspname, prsname "
   14810             :                       "FROM pg_ts_parser p, pg_namespace n "
   14811             :                       "WHERE p.oid = '%u' AND n.oid = prsnamespace",
   14812             :                       cfginfo->cfgparser);
   14813         280 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   14814         280 :     nspname = PQgetvalue(res, 0, 0);
   14815         280 :     prsname = PQgetvalue(res, 0, 1);
   14816             : 
   14817         280 :     appendPQExpBuffer(q, "CREATE TEXT SEARCH CONFIGURATION %s (\n",
   14818         280 :                       fmtQualifiedDumpable(cfginfo));
   14819             : 
   14820         280 :     appendPQExpBuffer(q, "    PARSER = %s.", fmtId(nspname));
   14821         280 :     appendPQExpBuffer(q, "%s );\n", fmtId(prsname));
   14822             : 
   14823         280 :     PQclear(res);
   14824             : 
   14825         280 :     resetPQExpBuffer(query);
   14826         280 :     appendPQExpBuffer(query,
   14827             :                       "SELECT\n"
   14828             :                       "  ( SELECT alias FROM pg_catalog.ts_token_type('%u'::pg_catalog.oid) AS t\n"
   14829             :                       "    WHERE t.tokid = m.maptokentype ) AS tokenname,\n"
   14830             :                       "  m.mapdict::pg_catalog.regdictionary AS dictname\n"
   14831             :                       "FROM pg_catalog.pg_ts_config_map AS m\n"
   14832             :                       "WHERE m.mapcfg = '%u'\n"
   14833             :                       "ORDER BY m.mapcfg, m.maptokentype, m.mapseqno",
   14834             :                       cfginfo->cfgparser, cfginfo->dobj.catId.oid);
   14835             : 
   14836         280 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   14837         280 :     ntups = PQntuples(res);
   14838             : 
   14839         280 :     i_tokenname = PQfnumber(res, "tokenname");
   14840         280 :     i_dictname = PQfnumber(res, "dictname");
   14841             : 
   14842        5870 :     for (i = 0; i < ntups; i++)
   14843             :     {
   14844        5590 :         char       *tokenname = PQgetvalue(res, i, i_tokenname);
   14845        5590 :         char       *dictname = PQgetvalue(res, i, i_dictname);
   14846             : 
   14847        5590 :         if (i == 0 ||
   14848        5310 :             strcmp(tokenname, PQgetvalue(res, i - 1, i_tokenname)) != 0)
   14849             :         {
   14850             :             /* starting a new token type, so start a new command */
   14851        5320 :             if (i > 0)
   14852        5040 :                 appendPQExpBufferStr(q, ";\n");
   14853        5320 :             appendPQExpBuffer(q, "\nALTER TEXT SEARCH CONFIGURATION %s\n",
   14854        5320 :                               fmtQualifiedDumpable(cfginfo));
   14855             :             /* tokenname needs quoting, dictname does NOT */
   14856        5320 :             appendPQExpBuffer(q, "    ADD MAPPING FOR %s WITH %s",
   14857             :                               fmtId(tokenname), dictname);
   14858             :         }
   14859             :         else
   14860         270 :             appendPQExpBuffer(q, ", %s", dictname);
   14861             :     }
   14862             : 
   14863         280 :     if (ntups > 0)
   14864         280 :         appendPQExpBufferStr(q, ";\n");
   14865             : 
   14866         280 :     PQclear(res);
   14867             : 
   14868         280 :     appendPQExpBuffer(delq, "DROP TEXT SEARCH CONFIGURATION %s;\n",
   14869         280 :                       fmtQualifiedDumpable(cfginfo));
   14870             : 
   14871         280 :     if (dopt->binary_upgrade)
   14872          10 :         binary_upgrade_extension_member(q, &cfginfo->dobj,
   14873             :                                         "TEXT SEARCH CONFIGURATION", qcfgname,
   14874          10 :                                         cfginfo->dobj.namespace->dobj.name);
   14875             : 
   14876         280 :     if (cfginfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   14877         280 :         ArchiveEntry(fout, cfginfo->dobj.catId, cfginfo->dobj.dumpId,
   14878         280 :                      ARCHIVE_OPTS(.tag = cfginfo->dobj.name,
   14879             :                                   .namespace = cfginfo->dobj.namespace->dobj.name,
   14880             :                                   .owner = cfginfo->rolname,
   14881             :                                   .description = "TEXT SEARCH CONFIGURATION",
   14882             :                                   .section = SECTION_PRE_DATA,
   14883             :                                   .createStmt = q->data,
   14884             :                                   .dropStmt = delq->data));
   14885             : 
   14886             :     /* Dump Configuration Comments */
   14887         280 :     if (cfginfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   14888         240 :         dumpComment(fout, "TEXT SEARCH CONFIGURATION", qcfgname,
   14889         240 :                     cfginfo->dobj.namespace->dobj.name, cfginfo->rolname,
   14890             :                     cfginfo->dobj.catId, 0, cfginfo->dobj.dumpId);
   14891             : 
   14892         280 :     destroyPQExpBuffer(q);
   14893         280 :     destroyPQExpBuffer(delq);
   14894         280 :     destroyPQExpBuffer(query);
   14895         280 :     free(qcfgname);
   14896             : }
   14897             : 
   14898             : /*
   14899             :  * dumpForeignDataWrapper
   14900             :  *    write out a single foreign-data wrapper definition
   14901             :  */
   14902             : static void
   14903         100 : dumpForeignDataWrapper(Archive *fout, const FdwInfo *fdwinfo)
   14904             : {
   14905         100 :     DumpOptions *dopt = fout->dopt;
   14906             :     PQExpBuffer q;
   14907             :     PQExpBuffer delq;
   14908             :     char       *qfdwname;
   14909             : 
   14910             :     /* Do nothing if not dumping schema */
   14911         100 :     if (!dopt->dumpSchema)
   14912           8 :         return;
   14913             : 
   14914          92 :     q = createPQExpBuffer();
   14915          92 :     delq = createPQExpBuffer();
   14916             : 
   14917          92 :     qfdwname = pg_strdup(fmtId(fdwinfo->dobj.name));
   14918             : 
   14919          92 :     appendPQExpBuffer(q, "CREATE FOREIGN DATA WRAPPER %s",
   14920             :                       qfdwname);
   14921             : 
   14922          92 :     if (strcmp(fdwinfo->fdwhandler, "-") != 0)
   14923           0 :         appendPQExpBuffer(q, " HANDLER %s", fdwinfo->fdwhandler);
   14924             : 
   14925          92 :     if (strcmp(fdwinfo->fdwvalidator, "-") != 0)
   14926           0 :         appendPQExpBuffer(q, " VALIDATOR %s", fdwinfo->fdwvalidator);
   14927             : 
   14928          92 :     if (strlen(fdwinfo->fdwoptions) > 0)
   14929           0 :         appendPQExpBuffer(q, " OPTIONS (\n    %s\n)", fdwinfo->fdwoptions);
   14930             : 
   14931          92 :     appendPQExpBufferStr(q, ";\n");
   14932             : 
   14933          92 :     appendPQExpBuffer(delq, "DROP FOREIGN DATA WRAPPER %s;\n",
   14934             :                       qfdwname);
   14935             : 
   14936          92 :     if (dopt->binary_upgrade)
   14937           4 :         binary_upgrade_extension_member(q, &fdwinfo->dobj,
   14938             :                                         "FOREIGN DATA WRAPPER", qfdwname,
   14939             :                                         NULL);
   14940             : 
   14941          92 :     if (fdwinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   14942          92 :         ArchiveEntry(fout, fdwinfo->dobj.catId, fdwinfo->dobj.dumpId,
   14943          92 :                      ARCHIVE_OPTS(.tag = fdwinfo->dobj.name,
   14944             :                                   .owner = fdwinfo->rolname,
   14945             :                                   .description = "FOREIGN DATA WRAPPER",
   14946             :                                   .section = SECTION_PRE_DATA,
   14947             :                                   .createStmt = q->data,
   14948             :                                   .dropStmt = delq->data));
   14949             : 
   14950             :     /* Dump Foreign Data Wrapper Comments */
   14951          92 :     if (fdwinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   14952           0 :         dumpComment(fout, "FOREIGN DATA WRAPPER", qfdwname,
   14953             :                     NULL, fdwinfo->rolname,
   14954             :                     fdwinfo->dobj.catId, 0, fdwinfo->dobj.dumpId);
   14955             : 
   14956             :     /* Handle the ACL */
   14957          92 :     if (fdwinfo->dobj.dump & DUMP_COMPONENT_ACL)
   14958          64 :         dumpACL(fout, fdwinfo->dobj.dumpId, InvalidDumpId,
   14959             :                 "FOREIGN DATA WRAPPER", qfdwname, NULL, NULL,
   14960             :                 NULL, fdwinfo->rolname, &fdwinfo->dacl);
   14961             : 
   14962          92 :     free(qfdwname);
   14963             : 
   14964          92 :     destroyPQExpBuffer(q);
   14965          92 :     destroyPQExpBuffer(delq);
   14966             : }
   14967             : 
   14968             : /*
   14969             :  * dumpForeignServer
   14970             :  *    write out a foreign server definition
   14971             :  */
   14972             : static void
   14973         108 : dumpForeignServer(Archive *fout, const ForeignServerInfo *srvinfo)
   14974             : {
   14975         108 :     DumpOptions *dopt = fout->dopt;
   14976             :     PQExpBuffer q;
   14977             :     PQExpBuffer delq;
   14978             :     PQExpBuffer query;
   14979             :     PGresult   *res;
   14980             :     char       *qsrvname;
   14981             :     char       *fdwname;
   14982             : 
   14983             :     /* Do nothing if not dumping schema */
   14984         108 :     if (!dopt->dumpSchema)
   14985          12 :         return;
   14986             : 
   14987          96 :     q = createPQExpBuffer();
   14988          96 :     delq = createPQExpBuffer();
   14989          96 :     query = createPQExpBuffer();
   14990             : 
   14991          96 :     qsrvname = pg_strdup(fmtId(srvinfo->dobj.name));
   14992             : 
   14993             :     /* look up the foreign-data wrapper */
   14994          96 :     appendPQExpBuffer(query, "SELECT fdwname "
   14995             :                       "FROM pg_foreign_data_wrapper w "
   14996             :                       "WHERE w.oid = '%u'",
   14997             :                       srvinfo->srvfdw);
   14998          96 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   14999          96 :     fdwname = PQgetvalue(res, 0, 0);
   15000             : 
   15001          96 :     appendPQExpBuffer(q, "CREATE SERVER %s", qsrvname);
   15002          96 :     if (srvinfo->srvtype && strlen(srvinfo->srvtype) > 0)
   15003             :     {
   15004           0 :         appendPQExpBufferStr(q, " TYPE ");
   15005           0 :         appendStringLiteralAH(q, srvinfo->srvtype, fout);
   15006             :     }
   15007          96 :     if (srvinfo->srvversion && strlen(srvinfo->srvversion) > 0)
   15008             :     {
   15009           0 :         appendPQExpBufferStr(q, " VERSION ");
   15010           0 :         appendStringLiteralAH(q, srvinfo->srvversion, fout);
   15011             :     }
   15012             : 
   15013          96 :     appendPQExpBufferStr(q, " FOREIGN DATA WRAPPER ");
   15014          96 :     appendPQExpBufferStr(q, fmtId(fdwname));
   15015             : 
   15016          96 :     if (srvinfo->srvoptions && strlen(srvinfo->srvoptions) > 0)
   15017           0 :         appendPQExpBuffer(q, " OPTIONS (\n    %s\n)", srvinfo->srvoptions);
   15018             : 
   15019          96 :     appendPQExpBufferStr(q, ";\n");
   15020             : 
   15021          96 :     appendPQExpBuffer(delq, "DROP SERVER %s;\n",
   15022             :                       qsrvname);
   15023             : 
   15024          96 :     if (dopt->binary_upgrade)
   15025           4 :         binary_upgrade_extension_member(q, &srvinfo->dobj,
   15026             :                                         "SERVER", qsrvname, NULL);
   15027             : 
   15028          96 :     if (srvinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   15029          96 :         ArchiveEntry(fout, srvinfo->dobj.catId, srvinfo->dobj.dumpId,
   15030          96 :                      ARCHIVE_OPTS(.tag = srvinfo->dobj.name,
   15031             :                                   .owner = srvinfo->rolname,
   15032             :                                   .description = "SERVER",
   15033             :                                   .section = SECTION_PRE_DATA,
   15034             :                                   .createStmt = q->data,
   15035             :                                   .dropStmt = delq->data));
   15036             : 
   15037             :     /* Dump Foreign Server Comments */
   15038          96 :     if (srvinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   15039           0 :         dumpComment(fout, "SERVER", qsrvname,
   15040             :                     NULL, srvinfo->rolname,
   15041             :                     srvinfo->dobj.catId, 0, srvinfo->dobj.dumpId);
   15042             : 
   15043             :     /* Handle the ACL */
   15044          96 :     if (srvinfo->dobj.dump & DUMP_COMPONENT_ACL)
   15045          64 :         dumpACL(fout, srvinfo->dobj.dumpId, InvalidDumpId,
   15046             :                 "FOREIGN SERVER", qsrvname, NULL, NULL,
   15047             :                 NULL, srvinfo->rolname, &srvinfo->dacl);
   15048             : 
   15049             :     /* Dump user mappings */
   15050          96 :     if (srvinfo->dobj.dump & DUMP_COMPONENT_USERMAP)
   15051          96 :         dumpUserMappings(fout,
   15052          96 :                          srvinfo->dobj.name, NULL,
   15053             :                          srvinfo->rolname,
   15054             :                          srvinfo->dobj.catId, srvinfo->dobj.dumpId);
   15055             : 
   15056          96 :     PQclear(res);
   15057             : 
   15058          96 :     free(qsrvname);
   15059             : 
   15060          96 :     destroyPQExpBuffer(q);
   15061          96 :     destroyPQExpBuffer(delq);
   15062          96 :     destroyPQExpBuffer(query);
   15063             : }
   15064             : 
   15065             : /*
   15066             :  * dumpUserMappings
   15067             :  *
   15068             :  * This routine is used to dump any user mappings associated with the
   15069             :  * server handed to this routine. Should be called after ArchiveEntry()
   15070             :  * for the server.
   15071             :  */
   15072             : static void
   15073          96 : dumpUserMappings(Archive *fout,
   15074             :                  const char *servername, const char *namespace,
   15075             :                  const char *owner,
   15076             :                  CatalogId catalogId, DumpId dumpId)
   15077             : {
   15078             :     PQExpBuffer q;
   15079             :     PQExpBuffer delq;
   15080             :     PQExpBuffer query;
   15081             :     PQExpBuffer tag;
   15082             :     PGresult   *res;
   15083             :     int         ntups;
   15084             :     int         i_usename;
   15085             :     int         i_umoptions;
   15086             :     int         i;
   15087             : 
   15088          96 :     q = createPQExpBuffer();
   15089          96 :     tag = createPQExpBuffer();
   15090          96 :     delq = createPQExpBuffer();
   15091          96 :     query = createPQExpBuffer();
   15092             : 
   15093             :     /*
   15094             :      * We read from the publicly accessible view pg_user_mappings, so as not
   15095             :      * to fail if run by a non-superuser.  Note that the view will show
   15096             :      * umoptions as null if the user hasn't got privileges for the associated
   15097             :      * server; this means that pg_dump will dump such a mapping, but with no
   15098             :      * OPTIONS clause.  A possible alternative is to skip such mappings
   15099             :      * altogether, but it's not clear that that's an improvement.
   15100             :      */
   15101          96 :     appendPQExpBuffer(query,
   15102             :                       "SELECT usename, "
   15103             :                       "array_to_string(ARRAY("
   15104             :                       "SELECT quote_ident(option_name) || ' ' || "
   15105             :                       "quote_literal(option_value) "
   15106             :                       "FROM pg_options_to_table(umoptions) "
   15107             :                       "ORDER BY option_name"
   15108             :                       "), E',\n    ') AS umoptions "
   15109             :                       "FROM pg_user_mappings "
   15110             :                       "WHERE srvid = '%u' "
   15111             :                       "ORDER BY usename",
   15112             :                       catalogId.oid);
   15113             : 
   15114          96 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   15115             : 
   15116          96 :     ntups = PQntuples(res);
   15117          96 :     i_usename = PQfnumber(res, "usename");
   15118          96 :     i_umoptions = PQfnumber(res, "umoptions");
   15119             : 
   15120         160 :     for (i = 0; i < ntups; i++)
   15121             :     {
   15122             :         char       *usename;
   15123             :         char       *umoptions;
   15124             : 
   15125          64 :         usename = PQgetvalue(res, i, i_usename);
   15126          64 :         umoptions = PQgetvalue(res, i, i_umoptions);
   15127             : 
   15128          64 :         resetPQExpBuffer(q);
   15129          64 :         appendPQExpBuffer(q, "CREATE USER MAPPING FOR %s", fmtId(usename));
   15130          64 :         appendPQExpBuffer(q, " SERVER %s", fmtId(servername));
   15131             : 
   15132          64 :         if (umoptions && strlen(umoptions) > 0)
   15133           0 :             appendPQExpBuffer(q, " OPTIONS (\n    %s\n)", umoptions);
   15134             : 
   15135          64 :         appendPQExpBufferStr(q, ";\n");
   15136             : 
   15137          64 :         resetPQExpBuffer(delq);
   15138          64 :         appendPQExpBuffer(delq, "DROP USER MAPPING FOR %s", fmtId(usename));
   15139          64 :         appendPQExpBuffer(delq, " SERVER %s;\n", fmtId(servername));
   15140             : 
   15141          64 :         resetPQExpBuffer(tag);
   15142          64 :         appendPQExpBuffer(tag, "USER MAPPING %s SERVER %s",
   15143             :                           usename, servername);
   15144             : 
   15145          64 :         ArchiveEntry(fout, nilCatalogId, createDumpId(),
   15146          64 :                      ARCHIVE_OPTS(.tag = tag->data,
   15147             :                                   .namespace = namespace,
   15148             :                                   .owner = owner,
   15149             :                                   .description = "USER MAPPING",
   15150             :                                   .section = SECTION_PRE_DATA,
   15151             :                                   .createStmt = q->data,
   15152             :                                   .dropStmt = delq->data));
   15153             :     }
   15154             : 
   15155          96 :     PQclear(res);
   15156             : 
   15157          96 :     destroyPQExpBuffer(query);
   15158          96 :     destroyPQExpBuffer(delq);
   15159          96 :     destroyPQExpBuffer(tag);
   15160          96 :     destroyPQExpBuffer(q);
   15161          96 : }
   15162             : 
   15163             : /*
   15164             :  * Write out default privileges information
   15165             :  */
   15166             : static void
   15167         284 : dumpDefaultACL(Archive *fout, const DefaultACLInfo *daclinfo)
   15168             : {
   15169         284 :     DumpOptions *dopt = fout->dopt;
   15170             :     PQExpBuffer q;
   15171             :     PQExpBuffer tag;
   15172             :     const char *type;
   15173             : 
   15174             :     /* Do nothing if not dumping schema, or if we're skipping ACLs */
   15175         284 :     if (!dopt->dumpSchema || dopt->aclsSkip)
   15176          32 :         return;
   15177             : 
   15178         252 :     q = createPQExpBuffer();
   15179         252 :     tag = createPQExpBuffer();
   15180             : 
   15181         252 :     switch (daclinfo->defaclobjtype)
   15182             :     {
   15183         126 :         case DEFACLOBJ_RELATION:
   15184         126 :             type = "TABLES";
   15185         126 :             break;
   15186           0 :         case DEFACLOBJ_SEQUENCE:
   15187           0 :             type = "SEQUENCES";
   15188           0 :             break;
   15189         126 :         case DEFACLOBJ_FUNCTION:
   15190         126 :             type = "FUNCTIONS";
   15191         126 :             break;
   15192           0 :         case DEFACLOBJ_TYPE:
   15193           0 :             type = "TYPES";
   15194           0 :             break;
   15195           0 :         case DEFACLOBJ_NAMESPACE:
   15196           0 :             type = "SCHEMAS";
   15197           0 :             break;
   15198           0 :         default:
   15199             :             /* shouldn't get here */
   15200           0 :             pg_fatal("unrecognized object type in default privileges: %d",
   15201             :                      (int) daclinfo->defaclobjtype);
   15202             :             type = "";            /* keep compiler quiet */
   15203             :     }
   15204             : 
   15205         252 :     appendPQExpBuffer(tag, "DEFAULT PRIVILEGES FOR %s", type);
   15206             : 
   15207             :     /* build the actual command(s) for this tuple */
   15208         252 :     if (!buildDefaultACLCommands(type,
   15209         252 :                                  daclinfo->dobj.namespace != NULL ?
   15210         128 :                                  daclinfo->dobj.namespace->dobj.name : NULL,
   15211         252 :                                  daclinfo->dacl.acl,
   15212         252 :                                  daclinfo->dacl.acldefault,
   15213             :                                  daclinfo->defaclrole,
   15214             :                                  fout->remoteVersion,
   15215             :                                  q))
   15216           0 :         pg_fatal("could not parse default ACL list (%s)",
   15217             :                  daclinfo->dacl.acl);
   15218             : 
   15219         252 :     if (daclinfo->dobj.dump & DUMP_COMPONENT_ACL)
   15220         252 :         ArchiveEntry(fout, daclinfo->dobj.catId, daclinfo->dobj.dumpId,
   15221         252 :                      ARCHIVE_OPTS(.tag = tag->data,
   15222             :                                   .namespace = daclinfo->dobj.namespace ?
   15223             :                                   daclinfo->dobj.namespace->dobj.name : NULL,
   15224             :                                   .owner = daclinfo->defaclrole,
   15225             :                                   .description = "DEFAULT ACL",
   15226             :                                   .section = SECTION_POST_DATA,
   15227             :                                   .createStmt = q->data));
   15228             : 
   15229         252 :     destroyPQExpBuffer(tag);
   15230         252 :     destroyPQExpBuffer(q);
   15231             : }
   15232             : 
   15233             : /*----------
   15234             :  * Write out grant/revoke information
   15235             :  *
   15236             :  * 'objDumpId' is the dump ID of the underlying object.
   15237             :  * 'altDumpId' can be a second dumpId that the ACL entry must also depend on,
   15238             :  *      or InvalidDumpId if there is no need for a second dependency.
   15239             :  * 'type' must be one of
   15240             :  *      TABLE, SEQUENCE, FUNCTION, LANGUAGE, SCHEMA, DATABASE, TABLESPACE,
   15241             :  *      FOREIGN DATA WRAPPER, SERVER, or LARGE OBJECT.
   15242             :  * 'name' is the formatted name of the object.  Must be quoted etc. already.
   15243             :  * 'subname' is the formatted name of the sub-object, if any.  Must be quoted.
   15244             :  *      (Currently we assume that subname is only provided for table columns.)
   15245             :  * 'nspname' is the namespace the object is in (NULL if none).
   15246             :  * 'tag' is the tag to use for the ACL TOC entry; typically, this is NULL
   15247             :  *      to use the default for the object type.
   15248             :  * 'owner' is the owner, NULL if there is no owner (for languages).
   15249             :  * 'dacl' is the DumpableAcl struct for the object.
   15250             :  *
   15251             :  * Returns the dump ID assigned to the ACL TocEntry, or InvalidDumpId if
   15252             :  * no ACL entry was created.
   15253             :  *----------
   15254             :  */
   15255             : static DumpId
   15256       45836 : dumpACL(Archive *fout, DumpId objDumpId, DumpId altDumpId,
   15257             :         const char *type, const char *name, const char *subname,
   15258             :         const char *nspname, const char *tag, const char *owner,
   15259             :         const DumpableAcl *dacl)
   15260             : {
   15261       45836 :     DumpId      aclDumpId = InvalidDumpId;
   15262       45836 :     DumpOptions *dopt = fout->dopt;
   15263       45836 :     const char *acls = dacl->acl;
   15264       45836 :     const char *acldefault = dacl->acldefault;
   15265       45836 :     char        privtype = dacl->privtype;
   15266       45836 :     const char *initprivs = dacl->initprivs;
   15267             :     const char *baseacls;
   15268             :     PQExpBuffer sql;
   15269             : 
   15270             :     /* Do nothing if ACL dump is not enabled */
   15271       45836 :     if (dopt->aclsSkip)
   15272         636 :         return InvalidDumpId;
   15273             : 
   15274             :     /* --data-only skips ACLs *except* large object ACLs */
   15275       45200 :     if (!dopt->dumpSchema && strcmp(type, "LARGE OBJECT") != 0)
   15276           0 :         return InvalidDumpId;
   15277             : 
   15278       45200 :     sql = createPQExpBuffer();
   15279             : 
   15280             :     /*
   15281             :      * In binary upgrade mode, we don't run an extension's script but instead
   15282             :      * dump out the objects independently and then recreate them.  To preserve
   15283             :      * any initial privileges which were set on extension objects, we need to
   15284             :      * compute the set of GRANT and REVOKE commands necessary to get from the
   15285             :      * default privileges of an object to its initial privileges as recorded
   15286             :      * in pg_init_privs.
   15287             :      *
   15288             :      * At restore time, we apply these commands after having called
   15289             :      * binary_upgrade_set_record_init_privs(true).  That tells the backend to
   15290             :      * copy the results into pg_init_privs.  This is how we preserve the
   15291             :      * contents of that catalog across binary upgrades.
   15292             :      */
   15293       45200 :     if (dopt->binary_upgrade && privtype == 'e' &&
   15294          26 :         initprivs && *initprivs != '\0')
   15295             :     {
   15296          26 :         appendPQExpBufferStr(sql, "SELECT pg_catalog.binary_upgrade_set_record_init_privs(true);\n");
   15297          26 :         if (!buildACLCommands(name, subname, nspname, type,
   15298             :                               initprivs, acldefault, owner,
   15299             :                               "", fout->remoteVersion, sql))
   15300           0 :             pg_fatal("could not parse initial ACL list (%s) or default (%s) for object \"%s\" (%s)",
   15301             :                      initprivs, acldefault, name, type);
   15302          26 :         appendPQExpBufferStr(sql, "SELECT pg_catalog.binary_upgrade_set_record_init_privs(false);\n");
   15303             :     }
   15304             : 
   15305             :     /*
   15306             :      * Now figure the GRANT and REVOKE commands needed to get to the object's
   15307             :      * actual current ACL, starting from the initprivs if given, else from the
   15308             :      * object-type-specific default.  Also, while buildACLCommands will assume
   15309             :      * that a NULL/empty acls string means it needn't do anything, what that
   15310             :      * actually represents is the object-type-specific default; so we need to
   15311             :      * substitute the acldefault string to get the right results in that case.
   15312             :      */
   15313       45200 :     if (initprivs && *initprivs != '\0')
   15314             :     {
   15315       41710 :         baseacls = initprivs;
   15316       41710 :         if (acls == NULL || *acls == '\0')
   15317          34 :             acls = acldefault;
   15318             :     }
   15319             :     else
   15320        3490 :         baseacls = acldefault;
   15321             : 
   15322       45200 :     if (!buildACLCommands(name, subname, nspname, type,
   15323             :                           acls, baseacls, owner,
   15324             :                           "", fout->remoteVersion, sql))
   15325           0 :         pg_fatal("could not parse ACL list (%s) or default (%s) for object \"%s\" (%s)",
   15326             :                  acls, baseacls, name, type);
   15327             : 
   15328       45200 :     if (sql->len > 0)
   15329             :     {
   15330        3648 :         PQExpBuffer tagbuf = createPQExpBuffer();
   15331             :         DumpId      aclDeps[2];
   15332        3648 :         int         nDeps = 0;
   15333             : 
   15334        3648 :         if (tag)
   15335           0 :             appendPQExpBufferStr(tagbuf, tag);
   15336        3648 :         else if (subname)
   15337        2158 :             appendPQExpBuffer(tagbuf, "COLUMN %s.%s", name, subname);
   15338             :         else
   15339        1490 :             appendPQExpBuffer(tagbuf, "%s %s", type, name);
   15340             : 
   15341        3648 :         aclDeps[nDeps++] = objDumpId;
   15342        3648 :         if (altDumpId != InvalidDumpId)
   15343        1988 :             aclDeps[nDeps++] = altDumpId;
   15344             : 
   15345        3648 :         aclDumpId = createDumpId();
   15346             : 
   15347        3648 :         ArchiveEntry(fout, nilCatalogId, aclDumpId,
   15348        3648 :                      ARCHIVE_OPTS(.tag = tagbuf->data,
   15349             :                                   .namespace = nspname,
   15350             :                                   .owner = owner,
   15351             :                                   .description = "ACL",
   15352             :                                   .section = SECTION_NONE,
   15353             :                                   .createStmt = sql->data,
   15354             :                                   .deps = aclDeps,
   15355             :                                   .nDeps = nDeps));
   15356             : 
   15357        3648 :         destroyPQExpBuffer(tagbuf);
   15358             :     }
   15359             : 
   15360       45200 :     destroyPQExpBuffer(sql);
   15361             : 
   15362       45200 :     return aclDumpId;
   15363             : }
   15364             : 
   15365             : /*
   15366             :  * dumpSecLabel
   15367             :  *
   15368             :  * This routine is used to dump any security labels associated with the
   15369             :  * object handed to this routine. The routine takes the object type
   15370             :  * and object name (ready to print, except for schema decoration), plus
   15371             :  * the namespace and owner of the object (for labeling the ArchiveEntry),
   15372             :  * plus catalog ID and subid which are the lookup key for pg_seclabel,
   15373             :  * plus the dump ID for the object (for setting a dependency).
   15374             :  * If a matching pg_seclabel entry is found, it is dumped.
   15375             :  *
   15376             :  * Note: although this routine takes a dumpId for dependency purposes,
   15377             :  * that purpose is just to mark the dependency in the emitted dump file
   15378             :  * for possible future use by pg_restore.  We do NOT use it for determining
   15379             :  * ordering of the label in the dump file, because this routine is called
   15380             :  * after dependency sorting occurs.  This routine should be called just after
   15381             :  * calling ArchiveEntry() for the specified object.
   15382             :  */
   15383             : static void
   15384           0 : dumpSecLabel(Archive *fout, const char *type, const char *name,
   15385             :              const char *namespace, const char *owner,
   15386             :              CatalogId catalogId, int subid, DumpId dumpId)
   15387             : {
   15388           0 :     DumpOptions *dopt = fout->dopt;
   15389             :     SecLabelItem *labels;
   15390             :     int         nlabels;
   15391             :     int         i;
   15392             :     PQExpBuffer query;
   15393             : 
   15394             :     /* do nothing, if --no-security-labels is supplied */
   15395           0 :     if (dopt->no_security_labels)
   15396           0 :         return;
   15397             : 
   15398             :     /*
   15399             :      * Security labels are schema not data ... except large object labels are
   15400             :      * data
   15401             :      */
   15402           0 :     if (strcmp(type, "LARGE OBJECT") != 0)
   15403             :     {
   15404           0 :         if (!dopt->dumpSchema)
   15405           0 :             return;
   15406             :     }
   15407             :     else
   15408             :     {
   15409             :         /* We do dump large object security labels in binary-upgrade mode */
   15410           0 :         if (!dopt->dumpData && !dopt->binary_upgrade)
   15411           0 :             return;
   15412             :     }
   15413             : 
   15414             :     /* Search for security labels associated with catalogId, using table */
   15415           0 :     nlabels = findSecLabels(catalogId.tableoid, catalogId.oid, &labels);
   15416             : 
   15417           0 :     query = createPQExpBuffer();
   15418             : 
   15419           0 :     for (i = 0; i < nlabels; i++)
   15420             :     {
   15421             :         /*
   15422             :          * Ignore label entries for which the subid doesn't match.
   15423             :          */
   15424           0 :         if (labels[i].objsubid != subid)
   15425           0 :             continue;
   15426             : 
   15427           0 :         appendPQExpBuffer(query,
   15428             :                           "SECURITY LABEL FOR %s ON %s ",
   15429           0 :                           fmtId(labels[i].provider), type);
   15430           0 :         if (namespace && *namespace)
   15431           0 :             appendPQExpBuffer(query, "%s.", fmtId(namespace));
   15432           0 :         appendPQExpBuffer(query, "%s IS ", name);
   15433           0 :         appendStringLiteralAH(query, labels[i].label, fout);
   15434           0 :         appendPQExpBufferStr(query, ";\n");
   15435             :     }
   15436             : 
   15437           0 :     if (query->len > 0)
   15438             :     {
   15439           0 :         PQExpBuffer tag = createPQExpBuffer();
   15440             : 
   15441           0 :         appendPQExpBuffer(tag, "%s %s", type, name);
   15442           0 :         ArchiveEntry(fout, nilCatalogId, createDumpId(),
   15443           0 :                      ARCHIVE_OPTS(.tag = tag->data,
   15444             :                                   .namespace = namespace,
   15445             :                                   .owner = owner,
   15446             :                                   .description = "SECURITY LABEL",
   15447             :                                   .section = SECTION_NONE,
   15448             :                                   .createStmt = query->data,
   15449             :                                   .deps = &dumpId,
   15450             :                                   .nDeps = 1));
   15451           0 :         destroyPQExpBuffer(tag);
   15452             :     }
   15453             : 
   15454           0 :     destroyPQExpBuffer(query);
   15455             : }
   15456             : 
   15457             : /*
   15458             :  * dumpTableSecLabel
   15459             :  *
   15460             :  * As above, but dump security label for both the specified table (or view)
   15461             :  * and its columns.
   15462             :  */
   15463             : static void
   15464           0 : dumpTableSecLabel(Archive *fout, const TableInfo *tbinfo, const char *reltypename)
   15465             : {
   15466           0 :     DumpOptions *dopt = fout->dopt;
   15467             :     SecLabelItem *labels;
   15468             :     int         nlabels;
   15469             :     int         i;
   15470             :     PQExpBuffer query;
   15471             :     PQExpBuffer target;
   15472             : 
   15473             :     /* do nothing, if --no-security-labels is supplied */
   15474           0 :     if (dopt->no_security_labels)
   15475           0 :         return;
   15476             : 
   15477             :     /* SecLabel are SCHEMA not data */
   15478           0 :     if (!dopt->dumpSchema)
   15479           0 :         return;
   15480             : 
   15481             :     /* Search for comments associated with relation, using table */
   15482           0 :     nlabels = findSecLabels(tbinfo->dobj.catId.tableoid,
   15483             :                             tbinfo->dobj.catId.oid,
   15484             :                             &labels);
   15485             : 
   15486             :     /* If security labels exist, build SECURITY LABEL statements */
   15487           0 :     if (nlabels <= 0)
   15488           0 :         return;
   15489             : 
   15490           0 :     query = createPQExpBuffer();
   15491           0 :     target = createPQExpBuffer();
   15492             : 
   15493           0 :     for (i = 0; i < nlabels; i++)
   15494             :     {
   15495             :         const char *colname;
   15496           0 :         const char *provider = labels[i].provider;
   15497           0 :         const char *label = labels[i].label;
   15498           0 :         int         objsubid = labels[i].objsubid;
   15499             : 
   15500           0 :         resetPQExpBuffer(target);
   15501           0 :         if (objsubid == 0)
   15502             :         {
   15503           0 :             appendPQExpBuffer(target, "%s %s", reltypename,
   15504           0 :                               fmtQualifiedDumpable(tbinfo));
   15505             :         }
   15506             :         else
   15507             :         {
   15508           0 :             colname = getAttrName(objsubid, tbinfo);
   15509             :             /* first fmtXXX result must be consumed before calling again */
   15510           0 :             appendPQExpBuffer(target, "COLUMN %s",
   15511           0 :                               fmtQualifiedDumpable(tbinfo));
   15512           0 :             appendPQExpBuffer(target, ".%s", fmtId(colname));
   15513             :         }
   15514           0 :         appendPQExpBuffer(query, "SECURITY LABEL FOR %s ON %s IS ",
   15515             :                           fmtId(provider), target->data);
   15516           0 :         appendStringLiteralAH(query, label, fout);
   15517           0 :         appendPQExpBufferStr(query, ";\n");
   15518             :     }
   15519           0 :     if (query->len > 0)
   15520             :     {
   15521           0 :         resetPQExpBuffer(target);
   15522           0 :         appendPQExpBuffer(target, "%s %s", reltypename,
   15523           0 :                           fmtId(tbinfo->dobj.name));
   15524           0 :         ArchiveEntry(fout, nilCatalogId, createDumpId(),
   15525           0 :                      ARCHIVE_OPTS(.tag = target->data,
   15526             :                                   .namespace = tbinfo->dobj.namespace->dobj.name,
   15527             :                                   .owner = tbinfo->rolname,
   15528             :                                   .description = "SECURITY LABEL",
   15529             :                                   .section = SECTION_NONE,
   15530             :                                   .createStmt = query->data,
   15531             :                                   .deps = &(tbinfo->dobj.dumpId),
   15532             :                                   .nDeps = 1));
   15533             :     }
   15534           0 :     destroyPQExpBuffer(query);
   15535           0 :     destroyPQExpBuffer(target);
   15536             : }
   15537             : 
   15538             : /*
   15539             :  * findSecLabels
   15540             :  *
   15541             :  * Find the security label(s), if any, associated with the given object.
   15542             :  * All the objsubid values associated with the given classoid/objoid are
   15543             :  * found with one search.
   15544             :  */
   15545             : static int
   15546           0 : findSecLabels(Oid classoid, Oid objoid, SecLabelItem **items)
   15547             : {
   15548           0 :     SecLabelItem *middle = NULL;
   15549             :     SecLabelItem *low;
   15550             :     SecLabelItem *high;
   15551             :     int         nmatch;
   15552             : 
   15553           0 :     if (nseclabels <= 0)     /* no labels, so no match is possible */
   15554             :     {
   15555           0 :         *items = NULL;
   15556           0 :         return 0;
   15557             :     }
   15558             : 
   15559             :     /*
   15560             :      * Do binary search to find some item matching the object.
   15561             :      */
   15562           0 :     low = &seclabels[0];
   15563           0 :     high = &seclabels[nseclabels - 1];
   15564           0 :     while (low <= high)
   15565             :     {
   15566           0 :         middle = low + (high - low) / 2;
   15567             : 
   15568           0 :         if (classoid < middle->classoid)
   15569           0 :             high = middle - 1;
   15570           0 :         else if (classoid > middle->classoid)
   15571           0 :             low = middle + 1;
   15572           0 :         else if (objoid < middle->objoid)
   15573           0 :             high = middle - 1;
   15574           0 :         else if (objoid > middle->objoid)
   15575           0 :             low = middle + 1;
   15576             :         else
   15577           0 :             break;              /* found a match */
   15578             :     }
   15579             : 
   15580           0 :     if (low > high)              /* no matches */
   15581             :     {
   15582           0 :         *items = NULL;
   15583           0 :         return 0;
   15584             :     }
   15585             : 
   15586             :     /*
   15587             :      * Now determine how many items match the object.  The search loop
   15588             :      * invariant still holds: only items between low and high inclusive could
   15589             :      * match.
   15590             :      */
   15591           0 :     nmatch = 1;
   15592           0 :     while (middle > low)
   15593             :     {
   15594           0 :         if (classoid != middle[-1].classoid ||
   15595           0 :             objoid != middle[-1].objoid)
   15596             :             break;
   15597           0 :         middle--;
   15598           0 :         nmatch++;
   15599             :     }
   15600             : 
   15601           0 :     *items = middle;
   15602             : 
   15603           0 :     middle += nmatch;
   15604           0 :     while (middle <= high)
   15605             :     {
   15606           0 :         if (classoid != middle->classoid ||
   15607           0 :             objoid != middle->objoid)
   15608             :             break;
   15609           0 :         middle++;
   15610           0 :         nmatch++;
   15611             :     }
   15612             : 
   15613           0 :     return nmatch;
   15614             : }
   15615             : 
   15616             : /*
   15617             :  * collectSecLabels
   15618             :  *
   15619             :  * Construct a table of all security labels available for database objects;
   15620             :  * also set the has-seclabel component flag for each relevant object.
   15621             :  *
   15622             :  * The table is sorted by classoid/objid/objsubid for speed in lookup.
   15623             :  */
   15624             : static void
   15625         308 : collectSecLabels(Archive *fout)
   15626             : {
   15627             :     PGresult   *res;
   15628             :     PQExpBuffer query;
   15629             :     int         i_label;
   15630             :     int         i_provider;
   15631             :     int         i_classoid;
   15632             :     int         i_objoid;
   15633             :     int         i_objsubid;
   15634             :     int         ntups;
   15635             :     int         i;
   15636             :     DumpableObject *dobj;
   15637             : 
   15638         308 :     query = createPQExpBuffer();
   15639             : 
   15640         308 :     appendPQExpBufferStr(query,
   15641             :                          "SELECT label, provider, classoid, objoid, objsubid "
   15642             :                          "FROM pg_catalog.pg_seclabel "
   15643             :                          "ORDER BY classoid, objoid, objsubid");
   15644             : 
   15645         308 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   15646             : 
   15647             :     /* Construct lookup table containing OIDs in numeric form */
   15648         308 :     i_label = PQfnumber(res, "label");
   15649         308 :     i_provider = PQfnumber(res, "provider");
   15650         308 :     i_classoid = PQfnumber(res, "classoid");
   15651         308 :     i_objoid = PQfnumber(res, "objoid");
   15652         308 :     i_objsubid = PQfnumber(res, "objsubid");
   15653             : 
   15654         308 :     ntups = PQntuples(res);
   15655             : 
   15656         308 :     seclabels = (SecLabelItem *) pg_malloc(ntups * sizeof(SecLabelItem));
   15657         308 :     nseclabels = 0;
   15658         308 :     dobj = NULL;
   15659             : 
   15660         308 :     for (i = 0; i < ntups; i++)
   15661             :     {
   15662             :         CatalogId   objId;
   15663             :         int         subid;
   15664             : 
   15665           0 :         objId.tableoid = atooid(PQgetvalue(res, i, i_classoid));
   15666           0 :         objId.oid = atooid(PQgetvalue(res, i, i_objoid));
   15667           0 :         subid = atoi(PQgetvalue(res, i, i_objsubid));
   15668             : 
   15669             :         /* We needn't remember labels that don't match any dumpable object */
   15670           0 :         if (dobj == NULL ||
   15671           0 :             dobj->catId.tableoid != objId.tableoid ||
   15672           0 :             dobj->catId.oid != objId.oid)
   15673           0 :             dobj = findObjectByCatalogId(objId);
   15674           0 :         if (dobj == NULL)
   15675           0 :             continue;
   15676             : 
   15677             :         /*
   15678             :          * Labels on columns of composite types are linked to the type's
   15679             :          * pg_class entry, but we need to set the DUMP_COMPONENT_SECLABEL flag
   15680             :          * in the type's own DumpableObject.
   15681             :          */
   15682           0 :         if (subid != 0 && dobj->objType == DO_TABLE &&
   15683           0 :             ((TableInfo *) dobj)->relkind == RELKIND_COMPOSITE_TYPE)
   15684           0 :         {
   15685             :             TypeInfo   *cTypeInfo;
   15686             : 
   15687           0 :             cTypeInfo = findTypeByOid(((TableInfo *) dobj)->reltype);
   15688           0 :             if (cTypeInfo)
   15689           0 :                 cTypeInfo->dobj.components |= DUMP_COMPONENT_SECLABEL;
   15690             :         }
   15691             :         else
   15692           0 :             dobj->components |= DUMP_COMPONENT_SECLABEL;
   15693             : 
   15694           0 :         seclabels[nseclabels].label = pg_strdup(PQgetvalue(res, i, i_label));
   15695           0 :         seclabels[nseclabels].provider = pg_strdup(PQgetvalue(res, i, i_provider));
   15696           0 :         seclabels[nseclabels].classoid = objId.tableoid;
   15697           0 :         seclabels[nseclabels].objoid = objId.oid;
   15698           0 :         seclabels[nseclabels].objsubid = subid;
   15699           0 :         nseclabels++;
   15700             :     }
   15701             : 
   15702         308 :     PQclear(res);
   15703         308 :     destroyPQExpBuffer(query);
   15704         308 : }
   15705             : 
   15706             : /*
   15707             :  * dumpTable
   15708             :  *    write out to fout the declarations (not data) of a user-defined table
   15709             :  */
   15710             : static void
   15711       49984 : dumpTable(Archive *fout, const TableInfo *tbinfo)
   15712             : {
   15713       49984 :     DumpOptions *dopt = fout->dopt;
   15714       49984 :     DumpId      tableAclDumpId = InvalidDumpId;
   15715             :     char       *namecopy;
   15716             : 
   15717             :     /* Do nothing if not dumping schema */
   15718       49984 :     if (!dopt->dumpSchema)
   15719        1734 :         return;
   15720             : 
   15721       48250 :     if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   15722             :     {
   15723       11876 :         if (tbinfo->relkind == RELKIND_SEQUENCE)
   15724         696 :             dumpSequence(fout, tbinfo);
   15725             :         else
   15726       11180 :             dumpTableSchema(fout, tbinfo);
   15727             :     }
   15728             : 
   15729             :     /* Handle the ACL here */
   15730       48250 :     namecopy = pg_strdup(fmtId(tbinfo->dobj.name));
   15731       48250 :     if (tbinfo->dobj.dump & DUMP_COMPONENT_ACL)
   15732             :     {
   15733       37806 :         const char *objtype =
   15734       37806 :             (tbinfo->relkind == RELKIND_SEQUENCE) ? "SEQUENCE" : "TABLE";
   15735             : 
   15736             :         tableAclDumpId =
   15737       37806 :             dumpACL(fout, tbinfo->dobj.dumpId, InvalidDumpId,
   15738             :                     objtype, namecopy, NULL,
   15739       37806 :                     tbinfo->dobj.namespace->dobj.name,
   15740             :                     NULL, tbinfo->rolname, &tbinfo->dacl);
   15741             :     }
   15742             : 
   15743             :     /*
   15744             :      * Handle column ACLs, if any.  Note: we pull these with a separate query
   15745             :      * rather than trying to fetch them during getTableAttrs, so that we won't
   15746             :      * miss ACLs on system columns.  Doing it this way also allows us to dump
   15747             :      * ACLs for catalogs that we didn't mark "interesting" back in getTables.
   15748             :      */
   15749       48250 :     if ((tbinfo->dobj.dump & DUMP_COMPONENT_ACL) && tbinfo->hascolumnACLs)
   15750             :     {
   15751         510 :         PQExpBuffer query = createPQExpBuffer();
   15752             :         PGresult   *res;
   15753             :         int         i;
   15754             : 
   15755         510 :         if (!fout->is_prepared[PREPQUERY_GETCOLUMNACLS])
   15756             :         {
   15757             :             /* Set up query for column ACLs */
   15758         262 :             appendPQExpBufferStr(query,
   15759             :                                  "PREPARE getColumnACLs(pg_catalog.oid) AS\n");
   15760             : 
   15761         262 :             if (fout->remoteVersion >= 90600)
   15762             :             {
   15763             :                 /*
   15764             :                  * In principle we should call acldefault('c', relowner) to
   15765             :                  * get the default ACL for a column.  However, we don't
   15766             :                  * currently store the numeric OID of the relowner in
   15767             :                  * TableInfo.  We could convert the owner name using regrole,
   15768             :                  * but that creates a risk of failure due to concurrent role
   15769             :                  * renames.  Given that the default ACL for columns is empty
   15770             :                  * and is likely to stay that way, it's not worth extra cycles
   15771             :                  * and risk to avoid hard-wiring that knowledge here.
   15772             :                  */
   15773         262 :                 appendPQExpBufferStr(query,
   15774             :                                      "SELECT at.attname, "
   15775             :                                      "at.attacl, "
   15776             :                                      "'{}' AS acldefault, "
   15777             :                                      "pip.privtype, pip.initprivs "
   15778             :                                      "FROM pg_catalog.pg_attribute at "
   15779             :                                      "LEFT JOIN pg_catalog.pg_init_privs pip ON "
   15780             :                                      "(at.attrelid = pip.objoid "
   15781             :                                      "AND pip.classoid = 'pg_catalog.pg_class'::pg_catalog.regclass "
   15782             :                                      "AND at.attnum = pip.objsubid) "
   15783             :                                      "WHERE at.attrelid = $1 AND "
   15784             :                                      "NOT at.attisdropped "
   15785             :                                      "AND (at.attacl IS NOT NULL OR pip.initprivs IS NOT NULL) "
   15786             :                                      "ORDER BY at.attnum");
   15787             :             }
   15788             :             else
   15789             :             {
   15790           0 :                 appendPQExpBufferStr(query,
   15791             :                                      "SELECT attname, attacl, '{}' AS acldefault, "
   15792             :                                      "NULL AS privtype, NULL AS initprivs "
   15793             :                                      "FROM pg_catalog.pg_attribute "
   15794             :                                      "WHERE attrelid = $1 AND NOT attisdropped "
   15795             :                                      "AND attacl IS NOT NULL "
   15796             :                                      "ORDER BY attnum");
   15797             :             }
   15798             : 
   15799         262 :             ExecuteSqlStatement(fout, query->data);
   15800             : 
   15801         262 :             fout->is_prepared[PREPQUERY_GETCOLUMNACLS] = true;
   15802             :         }
   15803             : 
   15804         510 :         printfPQExpBuffer(query,
   15805             :                           "EXECUTE getColumnACLs('%u')",
   15806             :                           tbinfo->dobj.catId.oid);
   15807             : 
   15808         510 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   15809             : 
   15810        7020 :         for (i = 0; i < PQntuples(res); i++)
   15811             :         {
   15812        6510 :             char       *attname = PQgetvalue(res, i, 0);
   15813        6510 :             char       *attacl = PQgetvalue(res, i, 1);
   15814        6510 :             char       *acldefault = PQgetvalue(res, i, 2);
   15815        6510 :             char        privtype = *(PQgetvalue(res, i, 3));
   15816        6510 :             char       *initprivs = PQgetvalue(res, i, 4);
   15817             :             DumpableAcl coldacl;
   15818             :             char       *attnamecopy;
   15819             : 
   15820        6510 :             coldacl.acl = attacl;
   15821        6510 :             coldacl.acldefault = acldefault;
   15822        6510 :             coldacl.privtype = privtype;
   15823        6510 :             coldacl.initprivs = initprivs;
   15824        6510 :             attnamecopy = pg_strdup(fmtId(attname));
   15825             : 
   15826             :             /*
   15827             :              * Column's GRANT type is always TABLE.  Each column ACL depends
   15828             :              * on the table-level ACL, since we can restore column ACLs in
   15829             :              * parallel but the table-level ACL has to be done first.
   15830             :              */
   15831        6510 :             dumpACL(fout, tbinfo->dobj.dumpId, tableAclDumpId,
   15832             :                     "TABLE", namecopy, attnamecopy,
   15833        6510 :                     tbinfo->dobj.namespace->dobj.name,
   15834             :                     NULL, tbinfo->rolname, &coldacl);
   15835        6510 :             free(attnamecopy);
   15836             :         }
   15837         510 :         PQclear(res);
   15838         510 :         destroyPQExpBuffer(query);
   15839             :     }
   15840             : 
   15841       48250 :     free(namecopy);
   15842             : }
   15843             : 
   15844             : /*
   15845             :  * Create the AS clause for a view or materialized view. The semicolon is
   15846             :  * stripped because a materialized view must add a WITH NO DATA clause.
   15847             :  *
   15848             :  * This returns a new buffer which must be freed by the caller.
   15849             :  */
   15850             : static PQExpBuffer
   15851        1688 : createViewAsClause(Archive *fout, const TableInfo *tbinfo)
   15852             : {
   15853        1688 :     PQExpBuffer query = createPQExpBuffer();
   15854        1688 :     PQExpBuffer result = createPQExpBuffer();
   15855             :     PGresult   *res;
   15856             :     int         len;
   15857             : 
   15858             :     /* Fetch the view definition */
   15859        1688 :     appendPQExpBuffer(query,
   15860             :                       "SELECT pg_catalog.pg_get_viewdef('%u'::pg_catalog.oid) AS viewdef",
   15861             :                       tbinfo->dobj.catId.oid);
   15862             : 
   15863        1688 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   15864             : 
   15865        1688 :     if (PQntuples(res) != 1)
   15866             :     {
   15867           0 :         if (PQntuples(res) < 1)
   15868           0 :             pg_fatal("query to obtain definition of view \"%s\" returned no data",
   15869             :                      tbinfo->dobj.name);
   15870             :         else
   15871           0 :             pg_fatal("query to obtain definition of view \"%s\" returned more than one definition",
   15872             :                      tbinfo->dobj.name);
   15873             :     }
   15874             : 
   15875        1688 :     len = PQgetlength(res, 0, 0);
   15876             : 
   15877        1688 :     if (len == 0)
   15878           0 :         pg_fatal("definition of view \"%s\" appears to be empty (length zero)",
   15879             :                  tbinfo->dobj.name);
   15880             : 
   15881             :     /* Strip off the trailing semicolon so that other things may follow. */
   15882             :     Assert(PQgetvalue(res, 0, 0)[len - 1] == ';');
   15883        1688 :     appendBinaryPQExpBuffer(result, PQgetvalue(res, 0, 0), len - 1);
   15884             : 
   15885        1688 :     PQclear(res);
   15886        1688 :     destroyPQExpBuffer(query);
   15887             : 
   15888        1688 :     return result;
   15889             : }
   15890             : 
   15891             : /*
   15892             :  * Create a dummy AS clause for a view.  This is used when the real view
   15893             :  * definition has to be postponed because of circular dependencies.
   15894             :  * We must duplicate the view's external properties -- column names and types
   15895             :  * (including collation) -- so that it works for subsequent references.
   15896             :  *
   15897             :  * This returns a new buffer which must be freed by the caller.
   15898             :  */
   15899             : static PQExpBuffer
   15900          40 : createDummyViewAsClause(Archive *fout, const TableInfo *tbinfo)
   15901             : {
   15902          40 :     PQExpBuffer result = createPQExpBuffer();
   15903             :     int         j;
   15904             : 
   15905          40 :     appendPQExpBufferStr(result, "SELECT");
   15906             : 
   15907          80 :     for (j = 0; j < tbinfo->numatts; j++)
   15908             :     {
   15909          40 :         if (j > 0)
   15910          20 :             appendPQExpBufferChar(result, ',');
   15911          40 :         appendPQExpBufferStr(result, "\n    ");
   15912             : 
   15913          40 :         appendPQExpBuffer(result, "NULL::%s", tbinfo->atttypnames[j]);
   15914             : 
   15915             :         /*
   15916             :          * Must add collation if not default for the type, because CREATE OR
   15917             :          * REPLACE VIEW won't change it
   15918             :          */
   15919          40 :         if (OidIsValid(tbinfo->attcollation[j]))
   15920             :         {
   15921             :             CollInfo   *coll;
   15922             : 
   15923           0 :             coll = findCollationByOid(tbinfo->attcollation[j]);
   15924           0 :             if (coll)
   15925           0 :                 appendPQExpBuffer(result, " COLLATE %s",
   15926           0 :                                   fmtQualifiedDumpable(coll));
   15927             :         }
   15928             : 
   15929          40 :         appendPQExpBuffer(result, " AS %s", fmtId(tbinfo->attnames[j]));
   15930             :     }
   15931             : 
   15932          40 :     return result;
   15933             : }
   15934             : 
   15935             : /*
   15936             :  * dumpTableSchema
   15937             :  *    write the declaration (not data) of one user-defined table or view
   15938             :  */
   15939             : static void
   15940       11180 : dumpTableSchema(Archive *fout, const TableInfo *tbinfo)
   15941             : {
   15942       11180 :     DumpOptions *dopt = fout->dopt;
   15943       11180 :     PQExpBuffer q = createPQExpBuffer();
   15944       11180 :     PQExpBuffer delq = createPQExpBuffer();
   15945       11180 :     PQExpBuffer extra = createPQExpBuffer();
   15946             :     char       *qrelname;
   15947             :     char       *qualrelname;
   15948             :     int         numParents;
   15949             :     TableInfo **parents;
   15950             :     int         actual_atts;    /* number of attrs in this CREATE statement */
   15951             :     const char *reltypename;
   15952             :     char       *storage;
   15953             :     int         j,
   15954             :                 k;
   15955             : 
   15956             :     /* We had better have loaded per-column details about this table */
   15957             :     Assert(tbinfo->interesting);
   15958             : 
   15959       11180 :     qrelname = pg_strdup(fmtId(tbinfo->dobj.name));
   15960       11180 :     qualrelname = pg_strdup(fmtQualifiedDumpable(tbinfo));
   15961             : 
   15962       11180 :     if (tbinfo->hasoids)
   15963           0 :         pg_log_warning("WITH OIDS is not supported anymore (table \"%s\")",
   15964             :                        qrelname);
   15965             : 
   15966       11180 :     if (dopt->binary_upgrade)
   15967        1524 :         binary_upgrade_set_type_oids_by_rel(fout, q, tbinfo);
   15968             : 
   15969             :     /* Is it a table or a view? */
   15970       11180 :     if (tbinfo->relkind == RELKIND_VIEW)
   15971             :     {
   15972             :         PQExpBuffer result;
   15973             : 
   15974             :         /*
   15975             :          * Note: keep this code in sync with the is_view case in dumpRule()
   15976             :          */
   15977             : 
   15978        1014 :         reltypename = "VIEW";
   15979             : 
   15980        1014 :         appendPQExpBuffer(delq, "DROP VIEW %s;\n", qualrelname);
   15981             : 
   15982        1014 :         if (dopt->binary_upgrade)
   15983          98 :             binary_upgrade_set_pg_class_oids(fout, q,
   15984             :                                              tbinfo->dobj.catId.oid);
   15985             : 
   15986        1014 :         appendPQExpBuffer(q, "CREATE VIEW %s", qualrelname);
   15987             : 
   15988        1014 :         if (tbinfo->dummy_view)
   15989          20 :             result = createDummyViewAsClause(fout, tbinfo);
   15990             :         else
   15991             :         {
   15992         994 :             if (nonemptyReloptions(tbinfo->reloptions))
   15993             :             {
   15994         124 :                 appendPQExpBufferStr(q, " WITH (");
   15995         124 :                 appendReloptionsArrayAH(q, tbinfo->reloptions, "", fout);
   15996         124 :                 appendPQExpBufferChar(q, ')');
   15997             :             }
   15998         994 :             result = createViewAsClause(fout, tbinfo);
   15999             :         }
   16000        1014 :         appendPQExpBuffer(q, " AS\n%s", result->data);
   16001        1014 :         destroyPQExpBuffer(result);
   16002             : 
   16003        1014 :         if (tbinfo->checkoption != NULL && !tbinfo->dummy_view)
   16004          66 :             appendPQExpBuffer(q, "\n  WITH %s CHECK OPTION", tbinfo->checkoption);
   16005        1014 :         appendPQExpBufferStr(q, ";\n");
   16006             :     }
   16007             :     else
   16008             :     {
   16009       10166 :         char       *partkeydef = NULL;
   16010       10166 :         char       *ftoptions = NULL;
   16011       10166 :         char       *srvname = NULL;
   16012       10166 :         const char *foreign = "";
   16013             : 
   16014             :         /*
   16015             :          * Set reltypename, and collect any relkind-specific data that we
   16016             :          * didn't fetch during getTables().
   16017             :          */
   16018       10166 :         switch (tbinfo->relkind)
   16019             :         {
   16020        1036 :             case RELKIND_PARTITIONED_TABLE:
   16021             :                 {
   16022        1036 :                     PQExpBuffer query = createPQExpBuffer();
   16023             :                     PGresult   *res;
   16024             : 
   16025        1036 :                     reltypename = "TABLE";
   16026             : 
   16027             :                     /* retrieve partition key definition */
   16028        1036 :                     appendPQExpBuffer(query,
   16029             :                                       "SELECT pg_get_partkeydef('%u')",
   16030             :                                       tbinfo->dobj.catId.oid);
   16031        1036 :                     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   16032        1036 :                     partkeydef = pg_strdup(PQgetvalue(res, 0, 0));
   16033        1036 :                     PQclear(res);
   16034        1036 :                     destroyPQExpBuffer(query);
   16035        1036 :                     break;
   16036             :                 }
   16037          70 :             case RELKIND_FOREIGN_TABLE:
   16038             :                 {
   16039          70 :                     PQExpBuffer query = createPQExpBuffer();
   16040             :                     PGresult   *res;
   16041             :                     int         i_srvname;
   16042             :                     int         i_ftoptions;
   16043             : 
   16044          70 :                     reltypename = "FOREIGN TABLE";
   16045             : 
   16046             :                     /* retrieve name of foreign server and generic options */
   16047          70 :                     appendPQExpBuffer(query,
   16048             :                                       "SELECT fs.srvname, "
   16049             :                                       "pg_catalog.array_to_string(ARRAY("
   16050             :                                       "SELECT pg_catalog.quote_ident(option_name) || "
   16051             :                                       "' ' || pg_catalog.quote_literal(option_value) "
   16052             :                                       "FROM pg_catalog.pg_options_to_table(ftoptions) "
   16053             :                                       "ORDER BY option_name"
   16054             :                                       "), E',\n    ') AS ftoptions "
   16055             :                                       "FROM pg_catalog.pg_foreign_table ft "
   16056             :                                       "JOIN pg_catalog.pg_foreign_server fs "
   16057             :                                       "ON (fs.oid = ft.ftserver) "
   16058             :                                       "WHERE ft.ftrelid = '%u'",
   16059             :                                       tbinfo->dobj.catId.oid);
   16060          70 :                     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   16061          70 :                     i_srvname = PQfnumber(res, "srvname");
   16062          70 :                     i_ftoptions = PQfnumber(res, "ftoptions");
   16063          70 :                     srvname = pg_strdup(PQgetvalue(res, 0, i_srvname));
   16064          70 :                     ftoptions = pg_strdup(PQgetvalue(res, 0, i_ftoptions));
   16065          70 :                     PQclear(res);
   16066          70 :                     destroyPQExpBuffer(query);
   16067             : 
   16068          70 :                     foreign = "FOREIGN ";
   16069          70 :                     break;
   16070             :                 }
   16071         674 :             case RELKIND_MATVIEW:
   16072         674 :                 reltypename = "MATERIALIZED VIEW";
   16073         674 :                 break;
   16074        8386 :             default:
   16075        8386 :                 reltypename = "TABLE";
   16076        8386 :                 break;
   16077             :         }
   16078             : 
   16079       10166 :         numParents = tbinfo->numParents;
   16080       10166 :         parents = tbinfo->parents;
   16081             : 
   16082       10166 :         appendPQExpBuffer(delq, "DROP %s %s;\n", reltypename, qualrelname);
   16083             : 
   16084       10166 :         if (dopt->binary_upgrade)
   16085        1426 :             binary_upgrade_set_pg_class_oids(fout, q,
   16086             :                                              tbinfo->dobj.catId.oid);
   16087             : 
   16088             :         /*
   16089             :          * PostgreSQL 18 has disabled UNLOGGED for partitioned tables, so
   16090             :          * ignore it when dumping if it was set in this case.
   16091             :          */
   16092       10166 :         appendPQExpBuffer(q, "CREATE %s%s %s",
   16093       10166 :                           (tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED &&
   16094          40 :                            tbinfo->relkind != RELKIND_PARTITIONED_TABLE) ?
   16095             :                           "UNLOGGED " : "",
   16096             :                           reltypename,
   16097             :                           qualrelname);
   16098             : 
   16099             :         /*
   16100             :          * Attach to type, if reloftype; except in case of a binary upgrade,
   16101             :          * we dump the table normally and attach it to the type afterward.
   16102             :          */
   16103       10166 :         if (OidIsValid(tbinfo->reloftype) && !dopt->binary_upgrade)
   16104          48 :             appendPQExpBuffer(q, " OF %s",
   16105             :                               getFormattedTypeName(fout, tbinfo->reloftype,
   16106             :                                                    zeroIsError));
   16107             : 
   16108       10166 :         if (tbinfo->relkind != RELKIND_MATVIEW)
   16109             :         {
   16110             :             /* Dump the attributes */
   16111        9492 :             actual_atts = 0;
   16112       46786 :             for (j = 0; j < tbinfo->numatts; j++)
   16113             :             {
   16114             :                 /*
   16115             :                  * Normally, dump if it's locally defined in this table, and
   16116             :                  * not dropped.  But for binary upgrade, we'll dump all the
   16117             :                  * columns, and then fix up the dropped and nonlocal cases
   16118             :                  * below.
   16119             :                  */
   16120       37294 :                 if (shouldPrintColumn(dopt, tbinfo, j))
   16121             :                 {
   16122             :                     bool        print_default;
   16123             :                     bool        print_notnull;
   16124             : 
   16125             :                     /*
   16126             :                      * Default value --- suppress if to be printed separately
   16127             :                      * or not at all.
   16128             :                      */
   16129       72934 :                     print_default = (tbinfo->attrdefs[j] != NULL &&
   16130       37150 :                                      tbinfo->attrdefs[j]->dobj.dump &&
   16131        1446 :                                      !tbinfo->attrdefs[j]->separate);
   16132             : 
   16133             :                     /*
   16134             :                      * Not Null constraint --- print it if it is locally
   16135             :                      * defined, or if binary upgrade.  (In the latter case, we
   16136             :                      * reset conislocal below.)
   16137             :                      */
   16138       39628 :                     print_notnull = (tbinfo->notnull_constrs[j] != NULL &&
   16139        3924 :                                      (tbinfo->notnull_islocal[j] ||
   16140        1076 :                                       dopt->binary_upgrade ||
   16141         932 :                                       tbinfo->ispartition));
   16142             : 
   16143             :                     /*
   16144             :                      * Skip column if fully defined by reloftype, except in
   16145             :                      * binary upgrade
   16146             :                      */
   16147       35704 :                     if (OidIsValid(tbinfo->reloftype) &&
   16148         100 :                         !print_default && !print_notnull &&
   16149          60 :                         !dopt->binary_upgrade)
   16150          48 :                         continue;
   16151             : 
   16152             :                     /* Format properly if not first attr */
   16153       35656 :                     if (actual_atts == 0)
   16154        9012 :                         appendPQExpBufferStr(q, " (");
   16155             :                     else
   16156       26644 :                         appendPQExpBufferChar(q, ',');
   16157       35656 :                     appendPQExpBufferStr(q, "\n    ");
   16158       35656 :                     actual_atts++;
   16159             : 
   16160             :                     /* Attribute name */
   16161       35656 :                     appendPQExpBufferStr(q, fmtId(tbinfo->attnames[j]));
   16162             : 
   16163       35656 :                     if (tbinfo->attisdropped[j])
   16164             :                     {
   16165             :                         /*
   16166             :                          * ALTER TABLE DROP COLUMN clears
   16167             :                          * pg_attribute.atttypid, so we will not have gotten a
   16168             :                          * valid type name; insert INTEGER as a stopgap. We'll
   16169             :                          * clean things up later.
   16170             :                          */
   16171         158 :                         appendPQExpBufferStr(q, " INTEGER /* dummy */");
   16172             :                         /* and skip to the next column */
   16173         158 :                         continue;
   16174             :                     }
   16175             : 
   16176             :                     /*
   16177             :                      * Attribute type; print it except when creating a typed
   16178             :                      * table ('OF type_name'), but in binary-upgrade mode,
   16179             :                      * print it in that case too.
   16180             :                      */
   16181       35498 :                     if (dopt->binary_upgrade || !OidIsValid(tbinfo->reloftype))
   16182             :                     {
   16183       35466 :                         appendPQExpBuffer(q, " %s",
   16184       35466 :                                           tbinfo->atttypnames[j]);
   16185             :                     }
   16186             : 
   16187       35498 :                     if (print_default)
   16188             :                     {
   16189        1232 :                         if (tbinfo->attgenerated[j] == ATTRIBUTE_GENERATED_STORED)
   16190         530 :                             appendPQExpBuffer(q, " GENERATED ALWAYS AS (%s) STORED",
   16191         530 :                                               tbinfo->attrdefs[j]->adef_expr);
   16192             :                         else
   16193         702 :                             appendPQExpBuffer(q, " DEFAULT %s",
   16194         702 :                                               tbinfo->attrdefs[j]->adef_expr);
   16195             :                     }
   16196             : 
   16197       39422 :                     print_notnull = (tbinfo->notnull_constrs[j] != NULL &&
   16198        3924 :                                      (tbinfo->notnull_islocal[j] ||
   16199        1076 :                                       dopt->binary_upgrade ||
   16200         932 :                                       tbinfo->ispartition));
   16201             : 
   16202       35498 :                     if (print_notnull)
   16203             :                     {
   16204        3860 :                         if (tbinfo->notnull_constrs[j][0] == '\0')
   16205        2766 :                             appendPQExpBufferStr(q, " NOT NULL");
   16206             :                         else
   16207        1094 :                             appendPQExpBuffer(q, " CONSTRAINT %s NOT NULL",
   16208        1094 :                                               fmtId(tbinfo->notnull_constrs[j]));
   16209             : 
   16210        3860 :                         if (tbinfo->notnull_noinh[j])
   16211           0 :                             appendPQExpBufferStr(q, " NO INHERIT");
   16212             :                     }
   16213             : 
   16214             :                     /* Add collation if not default for the type */
   16215       35498 :                     if (OidIsValid(tbinfo->attcollation[j]))
   16216             :                     {
   16217             :                         CollInfo   *coll;
   16218             : 
   16219         394 :                         coll = findCollationByOid(tbinfo->attcollation[j]);
   16220         394 :                         if (coll)
   16221         394 :                             appendPQExpBuffer(q, " COLLATE %s",
   16222         394 :                                               fmtQualifiedDumpable(coll));
   16223             :                     }
   16224             :                 }
   16225             : 
   16226             :                 /*
   16227             :                  * On the other hand, if we choose not to print a column
   16228             :                  * (likely because it is created by inheritance), but the
   16229             :                  * column has a locally-defined not-null constraint, we need
   16230             :                  * to dump the constraint as a standalone object.
   16231             :                  *
   16232             :                  * This syntax isn't SQL-conforming, but if you wanted
   16233             :                  * standard output you wouldn't be creating non-standard
   16234             :                  * objects to begin with.
   16235             :                  */
   16236       37088 :                 if (!shouldPrintColumn(dopt, tbinfo, j) &&
   16237        1590 :                     !tbinfo->attisdropped[j] &&
   16238         902 :                     tbinfo->notnull_constrs[j] != NULL &&
   16239         176 :                     tbinfo->notnull_islocal[j])
   16240             :                 {
   16241             :                     /* Format properly if not first attr */
   16242          32 :                     if (actual_atts == 0)
   16243          24 :                         appendPQExpBufferStr(q, " (");
   16244             :                     else
   16245           8 :                         appendPQExpBufferChar(q, ',');
   16246          32 :                     appendPQExpBufferStr(q, "\n    ");
   16247          32 :                     actual_atts++;
   16248             : 
   16249          32 :                     if (tbinfo->notnull_constrs[j][0] == '\0')
   16250           8 :                         appendPQExpBuffer(q, "NOT NULL %s",
   16251           8 :                                           fmtId(tbinfo->attnames[j]));
   16252             :                     else
   16253          48 :                         appendPQExpBuffer(q, "CONSTRAINT %s NOT NULL %s",
   16254          24 :                                           tbinfo->notnull_constrs[j],
   16255          24 :                                           fmtId(tbinfo->attnames[j]));
   16256             :                 }
   16257             :             }
   16258             : 
   16259             :             /*
   16260             :              * Add non-inherited CHECK constraints, if any.
   16261             :              *
   16262             :              * For partitions, we need to include check constraints even if
   16263             :              * they're not defined locally, because the ALTER TABLE ATTACH
   16264             :              * PARTITION that we'll emit later expects the constraint to be
   16265             :              * there.  (No need to fix conislocal: ATTACH PARTITION does that)
   16266             :              */
   16267       10618 :             for (j = 0; j < tbinfo->ncheck; j++)
   16268             :             {
   16269        1126 :                 ConstraintInfo *constr = &(tbinfo->checkexprs[j]);
   16270             : 
   16271        1126 :                 if (constr->separate ||
   16272         996 :                     (!constr->conislocal && !tbinfo->ispartition))
   16273         206 :                     continue;
   16274             : 
   16275         920 :                 if (actual_atts == 0)
   16276          32 :                     appendPQExpBufferStr(q, " (\n    ");
   16277             :                 else
   16278         888 :                     appendPQExpBufferStr(q, ",\n    ");
   16279             : 
   16280         920 :                 appendPQExpBuffer(q, "CONSTRAINT %s ",
   16281         920 :                                   fmtId(constr->dobj.name));
   16282         920 :                 appendPQExpBufferStr(q, constr->condef);
   16283             : 
   16284         920 :                 actual_atts++;
   16285             :             }
   16286             : 
   16287        9492 :             if (actual_atts)
   16288        9068 :                 appendPQExpBufferStr(q, "\n)");
   16289         424 :             else if (!(OidIsValid(tbinfo->reloftype) && !dopt->binary_upgrade))
   16290             :             {
   16291             :                 /*
   16292             :                  * No attributes? we must have a parenthesized attribute list,
   16293             :                  * even though empty, when not using the OF TYPE syntax.
   16294             :                  */
   16295         400 :                 appendPQExpBufferStr(q, " (\n)");
   16296             :             }
   16297             : 
   16298             :             /*
   16299             :              * Emit the INHERITS clause (not for partitions), except in
   16300             :              * binary-upgrade mode.
   16301             :              */
   16302        9492 :             if (numParents > 0 && !tbinfo->ispartition &&
   16303         672 :                 !dopt->binary_upgrade)
   16304             :             {
   16305         574 :                 appendPQExpBufferStr(q, "\nINHERITS (");
   16306        1204 :                 for (k = 0; k < numParents; k++)
   16307             :                 {
   16308         630 :                     TableInfo  *parentRel = parents[k];
   16309             : 
   16310         630 :                     if (k > 0)
   16311          56 :                         appendPQExpBufferStr(q, ", ");
   16312         630 :                     appendPQExpBufferStr(q, fmtQualifiedDumpable(parentRel));
   16313             :                 }
   16314         574 :                 appendPQExpBufferChar(q, ')');
   16315             :             }
   16316             : 
   16317        9492 :             if (tbinfo->relkind == RELKIND_PARTITIONED_TABLE)
   16318        1036 :                 appendPQExpBuffer(q, "\nPARTITION BY %s", partkeydef);
   16319             : 
   16320        9492 :             if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
   16321          70 :                 appendPQExpBuffer(q, "\nSERVER %s", fmtId(srvname));
   16322             :         }
   16323             : 
   16324       20046 :         if (nonemptyReloptions(tbinfo->reloptions) ||
   16325        9880 :             nonemptyReloptions(tbinfo->toast_reloptions))
   16326             :         {
   16327         286 :             bool        addcomma = false;
   16328             : 
   16329         286 :             appendPQExpBufferStr(q, "\nWITH (");
   16330         286 :             if (nonemptyReloptions(tbinfo->reloptions))
   16331             :             {
   16332         286 :                 addcomma = true;
   16333         286 :                 appendReloptionsArrayAH(q, tbinfo->reloptions, "", fout);
   16334             :             }
   16335         286 :             if (nonemptyReloptions(tbinfo->toast_reloptions))
   16336             :             {
   16337          10 :                 if (addcomma)
   16338          10 :                     appendPQExpBufferStr(q, ", ");
   16339          10 :                 appendReloptionsArrayAH(q, tbinfo->toast_reloptions, "toast.",
   16340             :                                         fout);
   16341             :             }
   16342         286 :             appendPQExpBufferChar(q, ')');
   16343             :         }
   16344             : 
   16345             :         /* Dump generic options if any */
   16346       10166 :         if (ftoptions && ftoptions[0])
   16347          66 :             appendPQExpBuffer(q, "\nOPTIONS (\n    %s\n)", ftoptions);
   16348             : 
   16349             :         /*
   16350             :          * For materialized views, create the AS clause just like a view. At
   16351             :          * this point, we always mark the view as not populated.
   16352             :          */
   16353       10166 :         if (tbinfo->relkind == RELKIND_MATVIEW)
   16354             :         {
   16355             :             PQExpBuffer result;
   16356             : 
   16357         674 :             result = createViewAsClause(fout, tbinfo);
   16358         674 :             appendPQExpBuffer(q, " AS\n%s\n  WITH NO DATA;\n",
   16359             :                               result->data);
   16360         674 :             destroyPQExpBuffer(result);
   16361             :         }
   16362             :         else
   16363        9492 :             appendPQExpBufferStr(q, ";\n");
   16364             : 
   16365             :         /* Materialized views can depend on extensions */
   16366       10166 :         if (tbinfo->relkind == RELKIND_MATVIEW)
   16367         674 :             append_depends_on_extension(fout, q, &tbinfo->dobj,
   16368             :                                         "pg_catalog.pg_class",
   16369             :                                         "MATERIALIZED VIEW",
   16370             :                                         qualrelname);
   16371             : 
   16372             :         /*
   16373             :          * in binary upgrade mode, update the catalog with any missing values
   16374             :          * that might be present.
   16375             :          */
   16376       10166 :         if (dopt->binary_upgrade)
   16377             :         {
   16378        7306 :             for (j = 0; j < tbinfo->numatts; j++)
   16379             :             {
   16380        5880 :                 if (tbinfo->attmissingval[j][0] != '\0')
   16381             :                 {
   16382           4 :                     appendPQExpBufferStr(q, "\n-- set missing value.\n");
   16383           4 :                     appendPQExpBufferStr(q,
   16384             :                                          "SELECT pg_catalog.binary_upgrade_set_missing_value(");
   16385           4 :                     appendStringLiteralAH(q, qualrelname, fout);
   16386           4 :                     appendPQExpBufferStr(q, "::pg_catalog.regclass,");
   16387           4 :                     appendStringLiteralAH(q, tbinfo->attnames[j], fout);
   16388           4 :                     appendPQExpBufferChar(q, ',');
   16389           4 :                     appendStringLiteralAH(q, tbinfo->attmissingval[j], fout);
   16390           4 :                     appendPQExpBufferStr(q, ");\n\n");
   16391             :                 }
   16392             :             }
   16393             :         }
   16394             : 
   16395             :         /*
   16396             :          * To create binary-compatible heap files, we have to ensure the same
   16397             :          * physical column order, including dropped columns, as in the
   16398             :          * original.  Therefore, we create dropped columns above and drop them
   16399             :          * here, also updating their attlen/attalign values so that the
   16400             :          * dropped column can be skipped properly.  (We do not bother with
   16401             :          * restoring the original attbyval setting.)  Also, inheritance
   16402             :          * relationships are set up by doing ALTER TABLE INHERIT rather than
   16403             :          * using an INHERITS clause --- the latter would possibly mess up the
   16404             :          * column order.  That also means we have to take care about setting
   16405             :          * attislocal correctly, plus fix up any inherited CHECK constraints.
   16406             :          * Analogously, we set up typed tables using ALTER TABLE / OF here.
   16407             :          *
   16408             :          * We process foreign and partitioned tables here, even though they
   16409             :          * lack heap storage, because they can participate in inheritance
   16410             :          * relationships and we want this stuff to be consistent across the
   16411             :          * inheritance tree.  We can exclude indexes, toast tables, sequences
   16412             :          * and matviews, even though they have storage, because we don't
   16413             :          * support altering or dropping columns in them, nor can they be part
   16414             :          * of inheritance trees.
   16415             :          */
   16416       10166 :         if (dopt->binary_upgrade &&
   16417        1426 :             (tbinfo->relkind == RELKIND_RELATION ||
   16418         208 :              tbinfo->relkind == RELKIND_FOREIGN_TABLE ||
   16419         206 :              tbinfo->relkind == RELKIND_PARTITIONED_TABLE))
   16420             :         {
   16421             :             bool        firstitem;
   16422             :             bool        firstitem_extra;
   16423             : 
   16424             :             /*
   16425             :              * Drop any dropped columns.  Merge the pg_attribute manipulations
   16426             :              * into a single SQL command, so that we don't cause repeated
   16427             :              * relcache flushes on the target table.  Otherwise we risk O(N^2)
   16428             :              * relcache bloat while dropping N columns.
   16429             :              */
   16430        1392 :             resetPQExpBuffer(extra);
   16431        1392 :             firstitem = true;
   16432        7232 :             for (j = 0; j < tbinfo->numatts; j++)
   16433             :             {
   16434        5840 :                 if (tbinfo->attisdropped[j])
   16435             :                 {
   16436         158 :                     if (firstitem)
   16437             :                     {
   16438          68 :                         appendPQExpBufferStr(q, "\n-- For binary upgrade, recreate dropped columns.\n"
   16439             :                                              "UPDATE pg_catalog.pg_attribute\n"
   16440             :                                              "SET attlen = v.dlen, "
   16441             :                                              "attalign = v.dalign, "
   16442             :                                              "attbyval = false\n"
   16443             :                                              "FROM (VALUES ");
   16444          68 :                         firstitem = false;
   16445             :                     }
   16446             :                     else
   16447          90 :                         appendPQExpBufferStr(q, ",\n             ");
   16448         158 :                     appendPQExpBufferChar(q, '(');
   16449         158 :                     appendStringLiteralAH(q, tbinfo->attnames[j], fout);
   16450         158 :                     appendPQExpBuffer(q, ", %d, '%c')",
   16451         158 :                                       tbinfo->attlen[j],
   16452         158 :                                       tbinfo->attalign[j]);
   16453             :                     /* The ALTER ... DROP COLUMN commands must come after */
   16454         158 :                     appendPQExpBuffer(extra, "ALTER %sTABLE ONLY %s ",
   16455             :                                       foreign, qualrelname);
   16456         158 :                     appendPQExpBuffer(extra, "DROP COLUMN %s;\n",
   16457         158 :                                       fmtId(tbinfo->attnames[j]));
   16458             :                 }
   16459             :             }
   16460        1392 :             if (!firstitem)
   16461             :             {
   16462          68 :                 appendPQExpBufferStr(q, ") v(dname, dlen, dalign)\n"
   16463             :                                      "WHERE attrelid = ");
   16464          68 :                 appendStringLiteralAH(q, qualrelname, fout);
   16465          68 :                 appendPQExpBufferStr(q, "::pg_catalog.regclass\n"
   16466             :                                      "  AND attname = v.dname;\n");
   16467             :                 /* Now we can issue the actual DROP COLUMN commands */
   16468          68 :                 appendBinaryPQExpBuffer(q, extra->data, extra->len);
   16469             :             }
   16470             : 
   16471             :             /*
   16472             :              * Fix up inherited columns.  As above, do the pg_attribute
   16473             :              * manipulations in a single SQL command.
   16474             :              */
   16475        1392 :             firstitem = true;
   16476        7232 :             for (j = 0; j < tbinfo->numatts; j++)
   16477             :             {
   16478        5840 :                 if (!tbinfo->attisdropped[j] &&
   16479        5682 :                     !tbinfo->attislocal[j])
   16480             :                 {
   16481        1122 :                     if (firstitem)
   16482             :                     {
   16483         488 :                         appendPQExpBufferStr(q, "\n-- For binary upgrade, recreate inherited columns.\n");
   16484         488 :                         appendPQExpBufferStr(q, "UPDATE pg_catalog.pg_attribute\n"
   16485             :                                              "SET attislocal = false\n"
   16486             :                                              "WHERE attrelid = ");
   16487         488 :                         appendStringLiteralAH(q, qualrelname, fout);
   16488         488 :                         appendPQExpBufferStr(q, "::pg_catalog.regclass\n"
   16489             :                                              "  AND attname IN (");
   16490         488 :                         firstitem = false;
   16491             :                     }
   16492             :                     else
   16493         634 :                         appendPQExpBufferStr(q, ", ");
   16494        1122 :                     appendStringLiteralAH(q, tbinfo->attnames[j], fout);
   16495             :                 }
   16496             :             }
   16497        1392 :             if (!firstitem)
   16498         488 :                 appendPQExpBufferStr(q, ");\n");
   16499             : 
   16500             :             /*
   16501             :              * Fix up not-null constraints that come from inheritance.  As
   16502             :              * above, do the pg_constraint manipulations in a single SQL
   16503             :              * command.  (Actually, two in special cases, if we're doing an
   16504             :              * upgrade from < 18).
   16505             :              */
   16506        1392 :             firstitem = true;
   16507        1392 :             firstitem_extra = true;
   16508        1392 :             resetPQExpBuffer(extra);
   16509        7232 :             for (j = 0; j < tbinfo->numatts; j++)
   16510             :             {
   16511             :                 /*
   16512             :                  * If a not-null constraint comes from inheritance, reset
   16513             :                  * conislocal.  The inhcount is fixed by ALTER TABLE INHERIT,
   16514             :                  * below.  Special hack: in versions < 18, columns with no
   16515             :                  * local definition need their constraint to be matched by
   16516             :                  * column number in conkeys instead of by constraint name,
   16517             :                  * because the latter is not available.  (We distinguish the
   16518             :                  * case because the constraint name is the empty string.)
   16519             :                  */
   16520        5840 :                 if (tbinfo->notnull_constrs[j] != NULL &&
   16521         480 :                     !tbinfo->notnull_islocal[j])
   16522             :                 {
   16523         144 :                     if (tbinfo->notnull_constrs[j][0] != '\0')
   16524             :                     {
   16525         120 :                         if (firstitem)
   16526             :                         {
   16527         104 :                             appendPQExpBufferStr(q, "UPDATE pg_catalog.pg_constraint\n"
   16528             :                                                  "SET conislocal = false\n"
   16529             :                                                  "WHERE contype = 'n' AND conrelid = ");
   16530         104 :                             appendStringLiteralAH(q, qualrelname, fout);
   16531         104 :                             appendPQExpBufferStr(q, "::pg_catalog.regclass AND\n"
   16532             :                                                  "conname IN (");
   16533         104 :                             firstitem = false;
   16534             :                         }
   16535             :                         else
   16536          16 :                             appendPQExpBufferStr(q, ", ");
   16537         120 :                         appendStringLiteralAH(q, tbinfo->notnull_constrs[j], fout);
   16538             :                     }
   16539             :                     else
   16540             :                     {
   16541          24 :                         if (firstitem_extra)
   16542             :                         {
   16543          24 :                             appendPQExpBufferStr(extra, "UPDATE pg_catalog.pg_constraint\n"
   16544             :                                                  "SET conislocal = false\n"
   16545             :                                                  "WHERE contype = 'n' AND conrelid = ");
   16546          24 :                             appendStringLiteralAH(extra, qualrelname, fout);
   16547          24 :                             appendPQExpBufferStr(extra, "::pg_catalog.regclass AND\n"
   16548             :                                                  "conkey IN (");
   16549          24 :                             firstitem_extra = false;
   16550             :                         }
   16551             :                         else
   16552           0 :                             appendPQExpBufferStr(extra, ", ");
   16553          24 :                         appendPQExpBuffer(extra, "'{%d}'", j + 1);
   16554             :                     }
   16555             :                 }
   16556             :             }
   16557        1392 :             if (!firstitem)
   16558         104 :                 appendPQExpBufferStr(q, ");\n");
   16559        1392 :             if (!firstitem_extra)
   16560          24 :                 appendPQExpBufferStr(extra, ");\n");
   16561             : 
   16562        1392 :             if (extra->len > 0)
   16563          24 :                 appendBinaryPQExpBuffer(q, extra->data, extra->len);
   16564             : 
   16565             :             /*
   16566             :              * Add inherited CHECK constraints, if any.
   16567             :              *
   16568             :              * For partitions, they were already dumped, and conislocal
   16569             :              * doesn't need fixing.
   16570             :              *
   16571             :              * As above, issue only one direct manipulation of pg_constraint.
   16572             :              * Although it is tempting to merge the ALTER ADD CONSTRAINT
   16573             :              * commands into one as well, refrain for now due to concern about
   16574             :              * possible backend memory bloat if there are many such
   16575             :              * constraints.
   16576             :              */
   16577        1392 :             resetPQExpBuffer(extra);
   16578        1392 :             firstitem = true;
   16579        1508 :             for (k = 0; k < tbinfo->ncheck; k++)
   16580             :             {
   16581         116 :                 ConstraintInfo *constr = &(tbinfo->checkexprs[k]);
   16582             : 
   16583         116 :                 if (constr->separate || constr->conislocal || tbinfo->ispartition)
   16584         112 :                     continue;
   16585             : 
   16586           4 :                 if (firstitem)
   16587           4 :                     appendPQExpBufferStr(q, "\n-- For binary upgrade, set up inherited constraints.\n");
   16588           4 :                 appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s ADD CONSTRAINT %s %s;\n",
   16589             :                                   foreign, qualrelname,
   16590           4 :                                   fmtId(constr->dobj.name),
   16591             :                                   constr->condef);
   16592             :                 /* Update pg_constraint after all the ALTER TABLEs */
   16593           4 :                 if (firstitem)
   16594             :                 {
   16595           4 :                     appendPQExpBufferStr(extra, "UPDATE pg_catalog.pg_constraint\n"
   16596             :                                          "SET conislocal = false\n"
   16597             :                                          "WHERE contype = 'c' AND conrelid = ");
   16598           4 :                     appendStringLiteralAH(extra, qualrelname, fout);
   16599           4 :                     appendPQExpBufferStr(extra, "::pg_catalog.regclass\n");
   16600           4 :                     appendPQExpBufferStr(extra, "  AND conname IN (");
   16601           4 :                     firstitem = false;
   16602             :                 }
   16603             :                 else
   16604           0 :                     appendPQExpBufferStr(extra, ", ");
   16605           4 :                 appendStringLiteralAH(extra, constr->dobj.name, fout);
   16606             :             }
   16607        1392 :             if (!firstitem)
   16608             :             {
   16609           4 :                 appendPQExpBufferStr(extra, ");\n");
   16610           4 :                 appendBinaryPQExpBuffer(q, extra->data, extra->len);
   16611             :             }
   16612             : 
   16613        1392 :             if (numParents > 0 && !tbinfo->ispartition)
   16614             :             {
   16615          98 :                 appendPQExpBufferStr(q, "\n-- For binary upgrade, set up inheritance this way.\n");
   16616         210 :                 for (k = 0; k < numParents; k++)
   16617             :                 {
   16618         112 :                     TableInfo  *parentRel = parents[k];
   16619             : 
   16620         112 :                     appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s INHERIT %s;\n", foreign,
   16621             :                                       qualrelname,
   16622         112 :                                       fmtQualifiedDumpable(parentRel));
   16623             :                 }
   16624             :             }
   16625             : 
   16626        1392 :             if (OidIsValid(tbinfo->reloftype))
   16627             :             {
   16628          12 :                 appendPQExpBufferStr(q, "\n-- For binary upgrade, set up typed tables this way.\n");
   16629          12 :                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s OF %s;\n",
   16630             :                                   qualrelname,
   16631             :                                   getFormattedTypeName(fout, tbinfo->reloftype,
   16632             :                                                        zeroIsError));
   16633             :             }
   16634             :         }
   16635             : 
   16636             :         /*
   16637             :          * In binary_upgrade mode, arrange to restore the old relfrozenxid and
   16638             :          * relminmxid of all vacuumable relations.  (While vacuum.c processes
   16639             :          * TOAST tables semi-independently, here we see them only as children
   16640             :          * of other relations; so this "if" lacks RELKIND_TOASTVALUE, and the
   16641             :          * child toast table is handled below.)
   16642             :          */
   16643       10166 :         if (dopt->binary_upgrade &&
   16644        1426 :             (tbinfo->relkind == RELKIND_RELATION ||
   16645         208 :              tbinfo->relkind == RELKIND_MATVIEW))
   16646             :         {
   16647        1252 :             appendPQExpBufferStr(q, "\n-- For binary upgrade, set heap's relfrozenxid and relminmxid\n");
   16648        1252 :             appendPQExpBuffer(q, "UPDATE pg_catalog.pg_class\n"
   16649             :                               "SET relfrozenxid = '%u', relminmxid = '%u'\n"
   16650             :                               "WHERE oid = ",
   16651             :                               tbinfo->frozenxid, tbinfo->minmxid);
   16652        1252 :             appendStringLiteralAH(q, qualrelname, fout);
   16653        1252 :             appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
   16654             : 
   16655        1252 :             if (tbinfo->toast_oid)
   16656             :             {
   16657             :                 /*
   16658             :                  * The toast table will have the same OID at restore, so we
   16659             :                  * can safely target it by OID.
   16660             :                  */
   16661         548 :                 appendPQExpBufferStr(q, "\n-- For binary upgrade, set toast's relfrozenxid and relminmxid\n");
   16662         548 :                 appendPQExpBuffer(q, "UPDATE pg_catalog.pg_class\n"
   16663             :                                   "SET relfrozenxid = '%u', relminmxid = '%u'\n"
   16664             :                                   "WHERE oid = '%u';\n",
   16665             :                                   tbinfo->toast_frozenxid,
   16666             :                                   tbinfo->toast_minmxid, tbinfo->toast_oid);
   16667             :             }
   16668             :         }
   16669             : 
   16670             :         /*
   16671             :          * In binary_upgrade mode, restore matviews' populated status by
   16672             :          * poking pg_class directly.  This is pretty ugly, but we can't use
   16673             :          * REFRESH MATERIALIZED VIEW since it's possible that some underlying
   16674             :          * matview is not populated even though this matview is; in any case,
   16675             :          * we want to transfer the matview's heap storage, not run REFRESH.
   16676             :          */
   16677       10166 :         if (dopt->binary_upgrade && tbinfo->relkind == RELKIND_MATVIEW &&
   16678          34 :             tbinfo->relispopulated)
   16679             :         {
   16680          30 :             appendPQExpBufferStr(q, "\n-- For binary upgrade, mark materialized view as populated\n");
   16681          30 :             appendPQExpBufferStr(q, "UPDATE pg_catalog.pg_class\n"
   16682             :                                  "SET relispopulated = 't'\n"
   16683             :                                  "WHERE oid = ");
   16684          30 :             appendStringLiteralAH(q, qualrelname, fout);
   16685          30 :             appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
   16686             :         }
   16687             : 
   16688             :         /*
   16689             :          * Dump additional per-column properties that we can't handle in the
   16690             :          * main CREATE TABLE command.
   16691             :          */
   16692       48220 :         for (j = 0; j < tbinfo->numatts; j++)
   16693             :         {
   16694             :             /* None of this applies to dropped columns */
   16695       38054 :             if (tbinfo->attisdropped[j])
   16696         846 :                 continue;
   16697             : 
   16698             :             /*
   16699             :              * Dump per-column statistics information. We only issue an ALTER
   16700             :              * TABLE statement if the attstattarget entry for this column is
   16701             :              * not the default value.
   16702             :              */
   16703       37208 :             if (tbinfo->attstattarget[j] >= 0)
   16704          66 :                 appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s ALTER COLUMN %s SET STATISTICS %d;\n",
   16705             :                                   foreign, qualrelname,
   16706          66 :                                   fmtId(tbinfo->attnames[j]),
   16707          66 :                                   tbinfo->attstattarget[j]);
   16708             : 
   16709             :             /*
   16710             :              * Dump per-column storage information.  The statement is only
   16711             :              * dumped if the storage has been changed from the type's default.
   16712             :              */
   16713       37208 :             if (tbinfo->attstorage[j] != tbinfo->typstorage[j])
   16714             :             {
   16715         162 :                 switch (tbinfo->attstorage[j])
   16716             :                 {
   16717          20 :                     case TYPSTORAGE_PLAIN:
   16718          20 :                         storage = "PLAIN";
   16719          20 :                         break;
   16720          76 :                     case TYPSTORAGE_EXTERNAL:
   16721          76 :                         storage = "EXTERNAL";
   16722          76 :                         break;
   16723           0 :                     case TYPSTORAGE_EXTENDED:
   16724           0 :                         storage = "EXTENDED";
   16725           0 :                         break;
   16726          66 :                     case TYPSTORAGE_MAIN:
   16727          66 :                         storage = "MAIN";
   16728          66 :                         break;
   16729           0 :                     default:
   16730           0 :                         storage = NULL;
   16731             :                 }
   16732             : 
   16733             :                 /*
   16734             :                  * Only dump the statement if it's a storage type we recognize
   16735             :                  */
   16736         162 :                 if (storage != NULL)
   16737         162 :                     appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s ALTER COLUMN %s SET STORAGE %s;\n",
   16738             :                                       foreign, qualrelname,
   16739         162 :                                       fmtId(tbinfo->attnames[j]),
   16740             :                                       storage);
   16741             :             }
   16742             : 
   16743             :             /*
   16744             :              * Dump per-column compression, if it's been set.
   16745             :              */
   16746       37208 :             if (!dopt->no_toast_compression)
   16747             :             {
   16748             :                 const char *cmname;
   16749             : 
   16750       37042 :                 switch (tbinfo->attcompression[j])
   16751             :                 {
   16752         114 :                     case 'p':
   16753         114 :                         cmname = "pglz";
   16754         114 :                         break;
   16755         188 :                     case 'l':
   16756         188 :                         cmname = "lz4";
   16757         188 :                         break;
   16758       36740 :                     default:
   16759       36740 :                         cmname = NULL;
   16760       36740 :                         break;
   16761             :                 }
   16762             : 
   16763       37042 :                 if (cmname != NULL)
   16764         302 :                     appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s ALTER COLUMN %s SET COMPRESSION %s;\n",
   16765             :                                       foreign, qualrelname,
   16766         302 :                                       fmtId(tbinfo->attnames[j]),
   16767             :                                       cmname);
   16768             :             }
   16769             : 
   16770             :             /*
   16771             :              * Dump per-column attributes.
   16772             :              */
   16773       37208 :             if (tbinfo->attoptions[j][0] != '\0')
   16774          66 :                 appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s ALTER COLUMN %s SET (%s);\n",
   16775             :                                   foreign, qualrelname,
   16776          66 :                                   fmtId(tbinfo->attnames[j]),
   16777          66 :                                   tbinfo->attoptions[j]);
   16778             : 
   16779             :             /*
   16780             :              * Dump per-column fdw options.
   16781             :              */
   16782       37208 :             if (tbinfo->relkind == RELKIND_FOREIGN_TABLE &&
   16783          70 :                 tbinfo->attfdwoptions[j][0] != '\0')
   16784          66 :                 appendPQExpBuffer(q,
   16785             :                                   "ALTER FOREIGN TABLE ONLY %s ALTER COLUMN %s OPTIONS (\n"
   16786             :                                   "    %s\n"
   16787             :                                   ");\n",
   16788             :                                   qualrelname,
   16789          66 :                                   fmtId(tbinfo->attnames[j]),
   16790          66 :                                   tbinfo->attfdwoptions[j]);
   16791             :         }                       /* end loop over columns */
   16792             : 
   16793       10166 :         free(partkeydef);
   16794       10166 :         free(ftoptions);
   16795       10166 :         free(srvname);
   16796             :     }
   16797             : 
   16798             :     /*
   16799             :      * dump properties we only have ALTER TABLE syntax for
   16800             :      */
   16801       11180 :     if ((tbinfo->relkind == RELKIND_RELATION ||
   16802        2794 :          tbinfo->relkind == RELKIND_PARTITIONED_TABLE ||
   16803        1758 :          tbinfo->relkind == RELKIND_MATVIEW) &&
   16804       10096 :         tbinfo->relreplident != REPLICA_IDENTITY_DEFAULT)
   16805             :     {
   16806         384 :         if (tbinfo->relreplident == REPLICA_IDENTITY_INDEX)
   16807             :         {
   16808             :             /* nothing to do, will be set when the index is dumped */
   16809             :         }
   16810         384 :         else if (tbinfo->relreplident == REPLICA_IDENTITY_NOTHING)
   16811             :         {
   16812         384 :             appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY NOTHING;\n",
   16813             :                               qualrelname);
   16814             :         }
   16815           0 :         else if (tbinfo->relreplident == REPLICA_IDENTITY_FULL)
   16816             :         {
   16817           0 :             appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY FULL;\n",
   16818             :                               qualrelname);
   16819             :         }
   16820             :     }
   16821             : 
   16822       11180 :     if (tbinfo->forcerowsec)
   16823          10 :         appendPQExpBuffer(q, "\nALTER TABLE ONLY %s FORCE ROW LEVEL SECURITY;\n",
   16824             :                           qualrelname);
   16825             : 
   16826       11180 :     if (dopt->binary_upgrade)
   16827        1524 :         binary_upgrade_extension_member(q, &tbinfo->dobj,
   16828             :                                         reltypename, qrelname,
   16829        1524 :                                         tbinfo->dobj.namespace->dobj.name);
   16830             : 
   16831       11180 :     if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   16832             :     {
   16833       11180 :         char       *tablespace = NULL;
   16834       11180 :         char       *tableam = NULL;
   16835             : 
   16836             :         /*
   16837             :          * _selectTablespace() relies on tablespace-enabled objects in the
   16838             :          * default tablespace to have a tablespace of "" (empty string) versus
   16839             :          * non-tablespace-enabled objects to have a tablespace of NULL.
   16840             :          * getTables() sets tbinfo->reltablespace to "" for the default
   16841             :          * tablespace (not NULL).
   16842             :          */
   16843       11180 :         if (RELKIND_HAS_TABLESPACE(tbinfo->relkind))
   16844       10096 :             tablespace = tbinfo->reltablespace;
   16845             : 
   16846       11180 :         if (RELKIND_HAS_TABLE_AM(tbinfo->relkind) ||
   16847        2120 :             tbinfo->relkind == RELKIND_PARTITIONED_TABLE)
   16848       10096 :             tableam = tbinfo->amname;
   16849             : 
   16850       11180 :         ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
   16851       11180 :                      ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
   16852             :                                   .namespace = tbinfo->dobj.namespace->dobj.name,
   16853             :                                   .tablespace = tablespace,
   16854             :                                   .tableam = tableam,
   16855             :                                   .relkind = tbinfo->relkind,
   16856             :                                   .owner = tbinfo->rolname,
   16857             :                                   .description = reltypename,
   16858             :                                   .section = tbinfo->postponed_def ?
   16859             :                                   SECTION_POST_DATA : SECTION_PRE_DATA,
   16860             :                                   .createStmt = q->data,
   16861             :                                   .dropStmt = delq->data));
   16862             :     }
   16863             : 
   16864             :     /* Dump Table Comments */
   16865       11180 :     if (tbinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   16866         152 :         dumpTableComment(fout, tbinfo, reltypename);
   16867             : 
   16868             :     /* Dump Table Security Labels */
   16869       11180 :     if (tbinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
   16870           0 :         dumpTableSecLabel(fout, tbinfo, reltypename);
   16871             : 
   16872             :     /* Dump comments on inlined table constraints */
   16873       12306 :     for (j = 0; j < tbinfo->ncheck; j++)
   16874             :     {
   16875        1126 :         ConstraintInfo *constr = &(tbinfo->checkexprs[j]);
   16876             : 
   16877        1126 :         if (constr->separate || !constr->conislocal)
   16878         488 :             continue;
   16879             : 
   16880         638 :         if (constr->dobj.dump & DUMP_COMPONENT_COMMENT)
   16881          76 :             dumpTableConstraintComment(fout, constr);
   16882             :     }
   16883             : 
   16884       11180 :     destroyPQExpBuffer(q);
   16885       11180 :     destroyPQExpBuffer(delq);
   16886       11180 :     destroyPQExpBuffer(extra);
   16887       11180 :     free(qrelname);
   16888       11180 :     free(qualrelname);
   16889       11180 : }
   16890             : 
   16891             : /*
   16892             :  * dumpTableAttach
   16893             :  *    write to fout the commands to attach a child partition
   16894             :  *
   16895             :  * Child partitions are always made by creating them separately
   16896             :  * and then using ATTACH PARTITION, rather than using
   16897             :  * CREATE TABLE ... PARTITION OF.  This is important for preserving
   16898             :  * any possible discrepancy in column layout, to allow assigning the
   16899             :  * correct tablespace if different, and so that it's possible to restore
   16900             :  * a partition without restoring its parent.  (You'll get an error from
   16901             :  * the ATTACH PARTITION command, but that can be ignored, or skipped
   16902             :  * using "pg_restore -L" if you prefer.)  The last point motivates
   16903             :  * treating ATTACH PARTITION as a completely separate ArchiveEntry
   16904             :  * rather than emitting it within the child partition's ArchiveEntry.
   16905             :  */
   16906             : static void
   16907        2496 : dumpTableAttach(Archive *fout, const TableAttachInfo *attachinfo)
   16908             : {
   16909        2496 :     DumpOptions *dopt = fout->dopt;
   16910             :     PQExpBuffer q;
   16911             :     PGresult   *res;
   16912             :     char       *partbound;
   16913             : 
   16914             :     /* Do nothing if not dumping schema */
   16915        2496 :     if (!dopt->dumpSchema)
   16916          42 :         return;
   16917             : 
   16918        2454 :     q = createPQExpBuffer();
   16919             : 
   16920        2454 :     if (!fout->is_prepared[PREPQUERY_DUMPTABLEATTACH])
   16921             :     {
   16922             :         /* Set up query for partbound details */
   16923          88 :         appendPQExpBufferStr(q,
   16924             :                              "PREPARE dumpTableAttach(pg_catalog.oid) AS\n");
   16925             : 
   16926          88 :         appendPQExpBufferStr(q,
   16927             :                              "SELECT pg_get_expr(c.relpartbound, c.oid) "
   16928             :                              "FROM pg_class c "
   16929             :                              "WHERE c.oid = $1");
   16930             : 
   16931          88 :         ExecuteSqlStatement(fout, q->data);
   16932             : 
   16933          88 :         fout->is_prepared[PREPQUERY_DUMPTABLEATTACH] = true;
   16934             :     }
   16935             : 
   16936        2454 :     printfPQExpBuffer(q,
   16937             :                       "EXECUTE dumpTableAttach('%u')",
   16938        2454 :                       attachinfo->partitionTbl->dobj.catId.oid);
   16939             : 
   16940        2454 :     res = ExecuteSqlQueryForSingleRow(fout, q->data);
   16941        2454 :     partbound = PQgetvalue(res, 0, 0);
   16942             : 
   16943             :     /* Perform ALTER TABLE on the parent */
   16944        2454 :     printfPQExpBuffer(q,
   16945             :                       "ALTER TABLE ONLY %s ",
   16946        2454 :                       fmtQualifiedDumpable(attachinfo->parentTbl));
   16947        2454 :     appendPQExpBuffer(q,
   16948             :                       "ATTACH PARTITION %s %s;\n",
   16949        2454 :                       fmtQualifiedDumpable(attachinfo->partitionTbl),
   16950             :                       partbound);
   16951             : 
   16952             :     /*
   16953             :      * There is no point in creating a drop query as the drop is done by table
   16954             :      * drop.  (If you think to change this, see also _printTocEntry().)
   16955             :      * Although this object doesn't really have ownership as such, set the
   16956             :      * owner field anyway to ensure that the command is run by the correct
   16957             :      * role at restore time.
   16958             :      */
   16959        2454 :     ArchiveEntry(fout, attachinfo->dobj.catId, attachinfo->dobj.dumpId,
   16960        2454 :                  ARCHIVE_OPTS(.tag = attachinfo->dobj.name,
   16961             :                               .namespace = attachinfo->dobj.namespace->dobj.name,
   16962             :                               .owner = attachinfo->partitionTbl->rolname,
   16963             :                               .description = "TABLE ATTACH",
   16964             :                               .section = SECTION_PRE_DATA,
   16965             :                               .createStmt = q->data));
   16966             : 
   16967        2454 :     PQclear(res);
   16968        2454 :     destroyPQExpBuffer(q);
   16969             : }
   16970             : 
   16971             : /*
   16972             :  * dumpAttrDef --- dump an attribute's default-value declaration
   16973             :  */
   16974             : static void
   16975        1520 : dumpAttrDef(Archive *fout, const AttrDefInfo *adinfo)
   16976             : {
   16977        1520 :     DumpOptions *dopt = fout->dopt;
   16978        1520 :     TableInfo  *tbinfo = adinfo->adtable;
   16979        1520 :     int         adnum = adinfo->adnum;
   16980             :     PQExpBuffer q;
   16981             :     PQExpBuffer delq;
   16982             :     char       *qualrelname;
   16983             :     char       *tag;
   16984             :     char       *foreign;
   16985             : 
   16986             :     /* Do nothing if not dumping schema */
   16987        1520 :     if (!dopt->dumpSchema)
   16988           0 :         return;
   16989             : 
   16990             :     /* Skip if not "separate"; it was dumped in the table's definition */
   16991        1520 :     if (!adinfo->separate)
   16992        1232 :         return;
   16993             : 
   16994         288 :     q = createPQExpBuffer();
   16995         288 :     delq = createPQExpBuffer();
   16996             : 
   16997         288 :     qualrelname = pg_strdup(fmtQualifiedDumpable(tbinfo));
   16998             : 
   16999         288 :     foreign = tbinfo->relkind == RELKIND_FOREIGN_TABLE ? "FOREIGN " : "";
   17000             : 
   17001         288 :     appendPQExpBuffer(q,
   17002             :                       "ALTER %sTABLE ONLY %s ALTER COLUMN %s SET DEFAULT %s;\n",
   17003         288 :                       foreign, qualrelname, fmtId(tbinfo->attnames[adnum - 1]),
   17004             :                       adinfo->adef_expr);
   17005             : 
   17006         288 :     appendPQExpBuffer(delq, "ALTER %sTABLE %s ALTER COLUMN %s DROP DEFAULT;\n",
   17007             :                       foreign, qualrelname,
   17008         288 :                       fmtId(tbinfo->attnames[adnum - 1]));
   17009             : 
   17010         288 :     tag = psprintf("%s %s", tbinfo->dobj.name, tbinfo->attnames[adnum - 1]);
   17011             : 
   17012         288 :     if (adinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   17013         288 :         ArchiveEntry(fout, adinfo->dobj.catId, adinfo->dobj.dumpId,
   17014         288 :                      ARCHIVE_OPTS(.tag = tag,
   17015             :                                   .namespace = tbinfo->dobj.namespace->dobj.name,
   17016             :                                   .owner = tbinfo->rolname,
   17017             :                                   .description = "DEFAULT",
   17018             :                                   .section = SECTION_PRE_DATA,
   17019             :                                   .createStmt = q->data,
   17020             :                                   .dropStmt = delq->data));
   17021             : 
   17022         288 :     free(tag);
   17023         288 :     destroyPQExpBuffer(q);
   17024         288 :     destroyPQExpBuffer(delq);
   17025         288 :     free(qualrelname);
   17026             : }
   17027             : 
   17028             : /*
   17029             :  * getAttrName: extract the correct name for an attribute
   17030             :  *
   17031             :  * The array tblInfo->attnames[] only provides names of user attributes;
   17032             :  * if a system attribute number is supplied, we have to fake it.
   17033             :  * We also do a little bit of bounds checking for safety's sake.
   17034             :  */
   17035             : static const char *
   17036        3916 : getAttrName(int attrnum, const TableInfo *tblInfo)
   17037             : {
   17038        3916 :     if (attrnum > 0 && attrnum <= tblInfo->numatts)
   17039        3916 :         return tblInfo->attnames[attrnum - 1];
   17040           0 :     switch (attrnum)
   17041             :     {
   17042           0 :         case SelfItemPointerAttributeNumber:
   17043           0 :             return "ctid";
   17044           0 :         case MinTransactionIdAttributeNumber:
   17045           0 :             return "xmin";
   17046           0 :         case MinCommandIdAttributeNumber:
   17047           0 :             return "cmin";
   17048           0 :         case MaxTransactionIdAttributeNumber:
   17049           0 :             return "xmax";
   17050           0 :         case MaxCommandIdAttributeNumber:
   17051           0 :             return "cmax";
   17052           0 :         case TableOidAttributeNumber:
   17053           0 :             return "tableoid";
   17054             :     }
   17055           0 :     pg_fatal("invalid column number %d for table \"%s\"",
   17056             :              attrnum, tblInfo->dobj.name);
   17057             :     return NULL;                /* keep compiler quiet */
   17058             : }
   17059             : 
   17060             : /*
   17061             :  * dumpIndex
   17062             :  *    write out to fout a user-defined index
   17063             :  */
   17064             : static void
   17065        4740 : dumpIndex(Archive *fout, const IndxInfo *indxinfo)
   17066             : {
   17067        4740 :     DumpOptions *dopt = fout->dopt;
   17068        4740 :     TableInfo  *tbinfo = indxinfo->indextable;
   17069        4740 :     bool        is_constraint = (indxinfo->indexconstraint != 0);
   17070             :     PQExpBuffer q;
   17071             :     PQExpBuffer delq;
   17072             :     char       *qindxname;
   17073             :     char       *qqindxname;
   17074             : 
   17075             :     /* Do nothing if not dumping schema */
   17076        4740 :     if (!dopt->dumpSchema)
   17077         114 :         return;
   17078             : 
   17079        4626 :     q = createPQExpBuffer();
   17080        4626 :     delq = createPQExpBuffer();
   17081             : 
   17082        4626 :     qindxname = pg_strdup(fmtId(indxinfo->dobj.name));
   17083        4626 :     qqindxname = pg_strdup(fmtQualifiedDumpable(indxinfo));
   17084             : 
   17085             :     /*
   17086             :      * If there's an associated constraint, don't dump the index per se, but
   17087             :      * do dump any comment for it.  (This is safe because dependency ordering
   17088             :      * will have ensured the constraint is emitted first.)  Note that the
   17089             :      * emitted comment has to be shown as depending on the constraint, not the
   17090             :      * index, in such cases.
   17091             :      */
   17092        4626 :     if (!is_constraint)
   17093             :     {
   17094        1958 :         char       *indstatcols = indxinfo->indstatcols;
   17095        1958 :         char       *indstatvals = indxinfo->indstatvals;
   17096        1958 :         char      **indstatcolsarray = NULL;
   17097        1958 :         char      **indstatvalsarray = NULL;
   17098        1958 :         int         nstatcols = 0;
   17099        1958 :         int         nstatvals = 0;
   17100             : 
   17101        1958 :         if (dopt->binary_upgrade)
   17102         298 :             binary_upgrade_set_pg_class_oids(fout, q,
   17103             :                                              indxinfo->dobj.catId.oid);
   17104             : 
   17105             :         /* Plain secondary index */
   17106        1958 :         appendPQExpBuffer(q, "%s;\n", indxinfo->indexdef);
   17107             : 
   17108             :         /*
   17109             :          * Append ALTER TABLE commands as needed to set properties that we
   17110             :          * only have ALTER TABLE syntax for.  Keep this in sync with the
   17111             :          * similar code in dumpConstraint!
   17112             :          */
   17113             : 
   17114             :         /* If the index is clustered, we need to record that. */
   17115        1958 :         if (indxinfo->indisclustered)
   17116             :         {
   17117           0 :             appendPQExpBuffer(q, "\nALTER TABLE %s CLUSTER",
   17118           0 :                               fmtQualifiedDumpable(tbinfo));
   17119             :             /* index name is not qualified in this syntax */
   17120           0 :             appendPQExpBuffer(q, " ON %s;\n",
   17121             :                               qindxname);
   17122             :         }
   17123             : 
   17124             :         /*
   17125             :          * If the index has any statistics on some of its columns, generate
   17126             :          * the associated ALTER INDEX queries.
   17127             :          */
   17128        1958 :         if (strlen(indstatcols) != 0 || strlen(indstatvals) != 0)
   17129             :         {
   17130             :             int         j;
   17131             : 
   17132          66 :             if (!parsePGArray(indstatcols, &indstatcolsarray, &nstatcols))
   17133           0 :                 pg_fatal("could not parse index statistic columns");
   17134          66 :             if (!parsePGArray(indstatvals, &indstatvalsarray, &nstatvals))
   17135           0 :                 pg_fatal("could not parse index statistic values");
   17136          66 :             if (nstatcols != nstatvals)
   17137           0 :                 pg_fatal("mismatched number of columns and values for index statistics");
   17138             : 
   17139         198 :             for (j = 0; j < nstatcols; j++)
   17140             :             {
   17141         132 :                 appendPQExpBuffer(q, "ALTER INDEX %s ", qqindxname);
   17142             : 
   17143             :                 /*
   17144             :                  * Note that this is a column number, so no quotes should be
   17145             :                  * used.
   17146             :                  */
   17147         132 :                 appendPQExpBuffer(q, "ALTER COLUMN %s ",
   17148         132 :                                   indstatcolsarray[j]);
   17149         132 :                 appendPQExpBuffer(q, "SET STATISTICS %s;\n",
   17150         132 :                                   indstatvalsarray[j]);
   17151             :             }
   17152             :         }
   17153             : 
   17154             :         /* Indexes can depend on extensions */
   17155        1958 :         append_depends_on_extension(fout, q, &indxinfo->dobj,
   17156             :                                     "pg_catalog.pg_class",
   17157             :                                     "INDEX", qqindxname);
   17158             : 
   17159             :         /* If the index defines identity, we need to record that. */
   17160        1958 :         if (indxinfo->indisreplident)
   17161             :         {
   17162           0 :             appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY USING",
   17163           0 :                               fmtQualifiedDumpable(tbinfo));
   17164             :             /* index name is not qualified in this syntax */
   17165           0 :             appendPQExpBuffer(q, " INDEX %s;\n",
   17166             :                               qindxname);
   17167             :         }
   17168             : 
   17169        1958 :         appendPQExpBuffer(delq, "DROP INDEX %s;\n", qqindxname);
   17170             : 
   17171        1958 :         if (indxinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   17172        1958 :             ArchiveEntry(fout, indxinfo->dobj.catId, indxinfo->dobj.dumpId,
   17173        1958 :                          ARCHIVE_OPTS(.tag = indxinfo->dobj.name,
   17174             :                                       .namespace = tbinfo->dobj.namespace->dobj.name,
   17175             :                                       .tablespace = indxinfo->tablespace,
   17176             :                                       .owner = tbinfo->rolname,
   17177             :                                       .description = "INDEX",
   17178             :                                       .section = SECTION_POST_DATA,
   17179             :                                       .createStmt = q->data,
   17180             :                                       .dropStmt = delq->data));
   17181             : 
   17182        1958 :         free(indstatcolsarray);
   17183        1958 :         free(indstatvalsarray);
   17184             :     }
   17185             : 
   17186             :     /* Dump Index Comments */
   17187        4626 :     if (indxinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   17188          30 :         dumpComment(fout, "INDEX", qindxname,
   17189          30 :                     tbinfo->dobj.namespace->dobj.name,
   17190             :                     tbinfo->rolname,
   17191             :                     indxinfo->dobj.catId, 0,
   17192             :                     is_constraint ? indxinfo->indexconstraint :
   17193             :                     indxinfo->dobj.dumpId);
   17194             : 
   17195        4626 :     destroyPQExpBuffer(q);
   17196        4626 :     destroyPQExpBuffer(delq);
   17197        4626 :     free(qindxname);
   17198        4626 :     free(qqindxname);
   17199             : }
   17200             : 
   17201             : /*
   17202             :  * dumpIndexAttach
   17203             :  *    write out to fout a partitioned-index attachment clause
   17204             :  */
   17205             : static void
   17206        1096 : dumpIndexAttach(Archive *fout, const IndexAttachInfo *attachinfo)
   17207             : {
   17208             :     /* Do nothing if not dumping schema */
   17209        1096 :     if (!fout->dopt->dumpSchema)
   17210          48 :         return;
   17211             : 
   17212        1048 :     if (attachinfo->partitionIdx->dobj.dump & DUMP_COMPONENT_DEFINITION)
   17213             :     {
   17214        1048 :         PQExpBuffer q = createPQExpBuffer();
   17215             : 
   17216        1048 :         appendPQExpBuffer(q, "ALTER INDEX %s ",
   17217        1048 :                           fmtQualifiedDumpable(attachinfo->parentIdx));
   17218        1048 :         appendPQExpBuffer(q, "ATTACH PARTITION %s;\n",
   17219        1048 :                           fmtQualifiedDumpable(attachinfo->partitionIdx));
   17220             : 
   17221             :         /*
   17222             :          * There is no point in creating a drop query as the drop is done by
   17223             :          * index drop.  (If you think to change this, see also
   17224             :          * _printTocEntry().)  Although this object doesn't really have
   17225             :          * ownership as such, set the owner field anyway to ensure that the
   17226             :          * command is run by the correct role at restore time.
   17227             :          */
   17228        1048 :         ArchiveEntry(fout, attachinfo->dobj.catId, attachinfo->dobj.dumpId,
   17229        1048 :                      ARCHIVE_OPTS(.tag = attachinfo->dobj.name,
   17230             :                                   .namespace = attachinfo->dobj.namespace->dobj.name,
   17231             :                                   .owner = attachinfo->parentIdx->indextable->rolname,
   17232             :                                   .description = "INDEX ATTACH",
   17233             :                                   .section = SECTION_POST_DATA,
   17234             :                                   .createStmt = q->data));
   17235             : 
   17236        1048 :         destroyPQExpBuffer(q);
   17237             :     }
   17238             : }
   17239             : 
   17240             : /*
   17241             :  * dumpStatisticsExt
   17242             :  *    write out to fout an extended statistics object
   17243             :  */
   17244             : static void
   17245         254 : dumpStatisticsExt(Archive *fout, const StatsExtInfo *statsextinfo)
   17246             : {
   17247         254 :     DumpOptions *dopt = fout->dopt;
   17248             :     PQExpBuffer q;
   17249             :     PQExpBuffer delq;
   17250             :     PQExpBuffer query;
   17251             :     char       *qstatsextname;
   17252             :     PGresult   *res;
   17253             :     char       *stxdef;
   17254             : 
   17255             :     /* Do nothing if not dumping schema */
   17256         254 :     if (!dopt->dumpSchema)
   17257          18 :         return;
   17258             : 
   17259         236 :     q = createPQExpBuffer();
   17260         236 :     delq = createPQExpBuffer();
   17261         236 :     query = createPQExpBuffer();
   17262             : 
   17263         236 :     qstatsextname = pg_strdup(fmtId(statsextinfo->dobj.name));
   17264             : 
   17265         236 :     appendPQExpBuffer(query, "SELECT "
   17266             :                       "pg_catalog.pg_get_statisticsobjdef('%u'::pg_catalog.oid)",
   17267             :                       statsextinfo->dobj.catId.oid);
   17268             : 
   17269         236 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   17270             : 
   17271         236 :     stxdef = PQgetvalue(res, 0, 0);
   17272             : 
   17273             :     /* Result of pg_get_statisticsobjdef is complete except for semicolon */
   17274         236 :     appendPQExpBuffer(q, "%s;\n", stxdef);
   17275             : 
   17276             :     /*
   17277             :      * We only issue an ALTER STATISTICS statement if the stxstattarget entry
   17278             :      * for this statistics object is not the default value.
   17279             :      */
   17280         236 :     if (statsextinfo->stattarget >= 0)
   17281             :     {
   17282          66 :         appendPQExpBuffer(q, "ALTER STATISTICS %s ",
   17283          66 :                           fmtQualifiedDumpable(statsextinfo));
   17284          66 :         appendPQExpBuffer(q, "SET STATISTICS %d;\n",
   17285             :                           statsextinfo->stattarget);
   17286             :     }
   17287             : 
   17288         236 :     appendPQExpBuffer(delq, "DROP STATISTICS %s;\n",
   17289         236 :                       fmtQualifiedDumpable(statsextinfo));
   17290             : 
   17291         236 :     if (statsextinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   17292         236 :         ArchiveEntry(fout, statsextinfo->dobj.catId,
   17293             :                      statsextinfo->dobj.dumpId,
   17294         236 :                      ARCHIVE_OPTS(.tag = statsextinfo->dobj.name,
   17295             :                                   .namespace = statsextinfo->dobj.namespace->dobj.name,
   17296             :                                   .owner = statsextinfo->rolname,
   17297             :                                   .description = "STATISTICS",
   17298             :                                   .section = SECTION_POST_DATA,
   17299             :                                   .createStmt = q->data,
   17300             :                                   .dropStmt = delq->data));
   17301             : 
   17302             :     /* Dump Statistics Comments */
   17303         236 :     if (statsextinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   17304           0 :         dumpComment(fout, "STATISTICS", qstatsextname,
   17305           0 :                     statsextinfo->dobj.namespace->dobj.name,
   17306             :                     statsextinfo->rolname,
   17307             :                     statsextinfo->dobj.catId, 0,
   17308             :                     statsextinfo->dobj.dumpId);
   17309             : 
   17310         236 :     PQclear(res);
   17311         236 :     destroyPQExpBuffer(q);
   17312         236 :     destroyPQExpBuffer(delq);
   17313         236 :     destroyPQExpBuffer(query);
   17314         236 :     free(qstatsextname);
   17315             : }
   17316             : 
   17317             : /*
   17318             :  * dumpConstraint
   17319             :  *    write out to fout a user-defined constraint
   17320             :  */
   17321             : static void
   17322        4396 : dumpConstraint(Archive *fout, const ConstraintInfo *coninfo)
   17323             : {
   17324        4396 :     DumpOptions *dopt = fout->dopt;
   17325        4396 :     TableInfo  *tbinfo = coninfo->contable;
   17326             :     PQExpBuffer q;
   17327             :     PQExpBuffer delq;
   17328        4396 :     char       *tag = NULL;
   17329             :     char       *foreign;
   17330             : 
   17331             :     /* Do nothing if not dumping schema */
   17332        4396 :     if (!dopt->dumpSchema)
   17333          94 :         return;
   17334             : 
   17335        4302 :     q = createPQExpBuffer();
   17336        4302 :     delq = createPQExpBuffer();
   17337             : 
   17338        8428 :     foreign = tbinfo &&
   17339        4302 :         tbinfo->relkind == RELKIND_FOREIGN_TABLE ? "FOREIGN " : "";
   17340             : 
   17341        4302 :     if (coninfo->contype == 'p' ||
   17342        2094 :         coninfo->contype == 'u' ||
   17343        1654 :         coninfo->contype == 'x')
   17344        2668 :     {
   17345             :         /* Index-related constraint */
   17346             :         IndxInfo   *indxinfo;
   17347             :         int         k;
   17348             : 
   17349        2668 :         indxinfo = (IndxInfo *) findObjectByDumpId(coninfo->conindex);
   17350             : 
   17351        2668 :         if (indxinfo == NULL)
   17352           0 :             pg_fatal("missing index for constraint \"%s\"",
   17353             :                      coninfo->dobj.name);
   17354             : 
   17355        2668 :         if (dopt->binary_upgrade)
   17356         252 :             binary_upgrade_set_pg_class_oids(fout, q,
   17357             :                                              indxinfo->dobj.catId.oid);
   17358             : 
   17359        2668 :         appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s\n", foreign,
   17360        2668 :                           fmtQualifiedDumpable(tbinfo));
   17361        2668 :         appendPQExpBuffer(q, "    ADD CONSTRAINT %s ",
   17362        2668 :                           fmtId(coninfo->dobj.name));
   17363             : 
   17364        2668 :         if (coninfo->condef)
   17365             :         {
   17366             :             /* pg_get_constraintdef should have provided everything */
   17367          20 :             appendPQExpBuffer(q, "%s;\n", coninfo->condef);
   17368             :         }
   17369             :         else
   17370             :         {
   17371        2648 :             appendPQExpBufferStr(q,
   17372        2648 :                                  coninfo->contype == 'p' ? "PRIMARY KEY" : "UNIQUE");
   17373             : 
   17374             :             /*
   17375             :              * PRIMARY KEY constraints should not be using NULLS NOT DISTINCT
   17376             :              * indexes. Being able to create this was fixed, but we need to
   17377             :              * make the index distinct in order to be able to restore the
   17378             :              * dump.
   17379             :              */
   17380        2648 :             if (indxinfo->indnullsnotdistinct && coninfo->contype != 'p')
   17381           0 :                 appendPQExpBufferStr(q, " NULLS NOT DISTINCT");
   17382        2648 :             appendPQExpBufferStr(q, " (");
   17383        6484 :             for (k = 0; k < indxinfo->indnkeyattrs; k++)
   17384             :             {
   17385        3836 :                 int         indkey = (int) indxinfo->indkeys[k];
   17386             :                 const char *attname;
   17387             : 
   17388        3836 :                 if (indkey == InvalidAttrNumber)
   17389           0 :                     break;
   17390        3836 :                 attname = getAttrName(indkey, tbinfo);
   17391             : 
   17392        3836 :                 appendPQExpBuffer(q, "%s%s",
   17393             :                                   (k == 0) ? "" : ", ",
   17394             :                                   fmtId(attname));
   17395             :             }
   17396        2648 :             if (coninfo->conperiod)
   17397         212 :                 appendPQExpBufferStr(q, " WITHOUT OVERLAPS");
   17398             : 
   17399        2648 :             if (indxinfo->indnkeyattrs < indxinfo->indnattrs)
   17400          40 :                 appendPQExpBufferStr(q, ") INCLUDE (");
   17401             : 
   17402        2728 :             for (k = indxinfo->indnkeyattrs; k < indxinfo->indnattrs; k++)
   17403             :             {
   17404          80 :                 int         indkey = (int) indxinfo->indkeys[k];
   17405             :                 const char *attname;
   17406             : 
   17407          80 :                 if (indkey == InvalidAttrNumber)
   17408           0 :                     break;
   17409          80 :                 attname = getAttrName(indkey, tbinfo);
   17410             : 
   17411         160 :                 appendPQExpBuffer(q, "%s%s",
   17412          80 :                                   (k == indxinfo->indnkeyattrs) ? "" : ", ",
   17413             :                                   fmtId(attname));
   17414             :             }
   17415             : 
   17416        2648 :             appendPQExpBufferChar(q, ')');
   17417             : 
   17418        2648 :             if (nonemptyReloptions(indxinfo->indreloptions))
   17419             :             {
   17420           0 :                 appendPQExpBufferStr(q, " WITH (");
   17421           0 :                 appendReloptionsArrayAH(q, indxinfo->indreloptions, "", fout);
   17422           0 :                 appendPQExpBufferChar(q, ')');
   17423             :             }
   17424             : 
   17425        2648 :             if (coninfo->condeferrable)
   17426             :             {
   17427          50 :                 appendPQExpBufferStr(q, " DEFERRABLE");
   17428          50 :                 if (coninfo->condeferred)
   17429          30 :                     appendPQExpBufferStr(q, " INITIALLY DEFERRED");
   17430             :             }
   17431             : 
   17432        2648 :             appendPQExpBufferStr(q, ";\n");
   17433             :         }
   17434             : 
   17435             :         /*
   17436             :          * Append ALTER TABLE commands as needed to set properties that we
   17437             :          * only have ALTER TABLE syntax for.  Keep this in sync with the
   17438             :          * similar code in dumpIndex!
   17439             :          */
   17440             : 
   17441             :         /* If the index is clustered, we need to record that. */
   17442        2668 :         if (indxinfo->indisclustered)
   17443             :         {
   17444          66 :             appendPQExpBuffer(q, "\nALTER TABLE %s CLUSTER",
   17445          66 :                               fmtQualifiedDumpable(tbinfo));
   17446             :             /* index name is not qualified in this syntax */
   17447          66 :             appendPQExpBuffer(q, " ON %s;\n",
   17448          66 :                               fmtId(indxinfo->dobj.name));
   17449             :         }
   17450             : 
   17451             :         /* If the index defines identity, we need to record that. */
   17452        2668 :         if (indxinfo->indisreplident)
   17453             :         {
   17454           0 :             appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY USING",
   17455           0 :                               fmtQualifiedDumpable(tbinfo));
   17456             :             /* index name is not qualified in this syntax */
   17457           0 :             appendPQExpBuffer(q, " INDEX %s;\n",
   17458           0 :                               fmtId(indxinfo->dobj.name));
   17459             :         }
   17460             : 
   17461             :         /* Indexes can depend on extensions */
   17462        2668 :         append_depends_on_extension(fout, q, &indxinfo->dobj,
   17463             :                                     "pg_catalog.pg_class", "INDEX",
   17464        2668 :                                     fmtQualifiedDumpable(indxinfo));
   17465             : 
   17466        2668 :         appendPQExpBuffer(delq, "ALTER %sTABLE ONLY %s ", foreign,
   17467        2668 :                           fmtQualifiedDumpable(tbinfo));
   17468        2668 :         appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
   17469        2668 :                           fmtId(coninfo->dobj.name));
   17470             : 
   17471        2668 :         tag = psprintf("%s %s", tbinfo->dobj.name, coninfo->dobj.name);
   17472             : 
   17473        2668 :         if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   17474        2668 :             ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
   17475        2668 :                          ARCHIVE_OPTS(.tag = tag,
   17476             :                                       .namespace = tbinfo->dobj.namespace->dobj.name,
   17477             :                                       .tablespace = indxinfo->tablespace,
   17478             :                                       .owner = tbinfo->rolname,
   17479             :                                       .description = "CONSTRAINT",
   17480             :                                       .section = SECTION_POST_DATA,
   17481             :                                       .createStmt = q->data,
   17482             :                                       .dropStmt = delq->data));
   17483             :     }
   17484        1634 :     else if (coninfo->contype == 'f')
   17485             :     {
   17486             :         char       *only;
   17487             : 
   17488             :         /*
   17489             :          * Foreign keys on partitioned tables are always declared as
   17490             :          * inheriting to partitions; for all other cases, emit them as
   17491             :          * applying ONLY directly to the named table, because that's how they
   17492             :          * work for regular inherited tables.
   17493             :          */
   17494         332 :         only = tbinfo->relkind == RELKIND_PARTITIONED_TABLE ? "" : "ONLY ";
   17495             : 
   17496             :         /*
   17497             :          * XXX Potentially wrap in a 'SET CONSTRAINTS OFF' block so that the
   17498             :          * current table data is not processed
   17499             :          */
   17500         332 :         appendPQExpBuffer(q, "ALTER %sTABLE %s%s\n", foreign,
   17501         332 :                           only, fmtQualifiedDumpable(tbinfo));
   17502         332 :         appendPQExpBuffer(q, "    ADD CONSTRAINT %s %s;\n",
   17503         332 :                           fmtId(coninfo->dobj.name),
   17504             :                           coninfo->condef);
   17505             : 
   17506         332 :         appendPQExpBuffer(delq, "ALTER %sTABLE %s%s ", foreign,
   17507         332 :                           only, fmtQualifiedDumpable(tbinfo));
   17508         332 :         appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
   17509         332 :                           fmtId(coninfo->dobj.name));
   17510             : 
   17511         332 :         tag = psprintf("%s %s", tbinfo->dobj.name, coninfo->dobj.name);
   17512             : 
   17513         332 :         if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   17514         332 :             ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
   17515         332 :                          ARCHIVE_OPTS(.tag = tag,
   17516             :                                       .namespace = tbinfo->dobj.namespace->dobj.name,
   17517             :                                       .owner = tbinfo->rolname,
   17518             :                                       .description = "FK CONSTRAINT",
   17519             :                                       .section = SECTION_POST_DATA,
   17520             :                                       .createStmt = q->data,
   17521             :                                       .dropStmt = delq->data));
   17522             :     }
   17523        1302 :     else if (coninfo->contype == 'c' && tbinfo)
   17524             :     {
   17525             :         /* CHECK constraint on a table */
   17526             : 
   17527             :         /* Ignore if not to be dumped separately, or if it was inherited */
   17528        1126 :         if (coninfo->separate && coninfo->conislocal)
   17529             :         {
   17530             :             /* not ONLY since we want it to propagate to children */
   17531          80 :             appendPQExpBuffer(q, "ALTER %sTABLE %s\n", foreign,
   17532          80 :                               fmtQualifiedDumpable(tbinfo));
   17533          80 :             appendPQExpBuffer(q, "    ADD CONSTRAINT %s %s;\n",
   17534          80 :                               fmtId(coninfo->dobj.name),
   17535             :                               coninfo->condef);
   17536             : 
   17537          80 :             appendPQExpBuffer(delq, "ALTER %sTABLE %s ", foreign,
   17538          80 :                               fmtQualifiedDumpable(tbinfo));
   17539          80 :             appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
   17540          80 :                               fmtId(coninfo->dobj.name));
   17541             : 
   17542          80 :             tag = psprintf("%s %s", tbinfo->dobj.name, coninfo->dobj.name);
   17543             : 
   17544          80 :             if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   17545          80 :                 ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
   17546          80 :                              ARCHIVE_OPTS(.tag = tag,
   17547             :                                           .namespace = tbinfo->dobj.namespace->dobj.name,
   17548             :                                           .owner = tbinfo->rolname,
   17549             :                                           .description = "CHECK CONSTRAINT",
   17550             :                                           .section = SECTION_POST_DATA,
   17551             :                                           .createStmt = q->data,
   17552             :                                           .dropStmt = delq->data));
   17553             :         }
   17554             :     }
   17555         176 :     else if (coninfo->contype == 'c' && tbinfo == NULL)
   17556         176 :     {
   17557             :         /* CHECK constraint on a domain */
   17558         176 :         TypeInfo   *tyinfo = coninfo->condomain;
   17559             : 
   17560             :         /* Ignore if not to be dumped separately */
   17561         176 :         if (coninfo->separate)
   17562             :         {
   17563           0 :             appendPQExpBuffer(q, "ALTER DOMAIN %s\n",
   17564           0 :                               fmtQualifiedDumpable(tyinfo));
   17565           0 :             appendPQExpBuffer(q, "    ADD CONSTRAINT %s %s;\n",
   17566           0 :                               fmtId(coninfo->dobj.name),
   17567             :                               coninfo->condef);
   17568             : 
   17569           0 :             appendPQExpBuffer(delq, "ALTER DOMAIN %s ",
   17570           0 :                               fmtQualifiedDumpable(tyinfo));
   17571           0 :             appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
   17572           0 :                               fmtId(coninfo->dobj.name));
   17573             : 
   17574           0 :             tag = psprintf("%s %s", tyinfo->dobj.name, coninfo->dobj.name);
   17575             : 
   17576           0 :             if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   17577           0 :                 ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
   17578           0 :                              ARCHIVE_OPTS(.tag = tag,
   17579             :                                           .namespace = tyinfo->dobj.namespace->dobj.name,
   17580             :                                           .owner = tyinfo->rolname,
   17581             :                                           .description = "CHECK CONSTRAINT",
   17582             :                                           .section = SECTION_POST_DATA,
   17583             :                                           .createStmt = q->data,
   17584             :                                           .dropStmt = delq->data));
   17585             :         }
   17586             :     }
   17587             :     else
   17588             :     {
   17589           0 :         pg_fatal("unrecognized constraint type: %c",
   17590             :                  coninfo->contype);
   17591             :     }
   17592             : 
   17593             :     /* Dump Constraint Comments --- only works for table constraints */
   17594        4302 :     if (tbinfo && coninfo->separate &&
   17595        3130 :         coninfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   17596          20 :         dumpTableConstraintComment(fout, coninfo);
   17597             : 
   17598        4302 :     free(tag);
   17599        4302 :     destroyPQExpBuffer(q);
   17600        4302 :     destroyPQExpBuffer(delq);
   17601             : }
   17602             : 
   17603             : /*
   17604             :  * dumpTableConstraintComment --- dump a constraint's comment if any
   17605             :  *
   17606             :  * This is split out because we need the function in two different places
   17607             :  * depending on whether the constraint is dumped as part of CREATE TABLE
   17608             :  * or as a separate ALTER command.
   17609             :  */
   17610             : static void
   17611          96 : dumpTableConstraintComment(Archive *fout, const ConstraintInfo *coninfo)
   17612             : {
   17613          96 :     TableInfo  *tbinfo = coninfo->contable;
   17614          96 :     PQExpBuffer conprefix = createPQExpBuffer();
   17615             :     char       *qtabname;
   17616             : 
   17617          96 :     qtabname = pg_strdup(fmtId(tbinfo->dobj.name));
   17618             : 
   17619          96 :     appendPQExpBuffer(conprefix, "CONSTRAINT %s ON",
   17620          96 :                       fmtId(coninfo->dobj.name));
   17621             : 
   17622          96 :     if (coninfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   17623          96 :         dumpComment(fout, conprefix->data, qtabname,
   17624          96 :                     tbinfo->dobj.namespace->dobj.name,
   17625             :                     tbinfo->rolname,
   17626             :                     coninfo->dobj.catId, 0,
   17627          96 :                     coninfo->separate ? coninfo->dobj.dumpId : tbinfo->dobj.dumpId);
   17628             : 
   17629          96 :     destroyPQExpBuffer(conprefix);
   17630          96 :     free(qtabname);
   17631          96 : }
   17632             : 
   17633             : static inline SeqType
   17634        1184 : parse_sequence_type(const char *name)
   17635             : {
   17636        2656 :     for (int i = 0; i < lengthof(SeqTypeNames); i++)
   17637             :     {
   17638        2656 :         if (strcmp(SeqTypeNames[i], name) == 0)
   17639        1184 :             return (SeqType) i;
   17640             :     }
   17641             : 
   17642           0 :     pg_fatal("unrecognized sequence type: %s", name);
   17643             :     return (SeqType) 0;         /* keep compiler quiet */
   17644             : }
   17645             : 
   17646             : /*
   17647             :  * bsearch() comparator for SequenceItem
   17648             :  */
   17649             : static int
   17650        5332 : SequenceItemCmp(const void *p1, const void *p2)
   17651             : {
   17652        5332 :     SequenceItem v1 = *((const SequenceItem *) p1);
   17653        5332 :     SequenceItem v2 = *((const SequenceItem *) p2);
   17654             : 
   17655        5332 :     return pg_cmp_u32(v1.oid, v2.oid);
   17656             : }
   17657             : 
   17658             : /*
   17659             :  * collectSequences
   17660             :  *
   17661             :  * Construct a table of sequence information.  This table is sorted by OID for
   17662             :  * speed in lookup.
   17663             :  */
   17664             : static void
   17665         308 : collectSequences(Archive *fout)
   17666             : {
   17667             :     PGresult   *res;
   17668             :     const char *query;
   17669             : 
   17670             :     /*
   17671             :      * Before Postgres 10, sequence metadata is in the sequence itself.  With
   17672             :      * some extra effort, we might be able to use the sorted table for those
   17673             :      * versions, but for now it seems unlikely to be worth it.
   17674             :      *
   17675             :      * Since version 18, we can gather the sequence data in this query with
   17676             :      * pg_get_sequence_data(), but we only do so for non-schema-only dumps.
   17677             :      */
   17678         308 :     if (fout->remoteVersion < 100000)
   17679           0 :         return;
   17680         308 :     else if (fout->remoteVersion < 180000 ||
   17681         308 :              (!fout->dopt->dumpData && !fout->dopt->sequence_data))
   17682           4 :         query = "SELECT seqrelid, format_type(seqtypid, NULL), "
   17683             :             "seqstart, seqincrement, "
   17684             :             "seqmax, seqmin, "
   17685             :             "seqcache, seqcycle, "
   17686             :             "NULL, 'f' "
   17687             :             "FROM pg_catalog.pg_sequence "
   17688             :             "ORDER BY seqrelid";
   17689             :     else
   17690         304 :         query = "SELECT seqrelid, format_type(seqtypid, NULL), "
   17691             :             "seqstart, seqincrement, "
   17692             :             "seqmax, seqmin, "
   17693             :             "seqcache, seqcycle, "
   17694             :             "last_value, is_called "
   17695             :             "FROM pg_catalog.pg_sequence, "
   17696             :             "pg_get_sequence_data(seqrelid) "
   17697             :             "ORDER BY seqrelid;";
   17698             : 
   17699         308 :     res = ExecuteSqlQuery(fout, query, PGRES_TUPLES_OK);
   17700             : 
   17701         308 :     nsequences = PQntuples(res);
   17702         308 :     sequences = (SequenceItem *) pg_malloc(nsequences * sizeof(SequenceItem));
   17703             : 
   17704        1492 :     for (int i = 0; i < nsequences; i++)
   17705             :     {
   17706        1184 :         sequences[i].oid = atooid(PQgetvalue(res, i, 0));
   17707        1184 :         sequences[i].seqtype = parse_sequence_type(PQgetvalue(res, i, 1));
   17708        1184 :         sequences[i].startv = strtoi64(PQgetvalue(res, i, 2), NULL, 10);
   17709        1184 :         sequences[i].incby = strtoi64(PQgetvalue(res, i, 3), NULL, 10);
   17710        1184 :         sequences[i].maxv = strtoi64(PQgetvalue(res, i, 4), NULL, 10);
   17711        1184 :         sequences[i].minv = strtoi64(PQgetvalue(res, i, 5), NULL, 10);
   17712        1184 :         sequences[i].cache = strtoi64(PQgetvalue(res, i, 6), NULL, 10);
   17713        1184 :         sequences[i].cycled = (strcmp(PQgetvalue(res, i, 7), "t") == 0);
   17714        1184 :         sequences[i].last_value = strtoi64(PQgetvalue(res, i, 8), NULL, 10);
   17715        1184 :         sequences[i].is_called = (strcmp(PQgetvalue(res, i, 9), "t") == 0);
   17716             :     }
   17717             : 
   17718         308 :     PQclear(res);
   17719             : }
   17720             : 
   17721             : /*
   17722             :  * dumpSequence
   17723             :  *    write the declaration (not data) of one user-defined sequence
   17724             :  */
   17725             : static void
   17726         696 : dumpSequence(Archive *fout, const TableInfo *tbinfo)
   17727             : {
   17728         696 :     DumpOptions *dopt = fout->dopt;
   17729             :     SequenceItem *seq;
   17730             :     bool        is_ascending;
   17731             :     int64       default_minv,
   17732             :                 default_maxv;
   17733         696 :     PQExpBuffer query = createPQExpBuffer();
   17734         696 :     PQExpBuffer delqry = createPQExpBuffer();
   17735             :     char       *qseqname;
   17736         696 :     TableInfo  *owning_tab = NULL;
   17737             : 
   17738         696 :     qseqname = pg_strdup(fmtId(tbinfo->dobj.name));
   17739             : 
   17740             :     /*
   17741             :      * For versions >= 10, the sequence information is gathered in a sorted
   17742             :      * table before any calls to dumpSequence().  See collectSequences() for
   17743             :      * more information.
   17744             :      */
   17745         696 :     if (fout->remoteVersion >= 100000)
   17746             :     {
   17747         696 :         SequenceItem key = {0};
   17748             : 
   17749             :         Assert(sequences);
   17750             : 
   17751         696 :         key.oid = tbinfo->dobj.catId.oid;
   17752         696 :         seq = bsearch(&key, sequences, nsequences,
   17753             :                       sizeof(SequenceItem), SequenceItemCmp);
   17754             :     }
   17755             :     else
   17756             :     {
   17757             :         PGresult   *res;
   17758             : 
   17759             :         /*
   17760             :          * Before PostgreSQL 10, sequence metadata is in the sequence itself.
   17761             :          *
   17762             :          * Note: it might seem that 'bigint' potentially needs to be
   17763             :          * schema-qualified, but actually that's a keyword.
   17764             :          */
   17765           0 :         appendPQExpBuffer(query,
   17766             :                           "SELECT 'bigint' AS sequence_type, "
   17767             :                           "start_value, increment_by, max_value, min_value, "
   17768             :                           "cache_value, is_cycled FROM %s",
   17769           0 :                           fmtQualifiedDumpable(tbinfo));
   17770             : 
   17771           0 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   17772             : 
   17773           0 :         if (PQntuples(res) != 1)
   17774           0 :             pg_fatal(ngettext("query to get data of sequence \"%s\" returned %d row (expected 1)",
   17775             :                               "query to get data of sequence \"%s\" returned %d rows (expected 1)",
   17776             :                               PQntuples(res)),
   17777             :                      tbinfo->dobj.name, PQntuples(res));
   17778             : 
   17779           0 :         seq = pg_malloc0(sizeof(SequenceItem));
   17780           0 :         seq->seqtype = parse_sequence_type(PQgetvalue(res, 0, 0));
   17781           0 :         seq->startv = strtoi64(PQgetvalue(res, 0, 1), NULL, 10);
   17782           0 :         seq->incby = strtoi64(PQgetvalue(res, 0, 2), NULL, 10);
   17783           0 :         seq->maxv = strtoi64(PQgetvalue(res, 0, 3), NULL, 10);
   17784           0 :         seq->minv = strtoi64(PQgetvalue(res, 0, 4), NULL, 10);
   17785           0 :         seq->cache = strtoi64(PQgetvalue(res, 0, 5), NULL, 10);
   17786           0 :         seq->cycled = (strcmp(PQgetvalue(res, 0, 6), "t") == 0);
   17787             : 
   17788           0 :         PQclear(res);
   17789             :     }
   17790             : 
   17791             :     /* Calculate default limits for a sequence of this type */
   17792         696 :     is_ascending = (seq->incby >= 0);
   17793         696 :     if (seq->seqtype == SEQTYPE_SMALLINT)
   17794             :     {
   17795          50 :         default_minv = is_ascending ? 1 : PG_INT16_MIN;
   17796          50 :         default_maxv = is_ascending ? PG_INT16_MAX : -1;
   17797             :     }
   17798         646 :     else if (seq->seqtype == SEQTYPE_INTEGER)
   17799             :     {
   17800         524 :         default_minv = is_ascending ? 1 : PG_INT32_MIN;
   17801         524 :         default_maxv = is_ascending ? PG_INT32_MAX : -1;
   17802             :     }
   17803         122 :     else if (seq->seqtype == SEQTYPE_BIGINT)
   17804             :     {
   17805         122 :         default_minv = is_ascending ? 1 : PG_INT64_MIN;
   17806         122 :         default_maxv = is_ascending ? PG_INT64_MAX : -1;
   17807             :     }
   17808             :     else
   17809             :     {
   17810           0 :         pg_fatal("unrecognized sequence type: %d", seq->seqtype);
   17811             :         default_minv = default_maxv = 0;    /* keep compiler quiet */
   17812             :     }
   17813             : 
   17814             :     /*
   17815             :      * Identity sequences are not to be dropped separately.
   17816             :      */
   17817         696 :     if (!tbinfo->is_identity_sequence)
   17818             :     {
   17819         410 :         appendPQExpBuffer(delqry, "DROP SEQUENCE %s;\n",
   17820         410 :                           fmtQualifiedDumpable(tbinfo));
   17821             :     }
   17822             : 
   17823         696 :     resetPQExpBuffer(query);
   17824             : 
   17825         696 :     if (dopt->binary_upgrade)
   17826             :     {
   17827         112 :         binary_upgrade_set_pg_class_oids(fout, query,
   17828             :                                          tbinfo->dobj.catId.oid);
   17829             : 
   17830             :         /*
   17831             :          * In older PG versions a sequence will have a pg_type entry, but v14
   17832             :          * and up don't use that, so don't attempt to preserve the type OID.
   17833             :          */
   17834             :     }
   17835             : 
   17836         696 :     if (tbinfo->is_identity_sequence)
   17837             :     {
   17838         286 :         owning_tab = findTableByOid(tbinfo->owning_tab);
   17839             : 
   17840         286 :         appendPQExpBuffer(query,
   17841             :                           "ALTER TABLE %s ",
   17842         286 :                           fmtQualifiedDumpable(owning_tab));
   17843         286 :         appendPQExpBuffer(query,
   17844             :                           "ALTER COLUMN %s ADD GENERATED ",
   17845         286 :                           fmtId(owning_tab->attnames[tbinfo->owning_col - 1]));
   17846         286 :         if (owning_tab->attidentity[tbinfo->owning_col - 1] == ATTRIBUTE_IDENTITY_ALWAYS)
   17847         206 :             appendPQExpBufferStr(query, "ALWAYS");
   17848          80 :         else if (owning_tab->attidentity[tbinfo->owning_col - 1] == ATTRIBUTE_IDENTITY_BY_DEFAULT)
   17849          80 :             appendPQExpBufferStr(query, "BY DEFAULT");
   17850         286 :         appendPQExpBuffer(query, " AS IDENTITY (\n    SEQUENCE NAME %s\n",
   17851         286 :                           fmtQualifiedDumpable(tbinfo));
   17852             : 
   17853             :         /*
   17854             :          * Emit persistence option only if it's different from the owning
   17855             :          * table's.  This avoids using this new syntax unnecessarily.
   17856             :          */
   17857         286 :         if (tbinfo->relpersistence != owning_tab->relpersistence)
   17858          20 :             appendPQExpBuffer(query, "    %s\n",
   17859          20 :                               tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED ?
   17860             :                               "UNLOGGED" : "LOGGED");
   17861             :     }
   17862             :     else
   17863             :     {
   17864         410 :         appendPQExpBuffer(query,
   17865             :                           "CREATE %sSEQUENCE %s\n",
   17866         410 :                           tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED ?
   17867             :                           "UNLOGGED " : "",
   17868         410 :                           fmtQualifiedDumpable(tbinfo));
   17869             : 
   17870         410 :         if (seq->seqtype != SEQTYPE_BIGINT)
   17871         318 :             appendPQExpBuffer(query, "    AS %s\n", SeqTypeNames[seq->seqtype]);
   17872             :     }
   17873             : 
   17874         696 :     appendPQExpBuffer(query, "    START WITH " INT64_FORMAT "\n", seq->startv);
   17875             : 
   17876         696 :     appendPQExpBuffer(query, "    INCREMENT BY " INT64_FORMAT "\n", seq->incby);
   17877             : 
   17878         696 :     if (seq->minv != default_minv)
   17879          30 :         appendPQExpBuffer(query, "    MINVALUE " INT64_FORMAT "\n", seq->minv);
   17880             :     else
   17881         666 :         appendPQExpBufferStr(query, "    NO MINVALUE\n");
   17882             : 
   17883         696 :     if (seq->maxv != default_maxv)
   17884          30 :         appendPQExpBuffer(query, "    MAXVALUE " INT64_FORMAT "\n", seq->maxv);
   17885             :     else
   17886         666 :         appendPQExpBufferStr(query, "    NO MAXVALUE\n");
   17887             : 
   17888         696 :     appendPQExpBuffer(query,
   17889             :                       "    CACHE " INT64_FORMAT "%s",
   17890         696 :                       seq->cache, (seq->cycled ? "\n    CYCLE" : ""));
   17891             : 
   17892         696 :     if (tbinfo->is_identity_sequence)
   17893         286 :         appendPQExpBufferStr(query, "\n);\n");
   17894             :     else
   17895         410 :         appendPQExpBufferStr(query, ";\n");
   17896             : 
   17897             :     /* binary_upgrade:  no need to clear TOAST table oid */
   17898             : 
   17899         696 :     if (dopt->binary_upgrade)
   17900         112 :         binary_upgrade_extension_member(query, &tbinfo->dobj,
   17901             :                                         "SEQUENCE", qseqname,
   17902         112 :                                         tbinfo->dobj.namespace->dobj.name);
   17903             : 
   17904         696 :     if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   17905         696 :         ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
   17906         696 :                      ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
   17907             :                                   .namespace = tbinfo->dobj.namespace->dobj.name,
   17908             :                                   .owner = tbinfo->rolname,
   17909             :                                   .description = "SEQUENCE",
   17910             :                                   .section = SECTION_PRE_DATA,
   17911             :                                   .createStmt = query->data,
   17912             :                                   .dropStmt = delqry->data));
   17913             : 
   17914             :     /*
   17915             :      * If the sequence is owned by a table column, emit the ALTER for it as a
   17916             :      * separate TOC entry immediately following the sequence's own entry. It's
   17917             :      * OK to do this rather than using full sorting logic, because the
   17918             :      * dependency that tells us it's owned will have forced the table to be
   17919             :      * created first.  We can't just include the ALTER in the TOC entry
   17920             :      * because it will fail if we haven't reassigned the sequence owner to
   17921             :      * match the table's owner.
   17922             :      *
   17923             :      * We need not schema-qualify the table reference because both sequence
   17924             :      * and table must be in the same schema.
   17925             :      */
   17926         696 :     if (OidIsValid(tbinfo->owning_tab) && !tbinfo->is_identity_sequence)
   17927             :     {
   17928         228 :         owning_tab = findTableByOid(tbinfo->owning_tab);
   17929             : 
   17930         228 :         if (owning_tab == NULL)
   17931           0 :             pg_fatal("failed sanity check, parent table with OID %u of sequence with OID %u not found",
   17932             :                      tbinfo->owning_tab, tbinfo->dobj.catId.oid);
   17933             : 
   17934         228 :         if (owning_tab->dobj.dump & DUMP_COMPONENT_DEFINITION)
   17935             :         {
   17936         224 :             resetPQExpBuffer(query);
   17937         224 :             appendPQExpBuffer(query, "ALTER SEQUENCE %s",
   17938         224 :                               fmtQualifiedDumpable(tbinfo));
   17939         224 :             appendPQExpBuffer(query, " OWNED BY %s",
   17940         224 :                               fmtQualifiedDumpable(owning_tab));
   17941         224 :             appendPQExpBuffer(query, ".%s;\n",
   17942         224 :                               fmtId(owning_tab->attnames[tbinfo->owning_col - 1]));
   17943             : 
   17944         224 :             if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   17945         224 :                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
   17946         224 :                              ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
   17947             :                                           .namespace = tbinfo->dobj.namespace->dobj.name,
   17948             :                                           .owner = tbinfo->rolname,
   17949             :                                           .description = "SEQUENCE OWNED BY",
   17950             :                                           .section = SECTION_PRE_DATA,
   17951             :                                           .createStmt = query->data,
   17952             :                                           .deps = &(tbinfo->dobj.dumpId),
   17953             :                                           .nDeps = 1));
   17954             :         }
   17955             :     }
   17956             : 
   17957             :     /* Dump Sequence Comments and Security Labels */
   17958         696 :     if (tbinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   17959           0 :         dumpComment(fout, "SEQUENCE", qseqname,
   17960           0 :                     tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
   17961             :                     tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
   17962             : 
   17963         696 :     if (tbinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
   17964           0 :         dumpSecLabel(fout, "SEQUENCE", qseqname,
   17965           0 :                      tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
   17966             :                      tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
   17967             : 
   17968         696 :     if (fout->remoteVersion < 100000)
   17969           0 :         pg_free(seq);
   17970         696 :     destroyPQExpBuffer(query);
   17971         696 :     destroyPQExpBuffer(delqry);
   17972         696 :     free(qseqname);
   17973         696 : }
   17974             : 
   17975             : /*
   17976             :  * dumpSequenceData
   17977             :  *    write the data of one user-defined sequence
   17978             :  */
   17979             : static void
   17980         728 : dumpSequenceData(Archive *fout, const TableDataInfo *tdinfo)
   17981             : {
   17982         728 :     TableInfo  *tbinfo = tdinfo->tdtable;
   17983             :     int64       last;
   17984             :     bool        called;
   17985         728 :     PQExpBuffer query = createPQExpBuffer();
   17986             : 
   17987             :     /*
   17988             :      * For versions >= 18, the sequence information is gathered in the sorted
   17989             :      * array before any calls to dumpSequenceData().  See collectSequences()
   17990             :      * for more information.
   17991             :      *
   17992             :      * For older versions, we have to query the sequence relations
   17993             :      * individually.
   17994             :      */
   17995         728 :     if (fout->remoteVersion < 180000)
   17996             :     {
   17997             :         PGresult   *res;
   17998             : 
   17999           0 :         appendPQExpBuffer(query,
   18000             :                           "SELECT last_value, is_called FROM %s",
   18001           0 :                           fmtQualifiedDumpable(tbinfo));
   18002             : 
   18003           0 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   18004             : 
   18005           0 :         if (PQntuples(res) != 1)
   18006           0 :             pg_fatal(ngettext("query to get data of sequence \"%s\" returned %d row (expected 1)",
   18007             :                               "query to get data of sequence \"%s\" returned %d rows (expected 1)",
   18008             :                               PQntuples(res)),
   18009             :                      tbinfo->dobj.name, PQntuples(res));
   18010             : 
   18011           0 :         last = strtoi64(PQgetvalue(res, 0, 0), NULL, 10);
   18012           0 :         called = (strcmp(PQgetvalue(res, 0, 1), "t") == 0);
   18013             : 
   18014           0 :         PQclear(res);
   18015             :     }
   18016             :     else
   18017             :     {
   18018         728 :         SequenceItem key = {0};
   18019             :         SequenceItem *entry;
   18020             : 
   18021             :         Assert(sequences);
   18022             :         Assert(tbinfo->dobj.catId.oid);
   18023             : 
   18024         728 :         key.oid = tbinfo->dobj.catId.oid;
   18025         728 :         entry = bsearch(&key, sequences, nsequences,
   18026             :                         sizeof(SequenceItem), SequenceItemCmp);
   18027             : 
   18028         728 :         last = entry->last_value;
   18029         728 :         called = entry->is_called;
   18030             :     }
   18031             : 
   18032         728 :     resetPQExpBuffer(query);
   18033         728 :     appendPQExpBufferStr(query, "SELECT pg_catalog.setval(");
   18034         728 :     appendStringLiteralAH(query, fmtQualifiedDumpable(tbinfo), fout);
   18035         728 :     appendPQExpBuffer(query, ", " INT64_FORMAT ", %s);\n",
   18036             :                       last, (called ? "true" : "false"));
   18037             : 
   18038         728 :     if (tdinfo->dobj.dump & DUMP_COMPONENT_DATA)
   18039         728 :         ArchiveEntry(fout, nilCatalogId, createDumpId(),
   18040         728 :                      ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
   18041             :                                   .namespace = tbinfo->dobj.namespace->dobj.name,
   18042             :                                   .owner = tbinfo->rolname,
   18043             :                                   .description = "SEQUENCE SET",
   18044             :                                   .section = SECTION_DATA,
   18045             :                                   .createStmt = query->data,
   18046             :                                   .deps = &(tbinfo->dobj.dumpId),
   18047             :                                   .nDeps = 1));
   18048             : 
   18049         728 :     destroyPQExpBuffer(query);
   18050         728 : }
   18051             : 
   18052             : /*
   18053             :  * dumpTrigger
   18054             :  *    write the declaration of one user-defined table trigger
   18055             :  */
   18056             : static void
   18057         986 : dumpTrigger(Archive *fout, const TriggerInfo *tginfo)
   18058             : {
   18059         986 :     DumpOptions *dopt = fout->dopt;
   18060         986 :     TableInfo  *tbinfo = tginfo->tgtable;
   18061             :     PQExpBuffer query;
   18062             :     PQExpBuffer delqry;
   18063             :     PQExpBuffer trigprefix;
   18064             :     PQExpBuffer trigidentity;
   18065             :     char       *qtabname;
   18066             :     char       *tag;
   18067             : 
   18068             :     /* Do nothing if not dumping schema */
   18069         986 :     if (!dopt->dumpSchema)
   18070          32 :         return;
   18071             : 
   18072         954 :     query = createPQExpBuffer();
   18073         954 :     delqry = createPQExpBuffer();
   18074         954 :     trigprefix = createPQExpBuffer();
   18075         954 :     trigidentity = createPQExpBuffer();
   18076             : 
   18077         954 :     qtabname = pg_strdup(fmtId(tbinfo->dobj.name));
   18078             : 
   18079         954 :     appendPQExpBuffer(trigidentity, "%s ", fmtId(tginfo->dobj.name));
   18080         954 :     appendPQExpBuffer(trigidentity, "ON %s", fmtQualifiedDumpable(tbinfo));
   18081             : 
   18082         954 :     appendPQExpBuffer(query, "%s;\n", tginfo->tgdef);
   18083         954 :     appendPQExpBuffer(delqry, "DROP TRIGGER %s;\n", trigidentity->data);
   18084             : 
   18085             :     /* Triggers can depend on extensions */
   18086         954 :     append_depends_on_extension(fout, query, &tginfo->dobj,
   18087             :                                 "pg_catalog.pg_trigger", "TRIGGER",
   18088         954 :                                 trigidentity->data);
   18089             : 
   18090         954 :     if (tginfo->tgispartition)
   18091             :     {
   18092             :         Assert(tbinfo->ispartition);
   18093             : 
   18094             :         /*
   18095             :          * Partition triggers only appear here because their 'tgenabled' flag
   18096             :          * differs from its parent's.  The trigger is created already, so
   18097             :          * remove the CREATE and replace it with an ALTER.  (Clear out the
   18098             :          * DROP query too, so that pg_dump --create does not cause errors.)
   18099             :          */
   18100         224 :         resetPQExpBuffer(query);
   18101         224 :         resetPQExpBuffer(delqry);
   18102         224 :         appendPQExpBuffer(query, "\nALTER %sTABLE %s ",
   18103         224 :                           tbinfo->relkind == RELKIND_FOREIGN_TABLE ? "FOREIGN " : "",
   18104         224 :                           fmtQualifiedDumpable(tbinfo));
   18105         224 :         switch (tginfo->tgenabled)
   18106             :         {
   18107          78 :             case 'f':
   18108             :             case 'D':
   18109          78 :                 appendPQExpBufferStr(query, "DISABLE");
   18110          78 :                 break;
   18111           0 :             case 't':
   18112             :             case 'O':
   18113           0 :                 appendPQExpBufferStr(query, "ENABLE");
   18114           0 :                 break;
   18115          68 :             case 'R':
   18116          68 :                 appendPQExpBufferStr(query, "ENABLE REPLICA");
   18117          68 :                 break;
   18118          78 :             case 'A':
   18119          78 :                 appendPQExpBufferStr(query, "ENABLE ALWAYS");
   18120          78 :                 break;
   18121             :         }
   18122         224 :         appendPQExpBuffer(query, " TRIGGER %s;\n",
   18123         224 :                           fmtId(tginfo->dobj.name));
   18124             :     }
   18125         730 :     else if (tginfo->tgenabled != 't' && tginfo->tgenabled != 'O')
   18126             :     {
   18127           0 :         appendPQExpBuffer(query, "\nALTER %sTABLE %s ",
   18128           0 :                           tbinfo->relkind == RELKIND_FOREIGN_TABLE ? "FOREIGN " : "",
   18129           0 :                           fmtQualifiedDumpable(tbinfo));
   18130           0 :         switch (tginfo->tgenabled)
   18131             :         {
   18132           0 :             case 'D':
   18133             :             case 'f':
   18134           0 :                 appendPQExpBufferStr(query, "DISABLE");
   18135           0 :                 break;
   18136           0 :             case 'A':
   18137           0 :                 appendPQExpBufferStr(query, "ENABLE ALWAYS");
   18138           0 :                 break;
   18139           0 :             case 'R':
   18140           0 :                 appendPQExpBufferStr(query, "ENABLE REPLICA");
   18141           0 :                 break;
   18142           0 :             default:
   18143           0 :                 appendPQExpBufferStr(query, "ENABLE");
   18144           0 :                 break;
   18145             :         }
   18146           0 :         appendPQExpBuffer(query, " TRIGGER %s;\n",
   18147           0 :                           fmtId(tginfo->dobj.name));
   18148             :     }
   18149             : 
   18150         954 :     appendPQExpBuffer(trigprefix, "TRIGGER %s ON",
   18151         954 :                       fmtId(tginfo->dobj.name));
   18152             : 
   18153         954 :     tag = psprintf("%s %s", tbinfo->dobj.name, tginfo->dobj.name);
   18154             : 
   18155         954 :     if (tginfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   18156         954 :         ArchiveEntry(fout, tginfo->dobj.catId, tginfo->dobj.dumpId,
   18157         954 :                      ARCHIVE_OPTS(.tag = tag,
   18158             :                                   .namespace = tbinfo->dobj.namespace->dobj.name,
   18159             :                                   .owner = tbinfo->rolname,
   18160             :                                   .description = "TRIGGER",
   18161             :                                   .section = SECTION_POST_DATA,
   18162             :                                   .createStmt = query->data,
   18163             :                                   .dropStmt = delqry->data));
   18164             : 
   18165         954 :     if (tginfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   18166           0 :         dumpComment(fout, trigprefix->data, qtabname,
   18167           0 :                     tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
   18168             :                     tginfo->dobj.catId, 0, tginfo->dobj.dumpId);
   18169             : 
   18170         954 :     free(tag);
   18171         954 :     destroyPQExpBuffer(query);
   18172         954 :     destroyPQExpBuffer(delqry);
   18173         954 :     destroyPQExpBuffer(trigprefix);
   18174         954 :     destroyPQExpBuffer(trigidentity);
   18175         954 :     free(qtabname);
   18176             : }
   18177             : 
   18178             : /*
   18179             :  * dumpEventTrigger
   18180             :  *    write the declaration of one user-defined event trigger
   18181             :  */
   18182             : static void
   18183          80 : dumpEventTrigger(Archive *fout, const EventTriggerInfo *evtinfo)
   18184             : {
   18185          80 :     DumpOptions *dopt = fout->dopt;
   18186             :     PQExpBuffer query;
   18187             :     PQExpBuffer delqry;
   18188             :     char       *qevtname;
   18189             : 
   18190             :     /* Do nothing if not dumping schema */
   18191          80 :     if (!dopt->dumpSchema)
   18192           6 :         return;
   18193             : 
   18194          74 :     query = createPQExpBuffer();
   18195          74 :     delqry = createPQExpBuffer();
   18196             : 
   18197          74 :     qevtname = pg_strdup(fmtId(evtinfo->dobj.name));
   18198             : 
   18199          74 :     appendPQExpBufferStr(query, "CREATE EVENT TRIGGER ");
   18200          74 :     appendPQExpBufferStr(query, qevtname);
   18201          74 :     appendPQExpBufferStr(query, " ON ");
   18202          74 :     appendPQExpBufferStr(query, fmtId(evtinfo->evtevent));
   18203             : 
   18204          74 :     if (strcmp("", evtinfo->evttags) != 0)
   18205             :     {
   18206          10 :         appendPQExpBufferStr(query, "\n         WHEN TAG IN (");
   18207          10 :         appendPQExpBufferStr(query, evtinfo->evttags);
   18208          10 :         appendPQExpBufferChar(query, ')');
   18209             :     }
   18210             : 
   18211          74 :     appendPQExpBufferStr(query, "\n   EXECUTE FUNCTION ");
   18212          74 :     appendPQExpBufferStr(query, evtinfo->evtfname);
   18213          74 :     appendPQExpBufferStr(query, "();\n");
   18214             : 
   18215          74 :     if (evtinfo->evtenabled != 'O')
   18216             :     {
   18217           0 :         appendPQExpBuffer(query, "\nALTER EVENT TRIGGER %s ",
   18218             :                           qevtname);
   18219           0 :         switch (evtinfo->evtenabled)
   18220             :         {
   18221           0 :             case 'D':
   18222           0 :                 appendPQExpBufferStr(query, "DISABLE");
   18223           0 :                 break;
   18224           0 :             case 'A':
   18225           0 :                 appendPQExpBufferStr(query, "ENABLE ALWAYS");
   18226           0 :                 break;
   18227           0 :             case 'R':
   18228           0 :                 appendPQExpBufferStr(query, "ENABLE REPLICA");
   18229           0 :                 break;
   18230           0 :             default:
   18231           0 :                 appendPQExpBufferStr(query, "ENABLE");
   18232           0 :                 break;
   18233             :         }
   18234           0 :         appendPQExpBufferStr(query, ";\n");
   18235             :     }
   18236             : 
   18237          74 :     appendPQExpBuffer(delqry, "DROP EVENT TRIGGER %s;\n",
   18238             :                       qevtname);
   18239             : 
   18240          74 :     if (dopt->binary_upgrade)
   18241           4 :         binary_upgrade_extension_member(query, &evtinfo->dobj,
   18242             :                                         "EVENT TRIGGER", qevtname, NULL);
   18243             : 
   18244          74 :     if (evtinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   18245          74 :         ArchiveEntry(fout, evtinfo->dobj.catId, evtinfo->dobj.dumpId,
   18246          74 :                      ARCHIVE_OPTS(.tag = evtinfo->dobj.name,
   18247             :                                   .owner = evtinfo->evtowner,
   18248             :                                   .description = "EVENT TRIGGER",
   18249             :                                   .section = SECTION_POST_DATA,
   18250             :                                   .createStmt = query->data,
   18251             :                                   .dropStmt = delqry->data));
   18252             : 
   18253          74 :     if (evtinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   18254           0 :         dumpComment(fout, "EVENT TRIGGER", qevtname,
   18255             :                     NULL, evtinfo->evtowner,
   18256             :                     evtinfo->dobj.catId, 0, evtinfo->dobj.dumpId);
   18257             : 
   18258          74 :     destroyPQExpBuffer(query);
   18259          74 :     destroyPQExpBuffer(delqry);
   18260          74 :     free(qevtname);
   18261             : }
   18262             : 
   18263             : /*
   18264             :  * dumpRule
   18265             :  *      Dump a rule
   18266             :  */
   18267             : static void
   18268        2150 : dumpRule(Archive *fout, const RuleInfo *rinfo)
   18269             : {
   18270        2150 :     DumpOptions *dopt = fout->dopt;
   18271        2150 :     TableInfo  *tbinfo = rinfo->ruletable;
   18272             :     bool        is_view;
   18273             :     PQExpBuffer query;
   18274             :     PQExpBuffer cmd;
   18275             :     PQExpBuffer delcmd;
   18276             :     PQExpBuffer ruleprefix;
   18277             :     char       *qtabname;
   18278             :     PGresult   *res;
   18279             :     char       *tag;
   18280             : 
   18281             :     /* Do nothing if not dumping schema */
   18282        2150 :     if (!dopt->dumpSchema)
   18283          60 :         return;
   18284             : 
   18285             :     /*
   18286             :      * If it is an ON SELECT rule that is created implicitly by CREATE VIEW,
   18287             :      * we do not want to dump it as a separate object.
   18288             :      */
   18289        2090 :     if (!rinfo->separate)
   18290        1668 :         return;
   18291             : 
   18292             :     /*
   18293             :      * If it's an ON SELECT rule, we want to print it as a view definition,
   18294             :      * instead of a rule.
   18295             :      */
   18296         422 :     is_view = (rinfo->ev_type == '1' && rinfo->is_instead);
   18297             : 
   18298         422 :     query = createPQExpBuffer();
   18299         422 :     cmd = createPQExpBuffer();
   18300         422 :     delcmd = createPQExpBuffer();
   18301         422 :     ruleprefix = createPQExpBuffer();
   18302             : 
   18303         422 :     qtabname = pg_strdup(fmtId(tbinfo->dobj.name));
   18304             : 
   18305         422 :     if (is_view)
   18306             :     {
   18307             :         PQExpBuffer result;
   18308             : 
   18309             :         /*
   18310             :          * We need OR REPLACE here because we'll be replacing a dummy view.
   18311             :          * Otherwise this should look largely like the regular view dump code.
   18312             :          */
   18313          20 :         appendPQExpBuffer(cmd, "CREATE OR REPLACE VIEW %s",
   18314          20 :                           fmtQualifiedDumpable(tbinfo));
   18315          20 :         if (nonemptyReloptions(tbinfo->reloptions))
   18316             :         {
   18317           0 :             appendPQExpBufferStr(cmd, " WITH (");
   18318           0 :             appendReloptionsArrayAH(cmd, tbinfo->reloptions, "", fout);
   18319           0 :             appendPQExpBufferChar(cmd, ')');
   18320             :         }
   18321          20 :         result = createViewAsClause(fout, tbinfo);
   18322          20 :         appendPQExpBuffer(cmd, " AS\n%s", result->data);
   18323          20 :         destroyPQExpBuffer(result);
   18324          20 :         if (tbinfo->checkoption != NULL)
   18325           0 :             appendPQExpBuffer(cmd, "\n  WITH %s CHECK OPTION",
   18326             :                               tbinfo->checkoption);
   18327          20 :         appendPQExpBufferStr(cmd, ";\n");
   18328             :     }
   18329             :     else
   18330             :     {
   18331             :         /* In the rule case, just print pg_get_ruledef's result verbatim */
   18332         402 :         appendPQExpBuffer(query,
   18333             :                           "SELECT pg_catalog.pg_get_ruledef('%u'::pg_catalog.oid)",
   18334             :                           rinfo->dobj.catId.oid);
   18335             : 
   18336         402 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   18337             : 
   18338         402 :         if (PQntuples(res) != 1)
   18339           0 :             pg_fatal("query to get rule \"%s\" for table \"%s\" failed: wrong number of rows returned",
   18340             :                      rinfo->dobj.name, tbinfo->dobj.name);
   18341             : 
   18342         402 :         printfPQExpBuffer(cmd, "%s\n", PQgetvalue(res, 0, 0));
   18343             : 
   18344         402 :         PQclear(res);
   18345             :     }
   18346             : 
   18347             :     /*
   18348             :      * Add the command to alter the rules replication firing semantics if it
   18349             :      * differs from the default.
   18350             :      */
   18351         422 :     if (rinfo->ev_enabled != 'O')
   18352             :     {
   18353          30 :         appendPQExpBuffer(cmd, "ALTER TABLE %s ", fmtQualifiedDumpable(tbinfo));
   18354          30 :         switch (rinfo->ev_enabled)
   18355             :         {
   18356           0 :             case 'A':
   18357           0 :                 appendPQExpBuffer(cmd, "ENABLE ALWAYS RULE %s;\n",
   18358           0 :                                   fmtId(rinfo->dobj.name));
   18359           0 :                 break;
   18360           0 :             case 'R':
   18361           0 :                 appendPQExpBuffer(cmd, "ENABLE REPLICA RULE %s;\n",
   18362           0 :                                   fmtId(rinfo->dobj.name));
   18363           0 :                 break;
   18364          30 :             case 'D':
   18365          30 :                 appendPQExpBuffer(cmd, "DISABLE RULE %s;\n",
   18366          30 :                                   fmtId(rinfo->dobj.name));
   18367          30 :                 break;
   18368             :         }
   18369         392 :     }
   18370             : 
   18371         422 :     if (is_view)
   18372             :     {
   18373             :         /*
   18374             :          * We can't DROP a view's ON SELECT rule.  Instead, use CREATE OR
   18375             :          * REPLACE VIEW to replace the rule with something with minimal
   18376             :          * dependencies.
   18377             :          */
   18378             :         PQExpBuffer result;
   18379             : 
   18380          20 :         appendPQExpBuffer(delcmd, "CREATE OR REPLACE VIEW %s",
   18381          20 :                           fmtQualifiedDumpable(tbinfo));
   18382          20 :         result = createDummyViewAsClause(fout, tbinfo);
   18383          20 :         appendPQExpBuffer(delcmd, " AS\n%s;\n", result->data);
   18384          20 :         destroyPQExpBuffer(result);
   18385             :     }
   18386             :     else
   18387             :     {
   18388         402 :         appendPQExpBuffer(delcmd, "DROP RULE %s ",
   18389         402 :                           fmtId(rinfo->dobj.name));
   18390         402 :         appendPQExpBuffer(delcmd, "ON %s;\n",
   18391         402 :                           fmtQualifiedDumpable(tbinfo));
   18392             :     }
   18393             : 
   18394         422 :     appendPQExpBuffer(ruleprefix, "RULE %s ON",
   18395         422 :                       fmtId(rinfo->dobj.name));
   18396             : 
   18397         422 :     tag = psprintf("%s %s", tbinfo->dobj.name, rinfo->dobj.name);
   18398             : 
   18399         422 :     if (rinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   18400         422 :         ArchiveEntry(fout, rinfo->dobj.catId, rinfo->dobj.dumpId,
   18401         422 :                      ARCHIVE_OPTS(.tag = tag,
   18402             :                                   .namespace = tbinfo->dobj.namespace->dobj.name,
   18403             :                                   .owner = tbinfo->rolname,
   18404             :                                   .description = "RULE",
   18405             :                                   .section = SECTION_POST_DATA,
   18406             :                                   .createStmt = cmd->data,
   18407             :                                   .dropStmt = delcmd->data));
   18408             : 
   18409             :     /* Dump rule comments */
   18410         422 :     if (rinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   18411           0 :         dumpComment(fout, ruleprefix->data, qtabname,
   18412           0 :                     tbinfo->dobj.namespace->dobj.name,
   18413             :                     tbinfo->rolname,
   18414             :                     rinfo->dobj.catId, 0, rinfo->dobj.dumpId);
   18415             : 
   18416         422 :     free(tag);
   18417         422 :     destroyPQExpBuffer(query);
   18418         422 :     destroyPQExpBuffer(cmd);
   18419         422 :     destroyPQExpBuffer(delcmd);
   18420         422 :     destroyPQExpBuffer(ruleprefix);
   18421         422 :     free(qtabname);
   18422             : }
   18423             : 
   18424             : /*
   18425             :  * getExtensionMembership --- obtain extension membership data
   18426             :  *
   18427             :  * We need to identify objects that are extension members as soon as they're
   18428             :  * loaded, so that we can correctly determine whether they need to be dumped.
   18429             :  * Generally speaking, extension member objects will get marked as *not* to
   18430             :  * be dumped, as they will be recreated by the single CREATE EXTENSION
   18431             :  * command.  However, in binary upgrade mode we still need to dump the members
   18432             :  * individually.
   18433             :  */
   18434             : void
   18435         310 : getExtensionMembership(Archive *fout, ExtensionInfo extinfo[],
   18436             :                        int numExtensions)
   18437             : {
   18438             :     PQExpBuffer query;
   18439             :     PGresult   *res;
   18440             :     int         ntups,
   18441             :                 i;
   18442             :     int         i_classid,
   18443             :                 i_objid,
   18444             :                 i_refobjid;
   18445             :     ExtensionInfo *ext;
   18446             : 
   18447             :     /* Nothing to do if no extensions */
   18448         310 :     if (numExtensions == 0)
   18449           0 :         return;
   18450             : 
   18451         310 :     query = createPQExpBuffer();
   18452             : 
   18453             :     /* refclassid constraint is redundant but may speed the search */
   18454         310 :     appendPQExpBufferStr(query, "SELECT "
   18455             :                          "classid, objid, refobjid "
   18456             :                          "FROM pg_depend "
   18457             :                          "WHERE refclassid = 'pg_extension'::regclass "
   18458             :                          "AND deptype = 'e' "
   18459             :                          "ORDER BY 3");
   18460             : 
   18461         310 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   18462             : 
   18463         310 :     ntups = PQntuples(res);
   18464             : 
   18465         310 :     i_classid = PQfnumber(res, "classid");
   18466         310 :     i_objid = PQfnumber(res, "objid");
   18467         310 :     i_refobjid = PQfnumber(res, "refobjid");
   18468             : 
   18469             :     /*
   18470             :      * Since we ordered the SELECT by referenced ID, we can expect that
   18471             :      * multiple entries for the same extension will appear together; this
   18472             :      * saves on searches.
   18473             :      */
   18474         310 :     ext = NULL;
   18475             : 
   18476        2750 :     for (i = 0; i < ntups; i++)
   18477             :     {
   18478             :         CatalogId   objId;
   18479             :         Oid         extId;
   18480             : 
   18481        2440 :         objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
   18482        2440 :         objId.oid = atooid(PQgetvalue(res, i, i_objid));
   18483        2440 :         extId = atooid(PQgetvalue(res, i, i_refobjid));
   18484             : 
   18485        2440 :         if (ext == NULL ||
   18486        2130 :             ext->dobj.catId.oid != extId)
   18487         360 :             ext = findExtensionByOid(extId);
   18488             : 
   18489        2440 :         if (ext == NULL)
   18490             :         {
   18491             :             /* shouldn't happen */
   18492           0 :             pg_log_warning("could not find referenced extension %u", extId);
   18493           0 :             continue;
   18494             :         }
   18495             : 
   18496        2440 :         recordExtensionMembership(objId, ext);
   18497             :     }
   18498             : 
   18499         310 :     PQclear(res);
   18500             : 
   18501         310 :     destroyPQExpBuffer(query);
   18502             : }
   18503             : 
   18504             : /*
   18505             :  * processExtensionTables --- deal with extension configuration tables
   18506             :  *
   18507             :  * There are two parts to this process:
   18508             :  *
   18509             :  * 1. Identify and create dump records for extension configuration tables.
   18510             :  *
   18511             :  *    Extensions can mark tables as "configuration", which means that the user
   18512             :  *    is able and expected to modify those tables after the extension has been
   18513             :  *    loaded.  For these tables, we dump out only the data- the structure is
   18514             :  *    expected to be handled at CREATE EXTENSION time, including any indexes or
   18515             :  *    foreign keys, which brings us to-
   18516             :  *
   18517             :  * 2. Record FK dependencies between configuration tables.
   18518             :  *
   18519             :  *    Due to the FKs being created at CREATE EXTENSION time and therefore before
   18520             :  *    the data is loaded, we have to work out what the best order for reloading
   18521             :  *    the data is, to avoid FK violations when the tables are restored.  This is
   18522             :  *    not perfect- we can't handle circular dependencies and if any exist they
   18523             :  *    will cause an invalid dump to be produced (though at least all of the data
   18524             :  *    is included for a user to manually restore).  This is currently documented
   18525             :  *    but perhaps we can provide a better solution in the future.
   18526             :  */
   18527             : void
   18528         308 : processExtensionTables(Archive *fout, ExtensionInfo extinfo[],
   18529             :                        int numExtensions)
   18530             : {
   18531         308 :     DumpOptions *dopt = fout->dopt;
   18532             :     PQExpBuffer query;
   18533             :     PGresult   *res;
   18534             :     int         ntups,
   18535             :                 i;
   18536             :     int         i_conrelid,
   18537             :                 i_confrelid;
   18538             : 
   18539             :     /* Nothing to do if no extensions */
   18540         308 :     if (numExtensions == 0)
   18541           0 :         return;
   18542             : 
   18543             :     /*
   18544             :      * Identify extension configuration tables and create TableDataInfo
   18545             :      * objects for them, ensuring their data will be dumped even though the
   18546             :      * tables themselves won't be.
   18547             :      *
   18548             :      * Note that we create TableDataInfo objects even in schema-only mode, ie,
   18549             :      * user data in a configuration table is treated like schema data. This
   18550             :      * seems appropriate since system data in a config table would get
   18551             :      * reloaded by CREATE EXTENSION.  If the extension is not listed in the
   18552             :      * list of extensions to be included, none of its data is dumped.
   18553             :      */
   18554         666 :     for (i = 0; i < numExtensions; i++)
   18555             :     {
   18556         358 :         ExtensionInfo *curext = &(extinfo[i]);
   18557         358 :         char       *extconfig = curext->extconfig;
   18558         358 :         char       *extcondition = curext->extcondition;
   18559         358 :         char      **extconfigarray = NULL;
   18560         358 :         char      **extconditionarray = NULL;
   18561         358 :         int         nconfigitems = 0;
   18562         358 :         int         nconditionitems = 0;
   18563             : 
   18564             :         /*
   18565             :          * Check if this extension is listed as to include in the dump.  If
   18566             :          * not, any table data associated with it is discarded.
   18567             :          */
   18568         358 :         if (extension_include_oids.head != NULL &&
   18569          16 :             !simple_oid_list_member(&extension_include_oids,
   18570             :                                     curext->dobj.catId.oid))
   18571          12 :             continue;
   18572             : 
   18573             :         /*
   18574             :          * Check if this extension is listed as to exclude in the dump.  If
   18575             :          * yes, any table data associated with it is discarded.
   18576             :          */
   18577         358 :         if (extension_exclude_oids.head != NULL &&
   18578           8 :             simple_oid_list_member(&extension_exclude_oids,
   18579             :                                    curext->dobj.catId.oid))
   18580           4 :             continue;
   18581             : 
   18582         346 :         if (strlen(extconfig) != 0 || strlen(extcondition) != 0)
   18583             :         {
   18584             :             int         j;
   18585             : 
   18586          40 :             if (!parsePGArray(extconfig, &extconfigarray, &nconfigitems))
   18587           0 :                 pg_fatal("could not parse %s array", "extconfig");
   18588          40 :             if (!parsePGArray(extcondition, &extconditionarray, &nconditionitems))
   18589           0 :                 pg_fatal("could not parse %s array", "extcondition");
   18590          40 :             if (nconfigitems != nconditionitems)
   18591           0 :                 pg_fatal("mismatched number of configurations and conditions for extension");
   18592             : 
   18593         120 :             for (j = 0; j < nconfigitems; j++)
   18594             :             {
   18595             :                 TableInfo  *configtbl;
   18596          80 :                 Oid         configtbloid = atooid(extconfigarray[j]);
   18597          80 :                 bool        dumpobj =
   18598          80 :                     curext->dobj.dump & DUMP_COMPONENT_DEFINITION;
   18599             : 
   18600          80 :                 configtbl = findTableByOid(configtbloid);
   18601          80 :                 if (configtbl == NULL)
   18602           0 :                     continue;
   18603             : 
   18604             :                 /*
   18605             :                  * Tables of not-to-be-dumped extensions shouldn't be dumped
   18606             :                  * unless the table or its schema is explicitly included
   18607             :                  */
   18608          80 :                 if (!(curext->dobj.dump & DUMP_COMPONENT_DEFINITION))
   18609             :                 {
   18610             :                     /* check table explicitly requested */
   18611           4 :                     if (table_include_oids.head != NULL &&
   18612           0 :                         simple_oid_list_member(&table_include_oids,
   18613             :                                                configtbloid))
   18614           0 :                         dumpobj = true;
   18615             : 
   18616             :                     /* check table's schema explicitly requested */
   18617           4 :                     if (configtbl->dobj.namespace->dobj.dump &
   18618             :                         DUMP_COMPONENT_DATA)
   18619           4 :                         dumpobj = true;
   18620             :                 }
   18621             : 
   18622             :                 /* check table excluded by an exclusion switch */
   18623          88 :                 if (table_exclude_oids.head != NULL &&
   18624           8 :                     simple_oid_list_member(&table_exclude_oids,
   18625             :                                            configtbloid))
   18626           2 :                     dumpobj = false;
   18627             : 
   18628             :                 /* check schema excluded by an exclusion switch */
   18629          80 :                 if (simple_oid_list_member(&schema_exclude_oids,
   18630          80 :                                            configtbl->dobj.namespace->dobj.catId.oid))
   18631           0 :                     dumpobj = false;
   18632             : 
   18633          80 :                 if (dumpobj)
   18634             :                 {
   18635          78 :                     makeTableDataInfo(dopt, configtbl);
   18636          78 :                     if (configtbl->dataObj != NULL)
   18637             :                     {
   18638          78 :                         if (strlen(extconditionarray[j]) > 0)
   18639           0 :                             configtbl->dataObj->filtercond = pg_strdup(extconditionarray[j]);
   18640             :                     }
   18641             :                 }
   18642             :             }
   18643             :         }
   18644         346 :         if (extconfigarray)
   18645          40 :             free(extconfigarray);
   18646         346 :         if (extconditionarray)
   18647          40 :             free(extconditionarray);
   18648             :     }
   18649             : 
   18650             :     /*
   18651             :      * Now that all the TableDataInfo objects have been created for all the
   18652             :      * extensions, check their FK dependencies and register them to try and
   18653             :      * dump the data out in an order that they can be restored in.
   18654             :      *
   18655             :      * Note that this is not a problem for user tables as their FKs are
   18656             :      * recreated after the data has been loaded.
   18657             :      */
   18658             : 
   18659         308 :     query = createPQExpBuffer();
   18660             : 
   18661         308 :     printfPQExpBuffer(query,
   18662             :                       "SELECT conrelid, confrelid "
   18663             :                       "FROM pg_constraint "
   18664             :                       "JOIN pg_depend ON (objid = confrelid) "
   18665             :                       "WHERE contype = 'f' "
   18666             :                       "AND refclassid = 'pg_extension'::regclass "
   18667             :                       "AND classid = 'pg_class'::regclass;");
   18668             : 
   18669         308 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   18670         308 :     ntups = PQntuples(res);
   18671             : 
   18672         308 :     i_conrelid = PQfnumber(res, "conrelid");
   18673         308 :     i_confrelid = PQfnumber(res, "confrelid");
   18674             : 
   18675             :     /* Now get the dependencies and register them */
   18676         308 :     for (i = 0; i < ntups; i++)
   18677             :     {
   18678             :         Oid         conrelid,
   18679             :                     confrelid;
   18680             :         TableInfo  *reftable,
   18681             :                    *contable;
   18682             : 
   18683           0 :         conrelid = atooid(PQgetvalue(res, i, i_conrelid));
   18684           0 :         confrelid = atooid(PQgetvalue(res, i, i_confrelid));
   18685           0 :         contable = findTableByOid(conrelid);
   18686           0 :         reftable = findTableByOid(confrelid);
   18687             : 
   18688           0 :         if (reftable == NULL ||
   18689           0 :             reftable->dataObj == NULL ||
   18690           0 :             contable == NULL ||
   18691           0 :             contable->dataObj == NULL)
   18692           0 :             continue;
   18693             : 
   18694             :         /*
   18695             :          * Make referencing TABLE_DATA object depend on the referenced table's
   18696             :          * TABLE_DATA object.
   18697             :          */
   18698           0 :         addObjectDependency(&contable->dataObj->dobj,
   18699           0 :                             reftable->dataObj->dobj.dumpId);
   18700             :     }
   18701         308 :     PQclear(res);
   18702         308 :     destroyPQExpBuffer(query);
   18703             : }
   18704             : 
   18705             : /*
   18706             :  * getDependencies --- obtain available dependency data
   18707             :  */
   18708             : static void
   18709         308 : getDependencies(Archive *fout)
   18710             : {
   18711             :     PQExpBuffer query;
   18712             :     PGresult   *res;
   18713             :     int         ntups,
   18714             :                 i;
   18715             :     int         i_classid,
   18716             :                 i_objid,
   18717             :                 i_refclassid,
   18718             :                 i_refobjid,
   18719             :                 i_deptype;
   18720             :     DumpableObject *dobj,
   18721             :                *refdobj;
   18722             : 
   18723         308 :     pg_log_info("reading dependency data");
   18724             : 
   18725         308 :     query = createPQExpBuffer();
   18726             : 
   18727             :     /*
   18728             :      * Messy query to collect the dependency data we need.  Note that we
   18729             :      * ignore the sub-object column, so that dependencies of or on a column
   18730             :      * look the same as dependencies of or on a whole table.
   18731             :      *
   18732             :      * PIN dependencies aren't interesting, and EXTENSION dependencies were
   18733             :      * already processed by getExtensionMembership.
   18734             :      */
   18735         308 :     appendPQExpBufferStr(query, "SELECT "
   18736             :                          "classid, objid, refclassid, refobjid, deptype "
   18737             :                          "FROM pg_depend "
   18738             :                          "WHERE deptype != 'p' AND deptype != 'e'\n");
   18739             : 
   18740             :     /*
   18741             :      * Since we don't treat pg_amop entries as separate DumpableObjects, we
   18742             :      * have to translate their dependencies into dependencies of their parent
   18743             :      * opfamily.  Ignore internal dependencies though, as those will point to
   18744             :      * their parent opclass, which we needn't consider here (and if we did,
   18745             :      * it'd just result in circular dependencies).  Also, "loose" opfamily
   18746             :      * entries will have dependencies on their parent opfamily, which we
   18747             :      * should drop since they'd likewise become useless self-dependencies.
   18748             :      * (But be sure to keep deps on *other* opfamilies; see amopsortfamily.)
   18749             :      */
   18750         308 :     appendPQExpBufferStr(query, "UNION ALL\n"
   18751             :                          "SELECT 'pg_opfamily'::regclass AS classid, amopfamily AS objid, refclassid, refobjid, deptype "
   18752             :                          "FROM pg_depend d, pg_amop o "
   18753             :                          "WHERE deptype NOT IN ('p', 'e', 'i') AND "
   18754             :                          "classid = 'pg_amop'::regclass AND objid = o.oid "
   18755             :                          "AND NOT (refclassid = 'pg_opfamily'::regclass AND amopfamily = refobjid)\n");
   18756             : 
   18757             :     /* Likewise for pg_amproc entries */
   18758         308 :     appendPQExpBufferStr(query, "UNION ALL\n"
   18759             :                          "SELECT 'pg_opfamily'::regclass AS classid, amprocfamily AS objid, refclassid, refobjid, deptype "
   18760             :                          "FROM pg_depend d, pg_amproc p "
   18761             :                          "WHERE deptype NOT IN ('p', 'e', 'i') AND "
   18762             :                          "classid = 'pg_amproc'::regclass AND objid = p.oid "
   18763             :                          "AND NOT (refclassid = 'pg_opfamily'::regclass AND amprocfamily = refobjid)\n");
   18764             : 
   18765             :     /* Sort the output for efficiency below */
   18766         308 :     appendPQExpBufferStr(query, "ORDER BY 1,2");
   18767             : 
   18768         308 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   18769             : 
   18770         308 :     ntups = PQntuples(res);
   18771             : 
   18772         308 :     i_classid = PQfnumber(res, "classid");
   18773         308 :     i_objid = PQfnumber(res, "objid");
   18774         308 :     i_refclassid = PQfnumber(res, "refclassid");
   18775         308 :     i_refobjid = PQfnumber(res, "refobjid");
   18776         308 :     i_deptype = PQfnumber(res, "deptype");
   18777             : 
   18778             :     /*
   18779             :      * Since we ordered the SELECT by referencing ID, we can expect that
   18780             :      * multiple entries for the same object will appear together; this saves
   18781             :      * on searches.
   18782             :      */
   18783         308 :     dobj = NULL;
   18784             : 
   18785      668622 :     for (i = 0; i < ntups; i++)
   18786             :     {
   18787             :         CatalogId   objId;
   18788             :         CatalogId   refobjId;
   18789             :         char        deptype;
   18790             : 
   18791      668314 :         objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
   18792      668314 :         objId.oid = atooid(PQgetvalue(res, i, i_objid));
   18793      668314 :         refobjId.tableoid = atooid(PQgetvalue(res, i, i_refclassid));
   18794      668314 :         refobjId.oid = atooid(PQgetvalue(res, i, i_refobjid));
   18795      668314 :         deptype = *(PQgetvalue(res, i, i_deptype));
   18796             : 
   18797      668314 :         if (dobj == NULL ||
   18798      623152 :             dobj->catId.tableoid != objId.tableoid ||
   18799      619482 :             dobj->catId.oid != objId.oid)
   18800      295422 :             dobj = findObjectByCatalogId(objId);
   18801             : 
   18802             :         /*
   18803             :          * Failure to find objects mentioned in pg_depend is not unexpected,
   18804             :          * since for example we don't collect info about TOAST tables.
   18805             :          */
   18806      668314 :         if (dobj == NULL)
   18807             :         {
   18808             : #ifdef NOT_USED
   18809             :             pg_log_warning("no referencing object %u %u",
   18810             :                            objId.tableoid, objId.oid);
   18811             : #endif
   18812       46380 :             continue;
   18813             :         }
   18814             : 
   18815      623444 :         refdobj = findObjectByCatalogId(refobjId);
   18816             : 
   18817      623444 :         if (refdobj == NULL)
   18818             :         {
   18819             : #ifdef NOT_USED
   18820             :             pg_log_warning("no referenced object %u %u",
   18821             :                            refobjId.tableoid, refobjId.oid);
   18822             : #endif
   18823        1510 :             continue;
   18824             :         }
   18825             : 
   18826             :         /*
   18827             :          * For 'x' dependencies, mark the object for later; we still add the
   18828             :          * normal dependency, for possible ordering purposes.  Currently
   18829             :          * pg_dump_sort.c knows to put extensions ahead of all object types
   18830             :          * that could possibly depend on them, but this is safer.
   18831             :          */
   18832      621934 :         if (deptype == 'x')
   18833          88 :             dobj->depends_on_ext = true;
   18834             : 
   18835             :         /*
   18836             :          * Ordinarily, table rowtypes have implicit dependencies on their
   18837             :          * tables.  However, for a composite type the implicit dependency goes
   18838             :          * the other way in pg_depend; which is the right thing for DROP but
   18839             :          * it doesn't produce the dependency ordering we need. So in that one
   18840             :          * case, we reverse the direction of the dependency.
   18841             :          */
   18842      621934 :         if (deptype == 'i' &&
   18843      173406 :             dobj->objType == DO_TABLE &&
   18844        2322 :             refdobj->objType == DO_TYPE)
   18845         360 :             addObjectDependency(refdobj, dobj->dumpId);
   18846             :         else
   18847             :             /* normal case */
   18848      621574 :             addObjectDependency(dobj, refdobj->dumpId);
   18849             :     }
   18850             : 
   18851         308 :     PQclear(res);
   18852             : 
   18853         308 :     destroyPQExpBuffer(query);
   18854         308 : }
   18855             : 
   18856             : 
   18857             : /*
   18858             :  * createBoundaryObjects - create dummy DumpableObjects to represent
   18859             :  * dump section boundaries.
   18860             :  */
   18861             : static DumpableObject *
   18862         308 : createBoundaryObjects(void)
   18863             : {
   18864             :     DumpableObject *dobjs;
   18865             : 
   18866         308 :     dobjs = (DumpableObject *) pg_malloc(2 * sizeof(DumpableObject));
   18867             : 
   18868         308 :     dobjs[0].objType = DO_PRE_DATA_BOUNDARY;
   18869         308 :     dobjs[0].catId = nilCatalogId;
   18870         308 :     AssignDumpId(dobjs + 0);
   18871         308 :     dobjs[0].name = pg_strdup("PRE-DATA BOUNDARY");
   18872             : 
   18873         308 :     dobjs[1].objType = DO_POST_DATA_BOUNDARY;
   18874         308 :     dobjs[1].catId = nilCatalogId;
   18875         308 :     AssignDumpId(dobjs + 1);
   18876         308 :     dobjs[1].name = pg_strdup("POST-DATA BOUNDARY");
   18877             : 
   18878         308 :     return dobjs;
   18879             : }
   18880             : 
   18881             : /*
   18882             :  * addBoundaryDependencies - add dependencies as needed to enforce the dump
   18883             :  * section boundaries.
   18884             :  */
   18885             : static void
   18886         308 : addBoundaryDependencies(DumpableObject **dobjs, int numObjs,
   18887             :                         DumpableObject *boundaryObjs)
   18888             : {
   18889         308 :     DumpableObject *preDataBound = boundaryObjs + 0;
   18890         308 :     DumpableObject *postDataBound = boundaryObjs + 1;
   18891             :     int         i;
   18892             : 
   18893     1126600 :     for (i = 0; i < numObjs; i++)
   18894             :     {
   18895     1126292 :         DumpableObject *dobj = dobjs[i];
   18896             : 
   18897             :         /*
   18898             :          * The classification of object types here must match the SECTION_xxx
   18899             :          * values assigned during subsequent ArchiveEntry calls!
   18900             :          */
   18901     1126292 :         switch (dobj->objType)
   18902             :         {
   18903     1055772 :             case DO_NAMESPACE:
   18904             :             case DO_EXTENSION:
   18905             :             case DO_TYPE:
   18906             :             case DO_SHELL_TYPE:
   18907             :             case DO_FUNC:
   18908             :             case DO_AGG:
   18909             :             case DO_OPERATOR:
   18910             :             case DO_ACCESS_METHOD:
   18911             :             case DO_OPCLASS:
   18912             :             case DO_OPFAMILY:
   18913             :             case DO_COLLATION:
   18914             :             case DO_CONVERSION:
   18915             :             case DO_TABLE:
   18916             :             case DO_TABLE_ATTACH:
   18917             :             case DO_ATTRDEF:
   18918             :             case DO_PROCLANG:
   18919             :             case DO_CAST:
   18920             :             case DO_DUMMY_TYPE:
   18921             :             case DO_TSPARSER:
   18922             :             case DO_TSDICT:
   18923             :             case DO_TSTEMPLATE:
   18924             :             case DO_TSCONFIG:
   18925             :             case DO_FDW:
   18926             :             case DO_FOREIGN_SERVER:
   18927             :             case DO_TRANSFORM:
   18928             :                 /* Pre-data objects: must come before the pre-data boundary */
   18929     1055772 :                 addObjectDependency(preDataBound, dobj->dumpId);
   18930     1055772 :                 break;
   18931        8320 :             case DO_TABLE_DATA:
   18932             :             case DO_SEQUENCE_SET:
   18933             :             case DO_LARGE_OBJECT:
   18934             :             case DO_LARGE_OBJECT_DATA:
   18935             :                 /* Data objects: must come between the boundaries */
   18936        8320 :                 addObjectDependency(dobj, preDataBound->dumpId);
   18937        8320 :                 addObjectDependency(postDataBound, dobj->dumpId);
   18938        8320 :                 break;
   18939       10250 :             case DO_INDEX:
   18940             :             case DO_INDEX_ATTACH:
   18941             :             case DO_STATSEXT:
   18942             :             case DO_REFRESH_MATVIEW:
   18943             :             case DO_TRIGGER:
   18944             :             case DO_EVENT_TRIGGER:
   18945             :             case DO_DEFAULT_ACL:
   18946             :             case DO_POLICY:
   18947             :             case DO_PUBLICATION:
   18948             :             case DO_PUBLICATION_REL:
   18949             :             case DO_PUBLICATION_TABLE_IN_SCHEMA:
   18950             :             case DO_SUBSCRIPTION:
   18951             :             case DO_SUBSCRIPTION_REL:
   18952             :                 /* Post-data objects: must come after the post-data boundary */
   18953       10250 :                 addObjectDependency(dobj, postDataBound->dumpId);
   18954       10250 :                 break;
   18955       46850 :             case DO_RULE:
   18956             :                 /* Rules are post-data, but only if dumped separately */
   18957       46850 :                 if (((RuleInfo *) dobj)->separate)
   18958        1162 :                     addObjectDependency(dobj, postDataBound->dumpId);
   18959       46850 :                 break;
   18960        4484 :             case DO_CONSTRAINT:
   18961             :             case DO_FK_CONSTRAINT:
   18962             :                 /* Constraints are post-data, but only if dumped separately */
   18963        4484 :                 if (((ConstraintInfo *) dobj)->separate)
   18964        3218 :                     addObjectDependency(dobj, postDataBound->dumpId);
   18965        4484 :                 break;
   18966         308 :             case DO_PRE_DATA_BOUNDARY:
   18967             :                 /* nothing to do */
   18968         308 :                 break;
   18969         308 :             case DO_POST_DATA_BOUNDARY:
   18970             :                 /* must come after the pre-data boundary */
   18971         308 :                 addObjectDependency(dobj, preDataBound->dumpId);
   18972         308 :                 break;
   18973             :         }
   18974     1126292 :     }
   18975         308 : }
   18976             : 
   18977             : 
   18978             : /*
   18979             :  * BuildArchiveDependencies - create dependency data for archive TOC entries
   18980             :  *
   18981             :  * The raw dependency data obtained by getDependencies() is not terribly
   18982             :  * useful in an archive dump, because in many cases there are dependency
   18983             :  * chains linking through objects that don't appear explicitly in the dump.
   18984             :  * For example, a view will depend on its _RETURN rule while the _RETURN rule
   18985             :  * will depend on other objects --- but the rule will not appear as a separate
   18986             :  * object in the dump.  We need to adjust the view's dependencies to include
   18987             :  * whatever the rule depends on that is included in the dump.
   18988             :  *
   18989             :  * Just to make things more complicated, there are also "special" dependencies
   18990             :  * such as the dependency of a TABLE DATA item on its TABLE, which we must
   18991             :  * not rearrange because pg_restore knows that TABLE DATA only depends on
   18992             :  * its table.  In these cases we must leave the dependencies strictly as-is
   18993             :  * even if they refer to not-to-be-dumped objects.
   18994             :  *
   18995             :  * To handle this, the convention is that "special" dependencies are created
   18996             :  * during ArchiveEntry calls, and an archive TOC item that has any such
   18997             :  * entries will not be touched here.  Otherwise, we recursively search the
   18998             :  * DumpableObject data structures to build the correct dependencies for each
   18999             :  * archive TOC item.
   19000             :  */
   19001             : static void
   19002          62 : BuildArchiveDependencies(Archive *fout)
   19003             : {
   19004          62 :     ArchiveHandle *AH = (ArchiveHandle *) fout;
   19005             :     TocEntry   *te;
   19006             : 
   19007             :     /* Scan all TOC entries in the archive */
   19008        9720 :     for (te = AH->toc->next; te != AH->toc; te = te->next)
   19009             :     {
   19010             :         DumpableObject *dobj;
   19011             :         DumpId     *dependencies;
   19012             :         int         nDeps;
   19013             :         int         allocDeps;
   19014             : 
   19015             :         /* No need to process entries that will not be dumped */
   19016        9658 :         if (te->reqs == 0)
   19017        2954 :             continue;
   19018             :         /* Ignore entries that already have "special" dependencies */
   19019        9652 :         if (te->nDeps > 0)
   19020        2420 :             continue;
   19021             :         /* Otherwise, look up the item's original DumpableObject, if any */
   19022        7232 :         dobj = findObjectByDumpId(te->dumpId);
   19023        7232 :         if (dobj == NULL)
   19024         318 :             continue;
   19025             :         /* No work if it has no dependencies */
   19026        6914 :         if (dobj->nDeps <= 0)
   19027         210 :             continue;
   19028             :         /* Set up work array */
   19029        6704 :         allocDeps = 64;
   19030        6704 :         dependencies = (DumpId *) pg_malloc(allocDeps * sizeof(DumpId));
   19031        6704 :         nDeps = 0;
   19032             :         /* Recursively find all dumpable dependencies */
   19033        6704 :         findDumpableDependencies(AH, dobj,
   19034             :                                  &dependencies, &nDeps, &allocDeps);
   19035             :         /* And save 'em ... */
   19036        6704 :         if (nDeps > 0)
   19037             :         {
   19038        5102 :             dependencies = (DumpId *) pg_realloc(dependencies,
   19039             :                                                  nDeps * sizeof(DumpId));
   19040        5102 :             te->dependencies = dependencies;
   19041        5102 :             te->nDeps = nDeps;
   19042             :         }
   19043             :         else
   19044        1602 :             free(dependencies);
   19045             :     }
   19046          62 : }
   19047             : 
   19048             : /* Recursive search subroutine for BuildArchiveDependencies */
   19049             : static void
   19050       16448 : findDumpableDependencies(ArchiveHandle *AH, const DumpableObject *dobj,
   19051             :                          DumpId **dependencies, int *nDeps, int *allocDeps)
   19052             : {
   19053             :     int         i;
   19054             : 
   19055             :     /*
   19056             :      * Ignore section boundary objects: if we search through them, we'll
   19057             :      * report lots of bogus dependencies.
   19058             :      */
   19059       16448 :     if (dobj->objType == DO_PRE_DATA_BOUNDARY ||
   19060       16410 :         dobj->objType == DO_POST_DATA_BOUNDARY)
   19061        2924 :         return;
   19062             : 
   19063       34256 :     for (i = 0; i < dobj->nDeps; i++)
   19064             :     {
   19065       20732 :         DumpId      depid = dobj->dependencies[i];
   19066             : 
   19067       20732 :         if (TocIDRequired(AH, depid) != 0)
   19068             :         {
   19069             :             /* Object will be dumped, so just reference it as a dependency */
   19070       10988 :             if (*nDeps >= *allocDeps)
   19071             :             {
   19072           0 :                 *allocDeps *= 2;
   19073           0 :                 *dependencies = (DumpId *) pg_realloc(*dependencies,
   19074           0 :                                                       *allocDeps * sizeof(DumpId));
   19075             :             }
   19076       10988 :             (*dependencies)[*nDeps] = depid;
   19077       10988 :             (*nDeps)++;
   19078             :         }
   19079             :         else
   19080             :         {
   19081             :             /*
   19082             :              * Object will not be dumped, so recursively consider its deps. We
   19083             :              * rely on the assumption that sortDumpableObjects already broke
   19084             :              * any dependency loops, else we might recurse infinitely.
   19085             :              */
   19086        9744 :             DumpableObject *otherdobj = findObjectByDumpId(depid);
   19087             : 
   19088        9744 :             if (otherdobj)
   19089        9744 :                 findDumpableDependencies(AH, otherdobj,
   19090             :                                          dependencies, nDeps, allocDeps);
   19091             :         }
   19092             :     }
   19093             : }
   19094             : 
   19095             : 
   19096             : /*
   19097             :  * getFormattedTypeName - retrieve a nicely-formatted type name for the
   19098             :  * given type OID.
   19099             :  *
   19100             :  * This does not guarantee to schema-qualify the output, so it should not
   19101             :  * be used to create the target object name for CREATE or ALTER commands.
   19102             :  *
   19103             :  * Note that the result is cached and must not be freed by the caller.
   19104             :  */
   19105             : static const char *
   19106        4624 : getFormattedTypeName(Archive *fout, Oid oid, OidOptions opts)
   19107             : {
   19108             :     TypeInfo   *typeInfo;
   19109             :     char       *result;
   19110             :     PQExpBuffer query;
   19111             :     PGresult   *res;
   19112             : 
   19113        4624 :     if (oid == 0)
   19114             :     {
   19115           0 :         if ((opts & zeroAsStar) != 0)
   19116           0 :             return "*";
   19117           0 :         else if ((opts & zeroAsNone) != 0)
   19118           0 :             return "NONE";
   19119             :     }
   19120             : 
   19121             :     /* see if we have the result cached in the type's TypeInfo record */
   19122        4624 :     typeInfo = findTypeByOid(oid);
   19123        4624 :     if (typeInfo && typeInfo->ftypname)
   19124        3676 :         return typeInfo->ftypname;
   19125             : 
   19126         948 :     query = createPQExpBuffer();
   19127         948 :     appendPQExpBuffer(query, "SELECT pg_catalog.format_type('%u'::pg_catalog.oid, NULL)",
   19128             :                       oid);
   19129             : 
   19130         948 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   19131             : 
   19132             :     /* result of format_type is already quoted */
   19133         948 :     result = pg_strdup(PQgetvalue(res, 0, 0));
   19134             : 
   19135         948 :     PQclear(res);
   19136         948 :     destroyPQExpBuffer(query);
   19137             : 
   19138             :     /*
   19139             :      * Cache the result for re-use in later requests, if possible.  If we
   19140             :      * don't have a TypeInfo for the type, the string will be leaked once the
   19141             :      * caller is done with it ... but that case really should not happen, so
   19142             :      * leaking if it does seems acceptable.
   19143             :      */
   19144         948 :     if (typeInfo)
   19145         948 :         typeInfo->ftypname = result;
   19146             : 
   19147         948 :     return result;
   19148             : }
   19149             : 
   19150             : /*
   19151             :  * Return a column list clause for the given relation.
   19152             :  *
   19153             :  * Special case: if there are no undropped columns in the relation, return
   19154             :  * "", not an invalid "()" column list.
   19155             :  */
   19156             : static const char *
   19157       14188 : fmtCopyColumnList(const TableInfo *ti, PQExpBuffer buffer)
   19158             : {
   19159       14188 :     int         numatts = ti->numatts;
   19160       14188 :     char      **attnames = ti->attnames;
   19161       14188 :     bool       *attisdropped = ti->attisdropped;
   19162       14188 :     char       *attgenerated = ti->attgenerated;
   19163             :     bool        needComma;
   19164             :     int         i;
   19165             : 
   19166       14188 :     appendPQExpBufferChar(buffer, '(');
   19167       14188 :     needComma = false;
   19168       72572 :     for (i = 0; i < numatts; i++)
   19169             :     {
   19170       58384 :         if (attisdropped[i])
   19171        1116 :             continue;
   19172       57268 :         if (attgenerated[i])
   19173        1180 :             continue;
   19174       56088 :         if (needComma)
   19175       42348 :             appendPQExpBufferStr(buffer, ", ");
   19176       56088 :         appendPQExpBufferStr(buffer, fmtId(attnames[i]));
   19177       56088 :         needComma = true;
   19178             :     }
   19179             : 
   19180       14188 :     if (!needComma)
   19181         448 :         return "";                /* no undropped columns */
   19182             : 
   19183       13740 :     appendPQExpBufferChar(buffer, ')');
   19184       13740 :     return buffer->data;
   19185             : }
   19186             : 
   19187             : /*
   19188             :  * Check if a reloptions array is nonempty.
   19189             :  */
   19190             : static bool
   19191       24280 : nonemptyReloptions(const char *reloptions)
   19192             : {
   19193             :     /* Don't want to print it if it's just "{}" */
   19194       24280 :     return (reloptions != NULL && strlen(reloptions) > 2);
   19195             : }
   19196             : 
   19197             : /*
   19198             :  * Format a reloptions array and append it to the given buffer.
   19199             :  *
   19200             :  * "prefix" is prepended to the option names; typically it's "" or "toast.".
   19201             :  */
   19202             : static void
   19203         420 : appendReloptionsArrayAH(PQExpBuffer buffer, const char *reloptions,
   19204             :                         const char *prefix, Archive *fout)
   19205             : {
   19206             :     bool        res;
   19207             : 
   19208         420 :     res = appendReloptionsArray(buffer, reloptions, prefix, fout->encoding,
   19209         420 :                                 fout->std_strings);
   19210         420 :     if (!res)
   19211           0 :         pg_log_warning("could not parse %s array", "reloptions");
   19212         420 : }
   19213             : 
   19214             : /*
   19215             :  * read_dump_filters - retrieve object identifier patterns from file
   19216             :  *
   19217             :  * Parse the specified filter file for include and exclude patterns, and add
   19218             :  * them to the relevant lists.  If the filename is "-" then filters will be
   19219             :  * read from STDIN rather than a file.
   19220             :  */
   19221             : static void
   19222          52 : read_dump_filters(const char *filename, DumpOptions *dopt)
   19223             : {
   19224             :     FilterStateData fstate;
   19225             :     char       *objname;
   19226             :     FilterCommandType comtype;
   19227             :     FilterObjectType objtype;
   19228             : 
   19229          52 :     filter_init(&fstate, filename, exit_nicely);
   19230             : 
   19231         116 :     while (filter_read_item(&fstate, &objname, &comtype, &objtype))
   19232             :     {
   19233          66 :         if (comtype == FILTER_COMMAND_TYPE_INCLUDE)
   19234             :         {
   19235          34 :             switch (objtype)
   19236             :             {
   19237           0 :                 case FILTER_OBJECT_TYPE_NONE:
   19238           0 :                     break;
   19239           0 :                 case FILTER_OBJECT_TYPE_DATABASE:
   19240             :                 case FILTER_OBJECT_TYPE_FUNCTION:
   19241             :                 case FILTER_OBJECT_TYPE_INDEX:
   19242             :                 case FILTER_OBJECT_TYPE_TABLE_DATA:
   19243             :                 case FILTER_OBJECT_TYPE_TABLE_DATA_AND_CHILDREN:
   19244             :                 case FILTER_OBJECT_TYPE_TRIGGER:
   19245           0 :                     pg_log_filter_error(&fstate, _("%s filter for \"%s\" is not allowed"),
   19246             :                                         "include",
   19247             :                                         filter_object_type_name(objtype));
   19248           0 :                     exit_nicely(1);
   19249             :                     break;      /* unreachable */
   19250             : 
   19251           2 :                 case FILTER_OBJECT_TYPE_EXTENSION:
   19252           2 :                     simple_string_list_append(&extension_include_patterns, objname);
   19253           2 :                     break;
   19254           2 :                 case FILTER_OBJECT_TYPE_FOREIGN_DATA:
   19255           2 :                     simple_string_list_append(&foreign_servers_include_patterns, objname);
   19256           2 :                     break;
   19257           2 :                 case FILTER_OBJECT_TYPE_SCHEMA:
   19258           2 :                     simple_string_list_append(&schema_include_patterns, objname);
   19259           2 :                     dopt->include_everything = false;
   19260           2 :                     break;
   19261          26 :                 case FILTER_OBJECT_TYPE_TABLE:
   19262          26 :                     simple_string_list_append(&table_include_patterns, objname);
   19263          26 :                     dopt->include_everything = false;
   19264          26 :                     break;
   19265           2 :                 case FILTER_OBJECT_TYPE_TABLE_AND_CHILDREN:
   19266           2 :                     simple_string_list_append(&table_include_patterns_and_children,
   19267             :                                               objname);
   19268           2 :                     dopt->include_everything = false;
   19269           2 :                     break;
   19270             :             }
   19271          34 :         }
   19272          32 :         else if (comtype == FILTER_COMMAND_TYPE_EXCLUDE)
   19273             :         {
   19274          18 :             switch (objtype)
   19275             :             {
   19276           0 :                 case FILTER_OBJECT_TYPE_NONE:
   19277           0 :                     break;
   19278           2 :                 case FILTER_OBJECT_TYPE_DATABASE:
   19279             :                 case FILTER_OBJECT_TYPE_FUNCTION:
   19280             :                 case FILTER_OBJECT_TYPE_INDEX:
   19281             :                 case FILTER_OBJECT_TYPE_TRIGGER:
   19282             :                 case FILTER_OBJECT_TYPE_FOREIGN_DATA:
   19283           2 :                     pg_log_filter_error(&fstate, _("%s filter for \"%s\" is not allowed"),
   19284             :                                         "exclude",
   19285             :                                         filter_object_type_name(objtype));
   19286           2 :                     exit_nicely(1);
   19287             :                     break;
   19288             : 
   19289           2 :                 case FILTER_OBJECT_TYPE_EXTENSION:
   19290           2 :                     simple_string_list_append(&extension_exclude_patterns, objname);
   19291           2 :                     break;
   19292           2 :                 case FILTER_OBJECT_TYPE_TABLE_DATA:
   19293           2 :                     simple_string_list_append(&tabledata_exclude_patterns,
   19294             :                                               objname);
   19295           2 :                     break;
   19296           2 :                 case FILTER_OBJECT_TYPE_TABLE_DATA_AND_CHILDREN:
   19297           2 :                     simple_string_list_append(&tabledata_exclude_patterns_and_children,
   19298             :                                               objname);
   19299           2 :                     break;
   19300           4 :                 case FILTER_OBJECT_TYPE_SCHEMA:
   19301           4 :                     simple_string_list_append(&schema_exclude_patterns, objname);
   19302           4 :                     break;
   19303           4 :                 case FILTER_OBJECT_TYPE_TABLE:
   19304           4 :                     simple_string_list_append(&table_exclude_patterns, objname);
   19305           4 :                     break;
   19306           2 :                 case FILTER_OBJECT_TYPE_TABLE_AND_CHILDREN:
   19307           2 :                     simple_string_list_append(&table_exclude_patterns_and_children,
   19308             :                                               objname);
   19309           2 :                     break;
   19310             :             }
   19311          16 :         }
   19312             :         else
   19313             :         {
   19314             :             Assert(comtype == FILTER_COMMAND_TYPE_NONE);
   19315             :             Assert(objtype == FILTER_OBJECT_TYPE_NONE);
   19316             :         }
   19317             : 
   19318          64 :         if (objname)
   19319          50 :             free(objname);
   19320             :     }
   19321             : 
   19322          44 :     filter_free(&fstate);
   19323          44 : }

Generated by: LCOV version 1.14