LCOV - code coverage report
Current view: top level - src/bin/pg_dump - pg_dump.c (source / functions) Coverage Total Hit
Test: PostgreSQL 19devel Lines: 90.9 % 8539 7766
Test Date: 2026-04-22 13:16:23 Functions: 98.9 % 189 187
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-2026, PostgreSQL Global Development Group
       8              :  * Portions Copyright (c) 1994, Regents of the University of California
       9              :  *
      10              :  *  pg_dump will read the system catalogs in a database and dump out a
      11              :  *  script that reproduces the schema in terms of SQL that is understood
      12              :  *  by PostgreSQL
      13              :  *
      14              :  *  Note that pg_dump runs in a transaction-snapshot mode transaction,
      15              :  *  so it sees a consistent snapshot of the database including system
      16              :  *  catalogs. However, it relies in part on various specialized backend
      17              :  *  functions like pg_get_indexdef(), and those things tend to look at
      18              :  *  the currently committed state.  So it is possible to get 'cache
      19              :  *  lookup failed' error if someone performs DDL changes while a dump is
      20              :  *  happening. The window for this sort of thing is from the acquisition
      21              :  *  of the transaction snapshot to getSchemaData() (when pg_dump acquires
      22              :  *  AccessShareLock on every table it intends to dump). It isn't very large,
      23              :  *  but it can happen.
      24              :  *
      25              :  *  http://archives.postgresql.org/pgsql-bugs/2010-02/msg00187.php
      26              :  *
      27              :  * IDENTIFICATION
      28              :  *    src/bin/pg_dump/pg_dump.c
      29              :  *
      30              :  *-------------------------------------------------------------------------
      31              :  */
      32              : #include "postgres_fe.h"
      33              : 
      34              : #include <unistd.h>
      35              : #include <ctype.h>
      36              : #include <limits.h>
      37              : #ifdef HAVE_TERMIOS_H
      38              : #include <termios.h>
      39              : #endif
      40              : 
      41              : #include "access/attnum.h"
      42              : #include "access/sysattr.h"
      43              : #include "access/transam.h"
      44              : #include "catalog/pg_aggregate_d.h"
      45              : #include "catalog/pg_am_d.h"
      46              : #include "catalog/pg_attribute_d.h"
      47              : #include "catalog/pg_authid_d.h"
      48              : #include "catalog/pg_cast_d.h"
      49              : #include "catalog/pg_class_d.h"
      50              : #include "catalog/pg_constraint_d.h"
      51              : #include "catalog/pg_default_acl_d.h"
      52              : #include "catalog/pg_largeobject_d.h"
      53              : #include "catalog/pg_largeobject_metadata_d.h"
      54              : #include "catalog/pg_proc_d.h"
      55              : #include "catalog/pg_publication_d.h"
      56              : #include "catalog/pg_shdepend_d.h"
      57              : #include "catalog/pg_subscription_d.h"
      58              : #include "catalog/pg_type_d.h"
      59              : #include "common/connect.h"
      60              : #include "common/int.h"
      61              : #include "common/relpath.h"
      62              : #include "common/shortest_dec.h"
      63              : #include "compress_io.h"
      64              : #include "dumputils.h"
      65              : #include "fe_utils/option_utils.h"
      66              : #include "fe_utils/string_utils.h"
      67              : #include "filter.h"
      68              : #include "getopt_long.h"
      69              : #include "libpq/libpq-fs.h"
      70              : #include "parallel.h"
      71              : #include "pg_backup_db.h"
      72              : #include "pg_backup_utils.h"
      73              : #include "pg_dump.h"
      74              : #include "statistics/statistics_format.h"
      75              : #include "storage/block.h"
      76              : 
      77              : typedef struct
      78              : {
      79              :     Oid         roleoid;        /* role's OID */
      80              :     const char *rolename;       /* role's name */
      81              : } RoleNameItem;
      82              : 
      83              : typedef struct
      84              : {
      85              :     const char *descr;          /* comment for an object */
      86              :     Oid         classoid;       /* object class (catalog OID) */
      87              :     Oid         objoid;         /* object OID */
      88              :     int         objsubid;       /* subobject (table column #) */
      89              : } CommentItem;
      90              : 
      91              : typedef struct
      92              : {
      93              :     const char *provider;       /* label provider of this security label */
      94              :     const char *label;          /* security label for an object */
      95              :     Oid         classoid;       /* object class (catalog OID) */
      96              :     Oid         objoid;         /* object OID */
      97              :     int         objsubid;       /* subobject (table column #) */
      98              : } SecLabelItem;
      99              : 
     100              : typedef struct
     101              : {
     102              :     Oid         oid;            /* object OID */
     103              :     char        relkind;        /* object kind */
     104              :     RelFileNumber relfilenumber;    /* object filenode */
     105              :     Oid         toast_oid;      /* toast table OID */
     106              :     RelFileNumber toast_relfilenumber;  /* toast table filenode */
     107              :     Oid         toast_index_oid;    /* toast table index OID */
     108              :     RelFileNumber toast_index_relfilenumber;    /* toast table index filenode */
     109              : } BinaryUpgradeClassOidItem;
     110              : 
     111              : /* sequence types */
     112              : typedef enum SeqType
     113              : {
     114              :     SEQTYPE_SMALLINT,
     115              :     SEQTYPE_INTEGER,
     116              :     SEQTYPE_BIGINT,
     117              : } SeqType;
     118              : 
     119              : static const char *const SeqTypeNames[] =
     120              : {
     121              :     [SEQTYPE_SMALLINT] = "smallint",
     122              :     [SEQTYPE_INTEGER] = "integer",
     123              :     [SEQTYPE_BIGINT] = "bigint",
     124              : };
     125              : 
     126              : StaticAssertDecl(lengthof(SeqTypeNames) == (SEQTYPE_BIGINT + 1),
     127              :                  "array length mismatch");
     128              : 
     129              : typedef struct
     130              : {
     131              :     Oid         oid;            /* sequence OID */
     132              :     SeqType     seqtype;        /* data type of sequence */
     133              :     bool        cycled;         /* whether sequence cycles */
     134              :     int64       minv;           /* minimum value */
     135              :     int64       maxv;           /* maximum value */
     136              :     int64       startv;         /* start value */
     137              :     int64       incby;          /* increment value */
     138              :     int64       cache;          /* cache size */
     139              :     int64       last_value;     /* last value of sequence */
     140              :     bool        is_called;      /* whether nextval advances before returning */
     141              :     bool        null_seqtuple;  /* did pg_get_sequence_data return nulls? */
     142              : } SequenceItem;
     143              : 
     144              : typedef enum OidOptions
     145              : {
     146              :     zeroIsError = 1,
     147              :     zeroAsStar = 2,
     148              :     zeroAsNone = 4,
     149              : } OidOptions;
     150              : 
     151              : /* global decls */
     152              : static bool dosync = true;      /* Issue fsync() to make dump durable on disk. */
     153              : 
     154              : static Oid  g_last_builtin_oid; /* value of the last builtin oid */
     155              : 
     156              : /* The specified names/patterns should to match at least one entity */
     157              : static int  strict_names = 0;
     158              : 
     159              : static pg_compress_algorithm compression_algorithm = PG_COMPRESSION_NONE;
     160              : 
     161              : /*
     162              :  * Object inclusion/exclusion lists
     163              :  *
     164              :  * The string lists record the patterns given by command-line switches,
     165              :  * which we then convert to lists of OIDs of matching objects.
     166              :  */
     167              : static SimpleStringList schema_include_patterns = {NULL, NULL};
     168              : static SimpleOidList schema_include_oids = {NULL, NULL};
     169              : static SimpleStringList schema_exclude_patterns = {NULL, NULL};
     170              : static SimpleOidList schema_exclude_oids = {NULL, NULL};
     171              : 
     172              : static SimpleStringList table_include_patterns = {NULL, NULL};
     173              : static SimpleStringList table_include_patterns_and_children = {NULL, NULL};
     174              : static SimpleOidList table_include_oids = {NULL, NULL};
     175              : static SimpleStringList table_exclude_patterns = {NULL, NULL};
     176              : static SimpleStringList table_exclude_patterns_and_children = {NULL, NULL};
     177              : static SimpleOidList table_exclude_oids = {NULL, NULL};
     178              : static SimpleStringList tabledata_exclude_patterns = {NULL, NULL};
     179              : static SimpleStringList tabledata_exclude_patterns_and_children = {NULL, NULL};
     180              : static SimpleOidList tabledata_exclude_oids = {NULL, NULL};
     181              : 
     182              : static SimpleStringList foreign_servers_include_patterns = {NULL, NULL};
     183              : static SimpleOidList foreign_servers_include_oids = {NULL, NULL};
     184              : 
     185              : static SimpleStringList extension_include_patterns = {NULL, NULL};
     186              : static SimpleOidList extension_include_oids = {NULL, NULL};
     187              : 
     188              : static SimpleStringList extension_exclude_patterns = {NULL, NULL};
     189              : static SimpleOidList extension_exclude_oids = {NULL, NULL};
     190              : 
     191              : static const CatalogId nilCatalogId = {0, 0};
     192              : 
     193              : /* override for standard extra_float_digits setting */
     194              : static bool have_extra_float_digits = false;
     195              : static int  extra_float_digits;
     196              : 
     197              : /* sorted table of role names */
     198              : static RoleNameItem *rolenames = NULL;
     199              : static int  nrolenames = 0;
     200              : 
     201              : /* sorted table of comments */
     202              : static CommentItem *comments = NULL;
     203              : static int  ncomments = 0;
     204              : 
     205              : /* sorted table of security labels */
     206              : static SecLabelItem *seclabels = NULL;
     207              : static int  nseclabels = 0;
     208              : 
     209              : /* sorted table of pg_class information for binary upgrade */
     210              : static BinaryUpgradeClassOidItem *binaryUpgradeClassOids = NULL;
     211              : static int  nbinaryUpgradeClassOids = 0;
     212              : 
     213              : /* sorted table of sequences */
     214              : static SequenceItem *sequences = NULL;
     215              : static int  nsequences = 0;
     216              : 
     217              : /* Maximum number of relations to fetch in a fetchAttributeStats() call. */
     218              : #define MAX_ATTR_STATS_RELS 64
     219              : 
     220              : /*
     221              :  * The default number of rows per INSERT when
     222              :  * --inserts is specified without --rows-per-insert
     223              :  */
     224              : #define DUMP_DEFAULT_ROWS_PER_INSERT 1
     225              : 
     226              : /*
     227              :  * Maximum number of large objects to group into a single ArchiveEntry.
     228              :  * At some point we might want to make this user-controllable, but for now
     229              :  * a hard-wired setting will suffice.
     230              :  */
     231              : #define MAX_BLOBS_PER_ARCHIVE_ENTRY 1000
     232              : 
     233              : /*
     234              :  * Macro for producing quoted, schema-qualified name of a dumpable object.
     235              :  */
     236              : #define fmtQualifiedDumpable(obj) \
     237              :     fmtQualifiedId((obj)->dobj.namespace->dobj.name, \
     238              :                    (obj)->dobj.name)
     239              : 
     240              : static void help(const char *progname);
     241              : static void setup_connection(Archive *AH,
     242              :                              const char *dumpencoding, const char *dumpsnapshot,
     243              :                              char *use_role);
     244              : static ArchiveFormat parseArchiveFormat(const char *format, ArchiveMode *mode);
     245              : static void expand_schema_name_patterns(Archive *fout,
     246              :                                         SimpleStringList *patterns,
     247              :                                         SimpleOidList *oids,
     248              :                                         bool strict_names);
     249              : static void expand_extension_name_patterns(Archive *fout,
     250              :                                            SimpleStringList *patterns,
     251              :                                            SimpleOidList *oids,
     252              :                                            bool strict_names);
     253              : static void expand_foreign_server_name_patterns(Archive *fout,
     254              :                                                 SimpleStringList *patterns,
     255              :                                                 SimpleOidList *oids);
     256              : static void expand_table_name_patterns(Archive *fout,
     257              :                                        SimpleStringList *patterns,
     258              :                                        SimpleOidList *oids,
     259              :                                        bool strict_names,
     260              :                                        bool with_child_tables);
     261              : static void prohibit_crossdb_refs(PGconn *conn, const char *dbname,
     262              :                                   const char *pattern);
     263              : 
     264              : static NamespaceInfo *findNamespace(Oid nsoid);
     265              : static void dumpTableData(Archive *fout, const TableDataInfo *tdinfo);
     266              : static void refreshMatViewData(Archive *fout, const TableDataInfo *tdinfo);
     267              : static const char *getRoleName(const char *roleoid_str);
     268              : static void collectRoleNames(Archive *fout);
     269              : static void getAdditionalACLs(Archive *fout);
     270              : static void dumpCommentExtended(Archive *fout, const char *type,
     271              :                                 const char *name, const char *namespace,
     272              :                                 const char *owner, CatalogId catalogId,
     273              :                                 int subid, DumpId dumpId,
     274              :                                 const char *initdb_comment);
     275              : static inline void dumpComment(Archive *fout, const char *type,
     276              :                                const char *name, const char *namespace,
     277              :                                const char *owner, CatalogId catalogId,
     278              :                                int subid, DumpId dumpId);
     279              : static int  findComments(Oid classoid, Oid objoid, CommentItem **items);
     280              : static void collectComments(Archive *fout);
     281              : static void dumpSecLabel(Archive *fout, const char *type, const char *name,
     282              :                          const char *namespace, const char *owner,
     283              :                          CatalogId catalogId, int subid, DumpId dumpId);
     284              : static int  findSecLabels(Oid classoid, Oid objoid, SecLabelItem **items);
     285              : static void collectSecLabels(Archive *fout);
     286              : static void dumpDumpableObject(Archive *fout, DumpableObject *dobj);
     287              : static void dumpNamespace(Archive *fout, const NamespaceInfo *nspinfo);
     288              : static void dumpExtension(Archive *fout, const ExtensionInfo *extinfo);
     289              : static void dumpType(Archive *fout, const TypeInfo *tyinfo);
     290              : static void dumpBaseType(Archive *fout, const TypeInfo *tyinfo);
     291              : static void dumpEnumType(Archive *fout, const TypeInfo *tyinfo);
     292              : static void dumpRangeType(Archive *fout, const TypeInfo *tyinfo);
     293              : static void dumpUndefinedType(Archive *fout, const TypeInfo *tyinfo);
     294              : static void dumpDomain(Archive *fout, const TypeInfo *tyinfo);
     295              : static void dumpCompositeType(Archive *fout, const TypeInfo *tyinfo);
     296              : static void dumpCompositeTypeColComments(Archive *fout, const TypeInfo *tyinfo,
     297              :                                          PGresult *res);
     298              : static void dumpShellType(Archive *fout, const ShellTypeInfo *stinfo);
     299              : static void dumpProcLang(Archive *fout, const ProcLangInfo *plang);
     300              : static void dumpFunc(Archive *fout, const FuncInfo *finfo);
     301              : static void dumpCast(Archive *fout, const CastInfo *cast);
     302              : static void dumpTransform(Archive *fout, const TransformInfo *transform);
     303              : static void dumpOpr(Archive *fout, const OprInfo *oprinfo);
     304              : static void dumpAccessMethod(Archive *fout, const AccessMethodInfo *aminfo);
     305              : static void dumpOpclass(Archive *fout, const OpclassInfo *opcinfo);
     306              : static void dumpOpfamily(Archive *fout, const OpfamilyInfo *opfinfo);
     307              : static void dumpCollation(Archive *fout, const CollInfo *collinfo);
     308              : static void dumpConversion(Archive *fout, const ConvInfo *convinfo);
     309              : static void dumpRule(Archive *fout, const RuleInfo *rinfo);
     310              : static void dumpAgg(Archive *fout, const AggInfo *agginfo);
     311              : static void dumpTrigger(Archive *fout, const TriggerInfo *tginfo);
     312              : static void dumpEventTrigger(Archive *fout, const EventTriggerInfo *evtinfo);
     313              : static void dumpTable(Archive *fout, const TableInfo *tbinfo);
     314              : static void dumpTableSchema(Archive *fout, const TableInfo *tbinfo);
     315              : static void dumpTableAttach(Archive *fout, const TableAttachInfo *attachinfo);
     316              : static void dumpAttrDef(Archive *fout, const AttrDefInfo *adinfo);
     317              : static void collectSequences(Archive *fout);
     318              : static void dumpSequence(Archive *fout, const TableInfo *tbinfo);
     319              : static void dumpSequenceData(Archive *fout, const TableDataInfo *tdinfo);
     320              : static void dumpIndex(Archive *fout, const IndxInfo *indxinfo);
     321              : static void dumpIndexAttach(Archive *fout, const IndexAttachInfo *attachinfo);
     322              : static void dumpStatisticsExt(Archive *fout, const StatsExtInfo *statsextinfo);
     323              : static void dumpStatisticsExtStats(Archive *fout, const StatsExtInfo *statsextinfo);
     324              : static void dumpConstraint(Archive *fout, const ConstraintInfo *coninfo);
     325              : static void dumpTableConstraintComment(Archive *fout, const ConstraintInfo *coninfo);
     326              : static void dumpTSParser(Archive *fout, const TSParserInfo *prsinfo);
     327              : static void dumpTSDictionary(Archive *fout, const TSDictInfo *dictinfo);
     328              : static void dumpTSTemplate(Archive *fout, const TSTemplateInfo *tmplinfo);
     329              : static void dumpTSConfig(Archive *fout, const TSConfigInfo *cfginfo);
     330              : static void dumpForeignDataWrapper(Archive *fout, const FdwInfo *fdwinfo);
     331              : static void dumpForeignServer(Archive *fout, const ForeignServerInfo *srvinfo);
     332              : static void dumpUserMappings(Archive *fout,
     333              :                              const char *servername, const char *namespace,
     334              :                              const char *owner, CatalogId catalogId, DumpId dumpId);
     335              : static void dumpDefaultACL(Archive *fout, const DefaultACLInfo *daclinfo);
     336              : 
     337              : static DumpId dumpACL(Archive *fout, DumpId objDumpId, DumpId altDumpId,
     338              :                       const char *type, const char *name, const char *subname,
     339              :                       const char *nspname, const char *tag, const char *owner,
     340              :                       const DumpableAcl *dacl);
     341              : 
     342              : static void getDependencies(Archive *fout);
     343              : static void BuildArchiveDependencies(Archive *fout);
     344              : static void findDumpableDependencies(ArchiveHandle *AH, const DumpableObject *dobj,
     345              :                                      DumpId **dependencies, int *nDeps, int *allocDeps);
     346              : 
     347              : static DumpableObject *createBoundaryObjects(void);
     348              : static void addBoundaryDependencies(DumpableObject **dobjs, int numObjs,
     349              :                                     DumpableObject *boundaryObjs);
     350              : 
     351              : static void addConstrChildIdxDeps(DumpableObject *dobj, const IndxInfo *refidx);
     352              : static void getDomainConstraints(Archive *fout, TypeInfo *tyinfo);
     353              : static void getTableData(DumpOptions *dopt, TableInfo *tblinfo, int numTables, char relkind);
     354              : static void makeTableDataInfo(DumpOptions *dopt, TableInfo *tbinfo);
     355              : static void buildMatViewRefreshDependencies(Archive *fout);
     356              : static void getTableDataFKConstraints(void);
     357              : static void determineNotNullFlags(Archive *fout, PGresult *res, int r,
     358              :                                   TableInfo *tbinfo, int j,
     359              :                                   int i_notnull_name,
     360              :                                   int i_notnull_comment,
     361              :                                   int i_notnull_invalidoid,
     362              :                                   int i_notnull_noinherit,
     363              :                                   int i_notnull_islocal,
     364              :                                   PQExpBuffer *invalidnotnulloids);
     365              : static char *format_function_arguments(const FuncInfo *finfo, const char *funcargs,
     366              :                                        bool is_agg);
     367              : static char *format_function_signature(Archive *fout,
     368              :                                        const FuncInfo *finfo, bool honor_quotes);
     369              : static char *convertRegProcReference(const char *proc);
     370              : static char *getFormattedOperatorName(const char *oproid);
     371              : static char *convertTSFunction(Archive *fout, Oid funcOid);
     372              : static const char *getFormattedTypeName(Archive *fout, Oid oid, OidOptions opts);
     373              : static void getLOs(Archive *fout);
     374              : static void dumpLO(Archive *fout, const LoInfo *loinfo);
     375              : static int  dumpLOs(Archive *fout, const void *arg);
     376              : static void dumpPolicy(Archive *fout, const PolicyInfo *polinfo);
     377              : static void dumpPublication(Archive *fout, const PublicationInfo *pubinfo);
     378              : static void dumpPublicationTable(Archive *fout, const PublicationRelInfo *pubrinfo);
     379              : static void dumpSubscription(Archive *fout, const SubscriptionInfo *subinfo);
     380              : static void dumpSubscriptionTable(Archive *fout, const SubRelInfo *subrinfo);
     381              : static void dumpDatabase(Archive *fout);
     382              : static void dumpDatabaseConfig(Archive *AH, PQExpBuffer outbuf,
     383              :                                const char *dbname, Oid dboid);
     384              : static void dumpEncoding(Archive *AH);
     385              : static void dumpStdStrings(Archive *AH);
     386              : static void dumpSearchPath(Archive *AH);
     387              : static void binary_upgrade_set_type_oids_by_type_oid(Archive *fout,
     388              :                                                      PQExpBuffer upgrade_buffer,
     389              :                                                      Oid pg_type_oid,
     390              :                                                      bool force_array_type,
     391              :                                                      bool include_multirange_type);
     392              : static void binary_upgrade_set_type_oids_by_rel(Archive *fout,
     393              :                                                 PQExpBuffer upgrade_buffer,
     394              :                                                 const TableInfo *tbinfo);
     395              : static void collectBinaryUpgradeClassOids(Archive *fout);
     396              : static void binary_upgrade_set_pg_class_oids(Archive *fout,
     397              :                                              PQExpBuffer upgrade_buffer,
     398              :                                              Oid pg_class_oid);
     399              : static void binary_upgrade_extension_member(PQExpBuffer upgrade_buffer,
     400              :                                             const DumpableObject *dobj,
     401              :                                             const char *objtype,
     402              :                                             const char *objname,
     403              :                                             const char *objnamespace);
     404              : static const char *getAttrName(int attrnum, const TableInfo *tblInfo);
     405              : static const char *fmtCopyColumnList(const TableInfo *ti, PQExpBuffer buffer);
     406              : static bool nonemptyReloptions(const char *reloptions);
     407              : static void appendReloptionsArrayAH(PQExpBuffer buffer, const char *reloptions,
     408              :                                     const char *prefix, Archive *fout);
     409              : static char *get_synchronized_snapshot(Archive *fout);
     410              : static void set_restrict_relation_kind(Archive *AH, const char *value);
     411              : static void setupDumpWorker(Archive *AH);
     412              : static TableInfo *getRootTableInfo(const TableInfo *tbinfo);
     413              : static bool forcePartitionRootLoad(const TableInfo *tbinfo);
     414              : static void read_dump_filters(const char *filename, DumpOptions *dopt);
     415              : 
     416              : 
     417              : int
     418          389 : main(int argc, char **argv)
     419              : {
     420              :     int         c;
     421          389 :     const char *filename = NULL;
     422          389 :     const char *format = "p";
     423              :     TableInfo  *tblinfo;
     424              :     int         numTables;
     425              :     DumpableObject **dobjs;
     426              :     int         numObjs;
     427              :     DumpableObject *boundaryObjs;
     428              :     int         i;
     429              :     int         optindex;
     430              :     RestoreOptions *ropt;
     431              :     Archive    *fout;           /* the script file */
     432          389 :     bool        g_verbose = false;
     433          389 :     const char *dumpencoding = NULL;
     434          389 :     const char *dumpsnapshot = NULL;
     435          389 :     char       *use_role = NULL;
     436          389 :     int         numWorkers = 1;
     437          389 :     int         plainText = 0;
     438          389 :     ArchiveFormat archiveFormat = archUnknown;
     439              :     ArchiveMode archiveMode;
     440          389 :     pg_compress_specification compression_spec = {0};
     441          389 :     char       *compression_detail = NULL;
     442          389 :     char       *compression_algorithm_str = "none";
     443          389 :     char       *error_detail = NULL;
     444          389 :     bool        user_compression_defined = false;
     445          389 :     DataDirSyncMethod sync_method = DATA_DIR_SYNC_METHOD_FSYNC;
     446          389 :     bool        data_only = false;
     447          389 :     bool        schema_only = false;
     448          389 :     bool        statistics_only = false;
     449          389 :     bool        with_statistics = false;
     450          389 :     bool        no_data = false;
     451          389 :     bool        no_schema = false;
     452          389 :     bool        no_statistics = false;
     453              : 
     454              :     static DumpOptions dopt;
     455              : 
     456              :     static struct option long_options[] = {
     457              :         {"data-only", no_argument, NULL, 'a'},
     458              :         {"blobs", no_argument, NULL, 'b'},
     459              :         {"large-objects", no_argument, NULL, 'b'},
     460              :         {"no-blobs", no_argument, NULL, 'B'},
     461              :         {"no-large-objects", no_argument, NULL, 'B'},
     462              :         {"clean", no_argument, NULL, 'c'},
     463              :         {"create", no_argument, NULL, 'C'},
     464              :         {"dbname", required_argument, NULL, 'd'},
     465              :         {"extension", required_argument, NULL, 'e'},
     466              :         {"file", required_argument, NULL, 'f'},
     467              :         {"format", required_argument, NULL, 'F'},
     468              :         {"host", required_argument, NULL, 'h'},
     469              :         {"jobs", 1, NULL, 'j'},
     470              :         {"no-reconnect", no_argument, NULL, 'R'},
     471              :         {"no-owner", no_argument, NULL, 'O'},
     472              :         {"port", required_argument, NULL, 'p'},
     473              :         {"schema", required_argument, NULL, 'n'},
     474              :         {"exclude-schema", required_argument, NULL, 'N'},
     475              :         {"schema-only", no_argument, NULL, 's'},
     476              :         {"superuser", required_argument, NULL, 'S'},
     477              :         {"table", required_argument, NULL, 't'},
     478              :         {"exclude-table", required_argument, NULL, 'T'},
     479              :         {"no-password", no_argument, NULL, 'w'},
     480              :         {"password", no_argument, NULL, 'W'},
     481              :         {"username", required_argument, NULL, 'U'},
     482              :         {"verbose", no_argument, NULL, 'v'},
     483              :         {"no-privileges", no_argument, NULL, 'x'},
     484              :         {"no-acl", no_argument, NULL, 'x'},
     485              :         {"compress", required_argument, NULL, 'Z'},
     486              :         {"encoding", required_argument, NULL, 'E'},
     487              :         {"help", no_argument, NULL, '?'},
     488              :         {"version", no_argument, NULL, 'V'},
     489              : 
     490              :         /*
     491              :          * the following options don't have an equivalent short option letter
     492              :          */
     493              :         {"attribute-inserts", no_argument, &dopt.column_inserts, 1},
     494              :         {"binary-upgrade", no_argument, &dopt.binary_upgrade, 1},
     495              :         {"column-inserts", no_argument, &dopt.column_inserts, 1},
     496              :         {"disable-dollar-quoting", no_argument, &dopt.disable_dollar_quoting, 1},
     497              :         {"disable-triggers", no_argument, &dopt.disable_triggers, 1},
     498              :         {"enable-row-security", no_argument, &dopt.enable_row_security, 1},
     499              :         {"exclude-table-data", required_argument, NULL, 4},
     500              :         {"extra-float-digits", required_argument, NULL, 8},
     501              :         {"if-exists", no_argument, &dopt.if_exists, 1},
     502              :         {"inserts", no_argument, NULL, 9},
     503              :         {"lock-wait-timeout", required_argument, NULL, 2},
     504              :         {"no-table-access-method", no_argument, &dopt.outputNoTableAm, 1},
     505              :         {"no-tablespaces", no_argument, &dopt.outputNoTablespaces, 1},
     506              :         {"quote-all-identifiers", no_argument, &quote_all_identifiers, 1},
     507              :         {"load-via-partition-root", no_argument, &dopt.load_via_partition_root, 1},
     508              :         {"role", required_argument, NULL, 3},
     509              :         {"section", required_argument, NULL, 5},
     510              :         {"serializable-deferrable", no_argument, &dopt.serializable_deferrable, 1},
     511              :         {"snapshot", required_argument, NULL, 6},
     512              :         {"statistics", no_argument, NULL, 22},
     513              :         {"statistics-only", no_argument, NULL, 18},
     514              :         {"strict-names", no_argument, &strict_names, 1},
     515              :         {"use-set-session-authorization", no_argument, &dopt.use_setsessauth, 1},
     516              :         {"no-comments", no_argument, &dopt.no_comments, 1},
     517              :         {"no-data", no_argument, NULL, 19},
     518              :         {"no-policies", no_argument, &dopt.no_policies, 1},
     519              :         {"no-publications", no_argument, &dopt.no_publications, 1},
     520              :         {"no-schema", no_argument, NULL, 20},
     521              :         {"no-security-labels", no_argument, &dopt.no_security_labels, 1},
     522              :         {"no-statistics", no_argument, NULL, 21},
     523              :         {"no-subscriptions", no_argument, &dopt.no_subscriptions, 1},
     524              :         {"no-toast-compression", no_argument, &dopt.no_toast_compression, 1},
     525              :         {"no-unlogged-table-data", no_argument, &dopt.no_unlogged_table_data, 1},
     526              :         {"no-sync", no_argument, NULL, 7},
     527              :         {"on-conflict-do-nothing", no_argument, &dopt.do_nothing, 1},
     528              :         {"rows-per-insert", required_argument, NULL, 10},
     529              :         {"include-foreign-data", required_argument, NULL, 11},
     530              :         {"table-and-children", required_argument, NULL, 12},
     531              :         {"exclude-table-and-children", required_argument, NULL, 13},
     532              :         {"exclude-table-data-and-children", required_argument, NULL, 14},
     533              :         {"sync-method", required_argument, NULL, 15},
     534              :         {"filter", required_argument, NULL, 16},
     535              :         {"exclude-extension", required_argument, NULL, 17},
     536              :         {"sequence-data", no_argument, &dopt.sequence_data, 1},
     537              :         {"restrict-key", required_argument, NULL, 25},
     538              : 
     539              :         {NULL, 0, NULL, 0}
     540              :     };
     541              : 
     542          389 :     pg_logging_init(argv[0]);
     543          389 :     pg_logging_set_level(PG_LOG_WARNING);
     544          389 :     set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_dump"));
     545              : 
     546              :     /*
     547              :      * Initialize what we need for parallel execution, especially for thread
     548              :      * support on Windows.
     549              :      */
     550          389 :     init_parallel_dump_utils();
     551              : 
     552          389 :     progname = get_progname(argv[0]);
     553              : 
     554          389 :     if (argc > 1)
     555              :     {
     556          389 :         if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
     557              :         {
     558            1 :             help(progname);
     559            1 :             exit_nicely(0);
     560              :         }
     561          388 :         if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
     562              :         {
     563           84 :             puts("pg_dump (PostgreSQL) " PG_VERSION);
     564           84 :             exit_nicely(0);
     565              :         }
     566              :     }
     567              : 
     568          304 :     InitDumpOptions(&dopt);
     569              : 
     570         1673 :     while ((c = getopt_long(argc, argv, "abBcCd:e:E:f:F:h:j:n:N:Op:RsS:t:T:U:vwWxXZ:",
     571         1673 :                             long_options, &optindex)) != -1)
     572              :     {
     573         1377 :         switch (c)
     574              :         {
     575            9 :             case 'a':           /* Dump data only */
     576            9 :                 data_only = true;
     577            9 :                 break;
     578              : 
     579            1 :             case 'b':           /* Dump LOs */
     580            1 :                 dopt.outputLOs = true;
     581            1 :                 break;
     582              : 
     583            2 :             case 'B':           /* Don't dump LOs */
     584            2 :                 dopt.dontOutputLOs = true;
     585            2 :                 break;
     586              : 
     587            6 :             case 'c':           /* clean (i.e., drop) schema prior to create */
     588            6 :                 dopt.outputClean = 1;
     589            6 :                 break;
     590              : 
     591           82 :             case 'C':           /* Create DB */
     592           82 :                 dopt.outputCreateDB = 1;
     593           82 :                 break;
     594              : 
     595            5 :             case 'd':           /* database name */
     596            5 :                 dopt.cparams.dbname = pg_strdup(optarg);
     597            5 :                 break;
     598              : 
     599            4 :             case 'e':           /* include extension(s) */
     600            4 :                 simple_string_list_append(&extension_include_patterns, optarg);
     601            4 :                 dopt.include_everything = false;
     602            4 :                 break;
     603              : 
     604            2 :             case 'E':           /* Dump encoding */
     605            2 :                 dumpencoding = pg_strdup(optarg);
     606            2 :                 break;
     607              : 
     608          336 :             case 'f':
     609          336 :                 filename = pg_strdup(optarg);
     610          336 :                 break;
     611              : 
     612          184 :             case 'F':
     613          184 :                 format = pg_strdup(optarg);
     614          184 :                 break;
     615              : 
     616           38 :             case 'h':           /* server host */
     617           38 :                 dopt.cparams.pghost = pg_strdup(optarg);
     618           38 :                 break;
     619              : 
     620           11 :             case 'j':           /* number of dump jobs */
     621           11 :                 if (!option_parse_int(optarg, "-j/--jobs", 1,
     622              :                                       PG_MAX_JOBS,
     623              :                                       &numWorkers))
     624            1 :                     exit_nicely(1);
     625           10 :                 break;
     626              : 
     627           17 :             case 'n':           /* include schema(s) */
     628           17 :                 simple_string_list_append(&schema_include_patterns, optarg);
     629           17 :                 dopt.include_everything = false;
     630           17 :                 break;
     631              : 
     632            1 :             case 'N':           /* exclude schema(s) */
     633            1 :                 simple_string_list_append(&schema_exclude_patterns, optarg);
     634            1 :                 break;
     635              : 
     636            2 :             case 'O':           /* Don't reconnect to match owner */
     637            2 :                 dopt.outputNoOwner = 1;
     638            2 :                 break;
     639              : 
     640           77 :             case 'p':           /* server port */
     641           77 :                 dopt.cparams.pgport = pg_strdup(optarg);
     642           77 :                 break;
     643              : 
     644            2 :             case 'R':
     645              :                 /* no-op, still accepted for backwards compatibility */
     646            2 :                 break;
     647              : 
     648            7 :             case 's':           /* dump schema only */
     649            7 :                 schema_only = true;
     650            7 :                 break;
     651              : 
     652            1 :             case 'S':           /* Username for superuser in plain text output */
     653            1 :                 dopt.outputSuperuser = pg_strdup(optarg);
     654            1 :                 break;
     655              : 
     656            8 :             case 't':           /* include table(s) */
     657            8 :                 simple_string_list_append(&table_include_patterns, optarg);
     658            8 :                 dopt.include_everything = false;
     659            8 :                 break;
     660              : 
     661            4 :             case 'T':           /* exclude table(s) */
     662            4 :                 simple_string_list_append(&table_exclude_patterns, optarg);
     663            4 :                 break;
     664              : 
     665           40 :             case 'U':
     666           40 :                 dopt.cparams.username = pg_strdup(optarg);
     667           40 :                 break;
     668              : 
     669            6 :             case 'v':           /* verbose */
     670            6 :                 g_verbose = true;
     671            6 :                 pg_logging_increase_verbosity();
     672            6 :                 break;
     673              : 
     674            1 :             case 'w':
     675            1 :                 dopt.cparams.promptPassword = TRI_NO;
     676            1 :                 break;
     677              : 
     678            0 :             case 'W':
     679            0 :                 dopt.cparams.promptPassword = TRI_YES;
     680            0 :                 break;
     681              : 
     682            2 :             case 'x':           /* skip ACL dump */
     683            2 :                 dopt.aclsSkip = true;
     684            2 :                 break;
     685              : 
     686           13 :             case 'Z':           /* Compression */
     687           13 :                 parse_compress_options(optarg, &compression_algorithm_str,
     688              :                                        &compression_detail);
     689           13 :                 user_compression_defined = true;
     690           13 :                 break;
     691              : 
     692          141 :             case 0:
     693              :                 /* This covers the long options. */
     694          141 :                 break;
     695              : 
     696            2 :             case 2:             /* lock-wait-timeout */
     697            2 :                 dopt.lockWaitTimeout = pg_strdup(optarg);
     698            2 :                 break;
     699              : 
     700            3 :             case 3:             /* SET ROLE */
     701            3 :                 use_role = pg_strdup(optarg);
     702            3 :                 break;
     703              : 
     704            1 :             case 4:             /* exclude table(s) data */
     705            1 :                 simple_string_list_append(&tabledata_exclude_patterns, optarg);
     706            1 :                 break;
     707              : 
     708            6 :             case 5:             /* section */
     709            6 :                 set_dump_section(optarg, &dopt.dumpSections);
     710            6 :                 break;
     711              : 
     712            0 :             case 6:             /* snapshot */
     713            0 :                 dumpsnapshot = pg_strdup(optarg);
     714            0 :                 break;
     715              : 
     716          151 :             case 7:             /* no-sync */
     717          151 :                 dosync = false;
     718          151 :                 break;
     719              : 
     720            1 :             case 8:
     721            1 :                 have_extra_float_digits = true;
     722            1 :                 if (!option_parse_int(optarg, "--extra-float-digits", -15, 3,
     723              :                                       &extra_float_digits))
     724            1 :                     exit_nicely(1);
     725            0 :                 break;
     726              : 
     727            2 :             case 9:             /* inserts */
     728              : 
     729              :                 /*
     730              :                  * dump_inserts also stores --rows-per-insert, careful not to
     731              :                  * overwrite that.
     732              :                  */
     733            2 :                 if (dopt.dump_inserts == 0)
     734            2 :                     dopt.dump_inserts = DUMP_DEFAULT_ROWS_PER_INSERT;
     735            2 :                 break;
     736              : 
     737            2 :             case 10:            /* rows per insert */
     738            2 :                 if (!option_parse_int(optarg, "--rows-per-insert", 1, INT_MAX,
     739              :                                       &dopt.dump_inserts))
     740            1 :                     exit_nicely(1);
     741            1 :                 break;
     742              : 
     743            4 :             case 11:            /* include foreign data */
     744            4 :                 simple_string_list_append(&foreign_servers_include_patterns,
     745              :                                           optarg);
     746            4 :                 break;
     747              : 
     748            1 :             case 12:            /* include table(s) and their children */
     749            1 :                 simple_string_list_append(&table_include_patterns_and_children,
     750              :                                           optarg);
     751            1 :                 dopt.include_everything = false;
     752            1 :                 break;
     753              : 
     754            1 :             case 13:            /* exclude table(s) and their children */
     755            1 :                 simple_string_list_append(&table_exclude_patterns_and_children,
     756              :                                           optarg);
     757            1 :                 break;
     758              : 
     759            1 :             case 14:            /* exclude data of table(s) and children */
     760            1 :                 simple_string_list_append(&tabledata_exclude_patterns_and_children,
     761              :                                           optarg);
     762            1 :                 break;
     763              : 
     764            0 :             case 15:
     765            0 :                 if (!parse_sync_method(optarg, &sync_method))
     766            0 :                     exit_nicely(1);
     767            0 :                 break;
     768              : 
     769           26 :             case 16:            /* read object filters from file */
     770           26 :                 read_dump_filters(optarg, &dopt);
     771           22 :                 break;
     772              : 
     773            1 :             case 17:            /* exclude extension(s) */
     774            1 :                 simple_string_list_append(&extension_exclude_patterns,
     775              :                                           optarg);
     776            1 :                 break;
     777              : 
     778            4 :             case 18:
     779            4 :                 statistics_only = true;
     780            4 :                 break;
     781              : 
     782           40 :             case 19:
     783           40 :                 no_data = true;
     784           40 :                 break;
     785              : 
     786            2 :             case 20:
     787            2 :                 no_schema = true;
     788            2 :                 break;
     789              : 
     790            8 :             case 21:
     791            8 :                 no_statistics = true;
     792            8 :                 break;
     793              : 
     794           92 :             case 22:
     795           92 :                 with_statistics = true;
     796           92 :                 break;
     797              : 
     798           26 :             case 25:
     799           26 :                 dopt.restrict_key = pg_strdup(optarg);
     800           26 :                 break;
     801              : 
     802            1 :             default:
     803              :                 /* getopt_long already emitted a complaint */
     804            1 :                 pg_log_error_hint("Try \"%s --help\" for more information.", progname);
     805            1 :                 exit_nicely(1);
     806              :         }
     807              :     }
     808              : 
     809              :     /*
     810              :      * Non-option argument specifies database name as long as it wasn't
     811              :      * already specified with -d / --dbname
     812              :      */
     813          296 :     if (optind < argc && dopt.cparams.dbname == NULL)
     814          260 :         dopt.cparams.dbname = argv[optind++];
     815              : 
     816              :     /* Complain if any arguments remain */
     817          296 :     if (optind < argc)
     818              :     {
     819            1 :         pg_log_error("too many command-line arguments (first is \"%s\")",
     820              :                      argv[optind]);
     821            1 :         pg_log_error_hint("Try \"%s --help\" for more information.", progname);
     822            1 :         exit_nicely(1);
     823              :     }
     824              : 
     825              :     /* --column-inserts implies --inserts */
     826          295 :     if (dopt.column_inserts && dopt.dump_inserts == 0)
     827            1 :         dopt.dump_inserts = DUMP_DEFAULT_ROWS_PER_INSERT;
     828              : 
     829              :     /* *-only options are incompatible with each other */
     830          295 :     check_mut_excl_opts(data_only, "-a/--data-only",
     831              :                         schema_only, "-s/--schema-only",
     832              :                         statistics_only, "--statistics-only");
     833              : 
     834              :     /* --no-* and *-only for same thing are incompatible */
     835          292 :     check_mut_excl_opts(data_only, "-a/--data-only",
     836              :                         no_data, "--no-data");
     837          292 :     check_mut_excl_opts(schema_only, "-s/--schema-only",
     838              :                         no_schema, "--no-schema");
     839          292 :     check_mut_excl_opts(statistics_only, "--statistics-only",
     840              :                         no_statistics, "--no-statistics");
     841              : 
     842              :     /* --statistics and --no-statistics are incompatible */
     843          291 :     check_mut_excl_opts(with_statistics, "--statistics",
     844              :                         no_statistics, "--no-statistics");
     845              : 
     846              :     /* --statistics is incompatible with *-only (except --statistics-only) */
     847          291 :     check_mut_excl_opts(with_statistics, "--statistics",
     848              :                         data_only, "-a/--data-only",
     849              :                         schema_only, "-s/--schema-only");
     850              : 
     851              :     /* --include-foreign-data is incompatible with --schema-only */
     852          290 :     check_mut_excl_opts(foreign_servers_include_patterns.head, "--include-foreign-data",
     853              :                         schema_only, "-s/--schema-only");
     854              : 
     855          289 :     if (numWorkers > 1 && foreign_servers_include_patterns.head != NULL)
     856            1 :         pg_fatal("option %s is not supported with parallel backup",
     857              :                  "--include-foreign-data");
     858              : 
     859              :     /* --clean is incompatible with --data-only */
     860          288 :     check_mut_excl_opts(dopt.outputClean, "-c/--clean",
     861              :                         data_only, "-a/--data-only");
     862              : 
     863          287 :     if (dopt.if_exists && !dopt.outputClean)
     864            1 :         pg_fatal("option %s requires option %s",
     865              :                  "--if-exists", "-c/--clean");
     866              : 
     867              :     /*
     868              :      * Set derivative flags. Ambiguous or nonsensical combinations, e.g.
     869              :      * "--schema-only --no-schema", will have already caused an error in one
     870              :      * of the checks above.
     871              :      */
     872          286 :     dopt.dumpData = ((dopt.dumpData && !schema_only && !statistics_only) ||
     873          572 :                      data_only) && !no_data;
     874          286 :     dopt.dumpSchema = ((dopt.dumpSchema && !data_only && !statistics_only) ||
     875          572 :                        schema_only) && !no_schema;
     876          286 :     dopt.dumpStatistics = ((dopt.dumpStatistics && !schema_only && !data_only) ||
     877          572 :                            (statistics_only || with_statistics)) && !no_statistics;
     878              : 
     879              : 
     880              :     /*
     881              :      * --inserts are already implied above if --column-inserts or
     882              :      * --rows-per-insert were specified.
     883              :      */
     884          286 :     if (dopt.do_nothing && dopt.dump_inserts == 0)
     885            1 :         pg_fatal("option %s requires option %s, %s, or %s",
     886              :                  "--on-conflict-do-nothing",
     887              :                  "--inserts", "--rows-per-insert", "--column-inserts");
     888              : 
     889              :     /* Identify archive format to emit */
     890          285 :     archiveFormat = parseArchiveFormat(format, &archiveMode);
     891              : 
     892              :     /* archiveFormat specific setup */
     893          284 :     if (archiveFormat == archNull)
     894              :     {
     895          152 :         plainText = 1;
     896              : 
     897              :         /*
     898              :          * If you don't provide a restrict key, one will be appointed for you.
     899              :          */
     900          152 :         if (!dopt.restrict_key)
     901          126 :             dopt.restrict_key = generate_restrict_key();
     902          152 :         if (!dopt.restrict_key)
     903            0 :             pg_fatal("could not generate restrict key");
     904          152 :         if (!valid_restrict_key(dopt.restrict_key))
     905            0 :             pg_fatal("invalid restrict key");
     906              :     }
     907          132 :     else if (dopt.restrict_key)
     908            0 :         pg_fatal("option %s can only be used with %s",
     909              :                  "--restrict-key", "--format=plain");
     910              : 
     911              :     /*
     912              :      * Custom and directory formats are compressed by default with gzip when
     913              :      * available, not the others.  If gzip is not available, no compression is
     914              :      * done by default.
     915              :      */
     916          284 :     if ((archiveFormat == archCustom || archiveFormat == archDirectory) &&
     917          121 :         !user_compression_defined)
     918              :     {
     919              : #ifdef HAVE_LIBZ
     920          115 :         compression_algorithm_str = "gzip";
     921              : #else
     922              :         compression_algorithm_str = "none";
     923              : #endif
     924              :     }
     925              : 
     926              :     /*
     927              :      * Compression options
     928              :      */
     929          284 :     if (!parse_compress_algorithm(compression_algorithm_str,
     930              :                                   &compression_algorithm))
     931            1 :         pg_fatal("unrecognized compression algorithm: \"%s\"",
     932              :                  compression_algorithm_str);
     933              : 
     934          283 :     parse_compress_specification(compression_algorithm, compression_detail,
     935              :                                  &compression_spec);
     936          283 :     error_detail = validate_compress_specification(&compression_spec);
     937          283 :     if (error_detail != NULL)
     938            3 :         pg_fatal("invalid compression specification: %s",
     939              :                  error_detail);
     940              : 
     941          280 :     error_detail = supports_compression(compression_spec);
     942          280 :     if (error_detail != NULL)
     943            0 :         pg_fatal("%s", error_detail);
     944              : 
     945              :     /*
     946              :      * Disable support for zstd workers for now - these are based on
     947              :      * threading, and it's unclear how it interacts with parallel dumps on
     948              :      * platforms where that relies on threads too (e.g. Windows).
     949              :      */
     950          280 :     if (compression_spec.options & PG_COMPRESSION_OPTION_WORKERS)
     951            0 :         pg_log_warning("compression option \"%s\" is not currently supported by pg_dump",
     952              :                        "workers");
     953              : 
     954              :     /*
     955              :      * If emitting an archive format, we always want to emit a DATABASE item,
     956              :      * in case --create is specified at pg_restore time.
     957              :      */
     958          280 :     if (!plainText)
     959          132 :         dopt.outputCreateDB = 1;
     960              : 
     961              :     /* Parallel backup only in the directory archive format so far */
     962          280 :     if (archiveFormat != archDirectory && numWorkers > 1)
     963            1 :         pg_fatal("parallel backup only supported by the directory format");
     964              : 
     965              :     /* Open the output file */
     966          279 :     fout = CreateArchive(filename, archiveFormat, compression_spec,
     967              :                          dosync, archiveMode, setupDumpWorker, sync_method);
     968              : 
     969              :     /* Make dump options accessible right away */
     970          278 :     SetArchiveOptions(fout, &dopt, NULL);
     971              : 
     972              :     /* Register the cleanup hook */
     973          278 :     on_exit_close_archive(fout);
     974              : 
     975              :     /* Let the archiver know how noisy to be */
     976          278 :     fout->verbose = g_verbose;
     977              : 
     978              : 
     979              :     /*
     980              :      * We allow the server to be back to 9.2, and up to any minor release of
     981              :      * our own major version.  (See also version check in pg_dumpall.c.)
     982              :      */
     983          278 :     fout->minRemoteVersion = 90200;
     984          278 :     fout->maxRemoteVersion = (PG_VERSION_NUM / 100) * 100 + 99;
     985              : 
     986          278 :     fout->numWorkers = numWorkers;
     987              : 
     988              :     /*
     989              :      * Open the database using the Archiver, so it knows about it. Errors mean
     990              :      * death.
     991              :      */
     992          278 :     ConnectDatabaseAhx(fout, &dopt.cparams, false);
     993          276 :     setup_connection(fout, dumpencoding, dumpsnapshot, use_role);
     994              : 
     995              :     /*
     996              :      * On hot standbys, never try to dump unlogged table data, since it will
     997              :      * just throw an error.
     998              :      */
     999          276 :     if (fout->isStandby)
    1000            4 :         dopt.no_unlogged_table_data = true;
    1001              : 
    1002              :     /*
    1003              :      * Find the last built-in OID, if needed (prior to 8.1)
    1004              :      *
    1005              :      * With 8.1 and above, we can just use FirstNormalObjectId - 1.
    1006              :      */
    1007          276 :     g_last_builtin_oid = FirstNormalObjectId - 1;
    1008              : 
    1009          276 :     pg_log_info("last built-in OID is %u", g_last_builtin_oid);
    1010              : 
    1011              :     /* Expand schema selection patterns into OID lists */
    1012          276 :     if (schema_include_patterns.head != NULL)
    1013              :     {
    1014           18 :         expand_schema_name_patterns(fout, &schema_include_patterns,
    1015              :                                     &schema_include_oids,
    1016              :                                     strict_names);
    1017           12 :         if (schema_include_oids.head == NULL)
    1018            1 :             pg_fatal("no matching schemas were found");
    1019              :     }
    1020          269 :     expand_schema_name_patterns(fout, &schema_exclude_patterns,
    1021              :                                 &schema_exclude_oids,
    1022              :                                 false);
    1023              :     /* non-matching exclusion patterns aren't an error */
    1024              : 
    1025              :     /* Expand table selection patterns into OID lists */
    1026          269 :     expand_table_name_patterns(fout, &table_include_patterns,
    1027              :                                &table_include_oids,
    1028              :                                strict_names, false);
    1029          264 :     expand_table_name_patterns(fout, &table_include_patterns_and_children,
    1030              :                                &table_include_oids,
    1031              :                                strict_names, true);
    1032          264 :     if ((table_include_patterns.head != NULL ||
    1033          253 :          table_include_patterns_and_children.head != NULL) &&
    1034           13 :         table_include_oids.head == NULL)
    1035            2 :         pg_fatal("no matching tables were found");
    1036              : 
    1037          262 :     expand_table_name_patterns(fout, &table_exclude_patterns,
    1038              :                                &table_exclude_oids,
    1039              :                                false, false);
    1040          262 :     expand_table_name_patterns(fout, &table_exclude_patterns_and_children,
    1041              :                                &table_exclude_oids,
    1042              :                                false, true);
    1043              : 
    1044          262 :     expand_table_name_patterns(fout, &tabledata_exclude_patterns,
    1045              :                                &tabledata_exclude_oids,
    1046              :                                false, false);
    1047          262 :     expand_table_name_patterns(fout, &tabledata_exclude_patterns_and_children,
    1048              :                                &tabledata_exclude_oids,
    1049              :                                false, true);
    1050              : 
    1051          262 :     expand_foreign_server_name_patterns(fout, &foreign_servers_include_patterns,
    1052              :                                         &foreign_servers_include_oids);
    1053              : 
    1054              :     /* non-matching exclusion patterns aren't an error */
    1055              : 
    1056              :     /* Expand extension selection patterns into OID lists */
    1057          261 :     if (extension_include_patterns.head != NULL)
    1058              :     {
    1059            5 :         expand_extension_name_patterns(fout, &extension_include_patterns,
    1060              :                                        &extension_include_oids,
    1061              :                                        strict_names);
    1062            5 :         if (extension_include_oids.head == NULL)
    1063            1 :             pg_fatal("no matching extensions were found");
    1064              :     }
    1065          260 :     expand_extension_name_patterns(fout, &extension_exclude_patterns,
    1066              :                                    &extension_exclude_oids,
    1067              :                                    false);
    1068              :     /* non-matching exclusion patterns aren't an error */
    1069              : 
    1070              :     /*
    1071              :      * Dumping LOs is the default for dumps where an inclusion switch is not
    1072              :      * used (an "include everything" dump).  -B can be used to exclude LOs
    1073              :      * from those dumps.  -b can be used to include LOs even when an inclusion
    1074              :      * switch is used.
    1075              :      *
    1076              :      * -s means "schema only" and LOs are data, not schema, so we never
    1077              :      * include LOs when -s is used.
    1078              :      */
    1079          260 :     if (dopt.include_everything && dopt.dumpData && !dopt.dontOutputLOs)
    1080          191 :         dopt.outputLOs = true;
    1081              : 
    1082              :     /*
    1083              :      * Collect role names so we can map object owner OIDs to names.
    1084              :      */
    1085          260 :     collectRoleNames(fout);
    1086              : 
    1087              :     /*
    1088              :      * Now scan the database and create DumpableObject structs for all the
    1089              :      * objects we intend to dump.
    1090              :      */
    1091          260 :     tblinfo = getSchemaData(fout, &numTables);
    1092              : 
    1093          259 :     if (dopt.dumpData)
    1094              :     {
    1095          215 :         getTableData(&dopt, tblinfo, numTables, 0);
    1096          215 :         buildMatViewRefreshDependencies(fout);
    1097          215 :         if (!dopt.dumpSchema)
    1098            7 :             getTableDataFKConstraints();
    1099              :     }
    1100              : 
    1101          259 :     if (!dopt.dumpData && dopt.sequence_data)
    1102           36 :         getTableData(&dopt, tblinfo, numTables, RELKIND_SEQUENCE);
    1103              : 
    1104              :     /*
    1105              :      * For binary upgrade mode, dump the pg_shdepend rows for large objects
    1106              :      * and maybe even pg_largeobject_metadata (see comment below for details).
    1107              :      * This is faster to restore than the equivalent set of large object
    1108              :      * commands.
    1109              :      */
    1110          259 :     if (dopt.binary_upgrade)
    1111              :     {
    1112              :         TableInfo  *shdepend;
    1113              : 
    1114           40 :         shdepend = findTableByOid(SharedDependRelationId);
    1115           40 :         makeTableDataInfo(&dopt, shdepend);
    1116              : 
    1117              :         /*
    1118              :          * Only dump large object shdepend rows for this database.
    1119              :          */
    1120           40 :         shdepend->dataObj->filtercond = "WHERE classid = 'pg_largeobject'::regclass "
    1121              :             "AND dbid = (SELECT oid FROM pg_database "
    1122              :             "            WHERE datname = current_database())";
    1123              : 
    1124              :         /*
    1125              :          * For binary upgrades from v16 and newer versions, we can copy
    1126              :          * pg_largeobject_metadata's files from the old cluster, so we don't
    1127              :          * need to dump its contents.  pg_upgrade can't copy/link the files
    1128              :          * from older versions because aclitem (needed by
    1129              :          * pg_largeobject_metadata.lomacl) changed its storage format in v16.
    1130              :          */
    1131           40 :         if (fout->remoteVersion < 160000)
    1132              :         {
    1133              :             TableInfo  *lo_metadata;
    1134              : 
    1135            0 :             lo_metadata = findTableByOid(LargeObjectMetadataRelationId);
    1136            0 :             makeTableDataInfo(&dopt, lo_metadata);
    1137              :         }
    1138              :     }
    1139              : 
    1140              :     /*
    1141              :      * In binary-upgrade mode, we do not have to worry about the actual LO
    1142              :      * data or the associated metadata that resides in the pg_largeobject and
    1143              :      * pg_largeobject_metadata tables, respectively.
    1144              :      *
    1145              :      * However, we do need to collect LO information as there may be comments
    1146              :      * or other information on LOs that we do need to dump out.
    1147              :      */
    1148          259 :     if (dopt.outputLOs || dopt.binary_upgrade)
    1149          231 :         getLOs(fout);
    1150              : 
    1151              :     /*
    1152              :      * Collect dependency data to assist in ordering the objects.
    1153              :      */
    1154          259 :     getDependencies(fout);
    1155              : 
    1156              :     /*
    1157              :      * Collect ACLs, comments, and security labels, if wanted.
    1158              :      */
    1159          259 :     if (!dopt.aclsSkip)
    1160          257 :         getAdditionalACLs(fout);
    1161          259 :     if (!dopt.no_comments)
    1162          259 :         collectComments(fout);
    1163          259 :     if (!dopt.no_security_labels)
    1164          259 :         collectSecLabels(fout);
    1165              : 
    1166              :     /* For binary upgrade mode, collect required pg_class information. */
    1167          259 :     if (dopt.binary_upgrade)
    1168           40 :         collectBinaryUpgradeClassOids(fout);
    1169              : 
    1170              :     /* Collect sequence information. */
    1171          259 :     collectSequences(fout);
    1172              : 
    1173              :     /* Lastly, create dummy objects to represent the section boundaries */
    1174          259 :     boundaryObjs = createBoundaryObjects();
    1175              : 
    1176              :     /* Get pointers to all the known DumpableObjects */
    1177          259 :     getDumpableObjects(&dobjs, &numObjs);
    1178              : 
    1179              :     /*
    1180              :      * Add dummy dependencies to enforce the dump section ordering.
    1181              :      */
    1182          259 :     addBoundaryDependencies(dobjs, numObjs, boundaryObjs);
    1183              : 
    1184              :     /*
    1185              :      * Sort the objects into a safe dump order (no forward references).
    1186              :      *
    1187              :      * We rely on dependency information to help us determine a safe order, so
    1188              :      * the initial sort is mostly for cosmetic purposes: we sort by name to
    1189              :      * ensure that logically identical schemas will dump identically.
    1190              :      */
    1191          259 :     sortDumpableObjectsByTypeName(dobjs, numObjs);
    1192              : 
    1193          259 :     sortDumpableObjects(dobjs, numObjs,
    1194          259 :                         boundaryObjs[0].dumpId, boundaryObjs[1].dumpId);
    1195              : 
    1196              :     /*
    1197              :      * Create archive TOC entries for all the objects to be dumped, in a safe
    1198              :      * order.
    1199              :      */
    1200              : 
    1201              :     /*
    1202              :      * First the special entries for ENCODING, STDSTRINGS, and SEARCHPATH.
    1203              :      */
    1204          259 :     dumpEncoding(fout);
    1205          259 :     dumpStdStrings(fout);
    1206          259 :     dumpSearchPath(fout);
    1207              : 
    1208              :     /* The database items are always next, unless we don't want them at all */
    1209          259 :     if (dopt.outputCreateDB)
    1210          160 :         dumpDatabase(fout);
    1211              : 
    1212              :     /* Now the rearrangeable objects. */
    1213       976294 :     for (i = 0; i < numObjs; i++)
    1214       976035 :         dumpDumpableObject(fout, dobjs[i]);
    1215              : 
    1216              :     /*
    1217              :      * Set up options info to ensure we dump what we want.
    1218              :      */
    1219          259 :     ropt = NewRestoreOptions();
    1220          259 :     ropt->filename = filename;
    1221              : 
    1222              :     /* if you change this list, see dumpOptionsFromRestoreOptions */
    1223          259 :     ropt->cparams.dbname = dopt.cparams.dbname ? pg_strdup(dopt.cparams.dbname) : NULL;
    1224          259 :     ropt->cparams.pgport = dopt.cparams.pgport ? pg_strdup(dopt.cparams.pgport) : NULL;
    1225          259 :     ropt->cparams.pghost = dopt.cparams.pghost ? pg_strdup(dopt.cparams.pghost) : NULL;
    1226          259 :     ropt->cparams.username = dopt.cparams.username ? pg_strdup(dopt.cparams.username) : NULL;
    1227          259 :     ropt->cparams.promptPassword = dopt.cparams.promptPassword;
    1228          259 :     ropt->dropSchema = dopt.outputClean;
    1229          259 :     ropt->dumpData = dopt.dumpData;
    1230          259 :     ropt->dumpSchema = dopt.dumpSchema;
    1231          259 :     ropt->dumpStatistics = dopt.dumpStatistics;
    1232          259 :     ropt->if_exists = dopt.if_exists;
    1233          259 :     ropt->column_inserts = dopt.column_inserts;
    1234          259 :     ropt->dumpSections = dopt.dumpSections;
    1235          259 :     ropt->aclsSkip = dopt.aclsSkip;
    1236          259 :     ropt->superuser = dopt.outputSuperuser;
    1237          259 :     ropt->createDB = dopt.outputCreateDB;
    1238          259 :     ropt->noOwner = dopt.outputNoOwner;
    1239          259 :     ropt->noTableAm = dopt.outputNoTableAm;
    1240          259 :     ropt->noTablespace = dopt.outputNoTablespaces;
    1241          259 :     ropt->disable_triggers = dopt.disable_triggers;
    1242          259 :     ropt->use_setsessauth = dopt.use_setsessauth;
    1243          259 :     ropt->disable_dollar_quoting = dopt.disable_dollar_quoting;
    1244          259 :     ropt->dump_inserts = dopt.dump_inserts;
    1245          259 :     ropt->no_comments = dopt.no_comments;
    1246          259 :     ropt->no_policies = dopt.no_policies;
    1247          259 :     ropt->no_publications = dopt.no_publications;
    1248          259 :     ropt->no_security_labels = dopt.no_security_labels;
    1249          259 :     ropt->no_subscriptions = dopt.no_subscriptions;
    1250          259 :     ropt->lockWaitTimeout = dopt.lockWaitTimeout;
    1251          259 :     ropt->include_everything = dopt.include_everything;
    1252          259 :     ropt->enable_row_security = dopt.enable_row_security;
    1253          259 :     ropt->sequence_data = dopt.sequence_data;
    1254          259 :     ropt->binary_upgrade = dopt.binary_upgrade;
    1255          259 :     ropt->restrict_key = dopt.restrict_key ? pg_strdup(dopt.restrict_key) : NULL;
    1256              : 
    1257          259 :     ropt->compression_spec = compression_spec;
    1258              : 
    1259          259 :     ropt->suppressDumpWarnings = true;   /* We've already shown them */
    1260              : 
    1261          259 :     SetArchiveOptions(fout, &dopt, ropt);
    1262              : 
    1263              :     /* Mark which entries should be output */
    1264          259 :     ProcessArchiveRestoreOptions(fout);
    1265              : 
    1266              :     /*
    1267              :      * The archive's TOC entries are now marked as to which ones will actually
    1268              :      * be output, so we can set up their dependency lists properly. This isn't
    1269              :      * necessary for plain-text output, though.
    1270              :      */
    1271          259 :     if (!plainText)
    1272          131 :         BuildArchiveDependencies(fout);
    1273              : 
    1274              :     /*
    1275              :      * And finally we can do the actual output.
    1276              :      *
    1277              :      * Note: for non-plain-text output formats, the output file is written
    1278              :      * inside CloseArchive().  This is, um, bizarre; but not worth changing
    1279              :      * right now.
    1280              :      */
    1281          259 :     if (plainText)
    1282          128 :         RestoreArchive(fout, false);
    1283              : 
    1284          258 :     CloseArchive(fout);
    1285              : 
    1286          258 :     exit_nicely(0);
    1287              : }
    1288              : 
    1289              : 
    1290              : static void
    1291            1 : help(const char *progname)
    1292              : {
    1293            1 :     printf(_("%s exports a PostgreSQL database as an SQL script or to other formats.\n\n"), progname);
    1294            1 :     printf(_("Usage:\n"));
    1295            1 :     printf(_("  %s [OPTION]... [DBNAME]\n"), progname);
    1296              : 
    1297            1 :     printf(_("\nGeneral options:\n"));
    1298            1 :     printf(_("  -f, --file=FILENAME          output file or directory name\n"));
    1299            1 :     printf(_("  -F, --format=c|d|t|p         output file format (custom, directory, tar,\n"
    1300              :              "                               plain text (default))\n"));
    1301            1 :     printf(_("  -j, --jobs=NUM               use this many parallel jobs to dump\n"));
    1302            1 :     printf(_("  -v, --verbose                verbose mode\n"));
    1303            1 :     printf(_("  -V, --version                output version information, then exit\n"));
    1304            1 :     printf(_("  -Z, --compress=METHOD[:DETAIL]\n"
    1305              :              "                               compress as specified\n"));
    1306            1 :     printf(_("  --lock-wait-timeout=TIMEOUT  fail after waiting TIMEOUT for a table lock\n"));
    1307            1 :     printf(_("  --no-sync                    do not wait for changes to be written safely to disk\n"));
    1308            1 :     printf(_("  --sync-method=METHOD         set method for syncing files to disk\n"));
    1309            1 :     printf(_("  -?, --help                   show this help, then exit\n"));
    1310              : 
    1311            1 :     printf(_("\nOptions controlling the output content:\n"));
    1312            1 :     printf(_("  -a, --data-only              dump only the data, not the schema or statistics\n"));
    1313            1 :     printf(_("  -b, --large-objects          include large objects in dump\n"));
    1314            1 :     printf(_("  --blobs                      (same as --large-objects, deprecated)\n"));
    1315            1 :     printf(_("  -B, --no-large-objects       exclude large objects in dump\n"));
    1316            1 :     printf(_("  --no-blobs                   (same as --no-large-objects, deprecated)\n"));
    1317            1 :     printf(_("  -c, --clean                  clean (drop) database objects before recreating\n"));
    1318            1 :     printf(_("  -C, --create                 include commands to create database in dump\n"));
    1319            1 :     printf(_("  -e, --extension=PATTERN      dump the specified extension(s) only\n"));
    1320            1 :     printf(_("  -E, --encoding=ENCODING      dump the data in encoding ENCODING\n"));
    1321            1 :     printf(_("  -n, --schema=PATTERN         dump the specified schema(s) only\n"));
    1322            1 :     printf(_("  -N, --exclude-schema=PATTERN do NOT dump the specified schema(s)\n"));
    1323            1 :     printf(_("  -O, --no-owner               skip restoration of object ownership in\n"
    1324              :              "                               plain-text format\n"));
    1325            1 :     printf(_("  -s, --schema-only            dump only the schema, no data or statistics\n"));
    1326            1 :     printf(_("  -S, --superuser=NAME         superuser user name to use in plain-text format\n"));
    1327            1 :     printf(_("  -t, --table=PATTERN          dump only the specified table(s)\n"));
    1328            1 :     printf(_("  -T, --exclude-table=PATTERN  do NOT dump the specified table(s)\n"));
    1329            1 :     printf(_("  -x, --no-privileges          do not dump privileges (grant/revoke)\n"));
    1330            1 :     printf(_("  --binary-upgrade             for use by upgrade utilities only\n"));
    1331            1 :     printf(_("  --column-inserts             dump data as INSERT commands with column names\n"));
    1332            1 :     printf(_("  --disable-dollar-quoting     disable dollar quoting, use SQL standard quoting\n"));
    1333            1 :     printf(_("  --disable-triggers           disable triggers during data-only restore\n"));
    1334            1 :     printf(_("  --enable-row-security        enable row security (dump only content user has\n"
    1335              :              "                               access to)\n"));
    1336            1 :     printf(_("  --exclude-extension=PATTERN  do NOT dump the specified extension(s)\n"));
    1337            1 :     printf(_("  --exclude-table-and-children=PATTERN\n"
    1338              :              "                               do NOT dump the specified table(s), including\n"
    1339              :              "                               child and partition tables\n"));
    1340            1 :     printf(_("  --exclude-table-data=PATTERN do NOT dump data for the specified table(s)\n"));
    1341            1 :     printf(_("  --exclude-table-data-and-children=PATTERN\n"
    1342              :              "                               do NOT dump data for the specified table(s),\n"
    1343              :              "                               including child and partition tables\n"));
    1344            1 :     printf(_("  --extra-float-digits=NUM     override default setting for extra_float_digits\n"));
    1345            1 :     printf(_("  --filter=FILENAME            include or exclude objects and data from dump\n"
    1346              :              "                               based on expressions in FILENAME\n"));
    1347            1 :     printf(_("  --if-exists                  use IF EXISTS when dropping objects\n"));
    1348            1 :     printf(_("  --include-foreign-data=PATTERN\n"
    1349              :              "                               include data of foreign tables on foreign\n"
    1350              :              "                               servers matching PATTERN\n"));
    1351            1 :     printf(_("  --inserts                    dump data as INSERT commands, rather than COPY\n"));
    1352            1 :     printf(_("  --load-via-partition-root    load partitions via the root table\n"));
    1353            1 :     printf(_("  --no-comments                do not dump comment commands\n"));
    1354            1 :     printf(_("  --no-data                    do not dump data\n"));
    1355            1 :     printf(_("  --no-policies                do not dump row security policies\n"));
    1356            1 :     printf(_("  --no-publications            do not dump publications\n"));
    1357            1 :     printf(_("  --no-schema                  do not dump schema\n"));
    1358            1 :     printf(_("  --no-security-labels         do not dump security label assignments\n"));
    1359            1 :     printf(_("  --no-statistics              do not dump statistics\n"));
    1360            1 :     printf(_("  --no-subscriptions           do not dump subscriptions\n"));
    1361            1 :     printf(_("  --no-table-access-method     do not dump table access methods\n"));
    1362            1 :     printf(_("  --no-tablespaces             do not dump tablespace assignments\n"));
    1363            1 :     printf(_("  --no-toast-compression       do not dump TOAST compression methods\n"));
    1364            1 :     printf(_("  --no-unlogged-table-data     do not dump unlogged table data\n"));
    1365            1 :     printf(_("  --on-conflict-do-nothing     add ON CONFLICT DO NOTHING to INSERT commands\n"));
    1366            1 :     printf(_("  --quote-all-identifiers      quote all identifiers, even if not key words\n"));
    1367            1 :     printf(_("  --restrict-key=RESTRICT_KEY  use provided string as psql \\restrict key\n"));
    1368            1 :     printf(_("  --rows-per-insert=NROWS      number of rows per INSERT; implies --inserts\n"));
    1369            1 :     printf(_("  --section=SECTION            dump named section (pre-data, data, or post-data)\n"));
    1370            1 :     printf(_("  --sequence-data              include sequence data in dump\n"));
    1371            1 :     printf(_("  --serializable-deferrable    wait until the dump can run without anomalies\n"));
    1372            1 :     printf(_("  --snapshot=SNAPSHOT          use given snapshot for the dump\n"));
    1373            1 :     printf(_("  --statistics                 dump the statistics\n"));
    1374            1 :     printf(_("  --statistics-only            dump only the statistics, not schema or data\n"));
    1375            1 :     printf(_("  --strict-names               require table and/or schema include patterns to\n"
    1376              :              "                               match at least one entity each\n"));
    1377            1 :     printf(_("  --table-and-children=PATTERN dump only the specified table(s), including\n"
    1378              :              "                               child and partition tables\n"));
    1379            1 :     printf(_("  --use-set-session-authorization\n"
    1380              :              "                               use SET SESSION AUTHORIZATION commands instead of\n"
    1381              :              "                               ALTER OWNER commands to set ownership\n"));
    1382              : 
    1383            1 :     printf(_("\nConnection options:\n"));
    1384            1 :     printf(_("  -d, --dbname=DBNAME      database to dump\n"));
    1385            1 :     printf(_("  -h, --host=HOSTNAME      database server host or socket directory\n"));
    1386            1 :     printf(_("  -p, --port=PORT          database server port number\n"));
    1387            1 :     printf(_("  -U, --username=NAME      connect as specified database user\n"));
    1388            1 :     printf(_("  -w, --no-password        never prompt for password\n"));
    1389            1 :     printf(_("  -W, --password           force password prompt (should happen automatically)\n"));
    1390            1 :     printf(_("  --role=ROLENAME          do SET ROLE before dump\n"));
    1391              : 
    1392            1 :     printf(_("\nIf no database name is supplied, then the PGDATABASE environment\n"
    1393              :              "variable value is used.\n\n"));
    1394            1 :     printf(_("Report bugs to <%s>.\n"), PACKAGE_BUGREPORT);
    1395            1 :     printf(_("%s home page: <%s>\n"), PACKAGE_NAME, PACKAGE_URL);
    1396            1 : }
    1397              : 
    1398              : static void
    1399          292 : setup_connection(Archive *AH, const char *dumpencoding,
    1400              :                  const char *dumpsnapshot, char *use_role)
    1401              : {
    1402          292 :     DumpOptions *dopt = AH->dopt;
    1403          292 :     PGconn     *conn = GetConnection(AH);
    1404              : 
    1405          292 :     PQclear(ExecuteSqlQueryForSingleRow(AH, ALWAYS_SECURE_SEARCH_PATH_SQL));
    1406              : 
    1407              :     /*
    1408              :      * Set the client encoding if requested.
    1409              :      */
    1410          292 :     if (dumpencoding)
    1411              :     {
    1412           18 :         if (PQsetClientEncoding(conn, dumpencoding) < 0)
    1413            0 :             pg_fatal("invalid client encoding \"%s\" specified",
    1414              :                      dumpencoding);
    1415              :     }
    1416              : 
    1417              :     /*
    1418              :      * Force standard_conforming_strings on, just in case we are dumping from
    1419              :      * an old server that has it disabled.  Without this, literals in views,
    1420              :      * expressions, etc, would be incorrect for modern servers.
    1421              :      */
    1422          292 :     ExecuteSqlStatement(AH, "SET standard_conforming_strings = on");
    1423              : 
    1424              :     /*
    1425              :      * And reflect that to AH->std_strings.  You might think that we should
    1426              :      * just delete that variable and the code that checks it, but that would
    1427              :      * be problematic for pg_restore, which at least for now should still cope
    1428              :      * with archives containing the other setting (cf. processStdStringsEntry
    1429              :      * in pg_backup_archiver.c).
    1430              :      */
    1431          292 :     AH->std_strings = true;
    1432              : 
    1433              :     /*
    1434              :      * Get the active encoding, so we know how to escape strings.
    1435              :      */
    1436          292 :     AH->encoding = PQclientEncoding(conn);
    1437          292 :     setFmtEncoding(AH->encoding);
    1438              : 
    1439              :     /*
    1440              :      * Set the role if requested.  In a parallel dump worker, we'll be passed
    1441              :      * use_role == NULL, but AH->use_role is already set (if user specified it
    1442              :      * originally) and we should use that.
    1443              :      */
    1444          292 :     if (!use_role && AH->use_role)
    1445            2 :         use_role = AH->use_role;
    1446              : 
    1447              :     /* Set the role if requested */
    1448          292 :     if (use_role)
    1449              :     {
    1450            5 :         PQExpBuffer query = createPQExpBuffer();
    1451              : 
    1452            5 :         appendPQExpBuffer(query, "SET ROLE %s", fmtId(use_role));
    1453            5 :         ExecuteSqlStatement(AH, query->data);
    1454            5 :         destroyPQExpBuffer(query);
    1455              : 
    1456              :         /* save it for possible later use by parallel workers */
    1457            5 :         if (!AH->use_role)
    1458            3 :             AH->use_role = pg_strdup(use_role);
    1459              :     }
    1460              : 
    1461              :     /* Set the datestyle to ISO to ensure the dump's portability */
    1462          292 :     ExecuteSqlStatement(AH, "SET DATESTYLE = ISO");
    1463              : 
    1464              :     /* Likewise, avoid using sql_standard intervalstyle */
    1465          292 :     ExecuteSqlStatement(AH, "SET INTERVALSTYLE = POSTGRES");
    1466              : 
    1467              :     /*
    1468              :      * Use an explicitly specified extra_float_digits if it has been provided.
    1469              :      * Otherwise, set extra_float_digits so that we can dump float data
    1470              :      * exactly (given correctly implemented float I/O code, anyway).
    1471              :      */
    1472          292 :     if (have_extra_float_digits)
    1473              :     {
    1474            0 :         PQExpBuffer q = createPQExpBuffer();
    1475              : 
    1476            0 :         appendPQExpBuffer(q, "SET extra_float_digits TO %d",
    1477              :                           extra_float_digits);
    1478            0 :         ExecuteSqlStatement(AH, q->data);
    1479            0 :         destroyPQExpBuffer(q);
    1480              :     }
    1481              :     else
    1482          292 :         ExecuteSqlStatement(AH, "SET extra_float_digits TO 3");
    1483              : 
    1484              :     /*
    1485              :      * Disable synchronized scanning, to prevent unpredictable changes in row
    1486              :      * ordering across a dump and reload.
    1487              :      */
    1488          292 :     ExecuteSqlStatement(AH, "SET synchronize_seqscans TO off");
    1489              : 
    1490              :     /*
    1491              :      * Disable timeouts if supported.
    1492              :      */
    1493          292 :     ExecuteSqlStatement(AH, "SET statement_timeout = 0");
    1494          292 :     if (AH->remoteVersion >= 90300)
    1495          292 :         ExecuteSqlStatement(AH, "SET lock_timeout = 0");
    1496          292 :     if (AH->remoteVersion >= 90600)
    1497          292 :         ExecuteSqlStatement(AH, "SET idle_in_transaction_session_timeout = 0");
    1498          292 :     if (AH->remoteVersion >= 170000)
    1499          292 :         ExecuteSqlStatement(AH, "SET transaction_timeout = 0");
    1500              : 
    1501              :     /*
    1502              :      * Quote all identifiers, if requested.
    1503              :      */
    1504          292 :     if (quote_all_identifiers)
    1505           38 :         ExecuteSqlStatement(AH, "SET quote_all_identifiers = true");
    1506              : 
    1507              :     /*
    1508              :      * Adjust row-security mode, if supported.
    1509              :      */
    1510          292 :     if (AH->remoteVersion >= 90500)
    1511              :     {
    1512          292 :         if (dopt->enable_row_security)
    1513            0 :             ExecuteSqlStatement(AH, "SET row_security = on");
    1514              :         else
    1515          292 :             ExecuteSqlStatement(AH, "SET row_security = off");
    1516              :     }
    1517              : 
    1518              :     /*
    1519              :      * For security reasons, we restrict the expansion of non-system views and
    1520              :      * access to foreign tables during the pg_dump process. This restriction
    1521              :      * is adjusted when dumping foreign table data.
    1522              :      */
    1523          292 :     set_restrict_relation_kind(AH, "view, foreign-table");
    1524              : 
    1525              :     /*
    1526              :      * Initialize prepared-query state to "nothing prepared".  We do this here
    1527              :      * so that a parallel dump worker will have its own state.
    1528              :      */
    1529          292 :     AH->is_prepared = pg_malloc0_array(bool, NUM_PREP_QUERIES);
    1530              : 
    1531              :     /*
    1532              :      * Start transaction-snapshot mode transaction to dump consistent data.
    1533              :      */
    1534          292 :     ExecuteSqlStatement(AH, "BEGIN");
    1535              : 
    1536              :     /*
    1537              :      * To support the combination of serializable_deferrable with the jobs
    1538              :      * option we use REPEATABLE READ for the worker connections that are
    1539              :      * passed a snapshot.  As long as the snapshot is acquired in a
    1540              :      * SERIALIZABLE, READ ONLY, DEFERRABLE transaction, its use within a
    1541              :      * REPEATABLE READ transaction provides the appropriate integrity
    1542              :      * guarantees.  This is a kluge, but safe for back-patching.
    1543              :      */
    1544          292 :     if (dopt->serializable_deferrable && AH->sync_snapshot_id == NULL)
    1545            0 :         ExecuteSqlStatement(AH,
    1546              :                             "SET TRANSACTION ISOLATION LEVEL "
    1547              :                             "SERIALIZABLE, READ ONLY, DEFERRABLE");
    1548              :     else
    1549          292 :         ExecuteSqlStatement(AH,
    1550              :                             "SET TRANSACTION ISOLATION LEVEL "
    1551              :                             "REPEATABLE READ, READ ONLY");
    1552              : 
    1553              :     /*
    1554              :      * If user specified a snapshot to use, select that.  In a parallel dump
    1555              :      * worker, we'll be passed dumpsnapshot == NULL, but AH->sync_snapshot_id
    1556              :      * is already set (if the server can handle it) and we should use that.
    1557              :      */
    1558          292 :     if (dumpsnapshot)
    1559            0 :         AH->sync_snapshot_id = pg_strdup(dumpsnapshot);
    1560              : 
    1561          292 :     if (AH->sync_snapshot_id)
    1562              :     {
    1563           16 :         PQExpBuffer query = createPQExpBuffer();
    1564              : 
    1565           16 :         appendPQExpBufferStr(query, "SET TRANSACTION SNAPSHOT ");
    1566           16 :         appendStringLiteralConn(query, AH->sync_snapshot_id, conn);
    1567           16 :         ExecuteSqlStatement(AH, query->data);
    1568           16 :         destroyPQExpBuffer(query);
    1569              :     }
    1570          276 :     else if (AH->numWorkers > 1)
    1571              :     {
    1572            8 :         if (AH->isStandby && AH->remoteVersion < 100000)
    1573            0 :             pg_fatal("parallel dumps from standby servers are not supported by this server version");
    1574            8 :         AH->sync_snapshot_id = get_synchronized_snapshot(AH);
    1575              :     }
    1576          292 : }
    1577              : 
    1578              : /* Set up connection for a parallel worker process */
    1579              : static void
    1580           16 : setupDumpWorker(Archive *AH)
    1581              : {
    1582              :     /*
    1583              :      * We want to re-select all the same values the leader connection is
    1584              :      * using.  We'll have inherited directly-usable values in
    1585              :      * AH->sync_snapshot_id and AH->use_role, but we need to translate the
    1586              :      * inherited encoding value back to a string to pass to setup_connection.
    1587              :      */
    1588           16 :     setup_connection(AH,
    1589              :                      pg_encoding_to_char(AH->encoding),
    1590              :                      NULL,
    1591              :                      NULL);
    1592           16 : }
    1593              : 
    1594              : static char *
    1595            8 : get_synchronized_snapshot(Archive *fout)
    1596              : {
    1597            8 :     char       *query = "SELECT pg_catalog.pg_export_snapshot()";
    1598              :     char       *result;
    1599              :     PGresult   *res;
    1600              : 
    1601            8 :     res = ExecuteSqlQueryForSingleRow(fout, query);
    1602            8 :     result = pg_strdup(PQgetvalue(res, 0, 0));
    1603            8 :     PQclear(res);
    1604              : 
    1605            8 :     return result;
    1606              : }
    1607              : 
    1608              : static ArchiveFormat
    1609          285 : parseArchiveFormat(const char *format, ArchiveMode *mode)
    1610              : {
    1611              :     ArchiveFormat archiveFormat;
    1612              : 
    1613          285 :     *mode = archModeWrite;
    1614              : 
    1615          285 :     if (pg_strcasecmp(format, "a") == 0 || pg_strcasecmp(format, "append") == 0)
    1616              :     {
    1617              :         /* This is used by pg_dumpall, and is not documented */
    1618           48 :         archiveFormat = archNull;
    1619           48 :         *mode = archModeAppend;
    1620              :     }
    1621          237 :     else if (pg_strcasecmp(format, "c") == 0)
    1622            0 :         archiveFormat = archCustom;
    1623          237 :     else if (pg_strcasecmp(format, "custom") == 0)
    1624           56 :         archiveFormat = archCustom;
    1625          181 :     else if (pg_strcasecmp(format, "d") == 0)
    1626            0 :         archiveFormat = archDirectory;
    1627          181 :     else if (pg_strcasecmp(format, "directory") == 0)
    1628           65 :         archiveFormat = archDirectory;
    1629          116 :     else if (pg_strcasecmp(format, "p") == 0)
    1630          101 :         archiveFormat = archNull;
    1631           15 :     else if (pg_strcasecmp(format, "plain") == 0)
    1632            3 :         archiveFormat = archNull;
    1633           12 :     else if (pg_strcasecmp(format, "t") == 0)
    1634            0 :         archiveFormat = archTar;
    1635           12 :     else if (pg_strcasecmp(format, "tar") == 0)
    1636           11 :         archiveFormat = archTar;
    1637              :     else
    1638            1 :         pg_fatal("invalid output format \"%s\" specified", format);
    1639          284 :     return archiveFormat;
    1640              : }
    1641              : 
    1642              : /*
    1643              :  * Find the OIDs of all schemas matching the given list of patterns,
    1644              :  * and append them to the given OID list.
    1645              :  */
    1646              : static void
    1647          287 : expand_schema_name_patterns(Archive *fout,
    1648              :                             SimpleStringList *patterns,
    1649              :                             SimpleOidList *oids,
    1650              :                             bool strict_names)
    1651              : {
    1652              :     PQExpBuffer query;
    1653              :     PGresult   *res;
    1654              :     SimpleStringListCell *cell;
    1655              :     int         i;
    1656              : 
    1657          287 :     if (patterns->head == NULL)
    1658          266 :         return;                 /* nothing to do */
    1659              : 
    1660           21 :     query = createPQExpBuffer();
    1661              : 
    1662              :     /*
    1663              :      * The loop below runs multiple SELECTs might sometimes result in
    1664              :      * duplicate entries in the OID list, but we don't care.
    1665              :      */
    1666              : 
    1667           36 :     for (cell = patterns->head; cell; cell = cell->next)
    1668              :     {
    1669              :         PQExpBufferData dbbuf;
    1670              :         int         dotcnt;
    1671              : 
    1672           21 :         appendPQExpBufferStr(query,
    1673              :                              "SELECT oid FROM pg_catalog.pg_namespace n\n");
    1674           21 :         initPQExpBuffer(&dbbuf);
    1675           21 :         processSQLNamePattern(GetConnection(fout), query, cell->val, false,
    1676              :                               false, NULL, "n.nspname", NULL, NULL, &dbbuf,
    1677              :                               &dotcnt);
    1678           21 :         if (dotcnt > 1)
    1679            2 :             pg_fatal("improper qualified name (too many dotted names): %s",
    1680              :                      cell->val);
    1681           19 :         else if (dotcnt == 1)
    1682            3 :             prohibit_crossdb_refs(GetConnection(fout), dbbuf.data, cell->val);
    1683           16 :         termPQExpBuffer(&dbbuf);
    1684              : 
    1685           16 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    1686           16 :         if (strict_names && PQntuples(res) == 0)
    1687            1 :             pg_fatal("no matching schemas were found for pattern \"%s\"", cell->val);
    1688              : 
    1689           29 :         for (i = 0; i < PQntuples(res); i++)
    1690              :         {
    1691           14 :             simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
    1692              :         }
    1693              : 
    1694           15 :         PQclear(res);
    1695           15 :         resetPQExpBuffer(query);
    1696              :     }
    1697              : 
    1698           15 :     destroyPQExpBuffer(query);
    1699              : }
    1700              : 
    1701              : /*
    1702              :  * Find the OIDs of all extensions matching the given list of patterns,
    1703              :  * and append them to the given OID list.
    1704              :  */
    1705              : static void
    1706          265 : expand_extension_name_patterns(Archive *fout,
    1707              :                                SimpleStringList *patterns,
    1708              :                                SimpleOidList *oids,
    1709              :                                bool strict_names)
    1710              : {
    1711              :     PQExpBuffer query;
    1712              :     PGresult   *res;
    1713              :     SimpleStringListCell *cell;
    1714              :     int         i;
    1715              : 
    1716          265 :     if (patterns->head == NULL)
    1717          258 :         return;                 /* nothing to do */
    1718              : 
    1719            7 :     query = createPQExpBuffer();
    1720              : 
    1721              :     /*
    1722              :      * The loop below runs multiple SELECTs might sometimes result in
    1723              :      * duplicate entries in the OID list, but we don't care.
    1724              :      */
    1725           14 :     for (cell = patterns->head; cell; cell = cell->next)
    1726              :     {
    1727              :         int         dotcnt;
    1728              : 
    1729            7 :         appendPQExpBufferStr(query,
    1730              :                              "SELECT oid FROM pg_catalog.pg_extension e\n");
    1731            7 :         processSQLNamePattern(GetConnection(fout), query, cell->val, false,
    1732              :                               false, NULL, "e.extname", NULL, NULL, NULL,
    1733              :                               &dotcnt);
    1734            7 :         if (dotcnt > 0)
    1735            0 :             pg_fatal("improper qualified name (too many dotted names): %s",
    1736              :                      cell->val);
    1737              : 
    1738            7 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    1739            7 :         if (strict_names && PQntuples(res) == 0)
    1740            0 :             pg_fatal("no matching extensions were found for pattern \"%s\"", cell->val);
    1741              : 
    1742           13 :         for (i = 0; i < PQntuples(res); i++)
    1743              :         {
    1744            6 :             simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
    1745              :         }
    1746              : 
    1747            7 :         PQclear(res);
    1748            7 :         resetPQExpBuffer(query);
    1749              :     }
    1750              : 
    1751            7 :     destroyPQExpBuffer(query);
    1752              : }
    1753              : 
    1754              : /*
    1755              :  * Find the OIDs of all foreign servers matching the given list of patterns,
    1756              :  * and append them to the given OID list.
    1757              :  */
    1758              : static void
    1759          262 : expand_foreign_server_name_patterns(Archive *fout,
    1760              :                                     SimpleStringList *patterns,
    1761              :                                     SimpleOidList *oids)
    1762              : {
    1763              :     PQExpBuffer query;
    1764              :     PGresult   *res;
    1765              :     SimpleStringListCell *cell;
    1766              :     int         i;
    1767              : 
    1768          262 :     if (patterns->head == NULL)
    1769          259 :         return;                 /* nothing to do */
    1770              : 
    1771            3 :     query = createPQExpBuffer();
    1772              : 
    1773              :     /*
    1774              :      * The loop below runs multiple SELECTs might sometimes result in
    1775              :      * duplicate entries in the OID list, but we don't care.
    1776              :      */
    1777              : 
    1778            5 :     for (cell = patterns->head; cell; cell = cell->next)
    1779              :     {
    1780              :         int         dotcnt;
    1781              : 
    1782            3 :         appendPQExpBufferStr(query,
    1783              :                              "SELECT oid FROM pg_catalog.pg_foreign_server s\n");
    1784            3 :         processSQLNamePattern(GetConnection(fout), query, cell->val, false,
    1785              :                               false, NULL, "s.srvname", NULL, NULL, NULL,
    1786              :                               &dotcnt);
    1787            3 :         if (dotcnt > 0)
    1788            0 :             pg_fatal("improper qualified name (too many dotted names): %s",
    1789              :                      cell->val);
    1790              : 
    1791            3 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    1792            3 :         if (PQntuples(res) == 0)
    1793            1 :             pg_fatal("no matching foreign servers were found for pattern \"%s\"", cell->val);
    1794              : 
    1795            4 :         for (i = 0; i < PQntuples(res); i++)
    1796            2 :             simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
    1797              : 
    1798            2 :         PQclear(res);
    1799            2 :         resetPQExpBuffer(query);
    1800              :     }
    1801              : 
    1802            2 :     destroyPQExpBuffer(query);
    1803              : }
    1804              : 
    1805              : /*
    1806              :  * Find the OIDs of all tables matching the given list of patterns,
    1807              :  * and append them to the given OID list. See also expand_dbname_patterns()
    1808              :  * in pg_dumpall.c
    1809              :  */
    1810              : static void
    1811         1581 : expand_table_name_patterns(Archive *fout,
    1812              :                            SimpleStringList *patterns, SimpleOidList *oids,
    1813              :                            bool strict_names, bool with_child_tables)
    1814              : {
    1815              :     PQExpBuffer query;
    1816              :     PGresult   *res;
    1817              :     SimpleStringListCell *cell;
    1818              :     int         i;
    1819              : 
    1820         1581 :     if (patterns->head == NULL)
    1821         1552 :         return;                 /* nothing to do */
    1822              : 
    1823           29 :     query = createPQExpBuffer();
    1824              : 
    1825              :     /*
    1826              :      * this might sometimes result in duplicate entries in the OID list, but
    1827              :      * we don't care.
    1828              :      */
    1829              : 
    1830           59 :     for (cell = patterns->head; cell; cell = cell->next)
    1831              :     {
    1832              :         PQExpBufferData dbbuf;
    1833              :         int         dotcnt;
    1834              : 
    1835              :         /*
    1836              :          * Query must remain ABSOLUTELY devoid of unqualified names.  This
    1837              :          * would be unnecessary given a pg_table_is_visible() variant taking a
    1838              :          * search_path argument.
    1839              :          *
    1840              :          * For with_child_tables, we start with the basic query's results and
    1841              :          * recursively search the inheritance tree to add child tables.
    1842              :          */
    1843           35 :         if (with_child_tables)
    1844              :         {
    1845            6 :             appendPQExpBufferStr(query, "WITH RECURSIVE partition_tree (relid) AS (\n");
    1846              :         }
    1847              : 
    1848           35 :         appendPQExpBuffer(query,
    1849              :                           "SELECT c.oid"
    1850              :                           "\nFROM pg_catalog.pg_class c"
    1851              :                           "\n     LEFT JOIN pg_catalog.pg_namespace n"
    1852              :                           "\n     ON n.oid OPERATOR(pg_catalog.=) c.relnamespace"
    1853              :                           "\nWHERE c.relkind OPERATOR(pg_catalog.=) ANY"
    1854              :                           "\n    (array['%c', '%c', '%c', '%c', '%c', '%c', '%c'])\n",
    1855              :                           RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_VIEW,
    1856              :                           RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE,
    1857              :                           RELKIND_PARTITIONED_TABLE, RELKIND_PROPGRAPH);
    1858           35 :         initPQExpBuffer(&dbbuf);
    1859           35 :         processSQLNamePattern(GetConnection(fout), query, cell->val, true,
    1860              :                               false, "n.nspname", "c.relname", NULL,
    1861              :                               "pg_catalog.pg_table_is_visible(c.oid)", &dbbuf,
    1862              :                               &dotcnt);
    1863           35 :         if (dotcnt > 2)
    1864            1 :             pg_fatal("improper relation name (too many dotted names): %s",
    1865              :                      cell->val);
    1866           34 :         else if (dotcnt == 2)
    1867            2 :             prohibit_crossdb_refs(GetConnection(fout), dbbuf.data, cell->val);
    1868           32 :         termPQExpBuffer(&dbbuf);
    1869              : 
    1870           32 :         if (with_child_tables)
    1871              :         {
    1872            6 :             appendPQExpBufferStr(query, "UNION"
    1873              :                                  "\nSELECT i.inhrelid"
    1874              :                                  "\nFROM partition_tree p"
    1875              :                                  "\n     JOIN pg_catalog.pg_inherits i"
    1876              :                                  "\n     ON p.relid OPERATOR(pg_catalog.=) i.inhparent"
    1877              :                                  "\n)"
    1878              :                                  "\nSELECT relid FROM partition_tree");
    1879              :         }
    1880              : 
    1881           32 :         ExecuteSqlStatement(fout, "RESET search_path");
    1882           32 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    1883           32 :         PQclear(ExecuteSqlQueryForSingleRow(fout,
    1884              :                                             ALWAYS_SECURE_SEARCH_PATH_SQL));
    1885           32 :         if (strict_names && PQntuples(res) == 0)
    1886            2 :             pg_fatal("no matching tables were found for pattern \"%s\"", cell->val);
    1887              : 
    1888           74 :         for (i = 0; i < PQntuples(res); i++)
    1889              :         {
    1890           44 :             simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
    1891              :         }
    1892              : 
    1893           30 :         PQclear(res);
    1894           30 :         resetPQExpBuffer(query);
    1895              :     }
    1896              : 
    1897           24 :     destroyPQExpBuffer(query);
    1898              : }
    1899              : 
    1900              : /*
    1901              :  * Verifies that the connected database name matches the given database name,
    1902              :  * and if not, dies with an error about the given pattern.
    1903              :  *
    1904              :  * The 'dbname' argument should be a literal name parsed from 'pattern'.
    1905              :  */
    1906              : static void
    1907            5 : prohibit_crossdb_refs(PGconn *conn, const char *dbname, const char *pattern)
    1908              : {
    1909              :     const char *db;
    1910              : 
    1911            5 :     db = PQdb(conn);
    1912            5 :     if (db == NULL)
    1913            0 :         pg_fatal("You are currently not connected to a database.");
    1914              : 
    1915            5 :     if (strcmp(db, dbname) != 0)
    1916            5 :         pg_fatal("cross-database references are not implemented: %s",
    1917              :                  pattern);
    1918            0 : }
    1919              : 
    1920              : /*
    1921              :  * checkExtensionMembership
    1922              :  *      Determine whether object is an extension member, and if so,
    1923              :  *      record an appropriate dependency and set the object's dump flag.
    1924              :  *
    1925              :  * It's important to call this for each object that could be an extension
    1926              :  * member.  Generally, we integrate this with determining the object's
    1927              :  * to-be-dumped-ness, since extension membership overrides other rules for that.
    1928              :  *
    1929              :  * Returns true if object is an extension member, else false.
    1930              :  */
    1931              : static bool
    1932       834297 : checkExtensionMembership(DumpableObject *dobj, Archive *fout)
    1933              : {
    1934       834297 :     ExtensionInfo *ext = findOwningExtension(dobj->catId);
    1935              : 
    1936       834297 :     if (ext == NULL)
    1937       833412 :         return false;
    1938              : 
    1939          885 :     dobj->ext_member = true;
    1940              : 
    1941              :     /* Record dependency so that getDependencies needn't deal with that */
    1942          885 :     addObjectDependency(dobj, ext->dobj.dumpId);
    1943              : 
    1944              :     /*
    1945              :      * In 9.6 and above, mark the member object to have any non-initial ACLs
    1946              :      * dumped.  (Any initial ACLs will be removed later, using data from
    1947              :      * pg_init_privs, so that we'll dump only the delta from the extension's
    1948              :      * initial setup.)
    1949              :      *
    1950              :      * Prior to 9.6, we do not include any extension member components.
    1951              :      *
    1952              :      * In binary upgrades, we still dump all components of the members
    1953              :      * individually, since the idea is to exactly reproduce the database
    1954              :      * contents rather than replace the extension contents with something
    1955              :      * different.
    1956              :      *
    1957              :      * Note: it might be interesting someday to implement storage and delta
    1958              :      * dumping of extension members' RLS policies and/or security labels.
    1959              :      * However there is a pitfall for RLS policies: trying to dump them
    1960              :      * requires getting a lock on their tables, and the calling user might not
    1961              :      * have privileges for that.  We need no lock to examine a table's ACLs,
    1962              :      * so the current feature doesn't have a problem of that sort.
    1963              :      */
    1964          885 :     if (fout->dopt->binary_upgrade)
    1965          186 :         dobj->dump = ext->dobj.dump;
    1966              :     else
    1967              :     {
    1968          699 :         if (fout->remoteVersion < 90600)
    1969            0 :             dobj->dump = DUMP_COMPONENT_NONE;
    1970              :         else
    1971          699 :             dobj->dump = ext->dobj.dump_contains & (DUMP_COMPONENT_ACL);
    1972              :     }
    1973              : 
    1974          885 :     return true;
    1975              : }
    1976              : 
    1977              : /*
    1978              :  * selectDumpableNamespace: policy-setting subroutine
    1979              :  *      Mark a namespace as to be dumped or not
    1980              :  */
    1981              : static void
    1982         1771 : selectDumpableNamespace(NamespaceInfo *nsinfo, Archive *fout)
    1983              : {
    1984              :     /*
    1985              :      * DUMP_COMPONENT_DEFINITION typically implies a CREATE SCHEMA statement
    1986              :      * and (for --clean) a DROP SCHEMA statement.  (In the absence of
    1987              :      * DUMP_COMPONENT_DEFINITION, this value is irrelevant.)
    1988              :      */
    1989         1771 :     nsinfo->create = true;
    1990              : 
    1991              :     /*
    1992              :      * If specific tables are being dumped, do not dump any complete
    1993              :      * namespaces. If specific namespaces are being dumped, dump just those
    1994              :      * namespaces. Otherwise, dump all non-system namespaces.
    1995              :      */
    1996         1771 :     if (table_include_oids.head != NULL)
    1997           50 :         nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
    1998         1721 :     else if (schema_include_oids.head != NULL)
    1999          195 :         nsinfo->dobj.dump_contains = nsinfo->dobj.dump =
    2000          195 :             simple_oid_list_member(&schema_include_oids,
    2001              :                                    nsinfo->dobj.catId.oid) ?
    2002          195 :             DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
    2003         1526 :     else if (fout->remoteVersion >= 90600 &&
    2004         1526 :              strcmp(nsinfo->dobj.name, "pg_catalog") == 0)
    2005              :     {
    2006              :         /*
    2007              :          * In 9.6 and above, we dump out any ACLs defined in pg_catalog, if
    2008              :          * they are interesting (and not the original ACLs which were set at
    2009              :          * initdb time, see pg_init_privs).
    2010              :          */
    2011          238 :         nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_ACL;
    2012              :     }
    2013         1288 :     else if (strncmp(nsinfo->dobj.name, "pg_", 3) == 0 ||
    2014          678 :              strcmp(nsinfo->dobj.name, "information_schema") == 0)
    2015              :     {
    2016              :         /* Other system schemas don't get dumped */
    2017          848 :         nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
    2018              :     }
    2019          440 :     else if (strcmp(nsinfo->dobj.name, "public") == 0)
    2020              :     {
    2021              :         /*
    2022              :          * The public schema is a strange beast that sits in a sort of
    2023              :          * no-mans-land between being a system object and a user object.
    2024              :          * CREATE SCHEMA would fail, so its DUMP_COMPONENT_DEFINITION is just
    2025              :          * a comment and an indication of ownership.  If the owner is the
    2026              :          * default, omit that superfluous DUMP_COMPONENT_DEFINITION.  Before
    2027              :          * v15, the default owner was BOOTSTRAP_SUPERUSERID.
    2028              :          */
    2029          234 :         nsinfo->create = false;
    2030          234 :         nsinfo->dobj.dump = DUMP_COMPONENT_ALL;
    2031          234 :         if (nsinfo->nspowner == ROLE_PG_DATABASE_OWNER)
    2032          192 :             nsinfo->dobj.dump &= ~DUMP_COMPONENT_DEFINITION;
    2033          234 :         nsinfo->dobj.dump_contains = DUMP_COMPONENT_ALL;
    2034              : 
    2035              :         /*
    2036              :          * Also, make like it has a comment even if it doesn't; this is so
    2037              :          * that we'll emit a command to drop the comment, if appropriate.
    2038              :          * (Without this, we'd not call dumpCommentExtended for it.)
    2039              :          */
    2040          234 :         nsinfo->dobj.components |= DUMP_COMPONENT_COMMENT;
    2041              :     }
    2042              :     else
    2043          206 :         nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_ALL;
    2044              : 
    2045              :     /*
    2046              :      * In any case, a namespace can be excluded by an exclusion switch
    2047              :      */
    2048         2460 :     if (nsinfo->dobj.dump_contains &&
    2049          689 :         simple_oid_list_member(&schema_exclude_oids,
    2050              :                                nsinfo->dobj.catId.oid))
    2051            3 :         nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
    2052              : 
    2053              :     /*
    2054              :      * If the schema belongs to an extension, allow extension membership to
    2055              :      * override the dump decision for the schema itself.  However, this does
    2056              :      * not change dump_contains, so this won't change what we do with objects
    2057              :      * within the schema.  (If they belong to the extension, they'll get
    2058              :      * suppressed by it, otherwise not.)
    2059              :      */
    2060         1771 :     (void) checkExtensionMembership(&nsinfo->dobj, fout);
    2061         1771 : }
    2062              : 
    2063              : /*
    2064              :  * selectDumpableTable: policy-setting subroutine
    2065              :  *      Mark a table as to be dumped or not
    2066              :  */
    2067              : static void
    2068        70838 : selectDumpableTable(TableInfo *tbinfo, Archive *fout)
    2069              : {
    2070        70838 :     if (checkExtensionMembership(&tbinfo->dobj, fout))
    2071          225 :         return;                 /* extension membership overrides all else */
    2072              : 
    2073              :     /*
    2074              :      * If specific tables are being dumped, dump just those tables; else, dump
    2075              :      * according to the parent namespace's dump flag.
    2076              :      */
    2077        70613 :     if (table_include_oids.head != NULL)
    2078         5646 :         tbinfo->dobj.dump = simple_oid_list_member(&table_include_oids,
    2079              :                                                    tbinfo->dobj.catId.oid) ?
    2080         2823 :             DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
    2081              :     else
    2082        67790 :         tbinfo->dobj.dump = tbinfo->dobj.namespace->dobj.dump_contains;
    2083              : 
    2084              :     /*
    2085              :      * In any case, a table can be excluded by an exclusion switch
    2086              :      */
    2087       115424 :     if (tbinfo->dobj.dump &&
    2088        44811 :         simple_oid_list_member(&table_exclude_oids,
    2089              :                                tbinfo->dobj.catId.oid))
    2090           12 :         tbinfo->dobj.dump = DUMP_COMPONENT_NONE;
    2091              : }
    2092              : 
    2093              : /*
    2094              :  * selectDumpableType: policy-setting subroutine
    2095              :  *      Mark a type as to be dumped or not
    2096              :  *
    2097              :  * If it's a table's rowtype or an autogenerated array type, we also apply a
    2098              :  * special type code to facilitate sorting into the desired order.  (We don't
    2099              :  * want to consider those to be ordinary types because that would bring tables
    2100              :  * up into the datatype part of the dump order.)  We still set the object's
    2101              :  * dump flag; that's not going to cause the dummy type to be dumped, but we
    2102              :  * need it so that casts involving such types will be dumped correctly -- see
    2103              :  * dumpCast.  This means the flag should be set the same as for the underlying
    2104              :  * object (the table or base type).
    2105              :  */
    2106              : static void
    2107       193219 : selectDumpableType(TypeInfo *tyinfo, Archive *fout)
    2108              : {
    2109              :     /* skip complex types, except for standalone composite types */
    2110       193219 :     if (OidIsValid(tyinfo->typrelid) &&
    2111        70080 :         tyinfo->typrelkind != RELKIND_COMPOSITE_TYPE)
    2112              :     {
    2113        69898 :         TableInfo  *tytable = findTableByOid(tyinfo->typrelid);
    2114              : 
    2115        69898 :         tyinfo->dobj.objType = DO_DUMMY_TYPE;
    2116        69898 :         if (tytable != NULL)
    2117        69898 :             tyinfo->dobj.dump = tytable->dobj.dump;
    2118              :         else
    2119            0 :             tyinfo->dobj.dump = DUMP_COMPONENT_NONE;
    2120        69898 :         return;
    2121              :     }
    2122              : 
    2123              :     /* skip auto-generated array and multirange types */
    2124       123321 :     if (tyinfo->isArray || tyinfo->isMultirange)
    2125              :     {
    2126        94521 :         tyinfo->dobj.objType = DO_DUMMY_TYPE;
    2127              : 
    2128              :         /*
    2129              :          * Fall through to set the dump flag; we assume that the subsequent
    2130              :          * rules will do the same thing as they would for the array's base
    2131              :          * type or multirange's range type.  (We cannot reliably look up the
    2132              :          * base type here, since getTypes may not have processed it yet.)
    2133              :          */
    2134              :     }
    2135              : 
    2136       123321 :     if (checkExtensionMembership(&tyinfo->dobj, fout))
    2137          150 :         return;                 /* extension membership overrides all else */
    2138              : 
    2139              :     /* Dump based on if the contents of the namespace are being dumped */
    2140       123171 :     tyinfo->dobj.dump = tyinfo->dobj.namespace->dobj.dump_contains;
    2141              : }
    2142              : 
    2143              : /*
    2144              :  * selectDumpableDefaultACL: policy-setting subroutine
    2145              :  *      Mark a default ACL as to be dumped or not
    2146              :  *
    2147              :  * For per-schema default ACLs, dump if the schema is to be dumped.
    2148              :  * Otherwise dump if we are dumping "everything".  Note that dumpSchema
    2149              :  * and aclsSkip are checked separately.
    2150              :  */
    2151              : static void
    2152          194 : selectDumpableDefaultACL(DefaultACLInfo *dinfo, DumpOptions *dopt)
    2153              : {
    2154              :     /* Default ACLs can't be extension members */
    2155              : 
    2156          194 :     if (dinfo->dobj.namespace)
    2157              :         /* default ACLs are considered part of the namespace */
    2158           90 :         dinfo->dobj.dump = dinfo->dobj.namespace->dobj.dump_contains;
    2159              :     else
    2160          104 :         dinfo->dobj.dump = dopt->include_everything ?
    2161          104 :             DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
    2162          194 : }
    2163              : 
    2164              : /*
    2165              :  * selectDumpableCast: policy-setting subroutine
    2166              :  *      Mark a cast as to be dumped or not
    2167              :  *
    2168              :  * Casts do not belong to any particular namespace (since they haven't got
    2169              :  * names), nor do they have identifiable owners.  To distinguish user-defined
    2170              :  * casts from built-in ones, we must resort to checking whether the cast's
    2171              :  * OID is in the range reserved for initdb.
    2172              :  */
    2173              : static void
    2174        63024 : selectDumpableCast(CastInfo *cast, Archive *fout)
    2175              : {
    2176        63024 :     if (checkExtensionMembership(&cast->dobj, fout))
    2177            0 :         return;                 /* extension membership overrides all else */
    2178              : 
    2179              :     /*
    2180              :      * This would be DUMP_COMPONENT_ACL for from-initdb casts, but they do not
    2181              :      * support ACLs currently.
    2182              :      */
    2183        63024 :     if (cast->dobj.catId.oid <= g_last_builtin_oid)
    2184        62937 :         cast->dobj.dump = DUMP_COMPONENT_NONE;
    2185              :     else
    2186           87 :         cast->dobj.dump = fout->dopt->include_everything ?
    2187           87 :             DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
    2188              : }
    2189              : 
    2190              : /*
    2191              :  * selectDumpableProcLang: policy-setting subroutine
    2192              :  *      Mark a procedural language as to be dumped or not
    2193              :  *
    2194              :  * Procedural languages do not belong to any particular namespace.  To
    2195              :  * identify built-in languages, we must resort to checking whether the
    2196              :  * language's OID is in the range reserved for initdb.
    2197              :  */
    2198              : static void
    2199          304 : selectDumpableProcLang(ProcLangInfo *plang, Archive *fout)
    2200              : {
    2201          304 :     if (checkExtensionMembership(&plang->dobj, fout))
    2202          259 :         return;                 /* extension membership overrides all else */
    2203              : 
    2204              :     /*
    2205              :      * Only include procedural languages when we are dumping everything.
    2206              :      *
    2207              :      * For from-initdb procedural languages, only include ACLs, as we do for
    2208              :      * the pg_catalog namespace.  We need this because procedural languages do
    2209              :      * not live in any namespace.
    2210              :      */
    2211           45 :     if (!fout->dopt->include_everything)
    2212            8 :         plang->dobj.dump = DUMP_COMPONENT_NONE;
    2213              :     else
    2214              :     {
    2215           37 :         if (plang->dobj.catId.oid <= g_last_builtin_oid)
    2216            0 :             plang->dobj.dump = fout->remoteVersion < 90600 ?
    2217            0 :                 DUMP_COMPONENT_NONE : DUMP_COMPONENT_ACL;
    2218              :         else
    2219           37 :             plang->dobj.dump = DUMP_COMPONENT_ALL;
    2220              :     }
    2221              : }
    2222              : 
    2223              : /*
    2224              :  * selectDumpableAccessMethod: policy-setting subroutine
    2225              :  *      Mark an access method as to be dumped or not
    2226              :  *
    2227              :  * Access methods do not belong to any particular namespace.  To identify
    2228              :  * built-in access methods, we must resort to checking whether the
    2229              :  * method's OID is in the range reserved for initdb.
    2230              :  */
    2231              : static void
    2232         1935 : selectDumpableAccessMethod(AccessMethodInfo *method, Archive *fout)
    2233              : {
    2234              :     /* see getAccessMethods() comment about v9.6. */
    2235         1935 :     if (fout->remoteVersion < 90600)
    2236              :     {
    2237            0 :         method->dobj.dump = DUMP_COMPONENT_NONE;
    2238            0 :         return;
    2239              :     }
    2240              : 
    2241         1935 :     if (checkExtensionMembership(&method->dobj, fout))
    2242           25 :         return;                 /* extension membership overrides all else */
    2243              : 
    2244              :     /*
    2245              :      * This would be DUMP_COMPONENT_ACL for from-initdb access methods, but
    2246              :      * they do not support ACLs currently.
    2247              :      */
    2248         1910 :     if (method->dobj.catId.oid <= g_last_builtin_oid)
    2249         1813 :         method->dobj.dump = DUMP_COMPONENT_NONE;
    2250              :     else
    2251           97 :         method->dobj.dump = fout->dopt->include_everything ?
    2252           97 :             DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
    2253              : }
    2254              : 
    2255              : /*
    2256              :  * selectDumpableExtension: policy-setting subroutine
    2257              :  *      Mark an extension as to be dumped or not
    2258              :  *
    2259              :  * Built-in extensions should be skipped except for checking ACLs, since we
    2260              :  * assume those will already be installed in the target database.  We identify
    2261              :  * such extensions by their having OIDs in the range reserved for initdb.
    2262              :  * We dump all user-added extensions by default.  No extensions are dumped
    2263              :  * if include_everything is false (i.e., a --schema or --table switch was
    2264              :  * given), except if --extension specifies a list of extensions to dump.
    2265              :  */
    2266              : static void
    2267          291 : selectDumpableExtension(ExtensionInfo *extinfo, DumpOptions *dopt)
    2268              : {
    2269              :     /*
    2270              :      * Use DUMP_COMPONENT_ACL for built-in extensions, to allow users to
    2271              :      * change permissions on their member objects, if they wish to, and have
    2272              :      * those changes preserved.
    2273              :      */
    2274          291 :     if (extinfo->dobj.catId.oid <= g_last_builtin_oid)
    2275          260 :         extinfo->dobj.dump = extinfo->dobj.dump_contains = DUMP_COMPONENT_ACL;
    2276              :     else
    2277              :     {
    2278              :         /* check if there is a list of extensions to dump */
    2279           31 :         if (extension_include_oids.head != NULL)
    2280            4 :             extinfo->dobj.dump = extinfo->dobj.dump_contains =
    2281            4 :                 simple_oid_list_member(&extension_include_oids,
    2282              :                                        extinfo->dobj.catId.oid) ?
    2283            4 :                 DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
    2284              :         else
    2285           27 :             extinfo->dobj.dump = extinfo->dobj.dump_contains =
    2286           27 :                 dopt->include_everything ?
    2287           27 :                 DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
    2288              : 
    2289              :         /* check that the extension is not explicitly excluded */
    2290           58 :         if (extinfo->dobj.dump &&
    2291           27 :             simple_oid_list_member(&extension_exclude_oids,
    2292              :                                    extinfo->dobj.catId.oid))
    2293            2 :             extinfo->dobj.dump = extinfo->dobj.dump_contains = DUMP_COMPONENT_NONE;
    2294              :     }
    2295          291 : }
    2296              : 
    2297              : /*
    2298              :  * selectDumpablePublicationObject: policy-setting subroutine
    2299              :  *      Mark a publication object as to be dumped or not
    2300              :  *
    2301              :  * A publication can have schemas and tables which have schemas, but those are
    2302              :  * ignored in decision making, because publications are only dumped when we are
    2303              :  * dumping everything.
    2304              :  */
    2305              : static void
    2306          475 : selectDumpablePublicationObject(DumpableObject *dobj, Archive *fout)
    2307              : {
    2308          475 :     if (checkExtensionMembership(dobj, fout))
    2309            0 :         return;                 /* extension membership overrides all else */
    2310              : 
    2311          475 :     dobj->dump = fout->dopt->include_everything ?
    2312          475 :         DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
    2313              : }
    2314              : 
    2315              : /*
    2316              :  * selectDumpableStatisticsObject: policy-setting subroutine
    2317              :  *      Mark an extended statistics object as to be dumped or not
    2318              :  *
    2319              :  * We dump an extended statistics object if the schema it's in and the table
    2320              :  * it's for are being dumped.  (This'll need more thought if statistics
    2321              :  * objects ever support cross-table stats.)
    2322              :  */
    2323              : static void
    2324          208 : selectDumpableStatisticsObject(StatsExtInfo *sobj, Archive *fout)
    2325              : {
    2326          208 :     if (checkExtensionMembership(&sobj->dobj, fout))
    2327            0 :         return;                 /* extension membership overrides all else */
    2328              : 
    2329          208 :     sobj->dobj.dump = sobj->dobj.namespace->dobj.dump_contains;
    2330          208 :     if (sobj->stattable == NULL ||
    2331          208 :         !(sobj->stattable->dobj.dump & DUMP_COMPONENT_DEFINITION))
    2332           35 :         sobj->dobj.dump = DUMP_COMPONENT_NONE;
    2333              : }
    2334              : 
    2335              : /*
    2336              :  * selectDumpableObject: policy-setting subroutine
    2337              :  *      Mark a generic dumpable object as to be dumped or not
    2338              :  *
    2339              :  * Use this only for object types without a special-case routine above.
    2340              :  */
    2341              : static void
    2342       572421 : selectDumpableObject(DumpableObject *dobj, Archive *fout)
    2343              : {
    2344       572421 :     if (checkExtensionMembership(dobj, fout))
    2345          201 :         return;                 /* extension membership overrides all else */
    2346              : 
    2347              :     /*
    2348              :      * Default policy is to dump if parent namespace is dumpable, or for
    2349              :      * non-namespace-associated items, dump if we're dumping "everything".
    2350              :      */
    2351       572220 :     if (dobj->namespace)
    2352       571356 :         dobj->dump = dobj->namespace->dobj.dump_contains;
    2353              :     else
    2354          864 :         dobj->dump = fout->dopt->include_everything ?
    2355          864 :             DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
    2356              : }
    2357              : 
    2358              : /*
    2359              :  *  Dump a table's contents for loading using the COPY command
    2360              :  *  - this routine is called by the Archiver when it wants the table
    2361              :  *    to be dumped.
    2362              :  */
    2363              : static int
    2364         4483 : dumpTableData_copy(Archive *fout, const void *dcontext)
    2365              : {
    2366         4483 :     const TableDataInfo *tdinfo = dcontext;
    2367         4483 :     const TableInfo *tbinfo = tdinfo->tdtable;
    2368         4483 :     const char *classname = tbinfo->dobj.name;
    2369         4483 :     PQExpBuffer q = createPQExpBuffer();
    2370              : 
    2371              :     /*
    2372              :      * Note: can't use getThreadLocalPQExpBuffer() here, we're calling fmtId
    2373              :      * which uses it already.
    2374              :      */
    2375         4483 :     PQExpBuffer clistBuf = createPQExpBuffer();
    2376         4483 :     PGconn     *conn = GetConnection(fout);
    2377              :     PGresult   *res;
    2378              :     int         ret;
    2379              :     char       *copybuf;
    2380              :     const char *column_list;
    2381              : 
    2382         4483 :     pg_log_info("dumping contents of table \"%s.%s\"",
    2383              :                 tbinfo->dobj.namespace->dobj.name, classname);
    2384              : 
    2385              :     /*
    2386              :      * Specify the column list explicitly so that we have no possibility of
    2387              :      * retrieving data in the wrong column order.  (The default column
    2388              :      * ordering of COPY will not be what we want in certain corner cases
    2389              :      * involving ADD COLUMN and inheritance.)
    2390              :      */
    2391         4483 :     column_list = fmtCopyColumnList(tbinfo, clistBuf);
    2392              : 
    2393              :     /*
    2394              :      * Use COPY (SELECT ...) TO when dumping a foreign table's data, when a
    2395              :      * filter condition was specified, and when in binary upgrade mode and
    2396              :      * dumping an old pg_largeobject_metadata defined WITH OIDS.  For other
    2397              :      * cases a simple COPY suffices.
    2398              :      */
    2399         4483 :     if (tdinfo->filtercond || tbinfo->relkind == RELKIND_FOREIGN_TABLE ||
    2400         4442 :         (fout->dopt->binary_upgrade && fout->remoteVersion < 120000 &&
    2401            0 :          tbinfo->dobj.catId.oid == LargeObjectMetadataRelationId))
    2402              :     {
    2403              :         /* Temporary allows to access to foreign tables to dump data */
    2404           41 :         if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
    2405            1 :             set_restrict_relation_kind(fout, "view");
    2406              : 
    2407           41 :         appendPQExpBufferStr(q, "COPY (SELECT ");
    2408              :         /* klugery to get rid of parens in column list */
    2409           41 :         if (strlen(column_list) > 2)
    2410              :         {
    2411           41 :             appendPQExpBufferStr(q, column_list + 1);
    2412           41 :             q->data[q->len - 1] = ' ';
    2413              :         }
    2414              :         else
    2415            0 :             appendPQExpBufferStr(q, "* ");
    2416              : 
    2417           82 :         appendPQExpBuffer(q, "FROM %s %s) TO stdout;",
    2418           41 :                           fmtQualifiedDumpable(tbinfo),
    2419           41 :                           tdinfo->filtercond ? tdinfo->filtercond : "");
    2420              :     }
    2421              :     else
    2422              :     {
    2423         4442 :         appendPQExpBuffer(q, "COPY %s %s TO stdout;",
    2424         4442 :                           fmtQualifiedDumpable(tbinfo),
    2425              :                           column_list);
    2426              :     }
    2427         4483 :     res = ExecuteSqlQuery(fout, q->data, PGRES_COPY_OUT);
    2428         4482 :     PQclear(res);
    2429         4482 :     destroyPQExpBuffer(clistBuf);
    2430              : 
    2431              :     for (;;)
    2432              :     {
    2433      1823941 :         ret = PQgetCopyData(conn, &copybuf, 0);
    2434              : 
    2435      1823941 :         if (ret < 0)
    2436         4482 :             break;              /* done or error */
    2437              : 
    2438      1819459 :         if (copybuf)
    2439              :         {
    2440      1819459 :             WriteData(fout, copybuf, ret);
    2441      1819459 :             PQfreemem(copybuf);
    2442              :         }
    2443              : 
    2444              :         /* ----------
    2445              :          * THROTTLE:
    2446              :          *
    2447              :          * There was considerable discussion in late July, 2000 regarding
    2448              :          * slowing down pg_dump when backing up large tables. Users with both
    2449              :          * slow & fast (multi-processor) machines experienced performance
    2450              :          * degradation when doing a backup.
    2451              :          *
    2452              :          * Initial attempts based on sleeping for a number of ms for each ms
    2453              :          * of work were deemed too complex, then a simple 'sleep in each loop'
    2454              :          * implementation was suggested. The latter failed because the loop
    2455              :          * was too tight. Finally, the following was implemented:
    2456              :          *
    2457              :          * If throttle is non-zero, then
    2458              :          *      See how long since the last sleep.
    2459              :          *      Work out how long to sleep (based on ratio).
    2460              :          *      If sleep is more than 100ms, then
    2461              :          *          sleep
    2462              :          *          reset timer
    2463              :          *      EndIf
    2464              :          * EndIf
    2465              :          *
    2466              :          * where the throttle value was the number of ms to sleep per ms of
    2467              :          * work. The calculation was done in each loop.
    2468              :          *
    2469              :          * Most of the hard work is done in the backend, and this solution
    2470              :          * still did not work particularly well: on slow machines, the ratio
    2471              :          * was 50:1, and on medium paced machines, 1:1, and on fast
    2472              :          * multi-processor machines, it had little or no effect, for reasons
    2473              :          * that were unclear.
    2474              :          *
    2475              :          * Further discussion ensued, and the proposal was dropped.
    2476              :          *
    2477              :          * For those people who want this feature, it can be implemented using
    2478              :          * gettimeofday in each loop, calculating the time since last sleep,
    2479              :          * multiplying that by the sleep ratio, then if the result is more
    2480              :          * than a preset 'minimum sleep time' (say 100ms), call the 'select'
    2481              :          * function to sleep for a subsecond period ie.
    2482              :          *
    2483              :          * select(0, NULL, NULL, NULL, &tvi);
    2484              :          *
    2485              :          * This will return after the interval specified in the structure tvi.
    2486              :          * Finally, call gettimeofday again to save the 'last sleep time'.
    2487              :          * ----------
    2488              :          */
    2489              :     }
    2490         4482 :     archprintf(fout, "\\.\n\n\n");
    2491              : 
    2492         4482 :     if (ret == -2)
    2493              :     {
    2494              :         /* copy data transfer failed */
    2495            0 :         pg_log_error("Dumping the contents of table \"%s\" failed: PQgetCopyData() failed.", classname);
    2496            0 :         pg_log_error_detail("Error message from server: %s", PQerrorMessage(conn));
    2497            0 :         pg_log_error_detail("Command was: %s", q->data);
    2498            0 :         exit_nicely(1);
    2499              :     }
    2500              : 
    2501              :     /* Check command status and return to normal libpq state */
    2502         4482 :     res = PQgetResult(conn);
    2503         4482 :     if (PQresultStatus(res) != PGRES_COMMAND_OK)
    2504              :     {
    2505            0 :         pg_log_error("Dumping the contents of table \"%s\" failed: PQgetResult() failed.", classname);
    2506            0 :         pg_log_error_detail("Error message from server: %s", PQerrorMessage(conn));
    2507            0 :         pg_log_error_detail("Command was: %s", q->data);
    2508            0 :         exit_nicely(1);
    2509              :     }
    2510         4482 :     PQclear(res);
    2511              : 
    2512              :     /* Do this to ensure we've pumped libpq back to idle state */
    2513         4482 :     if (PQgetResult(conn) != NULL)
    2514            0 :         pg_log_warning("unexpected extra results during COPY of table \"%s\"",
    2515              :                        classname);
    2516              : 
    2517         4482 :     destroyPQExpBuffer(q);
    2518              : 
    2519              :     /* Revert back the setting */
    2520         4482 :     if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
    2521            0 :         set_restrict_relation_kind(fout, "view, foreign-table");
    2522              : 
    2523         4482 :     return 1;
    2524              : }
    2525              : 
    2526              : /*
    2527              :  * Dump table data using INSERT commands.
    2528              :  *
    2529              :  * Caution: when we restore from an archive file direct to database, the
    2530              :  * INSERT commands emitted by this function have to be parsed by
    2531              :  * pg_backup_db.c's ExecuteSimpleCommands(), which will not handle comments,
    2532              :  * E'' strings, or dollar-quoted strings.  So don't emit anything like that.
    2533              :  */
    2534              : static int
    2535           87 : dumpTableData_insert(Archive *fout, const void *dcontext)
    2536              : {
    2537           87 :     const TableDataInfo *tdinfo = dcontext;
    2538           87 :     const TableInfo *tbinfo = tdinfo->tdtable;
    2539           87 :     DumpOptions *dopt = fout->dopt;
    2540           87 :     PQExpBuffer q = createPQExpBuffer();
    2541           87 :     PQExpBuffer insertStmt = NULL;
    2542              :     char       *attgenerated;
    2543              :     PGresult   *res;
    2544              :     int         nfields,
    2545              :                 i;
    2546           87 :     int         rows_per_statement = dopt->dump_inserts;
    2547           87 :     int         rows_this_statement = 0;
    2548              : 
    2549              :     /* Temporary allows to access to foreign tables to dump data */
    2550           87 :     if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
    2551            0 :         set_restrict_relation_kind(fout, "view");
    2552              : 
    2553              :     /*
    2554              :      * If we're going to emit INSERTs with column names, the most efficient
    2555              :      * way to deal with generated columns is to exclude them entirely.  For
    2556              :      * INSERTs without column names, we have to emit DEFAULT rather than the
    2557              :      * actual column value --- but we can save a few cycles by fetching nulls
    2558              :      * rather than the uninteresting-to-us value.
    2559              :      */
    2560           87 :     attgenerated = pg_malloc_array(char, tbinfo->numatts);
    2561           87 :     appendPQExpBufferStr(q, "DECLARE _pg_dump_cursor CURSOR FOR SELECT ");
    2562           87 :     nfields = 0;
    2563          269 :     for (i = 0; i < tbinfo->numatts; i++)
    2564              :     {
    2565          182 :         if (tbinfo->attisdropped[i])
    2566            2 :             continue;
    2567          180 :         if (tbinfo->attgenerated[i] && dopt->column_inserts)
    2568            8 :             continue;
    2569          172 :         if (nfields > 0)
    2570           92 :             appendPQExpBufferStr(q, ", ");
    2571          172 :         if (tbinfo->attgenerated[i])
    2572            8 :             appendPQExpBufferStr(q, "NULL");
    2573              :         else
    2574          164 :             appendPQExpBufferStr(q, fmtId(tbinfo->attnames[i]));
    2575          172 :         attgenerated[nfields] = tbinfo->attgenerated[i];
    2576          172 :         nfields++;
    2577              :     }
    2578              :     /* Servers before 9.4 will complain about zero-column SELECT */
    2579           87 :     if (nfields == 0)
    2580            7 :         appendPQExpBufferStr(q, "NULL");
    2581           87 :     appendPQExpBuffer(q, " FROM ONLY %s",
    2582           87 :                       fmtQualifiedDumpable(tbinfo));
    2583           87 :     if (tdinfo->filtercond)
    2584            0 :         appendPQExpBuffer(q, " %s", tdinfo->filtercond);
    2585              : 
    2586           87 :     ExecuteSqlStatement(fout, q->data);
    2587              : 
    2588              :     while (1)
    2589              :     {
    2590          139 :         res = ExecuteSqlQuery(fout, "FETCH 100 FROM _pg_dump_cursor",
    2591              :                               PGRES_TUPLES_OK);
    2592              : 
    2593              :         /* cross-check field count, allowing for dummy NULL if any */
    2594          139 :         if (nfields != PQnfields(res) &&
    2595           10 :             !(nfields == 0 && PQnfields(res) == 1))
    2596            0 :             pg_fatal("wrong number of fields retrieved from table \"%s\"",
    2597              :                      tbinfo->dobj.name);
    2598              : 
    2599              :         /*
    2600              :          * First time through, we build as much of the INSERT statement as
    2601              :          * possible in "insertStmt", which we can then just print for each
    2602              :          * statement. If the table happens to have zero dumpable columns then
    2603              :          * this will be a complete statement, otherwise it will end in
    2604              :          * "VALUES" and be ready to have the row's column values printed.
    2605              :          */
    2606          139 :         if (insertStmt == NULL)
    2607              :         {
    2608              :             const TableInfo *targettab;
    2609              : 
    2610           87 :             insertStmt = createPQExpBuffer();
    2611              : 
    2612              :             /*
    2613              :              * When load-via-partition-root is set or forced, get the root
    2614              :              * table name for the partition table, so that we can reload data
    2615              :              * through the root table.
    2616              :              */
    2617           87 :             if (tbinfo->ispartition &&
    2618           48 :                 (dopt->load_via_partition_root ||
    2619           24 :                  forcePartitionRootLoad(tbinfo)))
    2620            7 :                 targettab = getRootTableInfo(tbinfo);
    2621              :             else
    2622           80 :                 targettab = tbinfo;
    2623              : 
    2624           87 :             appendPQExpBuffer(insertStmt, "INSERT INTO %s ",
    2625           87 :                               fmtQualifiedDumpable(targettab));
    2626              : 
    2627              :             /* corner case for zero-column table */
    2628           87 :             if (nfields == 0)
    2629              :             {
    2630            7 :                 appendPQExpBufferStr(insertStmt, "DEFAULT VALUES;\n");
    2631              :             }
    2632              :             else
    2633              :             {
    2634              :                 /* append the list of column names if required */
    2635           80 :                 if (dopt->column_inserts)
    2636              :                 {
    2637           36 :                     appendPQExpBufferChar(insertStmt, '(');
    2638          109 :                     for (int field = 0; field < nfields; field++)
    2639              :                     {
    2640           73 :                         if (field > 0)
    2641           37 :                             appendPQExpBufferStr(insertStmt, ", ");
    2642           73 :                         appendPQExpBufferStr(insertStmt,
    2643           73 :                                              fmtId(PQfname(res, field)));
    2644              :                     }
    2645           36 :                     appendPQExpBufferStr(insertStmt, ") ");
    2646              :                 }
    2647              : 
    2648           80 :                 if (tbinfo->needs_override)
    2649            2 :                     appendPQExpBufferStr(insertStmt, "OVERRIDING SYSTEM VALUE ");
    2650              : 
    2651           80 :                 appendPQExpBufferStr(insertStmt, "VALUES");
    2652              :             }
    2653              :         }
    2654              : 
    2655         3608 :         for (int tuple = 0; tuple < PQntuples(res); tuple++)
    2656              :         {
    2657              :             /* Write the INSERT if not in the middle of a multi-row INSERT. */
    2658         3469 :             if (rows_this_statement == 0)
    2659         3463 :                 archputs(insertStmt->data, fout);
    2660              : 
    2661              :             /*
    2662              :              * If it is zero-column table then we've already written the
    2663              :              * complete statement, which will mean we've disobeyed
    2664              :              * --rows-per-insert when it's set greater than 1.  We do support
    2665              :              * a way to make this multi-row with: SELECT UNION ALL SELECT
    2666              :              * UNION ALL ... but that's non-standard so we should avoid it
    2667              :              * given that using INSERTs is mostly only ever needed for
    2668              :              * cross-database exports.
    2669              :              */
    2670         3469 :             if (nfields == 0)
    2671            6 :                 continue;
    2672              : 
    2673              :             /* Emit a row heading */
    2674         3463 :             if (rows_per_statement == 1)
    2675         3454 :                 archputs(" (", fout);
    2676            9 :             else if (rows_this_statement > 0)
    2677            6 :                 archputs(",\n\t(", fout);
    2678              :             else
    2679            3 :                 archputs("\n\t(", fout);
    2680              : 
    2681        10445 :             for (int field = 0; field < nfields; field++)
    2682              :             {
    2683         6982 :                 if (field > 0)
    2684         3519 :                     archputs(", ", fout);
    2685         6982 :                 if (attgenerated[field])
    2686              :                 {
    2687            2 :                     archputs("DEFAULT", fout);
    2688            2 :                     continue;
    2689              :                 }
    2690         6980 :                 if (PQgetisnull(res, tuple, field))
    2691              :                 {
    2692           83 :                     archputs("NULL", fout);
    2693           83 :                     continue;
    2694              :                 }
    2695              : 
    2696              :                 /* XXX This code is partially duplicated in ruleutils.c */
    2697         6897 :                 switch (PQftype(res, field))
    2698              :                 {
    2699         4869 :                     case INT2OID:
    2700              :                     case INT4OID:
    2701              :                     case INT8OID:
    2702              :                     case OIDOID:
    2703              :                     case FLOAT4OID:
    2704              :                     case FLOAT8OID:
    2705              :                     case NUMERICOID:
    2706              :                         {
    2707              :                             /*
    2708              :                              * These types are printed without quotes unless
    2709              :                              * they contain values that aren't accepted by the
    2710              :                              * scanner unquoted (e.g., 'NaN').  Note that
    2711              :                              * strtod() and friends might accept NaN, so we
    2712              :                              * can't use that to test.
    2713              :                              *
    2714              :                              * In reality we only need to defend against
    2715              :                              * infinity and NaN, so we need not get too crazy
    2716              :                              * about pattern matching here.
    2717              :                              */
    2718         4869 :                             const char *s = PQgetvalue(res, tuple, field);
    2719              : 
    2720         4869 :                             if (strspn(s, "0123456789 +-eE.") == strlen(s))
    2721         4867 :                                 archputs(s, fout);
    2722              :                             else
    2723            2 :                                 archprintf(fout, "'%s'", s);
    2724              :                         }
    2725         4869 :                         break;
    2726              : 
    2727            2 :                     case BITOID:
    2728              :                     case VARBITOID:
    2729            2 :                         archprintf(fout, "B'%s'",
    2730              :                                    PQgetvalue(res, tuple, field));
    2731            2 :                         break;
    2732              : 
    2733            4 :                     case BOOLOID:
    2734            4 :                         if (strcmp(PQgetvalue(res, tuple, field), "t") == 0)
    2735            2 :                             archputs("true", fout);
    2736              :                         else
    2737            2 :                             archputs("false", fout);
    2738            4 :                         break;
    2739              : 
    2740         2022 :                     default:
    2741              :                         /* All other types are printed as string literals. */
    2742         2022 :                         resetPQExpBuffer(q);
    2743         2022 :                         appendStringLiteralAH(q,
    2744              :                                               PQgetvalue(res, tuple, field),
    2745              :                                               fout);
    2746         2022 :                         archputs(q->data, fout);
    2747         2022 :                         break;
    2748              :                 }
    2749              :             }
    2750              : 
    2751              :             /* Terminate the row ... */
    2752         3463 :             archputs(")", fout);
    2753              : 
    2754              :             /* ... and the statement, if the target no. of rows is reached */
    2755         3463 :             if (++rows_this_statement >= rows_per_statement)
    2756              :             {
    2757         3456 :                 if (dopt->do_nothing)
    2758            0 :                     archputs(" ON CONFLICT DO NOTHING;\n", fout);
    2759              :                 else
    2760         3456 :                     archputs(";\n", fout);
    2761              :                 /* Reset the row counter */
    2762         3456 :                 rows_this_statement = 0;
    2763              :             }
    2764              :         }
    2765              : 
    2766          139 :         if (PQntuples(res) <= 0)
    2767              :         {
    2768           87 :             PQclear(res);
    2769           87 :             break;
    2770              :         }
    2771           52 :         PQclear(res);
    2772              :     }
    2773              : 
    2774              :     /* Terminate any statements that didn't make the row count. */
    2775           87 :     if (rows_this_statement > 0)
    2776              :     {
    2777            1 :         if (dopt->do_nothing)
    2778            0 :             archputs(" ON CONFLICT DO NOTHING;\n", fout);
    2779              :         else
    2780            1 :             archputs(";\n", fout);
    2781              :     }
    2782              : 
    2783           87 :     archputs("\n\n", fout);
    2784              : 
    2785           87 :     ExecuteSqlStatement(fout, "CLOSE _pg_dump_cursor");
    2786              : 
    2787           87 :     destroyPQExpBuffer(q);
    2788           87 :     if (insertStmt != NULL)
    2789           87 :         destroyPQExpBuffer(insertStmt);
    2790           87 :     free(attgenerated);
    2791              : 
    2792              :     /* Revert back the setting */
    2793           87 :     if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
    2794            0 :         set_restrict_relation_kind(fout, "view, foreign-table");
    2795              : 
    2796           87 :     return 1;
    2797              : }
    2798              : 
    2799              : /*
    2800              :  * getRootTableInfo:
    2801              :  *     get the root TableInfo for the given partition table.
    2802              :  */
    2803              : static TableInfo *
    2804           79 : getRootTableInfo(const TableInfo *tbinfo)
    2805              : {
    2806              :     TableInfo  *parentTbinfo;
    2807              : 
    2808              :     Assert(tbinfo->ispartition);
    2809              :     Assert(tbinfo->numParents == 1);
    2810              : 
    2811           79 :     parentTbinfo = tbinfo->parents[0];
    2812           79 :     while (parentTbinfo->ispartition)
    2813              :     {
    2814              :         Assert(parentTbinfo->numParents == 1);
    2815            0 :         parentTbinfo = parentTbinfo->parents[0];
    2816              :     }
    2817              : 
    2818           79 :     return parentTbinfo;
    2819              : }
    2820              : 
    2821              : /*
    2822              :  * forcePartitionRootLoad
    2823              :  *     Check if we must force load_via_partition_root for this partition.
    2824              :  *
    2825              :  * This is required if any level of ancestral partitioned table has an
    2826              :  * unsafe partitioning scheme.
    2827              :  */
    2828              : static bool
    2829         1084 : forcePartitionRootLoad(const TableInfo *tbinfo)
    2830              : {
    2831              :     TableInfo  *parentTbinfo;
    2832              : 
    2833              :     Assert(tbinfo->ispartition);
    2834              :     Assert(tbinfo->numParents == 1);
    2835              : 
    2836         1084 :     parentTbinfo = tbinfo->parents[0];
    2837         1084 :     if (parentTbinfo->unsafe_partitions)
    2838           79 :         return true;
    2839         1225 :     while (parentTbinfo->ispartition)
    2840              :     {
    2841              :         Assert(parentTbinfo->numParents == 1);
    2842          220 :         parentTbinfo = parentTbinfo->parents[0];
    2843          220 :         if (parentTbinfo->unsafe_partitions)
    2844            0 :             return true;
    2845              :     }
    2846              : 
    2847         1005 :     return false;
    2848              : }
    2849              : 
    2850              : /*
    2851              :  * dumpTableData -
    2852              :  *    dump the contents of a single table
    2853              :  *
    2854              :  * Actually, this just makes an ArchiveEntry for the table contents.
    2855              :  */
    2856              : static void
    2857         4656 : dumpTableData(Archive *fout, const TableDataInfo *tdinfo)
    2858              : {
    2859         4656 :     DumpOptions *dopt = fout->dopt;
    2860         4656 :     const TableInfo *tbinfo = tdinfo->tdtable;
    2861         4656 :     PQExpBuffer copyBuf = createPQExpBuffer();
    2862         4656 :     PQExpBuffer clistBuf = createPQExpBuffer();
    2863              :     DataDumperPtr dumpFn;
    2864         4656 :     char       *tdDefn = NULL;
    2865              :     char       *copyStmt;
    2866              :     const char *copyFrom;
    2867              : 
    2868              :     /* We had better have loaded per-column details about this table */
    2869              :     Assert(tbinfo->interesting);
    2870              : 
    2871              :     /*
    2872              :      * When load-via-partition-root is set or forced, get the root table name
    2873              :      * for the partition table, so that we can reload data through the root
    2874              :      * table.  Then construct a comment to be inserted into the TOC entry's
    2875              :      * defn field, so that such cases can be identified reliably.
    2876              :      */
    2877         4656 :     if (tbinfo->ispartition &&
    2878         2120 :         (dopt->load_via_partition_root ||
    2879         1060 :          forcePartitionRootLoad(tbinfo)))
    2880           72 :     {
    2881              :         const TableInfo *parentTbinfo;
    2882              :         char       *sanitized;
    2883              : 
    2884           72 :         parentTbinfo = getRootTableInfo(tbinfo);
    2885           72 :         copyFrom = fmtQualifiedDumpable(parentTbinfo);
    2886           72 :         sanitized = sanitize_line(copyFrom, true);
    2887           72 :         printfPQExpBuffer(copyBuf, "-- load via partition root %s",
    2888              :                           sanitized);
    2889           72 :         free(sanitized);
    2890           72 :         tdDefn = pg_strdup(copyBuf->data);
    2891              :     }
    2892              :     else
    2893         4584 :         copyFrom = fmtQualifiedDumpable(tbinfo);
    2894              : 
    2895         4656 :     if (dopt->dump_inserts == 0)
    2896              :     {
    2897              :         /* Dump/restore using COPY */
    2898         4569 :         dumpFn = dumpTableData_copy;
    2899              :         /* must use 2 steps here 'cause fmtId is nonreentrant */
    2900         4569 :         printfPQExpBuffer(copyBuf, "COPY %s ",
    2901              :                           copyFrom);
    2902         4569 :         appendPQExpBuffer(copyBuf, "%s FROM stdin;\n",
    2903              :                           fmtCopyColumnList(tbinfo, clistBuf));
    2904         4569 :         copyStmt = copyBuf->data;
    2905              :     }
    2906              :     else
    2907              :     {
    2908              :         /* Restore using INSERT */
    2909           87 :         dumpFn = dumpTableData_insert;
    2910           87 :         copyStmt = NULL;
    2911              :     }
    2912              : 
    2913              :     /*
    2914              :      * Note: although the TableDataInfo is a full DumpableObject, we treat its
    2915              :      * dependency on its table as "special" and pass it to ArchiveEntry now.
    2916              :      * See comments for BuildArchiveDependencies.
    2917              :      */
    2918         4656 :     if (tdinfo->dobj.dump & DUMP_COMPONENT_DATA)
    2919              :     {
    2920              :         TocEntry   *te;
    2921              : 
    2922         4656 :         te = ArchiveEntry(fout, tdinfo->dobj.catId, tdinfo->dobj.dumpId,
    2923         4656 :                           ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
    2924              :                                        .namespace = tbinfo->dobj.namespace->dobj.name,
    2925              :                                        .owner = tbinfo->rolname,
    2926              :                                        .description = "TABLE DATA",
    2927              :                                        .section = SECTION_DATA,
    2928              :                                        .createStmt = tdDefn,
    2929              :                                        .copyStmt = copyStmt,
    2930              :                                        .deps = &(tbinfo->dobj.dumpId),
    2931              :                                        .nDeps = 1,
    2932              :                                        .dumpFn = dumpFn,
    2933              :                                        .dumpArg = tdinfo));
    2934              : 
    2935              :         /*
    2936              :          * Set the TocEntry's dataLength in case we are doing a parallel dump
    2937              :          * and want to order dump jobs by table size.  We choose to measure
    2938              :          * dataLength in table pages (including TOAST pages) during dump, so
    2939              :          * no scaling is needed.
    2940              :          *
    2941              :          * However, relpages is declared as "integer" in pg_class, and hence
    2942              :          * also in TableInfo, but it's really BlockNumber a/k/a unsigned int.
    2943              :          * Cast so that we get the right interpretation of table sizes
    2944              :          * exceeding INT_MAX pages.
    2945              :          */
    2946         4656 :         te->dataLength = (BlockNumber) tbinfo->relpages;
    2947         4656 :         te->dataLength += (BlockNumber) tbinfo->toastpages;
    2948              : 
    2949              :         /*
    2950              :          * If pgoff_t is only 32 bits wide, the above refinement is useless,
    2951              :          * and instead we'd better worry about integer overflow.  Clamp to
    2952              :          * INT_MAX if the correct result exceeds that.
    2953              :          */
    2954              :         if (sizeof(te->dataLength) == 4 &&
    2955              :             (tbinfo->relpages < 0 || tbinfo->toastpages < 0 ||
    2956              :              te->dataLength < 0))
    2957              :             te->dataLength = INT_MAX;
    2958              :     }
    2959              : 
    2960         4656 :     destroyPQExpBuffer(copyBuf);
    2961         4656 :     destroyPQExpBuffer(clistBuf);
    2962         4656 : }
    2963              : 
    2964              : /*
    2965              :  * refreshMatViewData -
    2966              :  *    load or refresh the contents of a single materialized view
    2967              :  *
    2968              :  * Actually, this just makes an ArchiveEntry for the REFRESH MATERIALIZED VIEW
    2969              :  * statement.
    2970              :  */
    2971              : static void
    2972          345 : refreshMatViewData(Archive *fout, const TableDataInfo *tdinfo)
    2973              : {
    2974          345 :     TableInfo  *tbinfo = tdinfo->tdtable;
    2975              :     PQExpBuffer q;
    2976              : 
    2977              :     /* If the materialized view is not flagged as populated, skip this. */
    2978          345 :     if (!tbinfo->relispopulated)
    2979           68 :         return;
    2980              : 
    2981          277 :     q = createPQExpBuffer();
    2982              : 
    2983          277 :     appendPQExpBuffer(q, "REFRESH MATERIALIZED VIEW %s;\n",
    2984          277 :                       fmtQualifiedDumpable(tbinfo));
    2985              : 
    2986          277 :     if (tdinfo->dobj.dump & DUMP_COMPONENT_DATA)
    2987          277 :         ArchiveEntry(fout,
    2988              :                      tdinfo->dobj.catId, /* catalog ID */
    2989          277 :                      tdinfo->dobj.dumpId,    /* dump ID */
    2990          277 :                      ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
    2991              :                                   .namespace = tbinfo->dobj.namespace->dobj.name,
    2992              :                                   .owner = tbinfo->rolname,
    2993              :                                   .description = "MATERIALIZED VIEW DATA",
    2994              :                                   .section = SECTION_POST_DATA,
    2995              :                                   .createStmt = q->data,
    2996              :                                   .deps = tdinfo->dobj.dependencies,
    2997              :                                   .nDeps = tdinfo->dobj.nDeps));
    2998              : 
    2999          277 :     destroyPQExpBuffer(q);
    3000              : }
    3001              : 
    3002              : /*
    3003              :  * getTableData -
    3004              :  *    set up dumpable objects representing the contents of tables
    3005              :  */
    3006              : static void
    3007          251 : getTableData(DumpOptions *dopt, TableInfo *tblinfo, int numTables, char relkind)
    3008              : {
    3009              :     int         i;
    3010              : 
    3011        68904 :     for (i = 0; i < numTables; i++)
    3012              :     {
    3013        68653 :         if (tblinfo[i].dobj.dump & DUMP_COMPONENT_DATA &&
    3014         1009 :             (!relkind || tblinfo[i].relkind == relkind))
    3015         6500 :             makeTableDataInfo(dopt, &(tblinfo[i]));
    3016              :     }
    3017          251 : }
    3018              : 
    3019              : /*
    3020              :  * Make a dumpable object for the data of this specific table
    3021              :  *
    3022              :  * Note: we make a TableDataInfo if and only if we are going to dump the
    3023              :  * table data; the "dump" field in such objects isn't very interesting.
    3024              :  */
    3025              : static void
    3026         6579 : makeTableDataInfo(DumpOptions *dopt, TableInfo *tbinfo)
    3027              : {
    3028              :     TableDataInfo *tdinfo;
    3029              : 
    3030              :     /*
    3031              :      * Nothing to do if we already decided to dump the table.  This will
    3032              :      * happen for "config" tables.
    3033              :      */
    3034         6579 :     if (tbinfo->dataObj != NULL)
    3035            1 :         return;
    3036              : 
    3037              :     /* Skip property graphs (no data to dump) */
    3038         6578 :     if (tbinfo->relkind == RELKIND_PROPGRAPH)
    3039           86 :         return;
    3040              :     /* Skip VIEWs (no data to dump) */
    3041         6492 :     if (tbinfo->relkind == RELKIND_VIEW)
    3042          515 :         return;
    3043              :     /* Skip FOREIGN TABLEs (no data to dump) unless requested explicitly */
    3044         5977 :     if (tbinfo->relkind == RELKIND_FOREIGN_TABLE &&
    3045           38 :         (foreign_servers_include_oids.head == NULL ||
    3046            4 :          !simple_oid_list_member(&foreign_servers_include_oids,
    3047              :                                  tbinfo->foreign_server)))
    3048           37 :         return;
    3049              :     /* Skip partitioned tables (data in partitions) */
    3050         5940 :     if (tbinfo->relkind == RELKIND_PARTITIONED_TABLE)
    3051          511 :         return;
    3052              : 
    3053              :     /* Don't dump data in unlogged tables, if so requested */
    3054         5429 :     if (tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED &&
    3055           41 :         dopt->no_unlogged_table_data)
    3056           18 :         return;
    3057              : 
    3058              :     /* Check that the data is not explicitly excluded */
    3059         5411 :     if (simple_oid_list_member(&tabledata_exclude_oids,
    3060              :                                tbinfo->dobj.catId.oid))
    3061            8 :         return;
    3062              : 
    3063              :     /* OK, let's dump it */
    3064         5403 :     tdinfo = pg_malloc_object(TableDataInfo);
    3065              : 
    3066         5403 :     if (tbinfo->relkind == RELKIND_MATVIEW)
    3067          345 :         tdinfo->dobj.objType = DO_REFRESH_MATVIEW;
    3068         5058 :     else if (tbinfo->relkind == RELKIND_SEQUENCE)
    3069          402 :         tdinfo->dobj.objType = DO_SEQUENCE_SET;
    3070              :     else
    3071         4656 :         tdinfo->dobj.objType = DO_TABLE_DATA;
    3072              : 
    3073              :     /*
    3074              :      * Note: use tableoid 0 so that this object won't be mistaken for
    3075              :      * something that pg_depend entries apply to.
    3076              :      */
    3077         5403 :     tdinfo->dobj.catId.tableoid = 0;
    3078         5403 :     tdinfo->dobj.catId.oid = tbinfo->dobj.catId.oid;
    3079         5403 :     AssignDumpId(&tdinfo->dobj);
    3080         5403 :     tdinfo->dobj.name = tbinfo->dobj.name;
    3081         5403 :     tdinfo->dobj.namespace = tbinfo->dobj.namespace;
    3082         5403 :     tdinfo->tdtable = tbinfo;
    3083         5403 :     tdinfo->filtercond = NULL;   /* might get set later */
    3084         5403 :     addObjectDependency(&tdinfo->dobj, tbinfo->dobj.dumpId);
    3085              : 
    3086              :     /* A TableDataInfo contains data, of course */
    3087         5403 :     tdinfo->dobj.components |= DUMP_COMPONENT_DATA;
    3088              : 
    3089         5403 :     tbinfo->dataObj = tdinfo;
    3090              : 
    3091              :     /*
    3092              :      * Materialized view statistics must be restored after the data, because
    3093              :      * REFRESH MATERIALIZED VIEW replaces the storage and resets the stats.
    3094              :      *
    3095              :      * The dependency is added here because the statistics objects are created
    3096              :      * first.
    3097              :      */
    3098         5403 :     if (tbinfo->relkind == RELKIND_MATVIEW && tbinfo->stats != NULL)
    3099              :     {
    3100          268 :         tbinfo->stats->section = SECTION_POST_DATA;
    3101          268 :         addObjectDependency(&tbinfo->stats->dobj, tdinfo->dobj.dumpId);
    3102              :     }
    3103              : 
    3104              :     /* Make sure that we'll collect per-column info for this table. */
    3105         5403 :     tbinfo->interesting = true;
    3106              : }
    3107              : 
    3108              : /*
    3109              :  * The refresh for a materialized view must be dependent on the refresh for
    3110              :  * any materialized view that this one is dependent on.
    3111              :  *
    3112              :  * This must be called after all the objects are created, but before they are
    3113              :  * sorted.
    3114              :  */
    3115              : static void
    3116          215 : buildMatViewRefreshDependencies(Archive *fout)
    3117              : {
    3118              :     PQExpBuffer query;
    3119              :     PGresult   *res;
    3120              :     int         ntups,
    3121              :                 i;
    3122              :     int         i_classid,
    3123              :                 i_objid,
    3124              :                 i_refobjid;
    3125              : 
    3126              :     /* No Mat Views before 9.3. */
    3127          215 :     if (fout->remoteVersion < 90300)
    3128            0 :         return;
    3129              : 
    3130          215 :     query = createPQExpBuffer();
    3131              : 
    3132          215 :     appendPQExpBufferStr(query, "WITH RECURSIVE w AS "
    3133              :                          "( "
    3134              :                          "SELECT d1.objid, d2.refobjid, c2.relkind AS refrelkind "
    3135              :                          "FROM pg_depend d1 "
    3136              :                          "JOIN pg_class c1 ON c1.oid = d1.objid "
    3137              :                          "AND c1.relkind = " CppAsString2(RELKIND_MATVIEW)
    3138              :                          " JOIN pg_rewrite r1 ON r1.ev_class = d1.objid "
    3139              :                          "JOIN pg_depend d2 ON d2.classid = 'pg_rewrite'::regclass "
    3140              :                          "AND d2.objid = r1.oid "
    3141              :                          "AND d2.refobjid <> d1.objid "
    3142              :                          "JOIN pg_class c2 ON c2.oid = d2.refobjid "
    3143              :                          "AND c2.relkind IN (" CppAsString2(RELKIND_MATVIEW) ","
    3144              :                          CppAsString2(RELKIND_VIEW) ") "
    3145              :                          "WHERE d1.classid = 'pg_class'::regclass "
    3146              :                          "UNION "
    3147              :                          "SELECT w.objid, d3.refobjid, c3.relkind "
    3148              :                          "FROM w "
    3149              :                          "JOIN pg_rewrite r3 ON r3.ev_class = w.refobjid "
    3150              :                          "JOIN pg_depend d3 ON d3.classid = 'pg_rewrite'::regclass "
    3151              :                          "AND d3.objid = r3.oid "
    3152              :                          "AND d3.refobjid <> w.refobjid "
    3153              :                          "JOIN pg_class c3 ON c3.oid = d3.refobjid "
    3154              :                          "AND c3.relkind IN (" CppAsString2(RELKIND_MATVIEW) ","
    3155              :                          CppAsString2(RELKIND_VIEW) ") "
    3156              :                          ") "
    3157              :                          "SELECT 'pg_class'::regclass::oid AS classid, objid, refobjid "
    3158              :                          "FROM w "
    3159              :                          "WHERE refrelkind = " CppAsString2(RELKIND_MATVIEW));
    3160              : 
    3161          215 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    3162              : 
    3163          215 :     ntups = PQntuples(res);
    3164              : 
    3165          215 :     i_classid = PQfnumber(res, "classid");
    3166          215 :     i_objid = PQfnumber(res, "objid");
    3167          215 :     i_refobjid = PQfnumber(res, "refobjid");
    3168              : 
    3169          479 :     for (i = 0; i < ntups; i++)
    3170              :     {
    3171              :         CatalogId   objId;
    3172              :         CatalogId   refobjId;
    3173              :         DumpableObject *dobj;
    3174              :         DumpableObject *refdobj;
    3175              :         TableInfo  *tbinfo;
    3176              :         TableInfo  *reftbinfo;
    3177              : 
    3178          264 :         objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
    3179          264 :         objId.oid = atooid(PQgetvalue(res, i, i_objid));
    3180          264 :         refobjId.tableoid = objId.tableoid;
    3181          264 :         refobjId.oid = atooid(PQgetvalue(res, i, i_refobjid));
    3182              : 
    3183          264 :         dobj = findObjectByCatalogId(objId);
    3184          264 :         if (dobj == NULL)
    3185           48 :             continue;
    3186              : 
    3187              :         Assert(dobj->objType == DO_TABLE);
    3188          264 :         tbinfo = (TableInfo *) dobj;
    3189              :         Assert(tbinfo->relkind == RELKIND_MATVIEW);
    3190          264 :         dobj = (DumpableObject *) tbinfo->dataObj;
    3191          264 :         if (dobj == NULL)
    3192           48 :             continue;
    3193              :         Assert(dobj->objType == DO_REFRESH_MATVIEW);
    3194              : 
    3195          216 :         refdobj = findObjectByCatalogId(refobjId);
    3196          216 :         if (refdobj == NULL)
    3197            0 :             continue;
    3198              : 
    3199              :         Assert(refdobj->objType == DO_TABLE);
    3200          216 :         reftbinfo = (TableInfo *) refdobj;
    3201              :         Assert(reftbinfo->relkind == RELKIND_MATVIEW);
    3202          216 :         refdobj = (DumpableObject *) reftbinfo->dataObj;
    3203          216 :         if (refdobj == NULL)
    3204            0 :             continue;
    3205              :         Assert(refdobj->objType == DO_REFRESH_MATVIEW);
    3206              : 
    3207          216 :         addObjectDependency(dobj, refdobj->dumpId);
    3208              : 
    3209          216 :         if (!reftbinfo->relispopulated)
    3210           34 :             tbinfo->relispopulated = false;
    3211              :     }
    3212              : 
    3213          215 :     PQclear(res);
    3214              : 
    3215          215 :     destroyPQExpBuffer(query);
    3216              : }
    3217              : 
    3218              : /*
    3219              :  * getTableDataFKConstraints -
    3220              :  *    add dump-order dependencies reflecting foreign key constraints
    3221              :  *
    3222              :  * This code is executed only in a data-only dump --- in schema+data dumps
    3223              :  * we handle foreign key issues by not creating the FK constraints until
    3224              :  * after the data is loaded.  In a data-only dump, however, we want to
    3225              :  * order the table data objects in such a way that a table's referenced
    3226              :  * tables are restored first.  (In the presence of circular references or
    3227              :  * self-references this may be impossible; we'll detect and complain about
    3228              :  * that during the dependency sorting step.)
    3229              :  */
    3230              : static void
    3231            7 : getTableDataFKConstraints(void)
    3232              : {
    3233              :     DumpableObject **dobjs;
    3234              :     int         numObjs;
    3235              :     int         i;
    3236              : 
    3237              :     /* Search through all the dumpable objects for FK constraints */
    3238            7 :     getDumpableObjects(&dobjs, &numObjs);
    3239        26803 :     for (i = 0; i < numObjs; i++)
    3240              :     {
    3241        26796 :         if (dobjs[i]->objType == DO_FK_CONSTRAINT)
    3242              :         {
    3243            8 :             ConstraintInfo *cinfo = (ConstraintInfo *) dobjs[i];
    3244              :             TableInfo  *ftable;
    3245              : 
    3246              :             /* Not interesting unless both tables are to be dumped */
    3247            8 :             if (cinfo->contable == NULL ||
    3248            8 :                 cinfo->contable->dataObj == NULL)
    3249            4 :                 continue;
    3250            4 :             ftable = findTableByOid(cinfo->confrelid);
    3251            4 :             if (ftable == NULL ||
    3252            4 :                 ftable->dataObj == NULL)
    3253            0 :                 continue;
    3254              : 
    3255              :             /*
    3256              :              * Okay, make referencing table's TABLE_DATA object depend on the
    3257              :              * referenced table's TABLE_DATA object.
    3258              :              */
    3259            4 :             addObjectDependency(&cinfo->contable->dataObj->dobj,
    3260            4 :                                 ftable->dataObj->dobj.dumpId);
    3261              :         }
    3262              :     }
    3263            7 :     free(dobjs);
    3264            7 : }
    3265              : 
    3266              : 
    3267              : /*
    3268              :  * dumpDatabase:
    3269              :  *  dump the database definition
    3270              :  */
    3271              : static void
    3272          160 : dumpDatabase(Archive *fout)
    3273              : {
    3274          160 :     DumpOptions *dopt = fout->dopt;
    3275          160 :     PQExpBuffer dbQry = createPQExpBuffer();
    3276          160 :     PQExpBuffer delQry = createPQExpBuffer();
    3277          160 :     PQExpBuffer creaQry = createPQExpBuffer();
    3278          160 :     PQExpBuffer labelq = createPQExpBuffer();
    3279          160 :     PGconn     *conn = GetConnection(fout);
    3280              :     PGresult   *res;
    3281              :     int         i_tableoid,
    3282              :                 i_oid,
    3283              :                 i_datname,
    3284              :                 i_datdba,
    3285              :                 i_encoding,
    3286              :                 i_datlocprovider,
    3287              :                 i_collate,
    3288              :                 i_ctype,
    3289              :                 i_datlocale,
    3290              :                 i_daticurules,
    3291              :                 i_frozenxid,
    3292              :                 i_minmxid,
    3293              :                 i_datacl,
    3294              :                 i_acldefault,
    3295              :                 i_datistemplate,
    3296              :                 i_datconnlimit,
    3297              :                 i_datcollversion,
    3298              :                 i_tablespace;
    3299              :     CatalogId   dbCatId;
    3300              :     DumpId      dbDumpId;
    3301              :     DumpableAcl dbdacl;
    3302              :     const char *datname,
    3303              :                *dba,
    3304              :                *encoding,
    3305              :                *datlocprovider,
    3306              :                *collate,
    3307              :                *ctype,
    3308              :                *locale,
    3309              :                *icurules,
    3310              :                *datistemplate,
    3311              :                *datconnlimit,
    3312              :                *tablespace;
    3313              :     uint32      frozenxid,
    3314              :                 minmxid;
    3315              :     char       *qdatname;
    3316              : 
    3317          160 :     pg_log_info("saving database definition");
    3318              : 
    3319              :     /*
    3320              :      * Fetch the database-level properties for this database.
    3321              :      */
    3322          160 :     appendPQExpBufferStr(dbQry, "SELECT tableoid, oid, datname, "
    3323              :                          "datdba, "
    3324              :                          "pg_encoding_to_char(encoding) AS encoding, "
    3325              :                          "datcollate, datctype, datfrozenxid, "
    3326              :                          "datacl, acldefault('d', datdba) AS acldefault, "
    3327              :                          "datistemplate, datconnlimit, ");
    3328          160 :     if (fout->remoteVersion >= 90300)
    3329          160 :         appendPQExpBufferStr(dbQry, "datminmxid, ");
    3330              :     else
    3331            0 :         appendPQExpBufferStr(dbQry, "0 AS datminmxid, ");
    3332          160 :     if (fout->remoteVersion >= 170000)
    3333          160 :         appendPQExpBufferStr(dbQry, "datlocprovider, datlocale, datcollversion, ");
    3334            0 :     else if (fout->remoteVersion >= 150000)
    3335            0 :         appendPQExpBufferStr(dbQry, "datlocprovider, daticulocale AS datlocale, datcollversion, ");
    3336              :     else
    3337            0 :         appendPQExpBufferStr(dbQry, "'c' AS datlocprovider, NULL AS datlocale, NULL AS datcollversion, ");
    3338          160 :     if (fout->remoteVersion >= 160000)
    3339          160 :         appendPQExpBufferStr(dbQry, "daticurules, ");
    3340              :     else
    3341            0 :         appendPQExpBufferStr(dbQry, "NULL AS daticurules, ");
    3342          160 :     appendPQExpBufferStr(dbQry,
    3343              :                          "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace, "
    3344              :                          "shobj_description(oid, 'pg_database') AS description "
    3345              :                          "FROM pg_database "
    3346              :                          "WHERE datname = current_database()");
    3347              : 
    3348          160 :     res = ExecuteSqlQueryForSingleRow(fout, dbQry->data);
    3349              : 
    3350          160 :     i_tableoid = PQfnumber(res, "tableoid");
    3351          160 :     i_oid = PQfnumber(res, "oid");
    3352          160 :     i_datname = PQfnumber(res, "datname");
    3353          160 :     i_datdba = PQfnumber(res, "datdba");
    3354          160 :     i_encoding = PQfnumber(res, "encoding");
    3355          160 :     i_datlocprovider = PQfnumber(res, "datlocprovider");
    3356          160 :     i_collate = PQfnumber(res, "datcollate");
    3357          160 :     i_ctype = PQfnumber(res, "datctype");
    3358          160 :     i_datlocale = PQfnumber(res, "datlocale");
    3359          160 :     i_daticurules = PQfnumber(res, "daticurules");
    3360          160 :     i_frozenxid = PQfnumber(res, "datfrozenxid");
    3361          160 :     i_minmxid = PQfnumber(res, "datminmxid");
    3362          160 :     i_datacl = PQfnumber(res, "datacl");
    3363          160 :     i_acldefault = PQfnumber(res, "acldefault");
    3364          160 :     i_datistemplate = PQfnumber(res, "datistemplate");
    3365          160 :     i_datconnlimit = PQfnumber(res, "datconnlimit");
    3366          160 :     i_datcollversion = PQfnumber(res, "datcollversion");
    3367          160 :     i_tablespace = PQfnumber(res, "tablespace");
    3368              : 
    3369          160 :     dbCatId.tableoid = atooid(PQgetvalue(res, 0, i_tableoid));
    3370          160 :     dbCatId.oid = atooid(PQgetvalue(res, 0, i_oid));
    3371          160 :     datname = PQgetvalue(res, 0, i_datname);
    3372          160 :     dba = getRoleName(PQgetvalue(res, 0, i_datdba));
    3373          160 :     encoding = PQgetvalue(res, 0, i_encoding);
    3374          160 :     datlocprovider = PQgetvalue(res, 0, i_datlocprovider);
    3375          160 :     collate = PQgetvalue(res, 0, i_collate);
    3376          160 :     ctype = PQgetvalue(res, 0, i_ctype);
    3377          160 :     if (!PQgetisnull(res, 0, i_datlocale))
    3378           14 :         locale = PQgetvalue(res, 0, i_datlocale);
    3379              :     else
    3380          146 :         locale = NULL;
    3381          160 :     if (!PQgetisnull(res, 0, i_daticurules))
    3382            0 :         icurules = PQgetvalue(res, 0, i_daticurules);
    3383              :     else
    3384          160 :         icurules = NULL;
    3385          160 :     frozenxid = atooid(PQgetvalue(res, 0, i_frozenxid));
    3386          160 :     minmxid = atooid(PQgetvalue(res, 0, i_minmxid));
    3387          160 :     dbdacl.acl = PQgetvalue(res, 0, i_datacl);
    3388          160 :     dbdacl.acldefault = PQgetvalue(res, 0, i_acldefault);
    3389          160 :     datistemplate = PQgetvalue(res, 0, i_datistemplate);
    3390          160 :     datconnlimit = PQgetvalue(res, 0, i_datconnlimit);
    3391          160 :     tablespace = PQgetvalue(res, 0, i_tablespace);
    3392              : 
    3393          160 :     qdatname = pg_strdup(fmtId(datname));
    3394              : 
    3395              :     /*
    3396              :      * Prepare the CREATE DATABASE command.  We must specify OID (if we want
    3397              :      * to preserve that), as well as the encoding, locale, and tablespace
    3398              :      * since those can't be altered later.  Other DB properties are left to
    3399              :      * the DATABASE PROPERTIES entry, so that they can be applied after
    3400              :      * reconnecting to the target DB.
    3401              :      *
    3402              :      * For binary upgrade, we use the FILE_COPY strategy because testing has
    3403              :      * shown it to be faster.  When the server is in binary upgrade mode, it
    3404              :      * will also skip the checkpoints this strategy ordinarily performs.
    3405              :      */
    3406          160 :     if (dopt->binary_upgrade)
    3407              :     {
    3408           39 :         appendPQExpBuffer(creaQry,
    3409              :                           "CREATE DATABASE %s WITH TEMPLATE = template0 "
    3410              :                           "OID = %u STRATEGY = FILE_COPY",
    3411              :                           qdatname, dbCatId.oid);
    3412              :     }
    3413              :     else
    3414              :     {
    3415          121 :         appendPQExpBuffer(creaQry, "CREATE DATABASE %s WITH TEMPLATE = template0",
    3416              :                           qdatname);
    3417              :     }
    3418          160 :     if (strlen(encoding) > 0)
    3419              :     {
    3420          160 :         appendPQExpBufferStr(creaQry, " ENCODING = ");
    3421          160 :         appendStringLiteralAH(creaQry, encoding, fout);
    3422              :     }
    3423              : 
    3424          160 :     appendPQExpBufferStr(creaQry, " LOCALE_PROVIDER = ");
    3425          160 :     if (datlocprovider[0] == 'b')
    3426           14 :         appendPQExpBufferStr(creaQry, "builtin");
    3427          146 :     else if (datlocprovider[0] == 'c')
    3428          146 :         appendPQExpBufferStr(creaQry, "libc");
    3429            0 :     else if (datlocprovider[0] == 'i')
    3430            0 :         appendPQExpBufferStr(creaQry, "icu");
    3431              :     else
    3432            0 :         pg_fatal("unrecognized locale provider: %s",
    3433              :                  datlocprovider);
    3434              : 
    3435          160 :     if (strlen(collate) > 0 && strcmp(collate, ctype) == 0)
    3436              :     {
    3437          160 :         appendPQExpBufferStr(creaQry, " LOCALE = ");
    3438          160 :         appendStringLiteralAH(creaQry, collate, fout);
    3439              :     }
    3440              :     else
    3441              :     {
    3442            0 :         if (strlen(collate) > 0)
    3443              :         {
    3444            0 :             appendPQExpBufferStr(creaQry, " LC_COLLATE = ");
    3445            0 :             appendStringLiteralAH(creaQry, collate, fout);
    3446              :         }
    3447            0 :         if (strlen(ctype) > 0)
    3448              :         {
    3449            0 :             appendPQExpBufferStr(creaQry, " LC_CTYPE = ");
    3450            0 :             appendStringLiteralAH(creaQry, ctype, fout);
    3451              :         }
    3452              :     }
    3453          160 :     if (locale)
    3454              :     {
    3455           14 :         if (datlocprovider[0] == 'b')
    3456           14 :             appendPQExpBufferStr(creaQry, " BUILTIN_LOCALE = ");
    3457              :         else
    3458            0 :             appendPQExpBufferStr(creaQry, " ICU_LOCALE = ");
    3459              : 
    3460           14 :         appendStringLiteralAH(creaQry, locale, fout);
    3461              :     }
    3462              : 
    3463          160 :     if (icurules)
    3464              :     {
    3465            0 :         appendPQExpBufferStr(creaQry, " ICU_RULES = ");
    3466            0 :         appendStringLiteralAH(creaQry, icurules, fout);
    3467              :     }
    3468              : 
    3469              :     /*
    3470              :      * For binary upgrade, carry over the collation version.  For normal
    3471              :      * dump/restore, omit the version, so that it is computed upon restore.
    3472              :      */
    3473          160 :     if (dopt->binary_upgrade)
    3474              :     {
    3475           39 :         if (!PQgetisnull(res, 0, i_datcollversion))
    3476              :         {
    3477           39 :             appendPQExpBufferStr(creaQry, " COLLATION_VERSION = ");
    3478           39 :             appendStringLiteralAH(creaQry,
    3479              :                                   PQgetvalue(res, 0, i_datcollversion),
    3480              :                                   fout);
    3481              :         }
    3482              :     }
    3483              : 
    3484              :     /*
    3485              :      * Note: looking at dopt->outputNoTablespaces here is completely the wrong
    3486              :      * thing; the decision whether to specify a tablespace should be left till
    3487              :      * pg_restore, so that pg_restore --no-tablespaces applies.  Ideally we'd
    3488              :      * label the DATABASE entry with the tablespace and let the normal
    3489              :      * tablespace selection logic work ... but CREATE DATABASE doesn't pay
    3490              :      * attention to default_tablespace, so that won't work.
    3491              :      */
    3492          160 :     if (strlen(tablespace) > 0 && strcmp(tablespace, "pg_default") != 0 &&
    3493            5 :         !dopt->outputNoTablespaces)
    3494            5 :         appendPQExpBuffer(creaQry, " TABLESPACE = %s",
    3495              :                           fmtId(tablespace));
    3496          160 :     appendPQExpBufferStr(creaQry, ";\n");
    3497              : 
    3498          160 :     appendPQExpBuffer(delQry, "DROP DATABASE %s;\n",
    3499              :                       qdatname);
    3500              : 
    3501          160 :     dbDumpId = createDumpId();
    3502              : 
    3503          160 :     ArchiveEntry(fout,
    3504              :                  dbCatId,       /* catalog ID */
    3505              :                  dbDumpId,      /* dump ID */
    3506          160 :                  ARCHIVE_OPTS(.tag = datname,
    3507              :                               .owner = dba,
    3508              :                               .description = "DATABASE",
    3509              :                               .section = SECTION_PRE_DATA,
    3510              :                               .createStmt = creaQry->data,
    3511              :                               .dropStmt = delQry->data));
    3512              : 
    3513              :     /* Compute correct tag for archive entry */
    3514          160 :     appendPQExpBuffer(labelq, "DATABASE %s", qdatname);
    3515              : 
    3516              :     /* Dump DB comment if any */
    3517              :     {
    3518              :         /*
    3519              :          * 8.2 and up keep comments on shared objects in a shared table, so we
    3520              :          * cannot use the dumpComment() code used for other database objects.
    3521              :          * Be careful that the ArchiveEntry parameters match that function.
    3522              :          */
    3523          160 :         char       *comment = PQgetvalue(res, 0, PQfnumber(res, "description"));
    3524              : 
    3525          160 :         if (comment && *comment && !dopt->no_comments)
    3526              :         {
    3527           62 :             resetPQExpBuffer(dbQry);
    3528              : 
    3529              :             /*
    3530              :              * Generates warning when loaded into a differently-named
    3531              :              * database.
    3532              :              */
    3533           62 :             appendPQExpBuffer(dbQry, "COMMENT ON DATABASE %s IS ", qdatname);
    3534           62 :             appendStringLiteralAH(dbQry, comment, fout);
    3535           62 :             appendPQExpBufferStr(dbQry, ";\n");
    3536              : 
    3537           62 :             ArchiveEntry(fout, nilCatalogId, createDumpId(),
    3538           62 :                          ARCHIVE_OPTS(.tag = labelq->data,
    3539              :                                       .owner = dba,
    3540              :                                       .description = "COMMENT",
    3541              :                                       .section = SECTION_NONE,
    3542              :                                       .createStmt = dbQry->data,
    3543              :                                       .deps = &dbDumpId,
    3544              :                                       .nDeps = 1));
    3545              :         }
    3546              :     }
    3547              : 
    3548              :     /* Dump DB security label, if enabled */
    3549          160 :     if (!dopt->no_security_labels)
    3550              :     {
    3551              :         PGresult   *shres;
    3552              :         PQExpBuffer seclabelQry;
    3553              : 
    3554          160 :         seclabelQry = createPQExpBuffer();
    3555              : 
    3556          160 :         buildShSecLabelQuery("pg_database", dbCatId.oid, seclabelQry);
    3557          160 :         shres = ExecuteSqlQuery(fout, seclabelQry->data, PGRES_TUPLES_OK);
    3558          160 :         resetPQExpBuffer(seclabelQry);
    3559          160 :         emitShSecLabels(conn, shres, seclabelQry, "DATABASE", datname);
    3560          160 :         if (seclabelQry->len > 0)
    3561            0 :             ArchiveEntry(fout, nilCatalogId, createDumpId(),
    3562            0 :                          ARCHIVE_OPTS(.tag = labelq->data,
    3563              :                                       .owner = dba,
    3564              :                                       .description = "SECURITY LABEL",
    3565              :                                       .section = SECTION_NONE,
    3566              :                                       .createStmt = seclabelQry->data,
    3567              :                                       .deps = &dbDumpId,
    3568              :                                       .nDeps = 1));
    3569          160 :         destroyPQExpBuffer(seclabelQry);
    3570          160 :         PQclear(shres);
    3571              :     }
    3572              : 
    3573              :     /*
    3574              :      * Dump ACL if any.  Note that we do not support initial privileges
    3575              :      * (pg_init_privs) on databases.
    3576              :      */
    3577          160 :     dbdacl.privtype = 0;
    3578          160 :     dbdacl.initprivs = NULL;
    3579              : 
    3580          160 :     dumpACL(fout, dbDumpId, InvalidDumpId, "DATABASE",
    3581              :             qdatname, NULL, NULL,
    3582              :             NULL, dba, &dbdacl);
    3583              : 
    3584              :     /*
    3585              :      * Now construct a DATABASE PROPERTIES archive entry to restore any
    3586              :      * non-default database-level properties.  (The reason this must be
    3587              :      * separate is that we cannot put any additional commands into the TOC
    3588              :      * entry that has CREATE DATABASE.  pg_restore would execute such a group
    3589              :      * in an implicit transaction block, and the backend won't allow CREATE
    3590              :      * DATABASE in that context.)
    3591              :      */
    3592          160 :     resetPQExpBuffer(creaQry);
    3593          160 :     resetPQExpBuffer(delQry);
    3594              : 
    3595          160 :     if (strlen(datconnlimit) > 0 && strcmp(datconnlimit, "-1") != 0)
    3596            0 :         appendPQExpBuffer(creaQry, "ALTER DATABASE %s CONNECTION LIMIT = %s;\n",
    3597              :                           qdatname, datconnlimit);
    3598              : 
    3599          160 :     if (strcmp(datistemplate, "t") == 0)
    3600              :     {
    3601           21 :         appendPQExpBuffer(creaQry, "ALTER DATABASE %s IS_TEMPLATE = true;\n",
    3602              :                           qdatname);
    3603              : 
    3604              :         /*
    3605              :          * The backend won't accept DROP DATABASE on a template database.  We
    3606              :          * can deal with that by removing the template marking before the DROP
    3607              :          * gets issued.  We'd prefer to use ALTER DATABASE IF EXISTS here, but
    3608              :          * since no such command is currently supported, fake it with a direct
    3609              :          * UPDATE on pg_database.
    3610              :          */
    3611           21 :         appendPQExpBufferStr(delQry, "UPDATE pg_catalog.pg_database "
    3612              :                              "SET datistemplate = false WHERE datname = ");
    3613           21 :         appendStringLiteralAH(delQry, datname, fout);
    3614           21 :         appendPQExpBufferStr(delQry, ";\n");
    3615              :     }
    3616              : 
    3617              :     /*
    3618              :      * We do not restore pg_database.dathasloginevt because it is set
    3619              :      * automatically on login event trigger creation.
    3620              :      */
    3621              : 
    3622              :     /* Add database-specific SET options */
    3623          160 :     dumpDatabaseConfig(fout, creaQry, datname, dbCatId.oid);
    3624              : 
    3625              :     /*
    3626              :      * We stick this binary-upgrade query into the DATABASE PROPERTIES archive
    3627              :      * entry, too, for lack of a better place.
    3628              :      */
    3629          160 :     if (dopt->binary_upgrade)
    3630              :     {
    3631           39 :         appendPQExpBufferStr(creaQry, "\n-- For binary upgrade, set datfrozenxid and datminmxid.\n");
    3632           39 :         appendPQExpBuffer(creaQry, "UPDATE pg_catalog.pg_database\n"
    3633              :                           "SET datfrozenxid = '%u', datminmxid = '%u'\n"
    3634              :                           "WHERE datname = ",
    3635              :                           frozenxid, minmxid);
    3636           39 :         appendStringLiteralAH(creaQry, datname, fout);
    3637           39 :         appendPQExpBufferStr(creaQry, ";\n");
    3638              :     }
    3639              : 
    3640          160 :     if (creaQry->len > 0)
    3641           52 :         ArchiveEntry(fout, nilCatalogId, createDumpId(),
    3642           52 :                      ARCHIVE_OPTS(.tag = datname,
    3643              :                                   .owner = dba,
    3644              :                                   .description = "DATABASE PROPERTIES",
    3645              :                                   .section = SECTION_PRE_DATA,
    3646              :                                   .createStmt = creaQry->data,
    3647              :                                   .dropStmt = delQry->data,
    3648              :                                   .deps = &dbDumpId));
    3649              : 
    3650              :     /*
    3651              :      * pg_largeobject comes from the old system intact, so set its
    3652              :      * relfrozenxids, relminmxids and relfilenode.
    3653              :      *
    3654              :      * pg_largeobject_metadata also comes from the old system intact for
    3655              :      * upgrades from v16 and newer, so set its relfrozenxids, relminmxids, and
    3656              :      * relfilenode, too.  pg_upgrade can't copy/link the files from older
    3657              :      * versions because aclitem (needed by pg_largeobject_metadata.lomacl)
    3658              :      * changed its storage format in v16.
    3659              :      */
    3660          160 :     if (dopt->binary_upgrade)
    3661              :     {
    3662              :         PGresult   *lo_res;
    3663           39 :         PQExpBuffer loFrozenQry = createPQExpBuffer();
    3664           39 :         PQExpBuffer loOutQry = createPQExpBuffer();
    3665           39 :         PQExpBuffer lomOutQry = createPQExpBuffer();
    3666           39 :         PQExpBuffer loHorizonQry = createPQExpBuffer();
    3667           39 :         PQExpBuffer lomHorizonQry = createPQExpBuffer();
    3668              :         int         ii_relfrozenxid,
    3669              :                     ii_relfilenode,
    3670              :                     ii_oid,
    3671              :                     ii_relminmxid;
    3672              : 
    3673           39 :         if (fout->remoteVersion >= 90300)
    3674           39 :             appendPQExpBuffer(loFrozenQry, "SELECT relfrozenxid, relminmxid, relfilenode, oid\n"
    3675              :                               "FROM pg_catalog.pg_class\n"
    3676              :                               "WHERE oid IN (%u, %u, %u, %u);\n",
    3677              :                               LargeObjectRelationId, LargeObjectLOidPNIndexId,
    3678              :                               LargeObjectMetadataRelationId, LargeObjectMetadataOidIndexId);
    3679              :         else
    3680            0 :             appendPQExpBuffer(loFrozenQry, "SELECT relfrozenxid, 0 AS relminmxid, relfilenode, oid\n"
    3681              :                               "FROM pg_catalog.pg_class\n"
    3682              :                               "WHERE oid IN (%u, %u);\n",
    3683              :                               LargeObjectRelationId, LargeObjectLOidPNIndexId);
    3684              : 
    3685           39 :         lo_res = ExecuteSqlQuery(fout, loFrozenQry->data, PGRES_TUPLES_OK);
    3686              : 
    3687           39 :         ii_relfrozenxid = PQfnumber(lo_res, "relfrozenxid");
    3688           39 :         ii_relminmxid = PQfnumber(lo_res, "relminmxid");
    3689           39 :         ii_relfilenode = PQfnumber(lo_res, "relfilenode");
    3690           39 :         ii_oid = PQfnumber(lo_res, "oid");
    3691              : 
    3692           39 :         appendPQExpBufferStr(loHorizonQry, "\n-- For binary upgrade, set pg_largeobject relfrozenxid and relminmxid\n");
    3693           39 :         appendPQExpBufferStr(lomHorizonQry, "\n-- For binary upgrade, set pg_largeobject_metadata relfrozenxid and relminmxid\n");
    3694           39 :         appendPQExpBufferStr(loOutQry, "\n-- For binary upgrade, preserve pg_largeobject and index relfilenodes\n");
    3695           39 :         appendPQExpBufferStr(lomOutQry, "\n-- For binary upgrade, preserve pg_largeobject_metadata and index relfilenodes\n");
    3696          195 :         for (int i = 0; i < PQntuples(lo_res); ++i)
    3697              :         {
    3698              :             Oid         oid;
    3699              :             RelFileNumber relfilenumber;
    3700              :             PQExpBuffer horizonQry;
    3701              :             PQExpBuffer outQry;
    3702              : 
    3703          156 :             oid = atooid(PQgetvalue(lo_res, i, ii_oid));
    3704          156 :             relfilenumber = atooid(PQgetvalue(lo_res, i, ii_relfilenode));
    3705              : 
    3706          156 :             if (oid == LargeObjectRelationId ||
    3707              :                 oid == LargeObjectLOidPNIndexId)
    3708              :             {
    3709           78 :                 horizonQry = loHorizonQry;
    3710           78 :                 outQry = loOutQry;
    3711              :             }
    3712              :             else
    3713              :             {
    3714           78 :                 horizonQry = lomHorizonQry;
    3715           78 :                 outQry = lomOutQry;
    3716              :             }
    3717              : 
    3718          156 :             appendPQExpBuffer(horizonQry, "UPDATE pg_catalog.pg_class\n"
    3719              :                               "SET relfrozenxid = '%u', relminmxid = '%u'\n"
    3720              :                               "WHERE oid = %u;\n",
    3721          156 :                               atooid(PQgetvalue(lo_res, i, ii_relfrozenxid)),
    3722          156 :                               atooid(PQgetvalue(lo_res, i, ii_relminmxid)),
    3723          156 :                               atooid(PQgetvalue(lo_res, i, ii_oid)));
    3724              : 
    3725          156 :             if (oid == LargeObjectRelationId ||
    3726              :                 oid == LargeObjectMetadataRelationId)
    3727           78 :                 appendPQExpBuffer(outQry,
    3728              :                                   "SELECT pg_catalog.binary_upgrade_set_next_heap_relfilenode('%u'::pg_catalog.oid);\n",
    3729              :                                   relfilenumber);
    3730           78 :             else if (oid == LargeObjectLOidPNIndexId ||
    3731              :                      oid == LargeObjectMetadataOidIndexId)
    3732           78 :                 appendPQExpBuffer(outQry,
    3733              :                                   "SELECT pg_catalog.binary_upgrade_set_next_index_relfilenode('%u'::pg_catalog.oid);\n",
    3734              :                                   relfilenumber);
    3735              :         }
    3736              : 
    3737           39 :         appendPQExpBufferStr(loOutQry,
    3738              :                              "TRUNCATE pg_catalog.pg_largeobject;\n");
    3739           39 :         appendPQExpBufferStr(lomOutQry,
    3740              :                              "TRUNCATE pg_catalog.pg_largeobject_metadata;\n");
    3741              : 
    3742           39 :         appendPQExpBufferStr(loOutQry, loHorizonQry->data);
    3743           39 :         appendPQExpBufferStr(lomOutQry, lomHorizonQry->data);
    3744              : 
    3745           39 :         ArchiveEntry(fout, nilCatalogId, createDumpId(),
    3746           39 :                      ARCHIVE_OPTS(.tag = "pg_largeobject",
    3747              :                                   .description = "pg_largeobject",
    3748              :                                   .section = SECTION_PRE_DATA,
    3749              :                                   .createStmt = loOutQry->data));
    3750              : 
    3751           39 :         if (fout->remoteVersion >= 160000)
    3752           39 :             ArchiveEntry(fout, nilCatalogId, createDumpId(),
    3753           39 :                          ARCHIVE_OPTS(.tag = "pg_largeobject_metadata",
    3754              :                                       .description = "pg_largeobject_metadata",
    3755              :                                       .section = SECTION_PRE_DATA,
    3756              :                                       .createStmt = lomOutQry->data));
    3757              : 
    3758           39 :         PQclear(lo_res);
    3759              : 
    3760           39 :         destroyPQExpBuffer(loFrozenQry);
    3761           39 :         destroyPQExpBuffer(loHorizonQry);
    3762           39 :         destroyPQExpBuffer(lomHorizonQry);
    3763           39 :         destroyPQExpBuffer(loOutQry);
    3764           39 :         destroyPQExpBuffer(lomOutQry);
    3765              :     }
    3766              : 
    3767          160 :     PQclear(res);
    3768              : 
    3769          160 :     free(qdatname);
    3770          160 :     destroyPQExpBuffer(dbQry);
    3771          160 :     destroyPQExpBuffer(delQry);
    3772          160 :     destroyPQExpBuffer(creaQry);
    3773          160 :     destroyPQExpBuffer(labelq);
    3774          160 : }
    3775              : 
    3776              : /*
    3777              :  * Collect any database-specific or role-and-database-specific SET options
    3778              :  * for this database, and append them to outbuf.
    3779              :  */
    3780              : static void
    3781          160 : dumpDatabaseConfig(Archive *AH, PQExpBuffer outbuf,
    3782              :                    const char *dbname, Oid dboid)
    3783              : {
    3784          160 :     PGconn     *conn = GetConnection(AH);
    3785          160 :     PQExpBuffer buf = createPQExpBuffer();
    3786              :     PGresult   *res;
    3787              : 
    3788              :     /* First collect database-specific options */
    3789          160 :     printfPQExpBuffer(buf, "SELECT unnest(setconfig) FROM pg_db_role_setting "
    3790              :                       "WHERE setrole = 0 AND setdatabase = '%u'::oid",
    3791              :                       dboid);
    3792              : 
    3793          160 :     res = ExecuteSqlQuery(AH, buf->data, PGRES_TUPLES_OK);
    3794              : 
    3795          190 :     for (int i = 0; i < PQntuples(res); i++)
    3796           30 :         makeAlterConfigCommand(conn, PQgetvalue(res, i, 0),
    3797              :                                "DATABASE", dbname, NULL, NULL,
    3798              :                                outbuf);
    3799              : 
    3800          160 :     PQclear(res);
    3801              : 
    3802              :     /* Now look for role-and-database-specific options */
    3803          160 :     printfPQExpBuffer(buf, "SELECT rolname, unnest(setconfig) "
    3804              :                       "FROM pg_db_role_setting s, pg_roles r "
    3805              :                       "WHERE setrole = r.oid AND setdatabase = '%u'::oid",
    3806              :                       dboid);
    3807              : 
    3808          160 :     res = ExecuteSqlQuery(AH, buf->data, PGRES_TUPLES_OK);
    3809              : 
    3810          160 :     for (int i = 0; i < PQntuples(res); i++)
    3811            0 :         makeAlterConfigCommand(conn, PQgetvalue(res, i, 1),
    3812            0 :                                "ROLE", PQgetvalue(res, i, 0),
    3813              :                                "DATABASE", dbname,
    3814              :                                outbuf);
    3815              : 
    3816          160 :     PQclear(res);
    3817              : 
    3818          160 :     destroyPQExpBuffer(buf);
    3819          160 : }
    3820              : 
    3821              : /*
    3822              :  * dumpEncoding: put the correct encoding into the archive
    3823              :  */
    3824              : static void
    3825          259 : dumpEncoding(Archive *AH)
    3826              : {
    3827          259 :     const char *encname = pg_encoding_to_char(AH->encoding);
    3828          259 :     PQExpBuffer qry = createPQExpBuffer();
    3829              : 
    3830          259 :     pg_log_info("saving encoding = %s", encname);
    3831              : 
    3832          259 :     appendPQExpBufferStr(qry, "SET client_encoding = ");
    3833          259 :     appendStringLiteralAH(qry, encname, AH);
    3834          259 :     appendPQExpBufferStr(qry, ";\n");
    3835              : 
    3836          259 :     ArchiveEntry(AH, nilCatalogId, createDumpId(),
    3837          259 :                  ARCHIVE_OPTS(.tag = "ENCODING",
    3838              :                               .description = "ENCODING",
    3839              :                               .section = SECTION_PRE_DATA,
    3840              :                               .createStmt = qry->data));
    3841              : 
    3842          259 :     destroyPQExpBuffer(qry);
    3843          259 : }
    3844              : 
    3845              : 
    3846              : /*
    3847              :  * dumpStdStrings: put the correct escape string behavior into the archive
    3848              :  */
    3849              : static void
    3850          259 : dumpStdStrings(Archive *AH)
    3851              : {
    3852          259 :     const char *stdstrings = AH->std_strings ? "on" : "off";
    3853          259 :     PQExpBuffer qry = createPQExpBuffer();
    3854              : 
    3855          259 :     pg_log_info("saving \"standard_conforming_strings = %s\"",
    3856              :                 stdstrings);
    3857              : 
    3858          259 :     appendPQExpBuffer(qry, "SET standard_conforming_strings = '%s';\n",
    3859              :                       stdstrings);
    3860              : 
    3861          259 :     ArchiveEntry(AH, nilCatalogId, createDumpId(),
    3862          259 :                  ARCHIVE_OPTS(.tag = "STDSTRINGS",
    3863              :                               .description = "STDSTRINGS",
    3864              :                               .section = SECTION_PRE_DATA,
    3865              :                               .createStmt = qry->data));
    3866              : 
    3867          259 :     destroyPQExpBuffer(qry);
    3868          259 : }
    3869              : 
    3870              : /*
    3871              :  * dumpSearchPath: record the active search_path in the archive
    3872              :  */
    3873              : static void
    3874          259 : dumpSearchPath(Archive *AH)
    3875              : {
    3876          259 :     PQExpBuffer qry = createPQExpBuffer();
    3877          259 :     PQExpBuffer path = createPQExpBuffer();
    3878              :     PGresult   *res;
    3879          259 :     char      **schemanames = NULL;
    3880          259 :     int         nschemanames = 0;
    3881              :     int         i;
    3882              : 
    3883              :     /*
    3884              :      * We use the result of current_schemas(), not the search_path GUC,
    3885              :      * because that might contain wildcards such as "$user", which won't
    3886              :      * necessarily have the same value during restore.  Also, this way avoids
    3887              :      * listing schemas that may appear in search_path but not actually exist,
    3888              :      * which seems like a prudent exclusion.
    3889              :      */
    3890          259 :     res = ExecuteSqlQueryForSingleRow(AH,
    3891              :                                       "SELECT pg_catalog.current_schemas(false)");
    3892              : 
    3893          259 :     if (!parsePGArray(PQgetvalue(res, 0, 0), &schemanames, &nschemanames))
    3894            0 :         pg_fatal("could not parse result of current_schemas()");
    3895              : 
    3896              :     /*
    3897              :      * We use set_config(), not a simple "SET search_path" command, because
    3898              :      * the latter has less-clean behavior if the search path is empty.  While
    3899              :      * that's likely to get fixed at some point, it seems like a good idea to
    3900              :      * be as backwards-compatible as possible in what we put into archives.
    3901              :      */
    3902          259 :     for (i = 0; i < nschemanames; i++)
    3903              :     {
    3904            0 :         if (i > 0)
    3905            0 :             appendPQExpBufferStr(path, ", ");
    3906            0 :         appendPQExpBufferStr(path, fmtId(schemanames[i]));
    3907              :     }
    3908              : 
    3909          259 :     appendPQExpBufferStr(qry, "SELECT pg_catalog.set_config('search_path', ");
    3910          259 :     appendStringLiteralAH(qry, path->data, AH);
    3911          259 :     appendPQExpBufferStr(qry, ", false);\n");
    3912              : 
    3913          259 :     pg_log_info("saving \"search_path = %s\"", path->data);
    3914              : 
    3915          259 :     ArchiveEntry(AH, nilCatalogId, createDumpId(),
    3916          259 :                  ARCHIVE_OPTS(.tag = "SEARCHPATH",
    3917              :                               .description = "SEARCHPATH",
    3918              :                               .section = SECTION_PRE_DATA,
    3919              :                               .createStmt = qry->data));
    3920              : 
    3921              :     /* Also save it in AH->searchpath, in case we're doing plain text dump */
    3922          259 :     AH->searchpath = pg_strdup(qry->data);
    3923              : 
    3924          259 :     free(schemanames);
    3925          259 :     PQclear(res);
    3926          259 :     destroyPQExpBuffer(qry);
    3927          259 :     destroyPQExpBuffer(path);
    3928          259 : }
    3929              : 
    3930              : 
    3931              : /*
    3932              :  * getLOs:
    3933              :  *  Collect schema-level data about large objects
    3934              :  */
    3935              : static void
    3936          231 : getLOs(Archive *fout)
    3937              : {
    3938          231 :     DumpOptions *dopt = fout->dopt;
    3939          231 :     PQExpBuffer loQry = createPQExpBuffer();
    3940              :     PGresult   *res;
    3941              :     int         ntups;
    3942              :     int         i;
    3943              :     int         n;
    3944              :     int         i_oid;
    3945              :     int         i_lomowner;
    3946              :     int         i_lomacl;
    3947              :     int         i_acldefault;
    3948              : 
    3949          231 :     pg_log_info("reading large objects");
    3950              : 
    3951              :     /*
    3952              :      * Fetch LO OIDs and owner/ACL data.  Order the data so that all the blobs
    3953              :      * with the same owner/ACL appear together.
    3954              :      */
    3955          231 :     appendPQExpBufferStr(loQry,
    3956              :                          "SELECT oid, lomowner, lomacl, "
    3957              :                          "acldefault('L', lomowner) AS acldefault "
    3958              :                          "FROM pg_largeobject_metadata ");
    3959              : 
    3960              :     /*
    3961              :      * For binary upgrades, we transfer pg_largeobject_metadata via COPY or by
    3962              :      * copying/linking its files from the old cluster.  On such upgrades, we
    3963              :      * only need to consider large objects that have comments or security
    3964              :      * labels, since we still restore those objects via COMMENT/SECURITY LABEL
    3965              :      * commands.
    3966              :      */
    3967          231 :     if (dopt->binary_upgrade)
    3968           40 :         appendPQExpBufferStr(loQry,
    3969              :                              "WHERE oid IN "
    3970              :                              "(SELECT objoid FROM pg_description "
    3971              :                              "WHERE classoid = " CppAsString2(LargeObjectRelationId) " "
    3972              :                              "UNION SELECT objoid FROM pg_seclabel "
    3973              :                              "WHERE classoid = " CppAsString2(LargeObjectRelationId) ") ");
    3974              : 
    3975          231 :     appendPQExpBufferStr(loQry,
    3976              :                          "ORDER BY lomowner, lomacl::pg_catalog.text, oid");
    3977              : 
    3978          231 :     res = ExecuteSqlQuery(fout, loQry->data, PGRES_TUPLES_OK);
    3979              : 
    3980          231 :     i_oid = PQfnumber(res, "oid");
    3981          231 :     i_lomowner = PQfnumber(res, "lomowner");
    3982          231 :     i_lomacl = PQfnumber(res, "lomacl");
    3983          231 :     i_acldefault = PQfnumber(res, "acldefault");
    3984              : 
    3985          231 :     ntups = PQntuples(res);
    3986              : 
    3987              :     /*
    3988              :      * Group the blobs into suitably-sized groups that have the same owner and
    3989              :      * ACL setting, and build a metadata and a data DumpableObject for each
    3990              :      * group.  (If we supported initprivs for blobs, we'd have to insist that
    3991              :      * groups also share initprivs settings, since the DumpableObject only has
    3992              :      * room for one.)  i is the index of the first tuple in the current group,
    3993              :      * and n is the number of tuples we include in the group.
    3994              :      */
    3995          315 :     for (i = 0; i < ntups; i += n)
    3996              :     {
    3997           84 :         Oid         thisoid = atooid(PQgetvalue(res, i, i_oid));
    3998           84 :         char       *thisowner = PQgetvalue(res, i, i_lomowner);
    3999           84 :         char       *thisacl = PQgetvalue(res, i, i_lomacl);
    4000              :         LoInfo     *loinfo;
    4001              :         DumpableObject *lodata;
    4002              :         char        namebuf[64];
    4003              : 
    4004              :         /* Scan to find first tuple not to be included in group */
    4005           84 :         n = 1;
    4006           98 :         while (n < MAX_BLOBS_PER_ARCHIVE_ENTRY && i + n < ntups)
    4007              :         {
    4008           47 :             if (strcmp(thisowner, PQgetvalue(res, i + n, i_lomowner)) != 0 ||
    4009           47 :                 strcmp(thisacl, PQgetvalue(res, i + n, i_lomacl)) != 0)
    4010              :                 break;
    4011           14 :             n++;
    4012              :         }
    4013              : 
    4014              :         /* Build the metadata DumpableObject */
    4015           84 :         loinfo = (LoInfo *) pg_malloc(offsetof(LoInfo, looids) + n * sizeof(Oid));
    4016              : 
    4017           84 :         loinfo->dobj.objType = DO_LARGE_OBJECT;
    4018           84 :         loinfo->dobj.catId.tableoid = LargeObjectRelationId;
    4019           84 :         loinfo->dobj.catId.oid = thisoid;
    4020           84 :         AssignDumpId(&loinfo->dobj);
    4021              : 
    4022           84 :         if (n > 1)
    4023           10 :             snprintf(namebuf, sizeof(namebuf), "%u..%u", thisoid,
    4024           10 :                      atooid(PQgetvalue(res, i + n - 1, i_oid)));
    4025              :         else
    4026           74 :             snprintf(namebuf, sizeof(namebuf), "%u", thisoid);
    4027           84 :         loinfo->dobj.name = pg_strdup(namebuf);
    4028           84 :         loinfo->dacl.acl = pg_strdup(thisacl);
    4029           84 :         loinfo->dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
    4030           84 :         loinfo->dacl.privtype = 0;
    4031           84 :         loinfo->dacl.initprivs = NULL;
    4032           84 :         loinfo->rolname = getRoleName(thisowner);
    4033           84 :         loinfo->numlos = n;
    4034           84 :         loinfo->looids[0] = thisoid;
    4035              :         /* Collect OIDs of the remaining blobs in this group */
    4036           98 :         for (int k = 1; k < n; k++)
    4037              :         {
    4038              :             CatalogId   extraID;
    4039              : 
    4040           14 :             loinfo->looids[k] = atooid(PQgetvalue(res, i + k, i_oid));
    4041              : 
    4042              :             /* Make sure we can look up loinfo by any of the blobs' OIDs */
    4043           14 :             extraID.tableoid = LargeObjectRelationId;
    4044           14 :             extraID.oid = loinfo->looids[k];
    4045           14 :             recordAdditionalCatalogID(extraID, &loinfo->dobj);
    4046              :         }
    4047              : 
    4048              :         /* LOs have data */
    4049           84 :         loinfo->dobj.components |= DUMP_COMPONENT_DATA;
    4050              : 
    4051              :         /* Mark whether LO group has a non-empty ACL */
    4052           84 :         if (!PQgetisnull(res, i, i_lomacl))
    4053           34 :             loinfo->dobj.components |= DUMP_COMPONENT_ACL;
    4054              : 
    4055              :         /*
    4056              :          * In binary upgrade mode, pg_largeobject and pg_largeobject_metadata
    4057              :          * are transferred via COPY or by copying/linking the files from the
    4058              :          * old cluster.  Thus, we do not need to dump LO data, definitions, or
    4059              :          * ACLs.
    4060              :          */
    4061           84 :         if (dopt->binary_upgrade)
    4062            7 :             loinfo->dobj.dump &= ~(DUMP_COMPONENT_DATA | DUMP_COMPONENT_ACL | DUMP_COMPONENT_DEFINITION);
    4063              : 
    4064              :         /*
    4065              :          * Create a "BLOBS" data item for the group, too. This is just a
    4066              :          * placeholder for sorting; it carries no data now.
    4067              :          */
    4068           84 :         lodata = pg_malloc_object(DumpableObject);
    4069           84 :         lodata->objType = DO_LARGE_OBJECT_DATA;
    4070           84 :         lodata->catId = nilCatalogId;
    4071           84 :         AssignDumpId(lodata);
    4072           84 :         lodata->name = pg_strdup(namebuf);
    4073           84 :         lodata->components |= DUMP_COMPONENT_DATA;
    4074              :         /* Set up explicit dependency from data to metadata */
    4075           84 :         lodata->dependencies = pg_malloc_object(DumpId);
    4076           84 :         lodata->dependencies[0] = loinfo->dobj.dumpId;
    4077           84 :         lodata->nDeps = lodata->allocDeps = 1;
    4078              :     }
    4079              : 
    4080          231 :     PQclear(res);
    4081          231 :     destroyPQExpBuffer(loQry);
    4082          231 : }
    4083              : 
    4084              : /*
    4085              :  * dumpLO
    4086              :  *
    4087              :  * dump the definition (metadata) of the given large object group
    4088              :  */
    4089              : static void
    4090           84 : dumpLO(Archive *fout, const LoInfo *loinfo)
    4091              : {
    4092           84 :     PQExpBuffer cquery = createPQExpBuffer();
    4093              : 
    4094              :     /*
    4095              :      * The "definition" is just a newline-separated list of OIDs.  We need to
    4096              :      * put something into the dropStmt too, but it can just be a comment.
    4097              :      */
    4098          182 :     for (int i = 0; i < loinfo->numlos; i++)
    4099           98 :         appendPQExpBuffer(cquery, "%u\n", loinfo->looids[i]);
    4100              : 
    4101           84 :     if (loinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
    4102           77 :         ArchiveEntry(fout, loinfo->dobj.catId, loinfo->dobj.dumpId,
    4103           77 :                      ARCHIVE_OPTS(.tag = loinfo->dobj.name,
    4104              :                                   .owner = loinfo->rolname,
    4105              :                                   .description = "BLOB METADATA",
    4106              :                                   .section = SECTION_DATA,
    4107              :                                   .createStmt = cquery->data,
    4108              :                                   .dropStmt = "-- dummy"));
    4109              : 
    4110              :     /*
    4111              :      * Dump per-blob comments and seclabels if any.  We assume these are rare
    4112              :      * enough that it's okay to generate retail TOC entries for them.
    4113              :      */
    4114           84 :     if (loinfo->dobj.dump & (DUMP_COMPONENT_COMMENT |
    4115              :                              DUMP_COMPONENT_SECLABEL))
    4116              :     {
    4117          102 :         for (int i = 0; i < loinfo->numlos; i++)
    4118              :         {
    4119              :             CatalogId   catId;
    4120              :             char        namebuf[32];
    4121              : 
    4122              :             /* Build identifying info for this blob */
    4123           58 :             catId.tableoid = loinfo->dobj.catId.tableoid;
    4124           58 :             catId.oid = loinfo->looids[i];
    4125           58 :             snprintf(namebuf, sizeof(namebuf), "%u", loinfo->looids[i]);
    4126              : 
    4127           58 :             if (loinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
    4128           58 :                 dumpComment(fout, "LARGE OBJECT", namebuf,
    4129           58 :                             NULL, loinfo->rolname,
    4130           58 :                             catId, 0, loinfo->dobj.dumpId);
    4131              : 
    4132           58 :             if (loinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
    4133           10 :                 dumpSecLabel(fout, "LARGE OBJECT", namebuf,
    4134           10 :                              NULL, loinfo->rolname,
    4135           10 :                              catId, 0, loinfo->dobj.dumpId);
    4136              :         }
    4137              :     }
    4138              : 
    4139              :     /*
    4140              :      * Dump the ACLs if any (remember that all blobs in the group will have
    4141              :      * the same ACL).  If there's just one blob, dump a simple ACL entry; if
    4142              :      * there's more, make a "LARGE OBJECTS" entry that really contains only
    4143              :      * the ACL for the first blob.  _printTocEntry() will be cued by the tag
    4144              :      * string to emit a mutated version for each blob.
    4145              :      */
    4146           84 :     if (loinfo->dobj.dump & DUMP_COMPONENT_ACL)
    4147              :     {
    4148              :         char        namebuf[32];
    4149              : 
    4150              :         /* Build identifying info for the first blob */
    4151           33 :         snprintf(namebuf, sizeof(namebuf), "%u", loinfo->looids[0]);
    4152              : 
    4153           33 :         if (loinfo->numlos > 1)
    4154              :         {
    4155              :             char        tagbuf[64];
    4156              : 
    4157            0 :             snprintf(tagbuf, sizeof(tagbuf), "LARGE OBJECTS %u..%u",
    4158            0 :                      loinfo->looids[0], loinfo->looids[loinfo->numlos - 1]);
    4159              : 
    4160            0 :             dumpACL(fout, loinfo->dobj.dumpId, InvalidDumpId,
    4161              :                     "LARGE OBJECT", namebuf, NULL, NULL,
    4162            0 :                     tagbuf, loinfo->rolname, &loinfo->dacl);
    4163              :         }
    4164              :         else
    4165              :         {
    4166           33 :             dumpACL(fout, loinfo->dobj.dumpId, InvalidDumpId,
    4167              :                     "LARGE OBJECT", namebuf, NULL, NULL,
    4168           33 :                     NULL, loinfo->rolname, &loinfo->dacl);
    4169              :         }
    4170              :     }
    4171              : 
    4172           84 :     destroyPQExpBuffer(cquery);
    4173           84 : }
    4174              : 
    4175              : /*
    4176              :  * dumpLOs:
    4177              :  *  dump the data contents of the large objects in the given group
    4178              :  */
    4179              : static int
    4180           73 : dumpLOs(Archive *fout, const void *arg)
    4181              : {
    4182           73 :     const LoInfo *loinfo = (const LoInfo *) arg;
    4183           73 :     PGconn     *conn = GetConnection(fout);
    4184              :     char        buf[LOBBUFSIZE];
    4185              : 
    4186           73 :     pg_log_info("saving large objects \"%s\"", loinfo->dobj.name);
    4187              : 
    4188          154 :     for (int i = 0; i < loinfo->numlos; i++)
    4189              :     {
    4190           81 :         Oid         loOid = loinfo->looids[i];
    4191              :         int         loFd;
    4192              :         int         cnt;
    4193              : 
    4194              :         /* Open the LO */
    4195           81 :         loFd = lo_open(conn, loOid, INV_READ);
    4196           81 :         if (loFd == -1)
    4197            0 :             pg_fatal("could not open large object %u: %s",
    4198              :                      loOid, PQerrorMessage(conn));
    4199              : 
    4200           81 :         StartLO(fout, loOid);
    4201              : 
    4202              :         /* Now read it in chunks, sending data to archive */
    4203              :         do
    4204              :         {
    4205          127 :             cnt = lo_read(conn, loFd, buf, LOBBUFSIZE);
    4206          127 :             if (cnt < 0)
    4207            0 :                 pg_fatal("error reading large object %u: %s",
    4208              :                          loOid, PQerrorMessage(conn));
    4209              : 
    4210          127 :             WriteData(fout, buf, cnt);
    4211          127 :         } while (cnt > 0);
    4212              : 
    4213           81 :         lo_close(conn, loFd);
    4214              : 
    4215           81 :         EndLO(fout, loOid);
    4216              :     }
    4217              : 
    4218           73 :     return 1;
    4219              : }
    4220              : 
    4221              : /*
    4222              :  * getPolicies
    4223              :  *    get information about all RLS policies on dumpable tables.
    4224              :  */
    4225              : void
    4226          259 : getPolicies(Archive *fout, TableInfo tblinfo[], int numTables)
    4227              : {
    4228          259 :     DumpOptions *dopt = fout->dopt;
    4229              :     PQExpBuffer query;
    4230              :     PQExpBuffer tbloids;
    4231              :     PGresult   *res;
    4232              :     PolicyInfo *polinfo;
    4233              :     int         i_oid;
    4234              :     int         i_tableoid;
    4235              :     int         i_polrelid;
    4236              :     int         i_polname;
    4237              :     int         i_polcmd;
    4238              :     int         i_polpermissive;
    4239              :     int         i_polroles;
    4240              :     int         i_polqual;
    4241              :     int         i_polwithcheck;
    4242              :     int         i,
    4243              :                 j,
    4244              :                 ntups;
    4245              : 
    4246              :     /* No policies before 9.5 */
    4247          259 :     if (fout->remoteVersion < 90500)
    4248            0 :         return;
    4249              : 
    4250              :     /* Skip if --no-policies was specified */
    4251          259 :     if (dopt->no_policies)
    4252            1 :         return;
    4253              : 
    4254          258 :     query = createPQExpBuffer();
    4255          258 :     tbloids = createPQExpBuffer();
    4256              : 
    4257              :     /*
    4258              :      * Identify tables of interest, and check which ones have RLS enabled.
    4259              :      */
    4260          258 :     appendPQExpBufferChar(tbloids, '{');
    4261        70691 :     for (i = 0; i < numTables; i++)
    4262              :     {
    4263        70433 :         TableInfo  *tbinfo = &tblinfo[i];
    4264              : 
    4265              :         /* Ignore row security on tables not to be dumped */
    4266        70433 :         if (!(tbinfo->dobj.dump & DUMP_COMPONENT_POLICY))
    4267        62866 :             continue;
    4268              : 
    4269              :         /* It can't have RLS or policies if it's not a table */
    4270         7567 :         if (tbinfo->relkind != RELKIND_RELATION &&
    4271         2112 :             tbinfo->relkind != RELKIND_PARTITIONED_TABLE)
    4272         1496 :             continue;
    4273              : 
    4274              :         /* Add it to the list of table OIDs to be probed below */
    4275         6071 :         if (tbloids->len > 1) /* do we have more than the '{'? */
    4276         5896 :             appendPQExpBufferChar(tbloids, ',');
    4277         6071 :         appendPQExpBuffer(tbloids, "%u", tbinfo->dobj.catId.oid);
    4278              : 
    4279              :         /* Is RLS enabled?  (That's separate from whether it has policies) */
    4280         6071 :         if (tbinfo->rowsec)
    4281              :         {
    4282           63 :             tbinfo->dobj.components |= DUMP_COMPONENT_POLICY;
    4283              : 
    4284              :             /*
    4285              :              * We represent RLS being enabled on a table by creating a
    4286              :              * PolicyInfo object with null polname.
    4287              :              *
    4288              :              * Note: use tableoid 0 so that this object won't be mistaken for
    4289              :              * something that pg_depend entries apply to.
    4290              :              */
    4291           63 :             polinfo = pg_malloc_object(PolicyInfo);
    4292           63 :             polinfo->dobj.objType = DO_POLICY;
    4293           63 :             polinfo->dobj.catId.tableoid = 0;
    4294           63 :             polinfo->dobj.catId.oid = tbinfo->dobj.catId.oid;
    4295           63 :             AssignDumpId(&polinfo->dobj);
    4296           63 :             polinfo->dobj.namespace = tbinfo->dobj.namespace;
    4297           63 :             polinfo->dobj.name = pg_strdup(tbinfo->dobj.name);
    4298           63 :             polinfo->poltable = tbinfo;
    4299           63 :             polinfo->polname = NULL;
    4300           63 :             polinfo->polcmd = '\0';
    4301           63 :             polinfo->polpermissive = 0;
    4302           63 :             polinfo->polroles = NULL;
    4303           63 :             polinfo->polqual = NULL;
    4304           63 :             polinfo->polwithcheck = NULL;
    4305              :         }
    4306              :     }
    4307          258 :     appendPQExpBufferChar(tbloids, '}');
    4308              : 
    4309              :     /*
    4310              :      * Now, read all RLS policies belonging to the tables of interest, and
    4311              :      * create PolicyInfo objects for them.  (Note that we must filter the
    4312              :      * results server-side not locally, because we dare not apply pg_get_expr
    4313              :      * to tables we don't have lock on.)
    4314              :      */
    4315          258 :     pg_log_info("reading row-level security policies");
    4316              : 
    4317          258 :     printfPQExpBuffer(query,
    4318              :                       "SELECT pol.oid, pol.tableoid, pol.polrelid, pol.polname, pol.polcmd, ");
    4319          258 :     if (fout->remoteVersion >= 100000)
    4320          258 :         appendPQExpBufferStr(query, "pol.polpermissive, ");
    4321              :     else
    4322            0 :         appendPQExpBufferStr(query, "'t' as polpermissive, ");
    4323          258 :     appendPQExpBuffer(query,
    4324              :                       "CASE WHEN pol.polroles = '{0}' THEN NULL ELSE "
    4325              :                       "   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, "
    4326              :                       "pg_catalog.pg_get_expr(pol.polqual, pol.polrelid) AS polqual, "
    4327              :                       "pg_catalog.pg_get_expr(pol.polwithcheck, pol.polrelid) AS polwithcheck "
    4328              :                       "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
    4329              :                       "JOIN pg_catalog.pg_policy pol ON (src.tbloid = pol.polrelid)",
    4330              :                       tbloids->data);
    4331              : 
    4332          258 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    4333              : 
    4334          258 :     ntups = PQntuples(res);
    4335          258 :     if (ntups > 0)
    4336              :     {
    4337           43 :         i_oid = PQfnumber(res, "oid");
    4338           43 :         i_tableoid = PQfnumber(res, "tableoid");
    4339           43 :         i_polrelid = PQfnumber(res, "polrelid");
    4340           43 :         i_polname = PQfnumber(res, "polname");
    4341           43 :         i_polcmd = PQfnumber(res, "polcmd");
    4342           43 :         i_polpermissive = PQfnumber(res, "polpermissive");
    4343           43 :         i_polroles = PQfnumber(res, "polroles");
    4344           43 :         i_polqual = PQfnumber(res, "polqual");
    4345           43 :         i_polwithcheck = PQfnumber(res, "polwithcheck");
    4346              : 
    4347           43 :         polinfo = pg_malloc_array(PolicyInfo, ntups);
    4348              : 
    4349          316 :         for (j = 0; j < ntups; j++)
    4350              :         {
    4351          273 :             Oid         polrelid = atooid(PQgetvalue(res, j, i_polrelid));
    4352          273 :             TableInfo  *tbinfo = findTableByOid(polrelid);
    4353              : 
    4354          273 :             tbinfo->dobj.components |= DUMP_COMPONENT_POLICY;
    4355              : 
    4356          273 :             polinfo[j].dobj.objType = DO_POLICY;
    4357          273 :             polinfo[j].dobj.catId.tableoid =
    4358          273 :                 atooid(PQgetvalue(res, j, i_tableoid));
    4359          273 :             polinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
    4360          273 :             AssignDumpId(&polinfo[j].dobj);
    4361          273 :             polinfo[j].dobj.namespace = tbinfo->dobj.namespace;
    4362          273 :             polinfo[j].poltable = tbinfo;
    4363          273 :             polinfo[j].polname = pg_strdup(PQgetvalue(res, j, i_polname));
    4364          273 :             polinfo[j].dobj.name = pg_strdup(polinfo[j].polname);
    4365              : 
    4366          273 :             polinfo[j].polcmd = *(PQgetvalue(res, j, i_polcmd));
    4367          273 :             polinfo[j].polpermissive = *(PQgetvalue(res, j, i_polpermissive)) == 't';
    4368              : 
    4369          273 :             if (PQgetisnull(res, j, i_polroles))
    4370          121 :                 polinfo[j].polroles = NULL;
    4371              :             else
    4372          152 :                 polinfo[j].polroles = pg_strdup(PQgetvalue(res, j, i_polroles));
    4373              : 
    4374          273 :             if (PQgetisnull(res, j, i_polqual))
    4375           38 :                 polinfo[j].polqual = NULL;
    4376              :             else
    4377          235 :                 polinfo[j].polqual = pg_strdup(PQgetvalue(res, j, i_polqual));
    4378              : 
    4379          273 :             if (PQgetisnull(res, j, i_polwithcheck))
    4380          144 :                 polinfo[j].polwithcheck = NULL;
    4381              :             else
    4382          129 :                 polinfo[j].polwithcheck
    4383          129 :                     = pg_strdup(PQgetvalue(res, j, i_polwithcheck));
    4384              :         }
    4385              :     }
    4386              : 
    4387          258 :     PQclear(res);
    4388              : 
    4389          258 :     destroyPQExpBuffer(query);
    4390          258 :     destroyPQExpBuffer(tbloids);
    4391              : }
    4392              : 
    4393              : /*
    4394              :  * dumpPolicy
    4395              :  *    dump the definition of the given policy
    4396              :  */
    4397              : static void
    4398          336 : dumpPolicy(Archive *fout, const PolicyInfo *polinfo)
    4399              : {
    4400          336 :     DumpOptions *dopt = fout->dopt;
    4401          336 :     TableInfo  *tbinfo = polinfo->poltable;
    4402              :     PQExpBuffer query;
    4403              :     PQExpBuffer delqry;
    4404              :     PQExpBuffer polprefix;
    4405              :     char       *qtabname;
    4406              :     const char *cmd;
    4407              :     char       *tag;
    4408              : 
    4409              :     /* Do nothing if not dumping schema */
    4410          336 :     if (!dopt->dumpSchema)
    4411           49 :         return;
    4412              : 
    4413              :     /*
    4414              :      * If polname is NULL, then this record is just indicating that ROW LEVEL
    4415              :      * SECURITY is enabled for the table. Dump as ALTER TABLE <table> ENABLE
    4416              :      * ROW LEVEL SECURITY.
    4417              :      */
    4418          287 :     if (polinfo->polname == NULL)
    4419              :     {
    4420           56 :         query = createPQExpBuffer();
    4421              : 
    4422           56 :         appendPQExpBuffer(query, "ALTER TABLE %s ENABLE ROW LEVEL SECURITY;",
    4423           56 :                           fmtQualifiedDumpable(tbinfo));
    4424              : 
    4425              :         /*
    4426              :          * We must emit the ROW SECURITY object's dependency on its table
    4427              :          * explicitly, because it will not match anything in pg_depend (unlike
    4428              :          * the case for other PolicyInfo objects).
    4429              :          */
    4430           56 :         if (polinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
    4431           56 :             ArchiveEntry(fout, polinfo->dobj.catId, polinfo->dobj.dumpId,
    4432           56 :                          ARCHIVE_OPTS(.tag = polinfo->dobj.name,
    4433              :                                       .namespace = polinfo->dobj.namespace->dobj.name,
    4434              :                                       .owner = tbinfo->rolname,
    4435              :                                       .description = "ROW SECURITY",
    4436              :                                       .section = SECTION_POST_DATA,
    4437              :                                       .createStmt = query->data,
    4438              :                                       .deps = &(tbinfo->dobj.dumpId),
    4439              :                                       .nDeps = 1));
    4440              : 
    4441           56 :         destroyPQExpBuffer(query);
    4442           56 :         return;
    4443              :     }
    4444              : 
    4445          231 :     if (polinfo->polcmd == '*')
    4446           77 :         cmd = "";
    4447          154 :     else if (polinfo->polcmd == 'r')
    4448           41 :         cmd = " FOR SELECT";
    4449          113 :     else if (polinfo->polcmd == 'a')
    4450           31 :         cmd = " FOR INSERT";
    4451           82 :     else if (polinfo->polcmd == 'w')
    4452           41 :         cmd = " FOR UPDATE";
    4453           41 :     else if (polinfo->polcmd == 'd')
    4454           41 :         cmd = " FOR DELETE";
    4455              :     else
    4456            0 :         pg_fatal("unexpected policy command type: %c",
    4457              :                  polinfo->polcmd);
    4458              : 
    4459          231 :     query = createPQExpBuffer();
    4460          231 :     delqry = createPQExpBuffer();
    4461          231 :     polprefix = createPQExpBuffer();
    4462              : 
    4463          231 :     qtabname = pg_strdup(fmtId(tbinfo->dobj.name));
    4464              : 
    4465          231 :     appendPQExpBuffer(query, "CREATE POLICY %s", fmtId(polinfo->polname));
    4466              : 
    4467          231 :     appendPQExpBuffer(query, " ON %s%s%s", fmtQualifiedDumpable(tbinfo),
    4468          231 :                       !polinfo->polpermissive ? " AS RESTRICTIVE" : "", cmd);
    4469              : 
    4470          231 :     if (polinfo->polroles != NULL)
    4471          124 :         appendPQExpBuffer(query, " TO %s", polinfo->polroles);
    4472              : 
    4473          231 :     if (polinfo->polqual != NULL)
    4474          200 :         appendPQExpBuffer(query, " USING (%s)", polinfo->polqual);
    4475              : 
    4476          231 :     if (polinfo->polwithcheck != NULL)
    4477          108 :         appendPQExpBuffer(query, " WITH CHECK (%s)", polinfo->polwithcheck);
    4478              : 
    4479          231 :     appendPQExpBufferStr(query, ";\n");
    4480              : 
    4481          231 :     appendPQExpBuffer(delqry, "DROP POLICY %s", fmtId(polinfo->polname));
    4482          231 :     appendPQExpBuffer(delqry, " ON %s;\n", fmtQualifiedDumpable(tbinfo));
    4483              : 
    4484          231 :     appendPQExpBuffer(polprefix, "POLICY %s ON",
    4485          231 :                       fmtId(polinfo->polname));
    4486              : 
    4487          231 :     tag = psprintf("%s %s", tbinfo->dobj.name, polinfo->dobj.name);
    4488              : 
    4489          231 :     if (polinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
    4490          231 :         ArchiveEntry(fout, polinfo->dobj.catId, polinfo->dobj.dumpId,
    4491          231 :                      ARCHIVE_OPTS(.tag = tag,
    4492              :                                   .namespace = polinfo->dobj.namespace->dobj.name,
    4493              :                                   .owner = tbinfo->rolname,
    4494              :                                   .description = "POLICY",
    4495              :                                   .section = SECTION_POST_DATA,
    4496              :                                   .createStmt = query->data,
    4497              :                                   .dropStmt = delqry->data));
    4498              : 
    4499          231 :     if (polinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
    4500           31 :         dumpComment(fout, polprefix->data, qtabname,
    4501           31 :                     tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
    4502           31 :                     polinfo->dobj.catId, 0, polinfo->dobj.dumpId);
    4503              : 
    4504          231 :     free(tag);
    4505          231 :     destroyPQExpBuffer(query);
    4506          231 :     destroyPQExpBuffer(delqry);
    4507          231 :     destroyPQExpBuffer(polprefix);
    4508          231 :     free(qtabname);
    4509              : }
    4510              : 
    4511              : /*
    4512              :  * getPublications
    4513              :  *    get information about publications
    4514              :  */
    4515              : void
    4516          259 : getPublications(Archive *fout)
    4517              : {
    4518          259 :     DumpOptions *dopt = fout->dopt;
    4519              :     PQExpBuffer query;
    4520              :     PGresult   *res;
    4521              :     PublicationInfo *pubinfo;
    4522              :     int         i_tableoid;
    4523              :     int         i_oid;
    4524              :     int         i_pubname;
    4525              :     int         i_pubowner;
    4526              :     int         i_puballtables;
    4527              :     int         i_puballsequences;
    4528              :     int         i_pubinsert;
    4529              :     int         i_pubupdate;
    4530              :     int         i_pubdelete;
    4531              :     int         i_pubtruncate;
    4532              :     int         i_pubviaroot;
    4533              :     int         i_pubgencols;
    4534              :     int         i,
    4535              :                 ntups;
    4536              : 
    4537          259 :     if (dopt->no_publications || fout->remoteVersion < 100000)
    4538            0 :         return;
    4539              : 
    4540          259 :     query = createPQExpBuffer();
    4541              : 
    4542              :     /* Get the publications. */
    4543          259 :     appendPQExpBufferStr(query, "SELECT p.tableoid, p.oid, p.pubname, "
    4544              :                          "p.pubowner, p.puballtables, p.pubinsert, "
    4545              :                          "p.pubupdate, p.pubdelete, ");
    4546              : 
    4547          259 :     if (fout->remoteVersion >= 110000)
    4548          259 :         appendPQExpBufferStr(query, "p.pubtruncate, ");
    4549              :     else
    4550            0 :         appendPQExpBufferStr(query, "false AS pubtruncate, ");
    4551              : 
    4552          259 :     if (fout->remoteVersion >= 130000)
    4553          259 :         appendPQExpBufferStr(query, "p.pubviaroot, ");
    4554              :     else
    4555            0 :         appendPQExpBufferStr(query, "false AS pubviaroot, ");
    4556              : 
    4557          259 :     if (fout->remoteVersion >= 180000)
    4558          259 :         appendPQExpBufferStr(query, "p.pubgencols, ");
    4559              :     else
    4560            0 :         appendPQExpBuffer(query, "'%c' AS pubgencols, ", PUBLISH_GENCOLS_NONE);
    4561              : 
    4562          259 :     if (fout->remoteVersion >= 190000)
    4563          259 :         appendPQExpBufferStr(query, "p.puballsequences ");
    4564              :     else
    4565            0 :         appendPQExpBufferStr(query, "false AS puballsequences ");
    4566              : 
    4567          259 :     appendPQExpBufferStr(query, "FROM pg_publication p");
    4568              : 
    4569          259 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    4570              : 
    4571          259 :     ntups = PQntuples(res);
    4572              : 
    4573          259 :     if (ntups == 0)
    4574          206 :         goto cleanup;
    4575              : 
    4576           53 :     i_tableoid = PQfnumber(res, "tableoid");
    4577           53 :     i_oid = PQfnumber(res, "oid");
    4578           53 :     i_pubname = PQfnumber(res, "pubname");
    4579           53 :     i_pubowner = PQfnumber(res, "pubowner");
    4580           53 :     i_puballtables = PQfnumber(res, "puballtables");
    4581           53 :     i_puballsequences = PQfnumber(res, "puballsequences");
    4582           53 :     i_pubinsert = PQfnumber(res, "pubinsert");
    4583           53 :     i_pubupdate = PQfnumber(res, "pubupdate");
    4584           53 :     i_pubdelete = PQfnumber(res, "pubdelete");
    4585           53 :     i_pubtruncate = PQfnumber(res, "pubtruncate");
    4586           53 :     i_pubviaroot = PQfnumber(res, "pubviaroot");
    4587           53 :     i_pubgencols = PQfnumber(res, "pubgencols");
    4588              : 
    4589           53 :     pubinfo = pg_malloc_array(PublicationInfo, ntups);
    4590              : 
    4591          539 :     for (i = 0; i < ntups; i++)
    4592              :     {
    4593          486 :         pubinfo[i].dobj.objType = DO_PUBLICATION;
    4594          486 :         pubinfo[i].dobj.catId.tableoid =
    4595          486 :             atooid(PQgetvalue(res, i, i_tableoid));
    4596          486 :         pubinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    4597          486 :         AssignDumpId(&pubinfo[i].dobj);
    4598          486 :         pubinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_pubname));
    4599          486 :         pubinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_pubowner));
    4600          486 :         pubinfo[i].puballtables =
    4601          486 :             (strcmp(PQgetvalue(res, i, i_puballtables), "t") == 0);
    4602          486 :         pubinfo[i].puballsequences =
    4603          486 :             (strcmp(PQgetvalue(res, i, i_puballsequences), "t") == 0);
    4604          486 :         pubinfo[i].pubinsert =
    4605          486 :             (strcmp(PQgetvalue(res, i, i_pubinsert), "t") == 0);
    4606          486 :         pubinfo[i].pubupdate =
    4607          486 :             (strcmp(PQgetvalue(res, i, i_pubupdate), "t") == 0);
    4608          486 :         pubinfo[i].pubdelete =
    4609          486 :             (strcmp(PQgetvalue(res, i, i_pubdelete), "t") == 0);
    4610          486 :         pubinfo[i].pubtruncate =
    4611          486 :             (strcmp(PQgetvalue(res, i, i_pubtruncate), "t") == 0);
    4612          486 :         pubinfo[i].pubviaroot =
    4613          486 :             (strcmp(PQgetvalue(res, i, i_pubviaroot), "t") == 0);
    4614          486 :         pubinfo[i].pubgencols_type =
    4615          486 :             *(PQgetvalue(res, i, i_pubgencols));
    4616          486 :         pubinfo[i].except_tables = (SimplePtrList)
    4617              :         {
    4618              :             NULL, NULL
    4619              :         };
    4620              : 
    4621              :         /* Decide whether we want to dump it */
    4622          486 :         selectDumpableObject(&(pubinfo[i].dobj), fout);
    4623              : 
    4624              :         /*
    4625              :          * Get the list of tables for publications specified in the EXCEPT
    4626              :          * TABLE clause.
    4627              :          *
    4628              :          * Although individual table entries in EXCEPT list could be stored in
    4629              :          * PublicationRelInfo, dumpPublicationTable cannot be used to emit
    4630              :          * them, because there is no ALTER PUBLICATION ... ADD command to add
    4631              :          * individual table entries to the EXCEPT list.
    4632              :          *
    4633              :          * Therefore, the approach is to dump the complete EXCEPT list in a
    4634              :          * single CREATE PUBLICATION statement. PublicationInfo is used to
    4635              :          * collect this information, which is then emitted by
    4636              :          * dumpPublication().
    4637              :          */
    4638          486 :         if (fout->remoteVersion >= 190000)
    4639              :         {
    4640              :             int         ntbls;
    4641              :             PGresult   *res_tbls;
    4642              : 
    4643          486 :             resetPQExpBuffer(query);
    4644          486 :             appendPQExpBuffer(query,
    4645              :                               "SELECT prrelid\n"
    4646              :                               "FROM pg_catalog.pg_publication_rel\n"
    4647              :                               "WHERE prpubid = %u AND prexcept",
    4648          486 :                               pubinfo[i].dobj.catId.oid);
    4649              : 
    4650          486 :             res_tbls = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    4651              : 
    4652          486 :             ntbls = PQntuples(res_tbls);
    4653              : 
    4654          711 :             for (int j = 0; j < ntbls; j++)
    4655              :             {
    4656              :                 Oid         prrelid;
    4657              :                 TableInfo  *tbinfo;
    4658              : 
    4659          225 :                 prrelid = atooid(PQgetvalue(res_tbls, j, 0));
    4660              : 
    4661          225 :                 tbinfo = findTableByOid(prrelid);
    4662              : 
    4663          225 :                 if (tbinfo != NULL)
    4664          225 :                     simple_ptr_list_append(&pubinfo[i].except_tables, tbinfo);
    4665              :             }
    4666              : 
    4667          486 :             PQclear(res_tbls);
    4668              :         }
    4669              :     }
    4670              : 
    4671           53 : cleanup:
    4672          259 :     PQclear(res);
    4673              : 
    4674          259 :     destroyPQExpBuffer(query);
    4675              : }
    4676              : 
    4677              : /*
    4678              :  * dumpPublication
    4679              :  *    dump the definition of the given publication
    4680              :  */
    4681              : static void
    4682          396 : dumpPublication(Archive *fout, const PublicationInfo *pubinfo)
    4683              : {
    4684          396 :     DumpOptions *dopt = fout->dopt;
    4685              :     PQExpBuffer delq;
    4686              :     PQExpBuffer query;
    4687              :     char       *qpubname;
    4688          396 :     bool        first = true;
    4689              : 
    4690              :     /* Do nothing if not dumping schema */
    4691          396 :     if (!dopt->dumpSchema)
    4692           60 :         return;
    4693              : 
    4694          336 :     delq = createPQExpBuffer();
    4695          336 :     query = createPQExpBuffer();
    4696              : 
    4697          336 :     qpubname = pg_strdup(fmtId(pubinfo->dobj.name));
    4698              : 
    4699          336 :     appendPQExpBuffer(delq, "DROP PUBLICATION %s;\n",
    4700              :                       qpubname);
    4701              : 
    4702          336 :     appendPQExpBuffer(query, "CREATE PUBLICATION %s",
    4703              :                       qpubname);
    4704              : 
    4705          336 :     if (pubinfo->puballtables)
    4706              :     {
    4707          156 :         int         n_except = 0;
    4708              : 
    4709          156 :         appendPQExpBufferStr(query, " FOR ALL TABLES");
    4710              : 
    4711              :         /* Include EXCEPT (TABLE) clause if there are except_tables. */
    4712          311 :         for (SimplePtrListCell *cell = pubinfo->except_tables.head; cell; cell = cell->next)
    4713              :         {
    4714          155 :             TableInfo  *tbinfo = (TableInfo *) cell->ptr;
    4715              : 
    4716          155 :             if (++n_except == 1)
    4717           93 :                 appendPQExpBufferStr(query, " EXCEPT (");
    4718              :             else
    4719           62 :                 appendPQExpBufferStr(query, ", ");
    4720          155 :             appendPQExpBuffer(query, "TABLE ONLY %s", fmtQualifiedDumpable(tbinfo));
    4721              :         }
    4722          156 :         if (n_except > 0)
    4723           93 :             appendPQExpBufferChar(query, ')');
    4724              : 
    4725          156 :         if (pubinfo->puballsequences)
    4726           31 :             appendPQExpBufferStr(query, ", ALL SEQUENCES");
    4727              :     }
    4728          180 :     else if (pubinfo->puballsequences)
    4729           31 :         appendPQExpBufferStr(query, " FOR ALL SEQUENCES");
    4730              : 
    4731          336 :     appendPQExpBufferStr(query, " WITH (publish = '");
    4732          336 :     if (pubinfo->pubinsert)
    4733              :     {
    4734          274 :         appendPQExpBufferStr(query, "insert");
    4735          274 :         first = false;
    4736              :     }
    4737              : 
    4738          336 :     if (pubinfo->pubupdate)
    4739              :     {
    4740          274 :         if (!first)
    4741          274 :             appendPQExpBufferStr(query, ", ");
    4742              : 
    4743          274 :         appendPQExpBufferStr(query, "update");
    4744          274 :         first = false;
    4745              :     }
    4746              : 
    4747          336 :     if (pubinfo->pubdelete)
    4748              :     {
    4749          274 :         if (!first)
    4750          274 :             appendPQExpBufferStr(query, ", ");
    4751              : 
    4752          274 :         appendPQExpBufferStr(query, "delete");
    4753          274 :         first = false;
    4754              :     }
    4755              : 
    4756          336 :     if (pubinfo->pubtruncate)
    4757              :     {
    4758          274 :         if (!first)
    4759          274 :             appendPQExpBufferStr(query, ", ");
    4760              : 
    4761          274 :         appendPQExpBufferStr(query, "truncate");
    4762          274 :         first = false;
    4763              :     }
    4764              : 
    4765          336 :     appendPQExpBufferChar(query, '\'');
    4766              : 
    4767          336 :     if (pubinfo->pubviaroot)
    4768            5 :         appendPQExpBufferStr(query, ", publish_via_partition_root = true");
    4769              : 
    4770          336 :     if (pubinfo->pubgencols_type == PUBLISH_GENCOLS_STORED)
    4771           31 :         appendPQExpBufferStr(query, ", publish_generated_columns = stored");
    4772              : 
    4773          336 :     appendPQExpBufferStr(query, ");\n");
    4774              : 
    4775          336 :     if (pubinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
    4776          336 :         ArchiveEntry(fout, pubinfo->dobj.catId, pubinfo->dobj.dumpId,
    4777          336 :                      ARCHIVE_OPTS(.tag = pubinfo->dobj.name,
    4778              :                                   .owner = pubinfo->rolname,
    4779              :                                   .description = "PUBLICATION",
    4780              :                                   .section = SECTION_POST_DATA,
    4781              :                                   .createStmt = query->data,
    4782              :                                   .dropStmt = delq->data));
    4783              : 
    4784          336 :     if (pubinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
    4785           31 :         dumpComment(fout, "PUBLICATION", qpubname,
    4786           31 :                     NULL, pubinfo->rolname,
    4787           31 :                     pubinfo->dobj.catId, 0, pubinfo->dobj.dumpId);
    4788              : 
    4789          336 :     if (pubinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
    4790            0 :         dumpSecLabel(fout, "PUBLICATION", qpubname,
    4791            0 :                      NULL, pubinfo->rolname,
    4792            0 :                      pubinfo->dobj.catId, 0, pubinfo->dobj.dumpId);
    4793              : 
    4794          336 :     destroyPQExpBuffer(delq);
    4795          336 :     destroyPQExpBuffer(query);
    4796          336 :     free(qpubname);
    4797              : }
    4798              : 
    4799              : /*
    4800              :  * getPublicationNamespaces
    4801              :  *    get information about publication membership for dumpable schemas.
    4802              :  */
    4803              : void
    4804          259 : getPublicationNamespaces(Archive *fout)
    4805              : {
    4806              :     PQExpBuffer query;
    4807              :     PGresult   *res;
    4808              :     PublicationSchemaInfo *pubsinfo;
    4809          259 :     DumpOptions *dopt = fout->dopt;
    4810              :     int         i_tableoid;
    4811              :     int         i_oid;
    4812              :     int         i_pnpubid;
    4813              :     int         i_pnnspid;
    4814              :     int         i,
    4815              :                 j,
    4816              :                 ntups;
    4817              : 
    4818          259 :     if (dopt->no_publications || fout->remoteVersion < 150000)
    4819            0 :         return;
    4820              : 
    4821          259 :     query = createPQExpBuffer();
    4822              : 
    4823              :     /* Collect all publication membership info. */
    4824          259 :     appendPQExpBufferStr(query,
    4825              :                          "SELECT tableoid, oid, pnpubid, pnnspid "
    4826              :                          "FROM pg_catalog.pg_publication_namespace");
    4827          259 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    4828              : 
    4829          259 :     ntups = PQntuples(res);
    4830              : 
    4831          259 :     i_tableoid = PQfnumber(res, "tableoid");
    4832          259 :     i_oid = PQfnumber(res, "oid");
    4833          259 :     i_pnpubid = PQfnumber(res, "pnpubid");
    4834          259 :     i_pnnspid = PQfnumber(res, "pnnspid");
    4835              : 
    4836              :     /* this allocation may be more than we need */
    4837          259 :     pubsinfo = pg_malloc_array(PublicationSchemaInfo, ntups);
    4838          259 :     j = 0;
    4839              : 
    4840          384 :     for (i = 0; i < ntups; i++)
    4841              :     {
    4842          125 :         Oid         pnpubid = atooid(PQgetvalue(res, i, i_pnpubid));
    4843          125 :         Oid         pnnspid = atooid(PQgetvalue(res, i, i_pnnspid));
    4844              :         PublicationInfo *pubinfo;
    4845              :         NamespaceInfo *nspinfo;
    4846              : 
    4847              :         /*
    4848              :          * Ignore any entries for which we aren't interested in either the
    4849              :          * publication or the rel.
    4850              :          */
    4851          125 :         pubinfo = findPublicationByOid(pnpubid);
    4852          125 :         if (pubinfo == NULL)
    4853            0 :             continue;
    4854          125 :         nspinfo = findNamespaceByOid(pnnspid);
    4855          125 :         if (nspinfo == NULL)
    4856            0 :             continue;
    4857              : 
    4858              :         /* OK, make a DumpableObject for this relationship */
    4859          125 :         pubsinfo[j].dobj.objType = DO_PUBLICATION_TABLE_IN_SCHEMA;
    4860          125 :         pubsinfo[j].dobj.catId.tableoid =
    4861          125 :             atooid(PQgetvalue(res, i, i_tableoid));
    4862          125 :         pubsinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    4863          125 :         AssignDumpId(&pubsinfo[j].dobj);
    4864          125 :         pubsinfo[j].dobj.namespace = nspinfo->dobj.namespace;
    4865          125 :         pubsinfo[j].dobj.name = nspinfo->dobj.name;
    4866          125 :         pubsinfo[j].publication = pubinfo;
    4867          125 :         pubsinfo[j].pubschema = nspinfo;
    4868              : 
    4869              :         /* Decide whether we want to dump it */
    4870          125 :         selectDumpablePublicationObject(&(pubsinfo[j].dobj), fout);
    4871              : 
    4872          125 :         j++;
    4873              :     }
    4874              : 
    4875          259 :     PQclear(res);
    4876          259 :     destroyPQExpBuffer(query);
    4877              : }
    4878              : 
    4879              : /*
    4880              :  * getPublicationTables
    4881              :  *    get information about publication membership for dumpable tables.
    4882              :  */
    4883              : void
    4884          259 : getPublicationTables(Archive *fout, TableInfo tblinfo[], int numTables)
    4885              : {
    4886              :     PQExpBuffer query;
    4887              :     PGresult   *res;
    4888              :     PublicationRelInfo *pubrinfo;
    4889          259 :     DumpOptions *dopt = fout->dopt;
    4890              :     int         i_tableoid;
    4891              :     int         i_oid;
    4892              :     int         i_prpubid;
    4893              :     int         i_prrelid;
    4894              :     int         i_prrelqual;
    4895              :     int         i_prattrs;
    4896              :     int         i,
    4897              :                 j,
    4898              :                 ntups;
    4899              : 
    4900          259 :     if (dopt->no_publications || fout->remoteVersion < 100000)
    4901            0 :         return;
    4902              : 
    4903          259 :     query = createPQExpBuffer();
    4904              : 
    4905              :     /* Collect all publication membership info. */
    4906          259 :     if (fout->remoteVersion >= 150000)
    4907              :     {
    4908          259 :         appendPQExpBufferStr(query,
    4909              :                              "SELECT tableoid, oid, prpubid, prrelid, "
    4910              :                              "pg_catalog.pg_get_expr(prqual, prrelid) AS prrelqual, "
    4911              :                              "(CASE\n"
    4912              :                              "  WHEN pr.prattrs IS NOT NULL THEN\n"
    4913              :                              "    (SELECT array_agg(attname)\n"
    4914              :                              "       FROM\n"
    4915              :                              "         pg_catalog.generate_series(0, pg_catalog.array_upper(pr.prattrs::pg_catalog.int2[], 1)) s,\n"
    4916              :                              "         pg_catalog.pg_attribute\n"
    4917              :                              "      WHERE attrelid = pr.prrelid AND attnum = prattrs[s])\n"
    4918              :                              "  ELSE NULL END) prattrs "
    4919              :                              "FROM pg_catalog.pg_publication_rel pr");
    4920          259 :         if (fout->remoteVersion >= 190000)
    4921          259 :             appendPQExpBufferStr(query, " WHERE NOT pr.prexcept");
    4922              :     }
    4923              :     else
    4924            0 :         appendPQExpBufferStr(query,
    4925              :                              "SELECT tableoid, oid, prpubid, prrelid, "
    4926              :                              "NULL AS prrelqual, NULL AS prattrs "
    4927              :                              "FROM pg_catalog.pg_publication_rel");
    4928          259 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    4929              : 
    4930          259 :     ntups = PQntuples(res);
    4931              : 
    4932          259 :     i_tableoid = PQfnumber(res, "tableoid");
    4933          259 :     i_oid = PQfnumber(res, "oid");
    4934          259 :     i_prpubid = PQfnumber(res, "prpubid");
    4935          259 :     i_prrelid = PQfnumber(res, "prrelid");
    4936          259 :     i_prrelqual = PQfnumber(res, "prrelqual");
    4937          259 :     i_prattrs = PQfnumber(res, "prattrs");
    4938              : 
    4939              :     /* this allocation may be more than we need */
    4940          259 :     pubrinfo = pg_malloc_array(PublicationRelInfo, ntups);
    4941          259 :     j = 0;
    4942              : 
    4943          609 :     for (i = 0; i < ntups; i++)
    4944              :     {
    4945          350 :         Oid         prpubid = atooid(PQgetvalue(res, i, i_prpubid));
    4946          350 :         Oid         prrelid = atooid(PQgetvalue(res, i, i_prrelid));
    4947              :         PublicationInfo *pubinfo;
    4948              :         TableInfo  *tbinfo;
    4949              : 
    4950              :         /*
    4951              :          * Ignore any entries for which we aren't interested in either the
    4952              :          * publication or the rel.
    4953              :          */
    4954          350 :         pubinfo = findPublicationByOid(prpubid);
    4955          350 :         if (pubinfo == NULL)
    4956            0 :             continue;
    4957          350 :         tbinfo = findTableByOid(prrelid);
    4958          350 :         if (tbinfo == NULL)
    4959            0 :             continue;
    4960              : 
    4961              :         /* OK, make a DumpableObject for this relationship */
    4962          350 :         pubrinfo[j].dobj.objType = DO_PUBLICATION_REL;
    4963          350 :         pubrinfo[j].dobj.catId.tableoid =
    4964          350 :             atooid(PQgetvalue(res, i, i_tableoid));
    4965          350 :         pubrinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    4966          350 :         AssignDumpId(&pubrinfo[j].dobj);
    4967          350 :         pubrinfo[j].dobj.namespace = tbinfo->dobj.namespace;
    4968          350 :         pubrinfo[j].dobj.name = tbinfo->dobj.name;
    4969          350 :         pubrinfo[j].publication = pubinfo;
    4970          350 :         pubrinfo[j].pubtable = tbinfo;
    4971          350 :         if (PQgetisnull(res, i, i_prrelqual))
    4972          194 :             pubrinfo[j].pubrelqual = NULL;
    4973              :         else
    4974          156 :             pubrinfo[j].pubrelqual = pg_strdup(PQgetvalue(res, i, i_prrelqual));
    4975              : 
    4976          350 :         if (!PQgetisnull(res, i, i_prattrs))
    4977              :         {
    4978              :             char      **attnames;
    4979              :             int         nattnames;
    4980              :             PQExpBuffer attribs;
    4981              : 
    4982          111 :             if (!parsePGArray(PQgetvalue(res, i, i_prattrs),
    4983              :                               &attnames, &nattnames))
    4984            0 :                 pg_fatal("could not parse %s array", "prattrs");
    4985          111 :             attribs = createPQExpBuffer();
    4986          319 :             for (int k = 0; k < nattnames; k++)
    4987              :             {
    4988          208 :                 if (k > 0)
    4989           97 :                     appendPQExpBufferStr(attribs, ", ");
    4990              : 
    4991          208 :                 appendPQExpBufferStr(attribs, fmtId(attnames[k]));
    4992              :             }
    4993          111 :             pubrinfo[j].pubrattrs = attribs->data;
    4994          111 :             free(attribs);      /* but not attribs->data */
    4995          111 :             free(attnames);
    4996              :         }
    4997              :         else
    4998          239 :             pubrinfo[j].pubrattrs = NULL;
    4999              : 
    5000              :         /* Decide whether we want to dump it */
    5001          350 :         selectDumpablePublicationObject(&(pubrinfo[j].dobj), fout);
    5002              : 
    5003          350 :         j++;
    5004              :     }
    5005              : 
    5006          259 :     PQclear(res);
    5007          259 :     destroyPQExpBuffer(query);
    5008              : }
    5009              : 
    5010              : /*
    5011              :  * dumpPublicationNamespace
    5012              :  *    dump the definition of the given publication schema mapping.
    5013              :  */
    5014              : static void
    5015           99 : dumpPublicationNamespace(Archive *fout, const PublicationSchemaInfo *pubsinfo)
    5016              : {
    5017           99 :     DumpOptions *dopt = fout->dopt;
    5018           99 :     NamespaceInfo *schemainfo = pubsinfo->pubschema;
    5019           99 :     PublicationInfo *pubinfo = pubsinfo->publication;
    5020              :     PQExpBuffer query;
    5021              :     char       *tag;
    5022              : 
    5023              :     /* Do nothing if not dumping schema */
    5024           99 :     if (!dopt->dumpSchema)
    5025           12 :         return;
    5026              : 
    5027           87 :     tag = psprintf("%s %s", pubinfo->dobj.name, schemainfo->dobj.name);
    5028              : 
    5029           87 :     query = createPQExpBuffer();
    5030              : 
    5031           87 :     appendPQExpBuffer(query, "ALTER PUBLICATION %s ", fmtId(pubinfo->dobj.name));
    5032           87 :     appendPQExpBuffer(query, "ADD TABLES IN SCHEMA %s;\n", fmtId(schemainfo->dobj.name));
    5033              : 
    5034              :     /*
    5035              :      * There is no point in creating drop query as the drop is done by schema
    5036              :      * drop.
    5037              :      */
    5038           87 :     if (pubsinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
    5039           87 :         ArchiveEntry(fout, pubsinfo->dobj.catId, pubsinfo->dobj.dumpId,
    5040           87 :                      ARCHIVE_OPTS(.tag = tag,
    5041              :                                   .namespace = schemainfo->dobj.name,
    5042              :                                   .owner = pubinfo->rolname,
    5043              :                                   .description = "PUBLICATION TABLES IN SCHEMA",
    5044              :                                   .section = SECTION_POST_DATA,
    5045              :                                   .createStmt = query->data));
    5046              : 
    5047              :     /* These objects can't currently have comments or seclabels */
    5048              : 
    5049           87 :     free(tag);
    5050           87 :     destroyPQExpBuffer(query);
    5051              : }
    5052              : 
    5053              : /*
    5054              :  * dumpPublicationTable
    5055              :  *    dump the definition of the given publication table mapping
    5056              :  */
    5057              : static void
    5058          284 : dumpPublicationTable(Archive *fout, const PublicationRelInfo *pubrinfo)
    5059              : {
    5060          284 :     DumpOptions *dopt = fout->dopt;
    5061          284 :     PublicationInfo *pubinfo = pubrinfo->publication;
    5062          284 :     TableInfo  *tbinfo = pubrinfo->pubtable;
    5063              :     PQExpBuffer query;
    5064              :     char       *tag;
    5065              : 
    5066              :     /* Do nothing if not dumping schema */
    5067          284 :     if (!dopt->dumpSchema)
    5068           42 :         return;
    5069              : 
    5070          242 :     tag = psprintf("%s %s", pubinfo->dobj.name, tbinfo->dobj.name);
    5071              : 
    5072          242 :     query = createPQExpBuffer();
    5073              : 
    5074          242 :     appendPQExpBuffer(query, "ALTER PUBLICATION %s ADD TABLE ONLY",
    5075          242 :                       fmtId(pubinfo->dobj.name));
    5076          242 :     appendPQExpBuffer(query, " %s",
    5077          242 :                       fmtQualifiedDumpable(tbinfo));
    5078              : 
    5079          242 :     if (pubrinfo->pubrattrs)
    5080           77 :         appendPQExpBuffer(query, " (%s)", pubrinfo->pubrattrs);
    5081              : 
    5082          242 :     if (pubrinfo->pubrelqual)
    5083              :     {
    5084              :         /*
    5085              :          * It's necessary to add parentheses around the expression because
    5086              :          * pg_get_expr won't supply the parentheses for things like WHERE
    5087              :          * TRUE.
    5088              :          */
    5089          108 :         appendPQExpBuffer(query, " WHERE (%s)", pubrinfo->pubrelqual);
    5090              :     }
    5091          242 :     appendPQExpBufferStr(query, ";\n");
    5092              : 
    5093              :     /*
    5094              :      * There is no point in creating a drop query as the drop is done by table
    5095              :      * drop.  (If you think to change this, see also _printTocEntry().)
    5096              :      * Although this object doesn't really have ownership as such, set the
    5097              :      * owner field anyway to ensure that the command is run by the correct
    5098              :      * role at restore time.
    5099              :      */
    5100          242 :     if (pubrinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
    5101          242 :         ArchiveEntry(fout, pubrinfo->dobj.catId, pubrinfo->dobj.dumpId,
    5102          242 :                      ARCHIVE_OPTS(.tag = tag,
    5103              :                                   .namespace = tbinfo->dobj.namespace->dobj.name,
    5104              :                                   .owner = pubinfo->rolname,
    5105              :                                   .description = "PUBLICATION TABLE",
    5106              :                                   .section = SECTION_POST_DATA,
    5107              :                                   .createStmt = query->data));
    5108              : 
    5109              :     /* These objects can't currently have comments or seclabels */
    5110              : 
    5111          242 :     free(tag);
    5112          242 :     destroyPQExpBuffer(query);
    5113              : }
    5114              : 
    5115              : /*
    5116              :  * Is the currently connected user a superuser?
    5117              :  */
    5118              : static bool
    5119          258 : is_superuser(Archive *fout)
    5120              : {
    5121          258 :     ArchiveHandle *AH = (ArchiveHandle *) fout;
    5122              :     const char *val;
    5123              : 
    5124          258 :     val = PQparameterStatus(AH->connection, "is_superuser");
    5125              : 
    5126          258 :     if (val && strcmp(val, "on") == 0)
    5127          255 :         return true;
    5128              : 
    5129            3 :     return false;
    5130              : }
    5131              : 
    5132              : /*
    5133              :  * Set the given value to restrict_nonsystem_relation_kind value. Since
    5134              :  * restrict_nonsystem_relation_kind is introduced in minor version releases,
    5135              :  * the setting query is effective only where available.
    5136              :  */
    5137              : static void
    5138          293 : set_restrict_relation_kind(Archive *AH, const char *value)
    5139              : {
    5140          293 :     PQExpBuffer query = createPQExpBuffer();
    5141              :     PGresult   *res;
    5142              : 
    5143          293 :     appendPQExpBuffer(query,
    5144              :                       "SELECT set_config(name, '%s', false) "
    5145              :                       "FROM pg_settings "
    5146              :                       "WHERE name = 'restrict_nonsystem_relation_kind'",
    5147              :                       value);
    5148          293 :     res = ExecuteSqlQuery(AH, query->data, PGRES_TUPLES_OK);
    5149              : 
    5150          293 :     PQclear(res);
    5151          293 :     destroyPQExpBuffer(query);
    5152          293 : }
    5153              : 
    5154              : /*
    5155              :  * getSubscriptions
    5156              :  *    get information about subscriptions
    5157              :  */
    5158              : void
    5159          259 : getSubscriptions(Archive *fout)
    5160              : {
    5161          259 :     DumpOptions *dopt = fout->dopt;
    5162              :     PQExpBuffer query;
    5163              :     PGresult   *res;
    5164              :     SubscriptionInfo *subinfo;
    5165              :     int         i_tableoid;
    5166              :     int         i_oid;
    5167              :     int         i_subname;
    5168              :     int         i_subowner;
    5169              :     int         i_subbinary;
    5170              :     int         i_substream;
    5171              :     int         i_subtwophasestate;
    5172              :     int         i_subdisableonerr;
    5173              :     int         i_subpasswordrequired;
    5174              :     int         i_subrunasowner;
    5175              :     int         i_subservername;
    5176              :     int         i_subconninfo;
    5177              :     int         i_subslotname;
    5178              :     int         i_subsynccommit;
    5179              :     int         i_subwalrcvtimeout;
    5180              :     int         i_subpublications;
    5181              :     int         i_suborigin;
    5182              :     int         i_suboriginremotelsn;
    5183              :     int         i_subenabled;
    5184              :     int         i_subfailover;
    5185              :     int         i_subretaindeadtuples;
    5186              :     int         i_submaxretention;
    5187              :     int         i,
    5188              :                 ntups;
    5189              : 
    5190          259 :     if (dopt->no_subscriptions || fout->remoteVersion < 100000)
    5191            1 :         return;
    5192              : 
    5193          258 :     if (!is_superuser(fout))
    5194              :     {
    5195              :         int         n;
    5196              : 
    5197            3 :         res = ExecuteSqlQuery(fout,
    5198              :                               "SELECT count(*) FROM pg_subscription "
    5199              :                               "WHERE subdbid = (SELECT oid FROM pg_database"
    5200              :                               "                 WHERE datname = current_database())",
    5201              :                               PGRES_TUPLES_OK);
    5202            3 :         n = atoi(PQgetvalue(res, 0, 0));
    5203            3 :         if (n > 0)
    5204            2 :             pg_log_warning("subscriptions not dumped because current user is not a superuser");
    5205            3 :         PQclear(res);
    5206            3 :         return;
    5207              :     }
    5208              : 
    5209          255 :     query = createPQExpBuffer();
    5210              : 
    5211              :     /* Get the subscriptions in current database. */
    5212          255 :     appendPQExpBufferStr(query,
    5213              :                          "SELECT s.tableoid, s.oid, s.subname,\n"
    5214              :                          " s.subowner,\n"
    5215              :                          " s.subconninfo, s.subslotname, s.subsynccommit,\n"
    5216              :                          " s.subpublications,\n");
    5217              : 
    5218          255 :     if (fout->remoteVersion >= 140000)
    5219          255 :         appendPQExpBufferStr(query, " s.subbinary,\n");
    5220              :     else
    5221            0 :         appendPQExpBufferStr(query, " false AS subbinary,\n");
    5222              : 
    5223          255 :     if (fout->remoteVersion >= 140000)
    5224          255 :         appendPQExpBufferStr(query, " s.substream,\n");
    5225              :     else
    5226            0 :         appendPQExpBufferStr(query, " 'f' AS substream,\n");
    5227              : 
    5228          255 :     if (fout->remoteVersion >= 150000)
    5229          255 :         appendPQExpBufferStr(query,
    5230              :                              " s.subtwophasestate,\n"
    5231              :                              " s.subdisableonerr,\n");
    5232              :     else
    5233            0 :         appendPQExpBuffer(query,
    5234              :                           " '%c' AS subtwophasestate,\n"
    5235              :                           " false AS subdisableonerr,\n",
    5236              :                           LOGICALREP_TWOPHASE_STATE_DISABLED);
    5237              : 
    5238          255 :     if (fout->remoteVersion >= 160000)
    5239          255 :         appendPQExpBufferStr(query,
    5240              :                              " s.subpasswordrequired,\n"
    5241              :                              " s.subrunasowner,\n"
    5242              :                              " s.suborigin,\n");
    5243              :     else
    5244            0 :         appendPQExpBuffer(query,
    5245              :                           " 't' AS subpasswordrequired,\n"
    5246              :                           " 't' AS subrunasowner,\n"
    5247              :                           " '%s' AS suborigin,\n",
    5248              :                           LOGICALREP_ORIGIN_ANY);
    5249              : 
    5250          255 :     if (dopt->binary_upgrade && fout->remoteVersion >= 170000)
    5251           40 :         appendPQExpBufferStr(query, " o.remote_lsn AS suboriginremotelsn,\n"
    5252              :                              " s.subenabled,\n");
    5253              :     else
    5254          215 :         appendPQExpBufferStr(query, " NULL AS suboriginremotelsn,\n"
    5255              :                              " false AS subenabled,\n");
    5256              : 
    5257          255 :     if (fout->remoteVersion >= 170000)
    5258          255 :         appendPQExpBufferStr(query,
    5259              :                              " s.subfailover,\n");
    5260              :     else
    5261            0 :         appendPQExpBufferStr(query,
    5262              :                              " false AS subfailover,\n");
    5263              : 
    5264          255 :     if (fout->remoteVersion >= 190000)
    5265          255 :         appendPQExpBufferStr(query,
    5266              :                              " s.subretaindeadtuples,\n");
    5267              :     else
    5268            0 :         appendPQExpBufferStr(query,
    5269              :                              " false AS subretaindeadtuples,\n");
    5270              : 
    5271          255 :     if (fout->remoteVersion >= 190000)
    5272          255 :         appendPQExpBufferStr(query,
    5273              :                              " s.submaxretention,\n");
    5274              :     else
    5275            0 :         appendPQExpBufferStr(query, " 0 AS submaxretention,\n");
    5276              : 
    5277          255 :     if (fout->remoteVersion >= 190000)
    5278          255 :         appendPQExpBufferStr(query,
    5279              :                              " s.subwalrcvtimeout,\n");
    5280              :     else
    5281            0 :         appendPQExpBufferStr(query,
    5282              :                              " '-1' AS subwalrcvtimeout,\n");
    5283              : 
    5284          255 :     if (fout->remoteVersion >= 190000)
    5285          255 :         appendPQExpBufferStr(query, " fs.srvname AS subservername\n");
    5286              :     else
    5287            0 :         appendPQExpBufferStr(query, " NULL AS subservername\n");
    5288              : 
    5289          255 :     appendPQExpBufferStr(query,
    5290              :                          "FROM pg_subscription s\n");
    5291              : 
    5292          255 :     if (fout->remoteVersion >= 190000)
    5293          255 :         appendPQExpBufferStr(query,
    5294              :                              "LEFT JOIN pg_catalog.pg_foreign_server fs \n"
    5295              :                              "    ON fs.oid = s.subserver \n");
    5296              : 
    5297          255 :     if (dopt->binary_upgrade && fout->remoteVersion >= 170000)
    5298           40 :         appendPQExpBufferStr(query,
    5299              :                              "LEFT JOIN pg_catalog.pg_replication_origin_status o \n"
    5300              :                              "    ON o.external_id = 'pg_' || s.oid::text \n");
    5301              : 
    5302          255 :     appendPQExpBufferStr(query,
    5303              :                          "WHERE s.subdbid = (SELECT oid FROM pg_database\n"
    5304              :                          "                   WHERE datname = current_database())");
    5305              : 
    5306          255 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    5307              : 
    5308          255 :     ntups = PQntuples(res);
    5309              : 
    5310              :     /*
    5311              :      * Get subscription fields. We don't include subskiplsn in the dump as
    5312              :      * after restoring the dump this value may no longer be relevant.
    5313              :      */
    5314          255 :     i_tableoid = PQfnumber(res, "tableoid");
    5315          255 :     i_oid = PQfnumber(res, "oid");
    5316          255 :     i_subname = PQfnumber(res, "subname");
    5317          255 :     i_subowner = PQfnumber(res, "subowner");
    5318          255 :     i_subenabled = PQfnumber(res, "subenabled");
    5319          255 :     i_subbinary = PQfnumber(res, "subbinary");
    5320          255 :     i_substream = PQfnumber(res, "substream");
    5321          255 :     i_subtwophasestate = PQfnumber(res, "subtwophasestate");
    5322          255 :     i_subdisableonerr = PQfnumber(res, "subdisableonerr");
    5323          255 :     i_subpasswordrequired = PQfnumber(res, "subpasswordrequired");
    5324          255 :     i_subrunasowner = PQfnumber(res, "subrunasowner");
    5325          255 :     i_subfailover = PQfnumber(res, "subfailover");
    5326          255 :     i_subretaindeadtuples = PQfnumber(res, "subretaindeadtuples");
    5327          255 :     i_submaxretention = PQfnumber(res, "submaxretention");
    5328          255 :     i_subservername = PQfnumber(res, "subservername");
    5329          255 :     i_subconninfo = PQfnumber(res, "subconninfo");
    5330          255 :     i_subslotname = PQfnumber(res, "subslotname");
    5331          255 :     i_subsynccommit = PQfnumber(res, "subsynccommit");
    5332          255 :     i_subwalrcvtimeout = PQfnumber(res, "subwalrcvtimeout");
    5333          255 :     i_subpublications = PQfnumber(res, "subpublications");
    5334          255 :     i_suborigin = PQfnumber(res, "suborigin");
    5335          255 :     i_suboriginremotelsn = PQfnumber(res, "suboriginremotelsn");
    5336              : 
    5337          255 :     subinfo = pg_malloc_array(SubscriptionInfo, ntups);
    5338              : 
    5339          383 :     for (i = 0; i < ntups; i++)
    5340              :     {
    5341          128 :         subinfo[i].dobj.objType = DO_SUBSCRIPTION;
    5342          128 :         subinfo[i].dobj.catId.tableoid =
    5343          128 :             atooid(PQgetvalue(res, i, i_tableoid));
    5344          128 :         subinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    5345          128 :         AssignDumpId(&subinfo[i].dobj);
    5346          128 :         subinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_subname));
    5347          128 :         subinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_subowner));
    5348              : 
    5349          128 :         subinfo[i].subenabled =
    5350          128 :             (strcmp(PQgetvalue(res, i, i_subenabled), "t") == 0);
    5351          128 :         if (PQgetisnull(res, i, i_subservername))
    5352          128 :             subinfo[i].subservername = NULL;
    5353              :         else
    5354            0 :             subinfo[i].subservername = pg_strdup(PQgetvalue(res, i, i_subservername));
    5355          128 :         subinfo[i].subbinary =
    5356          128 :             (strcmp(PQgetvalue(res, i, i_subbinary), "t") == 0);
    5357          128 :         subinfo[i].substream = *(PQgetvalue(res, i, i_substream));
    5358          128 :         subinfo[i].subtwophasestate = *(PQgetvalue(res, i, i_subtwophasestate));
    5359          128 :         subinfo[i].subdisableonerr =
    5360          128 :             (strcmp(PQgetvalue(res, i, i_subdisableonerr), "t") == 0);
    5361          128 :         subinfo[i].subpasswordrequired =
    5362          128 :             (strcmp(PQgetvalue(res, i, i_subpasswordrequired), "t") == 0);
    5363          128 :         subinfo[i].subrunasowner =
    5364          128 :             (strcmp(PQgetvalue(res, i, i_subrunasowner), "t") == 0);
    5365          128 :         subinfo[i].subfailover =
    5366          128 :             (strcmp(PQgetvalue(res, i, i_subfailover), "t") == 0);
    5367          128 :         subinfo[i].subretaindeadtuples =
    5368          128 :             (strcmp(PQgetvalue(res, i, i_subretaindeadtuples), "t") == 0);
    5369          128 :         subinfo[i].submaxretention =
    5370          128 :             atoi(PQgetvalue(res, i, i_submaxretention));
    5371          128 :         if (PQgetisnull(res, i, i_subconninfo))
    5372            0 :             subinfo[i].subconninfo = NULL;
    5373              :         else
    5374          128 :             subinfo[i].subconninfo =
    5375          128 :                 pg_strdup(PQgetvalue(res, i, i_subconninfo));
    5376          128 :         if (PQgetisnull(res, i, i_subslotname))
    5377            0 :             subinfo[i].subslotname = NULL;
    5378              :         else
    5379          128 :             subinfo[i].subslotname =
    5380          128 :                 pg_strdup(PQgetvalue(res, i, i_subslotname));
    5381          256 :         subinfo[i].subsynccommit =
    5382          128 :             pg_strdup(PQgetvalue(res, i, i_subsynccommit));
    5383          256 :         subinfo[i].subwalrcvtimeout =
    5384          128 :             pg_strdup(PQgetvalue(res, i, i_subwalrcvtimeout));
    5385          256 :         subinfo[i].subpublications =
    5386          128 :             pg_strdup(PQgetvalue(res, i, i_subpublications));
    5387          128 :         subinfo[i].suborigin = pg_strdup(PQgetvalue(res, i, i_suborigin));
    5388          128 :         if (PQgetisnull(res, i, i_suboriginremotelsn))
    5389          127 :             subinfo[i].suboriginremotelsn = NULL;
    5390              :         else
    5391            1 :             subinfo[i].suboriginremotelsn =
    5392            1 :                 pg_strdup(PQgetvalue(res, i, i_suboriginremotelsn));
    5393              : 
    5394              :         /* Decide whether we want to dump it */
    5395          128 :         selectDumpableObject(&(subinfo[i].dobj), fout);
    5396              :     }
    5397          255 :     PQclear(res);
    5398              : 
    5399          255 :     destroyPQExpBuffer(query);
    5400              : }
    5401              : 
    5402              : /*
    5403              :  * getSubscriptionRelations
    5404              :  *    Get information about subscription membership for dumpable relations. This
    5405              :  *    will be used only in binary-upgrade mode for PG17 or later versions.
    5406              :  */
    5407              : void
    5408          259 : getSubscriptionRelations(Archive *fout)
    5409              : {
    5410          259 :     DumpOptions *dopt = fout->dopt;
    5411          259 :     SubscriptionInfo *subinfo = NULL;
    5412              :     SubRelInfo *subrinfo;
    5413              :     PGresult   *res;
    5414              :     int         i_srsubid;
    5415              :     int         i_srrelid;
    5416              :     int         i_srsubstate;
    5417              :     int         i_srsublsn;
    5418              :     int         ntups;
    5419          259 :     Oid         last_srsubid = InvalidOid;
    5420              : 
    5421          259 :     if (dopt->no_subscriptions || !dopt->binary_upgrade ||
    5422           40 :         fout->remoteVersion < 170000)
    5423          219 :         return;
    5424              : 
    5425           40 :     res = ExecuteSqlQuery(fout,
    5426              :                           "SELECT srsubid, srrelid, srsubstate, srsublsn "
    5427              :                           "FROM pg_catalog.pg_subscription_rel "
    5428              :                           "ORDER BY srsubid",
    5429              :                           PGRES_TUPLES_OK);
    5430           40 :     ntups = PQntuples(res);
    5431           40 :     if (ntups == 0)
    5432           39 :         goto cleanup;
    5433              : 
    5434              :     /* Get pg_subscription_rel attributes */
    5435            1 :     i_srsubid = PQfnumber(res, "srsubid");
    5436            1 :     i_srrelid = PQfnumber(res, "srrelid");
    5437            1 :     i_srsubstate = PQfnumber(res, "srsubstate");
    5438            1 :     i_srsublsn = PQfnumber(res, "srsublsn");
    5439              : 
    5440            1 :     subrinfo = pg_malloc_array(SubRelInfo, ntups);
    5441            4 :     for (int i = 0; i < ntups; i++)
    5442              :     {
    5443            3 :         Oid         cur_srsubid = atooid(PQgetvalue(res, i, i_srsubid));
    5444            3 :         Oid         relid = atooid(PQgetvalue(res, i, i_srrelid));
    5445              :         TableInfo  *tblinfo;
    5446              : 
    5447              :         /*
    5448              :          * If we switched to a new subscription, check if the subscription
    5449              :          * exists.
    5450              :          */
    5451            3 :         if (cur_srsubid != last_srsubid)
    5452              :         {
    5453            2 :             subinfo = findSubscriptionByOid(cur_srsubid);
    5454            2 :             if (subinfo == NULL)
    5455            0 :                 pg_fatal("subscription with OID %u does not exist", cur_srsubid);
    5456              : 
    5457            2 :             last_srsubid = cur_srsubid;
    5458              :         }
    5459              : 
    5460            3 :         tblinfo = findTableByOid(relid);
    5461            3 :         if (tblinfo == NULL)
    5462            0 :             pg_fatal("failed sanity check, relation with OID %u not found",
    5463              :                      relid);
    5464              : 
    5465              :         /* OK, make a DumpableObject for this relationship */
    5466            3 :         subrinfo[i].dobj.objType = DO_SUBSCRIPTION_REL;
    5467            3 :         subrinfo[i].dobj.catId.tableoid = relid;
    5468            3 :         subrinfo[i].dobj.catId.oid = cur_srsubid;
    5469            3 :         AssignDumpId(&subrinfo[i].dobj);
    5470            3 :         subrinfo[i].dobj.namespace = tblinfo->dobj.namespace;
    5471            3 :         subrinfo[i].dobj.name = tblinfo->dobj.name;
    5472            3 :         subrinfo[i].subinfo = subinfo;
    5473            3 :         subrinfo[i].tblinfo = tblinfo;
    5474            3 :         subrinfo[i].srsubstate = PQgetvalue(res, i, i_srsubstate)[0];
    5475            3 :         if (PQgetisnull(res, i, i_srsublsn))
    5476            1 :             subrinfo[i].srsublsn = NULL;
    5477              :         else
    5478            2 :             subrinfo[i].srsublsn = pg_strdup(PQgetvalue(res, i, i_srsublsn));
    5479              : 
    5480              :         /* Decide whether we want to dump it */
    5481            3 :         selectDumpableObject(&(subrinfo[i].dobj), fout);
    5482              :     }
    5483              : 
    5484            1 : cleanup:
    5485           40 :     PQclear(res);
    5486              : }
    5487              : 
    5488              : /*
    5489              :  * dumpSubscriptionTable
    5490              :  *    Dump the definition of the given subscription table mapping. This will be
    5491              :  *    used only in binary-upgrade mode for PG17 or later versions.
    5492              :  */
    5493              : static void
    5494            3 : dumpSubscriptionTable(Archive *fout, const SubRelInfo *subrinfo)
    5495              : {
    5496            3 :     DumpOptions *dopt = fout->dopt;
    5497            3 :     SubscriptionInfo *subinfo = subrinfo->subinfo;
    5498              :     PQExpBuffer query;
    5499              :     char       *tag;
    5500              : 
    5501              :     /* Do nothing if not dumping schema */
    5502            3 :     if (!dopt->dumpSchema)
    5503            0 :         return;
    5504              : 
    5505              :     Assert(fout->dopt->binary_upgrade && fout->remoteVersion >= 170000);
    5506              : 
    5507            3 :     tag = psprintf("%s %s", subinfo->dobj.name, subrinfo->tblinfo->dobj.name);
    5508              : 
    5509            3 :     query = createPQExpBuffer();
    5510              : 
    5511            3 :     if (subinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
    5512              :     {
    5513              :         /*
    5514              :          * binary_upgrade_add_sub_rel_state will add the subscription relation
    5515              :          * to pg_subscription_rel table. This will be used only in
    5516              :          * binary-upgrade mode.
    5517              :          */
    5518            3 :         appendPQExpBufferStr(query,
    5519              :                              "\n-- For binary upgrade, must preserve the subscriber table.\n");
    5520            3 :         appendPQExpBufferStr(query,
    5521              :                              "SELECT pg_catalog.binary_upgrade_add_sub_rel_state(");
    5522            3 :         appendStringLiteralAH(query, subinfo->dobj.name, fout);
    5523            3 :         appendPQExpBuffer(query,
    5524              :                           ", %u, '%c'",
    5525            3 :                           subrinfo->tblinfo->dobj.catId.oid,
    5526            3 :                           subrinfo->srsubstate);
    5527              : 
    5528            3 :         if (subrinfo->srsublsn && subrinfo->srsublsn[0] != '\0')
    5529            2 :             appendPQExpBuffer(query, ", '%s'", subrinfo->srsublsn);
    5530              :         else
    5531            1 :             appendPQExpBufferStr(query, ", NULL");
    5532              : 
    5533            3 :         appendPQExpBufferStr(query, ");\n");
    5534              :     }
    5535              : 
    5536              :     /*
    5537              :      * There is no point in creating a drop query as the drop is done by table
    5538              :      * drop.  (If you think to change this, see also _printTocEntry().)
    5539              :      * Although this object doesn't really have ownership as such, set the
    5540              :      * owner field anyway to ensure that the command is run by the correct
    5541              :      * role at restore time.
    5542              :      */
    5543            3 :     if (subrinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
    5544            3 :         ArchiveEntry(fout, subrinfo->dobj.catId, subrinfo->dobj.dumpId,
    5545            3 :                      ARCHIVE_OPTS(.tag = tag,
    5546              :                                   .namespace = subrinfo->tblinfo->dobj.namespace->dobj.name,
    5547              :                                   .owner = subinfo->rolname,
    5548              :                                   .description = "SUBSCRIPTION TABLE",
    5549              :                                   .section = SECTION_POST_DATA,
    5550              :                                   .createStmt = query->data));
    5551              : 
    5552              :     /* These objects can't currently have comments or seclabels */
    5553              : 
    5554            3 :     free(tag);
    5555            3 :     destroyPQExpBuffer(query);
    5556              : }
    5557              : 
    5558              : /*
    5559              :  * dumpSubscription
    5560              :  *    dump the definition of the given subscription
    5561              :  */
    5562              : static void
    5563          110 : dumpSubscription(Archive *fout, const SubscriptionInfo *subinfo)
    5564              : {
    5565          110 :     DumpOptions *dopt = fout->dopt;
    5566              :     PQExpBuffer delq;
    5567              :     PQExpBuffer query;
    5568              :     PQExpBuffer publications;
    5569              :     char       *qsubname;
    5570          110 :     char      **pubnames = NULL;
    5571          110 :     int         npubnames = 0;
    5572              :     int         i;
    5573              : 
    5574              :     /* Do nothing if not dumping schema */
    5575          110 :     if (!dopt->dumpSchema)
    5576           18 :         return;
    5577              : 
    5578           92 :     delq = createPQExpBuffer();
    5579           92 :     query = createPQExpBuffer();
    5580              : 
    5581           92 :     qsubname = pg_strdup(fmtId(subinfo->dobj.name));
    5582              : 
    5583           92 :     appendPQExpBuffer(delq, "DROP SUBSCRIPTION %s;\n",
    5584              :                       qsubname);
    5585              : 
    5586           92 :     appendPQExpBuffer(query, "CREATE SUBSCRIPTION %s ",
    5587              :                       qsubname);
    5588           92 :     if (subinfo->subservername)
    5589              :     {
    5590            0 :         appendPQExpBuffer(query, "SERVER %s", fmtId(subinfo->subservername));
    5591              :     }
    5592              :     else
    5593              :     {
    5594           92 :         appendPQExpBufferStr(query, "CONNECTION ");
    5595           92 :         appendStringLiteralAH(query, subinfo->subconninfo, fout);
    5596              :     }
    5597              : 
    5598              :     /* Build list of quoted publications and append them to query. */
    5599           92 :     if (!parsePGArray(subinfo->subpublications, &pubnames, &npubnames))
    5600            0 :         pg_fatal("could not parse %s array", "subpublications");
    5601              : 
    5602           92 :     publications = createPQExpBuffer();
    5603          184 :     for (i = 0; i < npubnames; i++)
    5604              :     {
    5605           92 :         if (i > 0)
    5606            0 :             appendPQExpBufferStr(publications, ", ");
    5607              : 
    5608           92 :         appendPQExpBufferStr(publications, fmtId(pubnames[i]));
    5609              :     }
    5610              : 
    5611           92 :     appendPQExpBuffer(query, " PUBLICATION %s WITH (connect = false, slot_name = ", publications->data);
    5612           92 :     if (subinfo->subslotname)
    5613           92 :         appendStringLiteralAH(query, subinfo->subslotname, fout);
    5614              :     else
    5615            0 :         appendPQExpBufferStr(query, "NONE");
    5616              : 
    5617           92 :     if (subinfo->subbinary)
    5618            0 :         appendPQExpBufferStr(query, ", binary = true");
    5619              : 
    5620           92 :     if (subinfo->substream == LOGICALREP_STREAM_ON)
    5621           30 :         appendPQExpBufferStr(query, ", streaming = on");
    5622           62 :     else if (subinfo->substream == LOGICALREP_STREAM_PARALLEL)
    5623           32 :         appendPQExpBufferStr(query, ", streaming = parallel");
    5624              :     else
    5625           30 :         appendPQExpBufferStr(query, ", streaming = off");
    5626              : 
    5627           92 :     if (subinfo->subtwophasestate != LOGICALREP_TWOPHASE_STATE_DISABLED)
    5628            0 :         appendPQExpBufferStr(query, ", two_phase = on");
    5629              : 
    5630           92 :     if (subinfo->subdisableonerr)
    5631            0 :         appendPQExpBufferStr(query, ", disable_on_error = true");
    5632              : 
    5633           92 :     if (!subinfo->subpasswordrequired)
    5634            0 :         appendPQExpBufferStr(query, ", password_required = false");
    5635              : 
    5636           92 :     if (subinfo->subrunasowner)
    5637            0 :         appendPQExpBufferStr(query, ", run_as_owner = true");
    5638              : 
    5639           92 :     if (subinfo->subfailover)
    5640            1 :         appendPQExpBufferStr(query, ", failover = true");
    5641              : 
    5642           92 :     if (subinfo->subretaindeadtuples)
    5643            1 :         appendPQExpBufferStr(query, ", retain_dead_tuples = true");
    5644              : 
    5645           92 :     if (subinfo->submaxretention)
    5646            0 :         appendPQExpBuffer(query, ", max_retention_duration = %d", subinfo->submaxretention);
    5647              : 
    5648           92 :     if (strcmp(subinfo->subsynccommit, "off") != 0)
    5649            0 :         appendPQExpBuffer(query, ", synchronous_commit = %s", fmtId(subinfo->subsynccommit));
    5650              : 
    5651           92 :     if (strcmp(subinfo->subwalrcvtimeout, "-1") != 0)
    5652            0 :         appendPQExpBuffer(query, ", wal_receiver_timeout = %s", fmtId(subinfo->subwalrcvtimeout));
    5653              : 
    5654           92 :     if (pg_strcasecmp(subinfo->suborigin, LOGICALREP_ORIGIN_ANY) != 0)
    5655           30 :         appendPQExpBuffer(query, ", origin = %s", subinfo->suborigin);
    5656              : 
    5657           92 :     appendPQExpBufferStr(query, ");\n");
    5658              : 
    5659              :     /*
    5660              :      * In binary-upgrade mode, we allow the replication to continue after the
    5661              :      * upgrade.
    5662              :      */
    5663           92 :     if (dopt->binary_upgrade && fout->remoteVersion >= 170000)
    5664              :     {
    5665            5 :         if (subinfo->suboriginremotelsn)
    5666              :         {
    5667              :             /*
    5668              :              * Preserve the remote_lsn for the subscriber's replication
    5669              :              * origin. This value is required to start the replication from
    5670              :              * the position before the upgrade. This value will be stale if
    5671              :              * the publisher gets upgraded before the subscriber node.
    5672              :              * However, this shouldn't be a problem as the upgrade of the
    5673              :              * publisher ensures that all the transactions were replicated
    5674              :              * before upgrading it.
    5675              :              */
    5676            1 :             appendPQExpBufferStr(query,
    5677              :                                  "\n-- For binary upgrade, must preserve the remote_lsn for the subscriber's replication origin.\n");
    5678            1 :             appendPQExpBufferStr(query,
    5679              :                                  "SELECT pg_catalog.binary_upgrade_replorigin_advance(");
    5680            1 :             appendStringLiteralAH(query, subinfo->dobj.name, fout);
    5681            1 :             appendPQExpBuffer(query, ", '%s');\n", subinfo->suboriginremotelsn);
    5682              :         }
    5683              : 
    5684            5 :         if (subinfo->subenabled)
    5685              :         {
    5686              :             /*
    5687              :              * Enable the subscription to allow the replication to continue
    5688              :              * after the upgrade.
    5689              :              */
    5690            1 :             appendPQExpBufferStr(query,
    5691              :                                  "\n-- For binary upgrade, must preserve the subscriber's running state.\n");
    5692            1 :             appendPQExpBuffer(query, "ALTER SUBSCRIPTION %s ENABLE;\n", qsubname);
    5693              :         }
    5694              :     }
    5695              : 
    5696           92 :     if (subinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
    5697           92 :         ArchiveEntry(fout, subinfo->dobj.catId, subinfo->dobj.dumpId,
    5698           92 :                      ARCHIVE_OPTS(.tag = subinfo->dobj.name,
    5699              :                                   .owner = subinfo->rolname,
    5700              :                                   .description = "SUBSCRIPTION",
    5701              :                                   .section = SECTION_POST_DATA,
    5702              :                                   .createStmt = query->data,
    5703              :                                   .dropStmt = delq->data));
    5704              : 
    5705           92 :     if (subinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
    5706           30 :         dumpComment(fout, "SUBSCRIPTION", qsubname,
    5707           30 :                     NULL, subinfo->rolname,
    5708           30 :                     subinfo->dobj.catId, 0, subinfo->dobj.dumpId);
    5709              : 
    5710           92 :     if (subinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
    5711            0 :         dumpSecLabel(fout, "SUBSCRIPTION", qsubname,
    5712            0 :                      NULL, subinfo->rolname,
    5713            0 :                      subinfo->dobj.catId, 0, subinfo->dobj.dumpId);
    5714              : 
    5715           92 :     destroyPQExpBuffer(publications);
    5716           92 :     free(pubnames);
    5717              : 
    5718           92 :     destroyPQExpBuffer(delq);
    5719           92 :     destroyPQExpBuffer(query);
    5720           92 :     free(qsubname);
    5721              : }
    5722              : 
    5723              : /*
    5724              :  * Given a "create query", append as many ALTER ... DEPENDS ON EXTENSION as
    5725              :  * the object needs.
    5726              :  */
    5727              : static void
    5728         5314 : append_depends_on_extension(Archive *fout,
    5729              :                             PQExpBuffer create,
    5730              :                             const DumpableObject *dobj,
    5731              :                             const char *catalog,
    5732              :                             const char *keyword,
    5733              :                             const char *objname)
    5734              : {
    5735         5314 :     if (dobj->depends_on_ext)
    5736              :     {
    5737              :         char       *nm;
    5738              :         PGresult   *res;
    5739              :         PQExpBuffer query;
    5740              :         int         ntups;
    5741              :         int         i_extname;
    5742              :         int         i;
    5743              : 
    5744              :         /* dodge fmtId() non-reentrancy */
    5745           42 :         nm = pg_strdup(objname);
    5746              : 
    5747           42 :         query = createPQExpBuffer();
    5748           42 :         appendPQExpBuffer(query,
    5749              :                           "SELECT e.extname "
    5750              :                           "FROM pg_catalog.pg_depend d, pg_catalog.pg_extension e "
    5751              :                           "WHERE d.refobjid = e.oid AND classid = '%s'::pg_catalog.regclass "
    5752              :                           "AND objid = '%u'::pg_catalog.oid AND deptype = 'x' "
    5753              :                           "AND refclassid = 'pg_catalog.pg_extension'::pg_catalog.regclass",
    5754              :                           catalog,
    5755           42 :                           dobj->catId.oid);
    5756           42 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    5757           42 :         ntups = PQntuples(res);
    5758           42 :         i_extname = PQfnumber(res, "extname");
    5759           84 :         for (i = 0; i < ntups; i++)
    5760              :         {
    5761           42 :             appendPQExpBuffer(create, "\nALTER %s %s DEPENDS ON EXTENSION %s;",
    5762              :                               keyword, nm,
    5763           42 :                               fmtId(PQgetvalue(res, i, i_extname)));
    5764              :         }
    5765              : 
    5766           42 :         PQclear(res);
    5767           42 :         destroyPQExpBuffer(query);
    5768           42 :         pg_free(nm);
    5769              :     }
    5770         5314 : }
    5771              : 
    5772              : static Oid
    5773            0 : get_next_possible_free_pg_type_oid(Archive *fout, PQExpBuffer upgrade_query)
    5774              : {
    5775              :     /*
    5776              :      * If the old version didn't assign an array type, but the new version
    5777              :      * does, we must select an unused type OID to assign.  This currently only
    5778              :      * happens for domains, when upgrading pre-v11 to v11 and up.
    5779              :      *
    5780              :      * Note: local state here is kind of ugly, but we must have some, since we
    5781              :      * mustn't choose the same unused OID more than once.
    5782              :      */
    5783              :     static Oid  next_possible_free_oid = FirstNormalObjectId;
    5784              :     PGresult   *res;
    5785              :     bool        is_dup;
    5786              : 
    5787              :     do
    5788              :     {
    5789            0 :         ++next_possible_free_oid;
    5790            0 :         printfPQExpBuffer(upgrade_query,
    5791              :                           "SELECT EXISTS(SELECT 1 "
    5792              :                           "FROM pg_catalog.pg_type "
    5793              :                           "WHERE oid = '%u'::pg_catalog.oid);",
    5794              :                           next_possible_free_oid);
    5795            0 :         res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data);
    5796            0 :         is_dup = (PQgetvalue(res, 0, 0)[0] == 't');
    5797            0 :         PQclear(res);
    5798            0 :     } while (is_dup);
    5799              : 
    5800            0 :     return next_possible_free_oid;
    5801              : }
    5802              : 
    5803              : static void
    5804         1028 : binary_upgrade_set_type_oids_by_type_oid(Archive *fout,
    5805              :                                          PQExpBuffer upgrade_buffer,
    5806              :                                          Oid pg_type_oid,
    5807              :                                          bool force_array_type,
    5808              :                                          bool include_multirange_type)
    5809              : {
    5810         1028 :     PQExpBuffer upgrade_query = createPQExpBuffer();
    5811              :     PGresult   *res;
    5812              :     Oid         pg_type_array_oid;
    5813              :     Oid         pg_type_multirange_oid;
    5814              :     Oid         pg_type_multirange_array_oid;
    5815              :     TypeInfo   *tinfo;
    5816              : 
    5817         1028 :     appendPQExpBufferStr(upgrade_buffer, "\n-- For binary upgrade, must preserve pg_type oid\n");
    5818         1028 :     appendPQExpBuffer(upgrade_buffer,
    5819              :                       "SELECT pg_catalog.binary_upgrade_set_next_pg_type_oid('%u'::pg_catalog.oid);\n\n",
    5820              :                       pg_type_oid);
    5821              : 
    5822         1028 :     tinfo = findTypeByOid(pg_type_oid);
    5823         1028 :     if (tinfo)
    5824         1028 :         pg_type_array_oid = tinfo->typarray;
    5825              :     else
    5826            0 :         pg_type_array_oid = InvalidOid;
    5827              : 
    5828         1028 :     if (!OidIsValid(pg_type_array_oid) && force_array_type)
    5829            0 :         pg_type_array_oid = get_next_possible_free_pg_type_oid(fout, upgrade_query);
    5830              : 
    5831         1028 :     if (OidIsValid(pg_type_array_oid))
    5832              :     {
    5833         1026 :         appendPQExpBufferStr(upgrade_buffer,
    5834              :                              "\n-- For binary upgrade, must preserve pg_type array oid\n");
    5835         1026 :         appendPQExpBuffer(upgrade_buffer,
    5836              :                           "SELECT pg_catalog.binary_upgrade_set_next_array_pg_type_oid('%u'::pg_catalog.oid);\n\n",
    5837              :                           pg_type_array_oid);
    5838              :     }
    5839              : 
    5840              :     /*
    5841              :      * Pre-set the multirange type oid and its own array type oid.
    5842              :      */
    5843         1028 :     if (include_multirange_type)
    5844              :     {
    5845            9 :         if (fout->remoteVersion >= 140000)
    5846              :         {
    5847            9 :             printfPQExpBuffer(upgrade_query,
    5848              :                               "SELECT t.oid, t.typarray "
    5849              :                               "FROM pg_catalog.pg_type t "
    5850              :                               "JOIN pg_catalog.pg_range r "
    5851              :                               "ON t.oid = r.rngmultitypid "
    5852              :                               "WHERE r.rngtypid = '%u'::pg_catalog.oid;",
    5853              :                               pg_type_oid);
    5854              : 
    5855            9 :             res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data);
    5856              : 
    5857            9 :             pg_type_multirange_oid = atooid(PQgetvalue(res, 0, PQfnumber(res, "oid")));
    5858            9 :             pg_type_multirange_array_oid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typarray")));
    5859              : 
    5860            9 :             PQclear(res);
    5861              :         }
    5862              :         else
    5863              :         {
    5864            0 :             pg_type_multirange_oid = get_next_possible_free_pg_type_oid(fout, upgrade_query);
    5865            0 :             pg_type_multirange_array_oid = get_next_possible_free_pg_type_oid(fout, upgrade_query);
    5866              :         }
    5867              : 
    5868            9 :         appendPQExpBufferStr(upgrade_buffer,
    5869              :                              "\n-- For binary upgrade, must preserve multirange pg_type oid\n");
    5870            9 :         appendPQExpBuffer(upgrade_buffer,
    5871              :                           "SELECT pg_catalog.binary_upgrade_set_next_multirange_pg_type_oid('%u'::pg_catalog.oid);\n\n",
    5872              :                           pg_type_multirange_oid);
    5873            9 :         appendPQExpBufferStr(upgrade_buffer,
    5874              :                              "\n-- For binary upgrade, must preserve multirange pg_type array oid\n");
    5875            9 :         appendPQExpBuffer(upgrade_buffer,
    5876              :                           "SELECT pg_catalog.binary_upgrade_set_next_multirange_array_pg_type_oid('%u'::pg_catalog.oid);\n\n",
    5877              :                           pg_type_multirange_array_oid);
    5878              :     }
    5879              : 
    5880         1028 :     destroyPQExpBuffer(upgrade_query);
    5881         1028 : }
    5882              : 
    5883              : static void
    5884          948 : binary_upgrade_set_type_oids_by_rel(Archive *fout,
    5885              :                                     PQExpBuffer upgrade_buffer,
    5886              :                                     const TableInfo *tbinfo)
    5887              : {
    5888          948 :     Oid         pg_type_oid = tbinfo->reltype;
    5889              : 
    5890          948 :     if (OidIsValid(pg_type_oid))
    5891          948 :         binary_upgrade_set_type_oids_by_type_oid(fout, upgrade_buffer,
    5892              :                                                  pg_type_oid, false, false);
    5893          948 : }
    5894              : 
    5895              : /*
    5896              :  * bsearch() comparator for BinaryUpgradeClassOidItem
    5897              :  */
    5898              : static int
    5899        13668 : BinaryUpgradeClassOidItemCmp(const void *p1, const void *p2)
    5900              : {
    5901        13668 :     BinaryUpgradeClassOidItem v1 = *((const BinaryUpgradeClassOidItem *) p1);
    5902        13668 :     BinaryUpgradeClassOidItem v2 = *((const BinaryUpgradeClassOidItem *) p2);
    5903              : 
    5904        13668 :     return pg_cmp_u32(v1.oid, v2.oid);
    5905              : }
    5906              : 
    5907              : /*
    5908              :  * collectBinaryUpgradeClassOids
    5909              :  *
    5910              :  * Construct a table of pg_class information required for
    5911              :  * binary_upgrade_set_pg_class_oids().  The table is sorted by OID for speed in
    5912              :  * lookup.
    5913              :  */
    5914              : static void
    5915           40 : collectBinaryUpgradeClassOids(Archive *fout)
    5916              : {
    5917              :     PGresult   *res;
    5918              :     const char *query;
    5919              : 
    5920           40 :     query = "SELECT c.oid, c.relkind, c.relfilenode, c.reltoastrelid, "
    5921              :         "ct.relfilenode, i.indexrelid, cti.relfilenode "
    5922              :         "FROM pg_catalog.pg_class c LEFT JOIN pg_catalog.pg_index i "
    5923              :         "ON (c.reltoastrelid = i.indrelid AND i.indisvalid) "
    5924              :         "LEFT JOIN pg_catalog.pg_class ct ON (c.reltoastrelid = ct.oid) "
    5925              :         "LEFT JOIN pg_catalog.pg_class AS cti ON (i.indexrelid = cti.oid) "
    5926              :         "ORDER BY c.oid;";
    5927              : 
    5928           40 :     res = ExecuteSqlQuery(fout, query, PGRES_TUPLES_OK);
    5929              : 
    5930           40 :     nbinaryUpgradeClassOids = PQntuples(res);
    5931           40 :     binaryUpgradeClassOids =
    5932           40 :         pg_malloc_array(BinaryUpgradeClassOidItem, nbinaryUpgradeClassOids);
    5933              : 
    5934        20077 :     for (int i = 0; i < nbinaryUpgradeClassOids; i++)
    5935              :     {
    5936        20037 :         binaryUpgradeClassOids[i].oid = atooid(PQgetvalue(res, i, 0));
    5937        20037 :         binaryUpgradeClassOids[i].relkind = *PQgetvalue(res, i, 1);
    5938        20037 :         binaryUpgradeClassOids[i].relfilenumber = atooid(PQgetvalue(res, i, 2));
    5939        20037 :         binaryUpgradeClassOids[i].toast_oid = atooid(PQgetvalue(res, i, 3));
    5940        20037 :         binaryUpgradeClassOids[i].toast_relfilenumber = atooid(PQgetvalue(res, i, 4));
    5941        20037 :         binaryUpgradeClassOids[i].toast_index_oid = atooid(PQgetvalue(res, i, 5));
    5942        20037 :         binaryUpgradeClassOids[i].toast_index_relfilenumber = atooid(PQgetvalue(res, i, 6));
    5943              :     }
    5944              : 
    5945           40 :     PQclear(res);
    5946           40 : }
    5947              : 
    5948              : static void
    5949         1367 : binary_upgrade_set_pg_class_oids(Archive *fout,
    5950              :                                  PQExpBuffer upgrade_buffer, Oid pg_class_oid)
    5951              : {
    5952         1367 :     BinaryUpgradeClassOidItem key = {0};
    5953              :     BinaryUpgradeClassOidItem *entry;
    5954              : 
    5955              :     Assert(binaryUpgradeClassOids);
    5956              : 
    5957              :     /*
    5958              :      * Preserve the OID and relfilenumber of the table, table's index, table's
    5959              :      * toast table and toast table's index if any.
    5960              :      *
    5961              :      * One complexity is that the current table definition might not require
    5962              :      * the creation of a TOAST table, but the old database might have a TOAST
    5963              :      * table that was created earlier, before some wide columns were dropped.
    5964              :      * By setting the TOAST oid we force creation of the TOAST heap and index
    5965              :      * by the new backend, so we can copy the files during binary upgrade
    5966              :      * without worrying about this case.
    5967              :      */
    5968         1367 :     key.oid = pg_class_oid;
    5969         1367 :     entry = bsearch(&key, binaryUpgradeClassOids, nbinaryUpgradeClassOids,
    5970              :                     sizeof(BinaryUpgradeClassOidItem),
    5971              :                     BinaryUpgradeClassOidItemCmp);
    5972              : 
    5973         1367 :     appendPQExpBufferStr(upgrade_buffer,
    5974              :                          "\n-- For binary upgrade, must preserve pg_class oids and relfilenodes\n");
    5975              : 
    5976         1367 :     if (entry->relkind != RELKIND_INDEX &&
    5977         1062 :         entry->relkind != RELKIND_PARTITIONED_INDEX)
    5978              :     {
    5979         1032 :         appendPQExpBuffer(upgrade_buffer,
    5980              :                           "SELECT pg_catalog.binary_upgrade_set_next_heap_pg_class_oid('%u'::pg_catalog.oid);\n",
    5981              :                           pg_class_oid);
    5982              : 
    5983              :         /*
    5984              :          * Not every relation has storage. Also, in a pre-v12 database,
    5985              :          * partitioned tables have a relfilenumber, which should not be
    5986              :          * preserved when upgrading.
    5987              :          */
    5988         1032 :         if (RelFileNumberIsValid(entry->relfilenumber) &&
    5989          846 :             entry->relkind != RELKIND_PARTITIONED_TABLE)
    5990          846 :             appendPQExpBuffer(upgrade_buffer,
    5991              :                               "SELECT pg_catalog.binary_upgrade_set_next_heap_relfilenode('%u'::pg_catalog.oid);\n",
    5992              :                               entry->relfilenumber);
    5993              : 
    5994              :         /*
    5995              :          * In a pre-v12 database, partitioned tables might be marked as having
    5996              :          * toast tables, but we should ignore them if so.
    5997              :          */
    5998         1032 :         if (OidIsValid(entry->toast_oid) &&
    5999          295 :             entry->relkind != RELKIND_PARTITIONED_TABLE)
    6000              :         {
    6001          295 :             appendPQExpBuffer(upgrade_buffer,
    6002              :                               "SELECT pg_catalog.binary_upgrade_set_next_toast_pg_class_oid('%u'::pg_catalog.oid);\n",
    6003              :                               entry->toast_oid);
    6004          295 :             appendPQExpBuffer(upgrade_buffer,
    6005              :                               "SELECT pg_catalog.binary_upgrade_set_next_toast_relfilenode('%u'::pg_catalog.oid);\n",
    6006              :                               entry->toast_relfilenumber);
    6007              : 
    6008              :             /* every toast table has an index */
    6009          295 :             appendPQExpBuffer(upgrade_buffer,
    6010              :                               "SELECT pg_catalog.binary_upgrade_set_next_index_pg_class_oid('%u'::pg_catalog.oid);\n",
    6011              :                               entry->toast_index_oid);
    6012          295 :             appendPQExpBuffer(upgrade_buffer,
    6013              :                               "SELECT pg_catalog.binary_upgrade_set_next_index_relfilenode('%u'::pg_catalog.oid);\n",
    6014              :                               entry->toast_index_relfilenumber);
    6015              :         }
    6016              :     }
    6017              :     else
    6018              :     {
    6019              :         /* Preserve the OID and relfilenumber of the index */
    6020          335 :         appendPQExpBuffer(upgrade_buffer,
    6021              :                           "SELECT pg_catalog.binary_upgrade_set_next_index_pg_class_oid('%u'::pg_catalog.oid);\n",
    6022              :                           pg_class_oid);
    6023          335 :         appendPQExpBuffer(upgrade_buffer,
    6024              :                           "SELECT pg_catalog.binary_upgrade_set_next_index_relfilenode('%u'::pg_catalog.oid);\n",
    6025              :                           entry->relfilenumber);
    6026              :     }
    6027              : 
    6028         1367 :     appendPQExpBufferChar(upgrade_buffer, '\n');
    6029         1367 : }
    6030              : 
    6031              : /*
    6032              :  * If the DumpableObject is a member of an extension, add a suitable
    6033              :  * ALTER EXTENSION ADD command to the creation commands in upgrade_buffer.
    6034              :  *
    6035              :  * For somewhat historical reasons, objname should already be quoted,
    6036              :  * but not objnamespace (if any).
    6037              :  */
    6038              : static void
    6039         1616 : binary_upgrade_extension_member(PQExpBuffer upgrade_buffer,
    6040              :                                 const DumpableObject *dobj,
    6041              :                                 const char *objtype,
    6042              :                                 const char *objname,
    6043              :                                 const char *objnamespace)
    6044              : {
    6045         1616 :     DumpableObject *extobj = NULL;
    6046              :     int         i;
    6047              : 
    6048         1616 :     if (!dobj->ext_member)
    6049         1594 :         return;
    6050              : 
    6051              :     /*
    6052              :      * Find the parent extension.  We could avoid this search if we wanted to
    6053              :      * add a link field to DumpableObject, but the space costs of that would
    6054              :      * be considerable.  We assume that member objects could only have a
    6055              :      * direct dependency on their own extension, not any others.
    6056              :      */
    6057           22 :     for (i = 0; i < dobj->nDeps; i++)
    6058              :     {
    6059           22 :         extobj = findObjectByDumpId(dobj->dependencies[i]);
    6060           22 :         if (extobj && extobj->objType == DO_EXTENSION)
    6061           22 :             break;
    6062            0 :         extobj = NULL;
    6063              :     }
    6064           22 :     if (extobj == NULL)
    6065            0 :         pg_fatal("could not find parent extension for %s %s",
    6066              :                  objtype, objname);
    6067              : 
    6068           22 :     appendPQExpBufferStr(upgrade_buffer,
    6069              :                          "\n-- For binary upgrade, handle extension membership the hard way\n");
    6070           22 :     appendPQExpBuffer(upgrade_buffer, "ALTER EXTENSION %s ADD %s ",
    6071           22 :                       fmtId(extobj->name),
    6072              :                       objtype);
    6073           22 :     if (objnamespace && *objnamespace)
    6074           19 :         appendPQExpBuffer(upgrade_buffer, "%s.", fmtId(objnamespace));
    6075           22 :     appendPQExpBuffer(upgrade_buffer, "%s;\n", objname);
    6076              : }
    6077              : 
    6078              : /*
    6079              :  * getNamespaces:
    6080              :  *    get information about all namespaces in the system catalogs
    6081              :  */
    6082              : void
    6083          260 : getNamespaces(Archive *fout)
    6084              : {
    6085              :     PGresult   *res;
    6086              :     int         ntups;
    6087              :     int         i;
    6088              :     PQExpBuffer query;
    6089              :     NamespaceInfo *nsinfo;
    6090              :     int         i_tableoid;
    6091              :     int         i_oid;
    6092              :     int         i_nspname;
    6093              :     int         i_nspowner;
    6094              :     int         i_nspacl;
    6095              :     int         i_acldefault;
    6096              : 
    6097          260 :     query = createPQExpBuffer();
    6098              : 
    6099              :     /*
    6100              :      * we fetch all namespaces including system ones, so that every object we
    6101              :      * read in can be linked to a containing namespace.
    6102              :      */
    6103          260 :     appendPQExpBufferStr(query, "SELECT n.tableoid, n.oid, n.nspname, "
    6104              :                          "n.nspowner, "
    6105              :                          "n.nspacl, "
    6106              :                          "acldefault('n', n.nspowner) AS acldefault "
    6107              :                          "FROM pg_namespace n");
    6108              : 
    6109          260 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    6110              : 
    6111          260 :     ntups = PQntuples(res);
    6112              : 
    6113          260 :     nsinfo = pg_malloc_array(NamespaceInfo, ntups);
    6114              : 
    6115          260 :     i_tableoid = PQfnumber(res, "tableoid");
    6116          260 :     i_oid = PQfnumber(res, "oid");
    6117          260 :     i_nspname = PQfnumber(res, "nspname");
    6118          260 :     i_nspowner = PQfnumber(res, "nspowner");
    6119          260 :     i_nspacl = PQfnumber(res, "nspacl");
    6120          260 :     i_acldefault = PQfnumber(res, "acldefault");
    6121              : 
    6122         2031 :     for (i = 0; i < ntups; i++)
    6123              :     {
    6124              :         const char *nspowner;
    6125              : 
    6126         1771 :         nsinfo[i].dobj.objType = DO_NAMESPACE;
    6127         1771 :         nsinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    6128         1771 :         nsinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    6129         1771 :         AssignDumpId(&nsinfo[i].dobj);
    6130         1771 :         nsinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_nspname));
    6131         1771 :         nsinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_nspacl));
    6132         1771 :         nsinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
    6133         1771 :         nsinfo[i].dacl.privtype = 0;
    6134         1771 :         nsinfo[i].dacl.initprivs = NULL;
    6135         1771 :         nspowner = PQgetvalue(res, i, i_nspowner);
    6136         1771 :         nsinfo[i].nspowner = atooid(nspowner);
    6137         1771 :         nsinfo[i].rolname = getRoleName(nspowner);
    6138              : 
    6139              :         /* Decide whether to dump this namespace */
    6140         1771 :         selectDumpableNamespace(&nsinfo[i], fout);
    6141              : 
    6142              :         /* Mark whether namespace has an ACL */
    6143         1771 :         if (!PQgetisnull(res, i, i_nspacl))
    6144          879 :             nsinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
    6145              : 
    6146              :         /*
    6147              :          * We ignore any pg_init_privs.initprivs entry for the public schema
    6148              :          * and assume a predetermined default, for several reasons.  First,
    6149              :          * dropping and recreating the schema removes its pg_init_privs entry,
    6150              :          * but an empty destination database starts with this ACL nonetheless.
    6151              :          * Second, we support dump/reload of public schema ownership changes.
    6152              :          * ALTER SCHEMA OWNER filters nspacl through aclnewowner(), but
    6153              :          * initprivs continues to reflect the initial owner.  Hence,
    6154              :          * synthesize the value that nspacl will have after the restore's
    6155              :          * ALTER SCHEMA OWNER.  Third, this makes the destination database
    6156              :          * match the source's ACL, even if the latter was an initdb-default
    6157              :          * ACL, which changed in v15.  An upgrade pulls in changes to most
    6158              :          * system object ACLs that the DBA had not customized.  We've made the
    6159              :          * public schema depart from that, because changing its ACL so easily
    6160              :          * breaks applications.
    6161              :          */
    6162         1771 :         if (strcmp(nsinfo[i].dobj.name, "public") == 0)
    6163              :         {
    6164          256 :             PQExpBuffer aclarray = createPQExpBuffer();
    6165          256 :             PQExpBuffer aclitem = createPQExpBuffer();
    6166              : 
    6167              :             /* Standard ACL as of v15 is {owner=UC/owner,=U/owner} */
    6168          256 :             appendPQExpBufferChar(aclarray, '{');
    6169          256 :             quoteAclUserName(aclitem, nsinfo[i].rolname);
    6170          256 :             appendPQExpBufferStr(aclitem, "=UC/");
    6171          256 :             quoteAclUserName(aclitem, nsinfo[i].rolname);
    6172          256 :             appendPGArray(aclarray, aclitem->data);
    6173          256 :             resetPQExpBuffer(aclitem);
    6174          256 :             appendPQExpBufferStr(aclitem, "=U/");
    6175          256 :             quoteAclUserName(aclitem, nsinfo[i].rolname);
    6176          256 :             appendPGArray(aclarray, aclitem->data);
    6177          256 :             appendPQExpBufferChar(aclarray, '}');
    6178              : 
    6179          256 :             nsinfo[i].dacl.privtype = 'i';
    6180          256 :             nsinfo[i].dacl.initprivs = pstrdup(aclarray->data);
    6181          256 :             nsinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
    6182              : 
    6183          256 :             destroyPQExpBuffer(aclarray);
    6184          256 :             destroyPQExpBuffer(aclitem);
    6185              :         }
    6186              :     }
    6187              : 
    6188          260 :     PQclear(res);
    6189          260 :     destroyPQExpBuffer(query);
    6190          260 : }
    6191              : 
    6192              : /*
    6193              :  * findNamespace:
    6194              :  *      given a namespace OID, look up the info read by getNamespaces
    6195              :  */
    6196              : static NamespaceInfo *
    6197       836092 : findNamespace(Oid nsoid)
    6198              : {
    6199              :     NamespaceInfo *nsinfo;
    6200              : 
    6201       836092 :     nsinfo = findNamespaceByOid(nsoid);
    6202       836092 :     if (nsinfo == NULL)
    6203            0 :         pg_fatal("schema with OID %u does not exist", nsoid);
    6204       836092 :     return nsinfo;
    6205              : }
    6206              : 
    6207              : /*
    6208              :  * getExtensions:
    6209              :  *    read all extensions in the system catalogs and return them in the
    6210              :  * ExtensionInfo* structure
    6211              :  *
    6212              :  *  numExtensions is set to the number of extensions read in
    6213              :  */
    6214              : ExtensionInfo *
    6215          260 : getExtensions(Archive *fout, int *numExtensions)
    6216              : {
    6217          260 :     DumpOptions *dopt = fout->dopt;
    6218              :     PGresult   *res;
    6219              :     int         ntups;
    6220              :     int         i;
    6221              :     PQExpBuffer query;
    6222          260 :     ExtensionInfo *extinfo = NULL;
    6223              :     int         i_tableoid;
    6224              :     int         i_oid;
    6225              :     int         i_extname;
    6226              :     int         i_nspname;
    6227              :     int         i_extrelocatable;
    6228              :     int         i_extversion;
    6229              :     int         i_extconfig;
    6230              :     int         i_extcondition;
    6231              : 
    6232          260 :     query = createPQExpBuffer();
    6233              : 
    6234          260 :     appendPQExpBufferStr(query, "SELECT x.tableoid, x.oid, "
    6235              :                          "x.extname, n.nspname, x.extrelocatable, x.extversion, x.extconfig, x.extcondition "
    6236              :                          "FROM pg_extension x "
    6237              :                          "JOIN pg_namespace n ON n.oid = x.extnamespace");
    6238              : 
    6239          260 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    6240              : 
    6241          260 :     ntups = PQntuples(res);
    6242          260 :     if (ntups == 0)
    6243            0 :         goto cleanup;
    6244              : 
    6245          260 :     extinfo = pg_malloc_array(ExtensionInfo, ntups);
    6246              : 
    6247          260 :     i_tableoid = PQfnumber(res, "tableoid");
    6248          260 :     i_oid = PQfnumber(res, "oid");
    6249          260 :     i_extname = PQfnumber(res, "extname");
    6250          260 :     i_nspname = PQfnumber(res, "nspname");
    6251          260 :     i_extrelocatable = PQfnumber(res, "extrelocatable");
    6252          260 :     i_extversion = PQfnumber(res, "extversion");
    6253          260 :     i_extconfig = PQfnumber(res, "extconfig");
    6254          260 :     i_extcondition = PQfnumber(res, "extcondition");
    6255              : 
    6256          551 :     for (i = 0; i < ntups; i++)
    6257              :     {
    6258          291 :         extinfo[i].dobj.objType = DO_EXTENSION;
    6259          291 :         extinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    6260          291 :         extinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    6261          291 :         AssignDumpId(&extinfo[i].dobj);
    6262          291 :         extinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_extname));
    6263          291 :         extinfo[i].namespace = pg_strdup(PQgetvalue(res, i, i_nspname));
    6264          291 :         extinfo[i].relocatable = *(PQgetvalue(res, i, i_extrelocatable)) == 't';
    6265          291 :         extinfo[i].extversion = pg_strdup(PQgetvalue(res, i, i_extversion));
    6266          291 :         extinfo[i].extconfig = pg_strdup(PQgetvalue(res, i, i_extconfig));
    6267          291 :         extinfo[i].extcondition = pg_strdup(PQgetvalue(res, i, i_extcondition));
    6268              : 
    6269              :         /* Decide whether we want to dump it */
    6270          291 :         selectDumpableExtension(&(extinfo[i]), dopt);
    6271              :     }
    6272              : 
    6273          260 : cleanup:
    6274          260 :     PQclear(res);
    6275          260 :     destroyPQExpBuffer(query);
    6276              : 
    6277          260 :     *numExtensions = ntups;
    6278              : 
    6279          260 :     return extinfo;
    6280              : }
    6281              : 
    6282              : /*
    6283              :  * getTypes:
    6284              :  *    get information about all types in the system catalogs
    6285              :  *
    6286              :  * NB: this must run after getFuncs() because we assume we can do
    6287              :  * findFuncByOid().
    6288              :  */
    6289              : void
    6290          259 : getTypes(Archive *fout)
    6291              : {
    6292              :     PGresult   *res;
    6293              :     int         ntups;
    6294              :     int         i;
    6295          259 :     PQExpBuffer query = createPQExpBuffer();
    6296              :     TypeInfo   *tyinfo;
    6297              :     ShellTypeInfo *stinfo;
    6298              :     int         i_tableoid;
    6299              :     int         i_oid;
    6300              :     int         i_typname;
    6301              :     int         i_typnamespace;
    6302              :     int         i_typacl;
    6303              :     int         i_acldefault;
    6304              :     int         i_typowner;
    6305              :     int         i_typelem;
    6306              :     int         i_typrelid;
    6307              :     int         i_typrelkind;
    6308              :     int         i_typtype;
    6309              :     int         i_typisdefined;
    6310              :     int         i_isarray;
    6311              :     int         i_typarray;
    6312              : 
    6313              :     /*
    6314              :      * we include even the built-in types because those may be used as array
    6315              :      * elements by user-defined types
    6316              :      *
    6317              :      * we filter out the built-in types when we dump out the types
    6318              :      *
    6319              :      * same approach for undefined (shell) types and array types
    6320              :      *
    6321              :      * Note: as of 8.3 we can reliably detect whether a type is an
    6322              :      * auto-generated array type by checking the element type's typarray.
    6323              :      * (Before that the test is capable of generating false positives.) We
    6324              :      * still check for name beginning with '_', though, so as to avoid the
    6325              :      * cost of the subselect probe for all standard types.  This would have to
    6326              :      * be revisited if the backend ever allows renaming of array types.
    6327              :      */
    6328          259 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, typname, "
    6329              :                          "typnamespace, typacl, "
    6330              :                          "acldefault('T', typowner) AS acldefault, "
    6331              :                          "typowner, "
    6332              :                          "typelem, typrelid, typarray, "
    6333              :                          "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
    6334              :                          "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
    6335              :                          "typtype, typisdefined, "
    6336              :                          "typname[0] = '_' AND typelem != 0 AND "
    6337              :                          "(SELECT typarray FROM pg_type te WHERE oid = pg_type.typelem) = oid AS isarray "
    6338              :                          "FROM pg_type");
    6339              : 
    6340          259 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    6341              : 
    6342          259 :     ntups = PQntuples(res);
    6343              : 
    6344          259 :     tyinfo = pg_malloc_array(TypeInfo, ntups);
    6345              : 
    6346          259 :     i_tableoid = PQfnumber(res, "tableoid");
    6347          259 :     i_oid = PQfnumber(res, "oid");
    6348          259 :     i_typname = PQfnumber(res, "typname");
    6349          259 :     i_typnamespace = PQfnumber(res, "typnamespace");
    6350          259 :     i_typacl = PQfnumber(res, "typacl");
    6351          259 :     i_acldefault = PQfnumber(res, "acldefault");
    6352          259 :     i_typowner = PQfnumber(res, "typowner");
    6353          259 :     i_typelem = PQfnumber(res, "typelem");
    6354          259 :     i_typrelid = PQfnumber(res, "typrelid");
    6355          259 :     i_typrelkind = PQfnumber(res, "typrelkind");
    6356          259 :     i_typtype = PQfnumber(res, "typtype");
    6357          259 :     i_typisdefined = PQfnumber(res, "typisdefined");
    6358          259 :     i_isarray = PQfnumber(res, "isarray");
    6359          259 :     i_typarray = PQfnumber(res, "typarray");
    6360              : 
    6361       193478 :     for (i = 0; i < ntups; i++)
    6362              :     {
    6363       193219 :         tyinfo[i].dobj.objType = DO_TYPE;
    6364       193219 :         tyinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    6365       193219 :         tyinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    6366       193219 :         AssignDumpId(&tyinfo[i].dobj);
    6367       193219 :         tyinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_typname));
    6368       386438 :         tyinfo[i].dobj.namespace =
    6369       193219 :             findNamespace(atooid(PQgetvalue(res, i, i_typnamespace)));
    6370       193219 :         tyinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_typacl));
    6371       193219 :         tyinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
    6372       193219 :         tyinfo[i].dacl.privtype = 0;
    6373       193219 :         tyinfo[i].dacl.initprivs = NULL;
    6374       193219 :         tyinfo[i].ftypname = NULL;  /* may get filled later */
    6375       193219 :         tyinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_typowner));
    6376       193219 :         tyinfo[i].typelem = atooid(PQgetvalue(res, i, i_typelem));
    6377       193219 :         tyinfo[i].typrelid = atooid(PQgetvalue(res, i, i_typrelid));
    6378       193219 :         tyinfo[i].typrelkind = *PQgetvalue(res, i, i_typrelkind);
    6379       193219 :         tyinfo[i].typtype = *PQgetvalue(res, i, i_typtype);
    6380       193219 :         tyinfo[i].shellType = NULL;
    6381              : 
    6382       193219 :         if (strcmp(PQgetvalue(res, i, i_typisdefined), "t") == 0)
    6383       193167 :             tyinfo[i].isDefined = true;
    6384              :         else
    6385           52 :             tyinfo[i].isDefined = false;
    6386              : 
    6387       193219 :         if (strcmp(PQgetvalue(res, i, i_isarray), "t") == 0)
    6388        92828 :             tyinfo[i].isArray = true;
    6389              :         else
    6390       100391 :             tyinfo[i].isArray = false;
    6391              : 
    6392       193219 :         tyinfo[i].typarray = atooid(PQgetvalue(res, i, i_typarray));
    6393              : 
    6394       193219 :         if (tyinfo[i].typtype == TYPTYPE_MULTIRANGE)
    6395         1693 :             tyinfo[i].isMultirange = true;
    6396              :         else
    6397       191526 :             tyinfo[i].isMultirange = false;
    6398              : 
    6399              :         /* Decide whether we want to dump it */
    6400       193219 :         selectDumpableType(&tyinfo[i], fout);
    6401              : 
    6402              :         /* Mark whether type has an ACL */
    6403       193219 :         if (!PQgetisnull(res, i, i_typacl))
    6404          205 :             tyinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
    6405              : 
    6406              :         /*
    6407              :          * If it's a domain, fetch info about its constraints, if any
    6408              :          */
    6409       193219 :         tyinfo[i].nDomChecks = 0;
    6410       193219 :         tyinfo[i].domChecks = NULL;
    6411       193219 :         tyinfo[i].notnull = NULL;
    6412       193219 :         if ((tyinfo[i].dobj.dump & DUMP_COMPONENT_DEFINITION) &&
    6413        16423 :             tyinfo[i].typtype == TYPTYPE_DOMAIN)
    6414          178 :             getDomainConstraints(fout, &(tyinfo[i]));
    6415              : 
    6416              :         /*
    6417              :          * If it's a base type, make a DumpableObject representing a shell
    6418              :          * definition of the type.  We will need to dump that ahead of the I/O
    6419              :          * functions for the type.  Similarly, range types need a shell
    6420              :          * definition in case they have a canonicalize function.
    6421              :          *
    6422              :          * Note: the shell type doesn't have a catId.  You might think it
    6423              :          * should copy the base type's catId, but then it might capture the
    6424              :          * pg_depend entries for the type, which we don't want.
    6425              :          */
    6426       193219 :         if ((tyinfo[i].dobj.dump & DUMP_COMPONENT_DEFINITION) &&
    6427        16423 :             (tyinfo[i].typtype == TYPTYPE_BASE ||
    6428         7995 :              tyinfo[i].typtype == TYPTYPE_RANGE))
    6429              :         {
    6430         8557 :             stinfo = pg_malloc_object(ShellTypeInfo);
    6431         8557 :             stinfo->dobj.objType = DO_SHELL_TYPE;
    6432         8557 :             stinfo->dobj.catId = nilCatalogId;
    6433         8557 :             AssignDumpId(&stinfo->dobj);
    6434         8557 :             stinfo->dobj.name = pg_strdup(tyinfo[i].dobj.name);
    6435         8557 :             stinfo->dobj.namespace = tyinfo[i].dobj.namespace;
    6436         8557 :             stinfo->baseType = &(tyinfo[i]);
    6437         8557 :             tyinfo[i].shellType = stinfo;
    6438              : 
    6439              :             /*
    6440              :              * Initially mark the shell type as not to be dumped.  We'll only
    6441              :              * dump it if the I/O or canonicalize functions need to be dumped;
    6442              :              * this is taken care of while sorting dependencies.
    6443              :              */
    6444         8557 :             stinfo->dobj.dump = DUMP_COMPONENT_NONE;
    6445              :         }
    6446              :     }
    6447              : 
    6448          259 :     PQclear(res);
    6449              : 
    6450          259 :     destroyPQExpBuffer(query);
    6451          259 : }
    6452              : 
    6453              : /*
    6454              :  * getOperators:
    6455              :  *    get information about all operators in the system catalogs
    6456              :  */
    6457              : void
    6458          259 : getOperators(Archive *fout)
    6459              : {
    6460              :     PGresult   *res;
    6461              :     int         ntups;
    6462              :     int         i;
    6463          259 :     PQExpBuffer query = createPQExpBuffer();
    6464              :     OprInfo    *oprinfo;
    6465              :     int         i_tableoid;
    6466              :     int         i_oid;
    6467              :     int         i_oprname;
    6468              :     int         i_oprnamespace;
    6469              :     int         i_oprowner;
    6470              :     int         i_oprkind;
    6471              :     int         i_oprleft;
    6472              :     int         i_oprright;
    6473              :     int         i_oprcode;
    6474              : 
    6475              :     /*
    6476              :      * find all operators, including builtin operators; we filter out
    6477              :      * system-defined operators at dump-out time.
    6478              :      */
    6479              : 
    6480          259 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, oprname, "
    6481              :                          "oprnamespace, "
    6482              :                          "oprowner, "
    6483              :                          "oprkind, "
    6484              :                          "oprleft, "
    6485              :                          "oprright, "
    6486              :                          "oprcode::oid AS oprcode "
    6487              :                          "FROM pg_operator");
    6488              : 
    6489          259 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    6490              : 
    6491          259 :     ntups = PQntuples(res);
    6492              : 
    6493          259 :     oprinfo = pg_malloc_array(OprInfo, ntups);
    6494              : 
    6495          259 :     i_tableoid = PQfnumber(res, "tableoid");
    6496          259 :     i_oid = PQfnumber(res, "oid");
    6497          259 :     i_oprname = PQfnumber(res, "oprname");
    6498          259 :     i_oprnamespace = PQfnumber(res, "oprnamespace");
    6499          259 :     i_oprowner = PQfnumber(res, "oprowner");
    6500          259 :     i_oprkind = PQfnumber(res, "oprkind");
    6501          259 :     i_oprleft = PQfnumber(res, "oprleft");
    6502          259 :     i_oprright = PQfnumber(res, "oprright");
    6503          259 :     i_oprcode = PQfnumber(res, "oprcode");
    6504              : 
    6505       208896 :     for (i = 0; i < ntups; i++)
    6506              :     {
    6507       208637 :         oprinfo[i].dobj.objType = DO_OPERATOR;
    6508       208637 :         oprinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    6509       208637 :         oprinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    6510       208637 :         AssignDumpId(&oprinfo[i].dobj);
    6511       208637 :         oprinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_oprname));
    6512       417274 :         oprinfo[i].dobj.namespace =
    6513       208637 :             findNamespace(atooid(PQgetvalue(res, i, i_oprnamespace)));
    6514       208637 :         oprinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_oprowner));
    6515       208637 :         oprinfo[i].oprkind = (PQgetvalue(res, i, i_oprkind))[0];
    6516       208637 :         oprinfo[i].oprleft = atooid(PQgetvalue(res, i, i_oprleft));
    6517       208637 :         oprinfo[i].oprright = atooid(PQgetvalue(res, i, i_oprright));
    6518       208637 :         oprinfo[i].oprcode = atooid(PQgetvalue(res, i, i_oprcode));
    6519              : 
    6520              :         /* Decide whether we want to dump it */
    6521       208637 :         selectDumpableObject(&(oprinfo[i].dobj), fout);
    6522              :     }
    6523              : 
    6524          259 :     PQclear(res);
    6525              : 
    6526          259 :     destroyPQExpBuffer(query);
    6527          259 : }
    6528              : 
    6529              : /*
    6530              :  * getCollations:
    6531              :  *    get information about all collations in the system catalogs
    6532              :  */
    6533              : void
    6534          259 : getCollations(Archive *fout)
    6535              : {
    6536              :     PGresult   *res;
    6537              :     int         ntups;
    6538              :     int         i;
    6539              :     PQExpBuffer query;
    6540              :     CollInfo   *collinfo;
    6541              :     int         i_tableoid;
    6542              :     int         i_oid;
    6543              :     int         i_collname;
    6544              :     int         i_collnamespace;
    6545              :     int         i_collowner;
    6546              :     int         i_collencoding;
    6547              : 
    6548          259 :     query = createPQExpBuffer();
    6549              : 
    6550              :     /*
    6551              :      * find all collations, including builtin collations; we filter out
    6552              :      * system-defined collations at dump-out time.
    6553              :      */
    6554              : 
    6555          259 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, collname, "
    6556              :                          "collnamespace, "
    6557              :                          "collowner, "
    6558              :                          "collencoding "
    6559              :                          "FROM pg_collation");
    6560              : 
    6561          259 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    6562              : 
    6563          259 :     ntups = PQntuples(res);
    6564              : 
    6565          259 :     collinfo = pg_malloc_array(CollInfo, ntups);
    6566              : 
    6567          259 :     i_tableoid = PQfnumber(res, "tableoid");
    6568          259 :     i_oid = PQfnumber(res, "oid");
    6569          259 :     i_collname = PQfnumber(res, "collname");
    6570          259 :     i_collnamespace = PQfnumber(res, "collnamespace");
    6571          259 :     i_collowner = PQfnumber(res, "collowner");
    6572          259 :     i_collencoding = PQfnumber(res, "collencoding");
    6573              : 
    6574       228290 :     for (i = 0; i < ntups; i++)
    6575              :     {
    6576       228031 :         collinfo[i].dobj.objType = DO_COLLATION;
    6577       228031 :         collinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    6578       228031 :         collinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    6579       228031 :         AssignDumpId(&collinfo[i].dobj);
    6580       228031 :         collinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_collname));
    6581       456062 :         collinfo[i].dobj.namespace =
    6582       228031 :             findNamespace(atooid(PQgetvalue(res, i, i_collnamespace)));
    6583       228031 :         collinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_collowner));
    6584       228031 :         collinfo[i].collencoding = atoi(PQgetvalue(res, i, i_collencoding));
    6585              : 
    6586              :         /* Decide whether we want to dump it */
    6587       228031 :         selectDumpableObject(&(collinfo[i].dobj), fout);
    6588              :     }
    6589              : 
    6590          259 :     PQclear(res);
    6591              : 
    6592          259 :     destroyPQExpBuffer(query);
    6593          259 : }
    6594              : 
    6595              : /*
    6596              :  * getConversions:
    6597              :  *    get information about all conversions in the system catalogs
    6598              :  */
    6599              : void
    6600          259 : getConversions(Archive *fout)
    6601              : {
    6602              :     PGresult   *res;
    6603              :     int         ntups;
    6604              :     int         i;
    6605              :     PQExpBuffer query;
    6606              :     ConvInfo   *convinfo;
    6607              :     int         i_tableoid;
    6608              :     int         i_oid;
    6609              :     int         i_conname;
    6610              :     int         i_connamespace;
    6611              :     int         i_conowner;
    6612              : 
    6613          259 :     query = createPQExpBuffer();
    6614              : 
    6615              :     /*
    6616              :      * find all conversions, including builtin conversions; we filter out
    6617              :      * system-defined conversions at dump-out time.
    6618              :      */
    6619              : 
    6620          259 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, conname, "
    6621              :                          "connamespace, "
    6622              :                          "conowner "
    6623              :                          "FROM pg_conversion");
    6624              : 
    6625          259 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    6626              : 
    6627          259 :     ntups = PQntuples(res);
    6628              : 
    6629          259 :     convinfo = pg_malloc_array(ConvInfo, ntups);
    6630              : 
    6631          259 :     i_tableoid = PQfnumber(res, "tableoid");
    6632          259 :     i_oid = PQfnumber(res, "oid");
    6633          259 :     i_conname = PQfnumber(res, "conname");
    6634          259 :     i_connamespace = PQfnumber(res, "connamespace");
    6635          259 :     i_conowner = PQfnumber(res, "conowner");
    6636              : 
    6637        25686 :     for (i = 0; i < ntups; i++)
    6638              :     {
    6639        25427 :         convinfo[i].dobj.objType = DO_CONVERSION;
    6640        25427 :         convinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    6641        25427 :         convinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    6642        25427 :         AssignDumpId(&convinfo[i].dobj);
    6643        25427 :         convinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_conname));
    6644        50854 :         convinfo[i].dobj.namespace =
    6645        25427 :             findNamespace(atooid(PQgetvalue(res, i, i_connamespace)));
    6646        25427 :         convinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_conowner));
    6647              : 
    6648              :         /* Decide whether we want to dump it */
    6649        25427 :         selectDumpableObject(&(convinfo[i].dobj), fout);
    6650              :     }
    6651              : 
    6652          259 :     PQclear(res);
    6653              : 
    6654          259 :     destroyPQExpBuffer(query);
    6655          259 : }
    6656              : 
    6657              : /*
    6658              :  * getAccessMethods:
    6659              :  *    get information about all user-defined access methods
    6660              :  */
    6661              : void
    6662          259 : getAccessMethods(Archive *fout)
    6663              : {
    6664              :     PGresult   *res;
    6665              :     int         ntups;
    6666              :     int         i;
    6667              :     PQExpBuffer query;
    6668              :     AccessMethodInfo *aminfo;
    6669              :     int         i_tableoid;
    6670              :     int         i_oid;
    6671              :     int         i_amname;
    6672              :     int         i_amhandler;
    6673              :     int         i_amtype;
    6674              : 
    6675          259 :     query = createPQExpBuffer();
    6676              : 
    6677              :     /*
    6678              :      * Select all access methods from pg_am table.  v9.6 introduced CREATE
    6679              :      * ACCESS METHOD, so earlier versions usually have only built-in access
    6680              :      * methods.  v9.6 also changed the access method API, replacing dozens of
    6681              :      * pg_am columns with amhandler.  Even if a user created an access method
    6682              :      * by "INSERT INTO pg_am", we have no way to translate pre-v9.6 pg_am
    6683              :      * columns to a v9.6+ CREATE ACCESS METHOD.  Hence, before v9.6, read
    6684              :      * pg_am just to facilitate findAccessMethodByOid() providing the
    6685              :      * OID-to-name mapping.
    6686              :      */
    6687          259 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, amname, ");
    6688          259 :     if (fout->remoteVersion >= 90600)
    6689          259 :         appendPQExpBufferStr(query,
    6690              :                              "amtype, "
    6691              :                              "amhandler::pg_catalog.regproc AS amhandler ");
    6692              :     else
    6693            0 :         appendPQExpBufferStr(query,
    6694              :                              "'i'::pg_catalog.\"char\" AS amtype, "
    6695              :                              "'-'::pg_catalog.regproc AS amhandler ");
    6696          259 :     appendPQExpBufferStr(query, "FROM pg_am");
    6697              : 
    6698          259 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    6699              : 
    6700          259 :     ntups = PQntuples(res);
    6701              : 
    6702          259 :     aminfo = pg_malloc_array(AccessMethodInfo, ntups);
    6703              : 
    6704          259 :     i_tableoid = PQfnumber(res, "tableoid");
    6705          259 :     i_oid = PQfnumber(res, "oid");
    6706          259 :     i_amname = PQfnumber(res, "amname");
    6707          259 :     i_amhandler = PQfnumber(res, "amhandler");
    6708          259 :     i_amtype = PQfnumber(res, "amtype");
    6709              : 
    6710         2194 :     for (i = 0; i < ntups; i++)
    6711              :     {
    6712         1935 :         aminfo[i].dobj.objType = DO_ACCESS_METHOD;
    6713         1935 :         aminfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    6714         1935 :         aminfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    6715         1935 :         AssignDumpId(&aminfo[i].dobj);
    6716         1935 :         aminfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_amname));
    6717         1935 :         aminfo[i].dobj.namespace = NULL;
    6718         1935 :         aminfo[i].amhandler = pg_strdup(PQgetvalue(res, i, i_amhandler));
    6719         1935 :         aminfo[i].amtype = *(PQgetvalue(res, i, i_amtype));
    6720              : 
    6721              :         /* Decide whether we want to dump it */
    6722         1935 :         selectDumpableAccessMethod(&(aminfo[i]), fout);
    6723              :     }
    6724              : 
    6725          259 :     PQclear(res);
    6726              : 
    6727          259 :     destroyPQExpBuffer(query);
    6728          259 : }
    6729              : 
    6730              : 
    6731              : /*
    6732              :  * getOpclasses:
    6733              :  *    get information about all opclasses in the system catalogs
    6734              :  */
    6735              : void
    6736          259 : getOpclasses(Archive *fout)
    6737              : {
    6738              :     PGresult   *res;
    6739              :     int         ntups;
    6740              :     int         i;
    6741          259 :     PQExpBuffer query = createPQExpBuffer();
    6742              :     OpclassInfo *opcinfo;
    6743              :     int         i_tableoid;
    6744              :     int         i_oid;
    6745              :     int         i_opcmethod;
    6746              :     int         i_opcname;
    6747              :     int         i_opcnamespace;
    6748              :     int         i_opcowner;
    6749              : 
    6750              :     /*
    6751              :      * find all opclasses, including builtin opclasses; we filter out
    6752              :      * system-defined opclasses at dump-out time.
    6753              :      */
    6754              : 
    6755          259 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, opcmethod, opcname, "
    6756              :                          "opcnamespace, "
    6757              :                          "opcowner "
    6758              :                          "FROM pg_opclass");
    6759              : 
    6760          259 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    6761              : 
    6762          259 :     ntups = PQntuples(res);
    6763              : 
    6764          259 :     opcinfo = pg_malloc_array(OpclassInfo, ntups);
    6765              : 
    6766          259 :     i_tableoid = PQfnumber(res, "tableoid");
    6767          259 :     i_oid = PQfnumber(res, "oid");
    6768          259 :     i_opcmethod = PQfnumber(res, "opcmethod");
    6769          259 :     i_opcname = PQfnumber(res, "opcname");
    6770          259 :     i_opcnamespace = PQfnumber(res, "opcnamespace");
    6771          259 :     i_opcowner = PQfnumber(res, "opcowner");
    6772              : 
    6773        46776 :     for (i = 0; i < ntups; i++)
    6774              :     {
    6775        46517 :         opcinfo[i].dobj.objType = DO_OPCLASS;
    6776        46517 :         opcinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    6777        46517 :         opcinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    6778        46517 :         AssignDumpId(&opcinfo[i].dobj);
    6779        46517 :         opcinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_opcname));
    6780        93034 :         opcinfo[i].dobj.namespace =
    6781        46517 :             findNamespace(atooid(PQgetvalue(res, i, i_opcnamespace)));
    6782        46517 :         opcinfo[i].opcmethod = atooid(PQgetvalue(res, i, i_opcmethod));
    6783        46517 :         opcinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_opcowner));
    6784              : 
    6785              :         /* Decide whether we want to dump it */
    6786        46517 :         selectDumpableObject(&(opcinfo[i].dobj), fout);
    6787              :     }
    6788              : 
    6789          259 :     PQclear(res);
    6790              : 
    6791          259 :     destroyPQExpBuffer(query);
    6792          259 : }
    6793              : 
    6794              : /*
    6795              :  * getOpfamilies:
    6796              :  *    get information about all opfamilies in the system catalogs
    6797              :  */
    6798              : void
    6799          259 : getOpfamilies(Archive *fout)
    6800              : {
    6801              :     PGresult   *res;
    6802              :     int         ntups;
    6803              :     int         i;
    6804              :     PQExpBuffer query;
    6805              :     OpfamilyInfo *opfinfo;
    6806              :     int         i_tableoid;
    6807              :     int         i_oid;
    6808              :     int         i_opfmethod;
    6809              :     int         i_opfname;
    6810              :     int         i_opfnamespace;
    6811              :     int         i_opfowner;
    6812              : 
    6813          259 :     query = createPQExpBuffer();
    6814              : 
    6815              :     /*
    6816              :      * find all opfamilies, including builtin opfamilies; we filter out
    6817              :      * system-defined opfamilies at dump-out time.
    6818              :      */
    6819              : 
    6820          259 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, opfmethod, opfname, "
    6821              :                          "opfnamespace, "
    6822              :                          "opfowner "
    6823              :                          "FROM pg_opfamily");
    6824              : 
    6825          259 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    6826              : 
    6827          259 :     ntups = PQntuples(res);
    6828              : 
    6829          259 :     opfinfo = pg_malloc_array(OpfamilyInfo, ntups);
    6830              : 
    6831          259 :     i_tableoid = PQfnumber(res, "tableoid");
    6832          259 :     i_oid = PQfnumber(res, "oid");
    6833          259 :     i_opfname = PQfnumber(res, "opfname");
    6834          259 :     i_opfmethod = PQfnumber(res, "opfmethod");
    6835          259 :     i_opfnamespace = PQfnumber(res, "opfnamespace");
    6836          259 :     i_opfowner = PQfnumber(res, "opfowner");
    6837              : 
    6838        38730 :     for (i = 0; i < ntups; i++)
    6839              :     {
    6840        38471 :         opfinfo[i].dobj.objType = DO_OPFAMILY;
    6841        38471 :         opfinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    6842        38471 :         opfinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    6843        38471 :         AssignDumpId(&opfinfo[i].dobj);
    6844        38471 :         opfinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_opfname));
    6845        76942 :         opfinfo[i].dobj.namespace =
    6846        38471 :             findNamespace(atooid(PQgetvalue(res, i, i_opfnamespace)));
    6847        38471 :         opfinfo[i].opfmethod = atooid(PQgetvalue(res, i, i_opfmethod));
    6848        38471 :         opfinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_opfowner));
    6849              : 
    6850              :         /* Decide whether we want to dump it */
    6851        38471 :         selectDumpableObject(&(opfinfo[i].dobj), fout);
    6852              :     }
    6853              : 
    6854          259 :     PQclear(res);
    6855              : 
    6856          259 :     destroyPQExpBuffer(query);
    6857          259 : }
    6858              : 
    6859              : /*
    6860              :  * getAggregates:
    6861              :  *    get information about all user-defined aggregates in the system catalogs
    6862              :  */
    6863              : void
    6864          259 : getAggregates(Archive *fout)
    6865              : {
    6866          259 :     DumpOptions *dopt = fout->dopt;
    6867              :     PGresult   *res;
    6868              :     int         ntups;
    6869              :     int         i;
    6870          259 :     PQExpBuffer query = createPQExpBuffer();
    6871              :     AggInfo    *agginfo;
    6872              :     int         i_tableoid;
    6873              :     int         i_oid;
    6874              :     int         i_aggname;
    6875              :     int         i_aggnamespace;
    6876              :     int         i_pronargs;
    6877              :     int         i_proargtypes;
    6878              :     int         i_proowner;
    6879              :     int         i_aggacl;
    6880              :     int         i_acldefault;
    6881              : 
    6882              :     /*
    6883              :      * Find all interesting aggregates.  See comment in getFuncs() for the
    6884              :      * rationale behind the filtering logic.
    6885              :      */
    6886          259 :     if (fout->remoteVersion >= 90600)
    6887              :     {
    6888              :         const char *agg_check;
    6889              : 
    6890          518 :         agg_check = (fout->remoteVersion >= 110000 ? "p.prokind = 'a'"
    6891          259 :                      : "p.proisagg");
    6892              : 
    6893          259 :         appendPQExpBuffer(query, "SELECT p.tableoid, p.oid, "
    6894              :                           "p.proname AS aggname, "
    6895              :                           "p.pronamespace AS aggnamespace, "
    6896              :                           "p.pronargs, p.proargtypes, "
    6897              :                           "p.proowner, "
    6898              :                           "p.proacl AS aggacl, "
    6899              :                           "acldefault('f', p.proowner) AS acldefault "
    6900              :                           "FROM pg_proc p "
    6901              :                           "LEFT JOIN pg_init_privs pip ON "
    6902              :                           "(p.oid = pip.objoid "
    6903              :                           "AND pip.classoid = 'pg_proc'::regclass "
    6904              :                           "AND pip.objsubid = 0) "
    6905              :                           "WHERE %s AND ("
    6906              :                           "p.pronamespace != "
    6907              :                           "(SELECT oid FROM pg_namespace "
    6908              :                           "WHERE nspname = 'pg_catalog') OR "
    6909              :                           "p.proacl IS DISTINCT FROM pip.initprivs",
    6910              :                           agg_check);
    6911          259 :         if (dopt->binary_upgrade)
    6912           40 :             appendPQExpBufferStr(query,
    6913              :                                  " OR EXISTS(SELECT 1 FROM pg_depend WHERE "
    6914              :                                  "classid = 'pg_proc'::regclass AND "
    6915              :                                  "objid = p.oid AND "
    6916              :                                  "refclassid = 'pg_extension'::regclass AND "
    6917              :                                  "deptype = 'e')");
    6918          259 :         appendPQExpBufferChar(query, ')');
    6919              :     }
    6920              :     else
    6921              :     {
    6922            0 :         appendPQExpBufferStr(query, "SELECT tableoid, oid, proname AS aggname, "
    6923              :                              "pronamespace AS aggnamespace, "
    6924              :                              "pronargs, proargtypes, "
    6925              :                              "proowner, "
    6926              :                              "proacl AS aggacl, "
    6927              :                              "acldefault('f', proowner) AS acldefault "
    6928              :                              "FROM pg_proc p "
    6929              :                              "WHERE proisagg AND ("
    6930              :                              "pronamespace != "
    6931              :                              "(SELECT oid FROM pg_namespace "
    6932              :                              "WHERE nspname = 'pg_catalog')");
    6933            0 :         if (dopt->binary_upgrade)
    6934            0 :             appendPQExpBufferStr(query,
    6935              :                                  " OR EXISTS(SELECT 1 FROM pg_depend WHERE "
    6936              :                                  "classid = 'pg_proc'::regclass AND "
    6937              :                                  "objid = p.oid AND "
    6938              :                                  "refclassid = 'pg_extension'::regclass AND "
    6939              :                                  "deptype = 'e')");
    6940            0 :         appendPQExpBufferChar(query, ')');
    6941              :     }
    6942              : 
    6943          259 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    6944              : 
    6945          259 :     ntups = PQntuples(res);
    6946              : 
    6947          259 :     agginfo = pg_malloc_array(AggInfo, ntups);
    6948              : 
    6949          259 :     i_tableoid = PQfnumber(res, "tableoid");
    6950          259 :     i_oid = PQfnumber(res, "oid");
    6951          259 :     i_aggname = PQfnumber(res, "aggname");
    6952          259 :     i_aggnamespace = PQfnumber(res, "aggnamespace");
    6953          259 :     i_pronargs = PQfnumber(res, "pronargs");
    6954          259 :     i_proargtypes = PQfnumber(res, "proargtypes");
    6955          259 :     i_proowner = PQfnumber(res, "proowner");
    6956          259 :     i_aggacl = PQfnumber(res, "aggacl");
    6957          259 :     i_acldefault = PQfnumber(res, "acldefault");
    6958              : 
    6959          658 :     for (i = 0; i < ntups; i++)
    6960              :     {
    6961          399 :         agginfo[i].aggfn.dobj.objType = DO_AGG;
    6962          399 :         agginfo[i].aggfn.dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    6963          399 :         agginfo[i].aggfn.dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    6964          399 :         AssignDumpId(&agginfo[i].aggfn.dobj);
    6965          399 :         agginfo[i].aggfn.dobj.name = pg_strdup(PQgetvalue(res, i, i_aggname));
    6966          798 :         agginfo[i].aggfn.dobj.namespace =
    6967          399 :             findNamespace(atooid(PQgetvalue(res, i, i_aggnamespace)));
    6968          399 :         agginfo[i].aggfn.dacl.acl = pg_strdup(PQgetvalue(res, i, i_aggacl));
    6969          399 :         agginfo[i].aggfn.dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
    6970          399 :         agginfo[i].aggfn.dacl.privtype = 0;
    6971          399 :         agginfo[i].aggfn.dacl.initprivs = NULL;
    6972          399 :         agginfo[i].aggfn.rolname = getRoleName(PQgetvalue(res, i, i_proowner));
    6973          399 :         agginfo[i].aggfn.lang = InvalidOid; /* not currently interesting */
    6974          399 :         agginfo[i].aggfn.prorettype = InvalidOid;   /* not saved */
    6975          399 :         agginfo[i].aggfn.nargs = atoi(PQgetvalue(res, i, i_pronargs));
    6976          399 :         if (agginfo[i].aggfn.nargs == 0)
    6977           56 :             agginfo[i].aggfn.argtypes = NULL;
    6978              :         else
    6979              :         {
    6980          343 :             agginfo[i].aggfn.argtypes = pg_malloc_array(Oid, agginfo[i].aggfn.nargs);
    6981          343 :             parseOidArray(PQgetvalue(res, i, i_proargtypes),
    6982          343 :                           agginfo[i].aggfn.argtypes,
    6983          343 :                           agginfo[i].aggfn.nargs);
    6984              :         }
    6985          399 :         agginfo[i].aggfn.postponed_def = false; /* might get set during sort */
    6986              : 
    6987              :         /* Decide whether we want to dump it */
    6988          399 :         selectDumpableObject(&(agginfo[i].aggfn.dobj), fout);
    6989              : 
    6990              :         /* Mark whether aggregate has an ACL */
    6991          399 :         if (!PQgetisnull(res, i, i_aggacl))
    6992           25 :             agginfo[i].aggfn.dobj.components |= DUMP_COMPONENT_ACL;
    6993              :     }
    6994              : 
    6995          259 :     PQclear(res);
    6996              : 
    6997          259 :     destroyPQExpBuffer(query);
    6998          259 : }
    6999              : 
    7000              : /*
    7001              :  * getFuncs:
    7002              :  *    get information about all user-defined functions in the system catalogs
    7003              :  */
    7004              : void
    7005          259 : getFuncs(Archive *fout)
    7006              : {
    7007          259 :     DumpOptions *dopt = fout->dopt;
    7008              :     PGresult   *res;
    7009              :     int         ntups;
    7010              :     int         i;
    7011          259 :     PQExpBuffer query = createPQExpBuffer();
    7012              :     FuncInfo   *finfo;
    7013              :     int         i_tableoid;
    7014              :     int         i_oid;
    7015              :     int         i_proname;
    7016              :     int         i_pronamespace;
    7017              :     int         i_proowner;
    7018              :     int         i_prolang;
    7019              :     int         i_pronargs;
    7020              :     int         i_proargtypes;
    7021              :     int         i_prorettype;
    7022              :     int         i_proacl;
    7023              :     int         i_acldefault;
    7024              : 
    7025              :     /*
    7026              :      * Find all interesting functions.  This is a bit complicated:
    7027              :      *
    7028              :      * 1. Always exclude aggregates; those are handled elsewhere.
    7029              :      *
    7030              :      * 2. Always exclude functions that are internally dependent on something
    7031              :      * else, since presumably those will be created as a result of creating
    7032              :      * the something else.  This currently acts only to suppress constructor
    7033              :      * functions for range types.  Note this is OK only because the
    7034              :      * constructors don't have any dependencies the range type doesn't have;
    7035              :      * otherwise we might not get creation ordering correct.
    7036              :      *
    7037              :      * 3. Otherwise, we normally exclude functions in pg_catalog.  However, if
    7038              :      * they're members of extensions and we are in binary-upgrade mode then
    7039              :      * include them, since we want to dump extension members individually in
    7040              :      * that mode.  Also, if they are used by casts or transforms then we need
    7041              :      * to gather the information about them, though they won't be dumped if
    7042              :      * they are built-in.  Also, in 9.6 and up, include functions in
    7043              :      * pg_catalog if they have an ACL different from what's shown in
    7044              :      * pg_init_privs (so we have to join to pg_init_privs; annoying).
    7045              :      */
    7046          259 :     if (fout->remoteVersion >= 90600)
    7047              :     {
    7048              :         const char *not_agg_check;
    7049              : 
    7050          518 :         not_agg_check = (fout->remoteVersion >= 110000 ? "p.prokind <> 'a'"
    7051          259 :                          : "NOT p.proisagg");
    7052              : 
    7053          259 :         appendPQExpBuffer(query,
    7054              :                           "SELECT p.tableoid, p.oid, p.proname, p.prolang, "
    7055              :                           "p.pronargs, p.proargtypes, p.prorettype, "
    7056              :                           "p.proacl, "
    7057              :                           "acldefault('f', p.proowner) AS acldefault, "
    7058              :                           "p.pronamespace, "
    7059              :                           "p.proowner "
    7060              :                           "FROM pg_proc p "
    7061              :                           "LEFT JOIN pg_init_privs pip ON "
    7062              :                           "(p.oid = pip.objoid "
    7063              :                           "AND pip.classoid = 'pg_proc'::regclass "
    7064              :                           "AND pip.objsubid = 0) "
    7065              :                           "WHERE %s"
    7066              :                           "\n  AND NOT EXISTS (SELECT 1 FROM pg_depend "
    7067              :                           "WHERE classid = 'pg_proc'::regclass AND "
    7068              :                           "objid = p.oid AND deptype = 'i')"
    7069              :                           "\n  AND ("
    7070              :                           "\n  pronamespace != "
    7071              :                           "(SELECT oid FROM pg_namespace "
    7072              :                           "WHERE nspname = 'pg_catalog')"
    7073              :                           "\n  OR EXISTS (SELECT 1 FROM pg_cast"
    7074              :                           "\n  WHERE pg_cast.oid > %u "
    7075              :                           "\n  AND p.oid = pg_cast.castfunc)"
    7076              :                           "\n  OR EXISTS (SELECT 1 FROM pg_transform"
    7077              :                           "\n  WHERE pg_transform.oid > %u AND "
    7078              :                           "\n  (p.oid = pg_transform.trffromsql"
    7079              :                           "\n  OR p.oid = pg_transform.trftosql))",
    7080              :                           not_agg_check,
    7081              :                           g_last_builtin_oid,
    7082              :                           g_last_builtin_oid);
    7083          259 :         if (dopt->binary_upgrade)
    7084           40 :             appendPQExpBufferStr(query,
    7085              :                                  "\n  OR EXISTS(SELECT 1 FROM pg_depend WHERE "
    7086              :                                  "classid = 'pg_proc'::regclass AND "
    7087              :                                  "objid = p.oid AND "
    7088              :                                  "refclassid = 'pg_extension'::regclass AND "
    7089              :                                  "deptype = 'e')");
    7090          259 :         appendPQExpBufferStr(query,
    7091              :                              "\n  OR p.proacl IS DISTINCT FROM pip.initprivs");
    7092          259 :         appendPQExpBufferChar(query, ')');
    7093              :     }
    7094              :     else
    7095              :     {
    7096            0 :         appendPQExpBuffer(query,
    7097              :                           "SELECT tableoid, oid, proname, prolang, "
    7098              :                           "pronargs, proargtypes, prorettype, proacl, "
    7099              :                           "acldefault('f', proowner) AS acldefault, "
    7100              :                           "pronamespace, "
    7101              :                           "proowner "
    7102              :                           "FROM pg_proc p "
    7103              :                           "WHERE NOT proisagg"
    7104              :                           "\n  AND NOT EXISTS (SELECT 1 FROM pg_depend "
    7105              :                           "WHERE classid = 'pg_proc'::regclass AND "
    7106              :                           "objid = p.oid AND deptype = 'i')"
    7107              :                           "\n  AND ("
    7108              :                           "\n  pronamespace != "
    7109              :                           "(SELECT oid FROM pg_namespace "
    7110              :                           "WHERE nspname = 'pg_catalog')"
    7111              :                           "\n  OR EXISTS (SELECT 1 FROM pg_cast"
    7112              :                           "\n  WHERE pg_cast.oid > '%u'::oid"
    7113              :                           "\n  AND p.oid = pg_cast.castfunc)",
    7114              :                           g_last_builtin_oid);
    7115              : 
    7116            0 :         if (fout->remoteVersion >= 90500)
    7117            0 :             appendPQExpBuffer(query,
    7118              :                               "\n  OR EXISTS (SELECT 1 FROM pg_transform"
    7119              :                               "\n  WHERE pg_transform.oid > '%u'::oid"
    7120              :                               "\n  AND (p.oid = pg_transform.trffromsql"
    7121              :                               "\n  OR p.oid = pg_transform.trftosql))",
    7122              :                               g_last_builtin_oid);
    7123              : 
    7124            0 :         if (dopt->binary_upgrade)
    7125            0 :             appendPQExpBufferStr(query,
    7126              :                                  "\n  OR EXISTS(SELECT 1 FROM pg_depend WHERE "
    7127              :                                  "classid = 'pg_proc'::regclass AND "
    7128              :                                  "objid = p.oid AND "
    7129              :                                  "refclassid = 'pg_extension'::regclass AND "
    7130              :                                  "deptype = 'e')");
    7131            0 :         appendPQExpBufferChar(query, ')');
    7132              :     }
    7133              : 
    7134          259 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    7135              : 
    7136          259 :     ntups = PQntuples(res);
    7137              : 
    7138          259 :     finfo = pg_malloc0_array(FuncInfo, ntups);
    7139              : 
    7140          259 :     i_tableoid = PQfnumber(res, "tableoid");
    7141          259 :     i_oid = PQfnumber(res, "oid");
    7142          259 :     i_proname = PQfnumber(res, "proname");
    7143          259 :     i_pronamespace = PQfnumber(res, "pronamespace");
    7144          259 :     i_proowner = PQfnumber(res, "proowner");
    7145          259 :     i_prolang = PQfnumber(res, "prolang");
    7146          259 :     i_pronargs = PQfnumber(res, "pronargs");
    7147          259 :     i_proargtypes = PQfnumber(res, "proargtypes");
    7148          259 :     i_prorettype = PQfnumber(res, "prorettype");
    7149          259 :     i_proacl = PQfnumber(res, "proacl");
    7150          259 :     i_acldefault = PQfnumber(res, "acldefault");
    7151              : 
    7152         5930 :     for (i = 0; i < ntups; i++)
    7153              :     {
    7154         5671 :         finfo[i].dobj.objType = DO_FUNC;
    7155         5671 :         finfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    7156         5671 :         finfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    7157         5671 :         AssignDumpId(&finfo[i].dobj);
    7158         5671 :         finfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_proname));
    7159        11342 :         finfo[i].dobj.namespace =
    7160         5671 :             findNamespace(atooid(PQgetvalue(res, i, i_pronamespace)));
    7161         5671 :         finfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_proacl));
    7162         5671 :         finfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
    7163         5671 :         finfo[i].dacl.privtype = 0;
    7164         5671 :         finfo[i].dacl.initprivs = NULL;
    7165         5671 :         finfo[i].rolname = getRoleName(PQgetvalue(res, i, i_proowner));
    7166         5671 :         finfo[i].lang = atooid(PQgetvalue(res, i, i_prolang));
    7167         5671 :         finfo[i].prorettype = atooid(PQgetvalue(res, i, i_prorettype));
    7168         5671 :         finfo[i].nargs = atoi(PQgetvalue(res, i, i_pronargs));
    7169         5671 :         if (finfo[i].nargs == 0)
    7170         1112 :             finfo[i].argtypes = NULL;
    7171              :         else
    7172              :         {
    7173         4559 :             finfo[i].argtypes = pg_malloc_array(Oid, finfo[i].nargs);
    7174         4559 :             parseOidArray(PQgetvalue(res, i, i_proargtypes),
    7175         4559 :                           finfo[i].argtypes, finfo[i].nargs);
    7176              :         }
    7177         5671 :         finfo[i].postponed_def = false; /* might get set during sort */
    7178              : 
    7179              :         /* Decide whether we want to dump it */
    7180         5671 :         selectDumpableObject(&(finfo[i].dobj), fout);
    7181              : 
    7182              :         /* Mark whether function has an ACL */
    7183         5671 :         if (!PQgetisnull(res, i, i_proacl))
    7184          149 :             finfo[i].dobj.components |= DUMP_COMPONENT_ACL;
    7185              :     }
    7186              : 
    7187          259 :     PQclear(res);
    7188              : 
    7189          259 :     destroyPQExpBuffer(query);
    7190          259 : }
    7191              : 
    7192              : /*
    7193              :  * getRelationStatistics
    7194              :  *    register the statistics object as a dependent of the relation.
    7195              :  *
    7196              :  * reltuples is passed as a string to avoid complexities in converting from/to
    7197              :  * floating point.
    7198              :  */
    7199              : static RelStatsInfo *
    7200        10457 : getRelationStatistics(Archive *fout, DumpableObject *rel, int32 relpages,
    7201              :                       char *reltuples, int32 relallvisible,
    7202              :                       int32 relallfrozen, char relkind,
    7203              :                       char **indAttNames, int nindAttNames)
    7204              : {
    7205        10457 :     if (!fout->dopt->dumpStatistics)
    7206         6695 :         return NULL;
    7207              : 
    7208         3762 :     if ((relkind == RELKIND_RELATION) ||
    7209         1560 :         (relkind == RELKIND_PARTITIONED_TABLE) ||
    7210          939 :         (relkind == RELKIND_INDEX) ||
    7211          621 :         (relkind == RELKIND_PARTITIONED_INDEX) ||
    7212          318 :         (relkind == RELKIND_MATVIEW ||
    7213              :          relkind == RELKIND_FOREIGN_TABLE))
    7214              :     {
    7215         3476 :         RelStatsInfo *info = pg_malloc0_object(RelStatsInfo);
    7216         3476 :         DumpableObject *dobj = &info->dobj;
    7217              : 
    7218         3476 :         dobj->objType = DO_REL_STATS;
    7219         3476 :         dobj->catId.tableoid = 0;
    7220         3476 :         dobj->catId.oid = 0;
    7221         3476 :         AssignDumpId(dobj);
    7222         3476 :         dobj->dependencies = pg_malloc_object(DumpId);
    7223         3476 :         dobj->dependencies[0] = rel->dumpId;
    7224         3476 :         dobj->nDeps = 1;
    7225         3476 :         dobj->allocDeps = 1;
    7226         3476 :         dobj->components |= DUMP_COMPONENT_STATISTICS;
    7227         3476 :         dobj->name = pg_strdup(rel->name);
    7228         3476 :         dobj->namespace = rel->namespace;
    7229         3476 :         info->relid = rel->catId.oid;
    7230         3476 :         info->relpages = relpages;
    7231         3476 :         info->reltuples = pstrdup(reltuples);
    7232         3476 :         info->relallvisible = relallvisible;
    7233         3476 :         info->relallfrozen = relallfrozen;
    7234         3476 :         info->relkind = relkind;
    7235         3476 :         info->indAttNames = indAttNames;
    7236         3476 :         info->nindAttNames = nindAttNames;
    7237              : 
    7238              :         /*
    7239              :          * Ordinarily, stats go in SECTION_DATA for tables and
    7240              :          * SECTION_POST_DATA for indexes.
    7241              :          *
    7242              :          * However, the section may be updated later for materialized view
    7243              :          * stats. REFRESH MATERIALIZED VIEW replaces the storage and resets
    7244              :          * the stats, so the stats must be restored after the data. Also, the
    7245              :          * materialized view definition may be postponed to SECTION_POST_DATA
    7246              :          * (see repairMatViewBoundaryMultiLoop()).
    7247              :          */
    7248         3476 :         switch (info->relkind)
    7249              :         {
    7250         2537 :             case RELKIND_RELATION:
    7251              :             case RELKIND_PARTITIONED_TABLE:
    7252              :             case RELKIND_MATVIEW:
    7253              :             case RELKIND_FOREIGN_TABLE:
    7254         2537 :                 info->section = SECTION_DATA;
    7255         2537 :                 break;
    7256          939 :             case RELKIND_INDEX:
    7257              :             case RELKIND_PARTITIONED_INDEX:
    7258          939 :                 info->section = SECTION_POST_DATA;
    7259          939 :                 break;
    7260            0 :             default:
    7261            0 :                 pg_fatal("cannot dump statistics for relation kind \"%c\"",
    7262              :                          info->relkind);
    7263              :         }
    7264              : 
    7265         3476 :         return info;
    7266              :     }
    7267          286 :     return NULL;
    7268              : }
    7269              : 
    7270              : /*
    7271              :  * getTables
    7272              :  *    read all the tables (no indexes) in the system catalogs,
    7273              :  *    and return them as an array of TableInfo structures
    7274              :  *
    7275              :  * *numTables is set to the number of tables read in
    7276              :  */
    7277              : TableInfo *
    7278          260 : getTables(Archive *fout, int *numTables)
    7279              : {
    7280          260 :     DumpOptions *dopt = fout->dopt;
    7281              :     PGresult   *res;
    7282              :     int         ntups;
    7283              :     int         i;
    7284          260 :     PQExpBuffer query = createPQExpBuffer();
    7285              :     TableInfo  *tblinfo;
    7286              :     int         i_reltableoid;
    7287              :     int         i_reloid;
    7288              :     int         i_relname;
    7289              :     int         i_relnamespace;
    7290              :     int         i_relkind;
    7291              :     int         i_reltype;
    7292              :     int         i_relowner;
    7293              :     int         i_relchecks;
    7294              :     int         i_relhasindex;
    7295              :     int         i_relhasrules;
    7296              :     int         i_relpages;
    7297              :     int         i_reltuples;
    7298              :     int         i_relallvisible;
    7299              :     int         i_relallfrozen;
    7300              :     int         i_toastpages;
    7301              :     int         i_owning_tab;
    7302              :     int         i_owning_col;
    7303              :     int         i_reltablespace;
    7304              :     int         i_relhasoids;
    7305              :     int         i_relhastriggers;
    7306              :     int         i_relpersistence;
    7307              :     int         i_relispopulated;
    7308              :     int         i_relreplident;
    7309              :     int         i_relrowsec;
    7310              :     int         i_relforcerowsec;
    7311              :     int         i_relfrozenxid;
    7312              :     int         i_toastfrozenxid;
    7313              :     int         i_toastoid;
    7314              :     int         i_relminmxid;
    7315              :     int         i_toastminmxid;
    7316              :     int         i_reloptions;
    7317              :     int         i_checkoption;
    7318              :     int         i_toastreloptions;
    7319              :     int         i_reloftype;
    7320              :     int         i_foreignserver;
    7321              :     int         i_amname;
    7322              :     int         i_is_identity_sequence;
    7323              :     int         i_relacl;
    7324              :     int         i_acldefault;
    7325              :     int         i_ispartition;
    7326              : 
    7327              :     /*
    7328              :      * Find all the tables and table-like objects.
    7329              :      *
    7330              :      * We must fetch all tables in this phase because otherwise we cannot
    7331              :      * correctly identify inherited columns, owned sequences, etc.
    7332              :      *
    7333              :      * We include system catalogs, so that we can work if a user table is
    7334              :      * defined to inherit from a system catalog (pretty weird, but...)
    7335              :      *
    7336              :      * Note: in this phase we should collect only a minimal amount of
    7337              :      * information about each table, basically just enough to decide if it is
    7338              :      * interesting.  In particular, since we do not yet have lock on any user
    7339              :      * table, we MUST NOT invoke any server-side data collection functions
    7340              :      * (for instance, pg_get_partkeydef()).  Those are likely to fail or give
    7341              :      * wrong answers if any concurrent DDL is happening.
    7342              :      */
    7343              : 
    7344          260 :     appendPQExpBufferStr(query,
    7345              :                          "SELECT c.tableoid, c.oid, c.relname, "
    7346              :                          "c.relnamespace, c.relkind, c.reltype, "
    7347              :                          "c.relowner, "
    7348              :                          "c.relchecks, "
    7349              :                          "c.relhasindex, c.relhasrules, c.relpages, "
    7350              :                          "c.reltuples, c.relallvisible, ");
    7351              : 
    7352          260 :     if (fout->remoteVersion >= 180000)
    7353          260 :         appendPQExpBufferStr(query, "c.relallfrozen, ");
    7354              :     else
    7355            0 :         appendPQExpBufferStr(query, "0 AS relallfrozen, ");
    7356              : 
    7357          260 :     appendPQExpBufferStr(query,
    7358              :                          "c.relhastriggers, c.relpersistence, "
    7359              :                          "c.reloftype, "
    7360              :                          "c.relacl, "
    7361              :                          "acldefault(CASE WHEN c.relkind = " CppAsString2(RELKIND_SEQUENCE)
    7362              :                          " THEN 's'::\"char\" ELSE 'r'::\"char\" END, c.relowner) AS acldefault, "
    7363              :                          "CASE WHEN c.relkind = " CppAsString2(RELKIND_FOREIGN_TABLE) " THEN "
    7364              :                          "(SELECT ftserver FROM pg_catalog.pg_foreign_table WHERE ftrelid = c.oid) "
    7365              :                          "ELSE 0 END AS foreignserver, "
    7366              :                          "c.relfrozenxid, tc.relfrozenxid AS tfrozenxid, "
    7367              :                          "tc.oid AS toid, "
    7368              :                          "tc.relpages AS toastpages, "
    7369              :                          "tc.reloptions AS toast_reloptions, "
    7370              :                          "d.refobjid AS owning_tab, "
    7371              :                          "d.refobjsubid AS owning_col, "
    7372              :                          "tsp.spcname AS reltablespace, ");
    7373              : 
    7374          260 :     if (fout->remoteVersion >= 120000)
    7375          260 :         appendPQExpBufferStr(query,
    7376              :                              "false AS relhasoids, ");
    7377              :     else
    7378            0 :         appendPQExpBufferStr(query,
    7379              :                              "c.relhasoids, ");
    7380              : 
    7381          260 :     if (fout->remoteVersion >= 90300)
    7382          260 :         appendPQExpBufferStr(query,
    7383              :                              "c.relispopulated, ");
    7384              :     else
    7385            0 :         appendPQExpBufferStr(query,
    7386              :                              "'t' as relispopulated, ");
    7387              : 
    7388          260 :     if (fout->remoteVersion >= 90400)
    7389          260 :         appendPQExpBufferStr(query,
    7390              :                              "c.relreplident, ");
    7391              :     else
    7392            0 :         appendPQExpBufferStr(query,
    7393              :                              "'d' AS relreplident, ");
    7394              : 
    7395          260 :     if (fout->remoteVersion >= 90500)
    7396          260 :         appendPQExpBufferStr(query,
    7397              :                              "c.relrowsecurity, c.relforcerowsecurity, ");
    7398              :     else
    7399            0 :         appendPQExpBufferStr(query,
    7400              :                              "false AS relrowsecurity, "
    7401              :                              "false AS relforcerowsecurity, ");
    7402              : 
    7403          260 :     if (fout->remoteVersion >= 90300)
    7404          260 :         appendPQExpBufferStr(query,
    7405              :                              "c.relminmxid, tc.relminmxid AS tminmxid, ");
    7406              :     else
    7407            0 :         appendPQExpBufferStr(query,
    7408              :                              "0 AS relminmxid, 0 AS tminmxid, ");
    7409              : 
    7410          260 :     if (fout->remoteVersion >= 90300)
    7411          260 :         appendPQExpBufferStr(query,
    7412              :                              "array_remove(array_remove(c.reloptions,'check_option=local'),'check_option=cascaded') AS reloptions, "
    7413              :                              "CASE WHEN 'check_option=local' = ANY (c.reloptions) THEN 'LOCAL'::text "
    7414              :                              "WHEN 'check_option=cascaded' = ANY (c.reloptions) THEN 'CASCADED'::text ELSE NULL END AS checkoption, ");
    7415              :     else
    7416            0 :         appendPQExpBufferStr(query,
    7417              :                              "c.reloptions, NULL AS checkoption, ");
    7418              : 
    7419          260 :     if (fout->remoteVersion >= 90600)
    7420          260 :         appendPQExpBufferStr(query,
    7421              :                              "am.amname, ");
    7422              :     else
    7423            0 :         appendPQExpBufferStr(query,
    7424              :                              "NULL AS amname, ");
    7425              : 
    7426          260 :     if (fout->remoteVersion >= 90600)
    7427          260 :         appendPQExpBufferStr(query,
    7428              :                              "(d.deptype = 'i') IS TRUE AS is_identity_sequence, ");
    7429              :     else
    7430            0 :         appendPQExpBufferStr(query,
    7431              :                              "false AS is_identity_sequence, ");
    7432              : 
    7433          260 :     if (fout->remoteVersion >= 100000)
    7434          260 :         appendPQExpBufferStr(query,
    7435              :                              "c.relispartition AS ispartition ");
    7436              :     else
    7437            0 :         appendPQExpBufferStr(query,
    7438              :                              "false AS ispartition ");
    7439              : 
    7440              :     /*
    7441              :      * Left join to pg_depend to pick up dependency info linking sequences to
    7442              :      * their owning column, if any (note this dependency is AUTO except for
    7443              :      * identity sequences, where it's INTERNAL). Also join to pg_tablespace to
    7444              :      * collect the spcname.
    7445              :      */
    7446          260 :     appendPQExpBufferStr(query,
    7447              :                          "\nFROM pg_class c\n"
    7448              :                          "LEFT JOIN pg_depend d ON "
    7449              :                          "(c.relkind = " CppAsString2(RELKIND_SEQUENCE) " AND "
    7450              :                          "d.classid = 'pg_class'::regclass AND d.objid = c.oid AND "
    7451              :                          "d.objsubid = 0 AND "
    7452              :                          "d.refclassid = 'pg_class'::regclass AND d.deptype IN ('a', 'i'))\n"
    7453              :                          "LEFT JOIN pg_tablespace tsp ON (tsp.oid = c.reltablespace)\n");
    7454              : 
    7455              :     /*
    7456              :      * In 9.6 and up, left join to pg_am to pick up the amname.
    7457              :      */
    7458          260 :     if (fout->remoteVersion >= 90600)
    7459          260 :         appendPQExpBufferStr(query,
    7460              :                              "LEFT JOIN pg_am am ON (c.relam = am.oid)\n");
    7461              : 
    7462              :     /*
    7463              :      * We purposefully ignore toast OIDs for partitioned tables; the reason is
    7464              :      * that versions 10 and 11 have them, but later versions do not, so
    7465              :      * emitting them causes the upgrade to fail.
    7466              :      */
    7467          260 :     appendPQExpBufferStr(query,
    7468              :                          "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid"
    7469              :                          " AND tc.relkind = " CppAsString2(RELKIND_TOASTVALUE)
    7470              :                          " AND c.relkind <> " CppAsString2(RELKIND_PARTITIONED_TABLE) ")\n");
    7471              : 
    7472              :     /*
    7473              :      * Restrict to interesting relkinds (in particular, not indexes).  Not all
    7474              :      * relkinds are possible in older servers, but it's not worth the trouble
    7475              :      * to emit a version-dependent list.
    7476              :      *
    7477              :      * Composite-type table entries won't be dumped as such, but we have to
    7478              :      * make a DumpableObject for them so that we can track dependencies of the
    7479              :      * composite type (pg_depend entries for columns of the composite type
    7480              :      * link to the pg_class entry not the pg_type entry).
    7481              :      */
    7482          260 :     appendPQExpBufferStr(query,
    7483              :                          "WHERE c.relkind IN ("
    7484              :                          CppAsString2(RELKIND_RELATION) ", "
    7485              :                          CppAsString2(RELKIND_SEQUENCE) ", "
    7486              :                          CppAsString2(RELKIND_VIEW) ", "
    7487              :                          CppAsString2(RELKIND_COMPOSITE_TYPE) ", "
    7488              :                          CppAsString2(RELKIND_MATVIEW) ", "
    7489              :                          CppAsString2(RELKIND_FOREIGN_TABLE) ", "
    7490              :                          CppAsString2(RELKIND_PARTITIONED_TABLE) ", "
    7491              :                          CppAsString2(RELKIND_PROPGRAPH) ")\n"
    7492              :                          "ORDER BY c.oid");
    7493              : 
    7494          260 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    7495              : 
    7496          260 :     ntups = PQntuples(res);
    7497              : 
    7498          260 :     *numTables = ntups;
    7499              : 
    7500              :     /*
    7501              :      * Extract data from result and lock dumpable tables.  We do the locking
    7502              :      * before anything else, to minimize the window wherein a table could
    7503              :      * disappear under us.
    7504              :      *
    7505              :      * Note that we have to save info about all tables here, even when dumping
    7506              :      * only one, because we don't yet know which tables might be inheritance
    7507              :      * ancestors of the target table.
    7508              :      */
    7509          260 :     tblinfo = pg_malloc0_array(TableInfo, ntups);
    7510              : 
    7511          260 :     i_reltableoid = PQfnumber(res, "tableoid");
    7512          260 :     i_reloid = PQfnumber(res, "oid");
    7513          260 :     i_relname = PQfnumber(res, "relname");
    7514          260 :     i_relnamespace = PQfnumber(res, "relnamespace");
    7515          260 :     i_relkind = PQfnumber(res, "relkind");
    7516          260 :     i_reltype = PQfnumber(res, "reltype");
    7517          260 :     i_relowner = PQfnumber(res, "relowner");
    7518          260 :     i_relchecks = PQfnumber(res, "relchecks");
    7519          260 :     i_relhasindex = PQfnumber(res, "relhasindex");
    7520          260 :     i_relhasrules = PQfnumber(res, "relhasrules");
    7521          260 :     i_relpages = PQfnumber(res, "relpages");
    7522          260 :     i_reltuples = PQfnumber(res, "reltuples");
    7523          260 :     i_relallvisible = PQfnumber(res, "relallvisible");
    7524          260 :     i_relallfrozen = PQfnumber(res, "relallfrozen");
    7525          260 :     i_toastpages = PQfnumber(res, "toastpages");
    7526          260 :     i_owning_tab = PQfnumber(res, "owning_tab");
    7527          260 :     i_owning_col = PQfnumber(res, "owning_col");
    7528          260 :     i_reltablespace = PQfnumber(res, "reltablespace");
    7529          260 :     i_relhasoids = PQfnumber(res, "relhasoids");
    7530          260 :     i_relhastriggers = PQfnumber(res, "relhastriggers");
    7531          260 :     i_relpersistence = PQfnumber(res, "relpersistence");
    7532          260 :     i_relispopulated = PQfnumber(res, "relispopulated");
    7533          260 :     i_relreplident = PQfnumber(res, "relreplident");
    7534          260 :     i_relrowsec = PQfnumber(res, "relrowsecurity");
    7535          260 :     i_relforcerowsec = PQfnumber(res, "relforcerowsecurity");
    7536          260 :     i_relfrozenxid = PQfnumber(res, "relfrozenxid");
    7537          260 :     i_toastfrozenxid = PQfnumber(res, "tfrozenxid");
    7538          260 :     i_toastoid = PQfnumber(res, "toid");
    7539          260 :     i_relminmxid = PQfnumber(res, "relminmxid");
    7540          260 :     i_toastminmxid = PQfnumber(res, "tminmxid");
    7541          260 :     i_reloptions = PQfnumber(res, "reloptions");
    7542          260 :     i_checkoption = PQfnumber(res, "checkoption");
    7543          260 :     i_toastreloptions = PQfnumber(res, "toast_reloptions");
    7544          260 :     i_reloftype = PQfnumber(res, "reloftype");
    7545          260 :     i_foreignserver = PQfnumber(res, "foreignserver");
    7546          260 :     i_amname = PQfnumber(res, "amname");
    7547          260 :     i_is_identity_sequence = PQfnumber(res, "is_identity_sequence");
    7548          260 :     i_relacl = PQfnumber(res, "relacl");
    7549          260 :     i_acldefault = PQfnumber(res, "acldefault");
    7550          260 :     i_ispartition = PQfnumber(res, "ispartition");
    7551              : 
    7552          260 :     if (dopt->lockWaitTimeout)
    7553              :     {
    7554              :         /*
    7555              :          * Arrange to fail instead of waiting forever for a table lock.
    7556              :          *
    7557              :          * NB: this coding assumes that the only queries issued within the
    7558              :          * following loop are LOCK TABLEs; else the timeout may be undesirably
    7559              :          * applied to other things too.
    7560              :          */
    7561            2 :         resetPQExpBuffer(query);
    7562            2 :         appendPQExpBufferStr(query, "SET statement_timeout = ");
    7563            2 :         appendStringLiteralConn(query, dopt->lockWaitTimeout, GetConnection(fout));
    7564            2 :         ExecuteSqlStatement(fout, query->data);
    7565              :     }
    7566              : 
    7567          260 :     resetPQExpBuffer(query);
    7568              : 
    7569        71281 :     for (i = 0; i < ntups; i++)
    7570              :     {
    7571        71021 :         int32       relallvisible = atoi(PQgetvalue(res, i, i_relallvisible));
    7572        71021 :         int32       relallfrozen = atoi(PQgetvalue(res, i, i_relallfrozen));
    7573              : 
    7574        71021 :         tblinfo[i].dobj.objType = DO_TABLE;
    7575        71021 :         tblinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_reltableoid));
    7576        71021 :         tblinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_reloid));
    7577        71021 :         AssignDumpId(&tblinfo[i].dobj);
    7578        71021 :         tblinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_relname));
    7579       142042 :         tblinfo[i].dobj.namespace =
    7580        71021 :             findNamespace(atooid(PQgetvalue(res, i, i_relnamespace)));
    7581        71021 :         tblinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_relacl));
    7582        71021 :         tblinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
    7583        71021 :         tblinfo[i].dacl.privtype = 0;
    7584        71021 :         tblinfo[i].dacl.initprivs = NULL;
    7585        71021 :         tblinfo[i].relkind = *(PQgetvalue(res, i, i_relkind));
    7586        71021 :         tblinfo[i].reltype = atooid(PQgetvalue(res, i, i_reltype));
    7587        71021 :         tblinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_relowner));
    7588        71021 :         tblinfo[i].ncheck = atoi(PQgetvalue(res, i, i_relchecks));
    7589        71021 :         tblinfo[i].hasindex = (strcmp(PQgetvalue(res, i, i_relhasindex), "t") == 0);
    7590        71021 :         tblinfo[i].hasrules = (strcmp(PQgetvalue(res, i, i_relhasrules), "t") == 0);
    7591        71021 :         tblinfo[i].relpages = atoi(PQgetvalue(res, i, i_relpages));
    7592        71021 :         if (PQgetisnull(res, i, i_toastpages))
    7593        57820 :             tblinfo[i].toastpages = 0;
    7594              :         else
    7595        13201 :             tblinfo[i].toastpages = atoi(PQgetvalue(res, i, i_toastpages));
    7596        71021 :         if (PQgetisnull(res, i, i_owning_tab))
    7597              :         {
    7598        70606 :             tblinfo[i].owning_tab = InvalidOid;
    7599        70606 :             tblinfo[i].owning_col = 0;
    7600              :         }
    7601              :         else
    7602              :         {
    7603          415 :             tblinfo[i].owning_tab = atooid(PQgetvalue(res, i, i_owning_tab));
    7604          415 :             tblinfo[i].owning_col = atoi(PQgetvalue(res, i, i_owning_col));
    7605              :         }
    7606        71021 :         tblinfo[i].reltablespace = pg_strdup(PQgetvalue(res, i, i_reltablespace));
    7607        71021 :         tblinfo[i].hasoids = (strcmp(PQgetvalue(res, i, i_relhasoids), "t") == 0);
    7608        71021 :         tblinfo[i].hastriggers = (strcmp(PQgetvalue(res, i, i_relhastriggers), "t") == 0);
    7609        71021 :         tblinfo[i].relpersistence = *(PQgetvalue(res, i, i_relpersistence));
    7610        71021 :         tblinfo[i].relispopulated = (strcmp(PQgetvalue(res, i, i_relispopulated), "t") == 0);
    7611        71021 :         tblinfo[i].relreplident = *(PQgetvalue(res, i, i_relreplident));
    7612        71021 :         tblinfo[i].rowsec = (strcmp(PQgetvalue(res, i, i_relrowsec), "t") == 0);
    7613        71021 :         tblinfo[i].forcerowsec = (strcmp(PQgetvalue(res, i, i_relforcerowsec), "t") == 0);
    7614        71021 :         tblinfo[i].frozenxid = atooid(PQgetvalue(res, i, i_relfrozenxid));
    7615        71021 :         tblinfo[i].toast_frozenxid = atooid(PQgetvalue(res, i, i_toastfrozenxid));
    7616        71021 :         tblinfo[i].toast_oid = atooid(PQgetvalue(res, i, i_toastoid));
    7617        71021 :         tblinfo[i].minmxid = atooid(PQgetvalue(res, i, i_relminmxid));
    7618        71021 :         tblinfo[i].toast_minmxid = atooid(PQgetvalue(res, i, i_toastminmxid));
    7619        71021 :         tblinfo[i].reloptions = pg_strdup(PQgetvalue(res, i, i_reloptions));
    7620        71021 :         if (PQgetisnull(res, i, i_checkoption))
    7621        70975 :             tblinfo[i].checkoption = NULL;
    7622              :         else
    7623           46 :             tblinfo[i].checkoption = pg_strdup(PQgetvalue(res, i, i_checkoption));
    7624        71021 :         tblinfo[i].toast_reloptions = pg_strdup(PQgetvalue(res, i, i_toastreloptions));
    7625        71021 :         tblinfo[i].reloftype = atooid(PQgetvalue(res, i, i_reloftype));
    7626        71021 :         tblinfo[i].foreign_server = atooid(PQgetvalue(res, i, i_foreignserver));
    7627        71021 :         if (PQgetisnull(res, i, i_amname))
    7628        44364 :             tblinfo[i].amname = NULL;
    7629              :         else
    7630        26657 :             tblinfo[i].amname = pg_strdup(PQgetvalue(res, i, i_amname));
    7631        71021 :         tblinfo[i].is_identity_sequence = (strcmp(PQgetvalue(res, i, i_is_identity_sequence), "t") == 0);
    7632        71021 :         tblinfo[i].ispartition = (strcmp(PQgetvalue(res, i, i_ispartition), "t") == 0);
    7633              : 
    7634              :         /* other fields were zeroed above */
    7635              : 
    7636              :         /*
    7637              :          * Decide whether we want to dump this table.
    7638              :          */
    7639        71021 :         if (tblinfo[i].relkind == RELKIND_COMPOSITE_TYPE)
    7640          183 :             tblinfo[i].dobj.dump = DUMP_COMPONENT_NONE;
    7641              :         else
    7642        70838 :             selectDumpableTable(&tblinfo[i], fout);
    7643              : 
    7644              :         /*
    7645              :          * Now, consider the table "interesting" if we need to dump its
    7646              :          * definition, data or its statistics.  Later on, we'll skip a lot of
    7647              :          * data collection for uninteresting tables.
    7648              :          *
    7649              :          * Note: the "interesting" flag will also be set by flagInhTables for
    7650              :          * parents of interesting tables, so that we collect necessary
    7651              :          * inheritance info even when the parents are not themselves being
    7652              :          * dumped.  This is the main reason why we need an "interesting" flag
    7653              :          * that's separate from the components-to-dump bitmask.
    7654              :          */
    7655        71021 :         tblinfo[i].interesting = (tblinfo[i].dobj.dump &
    7656              :                                   (DUMP_COMPONENT_DEFINITION |
    7657              :                                    DUMP_COMPONENT_DATA |
    7658        71021 :                                    DUMP_COMPONENT_STATISTICS)) != 0;
    7659              : 
    7660        71021 :         tblinfo[i].dummy_view = false;  /* might get set during sort */
    7661        71021 :         tblinfo[i].postponed_def = false;   /* might get set during sort */
    7662              : 
    7663              :         /* Tables have data */
    7664        71021 :         tblinfo[i].dobj.components |= DUMP_COMPONENT_DATA;
    7665              : 
    7666              :         /* Mark whether table has an ACL */
    7667        71021 :         if (!PQgetisnull(res, i, i_relacl))
    7668        59954 :             tblinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
    7669        71021 :         tblinfo[i].hascolumnACLs = false;   /* may get set later */
    7670              : 
    7671              :         /* Add statistics */
    7672        71021 :         if (tblinfo[i].interesting)
    7673              :         {
    7674              :             RelStatsInfo *stats;
    7675              : 
    7676        15360 :             stats = getRelationStatistics(fout, &tblinfo[i].dobj,
    7677         7680 :                                           tblinfo[i].relpages,
    7678              :                                           PQgetvalue(res, i, i_reltuples),
    7679              :                                           relallvisible, relallfrozen,
    7680         7680 :                                           tblinfo[i].relkind, NULL, 0);
    7681         7680 :             if (tblinfo[i].relkind == RELKIND_MATVIEW)
    7682          398 :                 tblinfo[i].stats = stats;
    7683              :         }
    7684              : 
    7685              :         /*
    7686              :          * Read-lock target tables to make sure they aren't DROPPED or altered
    7687              :          * in schema before we get around to dumping them.
    7688              :          *
    7689              :          * Note that we don't explicitly lock parents of the target tables; we
    7690              :          * assume our lock on the child is enough to prevent schema
    7691              :          * alterations to parent tables.
    7692              :          *
    7693              :          * NOTE: it'd be kinda nice to lock other relations too, not only
    7694              :          * plain or partitioned tables, but the backend doesn't presently
    7695              :          * allow that.
    7696              :          *
    7697              :          * We only need to lock the table for certain components; see
    7698              :          * pg_dump.h
    7699              :          */
    7700        71021 :         if ((tblinfo[i].dobj.dump & DUMP_COMPONENTS_REQUIRING_LOCK) &&
    7701         7680 :             (tblinfo[i].relkind == RELKIND_RELATION ||
    7702         2147 :              tblinfo[i].relkind == RELKIND_PARTITIONED_TABLE))
    7703              :         {
    7704              :             /*
    7705              :              * Tables are locked in batches.  When dumping from a remote
    7706              :              * server this can save a significant amount of time by reducing
    7707              :              * the number of round trips.
    7708              :              */
    7709         6157 :             if (query->len == 0)
    7710          177 :                 appendPQExpBuffer(query, "LOCK TABLE %s",
    7711          177 :                                   fmtQualifiedDumpable(&tblinfo[i]));
    7712              :             else
    7713              :             {
    7714         5980 :                 appendPQExpBuffer(query, ", %s",
    7715         5980 :                                   fmtQualifiedDumpable(&tblinfo[i]));
    7716              : 
    7717              :                 /* Arbitrarily end a batch when query length reaches 100K. */
    7718         5980 :                 if (query->len >= 100000)
    7719              :                 {
    7720              :                     /* Lock another batch of tables. */
    7721            0 :                     appendPQExpBufferStr(query, " IN ACCESS SHARE MODE");
    7722            0 :                     ExecuteSqlStatement(fout, query->data);
    7723            0 :                     resetPQExpBuffer(query);
    7724              :                 }
    7725              :             }
    7726              :         }
    7727              :     }
    7728              : 
    7729          260 :     if (query->len != 0)
    7730              :     {
    7731              :         /* Lock the tables in the last batch. */
    7732          177 :         appendPQExpBufferStr(query, " IN ACCESS SHARE MODE");
    7733          177 :         ExecuteSqlStatement(fout, query->data);
    7734              :     }
    7735              : 
    7736          259 :     if (dopt->lockWaitTimeout)
    7737              :     {
    7738            2 :         ExecuteSqlStatement(fout, "SET statement_timeout = 0");
    7739              :     }
    7740              : 
    7741          259 :     PQclear(res);
    7742              : 
    7743          259 :     destroyPQExpBuffer(query);
    7744              : 
    7745          259 :     return tblinfo;
    7746              : }
    7747              : 
    7748              : /*
    7749              :  * getOwnedSeqs
    7750              :  *    identify owned sequences and mark them as dumpable if owning table is
    7751              :  *
    7752              :  * We used to do this in getTables(), but it's better to do it after the
    7753              :  * index used by findTableByOid() has been set up.
    7754              :  */
    7755              : void
    7756          259 : getOwnedSeqs(Archive *fout, TableInfo tblinfo[], int numTables)
    7757              : {
    7758              :     int         i;
    7759              : 
    7760              :     /*
    7761              :      * Force sequences that are "owned" by table columns to be dumped whenever
    7762              :      * their owning table is being dumped.
    7763              :      */
    7764        70986 :     for (i = 0; i < numTables; i++)
    7765              :     {
    7766        70727 :         TableInfo  *seqinfo = &tblinfo[i];
    7767              :         TableInfo  *owning_tab;
    7768              : 
    7769        70727 :         if (!OidIsValid(seqinfo->owning_tab))
    7770        70315 :             continue;           /* not an owned sequence */
    7771              : 
    7772          412 :         owning_tab = findTableByOid(seqinfo->owning_tab);
    7773          412 :         if (owning_tab == NULL)
    7774            0 :             pg_fatal("failed sanity check, parent table with OID %u of sequence with OID %u not found",
    7775              :                      seqinfo->owning_tab, seqinfo->dobj.catId.oid);
    7776              : 
    7777              :         /*
    7778              :          * For an identity sequence, dump exactly the same components for the
    7779              :          * sequence as for the owning table.  This is important because we
    7780              :          * treat the identity sequence as an integral part of the table.  For
    7781              :          * example, there is not any DDL command that allows creation of such
    7782              :          * a sequence independently of the table.
    7783              :          *
    7784              :          * For other owned sequences such as serial sequences, we need to dump
    7785              :          * the components that are being dumped for the table and any
    7786              :          * components that the sequence is explicitly marked with.
    7787              :          *
    7788              :          * We can't simply use the set of components which are being dumped
    7789              :          * for the table as the table might be in an extension (and only the
    7790              :          * non-extension components, eg: ACLs if changed, security labels, and
    7791              :          * policies, are being dumped) while the sequence is not (and
    7792              :          * therefore the definition and other components should also be
    7793              :          * dumped).
    7794              :          *
    7795              :          * If the sequence is part of the extension then it should be properly
    7796              :          * marked by checkExtensionMembership() and this will be a no-op as
    7797              :          * the table will be equivalently marked.
    7798              :          */
    7799          412 :         if (seqinfo->is_identity_sequence)
    7800          199 :             seqinfo->dobj.dump = owning_tab->dobj.dump;
    7801              :         else
    7802          213 :             seqinfo->dobj.dump |= owning_tab->dobj.dump;
    7803              : 
    7804              :         /* Make sure that necessary data is available if we're dumping it */
    7805          412 :         if (seqinfo->dobj.dump != DUMP_COMPONENT_NONE)
    7806              :         {
    7807          316 :             seqinfo->interesting = true;
    7808          316 :             owning_tab->interesting = true;
    7809              :         }
    7810              :     }
    7811          259 : }
    7812              : 
    7813              : /*
    7814              :  * getInherits
    7815              :  *    read all the inheritance information
    7816              :  * from the system catalogs return them in the InhInfo* structure
    7817              :  *
    7818              :  * numInherits is set to the number of pairs read in
    7819              :  */
    7820              : InhInfo *
    7821          259 : getInherits(Archive *fout, int *numInherits)
    7822              : {
    7823              :     PGresult   *res;
    7824              :     int         ntups;
    7825              :     int         i;
    7826          259 :     PQExpBuffer query = createPQExpBuffer();
    7827              :     InhInfo    *inhinfo;
    7828              : 
    7829              :     int         i_inhrelid;
    7830              :     int         i_inhparent;
    7831              : 
    7832              :     /* find all the inheritance information */
    7833          259 :     appendPQExpBufferStr(query, "SELECT inhrelid, inhparent FROM pg_inherits");
    7834              : 
    7835          259 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    7836              : 
    7837          259 :     ntups = PQntuples(res);
    7838              : 
    7839          259 :     *numInherits = ntups;
    7840              : 
    7841          259 :     inhinfo = pg_malloc_array(InhInfo, ntups);
    7842              : 
    7843          259 :     i_inhrelid = PQfnumber(res, "inhrelid");
    7844          259 :     i_inhparent = PQfnumber(res, "inhparent");
    7845              : 
    7846         3812 :     for (i = 0; i < ntups; i++)
    7847              :     {
    7848         3553 :         inhinfo[i].inhrelid = atooid(PQgetvalue(res, i, i_inhrelid));
    7849         3553 :         inhinfo[i].inhparent = atooid(PQgetvalue(res, i, i_inhparent));
    7850              :     }
    7851              : 
    7852          259 :     PQclear(res);
    7853              : 
    7854          259 :     destroyPQExpBuffer(query);
    7855              : 
    7856          259 :     return inhinfo;
    7857              : }
    7858              : 
    7859              : /*
    7860              :  * getPartitioningInfo
    7861              :  *    get information about partitioning
    7862              :  *
    7863              :  * For the most part, we only collect partitioning info about tables we
    7864              :  * intend to dump.  However, this function has to consider all partitioned
    7865              :  * tables in the database, because we need to know about parents of partitions
    7866              :  * we are going to dump even if the parents themselves won't be dumped.
    7867              :  *
    7868              :  * Specifically, what we need to know is whether each partitioned table
    7869              :  * has an "unsafe" partitioning scheme that requires us to force
    7870              :  * load-via-partition-root mode for its children.  Currently the only case
    7871              :  * for which we force that is hash partitioning on enum columns, since the
    7872              :  * hash codes depend on enum value OIDs which won't be replicated across
    7873              :  * dump-and-reload.  There are other cases in which load-via-partition-root
    7874              :  * might be necessary, but we expect users to cope with them.
    7875              :  */
    7876              : void
    7877          259 : getPartitioningInfo(Archive *fout)
    7878              : {
    7879              :     PQExpBuffer query;
    7880              :     PGresult   *res;
    7881              :     int         ntups;
    7882              : 
    7883              :     /* hash partitioning didn't exist before v11 */
    7884          259 :     if (fout->remoteVersion < 110000)
    7885            0 :         return;
    7886              :     /* needn't bother if not dumping data */
    7887          259 :     if (!fout->dopt->dumpData)
    7888           44 :         return;
    7889              : 
    7890          215 :     query = createPQExpBuffer();
    7891              : 
    7892              :     /*
    7893              :      * Unsafe partitioning schemes are exactly those for which hash enum_ops
    7894              :      * appears among the partition opclasses.  We needn't check partstrat.
    7895              :      *
    7896              :      * Note that this query may well retrieve info about tables we aren't
    7897              :      * going to dump and hence have no lock on.  That's okay since we need not
    7898              :      * invoke any unsafe server-side functions.
    7899              :      */
    7900          215 :     appendPQExpBufferStr(query,
    7901              :                          "SELECT partrelid FROM pg_partitioned_table WHERE\n"
    7902              :                          "(SELECT c.oid FROM pg_opclass c JOIN pg_am a "
    7903              :                          "ON c.opcmethod = a.oid\n"
    7904              :                          "WHERE opcname = 'enum_ops' "
    7905              :                          "AND opcnamespace = 'pg_catalog'::regnamespace "
    7906              :                          "AND amname = 'hash') = ANY(partclass)");
    7907              : 
    7908          215 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    7909              : 
    7910          215 :     ntups = PQntuples(res);
    7911              : 
    7912          258 :     for (int i = 0; i < ntups; i++)
    7913              :     {
    7914           43 :         Oid         tabrelid = atooid(PQgetvalue(res, i, 0));
    7915              :         TableInfo  *tbinfo;
    7916              : 
    7917           43 :         tbinfo = findTableByOid(tabrelid);
    7918           43 :         if (tbinfo == NULL)
    7919            0 :             pg_fatal("failed sanity check, table OID %u appearing in pg_partitioned_table not found",
    7920              :                      tabrelid);
    7921           43 :         tbinfo->unsafe_partitions = true;
    7922              :     }
    7923              : 
    7924          215 :     PQclear(res);
    7925              : 
    7926          215 :     destroyPQExpBuffer(query);
    7927              : }
    7928              : 
    7929              : /*
    7930              :  * getIndexes
    7931              :  *    get information about every index on a dumpable table
    7932              :  *
    7933              :  * Note: index data is not returned directly to the caller, but it
    7934              :  * does get entered into the DumpableObject tables.
    7935              :  */
    7936              : void
    7937          259 : getIndexes(Archive *fout, TableInfo tblinfo[], int numTables)
    7938              : {
    7939          259 :     PQExpBuffer query = createPQExpBuffer();
    7940          259 :     PQExpBuffer tbloids = createPQExpBuffer();
    7941              :     PGresult   *res;
    7942              :     int         ntups;
    7943              :     int         curtblindx;
    7944              :     IndxInfo   *indxinfo;
    7945              :     int         i_tableoid,
    7946              :                 i_oid,
    7947              :                 i_indrelid,
    7948              :                 i_indexname,
    7949              :                 i_relpages,
    7950              :                 i_reltuples,
    7951              :                 i_relallvisible,
    7952              :                 i_relallfrozen,
    7953              :                 i_parentidx,
    7954              :                 i_indexdef,
    7955              :                 i_indnkeyatts,
    7956              :                 i_indnatts,
    7957              :                 i_indkey,
    7958              :                 i_indisclustered,
    7959              :                 i_indisreplident,
    7960              :                 i_indnullsnotdistinct,
    7961              :                 i_contype,
    7962              :                 i_conname,
    7963              :                 i_condeferrable,
    7964              :                 i_condeferred,
    7965              :                 i_conperiod,
    7966              :                 i_contableoid,
    7967              :                 i_conoid,
    7968              :                 i_condef,
    7969              :                 i_indattnames,
    7970              :                 i_tablespace,
    7971              :                 i_indreloptions,
    7972              :                 i_indstatcols,
    7973              :                 i_indstatvals;
    7974              : 
    7975              :     /*
    7976              :      * We want to perform just one query against pg_index.  However, we
    7977              :      * mustn't try to select every row of the catalog and then sort it out on
    7978              :      * the client side, because some of the server-side functions we need
    7979              :      * would be unsafe to apply to tables we don't have lock on.  Hence, we
    7980              :      * build an array of the OIDs of tables we care about (and now have lock
    7981              :      * on!), and use a WHERE clause to constrain which rows are selected.
    7982              :      */
    7983          259 :     appendPQExpBufferChar(tbloids, '{');
    7984        70986 :     for (int i = 0; i < numTables; i++)
    7985              :     {
    7986        70727 :         TableInfo  *tbinfo = &tblinfo[i];
    7987              : 
    7988        70727 :         if (!tbinfo->hasindex)
    7989        50271 :             continue;
    7990              : 
    7991              :         /*
    7992              :          * We can ignore indexes of uninteresting tables.
    7993              :          */
    7994        20456 :         if (!tbinfo->interesting)
    7995        18299 :             continue;
    7996              : 
    7997              :         /* OK, we need info for this table */
    7998         2157 :         if (tbloids->len > 1) /* do we have more than the '{'? */
    7999         2078 :             appendPQExpBufferChar(tbloids, ',');
    8000         2157 :         appendPQExpBuffer(tbloids, "%u", tbinfo->dobj.catId.oid);
    8001              :     }
    8002          259 :     appendPQExpBufferChar(tbloids, '}');
    8003              : 
    8004          259 :     appendPQExpBufferStr(query,
    8005              :                          "SELECT t.tableoid, t.oid, i.indrelid, "
    8006              :                          "t.relname AS indexname, "
    8007              :                          "t.relpages, t.reltuples, t.relallvisible, ");
    8008              : 
    8009          259 :     if (fout->remoteVersion >= 180000)
    8010          259 :         appendPQExpBufferStr(query, "t.relallfrozen, ");
    8011              :     else
    8012            0 :         appendPQExpBufferStr(query, "0 AS relallfrozen, ");
    8013              : 
    8014          259 :     appendPQExpBufferStr(query,
    8015              :                          "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
    8016              :                          "i.indkey, i.indisclustered, "
    8017              :                          "c.contype, c.conname, "
    8018              :                          "c.condeferrable, c.condeferred, "
    8019              :                          "c.tableoid AS contableoid, "
    8020              :                          "c.oid AS conoid, "
    8021              :                          "pg_catalog.pg_get_constraintdef(c.oid, false) AS condef, "
    8022              :                          "CASE WHEN i.indexprs IS NOT NULL THEN "
    8023              :                          "(SELECT pg_catalog.array_agg(attname ORDER BY attnum)"
    8024              :                          "  FROM pg_catalog.pg_attribute "
    8025              :                          "  WHERE attrelid = i.indexrelid) "
    8026              :                          "ELSE NULL END AS indattnames, "
    8027              :                          "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
    8028              :                          "t.reloptions AS indreloptions, ");
    8029              : 
    8030              : 
    8031          259 :     if (fout->remoteVersion >= 90400)
    8032          259 :         appendPQExpBufferStr(query,
    8033              :                              "i.indisreplident, ");
    8034              :     else
    8035            0 :         appendPQExpBufferStr(query,
    8036              :                              "false AS indisreplident, ");
    8037              : 
    8038          259 :     if (fout->remoteVersion >= 110000)
    8039          259 :         appendPQExpBufferStr(query,
    8040              :                              "inh.inhparent AS parentidx, "
    8041              :                              "i.indnkeyatts AS indnkeyatts, "
    8042              :                              "i.indnatts AS indnatts, "
    8043              :                              "(SELECT pg_catalog.array_agg(attnum ORDER BY attnum) "
    8044              :                              "  FROM pg_catalog.pg_attribute "
    8045              :                              "  WHERE attrelid = i.indexrelid AND "
    8046              :                              "    attstattarget >= 0) AS indstatcols, "
    8047              :                              "(SELECT pg_catalog.array_agg(attstattarget ORDER BY attnum) "
    8048              :                              "  FROM pg_catalog.pg_attribute "
    8049              :                              "  WHERE attrelid = i.indexrelid AND "
    8050              :                              "    attstattarget >= 0) AS indstatvals, ");
    8051              :     else
    8052            0 :         appendPQExpBufferStr(query,
    8053              :                              "0 AS parentidx, "
    8054              :                              "i.indnatts AS indnkeyatts, "
    8055              :                              "i.indnatts AS indnatts, "
    8056              :                              "'' AS indstatcols, "
    8057              :                              "'' AS indstatvals, ");
    8058              : 
    8059          259 :     if (fout->remoteVersion >= 150000)
    8060          259 :         appendPQExpBufferStr(query,
    8061              :                              "i.indnullsnotdistinct, ");
    8062              :     else
    8063            0 :         appendPQExpBufferStr(query,
    8064              :                              "false AS indnullsnotdistinct, ");
    8065              : 
    8066          259 :     if (fout->remoteVersion >= 180000)
    8067          259 :         appendPQExpBufferStr(query,
    8068              :                              "c.conperiod ");
    8069              :     else
    8070            0 :         appendPQExpBufferStr(query,
    8071              :                              "NULL AS conperiod ");
    8072              : 
    8073              :     /*
    8074              :      * The point of the messy-looking outer join is to find a constraint that
    8075              :      * is related by an internal dependency link to the index. If we find one,
    8076              :      * create a CONSTRAINT entry linked to the INDEX entry.  We assume an
    8077              :      * index won't have more than one internal dependency.
    8078              :      *
    8079              :      * Note: the check on conrelid is redundant, but useful because that
    8080              :      * column is indexed while conindid is not.
    8081              :      */
    8082          259 :     if (fout->remoteVersion >= 110000)
    8083              :     {
    8084          259 :         appendPQExpBuffer(query,
    8085              :                           "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
    8086              :                           "JOIN pg_catalog.pg_index i ON (src.tbloid = i.indrelid) "
    8087              :                           "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
    8088              :                           "JOIN pg_catalog.pg_class t2 ON (t2.oid = i.indrelid) "
    8089              :                           "LEFT JOIN pg_catalog.pg_constraint c "
    8090              :                           "ON (i.indrelid = c.conrelid AND "
    8091              :                           "i.indexrelid = c.conindid AND "
    8092              :                           "c.contype IN ('p','u','x')) "
    8093              :                           "LEFT JOIN pg_catalog.pg_inherits inh "
    8094              :                           "ON (inh.inhrelid = indexrelid) "
    8095              :                           "WHERE (i.indisvalid OR t2.relkind = 'p') "
    8096              :                           "AND i.indisready "
    8097              :                           "ORDER BY i.indrelid, indexname",
    8098              :                           tbloids->data);
    8099              :     }
    8100              :     else
    8101              :     {
    8102              :         /*
    8103              :          * the test on indisready is necessary in 9.2, and harmless in
    8104              :          * earlier/later versions
    8105              :          */
    8106            0 :         appendPQExpBuffer(query,
    8107              :                           "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
    8108              :                           "JOIN pg_catalog.pg_index i ON (src.tbloid = i.indrelid) "
    8109              :                           "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
    8110              :                           "LEFT JOIN pg_catalog.pg_constraint c "
    8111              :                           "ON (i.indrelid = c.conrelid AND "
    8112              :                           "i.indexrelid = c.conindid AND "
    8113              :                           "c.contype IN ('p','u','x')) "
    8114              :                           "WHERE i.indisvalid AND i.indisready "
    8115              :                           "ORDER BY i.indrelid, indexname",
    8116              :                           tbloids->data);
    8117              :     }
    8118              : 
    8119          259 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    8120              : 
    8121          259 :     ntups = PQntuples(res);
    8122              : 
    8123          259 :     i_tableoid = PQfnumber(res, "tableoid");
    8124          259 :     i_oid = PQfnumber(res, "oid");
    8125          259 :     i_indrelid = PQfnumber(res, "indrelid");
    8126          259 :     i_indexname = PQfnumber(res, "indexname");
    8127          259 :     i_relpages = PQfnumber(res, "relpages");
    8128          259 :     i_reltuples = PQfnumber(res, "reltuples");
    8129          259 :     i_relallvisible = PQfnumber(res, "relallvisible");
    8130          259 :     i_relallfrozen = PQfnumber(res, "relallfrozen");
    8131          259 :     i_parentidx = PQfnumber(res, "parentidx");
    8132          259 :     i_indexdef = PQfnumber(res, "indexdef");
    8133          259 :     i_indnkeyatts = PQfnumber(res, "indnkeyatts");
    8134          259 :     i_indnatts = PQfnumber(res, "indnatts");
    8135          259 :     i_indkey = PQfnumber(res, "indkey");
    8136          259 :     i_indisclustered = PQfnumber(res, "indisclustered");
    8137          259 :     i_indisreplident = PQfnumber(res, "indisreplident");
    8138          259 :     i_indnullsnotdistinct = PQfnumber(res, "indnullsnotdistinct");
    8139          259 :     i_contype = PQfnumber(res, "contype");
    8140          259 :     i_conname = PQfnumber(res, "conname");
    8141          259 :     i_condeferrable = PQfnumber(res, "condeferrable");
    8142          259 :     i_condeferred = PQfnumber(res, "condeferred");
    8143          259 :     i_conperiod = PQfnumber(res, "conperiod");
    8144          259 :     i_contableoid = PQfnumber(res, "contableoid");
    8145          259 :     i_conoid = PQfnumber(res, "conoid");
    8146          259 :     i_condef = PQfnumber(res, "condef");
    8147          259 :     i_indattnames = PQfnumber(res, "indattnames");
    8148          259 :     i_tablespace = PQfnumber(res, "tablespace");
    8149          259 :     i_indreloptions = PQfnumber(res, "indreloptions");
    8150          259 :     i_indstatcols = PQfnumber(res, "indstatcols");
    8151          259 :     i_indstatvals = PQfnumber(res, "indstatvals");
    8152              : 
    8153          259 :     indxinfo = pg_malloc_array(IndxInfo, ntups);
    8154              : 
    8155              :     /*
    8156              :      * Outer loop iterates once per table, not once per row.  Incrementing of
    8157              :      * j is handled by the inner loop.
    8158              :      */
    8159          259 :     curtblindx = -1;
    8160         2396 :     for (int j = 0; j < ntups;)
    8161              :     {
    8162         2137 :         Oid         indrelid = atooid(PQgetvalue(res, j, i_indrelid));
    8163         2137 :         TableInfo  *tbinfo = NULL;
    8164         2137 :         char      **indAttNames = NULL;
    8165         2137 :         int         nindAttNames = 0;
    8166              :         int         numinds;
    8167              : 
    8168              :         /* Count rows for this table */
    8169         2777 :         for (numinds = 1; numinds < ntups - j; numinds++)
    8170         2698 :             if (atooid(PQgetvalue(res, j + numinds, i_indrelid)) != indrelid)
    8171         2058 :                 break;
    8172              : 
    8173              :         /*
    8174              :          * Locate the associated TableInfo; we rely on tblinfo[] being in OID
    8175              :          * order.
    8176              :          */
    8177        25241 :         while (++curtblindx < numTables)
    8178              :         {
    8179        25241 :             tbinfo = &tblinfo[curtblindx];
    8180        25241 :             if (tbinfo->dobj.catId.oid == indrelid)
    8181         2137 :                 break;
    8182              :         }
    8183         2137 :         if (curtblindx >= numTables)
    8184            0 :             pg_fatal("unrecognized table OID %u", indrelid);
    8185              :         /* cross-check that we only got requested tables */
    8186         2137 :         if (!tbinfo->hasindex ||
    8187         2137 :             !tbinfo->interesting)
    8188            0 :             pg_fatal("unexpected index data for table \"%s\"",
    8189              :                      tbinfo->dobj.name);
    8190              : 
    8191              :         /* Save data for this table */
    8192         2137 :         tbinfo->indexes = indxinfo + j;
    8193         2137 :         tbinfo->numIndexes = numinds;
    8194              : 
    8195         4914 :         for (int c = 0; c < numinds; c++, j++)
    8196              :         {
    8197              :             char        contype;
    8198              :             char        indexkind;
    8199              :             RelStatsInfo *relstats;
    8200         2777 :             int32       relpages = atoi(PQgetvalue(res, j, i_relpages));
    8201         2777 :             int32       relallvisible = atoi(PQgetvalue(res, j, i_relallvisible));
    8202         2777 :             int32       relallfrozen = atoi(PQgetvalue(res, j, i_relallfrozen));
    8203              : 
    8204         2777 :             indxinfo[j].dobj.objType = DO_INDEX;
    8205         2777 :             indxinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
    8206         2777 :             indxinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
    8207         2777 :             AssignDumpId(&indxinfo[j].dobj);
    8208         2777 :             indxinfo[j].dobj.dump = tbinfo->dobj.dump;
    8209         2777 :             indxinfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_indexname));
    8210         2777 :             indxinfo[j].dobj.namespace = tbinfo->dobj.namespace;
    8211         2777 :             indxinfo[j].indextable = tbinfo;
    8212         2777 :             indxinfo[j].indexdef = pg_strdup(PQgetvalue(res, j, i_indexdef));
    8213         2777 :             indxinfo[j].indnkeyattrs = atoi(PQgetvalue(res, j, i_indnkeyatts));
    8214         2777 :             indxinfo[j].indnattrs = atoi(PQgetvalue(res, j, i_indnatts));
    8215         2777 :             indxinfo[j].tablespace = pg_strdup(PQgetvalue(res, j, i_tablespace));
    8216         2777 :             indxinfo[j].indreloptions = pg_strdup(PQgetvalue(res, j, i_indreloptions));
    8217         2777 :             indxinfo[j].indstatcols = pg_strdup(PQgetvalue(res, j, i_indstatcols));
    8218         2777 :             indxinfo[j].indstatvals = pg_strdup(PQgetvalue(res, j, i_indstatvals));
    8219         2777 :             indxinfo[j].indkeys = pg_malloc_array(Oid, indxinfo[j].indnattrs);
    8220         2777 :             parseOidArray(PQgetvalue(res, j, i_indkey),
    8221         2777 :                           indxinfo[j].indkeys, indxinfo[j].indnattrs);
    8222         2777 :             indxinfo[j].indisclustered = (PQgetvalue(res, j, i_indisclustered)[0] == 't');
    8223         2777 :             indxinfo[j].indisreplident = (PQgetvalue(res, j, i_indisreplident)[0] == 't');
    8224         2777 :             indxinfo[j].indnullsnotdistinct = (PQgetvalue(res, j, i_indnullsnotdistinct)[0] == 't');
    8225         2777 :             indxinfo[j].parentidx = atooid(PQgetvalue(res, j, i_parentidx));
    8226         2777 :             indxinfo[j].partattaches = (SimplePtrList)
    8227              :             {
    8228              :                 NULL, NULL
    8229              :             };
    8230              : 
    8231         2777 :             if (indxinfo[j].parentidx == 0)
    8232         2183 :                 indexkind = RELKIND_INDEX;
    8233              :             else
    8234          594 :                 indexkind = RELKIND_PARTITIONED_INDEX;
    8235              : 
    8236         2777 :             if (!PQgetisnull(res, j, i_indattnames))
    8237              :             {
    8238          146 :                 if (!parsePGArray(PQgetvalue(res, j, i_indattnames),
    8239              :                                   &indAttNames, &nindAttNames))
    8240            0 :                     pg_fatal("could not parse %s array", "indattnames");
    8241              :             }
    8242              : 
    8243         2777 :             relstats = getRelationStatistics(fout, &indxinfo[j].dobj, relpages,
    8244              :                                              PQgetvalue(res, j, i_reltuples),
    8245              :                                              relallvisible, relallfrozen, indexkind,
    8246              :                                              indAttNames, nindAttNames);
    8247              : 
    8248         2777 :             contype = *(PQgetvalue(res, j, i_contype));
    8249         2777 :             if (contype == 'p' || contype == 'u' || contype == 'x')
    8250         1682 :             {
    8251              :                 /*
    8252              :                  * If we found a constraint matching the index, create an
    8253              :                  * entry for it.
    8254              :                  */
    8255              :                 ConstraintInfo *constrinfo;
    8256              : 
    8257         1682 :                 constrinfo = pg_malloc_object(ConstraintInfo);
    8258         1682 :                 constrinfo->dobj.objType = DO_CONSTRAINT;
    8259         1682 :                 constrinfo->dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_contableoid));
    8260         1682 :                 constrinfo->dobj.catId.oid = atooid(PQgetvalue(res, j, i_conoid));
    8261         1682 :                 AssignDumpId(&constrinfo->dobj);
    8262         1682 :                 constrinfo->dobj.dump = tbinfo->dobj.dump;
    8263         1682 :                 constrinfo->dobj.name = pg_strdup(PQgetvalue(res, j, i_conname));
    8264         1682 :                 constrinfo->dobj.namespace = tbinfo->dobj.namespace;
    8265         1682 :                 constrinfo->contable = tbinfo;
    8266         1682 :                 constrinfo->condomain = NULL;
    8267         1682 :                 constrinfo->contype = contype;
    8268         1682 :                 if (contype == 'x')
    8269           10 :                     constrinfo->condef = pg_strdup(PQgetvalue(res, j, i_condef));
    8270              :                 else
    8271         1672 :                     constrinfo->condef = NULL;
    8272         1682 :                 constrinfo->confrelid = InvalidOid;
    8273         1682 :                 constrinfo->conindex = indxinfo[j].dobj.dumpId;
    8274         1682 :                 constrinfo->condeferrable = *(PQgetvalue(res, j, i_condeferrable)) == 't';
    8275         1682 :                 constrinfo->condeferred = *(PQgetvalue(res, j, i_condeferred)) == 't';
    8276         1682 :                 constrinfo->conperiod = *(PQgetvalue(res, j, i_conperiod)) == 't';
    8277         1682 :                 constrinfo->conislocal = true;
    8278         1682 :                 constrinfo->separate = true;
    8279              : 
    8280         1682 :                 indxinfo[j].indexconstraint = constrinfo->dobj.dumpId;
    8281         1682 :                 if (relstats != NULL)
    8282          557 :                     addObjectDependency(&relstats->dobj, constrinfo->dobj.dumpId);
    8283              :             }
    8284              :             else
    8285              :             {
    8286              :                 /* Plain secondary index */
    8287         1095 :                 indxinfo[j].indexconstraint = 0;
    8288              :             }
    8289              :         }
    8290              :     }
    8291              : 
    8292          259 :     PQclear(res);
    8293              : 
    8294          259 :     destroyPQExpBuffer(query);
    8295          259 :     destroyPQExpBuffer(tbloids);
    8296          259 : }
    8297              : 
    8298              : /*
    8299              :  * getExtendedStatistics
    8300              :  *    get information about extended-statistics objects.
    8301              :  *
    8302              :  * Note: extended statistics data is not returned directly to the caller, but
    8303              :  * it does get entered into the DumpableObject tables.
    8304              :  */
    8305              : void
    8306          259 : getExtendedStatistics(Archive *fout)
    8307              : {
    8308              :     PQExpBuffer query;
    8309              :     PGresult   *res;
    8310              :     StatsExtInfo *statsextinfo;
    8311              :     int         ntups;
    8312              :     int         i_tableoid;
    8313              :     int         i_oid;
    8314              :     int         i_stxname;
    8315              :     int         i_stxnamespace;
    8316              :     int         i_stxowner;
    8317              :     int         i_stxrelid;
    8318              :     int         i_stattarget;
    8319              :     int         i;
    8320              : 
    8321              :     /* Extended statistics were new in v10 */
    8322          259 :     if (fout->remoteVersion < 100000)
    8323            0 :         return;
    8324              : 
    8325          259 :     query = createPQExpBuffer();
    8326              : 
    8327          259 :     if (fout->remoteVersion < 130000)
    8328            0 :         appendPQExpBufferStr(query, "SELECT tableoid, oid, stxname, "
    8329              :                              "stxnamespace, stxowner, stxrelid, NULL AS stxstattarget "
    8330              :                              "FROM pg_catalog.pg_statistic_ext");
    8331              :     else
    8332          259 :         appendPQExpBufferStr(query, "SELECT tableoid, oid, stxname, "
    8333              :                              "stxnamespace, stxowner, stxrelid, stxstattarget "
    8334              :                              "FROM pg_catalog.pg_statistic_ext");
    8335              : 
    8336          259 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    8337              : 
    8338          259 :     ntups = PQntuples(res);
    8339              : 
    8340          259 :     i_tableoid = PQfnumber(res, "tableoid");
    8341          259 :     i_oid = PQfnumber(res, "oid");
    8342          259 :     i_stxname = PQfnumber(res, "stxname");
    8343          259 :     i_stxnamespace = PQfnumber(res, "stxnamespace");
    8344          259 :     i_stxowner = PQfnumber(res, "stxowner");
    8345          259 :     i_stxrelid = PQfnumber(res, "stxrelid");
    8346          259 :     i_stattarget = PQfnumber(res, "stxstattarget");
    8347              : 
    8348          259 :     statsextinfo = pg_malloc_array(StatsExtInfo, ntups);
    8349              : 
    8350          467 :     for (i = 0; i < ntups; i++)
    8351              :     {
    8352          208 :         statsextinfo[i].dobj.objType = DO_STATSEXT;
    8353          208 :         statsextinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    8354          208 :         statsextinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    8355          208 :         AssignDumpId(&statsextinfo[i].dobj);
    8356          208 :         statsextinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_stxname));
    8357          416 :         statsextinfo[i].dobj.namespace =
    8358          208 :             findNamespace(atooid(PQgetvalue(res, i, i_stxnamespace)));
    8359          208 :         statsextinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_stxowner));
    8360          416 :         statsextinfo[i].stattable =
    8361          208 :             findTableByOid(atooid(PQgetvalue(res, i, i_stxrelid)));
    8362          208 :         if (PQgetisnull(res, i, i_stattarget))
    8363          163 :             statsextinfo[i].stattarget = -1;
    8364              :         else
    8365           45 :             statsextinfo[i].stattarget = atoi(PQgetvalue(res, i, i_stattarget));
    8366              : 
    8367              :         /* Decide whether we want to dump it */
    8368          208 :         selectDumpableStatisticsObject(&(statsextinfo[i]), fout);
    8369              : 
    8370          208 :         if (fout->dopt->dumpStatistics)
    8371          152 :             statsextinfo[i].dobj.components |= DUMP_COMPONENT_STATISTICS;
    8372              :     }
    8373              : 
    8374          259 :     PQclear(res);
    8375          259 :     destroyPQExpBuffer(query);
    8376              : }
    8377              : 
    8378              : /*
    8379              :  * getConstraints
    8380              :  *
    8381              :  * Get info about constraints on dumpable tables.
    8382              :  *
    8383              :  * Currently handles foreign keys only.
    8384              :  * Unique and primary key constraints are handled with indexes,
    8385              :  * while check constraints are processed in getTableAttrs().
    8386              :  */
    8387              : void
    8388          259 : getConstraints(Archive *fout, TableInfo tblinfo[], int numTables)
    8389              : {
    8390          259 :     PQExpBuffer query = createPQExpBuffer();
    8391          259 :     PQExpBuffer tbloids = createPQExpBuffer();
    8392              :     PGresult   *res;
    8393              :     int         ntups;
    8394              :     int         curtblindx;
    8395          259 :     TableInfo  *tbinfo = NULL;
    8396              :     ConstraintInfo *constrinfo;
    8397              :     int         i_contableoid,
    8398              :                 i_conoid,
    8399              :                 i_conrelid,
    8400              :                 i_conname,
    8401              :                 i_confrelid,
    8402              :                 i_conindid,
    8403              :                 i_condef;
    8404              : 
    8405              :     /*
    8406              :      * We want to perform just one query against pg_constraint.  However, we
    8407              :      * mustn't try to select every row of the catalog and then sort it out on
    8408              :      * the client side, because some of the server-side functions we need
    8409              :      * would be unsafe to apply to tables we don't have lock on.  Hence, we
    8410              :      * build an array of the OIDs of tables we care about (and now have lock
    8411              :      * on!), and use a WHERE clause to constrain which rows are selected.
    8412              :      */
    8413          259 :     appendPQExpBufferChar(tbloids, '{');
    8414        70986 :     for (int i = 0; i < numTables; i++)
    8415              :     {
    8416        70727 :         TableInfo  *tinfo = &tblinfo[i];
    8417              : 
    8418        70727 :         if (!(tinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
    8419        63102 :             continue;
    8420              : 
    8421              :         /* OK, we need info for this table */
    8422         7625 :         if (tbloids->len > 1) /* do we have more than the '{'? */
    8423         7447 :             appendPQExpBufferChar(tbloids, ',');
    8424         7625 :         appendPQExpBuffer(tbloids, "%u", tinfo->dobj.catId.oid);
    8425              :     }
    8426          259 :     appendPQExpBufferChar(tbloids, '}');
    8427              : 
    8428          259 :     appendPQExpBufferStr(query,
    8429              :                          "SELECT c.tableoid, c.oid, "
    8430              :                          "conrelid, conname, confrelid, ");
    8431          259 :     if (fout->remoteVersion >= 110000)
    8432          259 :         appendPQExpBufferStr(query, "conindid, ");
    8433              :     else
    8434            0 :         appendPQExpBufferStr(query, "0 AS conindid, ");
    8435          259 :     appendPQExpBuffer(query,
    8436              :                       "pg_catalog.pg_get_constraintdef(c.oid) AS condef\n"
    8437              :                       "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
    8438              :                       "JOIN pg_catalog.pg_constraint c ON (src.tbloid = c.conrelid)\n"
    8439              :                       "WHERE contype = 'f' ",
    8440              :                       tbloids->data);
    8441          259 :     if (fout->remoteVersion >= 110000)
    8442          259 :         appendPQExpBufferStr(query,
    8443              :                              "AND conparentid = 0 ");
    8444          259 :     appendPQExpBufferStr(query,
    8445              :                          "ORDER BY conrelid, conname");
    8446              : 
    8447          259 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    8448              : 
    8449          259 :     ntups = PQntuples(res);
    8450              : 
    8451          259 :     i_contableoid = PQfnumber(res, "tableoid");
    8452          259 :     i_conoid = PQfnumber(res, "oid");
    8453          259 :     i_conrelid = PQfnumber(res, "conrelid");
    8454          259 :     i_conname = PQfnumber(res, "conname");
    8455          259 :     i_confrelid = PQfnumber(res, "confrelid");
    8456          259 :     i_conindid = PQfnumber(res, "conindid");
    8457          259 :     i_condef = PQfnumber(res, "condef");
    8458              : 
    8459          259 :     constrinfo = pg_malloc_array(ConstraintInfo, ntups);
    8460              : 
    8461          259 :     curtblindx = -1;
    8462          490 :     for (int j = 0; j < ntups; j++)
    8463              :     {
    8464          231 :         Oid         conrelid = atooid(PQgetvalue(res, j, i_conrelid));
    8465              :         TableInfo  *reftable;
    8466              : 
    8467              :         /*
    8468              :          * Locate the associated TableInfo; we rely on tblinfo[] being in OID
    8469              :          * order.
    8470              :          */
    8471          231 :         if (tbinfo == NULL || tbinfo->dobj.catId.oid != conrelid)
    8472              :         {
    8473        15665 :             while (++curtblindx < numTables)
    8474              :             {
    8475        15665 :                 tbinfo = &tblinfo[curtblindx];
    8476        15665 :                 if (tbinfo->dobj.catId.oid == conrelid)
    8477          191 :                     break;
    8478              :             }
    8479          191 :             if (curtblindx >= numTables)
    8480            0 :                 pg_fatal("unrecognized table OID %u", conrelid);
    8481              :         }
    8482              : 
    8483          231 :         constrinfo[j].dobj.objType = DO_FK_CONSTRAINT;
    8484          231 :         constrinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_contableoid));
    8485          231 :         constrinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_conoid));
    8486          231 :         AssignDumpId(&constrinfo[j].dobj);
    8487          231 :         constrinfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_conname));
    8488          231 :         constrinfo[j].dobj.namespace = tbinfo->dobj.namespace;
    8489          231 :         constrinfo[j].contable = tbinfo;
    8490          231 :         constrinfo[j].condomain = NULL;
    8491          231 :         constrinfo[j].contype = 'f';
    8492          231 :         constrinfo[j].condef = pg_strdup(PQgetvalue(res, j, i_condef));
    8493          231 :         constrinfo[j].confrelid = atooid(PQgetvalue(res, j, i_confrelid));
    8494          231 :         constrinfo[j].conindex = 0;
    8495          231 :         constrinfo[j].condeferrable = false;
    8496          231 :         constrinfo[j].condeferred = false;
    8497          231 :         constrinfo[j].conislocal = true;
    8498          231 :         constrinfo[j].separate = true;
    8499              : 
    8500              :         /*
    8501              :          * Restoring an FK that points to a partitioned table requires that
    8502              :          * all partition indexes have been attached beforehand. Ensure that
    8503              :          * happens by making the constraint depend on each index partition
    8504              :          * attach object.
    8505              :          */
    8506          231 :         reftable = findTableByOid(constrinfo[j].confrelid);
    8507          231 :         if (reftable && reftable->relkind == RELKIND_PARTITIONED_TABLE)
    8508              :         {
    8509           30 :             Oid         indexOid = atooid(PQgetvalue(res, j, i_conindid));
    8510              : 
    8511           30 :             if (indexOid != InvalidOid)
    8512              :             {
    8513           30 :                 for (int k = 0; k < reftable->numIndexes; k++)
    8514              :                 {
    8515              :                     IndxInfo   *refidx;
    8516              : 
    8517              :                     /* not our index? */
    8518           30 :                     if (reftable->indexes[k].dobj.catId.oid != indexOid)
    8519            0 :                         continue;
    8520              : 
    8521           30 :                     refidx = &reftable->indexes[k];
    8522           30 :                     addConstrChildIdxDeps(&constrinfo[j].dobj, refidx);
    8523           30 :                     break;
    8524              :                 }
    8525              :             }
    8526              :         }
    8527              :     }
    8528              : 
    8529          259 :     PQclear(res);
    8530              : 
    8531          259 :     destroyPQExpBuffer(query);
    8532          259 :     destroyPQExpBuffer(tbloids);
    8533          259 : }
    8534              : 
    8535              : /*
    8536              :  * addConstrChildIdxDeps
    8537              :  *
    8538              :  * Recursive subroutine for getConstraints
    8539              :  *
    8540              :  * Given an object representing a foreign key constraint and an index on the
    8541              :  * partitioned table it references, mark the constraint object as dependent
    8542              :  * on the DO_INDEX_ATTACH object of each index partition, recursively
    8543              :  * drilling down to their partitions if any.  This ensures that the FK is not
    8544              :  * restored until the index is fully marked valid.
    8545              :  */
    8546              : static void
    8547           55 : addConstrChildIdxDeps(DumpableObject *dobj, const IndxInfo *refidx)
    8548              : {
    8549              :     SimplePtrListCell *cell;
    8550              : 
    8551              :     Assert(dobj->objType == DO_FK_CONSTRAINT);
    8552              : 
    8553          185 :     for (cell = refidx->partattaches.head; cell; cell = cell->next)
    8554              :     {
    8555          130 :         IndexAttachInfo *attach = (IndexAttachInfo *) cell->ptr;
    8556              : 
    8557          130 :         addObjectDependency(dobj, attach->dobj.dumpId);
    8558              : 
    8559          130 :         if (attach->partitionIdx->partattaches.head != NULL)
    8560           25 :             addConstrChildIdxDeps(dobj, attach->partitionIdx);
    8561              :     }
    8562           55 : }
    8563              : 
    8564              : /*
    8565              :  * getDomainConstraints
    8566              :  *
    8567              :  * Get info about constraints on a domain.
    8568              :  */
    8569              : static void
    8570          178 : getDomainConstraints(Archive *fout, TypeInfo *tyinfo)
    8571              : {
    8572              :     ConstraintInfo *constrinfo;
    8573          178 :     PQExpBuffer query = createPQExpBuffer();
    8574              :     PGresult   *res;
    8575              :     int         i_tableoid,
    8576              :                 i_oid,
    8577              :                 i_conname,
    8578              :                 i_consrc,
    8579              :                 i_convalidated,
    8580              :                 i_contype;
    8581              :     int         ntups;
    8582              : 
    8583          178 :     if (!fout->is_prepared[PREPQUERY_GETDOMAINCONSTRAINTS])
    8584              :     {
    8585              :         /*
    8586              :          * Set up query for constraint-specific details.  For servers 17 and
    8587              :          * up, domains have constraints of type 'n' as well as 'c', otherwise
    8588              :          * just the latter.
    8589              :          */
    8590           43 :         appendPQExpBuffer(query,
    8591              :                           "PREPARE getDomainConstraints(pg_catalog.oid) AS\n"
    8592              :                           "SELECT tableoid, oid, conname, "
    8593              :                           "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
    8594              :                           "convalidated, contype "
    8595              :                           "FROM pg_catalog.pg_constraint "
    8596              :                           "WHERE contypid = $1 AND contype IN (%s) "
    8597              :                           "ORDER BY conname",
    8598           43 :                           fout->remoteVersion < 170000 ? "'c'" : "'c', 'n'");
    8599              : 
    8600           43 :         ExecuteSqlStatement(fout, query->data);
    8601              : 
    8602           43 :         fout->is_prepared[PREPQUERY_GETDOMAINCONSTRAINTS] = true;
    8603              :     }
    8604              : 
    8605          178 :     printfPQExpBuffer(query,
    8606              :                       "EXECUTE getDomainConstraints('%u')",
    8607              :                       tyinfo->dobj.catId.oid);
    8608              : 
    8609          178 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    8610              : 
    8611          178 :     ntups = PQntuples(res);
    8612              : 
    8613          178 :     i_tableoid = PQfnumber(res, "tableoid");
    8614          178 :     i_oid = PQfnumber(res, "oid");
    8615          178 :     i_conname = PQfnumber(res, "conname");
    8616          178 :     i_consrc = PQfnumber(res, "consrc");
    8617          178 :     i_convalidated = PQfnumber(res, "convalidated");
    8618          178 :     i_contype = PQfnumber(res, "contype");
    8619              : 
    8620          178 :     constrinfo = pg_malloc_array(ConstraintInfo, ntups);
    8621          178 :     tyinfo->domChecks = constrinfo;
    8622              : 
    8623              :     /* 'i' tracks result rows; 'j' counts CHECK constraints */
    8624          364 :     for (int i = 0, j = 0; i < ntups; i++)
    8625              :     {
    8626          186 :         bool        validated = PQgetvalue(res, i, i_convalidated)[0] == 't';
    8627          186 :         char        contype = (PQgetvalue(res, i, i_contype))[0];
    8628              :         ConstraintInfo *constraint;
    8629              : 
    8630          186 :         if (contype == CONSTRAINT_CHECK)
    8631              :         {
    8632          133 :             constraint = &constrinfo[j++];
    8633          133 :             tyinfo->nDomChecks++;
    8634              :         }
    8635              :         else
    8636              :         {
    8637              :             Assert(contype == CONSTRAINT_NOTNULL);
    8638              :             Assert(tyinfo->notnull == NULL);
    8639              :             /* use last item in array for the not-null constraint */
    8640           53 :             tyinfo->notnull = &(constrinfo[ntups - 1]);
    8641           53 :             constraint = tyinfo->notnull;
    8642              :         }
    8643              : 
    8644          186 :         constraint->dobj.objType = DO_CONSTRAINT;
    8645          186 :         constraint->dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    8646          186 :         constraint->dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    8647          186 :         AssignDumpId(&(constraint->dobj));
    8648          186 :         constraint->dobj.name = pg_strdup(PQgetvalue(res, i, i_conname));
    8649          186 :         constraint->dobj.namespace = tyinfo->dobj.namespace;
    8650          186 :         constraint->contable = NULL;
    8651          186 :         constraint->condomain = tyinfo;
    8652          186 :         constraint->contype = contype;
    8653          186 :         constraint->condef = pg_strdup(PQgetvalue(res, i, i_consrc));
    8654          186 :         constraint->confrelid = InvalidOid;
    8655          186 :         constraint->conindex = 0;
    8656          186 :         constraint->condeferrable = false;
    8657          186 :         constraint->condeferred = false;
    8658          186 :         constraint->conislocal = true;
    8659              : 
    8660          186 :         constraint->separate = !validated;
    8661              : 
    8662              :         /*
    8663              :          * Make the domain depend on the constraint, ensuring it won't be
    8664              :          * output till any constraint dependencies are OK.  If the constraint
    8665              :          * has not been validated, it's going to be dumped after the domain
    8666              :          * anyway, so this doesn't matter.
    8667              :          */
    8668          186 :         if (validated)
    8669          181 :             addObjectDependency(&tyinfo->dobj, constraint->dobj.dumpId);
    8670              :     }
    8671              : 
    8672          178 :     PQclear(res);
    8673              : 
    8674          178 :     destroyPQExpBuffer(query);
    8675          178 : }
    8676              : 
    8677              : /*
    8678              :  * getRules
    8679              :  *    get basic information about every rule in the system
    8680              :  */
    8681              : void
    8682          259 : getRules(Archive *fout)
    8683              : {
    8684              :     PGresult   *res;
    8685              :     int         ntups;
    8686              :     int         i;
    8687          259 :     PQExpBuffer query = createPQExpBuffer();
    8688              :     RuleInfo   *ruleinfo;
    8689              :     int         i_tableoid;
    8690              :     int         i_oid;
    8691              :     int         i_rulename;
    8692              :     int         i_ruletable;
    8693              :     int         i_ev_type;
    8694              :     int         i_is_instead;
    8695              :     int         i_ev_enabled;
    8696              : 
    8697          259 :     appendPQExpBufferStr(query, "SELECT "
    8698              :                          "tableoid, oid, rulename, "
    8699              :                          "ev_class AS ruletable, ev_type, is_instead, "
    8700              :                          "ev_enabled "
    8701              :                          "FROM pg_rewrite "
    8702              :                          "ORDER BY oid");
    8703              : 
    8704          259 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    8705              : 
    8706          259 :     ntups = PQntuples(res);
    8707              : 
    8708          259 :     ruleinfo = pg_malloc_array(RuleInfo, ntups);
    8709              : 
    8710          259 :     i_tableoid = PQfnumber(res, "tableoid");
    8711          259 :     i_oid = PQfnumber(res, "oid");
    8712          259 :     i_rulename = PQfnumber(res, "rulename");
    8713          259 :     i_ruletable = PQfnumber(res, "ruletable");
    8714          259 :     i_ev_type = PQfnumber(res, "ev_type");
    8715          259 :     i_is_instead = PQfnumber(res, "is_instead");
    8716          259 :     i_ev_enabled = PQfnumber(res, "ev_enabled");
    8717              : 
    8718        43906 :     for (i = 0; i < ntups; i++)
    8719              :     {
    8720              :         Oid         ruletableoid;
    8721              : 
    8722        43647 :         ruleinfo[i].dobj.objType = DO_RULE;
    8723        43647 :         ruleinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    8724        43647 :         ruleinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    8725        43647 :         AssignDumpId(&ruleinfo[i].dobj);
    8726        43647 :         ruleinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_rulename));
    8727        43647 :         ruletableoid = atooid(PQgetvalue(res, i, i_ruletable));
    8728        43647 :         ruleinfo[i].ruletable = findTableByOid(ruletableoid);
    8729        43647 :         if (ruleinfo[i].ruletable == NULL)
    8730            0 :             pg_fatal("failed sanity check, parent table with OID %u of pg_rewrite entry with OID %u not found",
    8731              :                      ruletableoid, ruleinfo[i].dobj.catId.oid);
    8732        43647 :         ruleinfo[i].dobj.namespace = ruleinfo[i].ruletable->dobj.namespace;
    8733        43647 :         ruleinfo[i].dobj.dump = ruleinfo[i].ruletable->dobj.dump;
    8734        43647 :         ruleinfo[i].ev_type = *(PQgetvalue(res, i, i_ev_type));
    8735        43647 :         ruleinfo[i].is_instead = *(PQgetvalue(res, i, i_is_instead)) == 't';
    8736        43647 :         ruleinfo[i].ev_enabled = *(PQgetvalue(res, i, i_ev_enabled));
    8737        43647 :         if (ruleinfo[i].ruletable)
    8738              :         {
    8739              :             /*
    8740              :              * If the table is a view or materialized view, force its ON
    8741              :              * SELECT rule to be sorted before the view itself --- this
    8742              :              * ensures that any dependencies for the rule affect the table's
    8743              :              * positioning. Other rules are forced to appear after their
    8744              :              * table.
    8745              :              */
    8746        43647 :             if ((ruleinfo[i].ruletable->relkind == RELKIND_VIEW ||
    8747          699 :                  ruleinfo[i].ruletable->relkind == RELKIND_MATVIEW) &&
    8748        43416 :                 ruleinfo[i].ev_type == '1' && ruleinfo[i].is_instead)
    8749              :             {
    8750        42856 :                 addObjectDependency(&ruleinfo[i].ruletable->dobj,
    8751        42856 :                                     ruleinfo[i].dobj.dumpId);
    8752              :                 /* We'll merge the rule into CREATE VIEW, if possible */
    8753        42856 :                 ruleinfo[i].separate = false;
    8754              :             }
    8755              :             else
    8756              :             {
    8757          791 :                 addObjectDependency(&ruleinfo[i].dobj,
    8758          791 :                                     ruleinfo[i].ruletable->dobj.dumpId);
    8759          791 :                 ruleinfo[i].separate = true;
    8760              :             }
    8761              :         }
    8762              :         else
    8763            0 :             ruleinfo[i].separate = true;
    8764              :     }
    8765              : 
    8766          259 :     PQclear(res);
    8767              : 
    8768          259 :     destroyPQExpBuffer(query);
    8769          259 : }
    8770              : 
    8771              : /*
    8772              :  * getTriggers
    8773              :  *    get information about every trigger on a dumpable table
    8774              :  *
    8775              :  * Note: trigger data is not returned directly to the caller, but it
    8776              :  * does get entered into the DumpableObject tables.
    8777              :  */
    8778              : void
    8779          259 : getTriggers(Archive *fout, TableInfo tblinfo[], int numTables)
    8780              : {
    8781          259 :     PQExpBuffer query = createPQExpBuffer();
    8782          259 :     PQExpBuffer tbloids = createPQExpBuffer();
    8783              :     PGresult   *res;
    8784              :     int         ntups;
    8785              :     int         curtblindx;
    8786              :     TriggerInfo *tginfo;
    8787              :     int         i_tableoid,
    8788              :                 i_oid,
    8789              :                 i_tgrelid,
    8790              :                 i_tgname,
    8791              :                 i_tgenabled,
    8792              :                 i_tgispartition,
    8793              :                 i_tgdef;
    8794              : 
    8795              :     /*
    8796              :      * We want to perform just one query against pg_trigger.  However, we
    8797              :      * mustn't try to select every row of the catalog and then sort it out on
    8798              :      * the client side, because some of the server-side functions we need
    8799              :      * would be unsafe to apply to tables we don't have lock on.  Hence, we
    8800              :      * build an array of the OIDs of tables we care about (and now have lock
    8801              :      * on!), and use a WHERE clause to constrain which rows are selected.
    8802              :      */
    8803          259 :     appendPQExpBufferChar(tbloids, '{');
    8804        70986 :     for (int i = 0; i < numTables; i++)
    8805              :     {
    8806        70727 :         TableInfo  *tbinfo = &tblinfo[i];
    8807              : 
    8808        70727 :         if (!tbinfo->hastriggers ||
    8809         1233 :             !(tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
    8810        69790 :             continue;
    8811              : 
    8812              :         /* OK, we need info for this table */
    8813          937 :         if (tbloids->len > 1) /* do we have more than the '{'? */
    8814          886 :             appendPQExpBufferChar(tbloids, ',');
    8815          937 :         appendPQExpBuffer(tbloids, "%u", tbinfo->dobj.catId.oid);
    8816              :     }
    8817          259 :     appendPQExpBufferChar(tbloids, '}');
    8818              : 
    8819          259 :     if (fout->remoteVersion >= 150000)
    8820              :     {
    8821              :         /*
    8822              :          * NB: think not to use pretty=true in pg_get_triggerdef.  It could
    8823              :          * result in non-forward-compatible dumps of WHEN clauses due to
    8824              :          * under-parenthesization.
    8825              :          *
    8826              :          * NB: We need to see partition triggers in case the tgenabled flag
    8827              :          * has been changed from the parent.
    8828              :          */
    8829          259 :         appendPQExpBuffer(query,
    8830              :                           "SELECT t.tgrelid, t.tgname, "
    8831              :                           "pg_catalog.pg_get_triggerdef(t.oid, false) AS tgdef, "
    8832              :                           "t.tgenabled, t.tableoid, t.oid, "
    8833              :                           "t.tgparentid <> 0 AS tgispartition\n"
    8834              :                           "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
    8835              :                           "JOIN pg_catalog.pg_trigger t ON (src.tbloid = t.tgrelid) "
    8836              :                           "LEFT JOIN pg_catalog.pg_trigger u ON (u.oid = t.tgparentid) "
    8837              :                           "WHERE ((NOT t.tgisinternal AND t.tgparentid = 0) "
    8838              :                           "OR t.tgenabled != u.tgenabled) "
    8839              :                           "ORDER BY t.tgrelid, t.tgname",
    8840              :                           tbloids->data);
    8841              :     }
    8842            0 :     else if (fout->remoteVersion >= 130000)
    8843              :     {
    8844              :         /*
    8845              :          * NB: think not to use pretty=true in pg_get_triggerdef.  It could
    8846              :          * result in non-forward-compatible dumps of WHEN clauses due to
    8847              :          * under-parenthesization.
    8848              :          *
    8849              :          * NB: We need to see tgisinternal triggers in partitions, in case the
    8850              :          * tgenabled flag has been changed from the parent.
    8851              :          */
    8852            0 :         appendPQExpBuffer(query,
    8853              :                           "SELECT t.tgrelid, t.tgname, "
    8854              :                           "pg_catalog.pg_get_triggerdef(t.oid, false) AS tgdef, "
    8855              :                           "t.tgenabled, t.tableoid, t.oid, t.tgisinternal as tgispartition\n"
    8856              :                           "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
    8857              :                           "JOIN pg_catalog.pg_trigger t ON (src.tbloid = t.tgrelid) "
    8858              :                           "LEFT JOIN pg_catalog.pg_trigger u ON (u.oid = t.tgparentid) "
    8859              :                           "WHERE (NOT t.tgisinternal OR t.tgenabled != u.tgenabled) "
    8860              :                           "ORDER BY t.tgrelid, t.tgname",
    8861              :                           tbloids->data);
    8862              :     }
    8863            0 :     else if (fout->remoteVersion >= 110000)
    8864              :     {
    8865              :         /*
    8866              :          * NB: We need to see tgisinternal triggers in partitions, in case the
    8867              :          * tgenabled flag has been changed from the parent. No tgparentid in
    8868              :          * version 11-12, so we have to match them via pg_depend.
    8869              :          *
    8870              :          * See above about pretty=true in pg_get_triggerdef.
    8871              :          */
    8872            0 :         appendPQExpBuffer(query,
    8873              :                           "SELECT t.tgrelid, t.tgname, "
    8874              :                           "pg_catalog.pg_get_triggerdef(t.oid, false) AS tgdef, "
    8875              :                           "t.tgenabled, t.tableoid, t.oid, t.tgisinternal as tgispartition "
    8876              :                           "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
    8877              :                           "JOIN pg_catalog.pg_trigger t ON (src.tbloid = t.tgrelid) "
    8878              :                           "LEFT JOIN pg_catalog.pg_depend AS d ON "
    8879              :                           " d.classid = 'pg_catalog.pg_trigger'::pg_catalog.regclass AND "
    8880              :                           " d.refclassid = 'pg_catalog.pg_trigger'::pg_catalog.regclass AND "
    8881              :                           " d.objid = t.oid "
    8882              :                           "LEFT JOIN pg_catalog.pg_trigger AS pt ON pt.oid = refobjid "
    8883              :                           "WHERE (NOT t.tgisinternal OR t.tgenabled != pt.tgenabled) "
    8884              :                           "ORDER BY t.tgrelid, t.tgname",
    8885              :                           tbloids->data);
    8886              :     }
    8887              :     else
    8888              :     {
    8889              :         /* See above about pretty=true in pg_get_triggerdef */
    8890            0 :         appendPQExpBuffer(query,
    8891              :                           "SELECT t.tgrelid, t.tgname, "
    8892              :                           "pg_catalog.pg_get_triggerdef(t.oid, false) AS tgdef, "
    8893              :                           "t.tgenabled, false as tgispartition, "
    8894              :                           "t.tableoid, t.oid "
    8895              :                           "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
    8896              :                           "JOIN pg_catalog.pg_trigger t ON (src.tbloid = t.tgrelid) "
    8897              :                           "WHERE NOT tgisinternal "
    8898              :                           "ORDER BY t.tgrelid, t.tgname",
    8899              :                           tbloids->data);
    8900              :     }
    8901              : 
    8902          259 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    8903              : 
    8904          259 :     ntups = PQntuples(res);
    8905              : 
    8906          259 :     i_tableoid = PQfnumber(res, "tableoid");
    8907          259 :     i_oid = PQfnumber(res, "oid");
    8908          259 :     i_tgrelid = PQfnumber(res, "tgrelid");
    8909          259 :     i_tgname = PQfnumber(res, "tgname");
    8910          259 :     i_tgenabled = PQfnumber(res, "tgenabled");
    8911          259 :     i_tgispartition = PQfnumber(res, "tgispartition");
    8912          259 :     i_tgdef = PQfnumber(res, "tgdef");
    8913              : 
    8914          259 :     tginfo = pg_malloc_array(TriggerInfo, ntups);
    8915              : 
    8916              :     /*
    8917              :      * Outer loop iterates once per table, not once per row.  Incrementing of
    8918              :      * j is handled by the inner loop.
    8919              :      */
    8920          259 :     curtblindx = -1;
    8921          565 :     for (int j = 0; j < ntups;)
    8922              :     {
    8923          306 :         Oid         tgrelid = atooid(PQgetvalue(res, j, i_tgrelid));
    8924          306 :         TableInfo  *tbinfo = NULL;
    8925              :         int         numtrigs;
    8926              : 
    8927              :         /* Count rows for this table */
    8928          523 :         for (numtrigs = 1; numtrigs < ntups - j; numtrigs++)
    8929          472 :             if (atooid(PQgetvalue(res, j + numtrigs, i_tgrelid)) != tgrelid)
    8930          255 :                 break;
    8931              : 
    8932              :         /*
    8933              :          * Locate the associated TableInfo; we rely on tblinfo[] being in OID
    8934              :          * order.
    8935              :          */
    8936        17416 :         while (++curtblindx < numTables)
    8937              :         {
    8938        17416 :             tbinfo = &tblinfo[curtblindx];
    8939        17416 :             if (tbinfo->dobj.catId.oid == tgrelid)
    8940          306 :                 break;
    8941              :         }
    8942          306 :         if (curtblindx >= numTables)
    8943            0 :             pg_fatal("unrecognized table OID %u", tgrelid);
    8944              : 
    8945              :         /* Save data for this table */
    8946          306 :         tbinfo->triggers = tginfo + j;
    8947          306 :         tbinfo->numTriggers = numtrigs;
    8948              : 
    8949          829 :         for (int c = 0; c < numtrigs; c++, j++)
    8950              :         {
    8951          523 :             tginfo[j].dobj.objType = DO_TRIGGER;
    8952          523 :             tginfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
    8953          523 :             tginfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
    8954          523 :             AssignDumpId(&tginfo[j].dobj);
    8955          523 :             tginfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_tgname));
    8956          523 :             tginfo[j].dobj.namespace = tbinfo->dobj.namespace;
    8957          523 :             tginfo[j].tgtable = tbinfo;
    8958          523 :             tginfo[j].tgenabled = *(PQgetvalue(res, j, i_tgenabled));
    8959          523 :             tginfo[j].tgispartition = *(PQgetvalue(res, j, i_tgispartition)) == 't';
    8960          523 :             tginfo[j].tgdef = pg_strdup(PQgetvalue(res, j, i_tgdef));
    8961              :         }
    8962              :     }
    8963              : 
    8964          259 :     PQclear(res);
    8965              : 
    8966          259 :     destroyPQExpBuffer(query);
    8967          259 :     destroyPQExpBuffer(tbloids);
    8968          259 : }
    8969              : 
    8970              : /*
    8971              :  * getEventTriggers
    8972              :  *    get information about event triggers
    8973              :  */
    8974              : void
    8975          259 : getEventTriggers(Archive *fout)
    8976              : {
    8977              :     int         i;
    8978              :     PQExpBuffer query;
    8979              :     PGresult   *res;
    8980              :     EventTriggerInfo *evtinfo;
    8981              :     int         i_tableoid,
    8982              :                 i_oid,
    8983              :                 i_evtname,
    8984              :                 i_evtevent,
    8985              :                 i_evtowner,
    8986              :                 i_evttags,
    8987              :                 i_evtfname,
    8988              :                 i_evtenabled;
    8989              :     int         ntups;
    8990              : 
    8991              :     /* Before 9.3, there are no event triggers */
    8992          259 :     if (fout->remoteVersion < 90300)
    8993            0 :         return;
    8994              : 
    8995          259 :     query = createPQExpBuffer();
    8996              : 
    8997          259 :     appendPQExpBufferStr(query,
    8998              :                          "SELECT e.tableoid, e.oid, evtname, evtenabled, "
    8999              :                          "evtevent, evtowner, "
    9000              :                          "array_to_string(array("
    9001              :                          "select quote_literal(x) "
    9002              :                          " from unnest(evttags) as t(x)), ', ') as evttags, "
    9003              :                          "e.evtfoid::regproc as evtfname "
    9004              :                          "FROM pg_event_trigger e "
    9005              :                          "ORDER BY e.oid");
    9006              : 
    9007          259 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    9008              : 
    9009          259 :     ntups = PQntuples(res);
    9010              : 
    9011          259 :     evtinfo = pg_malloc_array(EventTriggerInfo, ntups);
    9012              : 
    9013          259 :     i_tableoid = PQfnumber(res, "tableoid");
    9014          259 :     i_oid = PQfnumber(res, "oid");
    9015          259 :     i_evtname = PQfnumber(res, "evtname");
    9016          259 :     i_evtevent = PQfnumber(res, "evtevent");
    9017          259 :     i_evtowner = PQfnumber(res, "evtowner");
    9018          259 :     i_evttags = PQfnumber(res, "evttags");
    9019          259 :     i_evtfname = PQfnumber(res, "evtfname");
    9020          259 :     i_evtenabled = PQfnumber(res, "evtenabled");
    9021              : 
    9022          311 :     for (i = 0; i < ntups; i++)
    9023              :     {
    9024           52 :         evtinfo[i].dobj.objType = DO_EVENT_TRIGGER;
    9025           52 :         evtinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    9026           52 :         evtinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    9027           52 :         AssignDumpId(&evtinfo[i].dobj);
    9028           52 :         evtinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_evtname));
    9029           52 :         evtinfo[i].evtname = pg_strdup(PQgetvalue(res, i, i_evtname));
    9030           52 :         evtinfo[i].evtevent = pg_strdup(PQgetvalue(res, i, i_evtevent));
    9031           52 :         evtinfo[i].evtowner = getRoleName(PQgetvalue(res, i, i_evtowner));
    9032           52 :         evtinfo[i].evttags = pg_strdup(PQgetvalue(res, i, i_evttags));
    9033           52 :         evtinfo[i].evtfname = pg_strdup(PQgetvalue(res, i, i_evtfname));
    9034           52 :         evtinfo[i].evtenabled = *(PQgetvalue(res, i, i_evtenabled));
    9035              : 
    9036              :         /* Decide whether we want to dump it */
    9037           52 :         selectDumpableObject(&(evtinfo[i].dobj), fout);
    9038              :     }
    9039              : 
    9040          259 :     PQclear(res);
    9041              : 
    9042          259 :     destroyPQExpBuffer(query);
    9043              : }
    9044              : 
    9045              : /*
    9046              :  * getProcLangs
    9047              :  *    get basic information about every procedural language in the system
    9048              :  *
    9049              :  * NB: this must run after getFuncs() because we assume we can do
    9050              :  * findFuncByOid().
    9051              :  */
    9052              : void
    9053          259 : getProcLangs(Archive *fout)
    9054              : {
    9055              :     PGresult   *res;
    9056              :     int         ntups;
    9057              :     int         i;
    9058          259 :     PQExpBuffer query = createPQExpBuffer();
    9059              :     ProcLangInfo *planginfo;
    9060              :     int         i_tableoid;
    9061              :     int         i_oid;
    9062              :     int         i_lanname;
    9063              :     int         i_lanpltrusted;
    9064              :     int         i_lanplcallfoid;
    9065              :     int         i_laninline;
    9066              :     int         i_lanvalidator;
    9067              :     int         i_lanacl;
    9068              :     int         i_acldefault;
    9069              :     int         i_lanowner;
    9070              : 
    9071          259 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, "
    9072              :                          "lanname, lanpltrusted, lanplcallfoid, "
    9073              :                          "laninline, lanvalidator, "
    9074              :                          "lanacl, "
    9075              :                          "acldefault('l', lanowner) AS acldefault, "
    9076              :                          "lanowner "
    9077              :                          "FROM pg_language "
    9078              :                          "WHERE lanispl "
    9079              :                          "ORDER BY oid");
    9080              : 
    9081          259 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    9082              : 
    9083          259 :     ntups = PQntuples(res);
    9084              : 
    9085          259 :     planginfo = pg_malloc_array(ProcLangInfo, ntups);
    9086              : 
    9087          259 :     i_tableoid = PQfnumber(res, "tableoid");
    9088          259 :     i_oid = PQfnumber(res, "oid");
    9089          259 :     i_lanname = PQfnumber(res, "lanname");
    9090          259 :     i_lanpltrusted = PQfnumber(res, "lanpltrusted");
    9091          259 :     i_lanplcallfoid = PQfnumber(res, "lanplcallfoid");
    9092          259 :     i_laninline = PQfnumber(res, "laninline");
    9093          259 :     i_lanvalidator = PQfnumber(res, "lanvalidator");
    9094          259 :     i_lanacl = PQfnumber(res, "lanacl");
    9095          259 :     i_acldefault = PQfnumber(res, "acldefault");
    9096          259 :     i_lanowner = PQfnumber(res, "lanowner");
    9097              : 
    9098          563 :     for (i = 0; i < ntups; i++)
    9099              :     {
    9100          304 :         planginfo[i].dobj.objType = DO_PROCLANG;
    9101          304 :         planginfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    9102          304 :         planginfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    9103          304 :         AssignDumpId(&planginfo[i].dobj);
    9104              : 
    9105          304 :         planginfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_lanname));
    9106          304 :         planginfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_lanacl));
    9107          304 :         planginfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
    9108          304 :         planginfo[i].dacl.privtype = 0;
    9109          304 :         planginfo[i].dacl.initprivs = NULL;
    9110          304 :         planginfo[i].lanpltrusted = *(PQgetvalue(res, i, i_lanpltrusted)) == 't';
    9111          304 :         planginfo[i].lanplcallfoid = atooid(PQgetvalue(res, i, i_lanplcallfoid));
    9112          304 :         planginfo[i].laninline = atooid(PQgetvalue(res, i, i_laninline));
    9113          304 :         planginfo[i].lanvalidator = atooid(PQgetvalue(res, i, i_lanvalidator));
    9114          304 :         planginfo[i].lanowner = getRoleName(PQgetvalue(res, i, i_lanowner));
    9115              : 
    9116              :         /* Decide whether we want to dump it */
    9117          304 :         selectDumpableProcLang(&(planginfo[i]), fout);
    9118              : 
    9119              :         /* Mark whether language has an ACL */
    9120          304 :         if (!PQgetisnull(res, i, i_lanacl))
    9121           45 :             planginfo[i].dobj.components |= DUMP_COMPONENT_ACL;
    9122              :     }
    9123              : 
    9124          259 :     PQclear(res);
    9125              : 
    9126          259 :     destroyPQExpBuffer(query);
    9127          259 : }
    9128              : 
    9129              : /*
    9130              :  * getCasts
    9131              :  *    get basic information about most casts in the system
    9132              :  *
    9133              :  * Skip casts from a range to its multirange, since we'll create those
    9134              :  * automatically.
    9135              :  */
    9136              : void
    9137          259 : getCasts(Archive *fout)
    9138              : {
    9139              :     PGresult   *res;
    9140              :     int         ntups;
    9141              :     int         i;
    9142          259 :     PQExpBuffer query = createPQExpBuffer();
    9143              :     CastInfo   *castinfo;
    9144              :     int         i_tableoid;
    9145              :     int         i_oid;
    9146              :     int         i_castsource;
    9147              :     int         i_casttarget;
    9148              :     int         i_castfunc;
    9149              :     int         i_castcontext;
    9150              :     int         i_castmethod;
    9151              : 
    9152          259 :     if (fout->remoteVersion >= 140000)
    9153              :     {
    9154          259 :         appendPQExpBufferStr(query, "SELECT tableoid, oid, "
    9155              :                              "castsource, casttarget, castfunc, castcontext, "
    9156              :                              "castmethod "
    9157              :                              "FROM pg_cast c "
    9158              :                              "WHERE NOT EXISTS ( "
    9159              :                              "SELECT 1 FROM pg_range r "
    9160              :                              "WHERE c.castsource = r.rngtypid "
    9161              :                              "AND c.casttarget = r.rngmultitypid "
    9162              :                              ") "
    9163              :                              "ORDER BY 3,4");
    9164              :     }
    9165              :     else
    9166              :     {
    9167            0 :         appendPQExpBufferStr(query, "SELECT tableoid, oid, "
    9168              :                              "castsource, casttarget, castfunc, castcontext, "
    9169              :                              "castmethod "
    9170              :                              "FROM pg_cast ORDER BY 3,4");
    9171              :     }
    9172              : 
    9173          259 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    9174              : 
    9175          259 :     ntups = PQntuples(res);
    9176              : 
    9177          259 :     castinfo = pg_malloc_array(CastInfo, ntups);
    9178              : 
    9179          259 :     i_tableoid = PQfnumber(res, "tableoid");
    9180          259 :     i_oid = PQfnumber(res, "oid");
    9181          259 :     i_castsource = PQfnumber(res, "castsource");
    9182          259 :     i_casttarget = PQfnumber(res, "casttarget");
    9183          259 :     i_castfunc = PQfnumber(res, "castfunc");
    9184          259 :     i_castcontext = PQfnumber(res, "castcontext");
    9185          259 :     i_castmethod = PQfnumber(res, "castmethod");
    9186              : 
    9187        63283 :     for (i = 0; i < ntups; i++)
    9188              :     {
    9189              :         PQExpBufferData namebuf;
    9190              :         TypeInfo   *sTypeInfo;
    9191              :         TypeInfo   *tTypeInfo;
    9192              : 
    9193        63024 :         castinfo[i].dobj.objType = DO_CAST;
    9194        63024 :         castinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    9195        63024 :         castinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    9196        63024 :         AssignDumpId(&castinfo[i].dobj);
    9197        63024 :         castinfo[i].castsource = atooid(PQgetvalue(res, i, i_castsource));
    9198        63024 :         castinfo[i].casttarget = atooid(PQgetvalue(res, i, i_casttarget));
    9199        63024 :         castinfo[i].castfunc = atooid(PQgetvalue(res, i, i_castfunc));
    9200        63024 :         castinfo[i].castcontext = *(PQgetvalue(res, i, i_castcontext));
    9201        63024 :         castinfo[i].castmethod = *(PQgetvalue(res, i, i_castmethod));
    9202              : 
    9203              :         /*
    9204              :          * Try to name cast as concatenation of typnames.  This is only used
    9205              :          * for purposes of sorting.  If we fail to find either type, the name
    9206              :          * will be an empty string.
    9207              :          */
    9208        63024 :         initPQExpBuffer(&namebuf);
    9209        63024 :         sTypeInfo = findTypeByOid(castinfo[i].castsource);
    9210        63024 :         tTypeInfo = findTypeByOid(castinfo[i].casttarget);
    9211        63024 :         if (sTypeInfo && tTypeInfo)
    9212        63024 :             appendPQExpBuffer(&namebuf, "%s %s",
    9213              :                               sTypeInfo->dobj.name, tTypeInfo->dobj.name);
    9214        63024 :         castinfo[i].dobj.name = namebuf.data;
    9215              : 
    9216              :         /* Decide whether we want to dump it */
    9217        63024 :         selectDumpableCast(&(castinfo[i]), fout);
    9218              :     }
    9219              : 
    9220          259 :     PQclear(res);
    9221              : 
    9222          259 :     destroyPQExpBuffer(query);
    9223          259 : }
    9224              : 
    9225              : static char *
    9226           88 : get_language_name(Archive *fout, Oid langid)
    9227              : {
    9228              :     PQExpBuffer query;
    9229              :     PGresult   *res;
    9230              :     char       *lanname;
    9231              : 
    9232           88 :     query = createPQExpBuffer();
    9233           88 :     appendPQExpBuffer(query, "SELECT lanname FROM pg_language WHERE oid = %u", langid);
    9234           88 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
    9235           88 :     lanname = pg_strdup(fmtId(PQgetvalue(res, 0, 0)));
    9236           88 :     destroyPQExpBuffer(query);
    9237           88 :     PQclear(res);
    9238              : 
    9239           88 :     return lanname;
    9240              : }
    9241              : 
    9242              : /*
    9243              :  * getTransforms
    9244              :  *    get basic information about every transform in the system
    9245              :  */
    9246              : void
    9247          259 : getTransforms(Archive *fout)
    9248              : {
    9249              :     PGresult   *res;
    9250              :     int         ntups;
    9251              :     int         i;
    9252              :     PQExpBuffer query;
    9253              :     TransformInfo *transforminfo;
    9254              :     int         i_tableoid;
    9255              :     int         i_oid;
    9256              :     int         i_trftype;
    9257              :     int         i_trflang;
    9258              :     int         i_trffromsql;
    9259              :     int         i_trftosql;
    9260              : 
    9261              :     /* Transforms didn't exist pre-9.5 */
    9262          259 :     if (fout->remoteVersion < 90500)
    9263            0 :         return;
    9264              : 
    9265          259 :     query = createPQExpBuffer();
    9266              : 
    9267          259 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, "
    9268              :                          "trftype, trflang, trffromsql::oid, trftosql::oid "
    9269              :                          "FROM pg_transform "
    9270              :                          "ORDER BY 3,4");
    9271              : 
    9272          259 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    9273              : 
    9274          259 :     ntups = PQntuples(res);
    9275              : 
    9276          259 :     transforminfo = pg_malloc_array(TransformInfo, ntups);
    9277              : 
    9278          259 :     i_tableoid = PQfnumber(res, "tableoid");
    9279          259 :     i_oid = PQfnumber(res, "oid");
    9280          259 :     i_trftype = PQfnumber(res, "trftype");
    9281          259 :     i_trflang = PQfnumber(res, "trflang");
    9282          259 :     i_trffromsql = PQfnumber(res, "trffromsql");
    9283          259 :     i_trftosql = PQfnumber(res, "trftosql");
    9284              : 
    9285          311 :     for (i = 0; i < ntups; i++)
    9286              :     {
    9287              :         PQExpBufferData namebuf;
    9288              :         TypeInfo   *typeInfo;
    9289              :         char       *lanname;
    9290              : 
    9291           52 :         transforminfo[i].dobj.objType = DO_TRANSFORM;
    9292           52 :         transforminfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    9293           52 :         transforminfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    9294           52 :         AssignDumpId(&transforminfo[i].dobj);
    9295           52 :         transforminfo[i].trftype = atooid(PQgetvalue(res, i, i_trftype));
    9296           52 :         transforminfo[i].trflang = atooid(PQgetvalue(res, i, i_trflang));
    9297           52 :         transforminfo[i].trffromsql = atooid(PQgetvalue(res, i, i_trffromsql));
    9298           52 :         transforminfo[i].trftosql = atooid(PQgetvalue(res, i, i_trftosql));
    9299              : 
    9300              :         /*
    9301              :          * Try to name transform as concatenation of type and language name.
    9302              :          * This is only used for purposes of sorting.  If we fail to find
    9303              :          * either, the name will be an empty string.
    9304              :          */
    9305           52 :         initPQExpBuffer(&namebuf);
    9306           52 :         typeInfo = findTypeByOid(transforminfo[i].trftype);
    9307           52 :         lanname = get_language_name(fout, transforminfo[i].trflang);
    9308           52 :         if (typeInfo && lanname)
    9309           52 :             appendPQExpBuffer(&namebuf, "%s %s",
    9310              :                               typeInfo->dobj.name, lanname);
    9311           52 :         transforminfo[i].dobj.name = namebuf.data;
    9312           52 :         free(lanname);
    9313              : 
    9314              :         /* Decide whether we want to dump it */
    9315           52 :         selectDumpableObject(&(transforminfo[i].dobj), fout);
    9316              :     }
    9317              : 
    9318          259 :     PQclear(res);
    9319              : 
    9320          259 :     destroyPQExpBuffer(query);
    9321              : }
    9322              : 
    9323              : /*
    9324              :  * getTableAttrs -
    9325              :  *    for each interesting table, read info about its attributes
    9326              :  *    (names, types, default values, CHECK constraints, etc)
    9327              :  *
    9328              :  *  modifies tblinfo
    9329              :  */
    9330              : void
    9331          259 : getTableAttrs(Archive *fout, TableInfo *tblinfo, int numTables)
    9332              : {
    9333          259 :     DumpOptions *dopt = fout->dopt;
    9334          259 :     PQExpBuffer q = createPQExpBuffer();
    9335          259 :     PQExpBuffer tbloids = createPQExpBuffer();
    9336          259 :     PQExpBuffer checkoids = createPQExpBuffer();
    9337          259 :     PQExpBuffer invalidnotnulloids = NULL;
    9338              :     PGresult   *res;
    9339              :     int         ntups;
    9340              :     int         curtblindx;
    9341              :     int         i_attrelid;
    9342              :     int         i_attnum;
    9343              :     int         i_attname;
    9344              :     int         i_atttypname;
    9345              :     int         i_attstattarget;
    9346              :     int         i_attstorage;
    9347              :     int         i_typstorage;
    9348              :     int         i_attidentity;
    9349              :     int         i_attgenerated;
    9350              :     int         i_attisdropped;
    9351              :     int         i_attlen;
    9352              :     int         i_attalign;
    9353              :     int         i_attislocal;
    9354              :     int         i_notnull_name;
    9355              :     int         i_notnull_comment;
    9356              :     int         i_notnull_noinherit;
    9357              :     int         i_notnull_islocal;
    9358              :     int         i_notnull_invalidoid;
    9359              :     int         i_attoptions;
    9360              :     int         i_attcollation;
    9361              :     int         i_attcompression;
    9362              :     int         i_attfdwoptions;
    9363              :     int         i_attmissingval;
    9364              :     int         i_atthasdef;
    9365              : 
    9366              :     /*
    9367              :      * We want to perform just one query against pg_attribute, and then just
    9368              :      * one against pg_attrdef (for DEFAULTs) and two against pg_constraint
    9369              :      * (for CHECK constraints and for NOT NULL constraints).  However, we
    9370              :      * mustn't try to select every row of those catalogs and then sort it out
    9371              :      * on the client side, because some of the server-side functions we need
    9372              :      * would be unsafe to apply to tables we don't have lock on.  Hence, we
    9373              :      * build an array of the OIDs of tables we care about (and now have lock
    9374              :      * on!), and use a WHERE clause to constrain which rows are selected.
    9375              :      */
    9376          259 :     appendPQExpBufferChar(tbloids, '{');
    9377          259 :     appendPQExpBufferChar(checkoids, '{');
    9378        70986 :     for (int i = 0; i < numTables; i++)
    9379              :     {
    9380        70727 :         TableInfo  *tbinfo = &tblinfo[i];
    9381              : 
    9382              :         /* Don't bother to collect info for sequences */
    9383        70727 :         if (tbinfo->relkind == RELKIND_SEQUENCE)
    9384          647 :             continue;
    9385              : 
    9386              :         /*
    9387              :          * Don't bother with uninteresting tables, either.  For binary
    9388              :          * upgrades, this is bypassed for pg_largeobject_metadata and
    9389              :          * pg_shdepend so that the columns names are collected for the
    9390              :          * corresponding COPY commands.  Restoring the data for those catalogs
    9391              :          * is faster than restoring the equivalent set of large object
    9392              :          * commands.
    9393              :          */
    9394        70080 :         if (!tbinfo->interesting &&
    9395        62817 :             !(fout->dopt->binary_upgrade &&
    9396         9418 :               (tbinfo->dobj.catId.oid == LargeObjectMetadataRelationId ||
    9397         9378 :                tbinfo->dobj.catId.oid == SharedDependRelationId)))
    9398        62737 :             continue;
    9399              : 
    9400              :         /* OK, we need info for this table */
    9401         7343 :         if (tbloids->len > 1) /* do we have more than the '{'? */
    9402         7144 :             appendPQExpBufferChar(tbloids, ',');
    9403         7343 :         appendPQExpBuffer(tbloids, "%u", tbinfo->dobj.catId.oid);
    9404              : 
    9405         7343 :         if (tbinfo->ncheck > 0)
    9406              :         {
    9407              :             /* Also make a list of the ones with check constraints */
    9408          528 :             if (checkoids->len > 1) /* do we have more than the '{'? */
    9409          459 :                 appendPQExpBufferChar(checkoids, ',');
    9410          528 :             appendPQExpBuffer(checkoids, "%u", tbinfo->dobj.catId.oid);
    9411              :         }
    9412              :     }
    9413          259 :     appendPQExpBufferChar(tbloids, '}');
    9414          259 :     appendPQExpBufferChar(checkoids, '}');
    9415              : 
    9416              :     /*
    9417              :      * Find all the user attributes and their types.
    9418              :      *
    9419              :      * Since we only want to dump COLLATE clauses for attributes whose
    9420              :      * collation is different from their type's default, we use a CASE here to
    9421              :      * suppress uninteresting attcollations cheaply.
    9422              :      */
    9423          259 :     appendPQExpBufferStr(q,
    9424              :                          "SELECT\n"
    9425              :                          "a.attrelid,\n"
    9426              :                          "a.attnum,\n"
    9427              :                          "a.attname,\n"
    9428              :                          "a.attstattarget,\n"
    9429              :                          "a.attstorage,\n"
    9430              :                          "t.typstorage,\n"
    9431              :                          "a.atthasdef,\n"
    9432              :                          "a.attisdropped,\n"
    9433              :                          "a.attlen,\n"
    9434              :                          "a.attalign,\n"
    9435              :                          "a.attislocal,\n"
    9436              :                          "pg_catalog.format_type(t.oid, a.atttypmod) AS atttypname,\n"
    9437              :                          "array_to_string(a.attoptions, ', ') AS attoptions,\n"
    9438              :                          "CASE WHEN a.attcollation <> t.typcollation "
    9439              :                          "THEN a.attcollation ELSE 0 END AS attcollation,\n"
    9440              :                          "pg_catalog.array_to_string(ARRAY("
    9441              :                          "SELECT pg_catalog.quote_ident(option_name) || "
    9442              :                          "' ' || pg_catalog.quote_literal(option_value) "
    9443              :                          "FROM pg_catalog.pg_options_to_table(attfdwoptions) "
    9444              :                          "ORDER BY option_name"
    9445              :                          "), E',\n    ') AS attfdwoptions,\n");
    9446              : 
    9447              :     /*
    9448              :      * Find out any NOT NULL markings for each column.  In 18 and up we read
    9449              :      * pg_constraint to obtain the constraint name, and for valid constraints
    9450              :      * also pg_description to obtain its comment.  notnull_noinherit is set
    9451              :      * according to the NO INHERIT property.  For versions prior to 18, we
    9452              :      * store an empty string as the name when a constraint is marked as
    9453              :      * attnotnull (this cues dumpTableSchema to print the NOT NULL clause
    9454              :      * without a name); also, such cases are never NO INHERIT.
    9455              :      *
    9456              :      * For invalid constraints, we need to store their OIDs for processing
    9457              :      * elsewhere, so we bring the pg_constraint.oid value when the constraint
    9458              :      * is invalid, and NULL otherwise.  Their comments are handled not here
    9459              :      * but by collectComments, because they're their own dumpable object.
    9460              :      *
    9461              :      * We track in notnull_islocal whether the constraint was defined directly
    9462              :      * in this table or via an ancestor, for binary upgrade.  flagInhAttrs
    9463              :      * might modify this later.
    9464              :      */
    9465          259 :     if (fout->remoteVersion >= 180000)
    9466          259 :         appendPQExpBufferStr(q,
    9467              :                              "co.conname AS notnull_name,\n"
    9468              :                              "CASE WHEN co.convalidated THEN pt.description"
    9469              :                              " ELSE NULL END AS notnull_comment,\n"
    9470              :                              "CASE WHEN NOT co.convalidated THEN co.oid "
    9471              :                              "ELSE NULL END AS notnull_invalidoid,\n"
    9472              :                              "co.connoinherit AS notnull_noinherit,\n"
    9473              :                              "co.conislocal AS notnull_islocal,\n");
    9474              :     else
    9475            0 :         appendPQExpBufferStr(q,
    9476              :                              "CASE WHEN a.attnotnull THEN '' ELSE NULL END AS notnull_name,\n"
    9477              :                              "NULL AS notnull_comment,\n"
    9478              :                              "NULL AS notnull_invalidoid,\n"
    9479              :                              "false AS notnull_noinherit,\n"
    9480              :                              "CASE WHEN a.attislocal THEN true\n"
    9481              :                              "     WHEN a.attnotnull AND NOT a.attislocal THEN true\n"
    9482              :                              "     ELSE false\n"
    9483              :                              "END AS notnull_islocal,\n");
    9484              : 
    9485          259 :     if (fout->remoteVersion >= 140000)
    9486          259 :         appendPQExpBufferStr(q,
    9487              :                              "a.attcompression AS attcompression,\n");
    9488              :     else
    9489            0 :         appendPQExpBufferStr(q,
    9490              :                              "'' AS attcompression,\n");
    9491              : 
    9492          259 :     if (fout->remoteVersion >= 100000)
    9493          259 :         appendPQExpBufferStr(q,
    9494              :                              "a.attidentity,\n");
    9495              :     else
    9496            0 :         appendPQExpBufferStr(q,
    9497              :                              "'' AS attidentity,\n");
    9498              : 
    9499          259 :     if (fout->remoteVersion >= 110000)
    9500          259 :         appendPQExpBufferStr(q,
    9501              :                              "CASE WHEN a.atthasmissing AND NOT a.attisdropped "
    9502              :                              "THEN a.attmissingval ELSE null END AS attmissingval,\n");
    9503              :     else
    9504            0 :         appendPQExpBufferStr(q,
    9505              :                              "NULL AS attmissingval,\n");
    9506              : 
    9507          259 :     if (fout->remoteVersion >= 120000)
    9508          259 :         appendPQExpBufferStr(q,
    9509              :                              "a.attgenerated\n");
    9510              :     else
    9511            0 :         appendPQExpBufferStr(q,
    9512              :                              "'' AS attgenerated\n");
    9513              : 
    9514              :     /* need left join to pg_type to not fail on dropped columns ... */
    9515          259 :     appendPQExpBuffer(q,
    9516              :                       "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
    9517              :                       "JOIN pg_catalog.pg_attribute a ON (src.tbloid = a.attrelid) "
    9518              :                       "LEFT JOIN pg_catalog.pg_type t "
    9519              :                       "ON (a.atttypid = t.oid)\n",
    9520              :                       tbloids->data);
    9521              : 
    9522              :     /*
    9523              :      * In versions 18 and up, we need pg_constraint for explicit NOT NULL
    9524              :      * entries and pg_description to get their comments.
    9525              :      */
    9526          259 :     if (fout->remoteVersion >= 180000)
    9527          259 :         appendPQExpBufferStr(q,
    9528              :                              " LEFT JOIN pg_catalog.pg_constraint co ON "
    9529              :                              "(a.attrelid = co.conrelid\n"
    9530              :                              "   AND co.contype = 'n' AND "
    9531              :                              "co.conkey = array[a.attnum])\n"
    9532              :                              " LEFT JOIN pg_catalog.pg_description pt ON "
    9533              :                              "(pt.classoid = co.tableoid AND pt.objoid = co.oid)\n");
    9534              : 
    9535          259 :     appendPQExpBufferStr(q,
    9536              :                          "WHERE a.attnum > 0::pg_catalog.int2\n");
    9537              : 
    9538              :     /*
    9539              :      * For binary upgrades from <v12, be sure to pick up
    9540              :      * pg_largeobject_metadata's oid column.
    9541              :      */
    9542          259 :     if (fout->dopt->binary_upgrade && fout->remoteVersion < 120000)
    9543            0 :         appendPQExpBufferStr(q,
    9544              :                              "OR (a.attnum = -2::pg_catalog.int2 AND src.tbloid = "
    9545              :                              CppAsString2(LargeObjectMetadataRelationId) ")\n");
    9546              : 
    9547          259 :     appendPQExpBufferStr(q,
    9548              :                          "ORDER BY a.attrelid, a.attnum");
    9549              : 
    9550          259 :     res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
    9551              : 
    9552          259 :     ntups = PQntuples(res);
    9553              : 
    9554          259 :     i_attrelid = PQfnumber(res, "attrelid");
    9555          259 :     i_attnum = PQfnumber(res, "attnum");
    9556          259 :     i_attname = PQfnumber(res, "attname");
    9557          259 :     i_atttypname = PQfnumber(res, "atttypname");
    9558          259 :     i_attstattarget = PQfnumber(res, "attstattarget");
    9559          259 :     i_attstorage = PQfnumber(res, "attstorage");
    9560          259 :     i_typstorage = PQfnumber(res, "typstorage");
    9561          259 :     i_attidentity = PQfnumber(res, "attidentity");
    9562          259 :     i_attgenerated = PQfnumber(res, "attgenerated");
    9563          259 :     i_attisdropped = PQfnumber(res, "attisdropped");
    9564          259 :     i_attlen = PQfnumber(res, "attlen");
    9565          259 :     i_attalign = PQfnumber(res, "attalign");
    9566          259 :     i_attislocal = PQfnumber(res, "attislocal");
    9567          259 :     i_notnull_name = PQfnumber(res, "notnull_name");
    9568          259 :     i_notnull_comment = PQfnumber(res, "notnull_comment");
    9569          259 :     i_notnull_invalidoid = PQfnumber(res, "notnull_invalidoid");
    9570          259 :     i_notnull_noinherit = PQfnumber(res, "notnull_noinherit");
    9571          259 :     i_notnull_islocal = PQfnumber(res, "notnull_islocal");
    9572          259 :     i_attoptions = PQfnumber(res, "attoptions");
    9573          259 :     i_attcollation = PQfnumber(res, "attcollation");
    9574          259 :     i_attcompression = PQfnumber(res, "attcompression");
    9575          259 :     i_attfdwoptions = PQfnumber(res, "attfdwoptions");
    9576          259 :     i_attmissingval = PQfnumber(res, "attmissingval");
    9577          259 :     i_atthasdef = PQfnumber(res, "atthasdef");
    9578              : 
    9579              :     /* Within the next loop, we'll accumulate OIDs of tables with defaults */
    9580          259 :     resetPQExpBuffer(tbloids);
    9581          259 :     appendPQExpBufferChar(tbloids, '{');
    9582              : 
    9583              :     /*
    9584              :      * Outer loop iterates once per table, not once per row.  Incrementing of
    9585              :      * r is handled by the inner loop.
    9586              :      */
    9587          259 :     curtblindx = -1;
    9588         7361 :     for (int r = 0; r < ntups;)
    9589              :     {
    9590         7102 :         Oid         attrelid = atooid(PQgetvalue(res, r, i_attrelid));
    9591         7102 :         TableInfo  *tbinfo = NULL;
    9592              :         int         numatts;
    9593              :         bool        hasdefaults;
    9594              : 
    9595              :         /* Count rows for this table */
    9596        26412 :         for (numatts = 1; numatts < ntups - r; numatts++)
    9597        26216 :             if (atooid(PQgetvalue(res, r + numatts, i_attrelid)) != attrelid)
    9598         6906 :                 break;
    9599              : 
    9600              :         /*
    9601              :          * Locate the associated TableInfo; we rely on tblinfo[] being in OID
    9602              :          * order.
    9603              :          */
    9604        49784 :         while (++curtblindx < numTables)
    9605              :         {
    9606        49784 :             tbinfo = &tblinfo[curtblindx];
    9607        49784 :             if (tbinfo->dobj.catId.oid == attrelid)
    9608         7102 :                 break;
    9609              :         }
    9610         7102 :         if (curtblindx >= numTables)
    9611            0 :             pg_fatal("unrecognized table OID %u", attrelid);
    9612              :         /* cross-check that we only got requested tables */
    9613         7102 :         if (tbinfo->relkind == RELKIND_SEQUENCE ||
    9614         7102 :             (!tbinfo->interesting &&
    9615           80 :              !(fout->dopt->binary_upgrade &&
    9616           80 :                (tbinfo->dobj.catId.oid == LargeObjectMetadataRelationId ||
    9617           40 :                 tbinfo->dobj.catId.oid == SharedDependRelationId))))
    9618            0 :             pg_fatal("unexpected column data for table \"%s\"",
    9619              :                      tbinfo->dobj.name);
    9620              : 
    9621              :         /* Save data for this table */
    9622         7102 :         tbinfo->numatts = numatts;
    9623         7102 :         tbinfo->attnames = pg_malloc_array(char *, numatts);
    9624         7102 :         tbinfo->atttypnames = pg_malloc_array(char *, numatts);
    9625         7102 :         tbinfo->attstattarget = pg_malloc_array(int, numatts);
    9626         7102 :         tbinfo->attstorage = pg_malloc_array(char, numatts);
    9627         7102 :         tbinfo->typstorage = pg_malloc_array(char, numatts);
    9628         7102 :         tbinfo->attidentity = pg_malloc_array(char, numatts);
    9629         7102 :         tbinfo->attgenerated = pg_malloc_array(char, numatts);
    9630         7102 :         tbinfo->attisdropped = pg_malloc_array(bool, numatts);
    9631         7102 :         tbinfo->attlen = pg_malloc_array(int, numatts);
    9632         7102 :         tbinfo->attalign = pg_malloc_array(char, numatts);
    9633         7102 :         tbinfo->attislocal = pg_malloc_array(bool, numatts);
    9634         7102 :         tbinfo->attoptions = pg_malloc_array(char *, numatts);
    9635         7102 :         tbinfo->attcollation = pg_malloc_array(Oid, numatts);
    9636         7102 :         tbinfo->attcompression = pg_malloc_array(char, numatts);
    9637         7102 :         tbinfo->attfdwoptions = pg_malloc_array(char *, numatts);
    9638         7102 :         tbinfo->attmissingval = pg_malloc_array(char *, numatts);
    9639         7102 :         tbinfo->notnull_constrs = pg_malloc_array(char *, numatts);
    9640         7102 :         tbinfo->notnull_comment = pg_malloc_array(char *, numatts);
    9641         7102 :         tbinfo->notnull_invalid = pg_malloc_array(bool, numatts);
    9642         7102 :         tbinfo->notnull_noinh = pg_malloc_array(bool, numatts);
    9643         7102 :         tbinfo->notnull_islocal = pg_malloc_array(bool, numatts);
    9644         7102 :         tbinfo->attrdefs = pg_malloc_array(AttrDefInfo *, numatts);
    9645         7102 :         hasdefaults = false;
    9646              : 
    9647        33514 :         for (int j = 0; j < numatts; j++, r++)
    9648              :         {
    9649        26412 :             if (j + 1 != atoi(PQgetvalue(res, r, i_attnum)) &&
    9650            0 :                 !(fout->dopt->binary_upgrade && fout->remoteVersion < 120000 &&
    9651            0 :                   tbinfo->dobj.catId.oid == LargeObjectMetadataRelationId))
    9652            0 :                 pg_fatal("invalid column numbering in table \"%s\"",
    9653              :                          tbinfo->dobj.name);
    9654        26412 :             tbinfo->attnames[j] = pg_strdup(PQgetvalue(res, r, i_attname));
    9655        26412 :             tbinfo->atttypnames[j] = pg_strdup(PQgetvalue(res, r, i_atttypname));
    9656        26412 :             if (PQgetisnull(res, r, i_attstattarget))
    9657        26372 :                 tbinfo->attstattarget[j] = -1;
    9658              :             else
    9659           40 :                 tbinfo->attstattarget[j] = atoi(PQgetvalue(res, r, i_attstattarget));
    9660        26412 :             tbinfo->attstorage[j] = *(PQgetvalue(res, r, i_attstorage));
    9661        26412 :             tbinfo->typstorage[j] = *(PQgetvalue(res, r, i_typstorage));
    9662        26412 :             tbinfo->attidentity[j] = *(PQgetvalue(res, r, i_attidentity));
    9663        26412 :             tbinfo->attgenerated[j] = *(PQgetvalue(res, r, i_attgenerated));
    9664        26412 :             tbinfo->needs_override = tbinfo->needs_override || (tbinfo->attidentity[j] == ATTRIBUTE_IDENTITY_ALWAYS);
    9665        26412 :             tbinfo->attisdropped[j] = (PQgetvalue(res, r, i_attisdropped)[0] == 't');
    9666        26412 :             tbinfo->attlen[j] = atoi(PQgetvalue(res, r, i_attlen));
    9667        26412 :             tbinfo->attalign[j] = *(PQgetvalue(res, r, i_attalign));
    9668        26412 :             tbinfo->attislocal[j] = (PQgetvalue(res, r, i_attislocal)[0] == 't');
    9669              : 
    9670              :             /* Handle not-null constraint name and flags */
    9671        26412 :             determineNotNullFlags(fout, res, r,
    9672              :                                   tbinfo, j,
    9673              :                                   i_notnull_name,
    9674              :                                   i_notnull_comment,
    9675              :                                   i_notnull_invalidoid,
    9676              :                                   i_notnull_noinherit,
    9677              :                                   i_notnull_islocal,
    9678              :                                   &invalidnotnulloids);
    9679              : 
    9680        26412 :             tbinfo->notnull_comment[j] = PQgetisnull(res, r, i_notnull_comment) ?
    9681        26412 :                 NULL : pg_strdup(PQgetvalue(res, r, i_notnull_comment));
    9682        26412 :             tbinfo->attoptions[j] = pg_strdup(PQgetvalue(res, r, i_attoptions));
    9683        26412 :             tbinfo->attcollation[j] = atooid(PQgetvalue(res, r, i_attcollation));
    9684        26412 :             tbinfo->attcompression[j] = *(PQgetvalue(res, r, i_attcompression));
    9685        26412 :             tbinfo->attfdwoptions[j] = pg_strdup(PQgetvalue(res, r, i_attfdwoptions));
    9686        26412 :             tbinfo->attmissingval[j] = pg_strdup(PQgetvalue(res, r, i_attmissingval));
    9687        26412 :             tbinfo->attrdefs[j] = NULL; /* fix below */
    9688        26412 :             if (PQgetvalue(res, r, i_atthasdef)[0] == 't')
    9689         1323 :                 hasdefaults = true;
    9690              :         }
    9691              : 
    9692         7102 :         if (hasdefaults)
    9693              :         {
    9694              :             /* Collect OIDs of interesting tables that have defaults */
    9695          987 :             if (tbloids->len > 1) /* do we have more than the '{'? */
    9696          919 :                 appendPQExpBufferChar(tbloids, ',');
    9697          987 :             appendPQExpBuffer(tbloids, "%u", tbinfo->dobj.catId.oid);
    9698              :         }
    9699              :     }
    9700              : 
    9701              :     /* If invalidnotnulloids has any data, finalize it */
    9702          259 :     if (invalidnotnulloids != NULL)
    9703           43 :         appendPQExpBufferChar(invalidnotnulloids, '}');
    9704              : 
    9705          259 :     PQclear(res);
    9706              : 
    9707              :     /*
    9708              :      * Now get info about column defaults.  This is skipped for a data-only
    9709              :      * dump, as it is only needed for table schemas.
    9710              :      */
    9711          259 :     if (dopt->dumpSchema && tbloids->len > 1)
    9712              :     {
    9713              :         AttrDefInfo *attrdefs;
    9714              :         int         numDefaults;
    9715           60 :         TableInfo  *tbinfo = NULL;
    9716              : 
    9717           60 :         pg_log_info("finding table default expressions");
    9718              : 
    9719           60 :         appendPQExpBufferChar(tbloids, '}');
    9720              : 
    9721           60 :         printfPQExpBuffer(q, "SELECT a.tableoid, a.oid, adrelid, adnum, "
    9722              :                           "pg_catalog.pg_get_expr(adbin, adrelid) AS adsrc\n"
    9723              :                           "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
    9724              :                           "JOIN pg_catalog.pg_attrdef a ON (src.tbloid = a.adrelid)\n"
    9725              :                           "ORDER BY a.adrelid, a.adnum",
    9726              :                           tbloids->data);
    9727              : 
    9728           60 :         res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
    9729              : 
    9730           60 :         numDefaults = PQntuples(res);
    9731           60 :         attrdefs = pg_malloc_array(AttrDefInfo, numDefaults);
    9732              : 
    9733           60 :         curtblindx = -1;
    9734         1285 :         for (int j = 0; j < numDefaults; j++)
    9735              :         {
    9736         1225 :             Oid         adtableoid = atooid(PQgetvalue(res, j, 0));
    9737         1225 :             Oid         adoid = atooid(PQgetvalue(res, j, 1));
    9738         1225 :             Oid         adrelid = atooid(PQgetvalue(res, j, 2));
    9739         1225 :             int         adnum = atoi(PQgetvalue(res, j, 3));
    9740         1225 :             char       *adsrc = PQgetvalue(res, j, 4);
    9741              : 
    9742              :             /*
    9743              :              * Locate the associated TableInfo; we rely on tblinfo[] being in
    9744              :              * OID order.
    9745              :              */
    9746         1225 :             if (tbinfo == NULL || tbinfo->dobj.catId.oid != adrelid)
    9747              :             {
    9748        20329 :                 while (++curtblindx < numTables)
    9749              :                 {
    9750        20329 :                     tbinfo = &tblinfo[curtblindx];
    9751        20329 :                     if (tbinfo->dobj.catId.oid == adrelid)
    9752          919 :                         break;
    9753              :                 }
    9754          919 :                 if (curtblindx >= numTables)
    9755            0 :                     pg_fatal("unrecognized table OID %u", adrelid);
    9756              :             }
    9757              : 
    9758         1225 :             if (adnum <= 0 || adnum > tbinfo->numatts)
    9759            0 :                 pg_fatal("invalid adnum value %d for table \"%s\"",
    9760              :                          adnum, tbinfo->dobj.name);
    9761              : 
    9762              :             /*
    9763              :              * dropped columns shouldn't have defaults, but just in case,
    9764              :              * ignore 'em
    9765              :              */
    9766         1225 :             if (tbinfo->attisdropped[adnum - 1])
    9767            0 :                 continue;
    9768              : 
    9769         1225 :             attrdefs[j].dobj.objType = DO_ATTRDEF;
    9770         1225 :             attrdefs[j].dobj.catId.tableoid = adtableoid;
    9771         1225 :             attrdefs[j].dobj.catId.oid = adoid;
    9772         1225 :             AssignDumpId(&attrdefs[j].dobj);
    9773         1225 :             attrdefs[j].adtable = tbinfo;
    9774         1225 :             attrdefs[j].adnum = adnum;
    9775         1225 :             attrdefs[j].adef_expr = pg_strdup(adsrc);
    9776              : 
    9777         1225 :             attrdefs[j].dobj.name = pg_strdup(tbinfo->dobj.name);
    9778         1225 :             attrdefs[j].dobj.namespace = tbinfo->dobj.namespace;
    9779              : 
    9780         1225 :             attrdefs[j].dobj.dump = tbinfo->dobj.dump;
    9781              : 
    9782              :             /*
    9783              :              * Figure out whether the default/generation expression should be
    9784              :              * dumped as part of the main CREATE TABLE (or similar) command or
    9785              :              * as a separate ALTER TABLE (or similar) command. The preference
    9786              :              * is to put it into the CREATE command, but in some cases that's
    9787              :              * not possible.
    9788              :              */
    9789         1225 :             if (tbinfo->attgenerated[adnum - 1])
    9790              :             {
    9791              :                 /*
    9792              :                  * Column generation expressions cannot be dumped separately,
    9793              :                  * because there is no syntax for it.  By setting separate to
    9794              :                  * false here we prevent the "default" from being processed as
    9795              :                  * its own dumpable object.  Later, flagInhAttrs() will mark
    9796              :                  * it as not to be dumped at all, if possible (that is, if it
    9797              :                  * can be inherited from a parent).
    9798              :                  */
    9799          696 :                 attrdefs[j].separate = false;
    9800              :             }
    9801          529 :             else if (tbinfo->relkind == RELKIND_VIEW)
    9802              :             {
    9803              :                 /*
    9804              :                  * Defaults on a VIEW must always be dumped as separate ALTER
    9805              :                  * TABLE commands.
    9806              :                  */
    9807           32 :                 attrdefs[j].separate = true;
    9808              :             }
    9809          497 :             else if (!shouldPrintColumn(dopt, tbinfo, adnum - 1))
    9810              :             {
    9811              :                 /* column will be suppressed, print default separately */
    9812            4 :                 attrdefs[j].separate = true;
    9813              :             }
    9814              :             else
    9815              :             {
    9816          493 :                 attrdefs[j].separate = false;
    9817              :             }
    9818              : 
    9819         1225 :             if (!attrdefs[j].separate)
    9820              :             {
    9821              :                 /*
    9822              :                  * Mark the default as needing to appear before the table, so
    9823              :                  * that any dependencies it has must be emitted before the
    9824              :                  * CREATE TABLE.  If this is not possible, we'll change to
    9825              :                  * "separate" mode while sorting dependencies.
    9826              :                  */
    9827         1189 :                 addObjectDependency(&tbinfo->dobj,
    9828         1189 :                                     attrdefs[j].dobj.dumpId);
    9829              :             }
    9830              : 
    9831         1225 :             tbinfo->attrdefs[adnum - 1] = &attrdefs[j];
    9832              :         }
    9833              : 
    9834           60 :         PQclear(res);
    9835              :     }
    9836              : 
    9837              :     /*
    9838              :      * Get info about NOT NULL NOT VALID constraints.  This is skipped for a
    9839              :      * data-only dump, as it is only needed for table schemas.
    9840              :      */
    9841          259 :     if (dopt->dumpSchema && invalidnotnulloids)
    9842              :     {
    9843              :         ConstraintInfo *constrs;
    9844              :         int         numConstrs;
    9845              :         int         i_tableoid;
    9846              :         int         i_oid;
    9847              :         int         i_conrelid;
    9848              :         int         i_conname;
    9849              :         int         i_consrc;
    9850              :         int         i_conislocal;
    9851              : 
    9852           37 :         pg_log_info("finding invalid not-null constraints");
    9853              : 
    9854           37 :         resetPQExpBuffer(q);
    9855           37 :         appendPQExpBuffer(q,
    9856              :                           "SELECT c.tableoid, c.oid, conrelid, conname, "
    9857              :                           "pg_catalog.pg_get_constraintdef(c.oid) AS consrc, "
    9858              :                           "conislocal, convalidated "
    9859              :                           "FROM unnest('%s'::pg_catalog.oid[]) AS src(conoid)\n"
    9860              :                           "JOIN pg_catalog.pg_constraint c ON (src.conoid = c.oid)\n"
    9861              :                           "ORDER BY c.conrelid, c.conname",
    9862           37 :                           invalidnotnulloids->data);
    9863              : 
    9864           37 :         res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
    9865              : 
    9866           37 :         numConstrs = PQntuples(res);
    9867           37 :         constrs = pg_malloc_array(ConstraintInfo, numConstrs);
    9868              : 
    9869           37 :         i_tableoid = PQfnumber(res, "tableoid");
    9870           37 :         i_oid = PQfnumber(res, "oid");
    9871           37 :         i_conrelid = PQfnumber(res, "conrelid");
    9872           37 :         i_conname = PQfnumber(res, "conname");
    9873           37 :         i_consrc = PQfnumber(res, "consrc");
    9874           37 :         i_conislocal = PQfnumber(res, "conislocal");
    9875              : 
    9876              :         /* As above, this loop iterates once per table, not once per row */
    9877           37 :         curtblindx = -1;
    9878          104 :         for (int j = 0; j < numConstrs;)
    9879              :         {
    9880           67 :             Oid         conrelid = atooid(PQgetvalue(res, j, i_conrelid));
    9881           67 :             TableInfo  *tbinfo = NULL;
    9882              :             int         numcons;
    9883              : 
    9884              :             /* Count rows for this table */
    9885           67 :             for (numcons = 1; numcons < numConstrs - j; numcons++)
    9886           30 :                 if (atooid(PQgetvalue(res, j + numcons, i_conrelid)) != conrelid)
    9887           30 :                     break;
    9888              : 
    9889              :             /*
    9890              :              * Locate the associated TableInfo; we rely on tblinfo[] being in
    9891              :              * OID order.
    9892              :              */
    9893        13567 :             while (++curtblindx < numTables)
    9894              :             {
    9895        13567 :                 tbinfo = &tblinfo[curtblindx];
    9896        13567 :                 if (tbinfo->dobj.catId.oid == conrelid)
    9897           67 :                     break;
    9898              :             }
    9899           67 :             if (curtblindx >= numTables)
    9900            0 :                 pg_fatal("unrecognized table OID %u", conrelid);
    9901              : 
    9902          134 :             for (int c = 0; c < numcons; c++, j++)
    9903              :             {
    9904           67 :                 constrs[j].dobj.objType = DO_CONSTRAINT;
    9905           67 :                 constrs[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
    9906           67 :                 constrs[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
    9907           67 :                 AssignDumpId(&constrs[j].dobj);
    9908           67 :                 constrs[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_conname));
    9909           67 :                 constrs[j].dobj.namespace = tbinfo->dobj.namespace;
    9910           67 :                 constrs[j].contable = tbinfo;
    9911           67 :                 constrs[j].condomain = NULL;
    9912           67 :                 constrs[j].contype = 'n';
    9913           67 :                 constrs[j].condef = pg_strdup(PQgetvalue(res, j, i_consrc));
    9914           67 :                 constrs[j].confrelid = InvalidOid;
    9915           67 :                 constrs[j].conindex = 0;
    9916           67 :                 constrs[j].condeferrable = false;
    9917           67 :                 constrs[j].condeferred = false;
    9918           67 :                 constrs[j].conislocal = (PQgetvalue(res, j, i_conislocal)[0] == 't');
    9919              : 
    9920              :                 /*
    9921              :                  * All invalid not-null constraints must be dumped separately,
    9922              :                  * because CREATE TABLE would not create them as invalid, and
    9923              :                  * also because they must be created after potentially
    9924              :                  * violating data has been loaded.
    9925              :                  */
    9926           67 :                 constrs[j].separate = true;
    9927              : 
    9928           67 :                 constrs[j].dobj.dump = tbinfo->dobj.dump;
    9929              :             }
    9930              :         }
    9931           37 :         PQclear(res);
    9932              :     }
    9933              : 
    9934              :     /*
    9935              :      * Get info about table CHECK constraints.  This is skipped for a
    9936              :      * data-only dump, as it is only needed for table schemas.
    9937              :      */
    9938          259 :     if (dopt->dumpSchema && checkoids->len > 2)
    9939              :     {
    9940              :         ConstraintInfo *constrs;
    9941              :         int         numConstrs;
    9942              :         int         i_tableoid;
    9943              :         int         i_oid;
    9944              :         int         i_conrelid;
    9945              :         int         i_conname;
    9946              :         int         i_consrc;
    9947              :         int         i_conislocal;
    9948              :         int         i_convalidated;
    9949              : 
    9950           61 :         pg_log_info("finding table check constraints");
    9951              : 
    9952           61 :         resetPQExpBuffer(q);
    9953           61 :         appendPQExpBuffer(q,
    9954              :                           "SELECT c.tableoid, c.oid, conrelid, conname, "
    9955              :                           "pg_catalog.pg_get_constraintdef(c.oid) AS consrc, "
    9956              :                           "conislocal, convalidated "
    9957              :                           "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
    9958              :                           "JOIN pg_catalog.pg_constraint c ON (src.tbloid = c.conrelid)\n"
    9959              :                           "WHERE contype = 'c' "
    9960              :                           "ORDER BY c.conrelid, c.conname",
    9961              :                           checkoids->data);
    9962              : 
    9963           61 :         res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
    9964              : 
    9965           61 :         numConstrs = PQntuples(res);
    9966           61 :         constrs = pg_malloc_array(ConstraintInfo, numConstrs);
    9967              : 
    9968           61 :         i_tableoid = PQfnumber(res, "tableoid");
    9969           61 :         i_oid = PQfnumber(res, "oid");
    9970           61 :         i_conrelid = PQfnumber(res, "conrelid");
    9971           61 :         i_conname = PQfnumber(res, "conname");
    9972           61 :         i_consrc = PQfnumber(res, "consrc");
    9973           61 :         i_conislocal = PQfnumber(res, "conislocal");
    9974           61 :         i_convalidated = PQfnumber(res, "convalidated");
    9975              : 
    9976              :         /* As above, this loop iterates once per table, not once per row */
    9977           61 :         curtblindx = -1;
    9978          538 :         for (int j = 0; j < numConstrs;)
    9979              :         {
    9980          477 :             Oid         conrelid = atooid(PQgetvalue(res, j, i_conrelid));
    9981          477 :             TableInfo  *tbinfo = NULL;
    9982              :             int         numcons;
    9983              : 
    9984              :             /* Count rows for this table */
    9985          612 :             for (numcons = 1; numcons < numConstrs - j; numcons++)
    9986          551 :                 if (atooid(PQgetvalue(res, j + numcons, i_conrelid)) != conrelid)
    9987          416 :                     break;
    9988              : 
    9989              :             /*
    9990              :              * Locate the associated TableInfo; we rely on tblinfo[] being in
    9991              :              * OID order.
    9992              :              */
    9993        19603 :             while (++curtblindx < numTables)
    9994              :             {
    9995        19603 :                 tbinfo = &tblinfo[curtblindx];
    9996        19603 :                 if (tbinfo->dobj.catId.oid == conrelid)
    9997          477 :                     break;
    9998              :             }
    9999          477 :             if (curtblindx >= numTables)
   10000            0 :                 pg_fatal("unrecognized table OID %u", conrelid);
   10001              : 
   10002          477 :             if (numcons != tbinfo->ncheck)
   10003              :             {
   10004            0 :                 pg_log_error(ngettext("expected %d check constraint on table \"%s\" but found %d",
   10005              :                                       "expected %d check constraints on table \"%s\" but found %d",
   10006              :                                       tbinfo->ncheck),
   10007              :                              tbinfo->ncheck, tbinfo->dobj.name, numcons);
   10008            0 :                 pg_log_error_hint("The system catalogs might be corrupted.");
   10009            0 :                 exit_nicely(1);
   10010              :             }
   10011              : 
   10012          477 :             tbinfo->checkexprs = constrs + j;
   10013              : 
   10014         1089 :             for (int c = 0; c < numcons; c++, j++)
   10015              :             {
   10016          612 :                 bool        validated = PQgetvalue(res, j, i_convalidated)[0] == 't';
   10017              : 
   10018          612 :                 constrs[j].dobj.objType = DO_CONSTRAINT;
   10019          612 :                 constrs[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
   10020          612 :                 constrs[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
   10021          612 :                 AssignDumpId(&constrs[j].dobj);
   10022          612 :                 constrs[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_conname));
   10023          612 :                 constrs[j].dobj.namespace = tbinfo->dobj.namespace;
   10024          612 :                 constrs[j].contable = tbinfo;
   10025          612 :                 constrs[j].condomain = NULL;
   10026          612 :                 constrs[j].contype = 'c';
   10027          612 :                 constrs[j].condef = pg_strdup(PQgetvalue(res, j, i_consrc));
   10028          612 :                 constrs[j].confrelid = InvalidOid;
   10029          612 :                 constrs[j].conindex = 0;
   10030          612 :                 constrs[j].condeferrable = false;
   10031          612 :                 constrs[j].condeferred = false;
   10032          612 :                 constrs[j].conislocal = (PQgetvalue(res, j, i_conislocal)[0] == 't');
   10033              : 
   10034              :                 /*
   10035              :                  * An unvalidated constraint needs to be dumped separately, so
   10036              :                  * that potentially-violating existing data is loaded before
   10037              :                  * the constraint.
   10038              :                  */
   10039          612 :                 constrs[j].separate = !validated;
   10040              : 
   10041          612 :                 constrs[j].dobj.dump = tbinfo->dobj.dump;
   10042              : 
   10043              :                 /*
   10044              :                  * Mark the constraint as needing to appear before the table
   10045              :                  * --- this is so that any other dependencies of the
   10046              :                  * constraint will be emitted before we try to create the
   10047              :                  * table.  If the constraint is to be dumped separately, it
   10048              :                  * will be dumped after data is loaded anyway, so don't do it.
   10049              :                  * (There's an automatic dependency in the opposite direction
   10050              :                  * anyway, so don't need to add one manually here.)
   10051              :                  */
   10052          612 :                 if (!constrs[j].separate)
   10053          547 :                     addObjectDependency(&tbinfo->dobj,
   10054          547 :                                         constrs[j].dobj.dumpId);
   10055              : 
   10056              :                 /*
   10057              :                  * We will detect later whether the constraint must be split
   10058              :                  * out from the table definition.
   10059              :                  */
   10060              :             }
   10061              :         }
   10062              : 
   10063           61 :         PQclear(res);
   10064              :     }
   10065              : 
   10066          259 :     destroyPQExpBuffer(q);
   10067          259 :     destroyPQExpBuffer(tbloids);
   10068          259 :     destroyPQExpBuffer(checkoids);
   10069          259 : }
   10070              : 
   10071              : /*
   10072              :  * Based on the getTableAttrs query's row corresponding to one column, set
   10073              :  * the name and flags to handle a not-null constraint for that column in
   10074              :  * the tbinfo struct.
   10075              :  *
   10076              :  * Result row 'r' is for tbinfo's attribute 'j'.
   10077              :  *
   10078              :  * There are four possibilities:
   10079              :  * 1) the column has no not-null constraints. In that case, ->notnull_constrs
   10080              :  *    (the constraint name) remains NULL.
   10081              :  * 2) The column has a constraint with no name (this is the case when
   10082              :  *    constraints come from pre-18 servers).  In this case, ->notnull_constrs
   10083              :  *    is set to the empty string; dumpTableSchema will print just "NOT NULL".
   10084              :  * 3) The column has an invalid not-null constraint.  This must be treated
   10085              :  *    as a separate object (because it must be created after the table data
   10086              :  *    is loaded).  So we add its OID to invalidnotnulloids for processing
   10087              :  *    elsewhere and do nothing further with it here.  We distinguish this
   10088              :  *    case because the "notnull_invalidoid" column has been set to a non-NULL
   10089              :  *    value, which is the constraint OID.  Valid constraints have a null OID.
   10090              :  * 4) The column has a constraint with a known name; in that case
   10091              :  *    notnull_constrs carries that name and dumpTableSchema will print
   10092              :  *    "CONSTRAINT the_name NOT NULL".  However, if the name is the default
   10093              :  *    (table_column_not_null) and there's no comment on the constraint,
   10094              :  *    there's no need to print that name in the dump, so notnull_constrs
   10095              :  *    is set to the empty string and it behaves as case 2.
   10096              :  *
   10097              :  * In a child table that inherits from a parent already containing NOT NULL
   10098              :  * constraints and the columns in the child don't have their own NOT NULL
   10099              :  * declarations, we suppress printing constraints in the child: the
   10100              :  * constraints are acquired at the point where the child is attached to the
   10101              :  * parent.  This is tracked in ->notnull_islocal; for servers pre-18 this is
   10102              :  * set not here but in flagInhAttrs.  That flag is also used when the
   10103              :  * constraint was validated in a child but all its parent have it as NOT
   10104              :  * VALID.
   10105              :  *
   10106              :  * Any of these constraints might have the NO INHERIT bit.  If so we set
   10107              :  * ->notnull_noinh and NO INHERIT will be printed by dumpTableSchema.
   10108              :  *
   10109              :  * In case 4 above, the name comparison is a bit of a hack; it actually fails
   10110              :  * to do the right thing in all but the trivial case.  However, the downside
   10111              :  * of getting it wrong is simply that the name is printed rather than
   10112              :  * suppressed, so it's not a big deal.
   10113              :  *
   10114              :  * invalidnotnulloids is expected to be given as NULL; if any invalid not-null
   10115              :  * constraints are found, it is initialized and filled with the array of
   10116              :  * OIDs of such constraints, for later processing.
   10117              :  */
   10118              : static void
   10119        26412 : determineNotNullFlags(Archive *fout, PGresult *res, int r,
   10120              :                       TableInfo *tbinfo, int j,
   10121              :                       int i_notnull_name,
   10122              :                       int i_notnull_comment,
   10123              :                       int i_notnull_invalidoid,
   10124              :                       int i_notnull_noinherit,
   10125              :                       int i_notnull_islocal,
   10126              :                       PQExpBuffer *invalidnotnulloids)
   10127              : {
   10128        26412 :     DumpOptions *dopt = fout->dopt;
   10129              : 
   10130              :     /*
   10131              :      * If this not-null constraint is not valid, list its OID in
   10132              :      * invalidnotnulloids and do nothing further.  It'll be processed
   10133              :      * elsewhere later.
   10134              :      *
   10135              :      * Because invalid not-null constraints are rare, we don't want to malloc
   10136              :      * invalidnotnulloids until we're sure we're going it need it, which
   10137              :      * happens here.
   10138              :      */
   10139        26412 :     if (!PQgetisnull(res, r, i_notnull_invalidoid))
   10140              :     {
   10141           73 :         char       *constroid = PQgetvalue(res, r, i_notnull_invalidoid);
   10142              : 
   10143           73 :         if (*invalidnotnulloids == NULL)
   10144              :         {
   10145           43 :             *invalidnotnulloids = createPQExpBuffer();
   10146           43 :             appendPQExpBufferChar(*invalidnotnulloids, '{');
   10147           43 :             appendPQExpBufferStr(*invalidnotnulloids, constroid);
   10148              :         }
   10149              :         else
   10150           30 :             appendPQExpBuffer(*invalidnotnulloids, ",%s", constroid);
   10151              : 
   10152              :         /*
   10153              :          * Track when a parent constraint is invalid for the cases where a
   10154              :          * child constraint has been validated independenly.
   10155              :          */
   10156           73 :         tbinfo->notnull_invalid[j] = true;
   10157              : 
   10158              :         /* nothing else to do */
   10159           73 :         tbinfo->notnull_constrs[j] = NULL;
   10160           73 :         return;
   10161              :     }
   10162              : 
   10163              :     /*
   10164              :      * notnull_noinh is straight from the query result. notnull_islocal also,
   10165              :      * though flagInhAttrs may change that one later.
   10166              :      */
   10167        26339 :     tbinfo->notnull_noinh[j] = PQgetvalue(res, r, i_notnull_noinherit)[0] == 't';
   10168        26339 :     tbinfo->notnull_islocal[j] = PQgetvalue(res, r, i_notnull_islocal)[0] == 't';
   10169        26339 :     tbinfo->notnull_invalid[j] = false;
   10170              : 
   10171              :     /*
   10172              :      * Determine a constraint name to use.  If the column is not marked not-
   10173              :      * null, we set NULL which cues ... to do nothing.  An empty string says
   10174              :      * to print an unnamed NOT NULL, and anything else is a constraint name to
   10175              :      * use.
   10176              :      */
   10177        26339 :     if (fout->remoteVersion < 180000)
   10178              :     {
   10179              :         /*
   10180              :          * < 18 doesn't have not-null names, so an unnamed constraint is
   10181              :          * sufficient.
   10182              :          */
   10183            0 :         if (PQgetisnull(res, r, i_notnull_name))
   10184            0 :             tbinfo->notnull_constrs[j] = NULL;
   10185              :         else
   10186            0 :             tbinfo->notnull_constrs[j] = "";
   10187              :     }
   10188              :     else
   10189              :     {
   10190        26339 :         if (PQgetisnull(res, r, i_notnull_name))
   10191        23441 :             tbinfo->notnull_constrs[j] = NULL;
   10192              :         else
   10193              :         {
   10194              :             /*
   10195              :              * In binary upgrade of inheritance child tables, must have a
   10196              :              * constraint name that we can UPDATE later; same if there's a
   10197              :              * comment on the constraint.
   10198              :              */
   10199         2898 :             if ((dopt->binary_upgrade &&
   10200          373 :                  !tbinfo->ispartition &&
   10201         3162 :                  !tbinfo->notnull_islocal[j]) ||
   10202         2877 :                 !PQgetisnull(res, r, i_notnull_comment))
   10203              :             {
   10204           67 :                 tbinfo->notnull_constrs[j] =
   10205           67 :                     pstrdup(PQgetvalue(res, r, i_notnull_name));
   10206              :             }
   10207              :             else
   10208              :             {
   10209              :                 char       *default_name;
   10210              : 
   10211              :                 /* XXX should match ChooseConstraintName better */
   10212         2831 :                 default_name = psprintf("%s_%s_not_null", tbinfo->dobj.name,
   10213         2831 :                                         tbinfo->attnames[j]);
   10214         2831 :                 if (strcmp(default_name,
   10215         2831 :                            PQgetvalue(res, r, i_notnull_name)) == 0)
   10216         1898 :                     tbinfo->notnull_constrs[j] = "";
   10217              :                 else
   10218              :                 {
   10219          933 :                     tbinfo->notnull_constrs[j] =
   10220          933 :                         pstrdup(PQgetvalue(res, r, i_notnull_name));
   10221              :                 }
   10222         2831 :                 free(default_name);
   10223              :             }
   10224              :         }
   10225              :     }
   10226              : }
   10227              : 
   10228              : /*
   10229              :  * Test whether a column should be printed as part of table's CREATE TABLE.
   10230              :  * Column number is zero-based.
   10231              :  *
   10232              :  * Normally this is always true, but it's false for dropped columns, as well
   10233              :  * as those that were inherited without any local definition.  (If we print
   10234              :  * such a column it will mistakenly get pg_attribute.attislocal set to true.)
   10235              :  * For partitions, it's always true, because we want the partitions to be
   10236              :  * created independently and ATTACH PARTITION used afterwards.
   10237              :  *
   10238              :  * In binary_upgrade mode, we must print all columns and fix the attislocal/
   10239              :  * attisdropped state later, so as to keep control of the physical column
   10240              :  * order.
   10241              :  *
   10242              :  * This function exists because there are scattered nonobvious places that
   10243              :  * must be kept in sync with this decision.
   10244              :  */
   10245              : bool
   10246        42898 : shouldPrintColumn(const DumpOptions *dopt, const TableInfo *tbinfo, int colno)
   10247              : {
   10248        42898 :     if (dopt->binary_upgrade)
   10249         6600 :         return true;
   10250        36298 :     if (tbinfo->attisdropped[colno])
   10251          734 :         return false;
   10252        35564 :     return (tbinfo->attislocal[colno] || tbinfo->ispartition);
   10253              : }
   10254              : 
   10255              : 
   10256              : /*
   10257              :  * getTSParsers:
   10258              :  *    get information about all text search parsers in the system catalogs
   10259              :  */
   10260              : void
   10261          259 : getTSParsers(Archive *fout)
   10262              : {
   10263              :     PGresult   *res;
   10264              :     int         ntups;
   10265              :     int         i;
   10266              :     PQExpBuffer query;
   10267              :     TSParserInfo *prsinfo;
   10268              :     int         i_tableoid;
   10269              :     int         i_oid;
   10270              :     int         i_prsname;
   10271              :     int         i_prsnamespace;
   10272              :     int         i_prsstart;
   10273              :     int         i_prstoken;
   10274              :     int         i_prsend;
   10275              :     int         i_prsheadline;
   10276              :     int         i_prslextype;
   10277              : 
   10278          259 :     query = createPQExpBuffer();
   10279              : 
   10280              :     /*
   10281              :      * find all text search objects, including builtin ones; we filter out
   10282              :      * system-defined objects at dump-out time.
   10283              :      */
   10284              : 
   10285          259 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, prsname, prsnamespace, "
   10286              :                          "prsstart::oid, prstoken::oid, "
   10287              :                          "prsend::oid, prsheadline::oid, prslextype::oid "
   10288              :                          "FROM pg_ts_parser");
   10289              : 
   10290          259 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   10291              : 
   10292          259 :     ntups = PQntuples(res);
   10293              : 
   10294          259 :     prsinfo = pg_malloc_array(TSParserInfo, ntups);
   10295              : 
   10296          259 :     i_tableoid = PQfnumber(res, "tableoid");
   10297          259 :     i_oid = PQfnumber(res, "oid");
   10298          259 :     i_prsname = PQfnumber(res, "prsname");
   10299          259 :     i_prsnamespace = PQfnumber(res, "prsnamespace");
   10300          259 :     i_prsstart = PQfnumber(res, "prsstart");
   10301          259 :     i_prstoken = PQfnumber(res, "prstoken");
   10302          259 :     i_prsend = PQfnumber(res, "prsend");
   10303          259 :     i_prsheadline = PQfnumber(res, "prsheadline");
   10304          259 :     i_prslextype = PQfnumber(res, "prslextype");
   10305              : 
   10306          563 :     for (i = 0; i < ntups; i++)
   10307              :     {
   10308          304 :         prsinfo[i].dobj.objType = DO_TSPARSER;
   10309          304 :         prsinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
   10310          304 :         prsinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
   10311          304 :         AssignDumpId(&prsinfo[i].dobj);
   10312          304 :         prsinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_prsname));
   10313          608 :         prsinfo[i].dobj.namespace =
   10314          304 :             findNamespace(atooid(PQgetvalue(res, i, i_prsnamespace)));
   10315          304 :         prsinfo[i].prsstart = atooid(PQgetvalue(res, i, i_prsstart));
   10316          304 :         prsinfo[i].prstoken = atooid(PQgetvalue(res, i, i_prstoken));
   10317          304 :         prsinfo[i].prsend = atooid(PQgetvalue(res, i, i_prsend));
   10318          304 :         prsinfo[i].prsheadline = atooid(PQgetvalue(res, i, i_prsheadline));
   10319          304 :         prsinfo[i].prslextype = atooid(PQgetvalue(res, i, i_prslextype));
   10320              : 
   10321              :         /* Decide whether we want to dump it */
   10322          304 :         selectDumpableObject(&(prsinfo[i].dobj), fout);
   10323              :     }
   10324              : 
   10325          259 :     PQclear(res);
   10326              : 
   10327          259 :     destroyPQExpBuffer(query);
   10328          259 : }
   10329              : 
   10330              : /*
   10331              :  * getTSDictionaries:
   10332              :  *    get information about all text search dictionaries in the system catalogs
   10333              :  */
   10334              : void
   10335          259 : getTSDictionaries(Archive *fout)
   10336              : {
   10337              :     PGresult   *res;
   10338              :     int         ntups;
   10339              :     int         i;
   10340              :     PQExpBuffer query;
   10341              :     TSDictInfo *dictinfo;
   10342              :     int         i_tableoid;
   10343              :     int         i_oid;
   10344              :     int         i_dictname;
   10345              :     int         i_dictnamespace;
   10346              :     int         i_dictowner;
   10347              :     int         i_dicttemplate;
   10348              :     int         i_dictinitoption;
   10349              : 
   10350          259 :     query = createPQExpBuffer();
   10351              : 
   10352          259 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, dictname, "
   10353              :                          "dictnamespace, dictowner, "
   10354              :                          "dicttemplate, dictinitoption "
   10355              :                          "FROM pg_ts_dict");
   10356              : 
   10357          259 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   10358              : 
   10359          259 :     ntups = PQntuples(res);
   10360              : 
   10361          259 :     dictinfo = pg_malloc_array(TSDictInfo, ntups);
   10362              : 
   10363          259 :     i_tableoid = PQfnumber(res, "tableoid");
   10364          259 :     i_oid = PQfnumber(res, "oid");
   10365          259 :     i_dictname = PQfnumber(res, "dictname");
   10366          259 :     i_dictnamespace = PQfnumber(res, "dictnamespace");
   10367          259 :     i_dictowner = PQfnumber(res, "dictowner");
   10368          259 :     i_dictinitoption = PQfnumber(res, "dictinitoption");
   10369          259 :     i_dicttemplate = PQfnumber(res, "dicttemplate");
   10370              : 
   10371         8655 :     for (i = 0; i < ntups; i++)
   10372              :     {
   10373         8396 :         dictinfo[i].dobj.objType = DO_TSDICT;
   10374         8396 :         dictinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
   10375         8396 :         dictinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
   10376         8396 :         AssignDumpId(&dictinfo[i].dobj);
   10377         8396 :         dictinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_dictname));
   10378        16792 :         dictinfo[i].dobj.namespace =
   10379         8396 :             findNamespace(atooid(PQgetvalue(res, i, i_dictnamespace)));
   10380         8396 :         dictinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_dictowner));
   10381         8396 :         dictinfo[i].dicttemplate = atooid(PQgetvalue(res, i, i_dicttemplate));
   10382         8396 :         if (PQgetisnull(res, i, i_dictinitoption))
   10383          304 :             dictinfo[i].dictinitoption = NULL;
   10384              :         else
   10385         8092 :             dictinfo[i].dictinitoption = pg_strdup(PQgetvalue(res, i, i_dictinitoption));
   10386              : 
   10387              :         /* Decide whether we want to dump it */
   10388         8396 :         selectDumpableObject(&(dictinfo[i].dobj), fout);
   10389              :     }
   10390              : 
   10391          259 :     PQclear(res);
   10392              : 
   10393          259 :     destroyPQExpBuffer(query);
   10394          259 : }
   10395              : 
   10396              : /*
   10397              :  * getTSTemplates:
   10398              :  *    get information about all text search templates in the system catalogs
   10399              :  */
   10400              : void
   10401          259 : getTSTemplates(Archive *fout)
   10402              : {
   10403              :     PGresult   *res;
   10404              :     int         ntups;
   10405              :     int         i;
   10406              :     PQExpBuffer query;
   10407              :     TSTemplateInfo *tmplinfo;
   10408              :     int         i_tableoid;
   10409              :     int         i_oid;
   10410              :     int         i_tmplname;
   10411              :     int         i_tmplnamespace;
   10412              :     int         i_tmplinit;
   10413              :     int         i_tmpllexize;
   10414              : 
   10415          259 :     query = createPQExpBuffer();
   10416              : 
   10417          259 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, tmplname, "
   10418              :                          "tmplnamespace, tmplinit::oid, tmpllexize::oid "
   10419              :                          "FROM pg_ts_template");
   10420              : 
   10421          259 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   10422              : 
   10423          259 :     ntups = PQntuples(res);
   10424              : 
   10425          259 :     tmplinfo = pg_malloc_array(TSTemplateInfo, ntups);
   10426              : 
   10427          259 :     i_tableoid = PQfnumber(res, "tableoid");
   10428          259 :     i_oid = PQfnumber(res, "oid");
   10429          259 :     i_tmplname = PQfnumber(res, "tmplname");
   10430          259 :     i_tmplnamespace = PQfnumber(res, "tmplnamespace");
   10431          259 :     i_tmplinit = PQfnumber(res, "tmplinit");
   10432          259 :     i_tmpllexize = PQfnumber(res, "tmpllexize");
   10433              : 
   10434         1599 :     for (i = 0; i < ntups; i++)
   10435              :     {
   10436         1340 :         tmplinfo[i].dobj.objType = DO_TSTEMPLATE;
   10437         1340 :         tmplinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
   10438         1340 :         tmplinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
   10439         1340 :         AssignDumpId(&tmplinfo[i].dobj);
   10440         1340 :         tmplinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_tmplname));
   10441         2680 :         tmplinfo[i].dobj.namespace =
   10442         1340 :             findNamespace(atooid(PQgetvalue(res, i, i_tmplnamespace)));
   10443         1340 :         tmplinfo[i].tmplinit = atooid(PQgetvalue(res, i, i_tmplinit));
   10444         1340 :         tmplinfo[i].tmpllexize = atooid(PQgetvalue(res, i, i_tmpllexize));
   10445              : 
   10446              :         /* Decide whether we want to dump it */
   10447         1340 :         selectDumpableObject(&(tmplinfo[i].dobj), fout);
   10448              :     }
   10449              : 
   10450          259 :     PQclear(res);
   10451              : 
   10452          259 :     destroyPQExpBuffer(query);
   10453          259 : }
   10454              : 
   10455              : /*
   10456              :  * getTSConfigurations:
   10457              :  *    get information about all text search configurations
   10458              :  */
   10459              : void
   10460          259 : getTSConfigurations(Archive *fout)
   10461              : {
   10462              :     PGresult   *res;
   10463              :     int         ntups;
   10464              :     int         i;
   10465              :     PQExpBuffer query;
   10466              :     TSConfigInfo *cfginfo;
   10467              :     int         i_tableoid;
   10468              :     int         i_oid;
   10469              :     int         i_cfgname;
   10470              :     int         i_cfgnamespace;
   10471              :     int         i_cfgowner;
   10472              :     int         i_cfgparser;
   10473              : 
   10474          259 :     query = createPQExpBuffer();
   10475              : 
   10476          259 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, cfgname, "
   10477              :                          "cfgnamespace, cfgowner, cfgparser "
   10478              :                          "FROM pg_ts_config");
   10479              : 
   10480          259 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   10481              : 
   10482          259 :     ntups = PQntuples(res);
   10483              : 
   10484          259 :     cfginfo = pg_malloc_array(TSConfigInfo, ntups);
   10485              : 
   10486          259 :     i_tableoid = PQfnumber(res, "tableoid");
   10487          259 :     i_oid = PQfnumber(res, "oid");
   10488          259 :     i_cfgname = PQfnumber(res, "cfgname");
   10489          259 :     i_cfgnamespace = PQfnumber(res, "cfgnamespace");
   10490          259 :     i_cfgowner = PQfnumber(res, "cfgowner");
   10491          259 :     i_cfgparser = PQfnumber(res, "cfgparser");
   10492              : 
   10493         8620 :     for (i = 0; i < ntups; i++)
   10494              :     {
   10495         8361 :         cfginfo[i].dobj.objType = DO_TSCONFIG;
   10496         8361 :         cfginfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
   10497         8361 :         cfginfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
   10498         8361 :         AssignDumpId(&cfginfo[i].dobj);
   10499         8361 :         cfginfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_cfgname));
   10500        16722 :         cfginfo[i].dobj.namespace =
   10501         8361 :             findNamespace(atooid(PQgetvalue(res, i, i_cfgnamespace)));
   10502         8361 :         cfginfo[i].rolname = getRoleName(PQgetvalue(res, i, i_cfgowner));
   10503         8361 :         cfginfo[i].cfgparser = atooid(PQgetvalue(res, i, i_cfgparser));
   10504              : 
   10505              :         /* Decide whether we want to dump it */
   10506         8361 :         selectDumpableObject(&(cfginfo[i].dobj), fout);
   10507              :     }
   10508              : 
   10509          259 :     PQclear(res);
   10510              : 
   10511          259 :     destroyPQExpBuffer(query);
   10512          259 : }
   10513              : 
   10514              : /*
   10515              :  * getForeignDataWrappers:
   10516              :  *    get information about all foreign-data wrappers in the system catalogs
   10517              :  */
   10518              : void
   10519          259 : getForeignDataWrappers(Archive *fout)
   10520              : {
   10521              :     PGresult   *res;
   10522              :     int         ntups;
   10523              :     int         i;
   10524              :     PQExpBuffer query;
   10525              :     FdwInfo    *fdwinfo;
   10526              :     int         i_tableoid;
   10527              :     int         i_oid;
   10528              :     int         i_fdwname;
   10529              :     int         i_fdwowner;
   10530              :     int         i_fdwhandler;
   10531              :     int         i_fdwvalidator;
   10532              :     int         i_fdwconnection;
   10533              :     int         i_fdwacl;
   10534              :     int         i_acldefault;
   10535              :     int         i_fdwoptions;
   10536              : 
   10537          259 :     query = createPQExpBuffer();
   10538              : 
   10539          259 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, fdwname, "
   10540              :                          "fdwowner, "
   10541              :                          "fdwhandler::pg_catalog.regproc, "
   10542              :                          "fdwvalidator::pg_catalog.regproc, ");
   10543              : 
   10544          259 :     if (fout->remoteVersion >= 190000)
   10545          259 :         appendPQExpBufferStr(query, "fdwconnection::pg_catalog.regproc, ");
   10546              :     else
   10547            0 :         appendPQExpBufferStr(query, "'-' AS fdwconnection, ");
   10548              : 
   10549          259 :     appendPQExpBufferStr(query,
   10550              :                          "fdwacl, "
   10551              :                          "acldefault('F', fdwowner) AS acldefault, "
   10552              :                          "array_to_string(ARRAY("
   10553              :                          "SELECT quote_ident(option_name) || ' ' || "
   10554              :                          "quote_literal(option_value) "
   10555              :                          "FROM pg_options_to_table(fdwoptions) "
   10556              :                          "ORDER BY option_name"
   10557              :                          "), E',\n    ') AS fdwoptions "
   10558              :                          "FROM pg_foreign_data_wrapper");
   10559              : 
   10560          259 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   10561              : 
   10562          259 :     ntups = PQntuples(res);
   10563              : 
   10564          259 :     fdwinfo = pg_malloc_array(FdwInfo, ntups);
   10565              : 
   10566          259 :     i_tableoid = PQfnumber(res, "tableoid");
   10567          259 :     i_oid = PQfnumber(res, "oid");
   10568          259 :     i_fdwname = PQfnumber(res, "fdwname");
   10569          259 :     i_fdwowner = PQfnumber(res, "fdwowner");
   10570          259 :     i_fdwhandler = PQfnumber(res, "fdwhandler");
   10571          259 :     i_fdwvalidator = PQfnumber(res, "fdwvalidator");
   10572          259 :     i_fdwconnection = PQfnumber(res, "fdwconnection");
   10573          259 :     i_fdwacl = PQfnumber(res, "fdwacl");
   10574          259 :     i_acldefault = PQfnumber(res, "acldefault");
   10575          259 :     i_fdwoptions = PQfnumber(res, "fdwoptions");
   10576              : 
   10577          330 :     for (i = 0; i < ntups; i++)
   10578              :     {
   10579           71 :         fdwinfo[i].dobj.objType = DO_FDW;
   10580           71 :         fdwinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
   10581           71 :         fdwinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
   10582           71 :         AssignDumpId(&fdwinfo[i].dobj);
   10583           71 :         fdwinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_fdwname));
   10584           71 :         fdwinfo[i].dobj.namespace = NULL;
   10585           71 :         fdwinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_fdwacl));
   10586           71 :         fdwinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
   10587           71 :         fdwinfo[i].dacl.privtype = 0;
   10588           71 :         fdwinfo[i].dacl.initprivs = NULL;
   10589           71 :         fdwinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_fdwowner));
   10590           71 :         fdwinfo[i].fdwhandler = pg_strdup(PQgetvalue(res, i, i_fdwhandler));
   10591           71 :         fdwinfo[i].fdwvalidator = pg_strdup(PQgetvalue(res, i, i_fdwvalidator));
   10592           71 :         fdwinfo[i].fdwconnection = pg_strdup(PQgetvalue(res, i, i_fdwconnection));
   10593           71 :         fdwinfo[i].fdwoptions = pg_strdup(PQgetvalue(res, i, i_fdwoptions));
   10594              : 
   10595              :         /* Decide whether we want to dump it */
   10596           71 :         selectDumpableObject(&(fdwinfo[i].dobj), fout);
   10597              : 
   10598              :         /* Mark whether FDW has an ACL */
   10599           71 :         if (!PQgetisnull(res, i, i_fdwacl))
   10600           45 :             fdwinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
   10601              :     }
   10602              : 
   10603          259 :     PQclear(res);
   10604              : 
   10605          259 :     destroyPQExpBuffer(query);
   10606          259 : }
   10607              : 
   10608              : /*
   10609              :  * getForeignServers:
   10610              :  *    get information about all foreign servers in the system catalogs
   10611              :  */
   10612              : void
   10613          259 : getForeignServers(Archive *fout)
   10614              : {
   10615              :     PGresult   *res;
   10616              :     int         ntups;
   10617              :     int         i;
   10618              :     PQExpBuffer query;
   10619              :     ForeignServerInfo *srvinfo;
   10620              :     int         i_tableoid;
   10621              :     int         i_oid;
   10622              :     int         i_srvname;
   10623              :     int         i_srvowner;
   10624              :     int         i_srvfdw;
   10625              :     int         i_srvtype;
   10626              :     int         i_srvversion;
   10627              :     int         i_srvacl;
   10628              :     int         i_acldefault;
   10629              :     int         i_srvoptions;
   10630              : 
   10631          259 :     query = createPQExpBuffer();
   10632              : 
   10633          259 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, srvname, "
   10634              :                          "srvowner, "
   10635              :                          "srvfdw, srvtype, srvversion, srvacl, "
   10636              :                          "acldefault('S', srvowner) AS acldefault, "
   10637              :                          "array_to_string(ARRAY("
   10638              :                          "SELECT quote_ident(option_name) || ' ' || "
   10639              :                          "quote_literal(option_value) "
   10640              :                          "FROM pg_options_to_table(srvoptions) "
   10641              :                          "ORDER BY option_name"
   10642              :                          "), E',\n    ') AS srvoptions "
   10643              :                          "FROM pg_foreign_server");
   10644              : 
   10645          259 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   10646              : 
   10647          259 :     ntups = PQntuples(res);
   10648              : 
   10649          259 :     srvinfo = pg_malloc_array(ForeignServerInfo, ntups);
   10650              : 
   10651          259 :     i_tableoid = PQfnumber(res, "tableoid");
   10652          259 :     i_oid = PQfnumber(res, "oid");
   10653          259 :     i_srvname = PQfnumber(res, "srvname");
   10654          259 :     i_srvowner = PQfnumber(res, "srvowner");
   10655          259 :     i_srvfdw = PQfnumber(res, "srvfdw");
   10656          259 :     i_srvtype = PQfnumber(res, "srvtype");
   10657          259 :     i_srvversion = PQfnumber(res, "srvversion");
   10658          259 :     i_srvacl = PQfnumber(res, "srvacl");
   10659          259 :     i_acldefault = PQfnumber(res, "acldefault");
   10660          259 :     i_srvoptions = PQfnumber(res, "srvoptions");
   10661              : 
   10662          334 :     for (i = 0; i < ntups; i++)
   10663              :     {
   10664           75 :         srvinfo[i].dobj.objType = DO_FOREIGN_SERVER;
   10665           75 :         srvinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
   10666           75 :         srvinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
   10667           75 :         AssignDumpId(&srvinfo[i].dobj);
   10668           75 :         srvinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_srvname));
   10669           75 :         srvinfo[i].dobj.namespace = NULL;
   10670           75 :         srvinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_srvacl));
   10671           75 :         srvinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
   10672           75 :         srvinfo[i].dacl.privtype = 0;
   10673           75 :         srvinfo[i].dacl.initprivs = NULL;
   10674           75 :         srvinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_srvowner));
   10675           75 :         srvinfo[i].srvfdw = atooid(PQgetvalue(res, i, i_srvfdw));
   10676           75 :         srvinfo[i].srvtype = pg_strdup(PQgetvalue(res, i, i_srvtype));
   10677           75 :         srvinfo[i].srvversion = pg_strdup(PQgetvalue(res, i, i_srvversion));
   10678           75 :         srvinfo[i].srvoptions = pg_strdup(PQgetvalue(res, i, i_srvoptions));
   10679              : 
   10680              :         /* Decide whether we want to dump it */
   10681           75 :         selectDumpableObject(&(srvinfo[i].dobj), fout);
   10682              : 
   10683              :         /* Servers have user mappings */
   10684           75 :         srvinfo[i].dobj.components |= DUMP_COMPONENT_USERMAP;
   10685              : 
   10686              :         /* Mark whether server has an ACL */
   10687           75 :         if (!PQgetisnull(res, i, i_srvacl))
   10688           45 :             srvinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
   10689              :     }
   10690              : 
   10691          259 :     PQclear(res);
   10692              : 
   10693          259 :     destroyPQExpBuffer(query);
   10694          259 : }
   10695              : 
   10696              : /*
   10697              :  * getDefaultACLs:
   10698              :  *    get information about all default ACL information in the system catalogs
   10699              :  */
   10700              : void
   10701          259 : getDefaultACLs(Archive *fout)
   10702              : {
   10703          259 :     DumpOptions *dopt = fout->dopt;
   10704              :     DefaultACLInfo *daclinfo;
   10705              :     PQExpBuffer query;
   10706              :     PGresult   *res;
   10707              :     int         i_oid;
   10708              :     int         i_tableoid;
   10709              :     int         i_defaclrole;
   10710              :     int         i_defaclnamespace;
   10711              :     int         i_defaclobjtype;
   10712              :     int         i_defaclacl;
   10713              :     int         i_acldefault;
   10714              :     int         i,
   10715              :                 ntups;
   10716              : 
   10717          259 :     query = createPQExpBuffer();
   10718              : 
   10719              :     /*
   10720              :      * Global entries (with defaclnamespace=0) replace the hard-wired default
   10721              :      * ACL for their object type.  We should dump them as deltas from the
   10722              :      * default ACL, since that will be used as a starting point for
   10723              :      * interpreting the ALTER DEFAULT PRIVILEGES commands.  On the other hand,
   10724              :      * non-global entries can only add privileges not revoke them.  We must
   10725              :      * dump those as-is (i.e., as deltas from an empty ACL).
   10726              :      *
   10727              :      * We can use defaclobjtype as the object type for acldefault(), except
   10728              :      * for the case of 'S' (DEFACLOBJ_SEQUENCE) which must be converted to
   10729              :      * 's'.
   10730              :      */
   10731          259 :     appendPQExpBufferStr(query,
   10732              :                          "SELECT oid, tableoid, "
   10733              :                          "defaclrole, "
   10734              :                          "defaclnamespace, "
   10735              :                          "defaclobjtype, "
   10736              :                          "defaclacl, "
   10737              :                          "CASE WHEN defaclnamespace = 0 THEN "
   10738              :                          "acldefault(CASE WHEN defaclobjtype = 'S' "
   10739              :                          "THEN 's'::\"char\" ELSE defaclobjtype END, "
   10740              :                          "defaclrole) ELSE '{}' END AS acldefault "
   10741              :                          "FROM pg_default_acl");
   10742              : 
   10743          259 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   10744              : 
   10745          259 :     ntups = PQntuples(res);
   10746              : 
   10747          259 :     daclinfo = pg_malloc_array(DefaultACLInfo, ntups);
   10748              : 
   10749          259 :     i_oid = PQfnumber(res, "oid");
   10750          259 :     i_tableoid = PQfnumber(res, "tableoid");
   10751          259 :     i_defaclrole = PQfnumber(res, "defaclrole");
   10752          259 :     i_defaclnamespace = PQfnumber(res, "defaclnamespace");
   10753          259 :     i_defaclobjtype = PQfnumber(res, "defaclobjtype");
   10754          259 :     i_defaclacl = PQfnumber(res, "defaclacl");
   10755          259 :     i_acldefault = PQfnumber(res, "acldefault");
   10756              : 
   10757          453 :     for (i = 0; i < ntups; i++)
   10758              :     {
   10759          194 :         Oid         nspid = atooid(PQgetvalue(res, i, i_defaclnamespace));
   10760              : 
   10761          194 :         daclinfo[i].dobj.objType = DO_DEFAULT_ACL;
   10762          194 :         daclinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
   10763          194 :         daclinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
   10764          194 :         AssignDumpId(&daclinfo[i].dobj);
   10765              :         /* cheesy ... is it worth coming up with a better object name? */
   10766          194 :         daclinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_defaclobjtype));
   10767              : 
   10768          194 :         if (nspid != InvalidOid)
   10769           90 :             daclinfo[i].dobj.namespace = findNamespace(nspid);
   10770              :         else
   10771          104 :             daclinfo[i].dobj.namespace = NULL;
   10772              : 
   10773          194 :         daclinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_defaclacl));
   10774          194 :         daclinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
   10775          194 :         daclinfo[i].dacl.privtype = 0;
   10776          194 :         daclinfo[i].dacl.initprivs = NULL;
   10777          194 :         daclinfo[i].defaclrole = getRoleName(PQgetvalue(res, i, i_defaclrole));
   10778          194 :         daclinfo[i].defaclobjtype = *(PQgetvalue(res, i, i_defaclobjtype));
   10779              : 
   10780              :         /* Default ACLs are ACLs, of course */
   10781          194 :         daclinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
   10782              : 
   10783              :         /* Decide whether we want to dump it */
   10784          194 :         selectDumpableDefaultACL(&(daclinfo[i]), dopt);
   10785              :     }
   10786              : 
   10787          259 :     PQclear(res);
   10788              : 
   10789          259 :     destroyPQExpBuffer(query);
   10790          259 : }
   10791              : 
   10792              : /*
   10793              :  * getRoleName -- look up the name of a role, given its OID
   10794              :  *
   10795              :  * In current usage, we don't expect failures, so error out for a bad OID.
   10796              :  */
   10797              : static const char *
   10798       837683 : getRoleName(const char *roleoid_str)
   10799              : {
   10800       837683 :     Oid         roleoid = atooid(roleoid_str);
   10801              : 
   10802              :     /*
   10803              :      * Do binary search to find the appropriate item.
   10804              :      */
   10805       837683 :     if (nrolenames > 0)
   10806              :     {
   10807       837683 :         RoleNameItem *low = &rolenames[0];
   10808       837683 :         RoleNameItem *high = &rolenames[nrolenames - 1];
   10809              : 
   10810      3350969 :         while (low <= high)
   10811              :         {
   10812      3350969 :             RoleNameItem *middle = low + (high - low) / 2;
   10813              : 
   10814      3350969 :             if (roleoid < middle->roleoid)
   10815      2511827 :                 high = middle - 1;
   10816       839142 :             else if (roleoid > middle->roleoid)
   10817         1459 :                 low = middle + 1;
   10818              :             else
   10819       837683 :                 return middle->rolename; /* found a match */
   10820              :         }
   10821              :     }
   10822              : 
   10823            0 :     pg_fatal("role with OID %u does not exist", roleoid);
   10824              :     return NULL;                /* keep compiler quiet */
   10825              : }
   10826              : 
   10827              : /*
   10828              :  * collectRoleNames --
   10829              :  *
   10830              :  * Construct a table of all known roles.
   10831              :  * The table is sorted by OID for speed in lookup.
   10832              :  */
   10833              : static void
   10834          260 : collectRoleNames(Archive *fout)
   10835              : {
   10836              :     PGresult   *res;
   10837              :     const char *query;
   10838              :     int         i;
   10839              : 
   10840          260 :     query = "SELECT oid, rolname FROM pg_catalog.pg_roles ORDER BY 1";
   10841              : 
   10842          260 :     res = ExecuteSqlQuery(fout, query, PGRES_TUPLES_OK);
   10843              : 
   10844          260 :     nrolenames = PQntuples(res);
   10845              : 
   10846          260 :     rolenames = pg_malloc_array(RoleNameItem, nrolenames);
   10847              : 
   10848         5772 :     for (i = 0; i < nrolenames; i++)
   10849              :     {
   10850         5512 :         rolenames[i].roleoid = atooid(PQgetvalue(res, i, 0));
   10851         5512 :         rolenames[i].rolename = pg_strdup(PQgetvalue(res, i, 1));
   10852              :     }
   10853              : 
   10854          260 :     PQclear(res);
   10855          260 : }
   10856              : 
   10857              : /*
   10858              :  * getAdditionalACLs
   10859              :  *
   10860              :  * We have now created all the DumpableObjects, and collected the ACL data
   10861              :  * that appears in the directly-associated catalog entries.  However, there's
   10862              :  * more ACL-related info to collect.  If any of a table's columns have ACLs,
   10863              :  * we must set the TableInfo's DUMP_COMPONENT_ACL components flag, as well as
   10864              :  * its hascolumnACLs flag (we won't store the ACLs themselves here, though).
   10865              :  * Also, in versions having the pg_init_privs catalog, read that and load the
   10866              :  * information into the relevant DumpableObjects.
   10867              :  */
   10868              : static void
   10869          257 : getAdditionalACLs(Archive *fout)
   10870              : {
   10871          257 :     PQExpBuffer query = createPQExpBuffer();
   10872              :     PGresult   *res;
   10873              :     int         ntups,
   10874              :                 i;
   10875              : 
   10876              :     /* Check for per-column ACLs */
   10877          257 :     appendPQExpBufferStr(query,
   10878              :                          "SELECT DISTINCT attrelid FROM pg_attribute "
   10879              :                          "WHERE attacl IS NOT NULL");
   10880              : 
   10881          257 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   10882              : 
   10883          257 :     ntups = PQntuples(res);
   10884          684 :     for (i = 0; i < ntups; i++)
   10885              :     {
   10886          427 :         Oid         relid = atooid(PQgetvalue(res, i, 0));
   10887              :         TableInfo  *tblinfo;
   10888              : 
   10889          427 :         tblinfo = findTableByOid(relid);
   10890              :         /* OK to ignore tables we haven't got a DumpableObject for */
   10891          427 :         if (tblinfo)
   10892              :         {
   10893          427 :             tblinfo->dobj.components |= DUMP_COMPONENT_ACL;
   10894          427 :             tblinfo->hascolumnACLs = true;
   10895              :         }
   10896              :     }
   10897          257 :     PQclear(res);
   10898              : 
   10899              :     /* Fetch initial-privileges data */
   10900          257 :     if (fout->remoteVersion >= 90600)
   10901              :     {
   10902          257 :         printfPQExpBuffer(query,
   10903              :                           "SELECT objoid, classoid, objsubid, privtype, initprivs "
   10904              :                           "FROM pg_init_privs");
   10905              : 
   10906          257 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   10907              : 
   10908          257 :         ntups = PQntuples(res);
   10909        64301 :         for (i = 0; i < ntups; i++)
   10910              :         {
   10911        64044 :             Oid         objoid = atooid(PQgetvalue(res, i, 0));
   10912        64044 :             Oid         classoid = atooid(PQgetvalue(res, i, 1));
   10913        64044 :             int         objsubid = atoi(PQgetvalue(res, i, 2));
   10914        64044 :             char        privtype = *(PQgetvalue(res, i, 3));
   10915        64044 :             char       *initprivs = PQgetvalue(res, i, 4);
   10916              :             CatalogId   objId;
   10917              :             DumpableObject *dobj;
   10918              : 
   10919        64044 :             objId.tableoid = classoid;
   10920        64044 :             objId.oid = objoid;
   10921        64044 :             dobj = findObjectByCatalogId(objId);
   10922              :             /* OK to ignore entries we haven't got a DumpableObject for */
   10923        64044 :             if (dobj)
   10924              :             {
   10925              :                 /* Cope with sub-object initprivs */
   10926        46355 :                 if (objsubid != 0)
   10927              :                 {
   10928         5421 :                     if (dobj->objType == DO_TABLE)
   10929              :                     {
   10930              :                         /* For a column initprivs, set the table's ACL flags */
   10931         5421 :                         dobj->components |= DUMP_COMPONENT_ACL;
   10932         5421 :                         ((TableInfo *) dobj)->hascolumnACLs = true;
   10933              :                     }
   10934              :                     else
   10935            0 :                         pg_log_warning("unsupported pg_init_privs entry: %u %u %d",
   10936              :                                        classoid, objoid, objsubid);
   10937         5674 :                     continue;
   10938              :                 }
   10939              : 
   10940              :                 /*
   10941              :                  * We ignore any pg_init_privs.initprivs entry for the public
   10942              :                  * schema, as explained in getNamespaces().
   10943              :                  */
   10944        40934 :                 if (dobj->objType == DO_NAMESPACE &&
   10945          510 :                     strcmp(dobj->name, "public") == 0)
   10946          253 :                     continue;
   10947              : 
   10948              :                 /* Else it had better be of a type we think has ACLs */
   10949        40681 :                 if (dobj->objType == DO_NAMESPACE ||
   10950        40424 :                     dobj->objType == DO_TYPE ||
   10951        40400 :                     dobj->objType == DO_FUNC ||
   10952        40308 :                     dobj->objType == DO_AGG ||
   10953        40284 :                     dobj->objType == DO_TABLE ||
   10954            0 :                     dobj->objType == DO_PROCLANG ||
   10955            0 :                     dobj->objType == DO_FDW ||
   10956            0 :                     dobj->objType == DO_FOREIGN_SERVER)
   10957        40681 :                 {
   10958        40681 :                     DumpableObjectWithAcl *daobj = (DumpableObjectWithAcl *) dobj;
   10959              : 
   10960        40681 :                     daobj->dacl.privtype = privtype;
   10961        40681 :                     daobj->dacl.initprivs = pstrdup(initprivs);
   10962              :                 }
   10963              :                 else
   10964            0 :                     pg_log_warning("unsupported pg_init_privs entry: %u %u %d",
   10965              :                                    classoid, objoid, objsubid);
   10966              :             }
   10967              :         }
   10968          257 :         PQclear(res);
   10969              :     }
   10970              : 
   10971          257 :     destroyPQExpBuffer(query);
   10972          257 : }
   10973              : 
   10974              : /*
   10975              :  * dumpCommentExtended --
   10976              :  *
   10977              :  * This routine is used to dump any comments associated with the
   10978              :  * object handed to this routine. The routine takes the object type
   10979              :  * and object name (ready to print, except for schema decoration), plus
   10980              :  * the namespace and owner of the object (for labeling the ArchiveEntry),
   10981              :  * plus catalog ID and subid which are the lookup key for pg_description,
   10982              :  * plus the dump ID for the object (for setting a dependency).
   10983              :  * If a matching pg_description entry is found, it is dumped.
   10984              :  *
   10985              :  * Note: in some cases, such as comments for triggers and rules, the "type"
   10986              :  * string really looks like, e.g., "TRIGGER name ON".  This is a bit of a hack
   10987              :  * but it doesn't seem worth complicating the API for all callers to make
   10988              :  * it cleaner.
   10989              :  *
   10990              :  * Note: although this routine takes a dumpId for dependency purposes,
   10991              :  * that purpose is just to mark the dependency in the emitted dump file
   10992              :  * for possible future use by pg_restore.  We do NOT use it for determining
   10993              :  * ordering of the comment in the dump file, because this routine is called
   10994              :  * after dependency sorting occurs.  This routine should be called just after
   10995              :  * calling ArchiveEntry() for the specified object.
   10996              :  */
   10997              : static void
   10998         6674 : dumpCommentExtended(Archive *fout, const char *type,
   10999              :                     const char *name, const char *namespace,
   11000              :                     const char *owner, CatalogId catalogId,
   11001              :                     int subid, DumpId dumpId,
   11002              :                     const char *initdb_comment)
   11003              : {
   11004         6674 :     DumpOptions *dopt = fout->dopt;
   11005              :     CommentItem *comments;
   11006              :     int         ncomments;
   11007              : 
   11008              :     /* do nothing, if --no-comments is supplied */
   11009         6674 :     if (dopt->no_comments)
   11010            0 :         return;
   11011              : 
   11012              :     /* Comments are schema not data ... except LO comments are data */
   11013         6674 :     if (strcmp(type, "LARGE OBJECT") != 0)
   11014              :     {
   11015         6616 :         if (!dopt->dumpSchema)
   11016            0 :             return;
   11017              :     }
   11018              :     else
   11019              :     {
   11020              :         /* We do dump LO comments in binary-upgrade mode */
   11021           58 :         if (!dopt->dumpData && !dopt->binary_upgrade)
   11022            0 :             return;
   11023              :     }
   11024              : 
   11025              :     /* Search for comments associated with catalogId, using table */
   11026         6674 :     ncomments = findComments(catalogId.tableoid, catalogId.oid,
   11027              :                              &comments);
   11028              : 
   11029              :     /* Is there one matching the subid? */
   11030         6674 :     while (ncomments > 0)
   11031              :     {
   11032         6629 :         if (comments->objsubid == subid)
   11033         6629 :             break;
   11034            0 :         comments++;
   11035            0 :         ncomments--;
   11036              :     }
   11037              : 
   11038         6674 :     if (initdb_comment != NULL)
   11039              :     {
   11040              :         static CommentItem empty_comment = {.descr = ""};
   11041              : 
   11042              :         /*
   11043              :          * initdb creates this object with a comment.  Skip dumping the
   11044              :          * initdb-provided comment, which would complicate matters for
   11045              :          * non-superuser use of pg_dump.  When the DBA has removed initdb's
   11046              :          * comment, replicate that.
   11047              :          */
   11048          186 :         if (ncomments == 0)
   11049              :         {
   11050            4 :             comments = &empty_comment;
   11051            4 :             ncomments = 1;
   11052              :         }
   11053          182 :         else if (strcmp(comments->descr, initdb_comment) == 0)
   11054          182 :             ncomments = 0;
   11055              :     }
   11056              : 
   11057              :     /* If a comment exists, build COMMENT ON statement */
   11058         6674 :     if (ncomments > 0)
   11059              :     {
   11060         6451 :         PQExpBuffer query = createPQExpBuffer();
   11061         6451 :         PQExpBuffer tag = createPQExpBuffer();
   11062              : 
   11063         6451 :         appendPQExpBuffer(query, "COMMENT ON %s ", type);
   11064         6451 :         if (namespace && *namespace)
   11065         6270 :             appendPQExpBuffer(query, "%s.", fmtId(namespace));
   11066         6451 :         appendPQExpBuffer(query, "%s IS ", name);
   11067         6451 :         appendStringLiteralAH(query, comments->descr, fout);
   11068         6451 :         appendPQExpBufferStr(query, ";\n");
   11069              : 
   11070         6451 :         appendPQExpBuffer(tag, "%s %s", type, name);
   11071              : 
   11072              :         /*
   11073              :          * We mark comments as SECTION_NONE because they really belong in the
   11074              :          * same section as their parent, whether that is pre-data or
   11075              :          * post-data.
   11076              :          */
   11077         6451 :         ArchiveEntry(fout, nilCatalogId, createDumpId(),
   11078         6451 :                      ARCHIVE_OPTS(.tag = tag->data,
   11079              :                                   .namespace = namespace,
   11080              :                                   .owner = owner,
   11081              :                                   .description = "COMMENT",
   11082              :                                   .section = SECTION_NONE,
   11083              :                                   .createStmt = query->data,
   11084              :                                   .deps = &dumpId,
   11085              :                                   .nDeps = 1));
   11086              : 
   11087         6451 :         destroyPQExpBuffer(query);
   11088         6451 :         destroyPQExpBuffer(tag);
   11089              :     }
   11090              : }
   11091              : 
   11092              : /*
   11093              :  * dumpComment --
   11094              :  *
   11095              :  * Typical simplification of the above function.
   11096              :  */
   11097              : static inline void
   11098         6445 : dumpComment(Archive *fout, const char *type,
   11099              :             const char *name, const char *namespace,
   11100              :             const char *owner, CatalogId catalogId,
   11101              :             int subid, DumpId dumpId)
   11102              : {
   11103         6445 :     dumpCommentExtended(fout, type, name, namespace, owner,
   11104              :                         catalogId, subid, dumpId, NULL);
   11105         6445 : }
   11106              : 
   11107              : /*
   11108              :  * appendNamedArgument --
   11109              :  *
   11110              :  * Convenience routine for constructing parameters of the form:
   11111              :  * 'paraname', 'value'::type
   11112              :  */
   11113              : static void
   11114         5646 : appendNamedArgument(PQExpBuffer out, Archive *fout, const char *argname,
   11115              :                     const char *argtype, const char *argval)
   11116              : {
   11117         5646 :     appendPQExpBufferStr(out, ",\n\t");
   11118              : 
   11119         5646 :     appendStringLiteralAH(out, argname, fout);
   11120         5646 :     appendPQExpBufferStr(out, ", ");
   11121              : 
   11122         5646 :     appendStringLiteralAH(out, argval, fout);
   11123         5646 :     appendPQExpBuffer(out, "::%s", argtype);
   11124         5646 : }
   11125              : 
   11126              : /*
   11127              :  * fetchAttributeStats --
   11128              :  *
   11129              :  * Fetch next batch of attribute statistics for dumpRelationStats_dumper().
   11130              :  */
   11131              : static PGresult *
   11132         1040 : fetchAttributeStats(Archive *fout)
   11133              : {
   11134         1040 :     ArchiveHandle *AH = (ArchiveHandle *) fout;
   11135         1040 :     PQExpBuffer relids = createPQExpBuffer();
   11136         1040 :     PQExpBuffer nspnames = createPQExpBuffer();
   11137         1040 :     PQExpBuffer relnames = createPQExpBuffer();
   11138         1040 :     int         count = 0;
   11139         1040 :     PGresult   *res = NULL;
   11140              :     static TocEntry *te;
   11141              :     static bool restarted;
   11142         1040 :     int         max_rels = MAX_ATTR_STATS_RELS;
   11143              : 
   11144              :     /*
   11145              :      * Our query for retrieving statistics for multiple relations uses WITH
   11146              :      * ORDINALITY and multi-argument UNNEST(), both of which were introduced
   11147              :      * in v9.4.  For older versions, we resort to gathering statistics for a
   11148              :      * single relation at a time.
   11149              :      */
   11150         1040 :     if (fout->remoteVersion < 90400)
   11151            0 :         max_rels = 1;
   11152              : 
   11153              :     /* If we're just starting, set our TOC pointer. */
   11154         1040 :     if (!te)
   11155           62 :         te = AH->toc->next;
   11156              : 
   11157              :     /*
   11158              :      * We can't easily avoid a second TOC scan for the tar format because it
   11159              :      * writes restore.sql separately, which means we must execute the queries
   11160              :      * twice.  This feels risky, but there is no known reason it should
   11161              :      * generate different output than the first pass.  Even if it does, the
   11162              :      * worst-case scenario is that restore.sql might have different statistics
   11163              :      * data than the archive.
   11164              :      */
   11165         1040 :     if (!restarted && te == AH->toc && AH->format == archTar)
   11166              :     {
   11167            1 :         te = AH->toc->next;
   11168            1 :         restarted = true;
   11169              :     }
   11170              : 
   11171         1040 :     appendPQExpBufferChar(relids, '{');
   11172         1040 :     appendPQExpBufferChar(nspnames, '{');
   11173         1040 :     appendPQExpBufferChar(relnames, '{');
   11174              : 
   11175              :     /*
   11176              :      * Scan the TOC for the next set of relevant stats entries.  We assume
   11177              :      * that statistics are dumped in the order they are listed in the TOC.
   11178              :      * This is perhaps not the sturdiest assumption, so we verify it matches
   11179              :      * reality in dumpRelationStats_dumper().
   11180              :      */
   11181        16356 :     for (; te != AH->toc && count < max_rels; te = te->next)
   11182              :     {
   11183        15316 :         if ((te->reqs & REQ_STATS) == 0 ||
   11184         3439 :             strcmp(te->desc, "STATISTICS DATA") != 0)
   11185        11912 :             continue;
   11186              : 
   11187         3404 :         if (fout->remoteVersion >= 190000)
   11188              :         {
   11189         3404 :             const RelStatsInfo *rsinfo = (const RelStatsInfo *) te->defnDumperArg;
   11190              :             char        relid[32];
   11191              : 
   11192         3404 :             sprintf(relid, "%u", rsinfo->relid);
   11193         3404 :             appendPGArray(relids, relid);
   11194              :         }
   11195              :         else
   11196              :         {
   11197            0 :             appendPGArray(nspnames, te->namespace);
   11198            0 :             appendPGArray(relnames, te->tag);
   11199              :         }
   11200              : 
   11201         3404 :         count++;
   11202              :     }
   11203              : 
   11204         1040 :     appendPQExpBufferChar(relids, '}');
   11205         1040 :     appendPQExpBufferChar(nspnames, '}');
   11206         1040 :     appendPQExpBufferChar(relnames, '}');
   11207              : 
   11208              :     /* Execute the query for the next batch of relations. */
   11209         1040 :     if (count > 0)
   11210              :     {
   11211          107 :         PQExpBuffer query = createPQExpBuffer();
   11212              : 
   11213          107 :         appendPQExpBufferStr(query, "EXECUTE getAttributeStats(");
   11214              : 
   11215          107 :         if (fout->remoteVersion >= 190000)
   11216              :         {
   11217          107 :             appendStringLiteralAH(query, relids->data, fout);
   11218          107 :             appendPQExpBufferStr(query, "::pg_catalog.oid[])");
   11219              :         }
   11220              :         else
   11221              :         {
   11222            0 :             appendStringLiteralAH(query, nspnames->data, fout);
   11223            0 :             appendPQExpBufferStr(query, "::pg_catalog.name[],");
   11224            0 :             appendStringLiteralAH(query, relnames->data, fout);
   11225            0 :             appendPQExpBufferStr(query, "::pg_catalog.name[])");
   11226              :         }
   11227              : 
   11228          107 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   11229          107 :         destroyPQExpBuffer(query);
   11230              :     }
   11231              : 
   11232         1040 :     destroyPQExpBuffer(relids);
   11233         1040 :     destroyPQExpBuffer(nspnames);
   11234         1040 :     destroyPQExpBuffer(relnames);
   11235         1040 :     return res;
   11236              : }
   11237              : 
   11238              : /*
   11239              :  * dumpRelationStats_dumper --
   11240              :  *
   11241              :  * Generate command to import stats into the relation on the new database.
   11242              :  * This routine is called by the Archiver when it wants the statistics to be
   11243              :  * dumped.
   11244              :  */
   11245              : static char *
   11246         3404 : dumpRelationStats_dumper(Archive *fout, const void *userArg, const TocEntry *te)
   11247              : {
   11248         3404 :     const RelStatsInfo *rsinfo = userArg;
   11249              :     static PGresult *res;
   11250              :     static int  rownum;
   11251              :     PQExpBuffer query;
   11252              :     PQExpBufferData out_data;
   11253         3404 :     PQExpBuffer out = &out_data;
   11254              :     int         i_schemaname;
   11255              :     int         i_tablename;
   11256              :     int         i_attname;
   11257              :     int         i_inherited;
   11258              :     int         i_null_frac;
   11259              :     int         i_avg_width;
   11260              :     int         i_n_distinct;
   11261              :     int         i_most_common_vals;
   11262              :     int         i_most_common_freqs;
   11263              :     int         i_histogram_bounds;
   11264              :     int         i_correlation;
   11265              :     int         i_most_common_elems;
   11266              :     int         i_most_common_elem_freqs;
   11267              :     int         i_elem_count_histogram;
   11268              :     int         i_range_length_histogram;
   11269              :     int         i_range_empty_frac;
   11270              :     int         i_range_bounds_histogram;
   11271              :     static TocEntry *expected_te;
   11272              : 
   11273              :     /*
   11274              :      * fetchAttributeStats() assumes that the statistics are dumped in the
   11275              :      * order they are listed in the TOC.  We verify that here for safety.
   11276              :      */
   11277         3404 :     if (!expected_te)
   11278           62 :         expected_te = ((ArchiveHandle *) fout)->toc;
   11279              : 
   11280         3404 :     expected_te = expected_te->next;
   11281        13383 :     while ((expected_te->reqs & REQ_STATS) == 0 ||
   11282         3405 :            strcmp(expected_te->desc, "STATISTICS DATA") != 0)
   11283         9979 :         expected_te = expected_te->next;
   11284              : 
   11285         3404 :     if (te != expected_te)
   11286            0 :         pg_fatal("statistics dumped out of order (current: %d %s %s, expected: %d %s %s)",
   11287              :                  te->dumpId, te->desc, te->tag,
   11288              :                  expected_te->dumpId, expected_te->desc, expected_te->tag);
   11289              : 
   11290         3404 :     query = createPQExpBuffer();
   11291         3404 :     if (!fout->is_prepared[PREPQUERY_GETATTRIBUTESTATS])
   11292              :     {
   11293           62 :         if (fout->remoteVersion >= 190000)
   11294           62 :             appendPQExpBufferStr(query,
   11295              :                                  "PREPARE getAttributeStats(pg_catalog.oid[]) AS\n");
   11296              :         else
   11297            0 :             appendPQExpBufferStr(query,
   11298              :                                  "PREPARE getAttributeStats(pg_catalog.name[], pg_catalog.name[]) AS\n");
   11299              : 
   11300           62 :         appendPQExpBufferStr(query,
   11301              :                              "SELECT s.schemaname, s.tablename, s.attname, s.inherited, "
   11302              :                              "s.null_frac, s.avg_width, s.n_distinct, "
   11303              :                              "s.most_common_vals, s.most_common_freqs, "
   11304              :                              "s.histogram_bounds, s.correlation, "
   11305              :                              "s.most_common_elems, s.most_common_elem_freqs, "
   11306              :                              "s.elem_count_histogram, ");
   11307              : 
   11308           62 :         if (fout->remoteVersion >= 170000)
   11309           62 :             appendPQExpBufferStr(query,
   11310              :                                  "s.range_length_histogram, "
   11311              :                                  "s.range_empty_frac, "
   11312              :                                  "s.range_bounds_histogram ");
   11313              :         else
   11314            0 :             appendPQExpBufferStr(query,
   11315              :                                  "NULL AS range_length_histogram,"
   11316              :                                  "NULL AS range_empty_frac,"
   11317              :                                  "NULL AS range_bounds_histogram ");
   11318              : 
   11319              :         /*
   11320              :          * The results must be in the order of the relations supplied in the
   11321              :          * parameters to ensure we remain in sync as we walk through the TOC.
   11322              :          *
   11323              :          * For v9.4 through v18, the redundant filter clause on s.tablename =
   11324              :          * ANY(...) seems sufficient to convince the planner to use
   11325              :          * pg_class_relname_nsp_index, which avoids a full scan of pg_stats.
   11326              :          * In newer versions, pg_stats returns the table OIDs, eliminating the
   11327              :          * need for that hack.
   11328              :          *
   11329              :          * Our query for retrieving statistics for multiple relations uses
   11330              :          * WITH ORDINALITY and multi-argument UNNEST(), both of which were
   11331              :          * introduced in v9.4.  For older versions, we resort to gathering
   11332              :          * statistics for a single relation at a time.
   11333              :          */
   11334           62 :         if (fout->remoteVersion >= 190000)
   11335           62 :             appendPQExpBufferStr(query,
   11336              :                                  "FROM pg_catalog.pg_stats s "
   11337              :                                  "JOIN unnest($1) WITH ORDINALITY AS u (tableid, ord) "
   11338              :                                  "ON s.tableid = u.tableid "
   11339              :                                  "ORDER BY u.ord, s.attname, s.inherited");
   11340            0 :         else if (fout->remoteVersion >= 90400)
   11341            0 :             appendPQExpBufferStr(query,
   11342              :                                  "FROM pg_catalog.pg_stats s "
   11343              :                                  "JOIN unnest($1, $2) WITH ORDINALITY AS u (schemaname, tablename, ord) "
   11344              :                                  "ON s.schemaname = u.schemaname "
   11345              :                                  "AND s.tablename = u.tablename "
   11346              :                                  "WHERE s.tablename = ANY($2) "
   11347              :                                  "ORDER BY u.ord, s.attname, s.inherited");
   11348              :         else
   11349            0 :             appendPQExpBufferStr(query,
   11350              :                                  "FROM pg_catalog.pg_stats s "
   11351              :                                  "WHERE s.schemaname = $1[1] "
   11352              :                                  "AND s.tablename = $2[1] "
   11353              :                                  "ORDER BY s.attname, s.inherited");
   11354              : 
   11355           62 :         ExecuteSqlStatement(fout, query->data);
   11356              : 
   11357           62 :         fout->is_prepared[PREPQUERY_GETATTRIBUTESTATS] = true;
   11358           62 :         resetPQExpBuffer(query);
   11359              :     }
   11360              : 
   11361         3404 :     initPQExpBuffer(out);
   11362              : 
   11363              :     /* restore relation stats */
   11364         3404 :     appendPQExpBufferStr(out, "SELECT * FROM pg_catalog.pg_restore_relation_stats(\n");
   11365         3404 :     appendPQExpBuffer(out, "\t'version', '%d'::integer,\n",
   11366              :                       fout->remoteVersion);
   11367         3404 :     appendPQExpBufferStr(out, "\t'schemaname', ");
   11368         3404 :     appendStringLiteralAH(out, rsinfo->dobj.namespace->dobj.name, fout);
   11369         3404 :     appendPQExpBufferStr(out, ",\n");
   11370         3404 :     appendPQExpBufferStr(out, "\t'relname', ");
   11371         3404 :     appendStringLiteralAH(out, rsinfo->dobj.name, fout);
   11372         3404 :     appendPQExpBufferStr(out, ",\n");
   11373         3404 :     appendPQExpBuffer(out, "\t'relpages', '%d'::integer,\n", rsinfo->relpages);
   11374              : 
   11375              :     /*
   11376              :      * Before v14, a reltuples value of 0 was ambiguous: it could either mean
   11377              :      * the relation is empty, or it could mean that it hadn't yet been
   11378              :      * vacuumed or analyzed.  (Newer versions use -1 for the latter case.)
   11379              :      * This ambiguity allegedly can cause the planner to choose inefficient
   11380              :      * plans after restoring to v18 or newer.  To deal with this, let's just
   11381              :      * set reltuples to -1 in that case.
   11382              :      */
   11383         3404 :     if (fout->remoteVersion < 140000 && strcmp("0", rsinfo->reltuples) == 0)
   11384            0 :         appendPQExpBufferStr(out, "\t'reltuples', '-1'::real,\n");
   11385              :     else
   11386         3404 :         appendPQExpBuffer(out, "\t'reltuples', '%s'::real,\n", rsinfo->reltuples);
   11387              : 
   11388         3404 :     appendPQExpBuffer(out, "\t'relallvisible', '%d'::integer",
   11389         3404 :                       rsinfo->relallvisible);
   11390              : 
   11391         3404 :     if (fout->remoteVersion >= 180000)
   11392         3404 :         appendPQExpBuffer(out, ",\n\t'relallfrozen', '%d'::integer", rsinfo->relallfrozen);
   11393              : 
   11394         3404 :     appendPQExpBufferStr(out, "\n);\n");
   11395              : 
   11396              :     /* Fetch the next batch of attribute statistics if needed. */
   11397         3404 :     if (rownum >= PQntuples(res))
   11398              :     {
   11399         1040 :         PQclear(res);
   11400         1040 :         res = fetchAttributeStats(fout);
   11401         1040 :         rownum = 0;
   11402              :     }
   11403              : 
   11404         3404 :     i_schemaname = PQfnumber(res, "schemaname");
   11405         3404 :     i_tablename = PQfnumber(res, "tablename");
   11406         3404 :     i_attname = PQfnumber(res, "attname");
   11407         3404 :     i_inherited = PQfnumber(res, "inherited");
   11408         3404 :     i_null_frac = PQfnumber(res, "null_frac");
   11409         3404 :     i_avg_width = PQfnumber(res, "avg_width");
   11410         3404 :     i_n_distinct = PQfnumber(res, "n_distinct");
   11411         3404 :     i_most_common_vals = PQfnumber(res, "most_common_vals");
   11412         3404 :     i_most_common_freqs = PQfnumber(res, "most_common_freqs");
   11413         3404 :     i_histogram_bounds = PQfnumber(res, "histogram_bounds");
   11414         3404 :     i_correlation = PQfnumber(res, "correlation");
   11415         3404 :     i_most_common_elems = PQfnumber(res, "most_common_elems");
   11416         3404 :     i_most_common_elem_freqs = PQfnumber(res, "most_common_elem_freqs");
   11417         3404 :     i_elem_count_histogram = PQfnumber(res, "elem_count_histogram");
   11418         3404 :     i_range_length_histogram = PQfnumber(res, "range_length_histogram");
   11419         3404 :     i_range_empty_frac = PQfnumber(res, "range_empty_frac");
   11420         3404 :     i_range_bounds_histogram = PQfnumber(res, "range_bounds_histogram");
   11421              : 
   11422              :     /* restore attribute stats */
   11423         4221 :     for (; rownum < PQntuples(res); rownum++)
   11424              :     {
   11425              :         const char *attname;
   11426              : 
   11427              :         /* Stop if the next stat row in our cache isn't for this relation. */
   11428         3181 :         if (strcmp(te->tag, PQgetvalue(res, rownum, i_tablename)) != 0 ||
   11429          817 :             strcmp(te->namespace, PQgetvalue(res, rownum, i_schemaname)) != 0)
   11430              :             break;
   11431              : 
   11432          817 :         appendPQExpBufferStr(out, "SELECT * FROM pg_catalog.pg_restore_attribute_stats(\n");
   11433          817 :         appendPQExpBuffer(out, "\t'version', '%d'::integer,\n",
   11434              :                           fout->remoteVersion);
   11435          817 :         appendPQExpBufferStr(out, "\t'schemaname', ");
   11436          817 :         appendStringLiteralAH(out, rsinfo->dobj.namespace->dobj.name, fout);
   11437          817 :         appendPQExpBufferStr(out, ",\n\t'relname', ");
   11438          817 :         appendStringLiteralAH(out, rsinfo->dobj.name, fout);
   11439              : 
   11440          817 :         if (PQgetisnull(res, rownum, i_attname))
   11441            0 :             pg_fatal("unexpected null attname");
   11442          817 :         attname = PQgetvalue(res, rownum, i_attname);
   11443              : 
   11444              :         /*
   11445              :          * Indexes look up attname in indAttNames to derive attnum, all others
   11446              :          * use attname directly.  We must specify attnum for indexes, since
   11447              :          * their attnames are not necessarily stable across dump/reload.
   11448              :          */
   11449          817 :         if (rsinfo->nindAttNames == 0)
   11450              :         {
   11451          782 :             appendPQExpBufferStr(out, ",\n\t'attname', ");
   11452          782 :             appendStringLiteralAH(out, attname, fout);
   11453              :         }
   11454              :         else
   11455              :         {
   11456           35 :             bool        found = false;
   11457              : 
   11458           66 :             for (int i = 0; i < rsinfo->nindAttNames; i++)
   11459              :             {
   11460           66 :                 if (strcmp(attname, rsinfo->indAttNames[i]) == 0)
   11461              :                 {
   11462           35 :                     appendPQExpBuffer(out, ",\n\t'attnum', '%d'::smallint",
   11463              :                                       i + 1);
   11464           35 :                     found = true;
   11465           35 :                     break;
   11466              :                 }
   11467              :             }
   11468              : 
   11469           35 :             if (!found)
   11470            0 :                 pg_fatal("could not find index attname \"%s\"", attname);
   11471              :         }
   11472              : 
   11473          817 :         if (!PQgetisnull(res, rownum, i_inherited))
   11474          817 :             appendNamedArgument(out, fout, "inherited", "boolean",
   11475          817 :                                 PQgetvalue(res, rownum, i_inherited));
   11476          817 :         if (!PQgetisnull(res, rownum, i_null_frac))
   11477          817 :             appendNamedArgument(out, fout, "null_frac", "real",
   11478          817 :                                 PQgetvalue(res, rownum, i_null_frac));
   11479          817 :         if (!PQgetisnull(res, rownum, i_avg_width))
   11480          817 :             appendNamedArgument(out, fout, "avg_width", "integer",
   11481          817 :                                 PQgetvalue(res, rownum, i_avg_width));
   11482          817 :         if (!PQgetisnull(res, rownum, i_n_distinct))
   11483          817 :             appendNamedArgument(out, fout, "n_distinct", "real",
   11484          817 :                                 PQgetvalue(res, rownum, i_n_distinct));
   11485          817 :         if (!PQgetisnull(res, rownum, i_most_common_vals))
   11486          405 :             appendNamedArgument(out, fout, "most_common_vals", "text",
   11487          405 :                                 PQgetvalue(res, rownum, i_most_common_vals));
   11488          817 :         if (!PQgetisnull(res, rownum, i_most_common_freqs))
   11489          405 :             appendNamedArgument(out, fout, "most_common_freqs", "real[]",
   11490          405 :                                 PQgetvalue(res, rownum, i_most_common_freqs));
   11491          817 :         if (!PQgetisnull(res, rownum, i_histogram_bounds))
   11492          513 :             appendNamedArgument(out, fout, "histogram_bounds", "text",
   11493          513 :                                 PQgetvalue(res, rownum, i_histogram_bounds));
   11494          817 :         if (!PQgetisnull(res, rownum, i_correlation))
   11495          784 :             appendNamedArgument(out, fout, "correlation", "real",
   11496          784 :                                 PQgetvalue(res, rownum, i_correlation));
   11497          817 :         if (!PQgetisnull(res, rownum, i_most_common_elems))
   11498            8 :             appendNamedArgument(out, fout, "most_common_elems", "text",
   11499            8 :                                 PQgetvalue(res, rownum, i_most_common_elems));
   11500          817 :         if (!PQgetisnull(res, rownum, i_most_common_elem_freqs))
   11501            8 :             appendNamedArgument(out, fout, "most_common_elem_freqs", "real[]",
   11502            8 :                                 PQgetvalue(res, rownum, i_most_common_elem_freqs));
   11503          817 :         if (!PQgetisnull(res, rownum, i_elem_count_histogram))
   11504            7 :             appendNamedArgument(out, fout, "elem_count_histogram", "real[]",
   11505            7 :                                 PQgetvalue(res, rownum, i_elem_count_histogram));
   11506          817 :         if (fout->remoteVersion >= 170000)
   11507              :         {
   11508          817 :             if (!PQgetisnull(res, rownum, i_range_length_histogram))
   11509            3 :                 appendNamedArgument(out, fout, "range_length_histogram", "text",
   11510            3 :                                     PQgetvalue(res, rownum, i_range_length_histogram));
   11511          817 :             if (!PQgetisnull(res, rownum, i_range_empty_frac))
   11512            3 :                 appendNamedArgument(out, fout, "range_empty_frac", "real",
   11513            3 :                                     PQgetvalue(res, rownum, i_range_empty_frac));
   11514          817 :             if (!PQgetisnull(res, rownum, i_range_bounds_histogram))
   11515            3 :                 appendNamedArgument(out, fout, "range_bounds_histogram", "text",
   11516            3 :                                     PQgetvalue(res, rownum, i_range_bounds_histogram));
   11517              :         }
   11518          817 :         appendPQExpBufferStr(out, "\n);\n");
   11519              :     }
   11520              : 
   11521         3404 :     destroyPQExpBuffer(query);
   11522         3404 :     return out->data;
   11523              : }
   11524              : 
   11525              : /*
   11526              :  * dumpRelationStats --
   11527              :  *
   11528              :  * Make an ArchiveEntry for the relation statistics.  The Archiver will take
   11529              :  * care of gathering the statistics and generating the restore commands when
   11530              :  * they are needed.
   11531              :  */
   11532              : static void
   11533         3476 : dumpRelationStats(Archive *fout, const RelStatsInfo *rsinfo)
   11534              : {
   11535         3476 :     const DumpableObject *dobj = &rsinfo->dobj;
   11536              : 
   11537              :     /* nothing to do if we are not dumping statistics */
   11538         3476 :     if (!fout->dopt->dumpStatistics)
   11539            0 :         return;
   11540              : 
   11541         3476 :     ArchiveEntry(fout, nilCatalogId, createDumpId(),
   11542         3476 :                  ARCHIVE_OPTS(.tag = dobj->name,
   11543              :                               .namespace = dobj->namespace->dobj.name,
   11544              :                               .description = "STATISTICS DATA",
   11545              :                               .section = rsinfo->section,
   11546              :                               .defnFn = dumpRelationStats_dumper,
   11547              :                               .defnArg = rsinfo,
   11548              :                               .deps = dobj->dependencies,
   11549              :                               .nDeps = dobj->nDeps));
   11550              : }
   11551              : 
   11552              : /*
   11553              :  * dumpTableComment --
   11554              :  *
   11555              :  * As above, but dump comments for both the specified table (or view)
   11556              :  * and its columns.
   11557              :  */
   11558              : static void
   11559           74 : dumpTableComment(Archive *fout, const TableInfo *tbinfo,
   11560              :                  const char *reltypename)
   11561              : {
   11562           74 :     DumpOptions *dopt = fout->dopt;
   11563              :     CommentItem *comments;
   11564              :     int         ncomments;
   11565              :     PQExpBuffer query;
   11566              :     PQExpBuffer tag;
   11567              : 
   11568              :     /* do nothing, if --no-comments is supplied */
   11569           74 :     if (dopt->no_comments)
   11570            0 :         return;
   11571              : 
   11572              :     /* Comments are SCHEMA not data */
   11573           74 :     if (!dopt->dumpSchema)
   11574            0 :         return;
   11575              : 
   11576              :     /* Search for comments associated with relation, using table */
   11577           74 :     ncomments = findComments(tbinfo->dobj.catId.tableoid,
   11578           74 :                              tbinfo->dobj.catId.oid,
   11579              :                              &comments);
   11580              : 
   11581              :     /* If comments exist, build COMMENT ON statements */
   11582           74 :     if (ncomments <= 0)
   11583            0 :         return;
   11584              : 
   11585           74 :     query = createPQExpBuffer();
   11586           74 :     tag = createPQExpBuffer();
   11587              : 
   11588          212 :     while (ncomments > 0)
   11589              :     {
   11590          138 :         const char *descr = comments->descr;
   11591          138 :         int         objsubid = comments->objsubid;
   11592              : 
   11593          138 :         if (objsubid == 0)
   11594              :         {
   11595           32 :             resetPQExpBuffer(tag);
   11596           32 :             appendPQExpBuffer(tag, "%s %s", reltypename,
   11597           32 :                               fmtId(tbinfo->dobj.name));
   11598              : 
   11599           32 :             resetPQExpBuffer(query);
   11600           32 :             appendPQExpBuffer(query, "COMMENT ON %s %s IS ", reltypename,
   11601           32 :                               fmtQualifiedDumpable(tbinfo));
   11602           32 :             appendStringLiteralAH(query, descr, fout);
   11603           32 :             appendPQExpBufferStr(query, ";\n");
   11604              : 
   11605           32 :             ArchiveEntry(fout, nilCatalogId, createDumpId(),
   11606           32 :                          ARCHIVE_OPTS(.tag = tag->data,
   11607              :                                       .namespace = tbinfo->dobj.namespace->dobj.name,
   11608              :                                       .owner = tbinfo->rolname,
   11609              :                                       .description = "COMMENT",
   11610              :                                       .section = SECTION_NONE,
   11611              :                                       .createStmt = query->data,
   11612              :                                       .deps = &(tbinfo->dobj.dumpId),
   11613              :                                       .nDeps = 1));
   11614              :         }
   11615          106 :         else if (objsubid > 0 && objsubid <= tbinfo->numatts)
   11616              :         {
   11617          106 :             resetPQExpBuffer(tag);
   11618          106 :             appendPQExpBuffer(tag, "COLUMN %s.",
   11619          106 :                               fmtId(tbinfo->dobj.name));
   11620          106 :             appendPQExpBufferStr(tag, fmtId(tbinfo->attnames[objsubid - 1]));
   11621              : 
   11622          106 :             resetPQExpBuffer(query);
   11623          106 :             appendPQExpBuffer(query, "COMMENT ON COLUMN %s.",
   11624          106 :                               fmtQualifiedDumpable(tbinfo));
   11625          106 :             appendPQExpBuffer(query, "%s IS ",
   11626          106 :                               fmtId(tbinfo->attnames[objsubid - 1]));
   11627          106 :             appendStringLiteralAH(query, descr, fout);
   11628          106 :             appendPQExpBufferStr(query, ";\n");
   11629              : 
   11630          106 :             ArchiveEntry(fout, nilCatalogId, createDumpId(),
   11631          106 :                          ARCHIVE_OPTS(.tag = tag->data,
   11632              :                                       .namespace = tbinfo->dobj.namespace->dobj.name,
   11633              :                                       .owner = tbinfo->rolname,
   11634              :                                       .description = "COMMENT",
   11635              :                                       .section = SECTION_NONE,
   11636              :                                       .createStmt = query->data,
   11637              :                                       .deps = &(tbinfo->dobj.dumpId),
   11638              :                                       .nDeps = 1));
   11639              :         }
   11640              : 
   11641          138 :         comments++;
   11642          138 :         ncomments--;
   11643              :     }
   11644              : 
   11645           74 :     destroyPQExpBuffer(query);
   11646           74 :     destroyPQExpBuffer(tag);
   11647              : }
   11648              : 
   11649              : /*
   11650              :  * findComments --
   11651              :  *
   11652              :  * Find the comment(s), if any, associated with the given object.  All the
   11653              :  * objsubid values associated with the given classoid/objoid are found with
   11654              :  * one search.
   11655              :  */
   11656              : static int
   11657         6780 : findComments(Oid classoid, Oid objoid, CommentItem **items)
   11658              : {
   11659         6780 :     CommentItem *middle = NULL;
   11660              :     CommentItem *low;
   11661              :     CommentItem *high;
   11662              :     int         nmatch;
   11663              : 
   11664              :     /*
   11665              :      * Do binary search to find some item matching the object.
   11666              :      */
   11667         6780 :     low = &comments[0];
   11668         6780 :     high = &comments[ncomments - 1];
   11669        67655 :     while (low <= high)
   11670              :     {
   11671        67610 :         middle = low + (high - low) / 2;
   11672              : 
   11673        67610 :         if (classoid < middle->classoid)
   11674         7153 :             high = middle - 1;
   11675        60457 :         else if (classoid > middle->classoid)
   11676         7386 :             low = middle + 1;
   11677        53071 :         else if (objoid < middle->objoid)
   11678        22607 :             high = middle - 1;
   11679        30464 :         else if (objoid > middle->objoid)
   11680        23729 :             low = middle + 1;
   11681              :         else
   11682         6735 :             break;              /* found a match */
   11683              :     }
   11684              : 
   11685         6780 :     if (low > high)              /* no matches */
   11686              :     {
   11687           45 :         *items = NULL;
   11688           45 :         return 0;
   11689              :     }
   11690              : 
   11691              :     /*
   11692              :      * Now determine how many items match the object.  The search loop
   11693              :      * invariant still holds: only items between low and high inclusive could
   11694              :      * match.
   11695              :      */
   11696         6735 :     nmatch = 1;
   11697         6735 :     while (middle > low)
   11698              :     {
   11699         3356 :         if (classoid != middle[-1].classoid ||
   11700         3201 :             objoid != middle[-1].objoid)
   11701              :             break;
   11702            0 :         middle--;
   11703            0 :         nmatch++;
   11704              :     }
   11705              : 
   11706         6735 :     *items = middle;
   11707              : 
   11708         6735 :     middle += nmatch;
   11709         6799 :     while (middle <= high)
   11710              :     {
   11711         3620 :         if (classoid != middle->classoid ||
   11712         3166 :             objoid != middle->objoid)
   11713              :             break;
   11714           64 :         middle++;
   11715           64 :         nmatch++;
   11716              :     }
   11717              : 
   11718         6735 :     return nmatch;
   11719              : }
   11720              : 
   11721              : /*
   11722              :  * collectComments --
   11723              :  *
   11724              :  * Construct a table of all comments available for database objects;
   11725              :  * also set the has-comment component flag for each relevant object.
   11726              :  *
   11727              :  * We used to do per-object queries for the comments, but it's much faster
   11728              :  * to pull them all over at once, and on most databases the memory cost
   11729              :  * isn't high.
   11730              :  *
   11731              :  * The table is sorted by classoid/objid/objsubid for speed in lookup.
   11732              :  */
   11733              : static void
   11734          259 : collectComments(Archive *fout)
   11735              : {
   11736              :     PGresult   *res;
   11737              :     PQExpBuffer query;
   11738              :     int         i_description;
   11739              :     int         i_classoid;
   11740              :     int         i_objoid;
   11741              :     int         i_objsubid;
   11742              :     int         ntups;
   11743              :     int         i;
   11744              :     DumpableObject *dobj;
   11745              : 
   11746          259 :     query = createPQExpBuffer();
   11747              : 
   11748          259 :     appendPQExpBufferStr(query, "SELECT description, classoid, objoid, objsubid "
   11749              :                          "FROM pg_catalog.pg_description "
   11750              :                          "ORDER BY classoid, objoid, objsubid");
   11751              : 
   11752          259 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   11753              : 
   11754              :     /* Construct lookup table containing OIDs in numeric form */
   11755              : 
   11756          259 :     i_description = PQfnumber(res, "description");
   11757          259 :     i_classoid = PQfnumber(res, "classoid");
   11758          259 :     i_objoid = PQfnumber(res, "objoid");
   11759          259 :     i_objsubid = PQfnumber(res, "objsubid");
   11760              : 
   11761          259 :     ntups = PQntuples(res);
   11762              : 
   11763          259 :     comments = pg_malloc_array(CommentItem, ntups);
   11764          259 :     ncomments = 0;
   11765          259 :     dobj = NULL;
   11766              : 
   11767      1394387 :     for (i = 0; i < ntups; i++)
   11768              :     {
   11769              :         CatalogId   objId;
   11770              :         int         subid;
   11771              : 
   11772      1394128 :         objId.tableoid = atooid(PQgetvalue(res, i, i_classoid));
   11773      1394128 :         objId.oid = atooid(PQgetvalue(res, i, i_objoid));
   11774      1394128 :         subid = atoi(PQgetvalue(res, i, i_objsubid));
   11775              : 
   11776              :         /* We needn't remember comments that don't match any dumpable object */
   11777      1394128 :         if (dobj == NULL ||
   11778       507153 :             dobj->catId.tableoid != objId.tableoid ||
   11779       504067 :             dobj->catId.oid != objId.oid)
   11780      1394038 :             dobj = findObjectByCatalogId(objId);
   11781      1394128 :         if (dobj == NULL)
   11782       886722 :             continue;
   11783              : 
   11784              :         /*
   11785              :          * Comments on columns of composite types are linked to the type's
   11786              :          * pg_class entry, but we need to set the DUMP_COMPONENT_COMMENT flag
   11787              :          * in the type's own DumpableObject.
   11788              :          */
   11789       507406 :         if (subid != 0 && dobj->objType == DO_TABLE &&
   11790          194 :             ((TableInfo *) dobj)->relkind == RELKIND_COMPOSITE_TYPE)
   11791           45 :         {
   11792              :             TypeInfo   *cTypeInfo;
   11793              : 
   11794           45 :             cTypeInfo = findTypeByOid(((TableInfo *) dobj)->reltype);
   11795           45 :             if (cTypeInfo)
   11796           45 :                 cTypeInfo->dobj.components |= DUMP_COMPONENT_COMMENT;
   11797              :         }
   11798              :         else
   11799       507361 :             dobj->components |= DUMP_COMPONENT_COMMENT;
   11800              : 
   11801       507406 :         comments[ncomments].descr = pg_strdup(PQgetvalue(res, i, i_description));
   11802       507406 :         comments[ncomments].classoid = objId.tableoid;
   11803       507406 :         comments[ncomments].objoid = objId.oid;
   11804       507406 :         comments[ncomments].objsubid = subid;
   11805       507406 :         ncomments++;
   11806              :     }
   11807              : 
   11808          259 :     PQclear(res);
   11809          259 :     destroyPQExpBuffer(query);
   11810          259 : }
   11811              : 
   11812              : /*
   11813              :  * dumpDumpableObject
   11814              :  *
   11815              :  * This routine and its subsidiaries are responsible for creating
   11816              :  * ArchiveEntries (TOC objects) for each object to be dumped.
   11817              :  */
   11818              : static void
   11819       976035 : dumpDumpableObject(Archive *fout, DumpableObject *dobj)
   11820              : {
   11821              :     /*
   11822              :      * Clear any dump-request bits for components that don't exist for this
   11823              :      * object.  (This makes it safe to initially use DUMP_COMPONENT_ALL as the
   11824              :      * request for every kind of object.)
   11825              :      */
   11826       976035 :     dobj->dump &= dobj->components;
   11827              : 
   11828              :     /* Now, short-circuit if there's nothing to be done here. */
   11829       976035 :     if (dobj->dump == 0)
   11830       882810 :         return;
   11831              : 
   11832        93225 :     switch (dobj->objType)
   11833              :     {
   11834          660 :         case DO_NAMESPACE:
   11835          660 :             dumpNamespace(fout, (const NamespaceInfo *) dobj);
   11836          660 :             break;
   11837           25 :         case DO_EXTENSION:
   11838           25 :             dumpExtension(fout, (const ExtensionInfo *) dobj);
   11839           25 :             break;
   11840          948 :         case DO_TYPE:
   11841          948 :             dumpType(fout, (const TypeInfo *) dobj);
   11842          948 :             break;
   11843           73 :         case DO_SHELL_TYPE:
   11844           73 :             dumpShellType(fout, (const ShellTypeInfo *) dobj);
   11845           73 :             break;
   11846         1898 :         case DO_FUNC:
   11847         1898 :             dumpFunc(fout, (const FuncInfo *) dobj);
   11848         1898 :             break;
   11849          292 :         case DO_AGG:
   11850          292 :             dumpAgg(fout, (const AggInfo *) dobj);
   11851          292 :             break;
   11852         2522 :         case DO_OPERATOR:
   11853         2522 :             dumpOpr(fout, (const OprInfo *) dobj);
   11854         2522 :             break;
   11855           80 :         case DO_ACCESS_METHOD:
   11856           80 :             dumpAccessMethod(fout, (const AccessMethodInfo *) dobj);
   11857           80 :             break;
   11858          666 :         case DO_OPCLASS:
   11859          666 :             dumpOpclass(fout, (const OpclassInfo *) dobj);
   11860          666 :             break;
   11861          555 :         case DO_OPFAMILY:
   11862          555 :             dumpOpfamily(fout, (const OpfamilyInfo *) dobj);
   11863          555 :             break;
   11864         2729 :         case DO_COLLATION:
   11865         2729 :             dumpCollation(fout, (const CollInfo *) dobj);
   11866         2729 :             break;
   11867          332 :         case DO_CONVERSION:
   11868          332 :             dumpConversion(fout, (const ConvInfo *) dobj);
   11869          332 :             break;
   11870        44759 :         case DO_TABLE:
   11871        44759 :             dumpTable(fout, (const TableInfo *) dobj);
   11872        44759 :             break;
   11873         1431 :         case DO_TABLE_ATTACH:
   11874         1431 :             dumpTableAttach(fout, (const TableAttachInfo *) dobj);
   11875         1431 :             break;
   11876         1087 :         case DO_ATTRDEF:
   11877         1087 :             dumpAttrDef(fout, (const AttrDefInfo *) dobj);
   11878         1087 :             break;
   11879         2768 :         case DO_INDEX:
   11880         2768 :             dumpIndex(fout, (const IndxInfo *) dobj);
   11881         2768 :             break;
   11882          594 :         case DO_INDEX_ATTACH:
   11883          594 :             dumpIndexAttach(fout, (const IndexAttachInfo *) dobj);
   11884          594 :             break;
   11885          171 :         case DO_STATSEXT:
   11886          171 :             dumpStatisticsExt(fout, (const StatsExtInfo *) dobj);
   11887          171 :             dumpStatisticsExtStats(fout, (const StatsExtInfo *) dobj);
   11888          171 :             break;
   11889          345 :         case DO_REFRESH_MATVIEW:
   11890          345 :             refreshMatViewData(fout, (const TableDataInfo *) dobj);
   11891          345 :             break;
   11892         1164 :         case DO_RULE:
   11893         1164 :             dumpRule(fout, (const RuleInfo *) dobj);
   11894         1164 :             break;
   11895          523 :         case DO_TRIGGER:
   11896          523 :             dumpTrigger(fout, (const TriggerInfo *) dobj);
   11897          523 :             break;
   11898           42 :         case DO_EVENT_TRIGGER:
   11899           42 :             dumpEventTrigger(fout, (const EventTriggerInfo *) dobj);
   11900           42 :             break;
   11901         2503 :         case DO_CONSTRAINT:
   11902         2503 :             dumpConstraint(fout, (const ConstraintInfo *) dobj);
   11903         2503 :             break;
   11904          231 :         case DO_FK_CONSTRAINT:
   11905          231 :             dumpConstraint(fout, (const ConstraintInfo *) dobj);
   11906          231 :             break;
   11907           82 :         case DO_PROCLANG:
   11908           82 :             dumpProcLang(fout, (const ProcLangInfo *) dobj);
   11909           82 :             break;
   11910           67 :         case DO_CAST:
   11911           67 :             dumpCast(fout, (const CastInfo *) dobj);
   11912           67 :             break;
   11913           42 :         case DO_TRANSFORM:
   11914           42 :             dumpTransform(fout, (const TransformInfo *) dobj);
   11915           42 :             break;
   11916          402 :         case DO_SEQUENCE_SET:
   11917          402 :             dumpSequenceData(fout, (const TableDataInfo *) dobj);
   11918          402 :             break;
   11919         4656 :         case DO_TABLE_DATA:
   11920         4656 :             dumpTableData(fout, (const TableDataInfo *) dobj);
   11921         4656 :             break;
   11922        15493 :         case DO_DUMMY_TYPE:
   11923              :             /* table rowtypes and array types are never dumped separately */
   11924        15493 :             break;
   11925           41 :         case DO_TSPARSER:
   11926           41 :             dumpTSParser(fout, (const TSParserInfo *) dobj);
   11927           41 :             break;
   11928          179 :         case DO_TSDICT:
   11929          179 :             dumpTSDictionary(fout, (const TSDictInfo *) dobj);
   11930          179 :             break;
   11931           53 :         case DO_TSTEMPLATE:
   11932           53 :             dumpTSTemplate(fout, (const TSTemplateInfo *) dobj);
   11933           53 :             break;
   11934          154 :         case DO_TSCONFIG:
   11935          154 :             dumpTSConfig(fout, (const TSConfigInfo *) dobj);
   11936          154 :             break;
   11937           52 :         case DO_FDW:
   11938           52 :             dumpForeignDataWrapper(fout, (const FdwInfo *) dobj);
   11939           52 :             break;
   11940           56 :         case DO_FOREIGN_SERVER:
   11941           56 :             dumpForeignServer(fout, (const ForeignServerInfo *) dobj);
   11942           56 :             break;
   11943          160 :         case DO_DEFAULT_ACL:
   11944          160 :             dumpDefaultACL(fout, (const DefaultACLInfo *) dobj);
   11945          160 :             break;
   11946           84 :         case DO_LARGE_OBJECT:
   11947           84 :             dumpLO(fout, (const LoInfo *) dobj);
   11948           84 :             break;
   11949           84 :         case DO_LARGE_OBJECT_DATA:
   11950           84 :             if (dobj->dump & DUMP_COMPONENT_DATA)
   11951              :             {
   11952              :                 LoInfo     *loinfo;
   11953              :                 TocEntry   *te;
   11954              : 
   11955           84 :                 loinfo = (LoInfo *) findObjectByDumpId(dobj->dependencies[0]);
   11956           84 :                 if (loinfo == NULL)
   11957            0 :                     pg_fatal("missing metadata for large objects \"%s\"",
   11958              :                              dobj->name);
   11959              : 
   11960           84 :                 te = ArchiveEntry(fout, dobj->catId, dobj->dumpId,
   11961           84 :                                   ARCHIVE_OPTS(.tag = dobj->name,
   11962              :                                                .owner = loinfo->rolname,
   11963              :                                                .description = "BLOBS",
   11964              :                                                .section = SECTION_DATA,
   11965              :                                                .deps = dobj->dependencies,
   11966              :                                                .nDeps = dobj->nDeps,
   11967              :                                                .dumpFn = dumpLOs,
   11968              :                                                .dumpArg = loinfo));
   11969              : 
   11970              :                 /*
   11971              :                  * Set the TocEntry's dataLength in case we are doing a
   11972              :                  * parallel dump and want to order dump jobs by table size.
   11973              :                  * (We need some size estimate for every TocEntry with a
   11974              :                  * DataDumper function.)  We don't currently have any cheap
   11975              :                  * way to estimate the size of LOs, but fortunately it doesn't
   11976              :                  * matter too much as long as we get large batches of LOs
   11977              :                  * processed reasonably early.  Assume 8K per blob.
   11978              :                  */
   11979           84 :                 te->dataLength = loinfo->numlos * (pgoff_t) 8192;
   11980              :             }
   11981           84 :             break;
   11982          336 :         case DO_POLICY:
   11983          336 :             dumpPolicy(fout, (const PolicyInfo *) dobj);
   11984          336 :             break;
   11985          396 :         case DO_PUBLICATION:
   11986          396 :             dumpPublication(fout, (const PublicationInfo *) dobj);
   11987          396 :             break;
   11988          284 :         case DO_PUBLICATION_REL:
   11989          284 :             dumpPublicationTable(fout, (const PublicationRelInfo *) dobj);
   11990          284 :             break;
   11991           99 :         case DO_PUBLICATION_TABLE_IN_SCHEMA:
   11992           99 :             dumpPublicationNamespace(fout,
   11993              :                                      (const PublicationSchemaInfo *) dobj);
   11994           99 :             break;
   11995          110 :         case DO_SUBSCRIPTION:
   11996          110 :             dumpSubscription(fout, (const SubscriptionInfo *) dobj);
   11997          110 :             break;
   11998            3 :         case DO_SUBSCRIPTION_REL:
   11999            3 :             dumpSubscriptionTable(fout, (const SubRelInfo *) dobj);
   12000            3 :             break;
   12001         3476 :         case DO_REL_STATS:
   12002         3476 :             dumpRelationStats(fout, (const RelStatsInfo *) dobj);
   12003         3476 :             break;
   12004          518 :         case DO_PRE_DATA_BOUNDARY:
   12005              :         case DO_POST_DATA_BOUNDARY:
   12006              :             /* never dumped, nothing to do */
   12007          518 :             break;
   12008              :     }
   12009              : }
   12010              : 
   12011              : /*
   12012              :  * dumpNamespace
   12013              :  *    writes out to fout the queries to recreate a user-defined namespace
   12014              :  */
   12015              : static void
   12016          660 : dumpNamespace(Archive *fout, const NamespaceInfo *nspinfo)
   12017              : {
   12018          660 :     DumpOptions *dopt = fout->dopt;
   12019              :     PQExpBuffer q;
   12020              :     PQExpBuffer delq;
   12021              :     char       *qnspname;
   12022              : 
   12023              :     /* Do nothing if not dumping schema */
   12024          660 :     if (!dopt->dumpSchema)
   12025           28 :         return;
   12026              : 
   12027          632 :     q = createPQExpBuffer();
   12028          632 :     delq = createPQExpBuffer();
   12029              : 
   12030          632 :     qnspname = pg_strdup(fmtId(nspinfo->dobj.name));
   12031              : 
   12032          632 :     if (nspinfo->create)
   12033              :     {
   12034          408 :         appendPQExpBuffer(delq, "DROP SCHEMA %s;\n", qnspname);
   12035          408 :         appendPQExpBuffer(q, "CREATE SCHEMA %s;\n", qnspname);
   12036              :     }
   12037              :     else
   12038              :     {
   12039              :         /* see selectDumpableNamespace() */
   12040          224 :         appendPQExpBufferStr(delq,
   12041              :                              "-- *not* dropping schema, since initdb creates it\n");
   12042          224 :         appendPQExpBufferStr(q,
   12043              :                              "-- *not* creating schema, since initdb creates it\n");
   12044              :     }
   12045              : 
   12046          632 :     if (dopt->binary_upgrade)
   12047          102 :         binary_upgrade_extension_member(q, &nspinfo->dobj,
   12048              :                                         "SCHEMA", qnspname, NULL);
   12049              : 
   12050          632 :     if (nspinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   12051          214 :         ArchiveEntry(fout, nspinfo->dobj.catId, nspinfo->dobj.dumpId,
   12052          214 :                      ARCHIVE_OPTS(.tag = nspinfo->dobj.name,
   12053              :                                   .owner = nspinfo->rolname,
   12054              :                                   .description = "SCHEMA",
   12055              :                                   .section = SECTION_PRE_DATA,
   12056              :                                   .createStmt = q->data,
   12057              :                                   .dropStmt = delq->data));
   12058              : 
   12059              :     /* Dump Schema Comments and Security Labels */
   12060          632 :     if (nspinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   12061              :     {
   12062          229 :         const char *initdb_comment = NULL;
   12063              : 
   12064          229 :         if (!nspinfo->create && strcmp(qnspname, "public") == 0)
   12065          186 :             initdb_comment = "standard public schema";
   12066          229 :         dumpCommentExtended(fout, "SCHEMA", qnspname,
   12067          229 :                             NULL, nspinfo->rolname,
   12068          229 :                             nspinfo->dobj.catId, 0, nspinfo->dobj.dumpId,
   12069              :                             initdb_comment);
   12070              :     }
   12071              : 
   12072          632 :     if (nspinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
   12073            0 :         dumpSecLabel(fout, "SCHEMA", qnspname,
   12074            0 :                      NULL, nspinfo->rolname,
   12075            0 :                      nspinfo->dobj.catId, 0, nspinfo->dobj.dumpId);
   12076              : 
   12077          632 :     if (nspinfo->dobj.dump & DUMP_COMPONENT_ACL)
   12078          530 :         dumpACL(fout, nspinfo->dobj.dumpId, InvalidDumpId, "SCHEMA",
   12079              :                 qnspname, NULL, NULL,
   12080          530 :                 NULL, nspinfo->rolname, &nspinfo->dacl);
   12081              : 
   12082          632 :     free(qnspname);
   12083              : 
   12084          632 :     destroyPQExpBuffer(q);
   12085          632 :     destroyPQExpBuffer(delq);
   12086              : }
   12087              : 
   12088              : /*
   12089              :  * dumpExtension
   12090              :  *    writes out to fout the queries to recreate an extension
   12091              :  */
   12092              : static void
   12093           25 : dumpExtension(Archive *fout, const ExtensionInfo *extinfo)
   12094              : {
   12095           25 :     DumpOptions *dopt = fout->dopt;
   12096              :     PQExpBuffer q;
   12097              :     PQExpBuffer delq;
   12098              :     char       *qextname;
   12099              : 
   12100              :     /* Do nothing if not dumping schema */
   12101           25 :     if (!dopt->dumpSchema)
   12102            1 :         return;
   12103              : 
   12104           24 :     q = createPQExpBuffer();
   12105           24 :     delq = createPQExpBuffer();
   12106              : 
   12107           24 :     qextname = pg_strdup(fmtId(extinfo->dobj.name));
   12108              : 
   12109           24 :     appendPQExpBuffer(delq, "DROP EXTENSION %s;\n", qextname);
   12110              : 
   12111           24 :     if (!dopt->binary_upgrade)
   12112              :     {
   12113              :         /*
   12114              :          * In a regular dump, we simply create the extension, intentionally
   12115              :          * not specifying a version, so that the destination installation's
   12116              :          * default version is used.
   12117              :          *
   12118              :          * Use of IF NOT EXISTS here is unlike our behavior for other object
   12119              :          * types; but there are various scenarios in which it's convenient to
   12120              :          * manually create the desired extension before restoring, so we
   12121              :          * prefer to allow it to exist already.
   12122              :          */
   12123           17 :         appendPQExpBuffer(q, "CREATE EXTENSION IF NOT EXISTS %s WITH SCHEMA %s;\n",
   12124           17 :                           qextname, fmtId(extinfo->namespace));
   12125              :     }
   12126              :     else
   12127              :     {
   12128              :         /*
   12129              :          * In binary-upgrade mode, it's critical to reproduce the state of the
   12130              :          * database exactly, so our procedure is to create an empty extension,
   12131              :          * restore all the contained objects normally, and add them to the
   12132              :          * extension one by one.  This function performs just the first of
   12133              :          * those steps.  binary_upgrade_extension_member() takes care of
   12134              :          * adding member objects as they're created.
   12135              :          */
   12136              :         int         i;
   12137              :         int         n;
   12138              : 
   12139            7 :         appendPQExpBufferStr(q, "-- For binary upgrade, create an empty extension and insert objects into it\n");
   12140              : 
   12141              :         /*
   12142              :          * We unconditionally create the extension, so we must drop it if it
   12143              :          * exists.  This could happen if the user deleted 'plpgsql' and then
   12144              :          * readded it, causing its oid to be greater than g_last_builtin_oid.
   12145              :          */
   12146            7 :         appendPQExpBuffer(q, "DROP EXTENSION IF EXISTS %s;\n", qextname);
   12147              : 
   12148            7 :         appendPQExpBufferStr(q,
   12149              :                              "SELECT pg_catalog.binary_upgrade_create_empty_extension(");
   12150            7 :         appendStringLiteralAH(q, extinfo->dobj.name, fout);
   12151            7 :         appendPQExpBufferStr(q, ", ");
   12152            7 :         appendStringLiteralAH(q, extinfo->namespace, fout);
   12153            7 :         appendPQExpBufferStr(q, ", ");
   12154            7 :         appendPQExpBuffer(q, "%s, ", extinfo->relocatable ? "true" : "false");
   12155            7 :         appendStringLiteralAH(q, extinfo->extversion, fout);
   12156            7 :         appendPQExpBufferStr(q, ", ");
   12157              : 
   12158              :         /*
   12159              :          * Note that we're pushing extconfig (an OID array) back into
   12160              :          * pg_extension exactly as-is.  This is OK because pg_class OIDs are
   12161              :          * preserved in binary upgrade.
   12162              :          */
   12163            7 :         if (strlen(extinfo->extconfig) > 2)
   12164            1 :             appendStringLiteralAH(q, extinfo->extconfig, fout);
   12165              :         else
   12166            6 :             appendPQExpBufferStr(q, "NULL");
   12167            7 :         appendPQExpBufferStr(q, ", ");
   12168            7 :         if (strlen(extinfo->extcondition) > 2)
   12169            1 :             appendStringLiteralAH(q, extinfo->extcondition, fout);
   12170              :         else
   12171            6 :             appendPQExpBufferStr(q, "NULL");
   12172            7 :         appendPQExpBufferStr(q, ", ");
   12173            7 :         appendPQExpBufferStr(q, "ARRAY[");
   12174            7 :         n = 0;
   12175           14 :         for (i = 0; i < extinfo->dobj.nDeps; i++)
   12176              :         {
   12177              :             DumpableObject *extobj;
   12178              : 
   12179            7 :             extobj = findObjectByDumpId(extinfo->dobj.dependencies[i]);
   12180            7 :             if (extobj && extobj->objType == DO_EXTENSION)
   12181              :             {
   12182            0 :                 if (n++ > 0)
   12183            0 :                     appendPQExpBufferChar(q, ',');
   12184            0 :                 appendStringLiteralAH(q, extobj->name, fout);
   12185              :             }
   12186              :         }
   12187            7 :         appendPQExpBufferStr(q, "]::pg_catalog.text[]");
   12188            7 :         appendPQExpBufferStr(q, ");\n");
   12189              :     }
   12190              : 
   12191           24 :     if (extinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   12192           24 :         ArchiveEntry(fout, extinfo->dobj.catId, extinfo->dobj.dumpId,
   12193           24 :                      ARCHIVE_OPTS(.tag = extinfo->dobj.name,
   12194              :                                   .description = "EXTENSION",
   12195              :                                   .section = SECTION_PRE_DATA,
   12196              :                                   .createStmt = q->data,
   12197              :                                   .dropStmt = delq->data));
   12198              : 
   12199              :     /* Dump Extension Comments */
   12200           24 :     if (extinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   12201           24 :         dumpComment(fout, "EXTENSION", qextname,
   12202              :                     NULL, "",
   12203           24 :                     extinfo->dobj.catId, 0, extinfo->dobj.dumpId);
   12204              : 
   12205           24 :     free(qextname);
   12206              : 
   12207           24 :     destroyPQExpBuffer(q);
   12208           24 :     destroyPQExpBuffer(delq);
   12209              : }
   12210              : 
   12211              : /*
   12212              :  * dumpType
   12213              :  *    writes out to fout the queries to recreate a user-defined type
   12214              :  */
   12215              : static void
   12216          948 : dumpType(Archive *fout, const TypeInfo *tyinfo)
   12217              : {
   12218          948 :     DumpOptions *dopt = fout->dopt;
   12219              : 
   12220              :     /* Do nothing if not dumping schema */
   12221          948 :     if (!dopt->dumpSchema)
   12222           49 :         return;
   12223              : 
   12224              :     /* Dump out in proper style */
   12225          899 :     if (tyinfo->typtype == TYPTYPE_BASE)
   12226          283 :         dumpBaseType(fout, tyinfo);
   12227          616 :     else if (tyinfo->typtype == TYPTYPE_DOMAIN)
   12228          172 :         dumpDomain(fout, tyinfo);
   12229          444 :     else if (tyinfo->typtype == TYPTYPE_COMPOSITE)
   12230          130 :         dumpCompositeType(fout, tyinfo);
   12231          314 :     else if (tyinfo->typtype == TYPTYPE_ENUM)
   12232           85 :         dumpEnumType(fout, tyinfo);
   12233          229 :     else if (tyinfo->typtype == TYPTYPE_RANGE)
   12234          117 :         dumpRangeType(fout, tyinfo);
   12235          112 :     else if (tyinfo->typtype == TYPTYPE_PSEUDO && !tyinfo->isDefined)
   12236           37 :         dumpUndefinedType(fout, tyinfo);
   12237              :     else
   12238           75 :         pg_log_warning("typtype of data type \"%s\" appears to be invalid",
   12239              :                        tyinfo->dobj.name);
   12240              : }
   12241              : 
   12242              : /*
   12243              :  * dumpEnumType
   12244              :  *    writes out to fout the queries to recreate a user-defined enum type
   12245              :  */
   12246              : static void
   12247           85 : dumpEnumType(Archive *fout, const TypeInfo *tyinfo)
   12248              : {
   12249           85 :     DumpOptions *dopt = fout->dopt;
   12250           85 :     PQExpBuffer q = createPQExpBuffer();
   12251           85 :     PQExpBuffer delq = createPQExpBuffer();
   12252           85 :     PQExpBuffer query = createPQExpBuffer();
   12253              :     PGresult   *res;
   12254              :     int         num,
   12255              :                 i;
   12256              :     Oid         enum_oid;
   12257              :     char       *qtypname;
   12258              :     char       *qualtypname;
   12259              :     char       *label;
   12260              :     int         i_enumlabel;
   12261              :     int         i_oid;
   12262              : 
   12263           85 :     if (!fout->is_prepared[PREPQUERY_DUMPENUMTYPE])
   12264              :     {
   12265              :         /* Set up query for enum-specific details */
   12266           40 :         appendPQExpBufferStr(query,
   12267              :                              "PREPARE dumpEnumType(pg_catalog.oid) AS\n"
   12268              :                              "SELECT oid, enumlabel "
   12269              :                              "FROM pg_catalog.pg_enum "
   12270              :                              "WHERE enumtypid = $1 "
   12271              :                              "ORDER BY enumsortorder");
   12272              : 
   12273           40 :         ExecuteSqlStatement(fout, query->data);
   12274              : 
   12275           40 :         fout->is_prepared[PREPQUERY_DUMPENUMTYPE] = true;
   12276              :     }
   12277              : 
   12278           85 :     printfPQExpBuffer(query,
   12279              :                       "EXECUTE dumpEnumType('%u')",
   12280           85 :                       tyinfo->dobj.catId.oid);
   12281              : 
   12282           85 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   12283              : 
   12284           85 :     num = PQntuples(res);
   12285              : 
   12286           85 :     qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
   12287           85 :     qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
   12288              : 
   12289              :     /*
   12290              :      * CASCADE shouldn't be required here as for normal types since the I/O
   12291              :      * functions are generic and do not get dropped.
   12292              :      */
   12293           85 :     appendPQExpBuffer(delq, "DROP TYPE %s;\n", qualtypname);
   12294              : 
   12295           85 :     if (dopt->binary_upgrade)
   12296            6 :         binary_upgrade_set_type_oids_by_type_oid(fout, q,
   12297            6 :                                                  tyinfo->dobj.catId.oid,
   12298              :                                                  false, false);
   12299              : 
   12300           85 :     appendPQExpBuffer(q, "CREATE TYPE %s AS ENUM (",
   12301              :                       qualtypname);
   12302              : 
   12303           85 :     if (!dopt->binary_upgrade)
   12304              :     {
   12305           79 :         i_enumlabel = PQfnumber(res, "enumlabel");
   12306              : 
   12307              :         /* Labels with server-assigned oids */
   12308          482 :         for (i = 0; i < num; i++)
   12309              :         {
   12310          403 :             label = PQgetvalue(res, i, i_enumlabel);
   12311          403 :             if (i > 0)
   12312          324 :                 appendPQExpBufferChar(q, ',');
   12313          403 :             appendPQExpBufferStr(q, "\n    ");
   12314          403 :             appendStringLiteralAH(q, label, fout);
   12315              :         }
   12316              :     }
   12317              : 
   12318           85 :     appendPQExpBufferStr(q, "\n);\n");
   12319              : 
   12320           85 :     if (dopt->binary_upgrade)
   12321              :     {
   12322            6 :         i_oid = PQfnumber(res, "oid");
   12323            6 :         i_enumlabel = PQfnumber(res, "enumlabel");
   12324              : 
   12325              :         /* Labels with dump-assigned (preserved) oids */
   12326           62 :         for (i = 0; i < num; i++)
   12327              :         {
   12328           56 :             enum_oid = atooid(PQgetvalue(res, i, i_oid));
   12329           56 :             label = PQgetvalue(res, i, i_enumlabel);
   12330              : 
   12331           56 :             if (i == 0)
   12332            6 :                 appendPQExpBufferStr(q, "\n-- For binary upgrade, must preserve pg_enum oids\n");
   12333           56 :             appendPQExpBuffer(q,
   12334              :                               "SELECT pg_catalog.binary_upgrade_set_next_pg_enum_oid('%u'::pg_catalog.oid);\n",
   12335              :                               enum_oid);
   12336           56 :             appendPQExpBuffer(q, "ALTER TYPE %s ADD VALUE ", qualtypname);
   12337           56 :             appendStringLiteralAH(q, label, fout);
   12338           56 :             appendPQExpBufferStr(q, ";\n\n");
   12339              :         }
   12340              :     }
   12341              : 
   12342           85 :     if (dopt->binary_upgrade)
   12343            6 :         binary_upgrade_extension_member(q, &tyinfo->dobj,
   12344              :                                         "TYPE", qtypname,
   12345            6 :                                         tyinfo->dobj.namespace->dobj.name);
   12346              : 
   12347           85 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   12348           85 :         ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
   12349           85 :                      ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
   12350              :                                   .namespace = tyinfo->dobj.namespace->dobj.name,
   12351              :                                   .owner = tyinfo->rolname,
   12352              :                                   .description = "TYPE",
   12353              :                                   .section = SECTION_PRE_DATA,
   12354              :                                   .createStmt = q->data,
   12355              :                                   .dropStmt = delq->data));
   12356              : 
   12357              :     /* Dump Type Comments and Security Labels */
   12358           85 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   12359           32 :         dumpComment(fout, "TYPE", qtypname,
   12360           32 :                     tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
   12361           32 :                     tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
   12362              : 
   12363           85 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
   12364            0 :         dumpSecLabel(fout, "TYPE", qtypname,
   12365            0 :                      tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
   12366            0 :                      tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
   12367              : 
   12368           85 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
   12369           32 :         dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
   12370              :                 qtypname, NULL,
   12371           32 :                 tyinfo->dobj.namespace->dobj.name,
   12372           32 :                 NULL, tyinfo->rolname, &tyinfo->dacl);
   12373              : 
   12374           85 :     PQclear(res);
   12375           85 :     destroyPQExpBuffer(q);
   12376           85 :     destroyPQExpBuffer(delq);
   12377           85 :     destroyPQExpBuffer(query);
   12378           85 :     free(qtypname);
   12379           85 :     free(qualtypname);
   12380           85 : }
   12381              : 
   12382              : /*
   12383              :  * dumpRangeType
   12384              :  *    writes out to fout the queries to recreate a user-defined range type
   12385              :  */
   12386              : static void
   12387          117 : dumpRangeType(Archive *fout, const TypeInfo *tyinfo)
   12388              : {
   12389          117 :     DumpOptions *dopt = fout->dopt;
   12390          117 :     PQExpBuffer q = createPQExpBuffer();
   12391          117 :     PQExpBuffer delq = createPQExpBuffer();
   12392          117 :     PQExpBuffer query = createPQExpBuffer();
   12393              :     PGresult   *res;
   12394              :     Oid         collationOid;
   12395              :     char       *qtypname;
   12396              :     char       *qualtypname;
   12397              :     char       *procname;
   12398              : 
   12399          117 :     if (!fout->is_prepared[PREPQUERY_DUMPRANGETYPE])
   12400              :     {
   12401              :         /* Set up query for range-specific details */
   12402           40 :         appendPQExpBufferStr(query,
   12403              :                              "PREPARE dumpRangeType(pg_catalog.oid) AS\n");
   12404              : 
   12405           40 :         appendPQExpBufferStr(query,
   12406              :                              "SELECT ");
   12407              : 
   12408           40 :         if (fout->remoteVersion >= 140000)
   12409           40 :             appendPQExpBufferStr(query,
   12410              :                                  "pg_catalog.format_type(rngmultitypid, NULL) AS rngmultitype, ");
   12411              :         else
   12412            0 :             appendPQExpBufferStr(query,
   12413              :                                  "NULL AS rngmultitype, ");
   12414              : 
   12415           40 :         appendPQExpBufferStr(query,
   12416              :                              "pg_catalog.format_type(rngsubtype, NULL) AS rngsubtype, "
   12417              :                              "opc.opcname AS opcname, "
   12418              :                              "(SELECT nspname FROM pg_catalog.pg_namespace nsp "
   12419              :                              "  WHERE nsp.oid = opc.opcnamespace) AS opcnsp, "
   12420              :                              "opc.opcdefault, "
   12421              :                              "CASE WHEN rngcollation = st.typcollation THEN 0 "
   12422              :                              "     ELSE rngcollation END AS collation, "
   12423              :                              "rngcanonical, rngsubdiff "
   12424              :                              "FROM pg_catalog.pg_range r, pg_catalog.pg_type st, "
   12425              :                              "     pg_catalog.pg_opclass opc "
   12426              :                              "WHERE st.oid = rngsubtype AND opc.oid = rngsubopc AND "
   12427              :                              "rngtypid = $1");
   12428              : 
   12429           40 :         ExecuteSqlStatement(fout, query->data);
   12430              : 
   12431           40 :         fout->is_prepared[PREPQUERY_DUMPRANGETYPE] = true;
   12432              :     }
   12433              : 
   12434          117 :     printfPQExpBuffer(query,
   12435              :                       "EXECUTE dumpRangeType('%u')",
   12436          117 :                       tyinfo->dobj.catId.oid);
   12437              : 
   12438          117 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   12439              : 
   12440          117 :     qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
   12441          117 :     qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
   12442              : 
   12443              :     /*
   12444              :      * CASCADE shouldn't be required here as for normal types since the I/O
   12445              :      * functions are generic and do not get dropped.
   12446              :      */
   12447          117 :     appendPQExpBuffer(delq, "DROP TYPE %s;\n", qualtypname);
   12448              : 
   12449          117 :     if (dopt->binary_upgrade)
   12450            9 :         binary_upgrade_set_type_oids_by_type_oid(fout, q,
   12451            9 :                                                  tyinfo->dobj.catId.oid,
   12452              :                                                  false, true);
   12453              : 
   12454          117 :     appendPQExpBuffer(q, "CREATE TYPE %s AS RANGE (",
   12455              :                       qualtypname);
   12456              : 
   12457          117 :     appendPQExpBuffer(q, "\n    subtype = %s",
   12458              :                       PQgetvalue(res, 0, PQfnumber(res, "rngsubtype")));
   12459              : 
   12460          117 :     if (!PQgetisnull(res, 0, PQfnumber(res, "rngmultitype")))
   12461          117 :         appendPQExpBuffer(q, ",\n    multirange_type_name = %s",
   12462              :                           PQgetvalue(res, 0, PQfnumber(res, "rngmultitype")));
   12463              : 
   12464              :     /* print subtype_opclass only if not default for subtype */
   12465          117 :     if (PQgetvalue(res, 0, PQfnumber(res, "opcdefault"))[0] != 't')
   12466              :     {
   12467           32 :         char       *opcname = PQgetvalue(res, 0, PQfnumber(res, "opcname"));
   12468           32 :         char       *nspname = PQgetvalue(res, 0, PQfnumber(res, "opcnsp"));
   12469              : 
   12470           32 :         appendPQExpBuffer(q, ",\n    subtype_opclass = %s.",
   12471              :                           fmtId(nspname));
   12472           32 :         appendPQExpBufferStr(q, fmtId(opcname));
   12473              :     }
   12474              : 
   12475          117 :     collationOid = atooid(PQgetvalue(res, 0, PQfnumber(res, "collation")));
   12476          117 :     if (OidIsValid(collationOid))
   12477              :     {
   12478           37 :         CollInfo   *coll = findCollationByOid(collationOid);
   12479              : 
   12480           37 :         if (coll)
   12481           37 :             appendPQExpBuffer(q, ",\n    collation = %s",
   12482           37 :                               fmtQualifiedDumpable(coll));
   12483              :     }
   12484              : 
   12485          117 :     procname = PQgetvalue(res, 0, PQfnumber(res, "rngcanonical"));
   12486          117 :     if (strcmp(procname, "-") != 0)
   12487            9 :         appendPQExpBuffer(q, ",\n    canonical = %s", procname);
   12488              : 
   12489          117 :     procname = PQgetvalue(res, 0, PQfnumber(res, "rngsubdiff"));
   12490          117 :     if (strcmp(procname, "-") != 0)
   12491           23 :         appendPQExpBuffer(q, ",\n    subtype_diff = %s", procname);
   12492              : 
   12493          117 :     appendPQExpBufferStr(q, "\n);\n");
   12494              : 
   12495          117 :     if (dopt->binary_upgrade)
   12496            9 :         binary_upgrade_extension_member(q, &tyinfo->dobj,
   12497              :                                         "TYPE", qtypname,
   12498            9 :                                         tyinfo->dobj.namespace->dobj.name);
   12499              : 
   12500          117 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   12501          117 :         ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
   12502          117 :                      ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
   12503              :                                   .namespace = tyinfo->dobj.namespace->dobj.name,
   12504              :                                   .owner = tyinfo->rolname,
   12505              :                                   .description = "TYPE",
   12506              :                                   .section = SECTION_PRE_DATA,
   12507              :                                   .createStmt = q->data,
   12508              :                                   .dropStmt = delq->data));
   12509              : 
   12510              :     /* Dump Type Comments and Security Labels */
   12511          117 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   12512           50 :         dumpComment(fout, "TYPE", qtypname,
   12513           50 :                     tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
   12514           50 :                     tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
   12515              : 
   12516          117 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
   12517            0 :         dumpSecLabel(fout, "TYPE", qtypname,
   12518            0 :                      tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
   12519            0 :                      tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
   12520              : 
   12521          117 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
   12522           32 :         dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
   12523              :                 qtypname, NULL,
   12524           32 :                 tyinfo->dobj.namespace->dobj.name,
   12525           32 :                 NULL, tyinfo->rolname, &tyinfo->dacl);
   12526              : 
   12527          117 :     PQclear(res);
   12528          117 :     destroyPQExpBuffer(q);
   12529          117 :     destroyPQExpBuffer(delq);
   12530          117 :     destroyPQExpBuffer(query);
   12531          117 :     free(qtypname);
   12532          117 :     free(qualtypname);
   12533          117 : }
   12534              : 
   12535              : /*
   12536              :  * dumpUndefinedType
   12537              :  *    writes out to fout the queries to recreate a !typisdefined type
   12538              :  *
   12539              :  * This is a shell type, but we use different terminology to distinguish
   12540              :  * this case from where we have to emit a shell type definition to break
   12541              :  * circular dependencies.  An undefined type shouldn't ever have anything
   12542              :  * depending on it.
   12543              :  */
   12544              : static void
   12545           37 : dumpUndefinedType(Archive *fout, const TypeInfo *tyinfo)
   12546              : {
   12547           37 :     DumpOptions *dopt = fout->dopt;
   12548           37 :     PQExpBuffer q = createPQExpBuffer();
   12549           37 :     PQExpBuffer delq = createPQExpBuffer();
   12550              :     char       *qtypname;
   12551              :     char       *qualtypname;
   12552              : 
   12553           37 :     qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
   12554           37 :     qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
   12555              : 
   12556           37 :     appendPQExpBuffer(delq, "DROP TYPE %s;\n", qualtypname);
   12557              : 
   12558           37 :     if (dopt->binary_upgrade)
   12559            2 :         binary_upgrade_set_type_oids_by_type_oid(fout, q,
   12560            2 :                                                  tyinfo->dobj.catId.oid,
   12561              :                                                  false, false);
   12562              : 
   12563           37 :     appendPQExpBuffer(q, "CREATE TYPE %s;\n",
   12564              :                       qualtypname);
   12565              : 
   12566           37 :     if (dopt->binary_upgrade)
   12567            2 :         binary_upgrade_extension_member(q, &tyinfo->dobj,
   12568              :                                         "TYPE", qtypname,
   12569            2 :                                         tyinfo->dobj.namespace->dobj.name);
   12570              : 
   12571           37 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   12572           37 :         ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
   12573           37 :                      ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
   12574              :                                   .namespace = tyinfo->dobj.namespace->dobj.name,
   12575              :                                   .owner = tyinfo->rolname,
   12576              :                                   .description = "TYPE",
   12577              :                                   .section = SECTION_PRE_DATA,
   12578              :                                   .createStmt = q->data,
   12579              :                                   .dropStmt = delq->data));
   12580              : 
   12581              :     /* Dump Type Comments and Security Labels */
   12582           37 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   12583           32 :         dumpComment(fout, "TYPE", qtypname,
   12584           32 :                     tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
   12585           32 :                     tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
   12586              : 
   12587           37 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
   12588            0 :         dumpSecLabel(fout, "TYPE", qtypname,
   12589            0 :                      tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
   12590            0 :                      tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
   12591              : 
   12592           37 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
   12593            0 :         dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
   12594              :                 qtypname, NULL,
   12595            0 :                 tyinfo->dobj.namespace->dobj.name,
   12596            0 :                 NULL, tyinfo->rolname, &tyinfo->dacl);
   12597              : 
   12598           37 :     destroyPQExpBuffer(q);
   12599           37 :     destroyPQExpBuffer(delq);
   12600           37 :     free(qtypname);
   12601           37 :     free(qualtypname);
   12602           37 : }
   12603              : 
   12604              : /*
   12605              :  * dumpBaseType
   12606              :  *    writes out to fout the queries to recreate a user-defined base type
   12607              :  */
   12608              : static void
   12609          283 : dumpBaseType(Archive *fout, const TypeInfo *tyinfo)
   12610              : {
   12611          283 :     DumpOptions *dopt = fout->dopt;
   12612          283 :     PQExpBuffer q = createPQExpBuffer();
   12613          283 :     PQExpBuffer delq = createPQExpBuffer();
   12614          283 :     PQExpBuffer query = createPQExpBuffer();
   12615              :     PGresult   *res;
   12616              :     char       *qtypname;
   12617              :     char       *qualtypname;
   12618              :     char       *typlen;
   12619              :     char       *typinput;
   12620              :     char       *typoutput;
   12621              :     char       *typreceive;
   12622              :     char       *typsend;
   12623              :     char       *typmodin;
   12624              :     char       *typmodout;
   12625              :     char       *typanalyze;
   12626              :     char       *typsubscript;
   12627              :     Oid         typreceiveoid;
   12628              :     Oid         typsendoid;
   12629              :     Oid         typmodinoid;
   12630              :     Oid         typmodoutoid;
   12631              :     Oid         typanalyzeoid;
   12632              :     Oid         typsubscriptoid;
   12633              :     char       *typcategory;
   12634              :     char       *typispreferred;
   12635              :     char       *typdelim;
   12636              :     char       *typbyval;
   12637              :     char       *typalign;
   12638              :     char       *typstorage;
   12639              :     char       *typcollatable;
   12640              :     char       *typdefault;
   12641          283 :     bool        typdefault_is_literal = false;
   12642              : 
   12643          283 :     if (!fout->is_prepared[PREPQUERY_DUMPBASETYPE])
   12644              :     {
   12645              :         /* Set up query for type-specific details */
   12646           40 :         appendPQExpBufferStr(query,
   12647              :                              "PREPARE dumpBaseType(pg_catalog.oid) AS\n"
   12648              :                              "SELECT typlen, "
   12649              :                              "typinput, typoutput, typreceive, typsend, "
   12650              :                              "typreceive::pg_catalog.oid AS typreceiveoid, "
   12651              :                              "typsend::pg_catalog.oid AS typsendoid, "
   12652              :                              "typanalyze, "
   12653              :                              "typanalyze::pg_catalog.oid AS typanalyzeoid, "
   12654              :                              "typdelim, typbyval, typalign, typstorage, "
   12655              :                              "typmodin, typmodout, "
   12656              :                              "typmodin::pg_catalog.oid AS typmodinoid, "
   12657              :                              "typmodout::pg_catalog.oid AS typmodoutoid, "
   12658              :                              "typcategory, typispreferred, "
   12659              :                              "(typcollation <> 0) AS typcollatable, "
   12660              :                              "pg_catalog.pg_get_expr(typdefaultbin, 0) AS typdefaultbin, typdefault, ");
   12661              : 
   12662           40 :         if (fout->remoteVersion >= 140000)
   12663           40 :             appendPQExpBufferStr(query,
   12664              :                                  "typsubscript, "
   12665              :                                  "typsubscript::pg_catalog.oid AS typsubscriptoid ");
   12666              :         else
   12667            0 :             appendPQExpBufferStr(query,
   12668              :                                  "'-' AS typsubscript, 0 AS typsubscriptoid ");
   12669              : 
   12670           40 :         appendPQExpBufferStr(query, "FROM pg_catalog.pg_type "
   12671              :                              "WHERE oid = $1");
   12672              : 
   12673           40 :         ExecuteSqlStatement(fout, query->data);
   12674              : 
   12675           40 :         fout->is_prepared[PREPQUERY_DUMPBASETYPE] = true;
   12676              :     }
   12677              : 
   12678          283 :     printfPQExpBuffer(query,
   12679              :                       "EXECUTE dumpBaseType('%u')",
   12680          283 :                       tyinfo->dobj.catId.oid);
   12681              : 
   12682          283 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   12683              : 
   12684          283 :     typlen = PQgetvalue(res, 0, PQfnumber(res, "typlen"));
   12685          283 :     typinput = PQgetvalue(res, 0, PQfnumber(res, "typinput"));
   12686          283 :     typoutput = PQgetvalue(res, 0, PQfnumber(res, "typoutput"));
   12687          283 :     typreceive = PQgetvalue(res, 0, PQfnumber(res, "typreceive"));
   12688          283 :     typsend = PQgetvalue(res, 0, PQfnumber(res, "typsend"));
   12689          283 :     typmodin = PQgetvalue(res, 0, PQfnumber(res, "typmodin"));
   12690          283 :     typmodout = PQgetvalue(res, 0, PQfnumber(res, "typmodout"));
   12691          283 :     typanalyze = PQgetvalue(res, 0, PQfnumber(res, "typanalyze"));
   12692          283 :     typsubscript = PQgetvalue(res, 0, PQfnumber(res, "typsubscript"));
   12693          283 :     typreceiveoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typreceiveoid")));
   12694          283 :     typsendoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typsendoid")));
   12695          283 :     typmodinoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typmodinoid")));
   12696          283 :     typmodoutoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typmodoutoid")));
   12697          283 :     typanalyzeoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typanalyzeoid")));
   12698          283 :     typsubscriptoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typsubscriptoid")));
   12699          283 :     typcategory = PQgetvalue(res, 0, PQfnumber(res, "typcategory"));
   12700          283 :     typispreferred = PQgetvalue(res, 0, PQfnumber(res, "typispreferred"));
   12701          283 :     typdelim = PQgetvalue(res, 0, PQfnumber(res, "typdelim"));
   12702          283 :     typbyval = PQgetvalue(res, 0, PQfnumber(res, "typbyval"));
   12703          283 :     typalign = PQgetvalue(res, 0, PQfnumber(res, "typalign"));
   12704          283 :     typstorage = PQgetvalue(res, 0, PQfnumber(res, "typstorage"));
   12705          283 :     typcollatable = PQgetvalue(res, 0, PQfnumber(res, "typcollatable"));
   12706          283 :     if (!PQgetisnull(res, 0, PQfnumber(res, "typdefaultbin")))
   12707            0 :         typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefaultbin"));
   12708          283 :     else if (!PQgetisnull(res, 0, PQfnumber(res, "typdefault")))
   12709              :     {
   12710           42 :         typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefault"));
   12711           42 :         typdefault_is_literal = true;   /* it needs quotes */
   12712              :     }
   12713              :     else
   12714          241 :         typdefault = NULL;
   12715              : 
   12716          283 :     qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
   12717          283 :     qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
   12718              : 
   12719              :     /*
   12720              :      * The reason we include CASCADE is that the circular dependency between
   12721              :      * the type and its I/O functions makes it impossible to drop the type any
   12722              :      * other way.
   12723              :      */
   12724          283 :     appendPQExpBuffer(delq, "DROP TYPE %s CASCADE;\n", qualtypname);
   12725              : 
   12726              :     /*
   12727              :      * We might already have a shell type, but setting pg_type_oid is
   12728              :      * harmless, and in any case we'd better set the array type OID.
   12729              :      */
   12730          283 :     if (dopt->binary_upgrade)
   12731            8 :         binary_upgrade_set_type_oids_by_type_oid(fout, q,
   12732            8 :                                                  tyinfo->dobj.catId.oid,
   12733              :                                                  false, false);
   12734              : 
   12735          283 :     appendPQExpBuffer(q,
   12736              :                       "CREATE TYPE %s (\n"
   12737              :                       "    INTERNALLENGTH = %s",
   12738              :                       qualtypname,
   12739          283 :                       (strcmp(typlen, "-1") == 0) ? "variable" : typlen);
   12740              : 
   12741              :     /* regproc result is sufficiently quoted already */
   12742          283 :     appendPQExpBuffer(q, ",\n    INPUT = %s", typinput);
   12743          283 :     appendPQExpBuffer(q, ",\n    OUTPUT = %s", typoutput);
   12744          283 :     if (OidIsValid(typreceiveoid))
   12745          210 :         appendPQExpBuffer(q, ",\n    RECEIVE = %s", typreceive);
   12746          283 :     if (OidIsValid(typsendoid))
   12747          210 :         appendPQExpBuffer(q, ",\n    SEND = %s", typsend);
   12748          283 :     if (OidIsValid(typmodinoid))
   12749           35 :         appendPQExpBuffer(q, ",\n    TYPMOD_IN = %s", typmodin);
   12750          283 :     if (OidIsValid(typmodoutoid))
   12751           35 :         appendPQExpBuffer(q, ",\n    TYPMOD_OUT = %s", typmodout);
   12752          283 :     if (OidIsValid(typanalyzeoid))
   12753            3 :         appendPQExpBuffer(q, ",\n    ANALYZE = %s", typanalyze);
   12754              : 
   12755          283 :     if (strcmp(typcollatable, "t") == 0)
   12756           30 :         appendPQExpBufferStr(q, ",\n    COLLATABLE = true");
   12757              : 
   12758          283 :     if (typdefault != NULL)
   12759              :     {
   12760           42 :         appendPQExpBufferStr(q, ",\n    DEFAULT = ");
   12761           42 :         if (typdefault_is_literal)
   12762           42 :             appendStringLiteralAH(q, typdefault, fout);
   12763              :         else
   12764            0 :             appendPQExpBufferStr(q, typdefault);
   12765              :     }
   12766              : 
   12767          283 :     if (OidIsValid(typsubscriptoid))
   12768           29 :         appendPQExpBuffer(q, ",\n    SUBSCRIPT = %s", typsubscript);
   12769              : 
   12770          283 :     if (OidIsValid(tyinfo->typelem))
   12771           26 :         appendPQExpBuffer(q, ",\n    ELEMENT = %s",
   12772           26 :                           getFormattedTypeName(fout, tyinfo->typelem,
   12773              :                                                zeroIsError));
   12774              : 
   12775          283 :     if (strcmp(typcategory, "U") != 0)
   12776              :     {
   12777          161 :         appendPQExpBufferStr(q, ",\n    CATEGORY = ");
   12778          161 :         appendStringLiteralAH(q, typcategory, fout);
   12779              :     }
   12780              : 
   12781          283 :     if (strcmp(typispreferred, "t") == 0)
   12782           29 :         appendPQExpBufferStr(q, ",\n    PREFERRED = true");
   12783              : 
   12784          283 :     if (typdelim && strcmp(typdelim, ",") != 0)
   12785              :     {
   12786            3 :         appendPQExpBufferStr(q, ",\n    DELIMITER = ");
   12787            3 :         appendStringLiteralAH(q, typdelim, fout);
   12788              :     }
   12789              : 
   12790          283 :     if (*typalign == TYPALIGN_CHAR)
   12791           12 :         appendPQExpBufferStr(q, ",\n    ALIGNMENT = char");
   12792          271 :     else if (*typalign == TYPALIGN_SHORT)
   12793            6 :         appendPQExpBufferStr(q, ",\n    ALIGNMENT = int2");
   12794          265 :     else if (*typalign == TYPALIGN_INT)
   12795          187 :         appendPQExpBufferStr(q, ",\n    ALIGNMENT = int4");
   12796           78 :     else if (*typalign == TYPALIGN_DOUBLE)
   12797           78 :         appendPQExpBufferStr(q, ",\n    ALIGNMENT = double");
   12798              : 
   12799          283 :     if (*typstorage == TYPSTORAGE_PLAIN)
   12800          208 :         appendPQExpBufferStr(q, ",\n    STORAGE = plain");
   12801           75 :     else if (*typstorage == TYPSTORAGE_EXTERNAL)
   12802            0 :         appendPQExpBufferStr(q, ",\n    STORAGE = external");
   12803           75 :     else if (*typstorage == TYPSTORAGE_EXTENDED)
   12804           66 :         appendPQExpBufferStr(q, ",\n    STORAGE = extended");
   12805            9 :     else if (*typstorage == TYPSTORAGE_MAIN)
   12806            9 :         appendPQExpBufferStr(q, ",\n    STORAGE = main");
   12807              : 
   12808          283 :     if (strcmp(typbyval, "t") == 0)
   12809          137 :         appendPQExpBufferStr(q, ",\n    PASSEDBYVALUE");
   12810              : 
   12811          283 :     appendPQExpBufferStr(q, "\n);\n");
   12812              : 
   12813          283 :     if (dopt->binary_upgrade)
   12814            8 :         binary_upgrade_extension_member(q, &tyinfo->dobj,
   12815              :                                         "TYPE", qtypname,
   12816            8 :                                         tyinfo->dobj.namespace->dobj.name);
   12817              : 
   12818          283 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   12819          283 :         ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
   12820          283 :                      ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
   12821              :                                   .namespace = tyinfo->dobj.namespace->dobj.name,
   12822              :                                   .owner = tyinfo->rolname,
   12823              :                                   .description = "TYPE",
   12824              :                                   .section = SECTION_PRE_DATA,
   12825              :                                   .createStmt = q->data,
   12826              :                                   .dropStmt = delq->data));
   12827              : 
   12828              :     /* Dump Type Comments and Security Labels */
   12829          283 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   12830          248 :         dumpComment(fout, "TYPE", qtypname,
   12831          248 :                     tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
   12832          248 :                     tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
   12833              : 
   12834          283 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
   12835            0 :         dumpSecLabel(fout, "TYPE", qtypname,
   12836            0 :                      tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
   12837            0 :                      tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
   12838              : 
   12839          283 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
   12840           32 :         dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
   12841              :                 qtypname, NULL,
   12842           32 :                 tyinfo->dobj.namespace->dobj.name,
   12843           32 :                 NULL, tyinfo->rolname, &tyinfo->dacl);
   12844              : 
   12845          283 :     PQclear(res);
   12846          283 :     destroyPQExpBuffer(q);
   12847          283 :     destroyPQExpBuffer(delq);
   12848          283 :     destroyPQExpBuffer(query);
   12849          283 :     free(qtypname);
   12850          283 :     free(qualtypname);
   12851          283 : }
   12852              : 
   12853              : /*
   12854              :  * dumpDomain
   12855              :  *    writes out to fout the queries to recreate a user-defined domain
   12856              :  */
   12857              : static void
   12858          172 : dumpDomain(Archive *fout, const TypeInfo *tyinfo)
   12859              : {
   12860          172 :     DumpOptions *dopt = fout->dopt;
   12861          172 :     PQExpBuffer q = createPQExpBuffer();
   12862          172 :     PQExpBuffer delq = createPQExpBuffer();
   12863          172 :     PQExpBuffer query = createPQExpBuffer();
   12864              :     PGresult   *res;
   12865              :     int         i;
   12866              :     char       *qtypname;
   12867              :     char       *qualtypname;
   12868              :     char       *typnotnull;
   12869              :     char       *typdefn;
   12870              :     char       *typdefault;
   12871              :     Oid         typcollation;
   12872          172 :     bool        typdefault_is_literal = false;
   12873              : 
   12874          172 :     if (!fout->is_prepared[PREPQUERY_DUMPDOMAIN])
   12875              :     {
   12876              :         /* Set up query for domain-specific details */
   12877           37 :         appendPQExpBufferStr(query,
   12878              :                              "PREPARE dumpDomain(pg_catalog.oid) AS\n");
   12879              : 
   12880           37 :         appendPQExpBufferStr(query, "SELECT t.typnotnull, "
   12881              :                              "pg_catalog.format_type(t.typbasetype, t.typtypmod) AS typdefn, "
   12882              :                              "pg_catalog.pg_get_expr(t.typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, "
   12883              :                              "t.typdefault, "
   12884              :                              "CASE WHEN t.typcollation <> u.typcollation "
   12885              :                              "THEN t.typcollation ELSE 0 END AS typcollation "
   12886              :                              "FROM pg_catalog.pg_type t "
   12887              :                              "LEFT JOIN pg_catalog.pg_type u ON (t.typbasetype = u.oid) "
   12888              :                              "WHERE t.oid = $1");
   12889              : 
   12890           37 :         ExecuteSqlStatement(fout, query->data);
   12891              : 
   12892           37 :         fout->is_prepared[PREPQUERY_DUMPDOMAIN] = true;
   12893              :     }
   12894              : 
   12895          172 :     printfPQExpBuffer(query,
   12896              :                       "EXECUTE dumpDomain('%u')",
   12897          172 :                       tyinfo->dobj.catId.oid);
   12898              : 
   12899          172 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   12900              : 
   12901          172 :     typnotnull = PQgetvalue(res, 0, PQfnumber(res, "typnotnull"));
   12902          172 :     typdefn = PQgetvalue(res, 0, PQfnumber(res, "typdefn"));
   12903          172 :     if (!PQgetisnull(res, 0, PQfnumber(res, "typdefaultbin")))
   12904           37 :         typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefaultbin"));
   12905          135 :     else if (!PQgetisnull(res, 0, PQfnumber(res, "typdefault")))
   12906              :     {
   12907            0 :         typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefault"));
   12908            0 :         typdefault_is_literal = true;   /* it needs quotes */
   12909              :     }
   12910              :     else
   12911          135 :         typdefault = NULL;
   12912          172 :     typcollation = atooid(PQgetvalue(res, 0, PQfnumber(res, "typcollation")));
   12913              : 
   12914          172 :     if (dopt->binary_upgrade)
   12915           29 :         binary_upgrade_set_type_oids_by_type_oid(fout, q,
   12916           29 :                                                  tyinfo->dobj.catId.oid,
   12917              :                                                  true,  /* force array type */
   12918              :                                                  false);    /* force multirange type */
   12919              : 
   12920          172 :     qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
   12921          172 :     qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
   12922              : 
   12923          172 :     appendPQExpBuffer(q,
   12924              :                       "CREATE DOMAIN %s AS %s",
   12925              :                       qualtypname,
   12926              :                       typdefn);
   12927              : 
   12928              :     /* Print collation only if different from base type's collation */
   12929          172 :     if (OidIsValid(typcollation))
   12930              :     {
   12931              :         CollInfo   *coll;
   12932              : 
   12933           32 :         coll = findCollationByOid(typcollation);
   12934           32 :         if (coll)
   12935           32 :             appendPQExpBuffer(q, " COLLATE %s", fmtQualifiedDumpable(coll));
   12936              :     }
   12937              : 
   12938              :     /*
   12939              :      * Print a not-null constraint if there's one.  In servers older than 17
   12940              :      * these don't have names, so just print it unadorned; in newer ones they
   12941              :      * do, but most of the time it's going to be the standard generated one,
   12942              :      * so omit the name in that case also.
   12943              :      */
   12944          172 :     if (typnotnull[0] == 't')
   12945              :     {
   12946           47 :         if (fout->remoteVersion < 170000 || tyinfo->notnull == NULL)
   12947            0 :             appendPQExpBufferStr(q, " NOT NULL");
   12948              :         else
   12949              :         {
   12950           47 :             ConstraintInfo *notnull = tyinfo->notnull;
   12951              : 
   12952           47 :             if (!notnull->separate)
   12953              :             {
   12954              :                 char       *default_name;
   12955              : 
   12956              :                 /* XXX should match ChooseConstraintName better */
   12957           47 :                 default_name = psprintf("%s_not_null", tyinfo->dobj.name);
   12958              : 
   12959           47 :                 if (strcmp(default_name, notnull->dobj.name) == 0)
   12960           15 :                     appendPQExpBufferStr(q, " NOT NULL");
   12961              :                 else
   12962           32 :                     appendPQExpBuffer(q, " CONSTRAINT %s %s",
   12963           32 :                                       fmtId(notnull->dobj.name), notnull->condef);
   12964           47 :                 free(default_name);
   12965              :             }
   12966              :         }
   12967              :     }
   12968              : 
   12969          172 :     if (typdefault != NULL)
   12970              :     {
   12971           37 :         appendPQExpBufferStr(q, " DEFAULT ");
   12972           37 :         if (typdefault_is_literal)
   12973            0 :             appendStringLiteralAH(q, typdefault, fout);
   12974              :         else
   12975           37 :             appendPQExpBufferStr(q, typdefault);
   12976              :     }
   12977              : 
   12978          172 :     PQclear(res);
   12979              : 
   12980              :     /*
   12981              :      * Add any CHECK constraints for the domain
   12982              :      */
   12983          299 :     for (i = 0; i < tyinfo->nDomChecks; i++)
   12984              :     {
   12985          127 :         ConstraintInfo *domcheck = &(tyinfo->domChecks[i]);
   12986              : 
   12987          127 :         if (!domcheck->separate && domcheck->contype == 'c')
   12988          122 :             appendPQExpBuffer(q, "\n\tCONSTRAINT %s %s",
   12989          122 :                               fmtId(domcheck->dobj.name), domcheck->condef);
   12990              :     }
   12991              : 
   12992          172 :     appendPQExpBufferStr(q, ";\n");
   12993              : 
   12994          172 :     appendPQExpBuffer(delq, "DROP DOMAIN %s;\n", qualtypname);
   12995              : 
   12996          172 :     if (dopt->binary_upgrade)
   12997           29 :         binary_upgrade_extension_member(q, &tyinfo->dobj,
   12998              :                                         "DOMAIN", qtypname,
   12999           29 :                                         tyinfo->dobj.namespace->dobj.name);
   13000              : 
   13001          172 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   13002          172 :         ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
   13003          172 :                      ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
   13004              :                                   .namespace = tyinfo->dobj.namespace->dobj.name,
   13005              :                                   .owner = tyinfo->rolname,
   13006              :                                   .description = "DOMAIN",
   13007              :                                   .section = SECTION_PRE_DATA,
   13008              :                                   .createStmt = q->data,
   13009              :                                   .dropStmt = delq->data));
   13010              : 
   13011              :     /* Dump Domain Comments and Security Labels */
   13012          172 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   13013            0 :         dumpComment(fout, "DOMAIN", qtypname,
   13014            0 :                     tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
   13015            0 :                     tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
   13016              : 
   13017          172 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
   13018            0 :         dumpSecLabel(fout, "DOMAIN", qtypname,
   13019            0 :                      tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
   13020            0 :                      tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
   13021              : 
   13022          172 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
   13023           32 :         dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
   13024              :                 qtypname, NULL,
   13025           32 :                 tyinfo->dobj.namespace->dobj.name,
   13026           32 :                 NULL, tyinfo->rolname, &tyinfo->dacl);
   13027              : 
   13028              :     /* Dump any per-constraint comments */
   13029          299 :     for (i = 0; i < tyinfo->nDomChecks; i++)
   13030              :     {
   13031          127 :         ConstraintInfo *domcheck = &(tyinfo->domChecks[i]);
   13032              :         PQExpBuffer conprefix;
   13033              : 
   13034              :         /* but only if the constraint itself was dumped here */
   13035          127 :         if (domcheck->separate)
   13036            5 :             continue;
   13037              : 
   13038          122 :         conprefix = createPQExpBuffer();
   13039          122 :         appendPQExpBuffer(conprefix, "CONSTRAINT %s ON DOMAIN",
   13040          122 :                           fmtId(domcheck->dobj.name));
   13041              : 
   13042          122 :         if (domcheck->dobj.dump & DUMP_COMPONENT_COMMENT)
   13043           32 :             dumpComment(fout, conprefix->data, qtypname,
   13044           32 :                         tyinfo->dobj.namespace->dobj.name,
   13045           32 :                         tyinfo->rolname,
   13046           32 :                         domcheck->dobj.catId, 0, tyinfo->dobj.dumpId);
   13047              : 
   13048          122 :         destroyPQExpBuffer(conprefix);
   13049              :     }
   13050              : 
   13051              :     /*
   13052              :      * And a comment on the not-null constraint, if there's one -- but only if
   13053              :      * the constraint itself was dumped here
   13054              :      */
   13055          172 :     if (tyinfo->notnull != NULL && !tyinfo->notnull->separate)
   13056              :     {
   13057           47 :         PQExpBuffer conprefix = createPQExpBuffer();
   13058              : 
   13059           47 :         appendPQExpBuffer(conprefix, "CONSTRAINT %s ON DOMAIN",
   13060           47 :                           fmtId(tyinfo->notnull->dobj.name));
   13061              : 
   13062           47 :         if (tyinfo->notnull->dobj.dump & DUMP_COMPONENT_COMMENT)
   13063           32 :             dumpComment(fout, conprefix->data, qtypname,
   13064           32 :                         tyinfo->dobj.namespace->dobj.name,
   13065           32 :                         tyinfo->rolname,
   13066           32 :                         tyinfo->notnull->dobj.catId, 0, tyinfo->dobj.dumpId);
   13067           47 :         destroyPQExpBuffer(conprefix);
   13068              :     }
   13069              : 
   13070          172 :     destroyPQExpBuffer(q);
   13071          172 :     destroyPQExpBuffer(delq);
   13072          172 :     destroyPQExpBuffer(query);
   13073          172 :     free(qtypname);
   13074          172 :     free(qualtypname);
   13075          172 : }
   13076              : 
   13077              : /*
   13078              :  * dumpCompositeType
   13079              :  *    writes out to fout the queries to recreate a user-defined stand-alone
   13080              :  *    composite type
   13081              :  */
   13082              : static void
   13083          130 : dumpCompositeType(Archive *fout, const TypeInfo *tyinfo)
   13084              : {
   13085          130 :     DumpOptions *dopt = fout->dopt;
   13086          130 :     PQExpBuffer q = createPQExpBuffer();
   13087          130 :     PQExpBuffer dropped = createPQExpBuffer();
   13088          130 :     PQExpBuffer delq = createPQExpBuffer();
   13089          130 :     PQExpBuffer query = createPQExpBuffer();
   13090              :     PGresult   *res;
   13091              :     char       *qtypname;
   13092              :     char       *qualtypname;
   13093              :     int         ntups;
   13094              :     int         i_attname;
   13095              :     int         i_atttypdefn;
   13096              :     int         i_attlen;
   13097              :     int         i_attalign;
   13098              :     int         i_attisdropped;
   13099              :     int         i_attcollation;
   13100              :     int         i;
   13101              :     int         actual_atts;
   13102              : 
   13103          130 :     if (!fout->is_prepared[PREPQUERY_DUMPCOMPOSITETYPE])
   13104              :     {
   13105              :         /*
   13106              :          * Set up query for type-specific details.
   13107              :          *
   13108              :          * Since we only want to dump COLLATE clauses for attributes whose
   13109              :          * collation is different from their type's default, we use a CASE
   13110              :          * here to suppress uninteresting attcollations cheaply.  atttypid
   13111              :          * will be 0 for dropped columns; collation does not matter for those.
   13112              :          */
   13113           55 :         appendPQExpBufferStr(query,
   13114              :                              "PREPARE dumpCompositeType(pg_catalog.oid) AS\n"
   13115              :                              "SELECT a.attname, a.attnum, "
   13116              :                              "pg_catalog.format_type(a.atttypid, a.atttypmod) AS atttypdefn, "
   13117              :                              "a.attlen, a.attalign, a.attisdropped, "
   13118              :                              "CASE WHEN a.attcollation <> at.typcollation "
   13119              :                              "THEN a.attcollation ELSE 0 END AS attcollation "
   13120              :                              "FROM pg_catalog.pg_type ct "
   13121              :                              "JOIN pg_catalog.pg_attribute a ON a.attrelid = ct.typrelid "
   13122              :                              "LEFT JOIN pg_catalog.pg_type at ON at.oid = a.atttypid "
   13123              :                              "WHERE ct.oid = $1 "
   13124              :                              "ORDER BY a.attnum");
   13125              : 
   13126           55 :         ExecuteSqlStatement(fout, query->data);
   13127              : 
   13128           55 :         fout->is_prepared[PREPQUERY_DUMPCOMPOSITETYPE] = true;
   13129              :     }
   13130              : 
   13131          130 :     printfPQExpBuffer(query,
   13132              :                       "EXECUTE dumpCompositeType('%u')",
   13133          130 :                       tyinfo->dobj.catId.oid);
   13134              : 
   13135          130 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   13136              : 
   13137          130 :     ntups = PQntuples(res);
   13138              : 
   13139          130 :     i_attname = PQfnumber(res, "attname");
   13140          130 :     i_atttypdefn = PQfnumber(res, "atttypdefn");
   13141          130 :     i_attlen = PQfnumber(res, "attlen");
   13142          130 :     i_attalign = PQfnumber(res, "attalign");
   13143          130 :     i_attisdropped = PQfnumber(res, "attisdropped");
   13144          130 :     i_attcollation = PQfnumber(res, "attcollation");
   13145              : 
   13146          130 :     if (dopt->binary_upgrade)
   13147              :     {
   13148           18 :         binary_upgrade_set_type_oids_by_type_oid(fout, q,
   13149           18 :                                                  tyinfo->dobj.catId.oid,
   13150              :                                                  false, false);
   13151           18 :         binary_upgrade_set_pg_class_oids(fout, q, tyinfo->typrelid);
   13152              :     }
   13153              : 
   13154          130 :     qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
   13155          130 :     qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
   13156              : 
   13157          130 :     appendPQExpBuffer(q, "CREATE TYPE %s AS (",
   13158              :                       qualtypname);
   13159              : 
   13160          130 :     actual_atts = 0;
   13161          412 :     for (i = 0; i < ntups; i++)
   13162              :     {
   13163              :         char       *attname;
   13164              :         char       *atttypdefn;
   13165              :         char       *attlen;
   13166              :         char       *attalign;
   13167              :         bool        attisdropped;
   13168              :         Oid         attcollation;
   13169              : 
   13170          282 :         attname = PQgetvalue(res, i, i_attname);
   13171          282 :         atttypdefn = PQgetvalue(res, i, i_atttypdefn);
   13172          282 :         attlen = PQgetvalue(res, i, i_attlen);
   13173          282 :         attalign = PQgetvalue(res, i, i_attalign);
   13174          282 :         attisdropped = (PQgetvalue(res, i, i_attisdropped)[0] == 't');
   13175          282 :         attcollation = atooid(PQgetvalue(res, i, i_attcollation));
   13176              : 
   13177          282 :         if (attisdropped && !dopt->binary_upgrade)
   13178            8 :             continue;
   13179              : 
   13180              :         /* Format properly if not first attr */
   13181          274 :         if (actual_atts++ > 0)
   13182          144 :             appendPQExpBufferChar(q, ',');
   13183          274 :         appendPQExpBufferStr(q, "\n\t");
   13184              : 
   13185          274 :         if (!attisdropped)
   13186              :         {
   13187          272 :             appendPQExpBuffer(q, "%s %s", fmtId(attname), atttypdefn);
   13188              : 
   13189              :             /* Add collation if not default for the column type */
   13190          272 :             if (OidIsValid(attcollation))
   13191              :             {
   13192              :                 CollInfo   *coll;
   13193              : 
   13194            0 :                 coll = findCollationByOid(attcollation);
   13195            0 :                 if (coll)
   13196            0 :                     appendPQExpBuffer(q, " COLLATE %s",
   13197            0 :                                       fmtQualifiedDumpable(coll));
   13198              :             }
   13199              :         }
   13200              :         else
   13201              :         {
   13202              :             /*
   13203              :              * This is a dropped attribute and we're in binary_upgrade mode.
   13204              :              * Insert a placeholder for it in the CREATE TYPE command, and set
   13205              :              * length and alignment with direct UPDATE to the catalogs
   13206              :              * afterwards. See similar code in dumpTableSchema().
   13207              :              */
   13208            2 :             appendPQExpBuffer(q, "%s INTEGER /* dummy */", fmtId(attname));
   13209              : 
   13210              :             /* stash separately for insertion after the CREATE TYPE */
   13211            2 :             appendPQExpBufferStr(dropped,
   13212              :                                  "\n-- For binary upgrade, recreate dropped column.\n");
   13213            2 :             appendPQExpBuffer(dropped, "UPDATE pg_catalog.pg_attribute\n"
   13214              :                               "SET attlen = %s, "
   13215              :                               "attalign = '%s', attbyval = false\n"
   13216              :                               "WHERE attname = ", attlen, attalign);
   13217            2 :             appendStringLiteralAH(dropped, attname, fout);
   13218            2 :             appendPQExpBufferStr(dropped, "\n  AND attrelid = ");
   13219            2 :             appendStringLiteralAH(dropped, qualtypname, fout);
   13220            2 :             appendPQExpBufferStr(dropped, "::pg_catalog.regclass;\n");
   13221              : 
   13222            2 :             appendPQExpBuffer(dropped, "ALTER TYPE %s ",
   13223              :                               qualtypname);
   13224            2 :             appendPQExpBuffer(dropped, "DROP ATTRIBUTE %s;\n",
   13225              :                               fmtId(attname));
   13226              :         }
   13227              :     }
   13228          130 :     appendPQExpBufferStr(q, "\n);\n");
   13229          130 :     appendPQExpBufferStr(q, dropped->data);
   13230              : 
   13231          130 :     appendPQExpBuffer(delq, "DROP TYPE %s;\n", qualtypname);
   13232              : 
   13233          130 :     if (dopt->binary_upgrade)
   13234           18 :         binary_upgrade_extension_member(q, &tyinfo->dobj,
   13235              :                                         "TYPE", qtypname,
   13236           18 :                                         tyinfo->dobj.namespace->dobj.name);
   13237              : 
   13238          130 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   13239          113 :         ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
   13240          113 :                      ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
   13241              :                                   .namespace = tyinfo->dobj.namespace->dobj.name,
   13242              :                                   .owner = tyinfo->rolname,
   13243              :                                   .description = "TYPE",
   13244              :                                   .section = SECTION_PRE_DATA,
   13245              :                                   .createStmt = q->data,
   13246              :                                   .dropStmt = delq->data));
   13247              : 
   13248              : 
   13249              :     /* Dump Type Comments and Security Labels */
   13250          130 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   13251           32 :         dumpComment(fout, "TYPE", qtypname,
   13252           32 :                     tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
   13253           32 :                     tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
   13254              : 
   13255          130 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
   13256            0 :         dumpSecLabel(fout, "TYPE", qtypname,
   13257            0 :                      tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
   13258            0 :                      tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
   13259              : 
   13260          130 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
   13261           18 :         dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
   13262              :                 qtypname, NULL,
   13263           18 :                 tyinfo->dobj.namespace->dobj.name,
   13264           18 :                 NULL, tyinfo->rolname, &tyinfo->dacl);
   13265              : 
   13266              :     /* Dump any per-column comments */
   13267          130 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   13268           32 :         dumpCompositeTypeColComments(fout, tyinfo, res);
   13269              : 
   13270          130 :     PQclear(res);
   13271          130 :     destroyPQExpBuffer(q);
   13272          130 :     destroyPQExpBuffer(dropped);
   13273          130 :     destroyPQExpBuffer(delq);
   13274          130 :     destroyPQExpBuffer(query);
   13275          130 :     free(qtypname);
   13276          130 :     free(qualtypname);
   13277          130 : }
   13278              : 
   13279              : /*
   13280              :  * dumpCompositeTypeColComments
   13281              :  *    writes out to fout the queries to recreate comments on the columns of
   13282              :  *    a user-defined stand-alone composite type.
   13283              :  *
   13284              :  * The caller has already made a query to collect the names and attnums
   13285              :  * of the type's columns, so we just pass that result into here rather
   13286              :  * than reading them again.
   13287              :  */
   13288              : static void
   13289           32 : dumpCompositeTypeColComments(Archive *fout, const TypeInfo *tyinfo,
   13290              :                              PGresult *res)
   13291              : {
   13292              :     CommentItem *comments;
   13293              :     int         ncomments;
   13294              :     PQExpBuffer query;
   13295              :     PQExpBuffer target;
   13296              :     int         i;
   13297              :     int         ntups;
   13298              :     int         i_attname;
   13299              :     int         i_attnum;
   13300              :     int         i_attisdropped;
   13301              : 
   13302              :     /* do nothing, if --no-comments is supplied */
   13303           32 :     if (fout->dopt->no_comments)
   13304            0 :         return;
   13305              : 
   13306              :     /* Search for comments associated with type's pg_class OID */
   13307           32 :     ncomments = findComments(RelationRelationId, tyinfo->typrelid,
   13308              :                              &comments);
   13309              : 
   13310              :     /* If no comments exist, we're done */
   13311           32 :     if (ncomments <= 0)
   13312            0 :         return;
   13313              : 
   13314              :     /* Build COMMENT ON statements */
   13315           32 :     query = createPQExpBuffer();
   13316           32 :     target = createPQExpBuffer();
   13317              : 
   13318           32 :     ntups = PQntuples(res);
   13319           32 :     i_attnum = PQfnumber(res, "attnum");
   13320           32 :     i_attname = PQfnumber(res, "attname");
   13321           32 :     i_attisdropped = PQfnumber(res, "attisdropped");
   13322           64 :     while (ncomments > 0)
   13323              :     {
   13324              :         const char *attname;
   13325              : 
   13326           32 :         attname = NULL;
   13327           32 :         for (i = 0; i < ntups; i++)
   13328              :         {
   13329           32 :             if (atoi(PQgetvalue(res, i, i_attnum)) == comments->objsubid &&
   13330           32 :                 PQgetvalue(res, i, i_attisdropped)[0] != 't')
   13331              :             {
   13332           32 :                 attname = PQgetvalue(res, i, i_attname);
   13333           32 :                 break;
   13334              :             }
   13335              :         }
   13336           32 :         if (attname)            /* just in case we don't find it */
   13337              :         {
   13338           32 :             const char *descr = comments->descr;
   13339              : 
   13340           32 :             resetPQExpBuffer(target);
   13341           32 :             appendPQExpBuffer(target, "COLUMN %s.",
   13342           32 :                               fmtId(tyinfo->dobj.name));
   13343           32 :             appendPQExpBufferStr(target, fmtId(attname));
   13344              : 
   13345           32 :             resetPQExpBuffer(query);
   13346           32 :             appendPQExpBuffer(query, "COMMENT ON COLUMN %s.",
   13347           32 :                               fmtQualifiedDumpable(tyinfo));
   13348           32 :             appendPQExpBuffer(query, "%s IS ", fmtId(attname));
   13349           32 :             appendStringLiteralAH(query, descr, fout);
   13350           32 :             appendPQExpBufferStr(query, ";\n");
   13351              : 
   13352           32 :             ArchiveEntry(fout, nilCatalogId, createDumpId(),
   13353           32 :                          ARCHIVE_OPTS(.tag = target->data,
   13354              :                                       .namespace = tyinfo->dobj.namespace->dobj.name,
   13355              :                                       .owner = tyinfo->rolname,
   13356              :                                       .description = "COMMENT",
   13357              :                                       .section = SECTION_NONE,
   13358              :                                       .createStmt = query->data,
   13359              :                                       .deps = &(tyinfo->dobj.dumpId),
   13360              :                                       .nDeps = 1));
   13361              :         }
   13362              : 
   13363           32 :         comments++;
   13364           32 :         ncomments--;
   13365              :     }
   13366              : 
   13367           32 :     destroyPQExpBuffer(query);
   13368           32 :     destroyPQExpBuffer(target);
   13369              : }
   13370              : 
   13371              : /*
   13372              :  * dumpShellType
   13373              :  *    writes out to fout the queries to create a shell type
   13374              :  *
   13375              :  * We dump a shell definition in advance of the I/O functions for the type.
   13376              :  */
   13377              : static void
   13378           73 : dumpShellType(Archive *fout, const ShellTypeInfo *stinfo)
   13379              : {
   13380           73 :     DumpOptions *dopt = fout->dopt;
   13381              :     PQExpBuffer q;
   13382              : 
   13383              :     /* Do nothing if not dumping schema */
   13384           73 :     if (!dopt->dumpSchema)
   13385            6 :         return;
   13386              : 
   13387           67 :     q = createPQExpBuffer();
   13388              : 
   13389              :     /*
   13390              :      * Note the lack of a DROP command for the shell type; any required DROP
   13391              :      * is driven off the base type entry, instead.  This interacts with
   13392              :      * _printTocEntry()'s use of the presence of a DROP command to decide
   13393              :      * whether an entry needs an ALTER OWNER command.  We don't want to alter
   13394              :      * the shell type's owner immediately on creation; that should happen only
   13395              :      * after it's filled in, otherwise the backend complains.
   13396              :      */
   13397              : 
   13398           67 :     if (dopt->binary_upgrade)
   13399            8 :         binary_upgrade_set_type_oids_by_type_oid(fout, q,
   13400            8 :                                                  stinfo->baseType->dobj.catId.oid,
   13401              :                                                  false, false);
   13402              : 
   13403           67 :     appendPQExpBuffer(q, "CREATE TYPE %s;\n",
   13404           67 :                       fmtQualifiedDumpable(stinfo));
   13405              : 
   13406           67 :     if (stinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   13407           67 :         ArchiveEntry(fout, stinfo->dobj.catId, stinfo->dobj.dumpId,
   13408           67 :                      ARCHIVE_OPTS(.tag = stinfo->dobj.name,
   13409              :                                   .namespace = stinfo->dobj.namespace->dobj.name,
   13410              :                                   .owner = stinfo->baseType->rolname,
   13411              :                                   .description = "SHELL TYPE",
   13412              :                                   .section = SECTION_PRE_DATA,
   13413              :                                   .createStmt = q->data));
   13414              : 
   13415           67 :     destroyPQExpBuffer(q);
   13416              : }
   13417              : 
   13418              : /*
   13419              :  * dumpProcLang
   13420              :  *        writes out to fout the queries to recreate a user-defined
   13421              :  *        procedural language
   13422              :  */
   13423              : static void
   13424           82 : dumpProcLang(Archive *fout, const ProcLangInfo *plang)
   13425              : {
   13426           82 :     DumpOptions *dopt = fout->dopt;
   13427              :     PQExpBuffer defqry;
   13428              :     PQExpBuffer delqry;
   13429              :     bool        useParams;
   13430              :     char       *qlanname;
   13431              :     FuncInfo   *funcInfo;
   13432           82 :     FuncInfo   *inlineInfo = NULL;
   13433           82 :     FuncInfo   *validatorInfo = NULL;
   13434              : 
   13435              :     /* Do nothing if not dumping schema */
   13436           82 :     if (!dopt->dumpSchema)
   13437           13 :         return;
   13438              : 
   13439              :     /*
   13440              :      * Try to find the support function(s).  It is not an error if we don't
   13441              :      * find them --- if the functions are in the pg_catalog schema, as is
   13442              :      * standard in 8.1 and up, then we won't have loaded them. (In this case
   13443              :      * we will emit a parameterless CREATE LANGUAGE command, which will
   13444              :      * require PL template knowledge in the backend to reload.)
   13445              :      */
   13446              : 
   13447           69 :     funcInfo = findFuncByOid(plang->lanplcallfoid);
   13448           69 :     if (funcInfo != NULL && !funcInfo->dobj.dump)
   13449            2 :         funcInfo = NULL;        /* treat not-dumped same as not-found */
   13450              : 
   13451           69 :     if (OidIsValid(plang->laninline))
   13452              :     {
   13453           38 :         inlineInfo = findFuncByOid(plang->laninline);
   13454           38 :         if (inlineInfo != NULL && !inlineInfo->dobj.dump)
   13455            1 :             inlineInfo = NULL;
   13456              :     }
   13457              : 
   13458           69 :     if (OidIsValid(plang->lanvalidator))
   13459              :     {
   13460           38 :         validatorInfo = findFuncByOid(plang->lanvalidator);
   13461           38 :         if (validatorInfo != NULL && !validatorInfo->dobj.dump)
   13462            1 :             validatorInfo = NULL;
   13463              :     }
   13464              : 
   13465              :     /*
   13466              :      * If the functions are dumpable then emit a complete CREATE LANGUAGE with
   13467              :      * parameters.  Otherwise, we'll write a parameterless command, which will
   13468              :      * be interpreted as CREATE EXTENSION.
   13469              :      */
   13470           30 :     useParams = (funcInfo != NULL &&
   13471          129 :                  (inlineInfo != NULL || !OidIsValid(plang->laninline)) &&
   13472           30 :                  (validatorInfo != NULL || !OidIsValid(plang->lanvalidator)));
   13473              : 
   13474           69 :     defqry = createPQExpBuffer();
   13475           69 :     delqry = createPQExpBuffer();
   13476              : 
   13477           69 :     qlanname = pg_strdup(fmtId(plang->dobj.name));
   13478              : 
   13479           69 :     appendPQExpBuffer(delqry, "DROP PROCEDURAL LANGUAGE %s;\n",
   13480              :                       qlanname);
   13481              : 
   13482           69 :     if (useParams)
   13483              :     {
   13484           30 :         appendPQExpBuffer(defqry, "CREATE %sPROCEDURAL LANGUAGE %s",
   13485           30 :                           plang->lanpltrusted ? "TRUSTED " : "",
   13486              :                           qlanname);
   13487           30 :         appendPQExpBuffer(defqry, " HANDLER %s",
   13488           30 :                           fmtQualifiedDumpable(funcInfo));
   13489           30 :         if (OidIsValid(plang->laninline))
   13490            0 :             appendPQExpBuffer(defqry, " INLINE %s",
   13491            0 :                               fmtQualifiedDumpable(inlineInfo));
   13492           30 :         if (OidIsValid(plang->lanvalidator))
   13493            0 :             appendPQExpBuffer(defqry, " VALIDATOR %s",
   13494            0 :                               fmtQualifiedDumpable(validatorInfo));
   13495              :     }
   13496              :     else
   13497              :     {
   13498              :         /*
   13499              :          * If not dumping parameters, then use CREATE OR REPLACE so that the
   13500              :          * command will not fail if the language is preinstalled in the target
   13501              :          * database.
   13502              :          *
   13503              :          * Modern servers will interpret this as CREATE EXTENSION IF NOT
   13504              :          * EXISTS; perhaps we should emit that instead?  But it might just add
   13505              :          * confusion.
   13506              :          */
   13507           39 :         appendPQExpBuffer(defqry, "CREATE OR REPLACE PROCEDURAL LANGUAGE %s",
   13508              :                           qlanname);
   13509              :     }
   13510           69 :     appendPQExpBufferStr(defqry, ";\n");
   13511              : 
   13512           69 :     if (dopt->binary_upgrade)
   13513            2 :         binary_upgrade_extension_member(defqry, &plang->dobj,
   13514              :                                         "LANGUAGE", qlanname, NULL);
   13515              : 
   13516           69 :     if (plang->dobj.dump & DUMP_COMPONENT_DEFINITION)
   13517           31 :         ArchiveEntry(fout, plang->dobj.catId, plang->dobj.dumpId,
   13518           31 :                      ARCHIVE_OPTS(.tag = plang->dobj.name,
   13519              :                                   .owner = plang->lanowner,
   13520              :                                   .description = "PROCEDURAL LANGUAGE",
   13521              :                                   .section = SECTION_PRE_DATA,
   13522              :                                   .createStmt = defqry->data,
   13523              :                                   .dropStmt = delqry->data,
   13524              :                                   ));
   13525              : 
   13526              :     /* Dump Proc Lang Comments and Security Labels */
   13527           69 :     if (plang->dobj.dump & DUMP_COMPONENT_COMMENT)
   13528            0 :         dumpComment(fout, "LANGUAGE", qlanname,
   13529            0 :                     NULL, plang->lanowner,
   13530            0 :                     plang->dobj.catId, 0, plang->dobj.dumpId);
   13531              : 
   13532           69 :     if (plang->dobj.dump & DUMP_COMPONENT_SECLABEL)
   13533            0 :         dumpSecLabel(fout, "LANGUAGE", qlanname,
   13534            0 :                      NULL, plang->lanowner,
   13535            0 :                      plang->dobj.catId, 0, plang->dobj.dumpId);
   13536              : 
   13537           69 :     if (plang->lanpltrusted && plang->dobj.dump & DUMP_COMPONENT_ACL)
   13538           38 :         dumpACL(fout, plang->dobj.dumpId, InvalidDumpId, "LANGUAGE",
   13539              :                 qlanname, NULL, NULL,
   13540           38 :                 NULL, plang->lanowner, &plang->dacl);
   13541              : 
   13542           69 :     free(qlanname);
   13543              : 
   13544           69 :     destroyPQExpBuffer(defqry);
   13545           69 :     destroyPQExpBuffer(delqry);
   13546              : }
   13547              : 
   13548              : /*
   13549              :  * format_function_arguments: generate function name and argument list
   13550              :  *
   13551              :  * This is used when we can rely on pg_get_function_arguments to format
   13552              :  * the argument list.  Note, however, that pg_get_function_arguments
   13553              :  * does not special-case zero-argument aggregates.
   13554              :  */
   13555              : static char *
   13556         4242 : format_function_arguments(const FuncInfo *finfo, const char *funcargs, bool is_agg)
   13557              : {
   13558              :     PQExpBufferData fn;
   13559              : 
   13560         4242 :     initPQExpBuffer(&fn);
   13561         4242 :     appendPQExpBufferStr(&fn, fmtId(finfo->dobj.name));
   13562         4242 :     if (is_agg && finfo->nargs == 0)
   13563           80 :         appendPQExpBufferStr(&fn, "(*)");
   13564              :     else
   13565         4162 :         appendPQExpBuffer(&fn, "(%s)", funcargs);
   13566         4242 :     return fn.data;
   13567              : }
   13568              : 
   13569              : /*
   13570              :  * format_function_signature: generate function name and argument list
   13571              :  *
   13572              :  * Only a minimal list of input argument types is generated; this is
   13573              :  * sufficient to reference the function, but not to define it.
   13574              :  *
   13575              :  * If honor_quotes is false then the function name is never quoted.
   13576              :  * This is appropriate for use in TOC tags, but not in SQL commands.
   13577              :  */
   13578              : static char *
   13579         2229 : format_function_signature(Archive *fout, const FuncInfo *finfo, bool honor_quotes)
   13580              : {
   13581              :     PQExpBufferData fn;
   13582              :     int         j;
   13583              : 
   13584         2229 :     initPQExpBuffer(&fn);
   13585         2229 :     if (honor_quotes)
   13586          393 :         appendPQExpBuffer(&fn, "%s(", fmtId(finfo->dobj.name));
   13587              :     else
   13588         1836 :         appendPQExpBuffer(&fn, "%s(", finfo->dobj.name);
   13589         4100 :     for (j = 0; j < finfo->nargs; j++)
   13590              :     {
   13591         1871 :         if (j > 0)
   13592          452 :             appendPQExpBufferStr(&fn, ", ");
   13593              : 
   13594         1871 :         appendPQExpBufferStr(&fn,
   13595         1871 :                              getFormattedTypeName(fout, finfo->argtypes[j],
   13596              :                                                   zeroIsError));
   13597              :     }
   13598         2229 :     appendPQExpBufferChar(&fn, ')');
   13599         2229 :     return fn.data;
   13600              : }
   13601              : 
   13602              : 
   13603              : /*
   13604              :  * dumpFunc:
   13605              :  *    dump out one function
   13606              :  */
   13607              : static void
   13608         1898 : dumpFunc(Archive *fout, const FuncInfo *finfo)
   13609              : {
   13610         1898 :     DumpOptions *dopt = fout->dopt;
   13611              :     PQExpBuffer query;
   13612              :     PQExpBuffer q;
   13613              :     PQExpBuffer delqry;
   13614              :     PQExpBuffer asPart;
   13615              :     PGresult   *res;
   13616              :     char       *funcsig;        /* identity signature */
   13617         1898 :     char       *funcfullsig = NULL; /* full signature */
   13618              :     char       *funcsig_tag;
   13619              :     char       *qual_funcsig;
   13620              :     char       *proretset;
   13621              :     char       *prosrc;
   13622              :     char       *probin;
   13623              :     char       *prosqlbody;
   13624              :     char       *funcargs;
   13625              :     char       *funciargs;
   13626              :     char       *funcresult;
   13627              :     char       *protrftypes;
   13628              :     char       *prokind;
   13629              :     char       *provolatile;
   13630              :     char       *proisstrict;
   13631              :     char       *prosecdef;
   13632              :     char       *proleakproof;
   13633              :     char       *proconfig;
   13634              :     char       *procost;
   13635              :     char       *prorows;
   13636              :     char       *prosupport;
   13637              :     char       *proparallel;
   13638              :     char       *lanname;
   13639         1898 :     char      **configitems = NULL;
   13640         1898 :     int         nconfigitems = 0;
   13641              :     const char *keyword;
   13642              : 
   13643              :     /* Do nothing if not dumping schema */
   13644         1898 :     if (!dopt->dumpSchema)
   13645           62 :         return;
   13646              : 
   13647         1836 :     query = createPQExpBuffer();
   13648         1836 :     q = createPQExpBuffer();
   13649         1836 :     delqry = createPQExpBuffer();
   13650         1836 :     asPart = createPQExpBuffer();
   13651              : 
   13652         1836 :     if (!fout->is_prepared[PREPQUERY_DUMPFUNC])
   13653              :     {
   13654              :         /* Set up query for function-specific details */
   13655           76 :         appendPQExpBufferStr(query,
   13656              :                              "PREPARE dumpFunc(pg_catalog.oid) AS\n");
   13657              : 
   13658           76 :         appendPQExpBufferStr(query,
   13659              :                              "SELECT\n"
   13660              :                              "proretset,\n"
   13661              :                              "prosrc,\n"
   13662              :                              "probin,\n"
   13663              :                              "provolatile,\n"
   13664              :                              "proisstrict,\n"
   13665              :                              "prosecdef,\n"
   13666              :                              "lanname,\n"
   13667              :                              "proconfig,\n"
   13668              :                              "procost,\n"
   13669              :                              "prorows,\n"
   13670              :                              "pg_catalog.pg_get_function_arguments(p.oid) AS funcargs,\n"
   13671              :                              "pg_catalog.pg_get_function_identity_arguments(p.oid) AS funciargs,\n"
   13672              :                              "pg_catalog.pg_get_function_result(p.oid) AS funcresult,\n"
   13673              :                              "proleakproof,\n");
   13674              : 
   13675           76 :         if (fout->remoteVersion >= 90500)
   13676           76 :             appendPQExpBufferStr(query,
   13677              :                                  "array_to_string(protrftypes, ' ') AS protrftypes,\n");
   13678              :         else
   13679            0 :             appendPQExpBufferStr(query,
   13680              :                                  "NULL AS protrftypes,\n");
   13681              : 
   13682           76 :         if (fout->remoteVersion >= 90600)
   13683           76 :             appendPQExpBufferStr(query,
   13684              :                                  "proparallel,\n");
   13685              :         else
   13686            0 :             appendPQExpBufferStr(query,
   13687              :                                  "'u' AS proparallel,\n");
   13688              : 
   13689           76 :         if (fout->remoteVersion >= 110000)
   13690           76 :             appendPQExpBufferStr(query,
   13691              :                                  "prokind,\n");
   13692              :         else
   13693            0 :             appendPQExpBufferStr(query,
   13694              :                                  "CASE WHEN proiswindow THEN 'w' ELSE 'f' END AS prokind,\n");
   13695              : 
   13696           76 :         if (fout->remoteVersion >= 120000)
   13697           76 :             appendPQExpBufferStr(query,
   13698              :                                  "prosupport,\n");
   13699              :         else
   13700            0 :             appendPQExpBufferStr(query,
   13701              :                                  "'-' AS prosupport,\n");
   13702              : 
   13703           76 :         if (fout->remoteVersion >= 140000)
   13704           76 :             appendPQExpBufferStr(query,
   13705              :                                  "pg_get_function_sqlbody(p.oid) AS prosqlbody\n");
   13706              :         else
   13707            0 :             appendPQExpBufferStr(query,
   13708              :                                  "NULL AS prosqlbody\n");
   13709              : 
   13710           76 :         appendPQExpBufferStr(query,
   13711              :                              "FROM pg_catalog.pg_proc p, pg_catalog.pg_language l\n"
   13712              :                              "WHERE p.oid = $1 "
   13713              :                              "AND l.oid = p.prolang");
   13714              : 
   13715           76 :         ExecuteSqlStatement(fout, query->data);
   13716              : 
   13717           76 :         fout->is_prepared[PREPQUERY_DUMPFUNC] = true;
   13718              :     }
   13719              : 
   13720         1836 :     printfPQExpBuffer(query,
   13721              :                       "EXECUTE dumpFunc('%u')",
   13722         1836 :                       finfo->dobj.catId.oid);
   13723              : 
   13724         1836 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   13725              : 
   13726         1836 :     proretset = PQgetvalue(res, 0, PQfnumber(res, "proretset"));
   13727         1836 :     if (PQgetisnull(res, 0, PQfnumber(res, "prosqlbody")))
   13728              :     {
   13729         1788 :         prosrc = PQgetvalue(res, 0, PQfnumber(res, "prosrc"));
   13730         1788 :         probin = PQgetvalue(res, 0, PQfnumber(res, "probin"));
   13731         1788 :         prosqlbody = NULL;
   13732              :     }
   13733              :     else
   13734              :     {
   13735           48 :         prosrc = NULL;
   13736           48 :         probin = NULL;
   13737           48 :         prosqlbody = PQgetvalue(res, 0, PQfnumber(res, "prosqlbody"));
   13738              :     }
   13739         1836 :     funcargs = PQgetvalue(res, 0, PQfnumber(res, "funcargs"));
   13740         1836 :     funciargs = PQgetvalue(res, 0, PQfnumber(res, "funciargs"));
   13741         1836 :     funcresult = PQgetvalue(res, 0, PQfnumber(res, "funcresult"));
   13742         1836 :     protrftypes = PQgetvalue(res, 0, PQfnumber(res, "protrftypes"));
   13743         1836 :     prokind = PQgetvalue(res, 0, PQfnumber(res, "prokind"));
   13744         1836 :     provolatile = PQgetvalue(res, 0, PQfnumber(res, "provolatile"));
   13745         1836 :     proisstrict = PQgetvalue(res, 0, PQfnumber(res, "proisstrict"));
   13746         1836 :     prosecdef = PQgetvalue(res, 0, PQfnumber(res, "prosecdef"));
   13747         1836 :     proleakproof = PQgetvalue(res, 0, PQfnumber(res, "proleakproof"));
   13748         1836 :     proconfig = PQgetvalue(res, 0, PQfnumber(res, "proconfig"));
   13749         1836 :     procost = PQgetvalue(res, 0, PQfnumber(res, "procost"));
   13750         1836 :     prorows = PQgetvalue(res, 0, PQfnumber(res, "prorows"));
   13751         1836 :     prosupport = PQgetvalue(res, 0, PQfnumber(res, "prosupport"));
   13752         1836 :     proparallel = PQgetvalue(res, 0, PQfnumber(res, "proparallel"));
   13753         1836 :     lanname = PQgetvalue(res, 0, PQfnumber(res, "lanname"));
   13754              : 
   13755              :     /*
   13756              :      * See backend/commands/functioncmds.c for details of how the 'AS' clause
   13757              :      * is used.
   13758              :      */
   13759         1836 :     if (prosqlbody)
   13760              :     {
   13761           48 :         appendPQExpBufferStr(asPart, prosqlbody);
   13762              :     }
   13763         1788 :     else if (probin[0] != '\0')
   13764              :     {
   13765          158 :         appendPQExpBufferStr(asPart, "AS ");
   13766          158 :         appendStringLiteralAH(asPart, probin, fout);
   13767          158 :         if (prosrc[0] != '\0')
   13768              :         {
   13769          158 :             appendPQExpBufferStr(asPart, ", ");
   13770              : 
   13771              :             /*
   13772              :              * where we have bin, use dollar quoting if allowed and src
   13773              :              * contains quote or backslash; else use regular quoting.
   13774              :              */
   13775          158 :             if (dopt->disable_dollar_quoting ||
   13776          158 :                 (strchr(prosrc, '\'') == NULL && strchr(prosrc, '\\') == NULL))
   13777          158 :                 appendStringLiteralAH(asPart, prosrc, fout);
   13778              :             else
   13779            0 :                 appendStringLiteralDQ(asPart, prosrc, NULL);
   13780              :         }
   13781              :     }
   13782              :     else
   13783              :     {
   13784         1630 :         appendPQExpBufferStr(asPart, "AS ");
   13785              :         /* with no bin, dollar quote src unconditionally if allowed */
   13786         1630 :         if (dopt->disable_dollar_quoting)
   13787            0 :             appendStringLiteralAH(asPart, prosrc, fout);
   13788              :         else
   13789         1630 :             appendStringLiteralDQ(asPart, prosrc, NULL);
   13790              :     }
   13791              : 
   13792         1836 :     if (*proconfig)
   13793              :     {
   13794           15 :         if (!parsePGArray(proconfig, &configitems, &nconfigitems))
   13795            0 :             pg_fatal("could not parse %s array", "proconfig");
   13796              :     }
   13797              :     else
   13798              :     {
   13799         1821 :         configitems = NULL;
   13800         1821 :         nconfigitems = 0;
   13801              :     }
   13802              : 
   13803         1836 :     funcfullsig = format_function_arguments(finfo, funcargs, false);
   13804         1836 :     funcsig = format_function_arguments(finfo, funciargs, false);
   13805              : 
   13806         1836 :     funcsig_tag = format_function_signature(fout, finfo, false);
   13807              : 
   13808         1836 :     qual_funcsig = psprintf("%s.%s",
   13809         1836 :                             fmtId(finfo->dobj.namespace->dobj.name),
   13810              :                             funcsig);
   13811              : 
   13812         1836 :     if (prokind[0] == PROKIND_PROCEDURE)
   13813           92 :         keyword = "PROCEDURE";
   13814              :     else
   13815         1744 :         keyword = "FUNCTION"; /* works for window functions too */
   13816              : 
   13817         1836 :     appendPQExpBuffer(delqry, "DROP %s %s;\n",
   13818              :                       keyword, qual_funcsig);
   13819              : 
   13820         3672 :     appendPQExpBuffer(q, "CREATE %s %s.%s",
   13821              :                       keyword,
   13822         1836 :                       fmtId(finfo->dobj.namespace->dobj.name),
   13823              :                       funcfullsig ? funcfullsig :
   13824              :                       funcsig);
   13825              : 
   13826         1836 :     if (prokind[0] == PROKIND_PROCEDURE)
   13827              :          /* no result type to output */ ;
   13828         1744 :     else if (funcresult)
   13829         1744 :         appendPQExpBuffer(q, " RETURNS %s", funcresult);
   13830              :     else
   13831            0 :         appendPQExpBuffer(q, " RETURNS %s%s",
   13832            0 :                           (proretset[0] == 't') ? "SETOF " : "",
   13833            0 :                           getFormattedTypeName(fout, finfo->prorettype,
   13834              :                                                zeroIsError));
   13835              : 
   13836         1836 :     appendPQExpBuffer(q, "\n    LANGUAGE %s", fmtId(lanname));
   13837              : 
   13838         1836 :     if (*protrftypes)
   13839              :     {
   13840            0 :         Oid        *typeids = pg_malloc_array(Oid, FUNC_MAX_ARGS);
   13841              :         int         i;
   13842              : 
   13843            0 :         appendPQExpBufferStr(q, " TRANSFORM ");
   13844            0 :         parseOidArray(protrftypes, typeids, FUNC_MAX_ARGS);
   13845            0 :         for (i = 0; typeids[i]; i++)
   13846              :         {
   13847            0 :             if (i != 0)
   13848            0 :                 appendPQExpBufferStr(q, ", ");
   13849            0 :             appendPQExpBuffer(q, "FOR TYPE %s",
   13850            0 :                               getFormattedTypeName(fout, typeids[i], zeroAsNone));
   13851              :         }
   13852              : 
   13853            0 :         free(typeids);
   13854              :     }
   13855              : 
   13856         1836 :     if (prokind[0] == PROKIND_WINDOW)
   13857            5 :         appendPQExpBufferStr(q, " WINDOW");
   13858              : 
   13859         1836 :     if (provolatile[0] != PROVOLATILE_VOLATILE)
   13860              :     {
   13861          351 :         if (provolatile[0] == PROVOLATILE_IMMUTABLE)
   13862          330 :             appendPQExpBufferStr(q, " IMMUTABLE");
   13863           21 :         else if (provolatile[0] == PROVOLATILE_STABLE)
   13864           21 :             appendPQExpBufferStr(q, " STABLE");
   13865            0 :         else if (provolatile[0] != PROVOLATILE_VOLATILE)
   13866            0 :             pg_fatal("unrecognized provolatile value for function \"%s\"",
   13867              :                      finfo->dobj.name);
   13868              :     }
   13869              : 
   13870         1836 :     if (proisstrict[0] == 't')
   13871          358 :         appendPQExpBufferStr(q, " STRICT");
   13872              : 
   13873         1836 :     if (prosecdef[0] == 't')
   13874            0 :         appendPQExpBufferStr(q, " SECURITY DEFINER");
   13875              : 
   13876         1836 :     if (proleakproof[0] == 't')
   13877           10 :         appendPQExpBufferStr(q, " LEAKPROOF");
   13878              : 
   13879              :     /*
   13880              :      * COST and ROWS are emitted only if present and not default, so as not to
   13881              :      * break backwards-compatibility of the dump without need.  Keep this code
   13882              :      * in sync with the defaults in functioncmds.c.
   13883              :      */
   13884         1836 :     if (strcmp(procost, "0") != 0)
   13885              :     {
   13886         1836 :         if (strcmp(lanname, "internal") == 0 || strcmp(lanname, "c") == 0)
   13887              :         {
   13888              :             /* default cost is 1 */
   13889          387 :             if (strcmp(procost, "1") != 0)
   13890            0 :                 appendPQExpBuffer(q, " COST %s", procost);
   13891              :         }
   13892              :         else
   13893              :         {
   13894              :             /* default cost is 100 */
   13895         1449 :             if (strcmp(procost, "100") != 0)
   13896           11 :                 appendPQExpBuffer(q, " COST %s", procost);
   13897              :         }
   13898              :     }
   13899         1836 :     if (proretset[0] == 't' &&
   13900          192 :         strcmp(prorows, "0") != 0 && strcmp(prorows, "1000") != 0)
   13901            0 :         appendPQExpBuffer(q, " ROWS %s", prorows);
   13902              : 
   13903         1836 :     if (strcmp(prosupport, "-") != 0)
   13904              :     {
   13905              :         /* We rely on regprocout to provide quoting and qualification */
   13906           42 :         appendPQExpBuffer(q, " SUPPORT %s", prosupport);
   13907              :     }
   13908              : 
   13909         1836 :     if (proparallel[0] != PROPARALLEL_UNSAFE)
   13910              :     {
   13911          116 :         if (proparallel[0] == PROPARALLEL_SAFE)
   13912          111 :             appendPQExpBufferStr(q, " PARALLEL SAFE");
   13913            5 :         else if (proparallel[0] == PROPARALLEL_RESTRICTED)
   13914            5 :             appendPQExpBufferStr(q, " PARALLEL RESTRICTED");
   13915            0 :         else if (proparallel[0] != PROPARALLEL_UNSAFE)
   13916            0 :             pg_fatal("unrecognized proparallel value for function \"%s\"",
   13917              :                      finfo->dobj.name);
   13918              :     }
   13919              : 
   13920         1876 :     for (int i = 0; i < nconfigitems; i++)
   13921              :     {
   13922              :         /* we feel free to scribble on configitems[] here */
   13923           40 :         char       *configitem = configitems[i];
   13924              :         char       *pos;
   13925              : 
   13926           40 :         pos = strchr(configitem, '=');
   13927           40 :         if (pos == NULL)
   13928            0 :             continue;
   13929           40 :         *pos++ = '\0';
   13930           40 :         appendPQExpBuffer(q, "\n    SET %s TO ", fmtId(configitem));
   13931              : 
   13932              :         /*
   13933              :          * Variables that are marked GUC_LIST_QUOTE were already fully quoted
   13934              :          * by flatten_set_variable_args() before they were put into the
   13935              :          * proconfig array.  However, because the quoting rules used there
   13936              :          * aren't exactly like SQL's, we have to break the list value apart
   13937              :          * and then quote the elements as string literals.  (The elements may
   13938              :          * be double-quoted as-is, but we can't just feed them to the SQL
   13939              :          * parser; it would do the wrong thing with elements that are
   13940              :          * zero-length or longer than NAMEDATALEN.)  Also, we need a special
   13941              :          * case for empty lists.
   13942              :          *
   13943              :          * Variables that are not so marked should just be emitted as simple
   13944              :          * string literals.  If the variable is not known to
   13945              :          * variable_is_guc_list_quote(), we'll do that; this makes it unsafe
   13946              :          * to use GUC_LIST_QUOTE for extension variables.
   13947              :          */
   13948           40 :         if (variable_is_guc_list_quote(configitem))
   13949              :         {
   13950              :             char      **namelist;
   13951              :             char      **nameptr;
   13952              : 
   13953              :             /* Parse string into list of identifiers */
   13954              :             /* this shouldn't fail really */
   13955           15 :             if (SplitGUCList(pos, ',', &namelist))
   13956              :             {
   13957              :                 /* Special case: represent an empty list as NULL */
   13958           15 :                 if (*namelist == NULL)
   13959            5 :                     appendPQExpBufferStr(q, "NULL");
   13960           40 :                 for (nameptr = namelist; *nameptr; nameptr++)
   13961              :                 {
   13962           25 :                     if (nameptr != namelist)
   13963           15 :                         appendPQExpBufferStr(q, ", ");
   13964           25 :                     appendStringLiteralAH(q, *nameptr, fout);
   13965              :                 }
   13966              :             }
   13967           15 :             pg_free(namelist);
   13968              :         }
   13969              :         else
   13970           25 :             appendStringLiteralAH(q, pos, fout);
   13971              :     }
   13972              : 
   13973         1836 :     appendPQExpBuffer(q, "\n    %s;\n", asPart->data);
   13974              : 
   13975         1836 :     append_depends_on_extension(fout, q, &finfo->dobj,
   13976              :                                 "pg_catalog.pg_proc", keyword,
   13977              :                                 qual_funcsig);
   13978              : 
   13979         1836 :     if (dopt->binary_upgrade)
   13980          308 :         binary_upgrade_extension_member(q, &finfo->dobj,
   13981              :                                         keyword, funcsig,
   13982          308 :                                         finfo->dobj.namespace->dobj.name);
   13983              : 
   13984         1836 :     if (finfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   13985         1740 :         ArchiveEntry(fout, finfo->dobj.catId, finfo->dobj.dumpId,
   13986         1740 :                      ARCHIVE_OPTS(.tag = funcsig_tag,
   13987              :                                   .namespace = finfo->dobj.namespace->dobj.name,
   13988              :                                   .owner = finfo->rolname,
   13989              :                                   .description = keyword,
   13990              :                                   .section = finfo->postponed_def ?
   13991              :                                   SECTION_POST_DATA : SECTION_PRE_DATA,
   13992              :                                   .createStmt = q->data,
   13993              :                                   .dropStmt = delqry->data));
   13994              : 
   13995              :     /* Dump Function Comments and Security Labels */
   13996         1836 :     if (finfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   13997            9 :         dumpComment(fout, keyword, funcsig,
   13998            9 :                     finfo->dobj.namespace->dobj.name, finfo->rolname,
   13999            9 :                     finfo->dobj.catId, 0, finfo->dobj.dumpId);
   14000              : 
   14001         1836 :     if (finfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
   14002            0 :         dumpSecLabel(fout, keyword, funcsig,
   14003            0 :                      finfo->dobj.namespace->dobj.name, finfo->rolname,
   14004            0 :                      finfo->dobj.catId, 0, finfo->dobj.dumpId);
   14005              : 
   14006         1836 :     if (finfo->dobj.dump & DUMP_COMPONENT_ACL)
   14007          109 :         dumpACL(fout, finfo->dobj.dumpId, InvalidDumpId, keyword,
   14008              :                 funcsig, NULL,
   14009          109 :                 finfo->dobj.namespace->dobj.name,
   14010          109 :                 NULL, finfo->rolname, &finfo->dacl);
   14011              : 
   14012         1836 :     PQclear(res);
   14013              : 
   14014         1836 :     destroyPQExpBuffer(query);
   14015         1836 :     destroyPQExpBuffer(q);
   14016         1836 :     destroyPQExpBuffer(delqry);
   14017         1836 :     destroyPQExpBuffer(asPart);
   14018         1836 :     free(funcsig);
   14019         1836 :     free(funcfullsig);
   14020         1836 :     free(funcsig_tag);
   14021         1836 :     free(qual_funcsig);
   14022         1836 :     free(configitems);
   14023              : }
   14024              : 
   14025              : 
   14026              : /*
   14027              :  * Dump a user-defined cast
   14028              :  */
   14029              : static void
   14030           67 : dumpCast(Archive *fout, const CastInfo *cast)
   14031              : {
   14032           67 :     DumpOptions *dopt = fout->dopt;
   14033              :     PQExpBuffer defqry;
   14034              :     PQExpBuffer delqry;
   14035              :     PQExpBuffer labelq;
   14036              :     PQExpBuffer castargs;
   14037           67 :     FuncInfo   *funcInfo = NULL;
   14038              :     const char *sourceType;
   14039              :     const char *targetType;
   14040              : 
   14041              :     /* Do nothing if not dumping schema */
   14042           67 :     if (!dopt->dumpSchema)
   14043            6 :         return;
   14044              : 
   14045              :     /* Cannot dump if we don't have the cast function's info */
   14046           61 :     if (OidIsValid(cast->castfunc))
   14047              :     {
   14048           36 :         funcInfo = findFuncByOid(cast->castfunc);
   14049           36 :         if (funcInfo == NULL)
   14050            0 :             pg_fatal("could not find function definition for function with OID %u",
   14051              :                      cast->castfunc);
   14052              :     }
   14053              : 
   14054           61 :     defqry = createPQExpBuffer();
   14055           61 :     delqry = createPQExpBuffer();
   14056           61 :     labelq = createPQExpBuffer();
   14057           61 :     castargs = createPQExpBuffer();
   14058              : 
   14059           61 :     sourceType = getFormattedTypeName(fout, cast->castsource, zeroAsNone);
   14060           61 :     targetType = getFormattedTypeName(fout, cast->casttarget, zeroAsNone);
   14061           61 :     appendPQExpBuffer(delqry, "DROP CAST (%s AS %s);\n",
   14062              :                       sourceType, targetType);
   14063              : 
   14064           61 :     appendPQExpBuffer(defqry, "CREATE CAST (%s AS %s) ",
   14065              :                       sourceType, targetType);
   14066              : 
   14067           61 :     switch (cast->castmethod)
   14068              :     {
   14069           25 :         case COERCION_METHOD_BINARY:
   14070           25 :             appendPQExpBufferStr(defqry, "WITHOUT FUNCTION");
   14071           25 :             break;
   14072            0 :         case COERCION_METHOD_INOUT:
   14073            0 :             appendPQExpBufferStr(defqry, "WITH INOUT");
   14074            0 :             break;
   14075           36 :         case COERCION_METHOD_FUNCTION:
   14076           36 :             if (funcInfo)
   14077              :             {
   14078           36 :                 char       *fsig = format_function_signature(fout, funcInfo, true);
   14079              : 
   14080              :                 /*
   14081              :                  * Always qualify the function name (format_function_signature
   14082              :                  * won't qualify it).
   14083              :                  */
   14084           36 :                 appendPQExpBuffer(defqry, "WITH FUNCTION %s.%s",
   14085           36 :                                   fmtId(funcInfo->dobj.namespace->dobj.name), fsig);
   14086           36 :                 free(fsig);
   14087              :             }
   14088              :             else
   14089            0 :                 pg_log_warning("bogus value in pg_cast.castfunc or pg_cast.castmethod field");
   14090           36 :             break;
   14091            0 :         default:
   14092            0 :             pg_log_warning("bogus value in pg_cast.castmethod field");
   14093              :     }
   14094              : 
   14095           61 :     if (cast->castcontext == 'a')
   14096           31 :         appendPQExpBufferStr(defqry, " AS ASSIGNMENT");
   14097           30 :     else if (cast->castcontext == 'i')
   14098           10 :         appendPQExpBufferStr(defqry, " AS IMPLICIT");
   14099           61 :     appendPQExpBufferStr(defqry, ";\n");
   14100              : 
   14101           61 :     appendPQExpBuffer(labelq, "CAST (%s AS %s)",
   14102              :                       sourceType, targetType);
   14103              : 
   14104           61 :     appendPQExpBuffer(castargs, "(%s AS %s)",
   14105              :                       sourceType, targetType);
   14106              : 
   14107           61 :     if (dopt->binary_upgrade)
   14108            7 :         binary_upgrade_extension_member(defqry, &cast->dobj,
   14109            7 :                                         "CAST", castargs->data, NULL);
   14110              : 
   14111           61 :     if (cast->dobj.dump & DUMP_COMPONENT_DEFINITION)
   14112           61 :         ArchiveEntry(fout, cast->dobj.catId, cast->dobj.dumpId,
   14113           61 :                      ARCHIVE_OPTS(.tag = labelq->data,
   14114              :                                   .description = "CAST",
   14115              :                                   .section = SECTION_PRE_DATA,
   14116              :                                   .createStmt = defqry->data,
   14117              :                                   .dropStmt = delqry->data));
   14118              : 
   14119              :     /* Dump Cast Comments */
   14120           61 :     if (cast->dobj.dump & DUMP_COMPONENT_COMMENT)
   14121            0 :         dumpComment(fout, "CAST", castargs->data,
   14122              :                     NULL, "",
   14123            0 :                     cast->dobj.catId, 0, cast->dobj.dumpId);
   14124              : 
   14125           61 :     destroyPQExpBuffer(defqry);
   14126           61 :     destroyPQExpBuffer(delqry);
   14127           61 :     destroyPQExpBuffer(labelq);
   14128           61 :     destroyPQExpBuffer(castargs);
   14129              : }
   14130              : 
   14131              : /*
   14132              :  * Dump a transform
   14133              :  */
   14134              : static void
   14135           42 : dumpTransform(Archive *fout, const TransformInfo *transform)
   14136              : {
   14137           42 :     DumpOptions *dopt = fout->dopt;
   14138              :     PQExpBuffer defqry;
   14139              :     PQExpBuffer delqry;
   14140              :     PQExpBuffer labelq;
   14141              :     PQExpBuffer transformargs;
   14142           42 :     FuncInfo   *fromsqlFuncInfo = NULL;
   14143           42 :     FuncInfo   *tosqlFuncInfo = NULL;
   14144              :     char       *lanname;
   14145              :     const char *transformType;
   14146              : 
   14147              :     /* Do nothing if not dumping schema */
   14148           42 :     if (!dopt->dumpSchema)
   14149            6 :         return;
   14150              : 
   14151              :     /* Cannot dump if we don't have the transform functions' info */
   14152           36 :     if (OidIsValid(transform->trffromsql))
   14153              :     {
   14154           36 :         fromsqlFuncInfo = findFuncByOid(transform->trffromsql);
   14155           36 :         if (fromsqlFuncInfo == NULL)
   14156            0 :             pg_fatal("could not find function definition for function with OID %u",
   14157              :                      transform->trffromsql);
   14158              :     }
   14159           36 :     if (OidIsValid(transform->trftosql))
   14160              :     {
   14161           36 :         tosqlFuncInfo = findFuncByOid(transform->trftosql);
   14162           36 :         if (tosqlFuncInfo == NULL)
   14163            0 :             pg_fatal("could not find function definition for function with OID %u",
   14164              :                      transform->trftosql);
   14165              :     }
   14166              : 
   14167           36 :     defqry = createPQExpBuffer();
   14168           36 :     delqry = createPQExpBuffer();
   14169           36 :     labelq = createPQExpBuffer();
   14170           36 :     transformargs = createPQExpBuffer();
   14171              : 
   14172           36 :     lanname = get_language_name(fout, transform->trflang);
   14173           36 :     transformType = getFormattedTypeName(fout, transform->trftype, zeroAsNone);
   14174              : 
   14175           36 :     appendPQExpBuffer(delqry, "DROP TRANSFORM FOR %s LANGUAGE %s;\n",
   14176              :                       transformType, lanname);
   14177              : 
   14178           36 :     appendPQExpBuffer(defqry, "CREATE TRANSFORM FOR %s LANGUAGE %s (",
   14179              :                       transformType, lanname);
   14180              : 
   14181           36 :     if (!transform->trffromsql && !transform->trftosql)
   14182            0 :         pg_log_warning("bogus transform definition, at least one of trffromsql and trftosql should be nonzero");
   14183              : 
   14184           36 :     if (transform->trffromsql)
   14185              :     {
   14186           36 :         if (fromsqlFuncInfo)
   14187              :         {
   14188           36 :             char       *fsig = format_function_signature(fout, fromsqlFuncInfo, true);
   14189              : 
   14190              :             /*
   14191              :              * Always qualify the function name (format_function_signature
   14192              :              * won't qualify it).
   14193              :              */
   14194           36 :             appendPQExpBuffer(defqry, "FROM SQL WITH FUNCTION %s.%s",
   14195           36 :                               fmtId(fromsqlFuncInfo->dobj.namespace->dobj.name), fsig);
   14196           36 :             free(fsig);
   14197              :         }
   14198              :         else
   14199            0 :             pg_log_warning("bogus value in pg_transform.trffromsql field");
   14200              :     }
   14201              : 
   14202           36 :     if (transform->trftosql)
   14203              :     {
   14204           36 :         if (transform->trffromsql)
   14205           36 :             appendPQExpBufferStr(defqry, ", ");
   14206              : 
   14207           36 :         if (tosqlFuncInfo)
   14208              :         {
   14209           36 :             char       *fsig = format_function_signature(fout, tosqlFuncInfo, true);
   14210              : 
   14211              :             /*
   14212              :              * Always qualify the function name (format_function_signature
   14213              :              * won't qualify it).
   14214              :              */
   14215           36 :             appendPQExpBuffer(defqry, "TO SQL WITH FUNCTION %s.%s",
   14216           36 :                               fmtId(tosqlFuncInfo->dobj.namespace->dobj.name), fsig);
   14217           36 :             free(fsig);
   14218              :         }
   14219              :         else
   14220            0 :             pg_log_warning("bogus value in pg_transform.trftosql field");
   14221              :     }
   14222              : 
   14223           36 :     appendPQExpBufferStr(defqry, ");\n");
   14224              : 
   14225           36 :     appendPQExpBuffer(labelq, "TRANSFORM FOR %s LANGUAGE %s",
   14226              :                       transformType, lanname);
   14227              : 
   14228           36 :     appendPQExpBuffer(transformargs, "FOR %s LANGUAGE %s",
   14229              :                       transformType, lanname);
   14230              : 
   14231           36 :     if (dopt->binary_upgrade)
   14232            2 :         binary_upgrade_extension_member(defqry, &transform->dobj,
   14233            2 :                                         "TRANSFORM", transformargs->data, NULL);
   14234              : 
   14235           36 :     if (transform->dobj.dump & DUMP_COMPONENT_DEFINITION)
   14236           36 :         ArchiveEntry(fout, transform->dobj.catId, transform->dobj.dumpId,
   14237           36 :                      ARCHIVE_OPTS(.tag = labelq->data,
   14238              :                                   .description = "TRANSFORM",
   14239              :                                   .section = SECTION_PRE_DATA,
   14240              :                                   .createStmt = defqry->data,
   14241              :                                   .dropStmt = delqry->data,
   14242              :                                   .deps = transform->dobj.dependencies,
   14243              :                                   .nDeps = transform->dobj.nDeps));
   14244              : 
   14245              :     /* Dump Transform Comments */
   14246           36 :     if (transform->dobj.dump & DUMP_COMPONENT_COMMENT)
   14247            0 :         dumpComment(fout, "TRANSFORM", transformargs->data,
   14248              :                     NULL, "",
   14249            0 :                     transform->dobj.catId, 0, transform->dobj.dumpId);
   14250              : 
   14251           36 :     free(lanname);
   14252           36 :     destroyPQExpBuffer(defqry);
   14253           36 :     destroyPQExpBuffer(delqry);
   14254           36 :     destroyPQExpBuffer(labelq);
   14255           36 :     destroyPQExpBuffer(transformargs);
   14256              : }
   14257              : 
   14258              : 
   14259              : /*
   14260              :  * dumpOpr
   14261              :  *    write out a single operator definition
   14262              :  */
   14263              : static void
   14264         2522 : dumpOpr(Archive *fout, const OprInfo *oprinfo)
   14265              : {
   14266         2522 :     DumpOptions *dopt = fout->dopt;
   14267              :     PQExpBuffer query;
   14268              :     PQExpBuffer q;
   14269              :     PQExpBuffer delq;
   14270              :     PQExpBuffer oprid;
   14271              :     PQExpBuffer details;
   14272              :     PGresult   *res;
   14273              :     int         i_oprkind;
   14274              :     int         i_oprcode;
   14275              :     int         i_oprleft;
   14276              :     int         i_oprright;
   14277              :     int         i_oprcom;
   14278              :     int         i_oprnegate;
   14279              :     int         i_oprrest;
   14280              :     int         i_oprjoin;
   14281              :     int         i_oprcanmerge;
   14282              :     int         i_oprcanhash;
   14283              :     char       *oprkind;
   14284              :     char       *oprcode;
   14285              :     char       *oprleft;
   14286              :     char       *oprright;
   14287              :     char       *oprcom;
   14288              :     char       *oprnegate;
   14289              :     char       *oprrest;
   14290              :     char       *oprjoin;
   14291              :     char       *oprcanmerge;
   14292              :     char       *oprcanhash;
   14293              :     char       *oprregproc;
   14294              :     char       *oprref;
   14295              : 
   14296              :     /* Do nothing if not dumping schema */
   14297         2522 :     if (!dopt->dumpSchema)
   14298            6 :         return;
   14299              : 
   14300              :     /*
   14301              :      * some operators are invalid because they were the result of user
   14302              :      * defining operators before commutators exist
   14303              :      */
   14304         2516 :     if (!OidIsValid(oprinfo->oprcode))
   14305           14 :         return;
   14306              : 
   14307         2502 :     query = createPQExpBuffer();
   14308         2502 :     q = createPQExpBuffer();
   14309         2502 :     delq = createPQExpBuffer();
   14310         2502 :     oprid = createPQExpBuffer();
   14311         2502 :     details = createPQExpBuffer();
   14312              : 
   14313         2502 :     if (!fout->is_prepared[PREPQUERY_DUMPOPR])
   14314              :     {
   14315              :         /* Set up query for operator-specific details */
   14316           40 :         appendPQExpBufferStr(query,
   14317              :                              "PREPARE dumpOpr(pg_catalog.oid) AS\n"
   14318              :                              "SELECT oprkind, "
   14319              :                              "oprcode::pg_catalog.regprocedure, "
   14320              :                              "oprleft::pg_catalog.regtype, "
   14321              :                              "oprright::pg_catalog.regtype, "
   14322              :                              "oprcom, "
   14323              :                              "oprnegate, "
   14324              :                              "oprrest::pg_catalog.regprocedure, "
   14325              :                              "oprjoin::pg_catalog.regprocedure, "
   14326              :                              "oprcanmerge, oprcanhash "
   14327              :                              "FROM pg_catalog.pg_operator "
   14328              :                              "WHERE oid = $1");
   14329              : 
   14330           40 :         ExecuteSqlStatement(fout, query->data);
   14331              : 
   14332           40 :         fout->is_prepared[PREPQUERY_DUMPOPR] = true;
   14333              :     }
   14334              : 
   14335         2502 :     printfPQExpBuffer(query,
   14336              :                       "EXECUTE dumpOpr('%u')",
   14337         2502 :                       oprinfo->dobj.catId.oid);
   14338              : 
   14339         2502 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   14340              : 
   14341         2502 :     i_oprkind = PQfnumber(res, "oprkind");
   14342         2502 :     i_oprcode = PQfnumber(res, "oprcode");
   14343         2502 :     i_oprleft = PQfnumber(res, "oprleft");
   14344         2502 :     i_oprright = PQfnumber(res, "oprright");
   14345         2502 :     i_oprcom = PQfnumber(res, "oprcom");
   14346         2502 :     i_oprnegate = PQfnumber(res, "oprnegate");
   14347         2502 :     i_oprrest = PQfnumber(res, "oprrest");
   14348         2502 :     i_oprjoin = PQfnumber(res, "oprjoin");
   14349         2502 :     i_oprcanmerge = PQfnumber(res, "oprcanmerge");
   14350         2502 :     i_oprcanhash = PQfnumber(res, "oprcanhash");
   14351              : 
   14352         2502 :     oprkind = PQgetvalue(res, 0, i_oprkind);
   14353         2502 :     oprcode = PQgetvalue(res, 0, i_oprcode);
   14354         2502 :     oprleft = PQgetvalue(res, 0, i_oprleft);
   14355         2502 :     oprright = PQgetvalue(res, 0, i_oprright);
   14356         2502 :     oprcom = PQgetvalue(res, 0, i_oprcom);
   14357         2502 :     oprnegate = PQgetvalue(res, 0, i_oprnegate);
   14358         2502 :     oprrest = PQgetvalue(res, 0, i_oprrest);
   14359         2502 :     oprjoin = PQgetvalue(res, 0, i_oprjoin);
   14360         2502 :     oprcanmerge = PQgetvalue(res, 0, i_oprcanmerge);
   14361         2502 :     oprcanhash = PQgetvalue(res, 0, i_oprcanhash);
   14362              : 
   14363              :     /* In PG14 upwards postfix operator support does not exist anymore. */
   14364         2502 :     if (strcmp(oprkind, "r") == 0)
   14365            0 :         pg_log_warning("postfix operators are not supported anymore (operator \"%s\")",
   14366              :                        oprcode);
   14367              : 
   14368         2502 :     oprregproc = convertRegProcReference(oprcode);
   14369         2502 :     if (oprregproc)
   14370              :     {
   14371         2502 :         appendPQExpBuffer(details, "    FUNCTION = %s", oprregproc);
   14372         2502 :         free(oprregproc);
   14373              :     }
   14374              : 
   14375         2502 :     appendPQExpBuffer(oprid, "%s (",
   14376         2502 :                       oprinfo->dobj.name);
   14377              : 
   14378              :     /*
   14379              :      * right unary means there's a left arg and left unary means there's a
   14380              :      * right arg.  (Although the "r" case is dead code for PG14 and later,
   14381              :      * continue to support it in case we're dumping from an old server.)
   14382              :      */
   14383         2502 :     if (strcmp(oprkind, "r") == 0 ||
   14384         2502 :         strcmp(oprkind, "b") == 0)
   14385              :     {
   14386         2359 :         appendPQExpBuffer(details, ",\n    LEFTARG = %s", oprleft);
   14387         2359 :         appendPQExpBufferStr(oprid, oprleft);
   14388              :     }
   14389              :     else
   14390          143 :         appendPQExpBufferStr(oprid, "NONE");
   14391              : 
   14392         2502 :     if (strcmp(oprkind, "l") == 0 ||
   14393         2359 :         strcmp(oprkind, "b") == 0)
   14394              :     {
   14395         2502 :         appendPQExpBuffer(details, ",\n    RIGHTARG = %s", oprright);
   14396         2502 :         appendPQExpBuffer(oprid, ", %s)", oprright);
   14397              :     }
   14398              :     else
   14399            0 :         appendPQExpBufferStr(oprid, ", NONE)");
   14400              : 
   14401         2502 :     oprref = getFormattedOperatorName(oprcom);
   14402         2502 :     if (oprref)
   14403              :     {
   14404         1679 :         appendPQExpBuffer(details, ",\n    COMMUTATOR = %s", oprref);
   14405         1679 :         free(oprref);
   14406              :     }
   14407              : 
   14408         2502 :     oprref = getFormattedOperatorName(oprnegate);
   14409         2502 :     if (oprref)
   14410              :     {
   14411         1181 :         appendPQExpBuffer(details, ",\n    NEGATOR = %s", oprref);
   14412         1181 :         free(oprref);
   14413              :     }
   14414              : 
   14415         2502 :     if (strcmp(oprcanmerge, "t") == 0)
   14416          188 :         appendPQExpBufferStr(details, ",\n    MERGES");
   14417              : 
   14418         2502 :     if (strcmp(oprcanhash, "t") == 0)
   14419          141 :         appendPQExpBufferStr(details, ",\n    HASHES");
   14420              : 
   14421         2502 :     oprregproc = convertRegProcReference(oprrest);
   14422         2502 :     if (oprregproc)
   14423              :     {
   14424         1532 :         appendPQExpBuffer(details, ",\n    RESTRICT = %s", oprregproc);
   14425         1532 :         free(oprregproc);
   14426              :     }
   14427              : 
   14428         2502 :     oprregproc = convertRegProcReference(oprjoin);
   14429         2502 :     if (oprregproc)
   14430              :     {
   14431         1532 :         appendPQExpBuffer(details, ",\n    JOIN = %s", oprregproc);
   14432         1532 :         free(oprregproc);
   14433              :     }
   14434              : 
   14435         2502 :     appendPQExpBuffer(delq, "DROP OPERATOR %s.%s;\n",
   14436         2502 :                       fmtId(oprinfo->dobj.namespace->dobj.name),
   14437              :                       oprid->data);
   14438              : 
   14439         2502 :     appendPQExpBuffer(q, "CREATE OPERATOR %s.%s (\n%s\n);\n",
   14440         2502 :                       fmtId(oprinfo->dobj.namespace->dobj.name),
   14441         2502 :                       oprinfo->dobj.name, details->data);
   14442              : 
   14443         2502 :     if (dopt->binary_upgrade)
   14444           12 :         binary_upgrade_extension_member(q, &oprinfo->dobj,
   14445           12 :                                         "OPERATOR", oprid->data,
   14446           12 :                                         oprinfo->dobj.namespace->dobj.name);
   14447              : 
   14448         2502 :     if (oprinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   14449         2502 :         ArchiveEntry(fout, oprinfo->dobj.catId, oprinfo->dobj.dumpId,
   14450         2502 :                      ARCHIVE_OPTS(.tag = oprinfo->dobj.name,
   14451              :                                   .namespace = oprinfo->dobj.namespace->dobj.name,
   14452              :                                   .owner = oprinfo->rolname,
   14453              :                                   .description = "OPERATOR",
   14454              :                                   .section = SECTION_PRE_DATA,
   14455              :                                   .createStmt = q->data,
   14456              :                                   .dropStmt = delq->data));
   14457              : 
   14458              :     /* Dump Operator Comments */
   14459         2502 :     if (oprinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   14460         2415 :         dumpComment(fout, "OPERATOR", oprid->data,
   14461         2415 :                     oprinfo->dobj.namespace->dobj.name, oprinfo->rolname,
   14462         2415 :                     oprinfo->dobj.catId, 0, oprinfo->dobj.dumpId);
   14463              : 
   14464         2502 :     PQclear(res);
   14465              : 
   14466         2502 :     destroyPQExpBuffer(query);
   14467         2502 :     destroyPQExpBuffer(q);
   14468         2502 :     destroyPQExpBuffer(delq);
   14469         2502 :     destroyPQExpBuffer(oprid);
   14470         2502 :     destroyPQExpBuffer(details);
   14471              : }
   14472              : 
   14473              : /*
   14474              :  * Convert a function reference obtained from pg_operator
   14475              :  *
   14476              :  * Returns allocated string of what to print, or NULL if function references
   14477              :  * is InvalidOid. Returned string is expected to be free'd by the caller.
   14478              :  *
   14479              :  * The input is a REGPROCEDURE display; we have to strip the argument-types
   14480              :  * part.
   14481              :  */
   14482              : static char *
   14483         7506 : convertRegProcReference(const char *proc)
   14484              : {
   14485              :     char       *name;
   14486              :     char       *paren;
   14487              :     bool        inquote;
   14488              : 
   14489              :     /* In all cases "-" means a null reference */
   14490         7506 :     if (strcmp(proc, "-") == 0)
   14491         1940 :         return NULL;
   14492              : 
   14493         5566 :     name = pg_strdup(proc);
   14494              :     /* find non-double-quoted left paren */
   14495         5566 :     inquote = false;
   14496        66996 :     for (paren = name; *paren; paren++)
   14497              :     {
   14498        66996 :         if (*paren == '(' && !inquote)
   14499              :         {
   14500         5566 :             *paren = '\0';
   14501         5566 :             break;
   14502              :         }
   14503        61430 :         if (*paren == '"')
   14504           50 :             inquote = !inquote;
   14505              :     }
   14506         5566 :     return name;
   14507              : }
   14508              : 
   14509              : /*
   14510              :  * getFormattedOperatorName - retrieve the operator name for the
   14511              :  * given operator OID (presented in string form).
   14512              :  *
   14513              :  * Returns an allocated string, or NULL if the given OID is invalid.
   14514              :  * Caller is responsible for free'ing result string.
   14515              :  *
   14516              :  * What we produce has the format "OPERATOR(schema.oprname)".  This is only
   14517              :  * useful in commands where the operator's argument types can be inferred from
   14518              :  * context.  We always schema-qualify the name, though.  The predecessor to
   14519              :  * this code tried to skip the schema qualification if possible, but that led
   14520              :  * to wrong results in corner cases, such as if an operator and its negator
   14521              :  * are in different schemas.
   14522              :  */
   14523              : static char *
   14524         5289 : getFormattedOperatorName(const char *oproid)
   14525              : {
   14526              :     OprInfo    *oprInfo;
   14527              : 
   14528              :     /* In all cases "0" means a null reference */
   14529         5289 :     if (strcmp(oproid, "0") == 0)
   14530         2429 :         return NULL;
   14531              : 
   14532         2860 :     oprInfo = findOprByOid(atooid(oproid));
   14533         2860 :     if (oprInfo == NULL)
   14534              :     {
   14535            0 :         pg_log_warning("could not find operator with OID %s",
   14536              :                        oproid);
   14537            0 :         return NULL;
   14538              :     }
   14539              : 
   14540         2860 :     return psprintf("OPERATOR(%s.%s)",
   14541         2860 :                     fmtId(oprInfo->dobj.namespace->dobj.name),
   14542              :                     oprInfo->dobj.name);
   14543              : }
   14544              : 
   14545              : /*
   14546              :  * Convert a function OID obtained from pg_ts_parser or pg_ts_template
   14547              :  *
   14548              :  * It is sufficient to use REGPROC rather than REGPROCEDURE, since the
   14549              :  * argument lists of these functions are predetermined.  Note that the
   14550              :  * caller should ensure we are in the proper schema, because the results
   14551              :  * are search path dependent!
   14552              :  */
   14553              : static char *
   14554          205 : convertTSFunction(Archive *fout, Oid funcOid)
   14555              : {
   14556              :     char       *result;
   14557              :     char        query[128];
   14558              :     PGresult   *res;
   14559              : 
   14560          205 :     snprintf(query, sizeof(query),
   14561              :              "SELECT '%u'::pg_catalog.regproc", funcOid);
   14562          205 :     res = ExecuteSqlQueryForSingleRow(fout, query);
   14563              : 
   14564          205 :     result = pg_strdup(PQgetvalue(res, 0, 0));
   14565              : 
   14566          205 :     PQclear(res);
   14567              : 
   14568          205 :     return result;
   14569              : }
   14570              : 
   14571              : /*
   14572              :  * dumpAccessMethod
   14573              :  *    write out a single access method definition
   14574              :  */
   14575              : static void
   14576           80 : dumpAccessMethod(Archive *fout, const AccessMethodInfo *aminfo)
   14577              : {
   14578           80 :     DumpOptions *dopt = fout->dopt;
   14579              :     PQExpBuffer q;
   14580              :     PQExpBuffer delq;
   14581              :     char       *qamname;
   14582              : 
   14583              :     /* Do nothing if not dumping schema */
   14584           80 :     if (!dopt->dumpSchema)
   14585           12 :         return;
   14586              : 
   14587           68 :     q = createPQExpBuffer();
   14588           68 :     delq = createPQExpBuffer();
   14589              : 
   14590           68 :     qamname = pg_strdup(fmtId(aminfo->dobj.name));
   14591              : 
   14592           68 :     appendPQExpBuffer(q, "CREATE ACCESS METHOD %s ", qamname);
   14593              : 
   14594           68 :     switch (aminfo->amtype)
   14595              :     {
   14596           32 :         case AMTYPE_INDEX:
   14597           32 :             appendPQExpBufferStr(q, "TYPE INDEX ");
   14598           32 :             break;
   14599           36 :         case AMTYPE_TABLE:
   14600           36 :             appendPQExpBufferStr(q, "TYPE TABLE ");
   14601           36 :             break;
   14602            0 :         default:
   14603            0 :             pg_log_warning("invalid type \"%c\" of access method \"%s\"",
   14604              :                            aminfo->amtype, qamname);
   14605            0 :             destroyPQExpBuffer(q);
   14606            0 :             destroyPQExpBuffer(delq);
   14607            0 :             free(qamname);
   14608            0 :             return;
   14609              :     }
   14610              : 
   14611           68 :     appendPQExpBuffer(q, "HANDLER %s;\n", aminfo->amhandler);
   14612              : 
   14613           68 :     appendPQExpBuffer(delq, "DROP ACCESS METHOD %s;\n",
   14614              :                       qamname);
   14615              : 
   14616           68 :     if (dopt->binary_upgrade)
   14617            4 :         binary_upgrade_extension_member(q, &aminfo->dobj,
   14618              :                                         "ACCESS METHOD", qamname, NULL);
   14619              : 
   14620           68 :     if (aminfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   14621           68 :         ArchiveEntry(fout, aminfo->dobj.catId, aminfo->dobj.dumpId,
   14622           68 :                      ARCHIVE_OPTS(.tag = aminfo->dobj.name,
   14623              :                                   .description = "ACCESS METHOD",
   14624              :                                   .section = SECTION_PRE_DATA,
   14625              :                                   .createStmt = q->data,
   14626              :                                   .dropStmt = delq->data));
   14627              : 
   14628              :     /* Dump Access Method Comments */
   14629           68 :     if (aminfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   14630            0 :         dumpComment(fout, "ACCESS METHOD", qamname,
   14631              :                     NULL, "",
   14632            0 :                     aminfo->dobj.catId, 0, aminfo->dobj.dumpId);
   14633              : 
   14634           68 :     destroyPQExpBuffer(q);
   14635           68 :     destroyPQExpBuffer(delq);
   14636           68 :     free(qamname);
   14637              : }
   14638              : 
   14639              : /*
   14640              :  * dumpOpclass
   14641              :  *    write out a single operator class definition
   14642              :  */
   14643              : static void
   14644          666 : dumpOpclass(Archive *fout, const OpclassInfo *opcinfo)
   14645              : {
   14646          666 :     DumpOptions *dopt = fout->dopt;
   14647              :     PQExpBuffer query;
   14648              :     PQExpBuffer q;
   14649              :     PQExpBuffer delq;
   14650              :     PQExpBuffer nameusing;
   14651              :     PGresult   *res;
   14652              :     int         ntups;
   14653              :     int         i_opcintype;
   14654              :     int         i_opckeytype;
   14655              :     int         i_opcdefault;
   14656              :     int         i_opcfamily;
   14657              :     int         i_opcfamilyname;
   14658              :     int         i_opcfamilynsp;
   14659              :     int         i_amname;
   14660              :     int         i_amopstrategy;
   14661              :     int         i_amopopr;
   14662              :     int         i_sortfamily;
   14663              :     int         i_sortfamilynsp;
   14664              :     int         i_amprocnum;
   14665              :     int         i_amproc;
   14666              :     int         i_amproclefttype;
   14667              :     int         i_amprocrighttype;
   14668              :     char       *opcintype;
   14669              :     char       *opckeytype;
   14670              :     char       *opcdefault;
   14671              :     char       *opcfamily;
   14672              :     char       *opcfamilyname;
   14673              :     char       *opcfamilynsp;
   14674              :     char       *amname;
   14675              :     char       *amopstrategy;
   14676              :     char       *amopopr;
   14677              :     char       *sortfamily;
   14678              :     char       *sortfamilynsp;
   14679              :     char       *amprocnum;
   14680              :     char       *amproc;
   14681              :     char       *amproclefttype;
   14682              :     char       *amprocrighttype;
   14683              :     bool        needComma;
   14684              :     int         i;
   14685              : 
   14686              :     /* Do nothing if not dumping schema */
   14687          666 :     if (!dopt->dumpSchema)
   14688           18 :         return;
   14689              : 
   14690          648 :     query = createPQExpBuffer();
   14691          648 :     q = createPQExpBuffer();
   14692          648 :     delq = createPQExpBuffer();
   14693          648 :     nameusing = createPQExpBuffer();
   14694              : 
   14695              :     /* Get additional fields from the pg_opclass row */
   14696          648 :     appendPQExpBuffer(query, "SELECT opcintype::pg_catalog.regtype, "
   14697              :                       "opckeytype::pg_catalog.regtype, "
   14698              :                       "opcdefault, opcfamily, "
   14699              :                       "opfname AS opcfamilyname, "
   14700              :                       "nspname AS opcfamilynsp, "
   14701              :                       "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opcmethod) AS amname "
   14702              :                       "FROM pg_catalog.pg_opclass c "
   14703              :                       "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = opcfamily "
   14704              :                       "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
   14705              :                       "WHERE c.oid = '%u'::pg_catalog.oid",
   14706          648 :                       opcinfo->dobj.catId.oid);
   14707              : 
   14708          648 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   14709              : 
   14710          648 :     i_opcintype = PQfnumber(res, "opcintype");
   14711          648 :     i_opckeytype = PQfnumber(res, "opckeytype");
   14712          648 :     i_opcdefault = PQfnumber(res, "opcdefault");
   14713          648 :     i_opcfamily = PQfnumber(res, "opcfamily");
   14714          648 :     i_opcfamilyname = PQfnumber(res, "opcfamilyname");
   14715          648 :     i_opcfamilynsp = PQfnumber(res, "opcfamilynsp");
   14716          648 :     i_amname = PQfnumber(res, "amname");
   14717              : 
   14718              :     /* opcintype may still be needed after we PQclear res */
   14719          648 :     opcintype = pg_strdup(PQgetvalue(res, 0, i_opcintype));
   14720          648 :     opckeytype = PQgetvalue(res, 0, i_opckeytype);
   14721          648 :     opcdefault = PQgetvalue(res, 0, i_opcdefault);
   14722              :     /* opcfamily will still be needed after we PQclear res */
   14723          648 :     opcfamily = pg_strdup(PQgetvalue(res, 0, i_opcfamily));
   14724          648 :     opcfamilyname = PQgetvalue(res, 0, i_opcfamilyname);
   14725          648 :     opcfamilynsp = PQgetvalue(res, 0, i_opcfamilynsp);
   14726              :     /* amname will still be needed after we PQclear res */
   14727          648 :     amname = pg_strdup(PQgetvalue(res, 0, i_amname));
   14728              : 
   14729          648 :     appendPQExpBuffer(delq, "DROP OPERATOR CLASS %s",
   14730          648 :                       fmtQualifiedDumpable(opcinfo));
   14731          648 :     appendPQExpBuffer(delq, " USING %s;\n",
   14732              :                       fmtId(amname));
   14733              : 
   14734              :     /* Build the fixed portion of the CREATE command */
   14735          648 :     appendPQExpBuffer(q, "CREATE OPERATOR CLASS %s\n    ",
   14736          648 :                       fmtQualifiedDumpable(opcinfo));
   14737          648 :     if (strcmp(opcdefault, "t") == 0)
   14738          366 :         appendPQExpBufferStr(q, "DEFAULT ");
   14739          648 :     appendPQExpBuffer(q, "FOR TYPE %s USING %s",
   14740              :                       opcintype,
   14741              :                       fmtId(amname));
   14742          648 :     if (strlen(opcfamilyname) > 0)
   14743              :     {
   14744          648 :         appendPQExpBufferStr(q, " FAMILY ");
   14745          648 :         appendPQExpBuffer(q, "%s.", fmtId(opcfamilynsp));
   14746          648 :         appendPQExpBufferStr(q, fmtId(opcfamilyname));
   14747              :     }
   14748          648 :     appendPQExpBufferStr(q, " AS\n    ");
   14749              : 
   14750          648 :     needComma = false;
   14751              : 
   14752          648 :     if (strcmp(opckeytype, "-") != 0)
   14753              :     {
   14754          252 :         appendPQExpBuffer(q, "STORAGE %s",
   14755              :                           opckeytype);
   14756          252 :         needComma = true;
   14757              :     }
   14758              : 
   14759          648 :     PQclear(res);
   14760              : 
   14761              :     /*
   14762              :      * Now fetch and print the OPERATOR entries (pg_amop rows).
   14763              :      *
   14764              :      * Print only those opfamily members that are tied to the opclass by
   14765              :      * pg_depend entries.
   14766              :      */
   14767          648 :     resetPQExpBuffer(query);
   14768          648 :     appendPQExpBuffer(query, "SELECT amopstrategy, "
   14769              :                       "amopopr::pg_catalog.regoperator, "
   14770              :                       "opfname AS sortfamily, "
   14771              :                       "nspname AS sortfamilynsp "
   14772              :                       "FROM pg_catalog.pg_amop ao JOIN pg_catalog.pg_depend ON "
   14773              :                       "(classid = 'pg_catalog.pg_amop'::pg_catalog.regclass AND objid = ao.oid) "
   14774              :                       "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = amopsortfamily "
   14775              :                       "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
   14776              :                       "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
   14777              :                       "AND refobjid = '%u'::pg_catalog.oid "
   14778              :                       "AND amopfamily = '%s'::pg_catalog.oid "
   14779              :                       "ORDER BY amopstrategy",
   14780          648 :                       opcinfo->dobj.catId.oid,
   14781              :                       opcfamily);
   14782              : 
   14783          648 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   14784              : 
   14785          648 :     ntups = PQntuples(res);
   14786              : 
   14787          648 :     i_amopstrategy = PQfnumber(res, "amopstrategy");
   14788          648 :     i_amopopr = PQfnumber(res, "amopopr");
   14789          648 :     i_sortfamily = PQfnumber(res, "sortfamily");
   14790          648 :     i_sortfamilynsp = PQfnumber(res, "sortfamilynsp");
   14791              : 
   14792          850 :     for (i = 0; i < ntups; i++)
   14793              :     {
   14794          202 :         amopstrategy = PQgetvalue(res, i, i_amopstrategy);
   14795          202 :         amopopr = PQgetvalue(res, i, i_amopopr);
   14796          202 :         sortfamily = PQgetvalue(res, i, i_sortfamily);
   14797          202 :         sortfamilynsp = PQgetvalue(res, i, i_sortfamilynsp);
   14798              : 
   14799          202 :         if (needComma)
   14800          128 :             appendPQExpBufferStr(q, " ,\n    ");
   14801              : 
   14802          202 :         appendPQExpBuffer(q, "OPERATOR %s %s",
   14803              :                           amopstrategy, amopopr);
   14804              : 
   14805          202 :         if (strlen(sortfamily) > 0)
   14806              :         {
   14807            0 :             appendPQExpBufferStr(q, " FOR ORDER BY ");
   14808            0 :             appendPQExpBuffer(q, "%s.", fmtId(sortfamilynsp));
   14809            0 :             appendPQExpBufferStr(q, fmtId(sortfamily));
   14810              :         }
   14811              : 
   14812          202 :         needComma = true;
   14813              :     }
   14814              : 
   14815          648 :     PQclear(res);
   14816              : 
   14817              :     /*
   14818              :      * Now fetch and print the FUNCTION entries (pg_amproc rows).
   14819              :      *
   14820              :      * Print only those opfamily members that are tied to the opclass by
   14821              :      * pg_depend entries.
   14822              :      *
   14823              :      * We print the amproclefttype/amprocrighttype even though in most cases
   14824              :      * the backend could deduce the right values, because of the corner case
   14825              :      * of a btree sort support function for a cross-type comparison.
   14826              :      */
   14827          648 :     resetPQExpBuffer(query);
   14828              : 
   14829          648 :     appendPQExpBuffer(query, "SELECT amprocnum, "
   14830              :                       "amproc::pg_catalog.regprocedure, "
   14831              :                       "amproclefttype::pg_catalog.regtype, "
   14832              :                       "amprocrighttype::pg_catalog.regtype "
   14833              :                       "FROM pg_catalog.pg_amproc ap, pg_catalog.pg_depend "
   14834              :                       "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
   14835              :                       "AND refobjid = '%u'::pg_catalog.oid "
   14836              :                       "AND classid = 'pg_catalog.pg_amproc'::pg_catalog.regclass "
   14837              :                       "AND objid = ap.oid "
   14838              :                       "ORDER BY amprocnum",
   14839          648 :                       opcinfo->dobj.catId.oid);
   14840              : 
   14841          648 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   14842              : 
   14843          648 :     ntups = PQntuples(res);
   14844              : 
   14845          648 :     i_amprocnum = PQfnumber(res, "amprocnum");
   14846          648 :     i_amproc = PQfnumber(res, "amproc");
   14847          648 :     i_amproclefttype = PQfnumber(res, "amproclefttype");
   14848          648 :     i_amprocrighttype = PQfnumber(res, "amprocrighttype");
   14849              : 
   14850          680 :     for (i = 0; i < ntups; i++)
   14851              :     {
   14852           32 :         amprocnum = PQgetvalue(res, i, i_amprocnum);
   14853           32 :         amproc = PQgetvalue(res, i, i_amproc);
   14854           32 :         amproclefttype = PQgetvalue(res, i, i_amproclefttype);
   14855           32 :         amprocrighttype = PQgetvalue(res, i, i_amprocrighttype);
   14856              : 
   14857           32 :         if (needComma)
   14858           32 :             appendPQExpBufferStr(q, " ,\n    ");
   14859              : 
   14860           32 :         appendPQExpBuffer(q, "FUNCTION %s", amprocnum);
   14861              : 
   14862           32 :         if (*amproclefttype && *amprocrighttype)
   14863           32 :             appendPQExpBuffer(q, " (%s, %s)", amproclefttype, amprocrighttype);
   14864              : 
   14865           32 :         appendPQExpBuffer(q, " %s", amproc);
   14866              : 
   14867           32 :         needComma = true;
   14868              :     }
   14869              : 
   14870          648 :     PQclear(res);
   14871              : 
   14872              :     /*
   14873              :      * If needComma is still false it means we haven't added anything after
   14874              :      * the AS keyword.  To avoid printing broken SQL, append a dummy STORAGE
   14875              :      * clause with the same datatype.  This isn't sanctioned by the
   14876              :      * documentation, but actually DefineOpClass will treat it as a no-op.
   14877              :      */
   14878          648 :     if (!needComma)
   14879          322 :         appendPQExpBuffer(q, "STORAGE %s", opcintype);
   14880              : 
   14881          648 :     appendPQExpBufferStr(q, ";\n");
   14882              : 
   14883          648 :     appendPQExpBufferStr(nameusing, fmtId(opcinfo->dobj.name));
   14884          648 :     appendPQExpBuffer(nameusing, " USING %s",
   14885              :                       fmtId(amname));
   14886              : 
   14887          648 :     if (dopt->binary_upgrade)
   14888            6 :         binary_upgrade_extension_member(q, &opcinfo->dobj,
   14889            6 :                                         "OPERATOR CLASS", nameusing->data,
   14890            6 :                                         opcinfo->dobj.namespace->dobj.name);
   14891              : 
   14892          648 :     if (opcinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   14893          648 :         ArchiveEntry(fout, opcinfo->dobj.catId, opcinfo->dobj.dumpId,
   14894          648 :                      ARCHIVE_OPTS(.tag = opcinfo->dobj.name,
   14895              :                                   .namespace = opcinfo->dobj.namespace->dobj.name,
   14896              :                                   .owner = opcinfo->rolname,
   14897              :                                   .description = "OPERATOR CLASS",
   14898              :                                   .section = SECTION_PRE_DATA,
   14899              :                                   .createStmt = q->data,
   14900              :                                   .dropStmt = delq->data));
   14901              : 
   14902              :     /* Dump Operator Class Comments */
   14903          648 :     if (opcinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   14904            0 :         dumpComment(fout, "OPERATOR CLASS", nameusing->data,
   14905            0 :                     opcinfo->dobj.namespace->dobj.name, opcinfo->rolname,
   14906            0 :                     opcinfo->dobj.catId, 0, opcinfo->dobj.dumpId);
   14907              : 
   14908          648 :     free(opcintype);
   14909          648 :     free(opcfamily);
   14910          648 :     free(amname);
   14911          648 :     destroyPQExpBuffer(query);
   14912          648 :     destroyPQExpBuffer(q);
   14913          648 :     destroyPQExpBuffer(delq);
   14914          648 :     destroyPQExpBuffer(nameusing);
   14915              : }
   14916              : 
   14917              : /*
   14918              :  * dumpOpfamily
   14919              :  *    write out a single operator family definition
   14920              :  *
   14921              :  * Note: this also dumps any "loose" operator members that aren't bound to a
   14922              :  * specific opclass within the opfamily.
   14923              :  */
   14924              : static void
   14925          555 : dumpOpfamily(Archive *fout, const OpfamilyInfo *opfinfo)
   14926              : {
   14927          555 :     DumpOptions *dopt = fout->dopt;
   14928              :     PQExpBuffer query;
   14929              :     PQExpBuffer q;
   14930              :     PQExpBuffer delq;
   14931              :     PQExpBuffer nameusing;
   14932              :     PGresult   *res;
   14933              :     PGresult   *res_ops;
   14934              :     PGresult   *res_procs;
   14935              :     int         ntups;
   14936              :     int         i_amname;
   14937              :     int         i_amopstrategy;
   14938              :     int         i_amopopr;
   14939              :     int         i_sortfamily;
   14940              :     int         i_sortfamilynsp;
   14941              :     int         i_amprocnum;
   14942              :     int         i_amproc;
   14943              :     int         i_amproclefttype;
   14944              :     int         i_amprocrighttype;
   14945              :     char       *amname;
   14946              :     char       *amopstrategy;
   14947              :     char       *amopopr;
   14948              :     char       *sortfamily;
   14949              :     char       *sortfamilynsp;
   14950              :     char       *amprocnum;
   14951              :     char       *amproc;
   14952              :     char       *amproclefttype;
   14953              :     char       *amprocrighttype;
   14954              :     bool        needComma;
   14955              :     int         i;
   14956              : 
   14957              :     /* Do nothing if not dumping schema */
   14958          555 :     if (!dopt->dumpSchema)
   14959           12 :         return;
   14960              : 
   14961          543 :     query = createPQExpBuffer();
   14962          543 :     q = createPQExpBuffer();
   14963          543 :     delq = createPQExpBuffer();
   14964          543 :     nameusing = createPQExpBuffer();
   14965              : 
   14966              :     /*
   14967              :      * Fetch only those opfamily members that are tied directly to the
   14968              :      * opfamily by pg_depend entries.
   14969              :      */
   14970          543 :     appendPQExpBuffer(query, "SELECT amopstrategy, "
   14971              :                       "amopopr::pg_catalog.regoperator, "
   14972              :                       "opfname AS sortfamily, "
   14973              :                       "nspname AS sortfamilynsp "
   14974              :                       "FROM pg_catalog.pg_amop ao JOIN pg_catalog.pg_depend ON "
   14975              :                       "(classid = 'pg_catalog.pg_amop'::pg_catalog.regclass AND objid = ao.oid) "
   14976              :                       "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = amopsortfamily "
   14977              :                       "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
   14978              :                       "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
   14979              :                       "AND refobjid = '%u'::pg_catalog.oid "
   14980              :                       "AND amopfamily = '%u'::pg_catalog.oid "
   14981              :                       "ORDER BY amopstrategy",
   14982          543 :                       opfinfo->dobj.catId.oid,
   14983          543 :                       opfinfo->dobj.catId.oid);
   14984              : 
   14985          543 :     res_ops = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   14986              : 
   14987          543 :     resetPQExpBuffer(query);
   14988              : 
   14989          543 :     appendPQExpBuffer(query, "SELECT amprocnum, "
   14990              :                       "amproc::pg_catalog.regprocedure, "
   14991              :                       "amproclefttype::pg_catalog.regtype, "
   14992              :                       "amprocrighttype::pg_catalog.regtype "
   14993              :                       "FROM pg_catalog.pg_amproc ap, pg_catalog.pg_depend "
   14994              :                       "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
   14995              :                       "AND refobjid = '%u'::pg_catalog.oid "
   14996              :                       "AND classid = 'pg_catalog.pg_amproc'::pg_catalog.regclass "
   14997              :                       "AND objid = ap.oid "
   14998              :                       "ORDER BY amprocnum",
   14999          543 :                       opfinfo->dobj.catId.oid);
   15000              : 
   15001          543 :     res_procs = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   15002              : 
   15003              :     /* Get additional fields from the pg_opfamily row */
   15004          543 :     resetPQExpBuffer(query);
   15005              : 
   15006          543 :     appendPQExpBuffer(query, "SELECT "
   15007              :                       "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opfmethod) AS amname "
   15008              :                       "FROM pg_catalog.pg_opfamily "
   15009              :                       "WHERE oid = '%u'::pg_catalog.oid",
   15010          543 :                       opfinfo->dobj.catId.oid);
   15011              : 
   15012          543 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   15013              : 
   15014          543 :     i_amname = PQfnumber(res, "amname");
   15015              : 
   15016              :     /* amname will still be needed after we PQclear res */
   15017          543 :     amname = pg_strdup(PQgetvalue(res, 0, i_amname));
   15018              : 
   15019          543 :     appendPQExpBuffer(delq, "DROP OPERATOR FAMILY %s",
   15020          543 :                       fmtQualifiedDumpable(opfinfo));
   15021          543 :     appendPQExpBuffer(delq, " USING %s;\n",
   15022              :                       fmtId(amname));
   15023              : 
   15024              :     /* Build the fixed portion of the CREATE command */
   15025          543 :     appendPQExpBuffer(q, "CREATE OPERATOR FAMILY %s",
   15026          543 :                       fmtQualifiedDumpable(opfinfo));
   15027          543 :     appendPQExpBuffer(q, " USING %s;\n",
   15028              :                       fmtId(amname));
   15029              : 
   15030          543 :     PQclear(res);
   15031              : 
   15032              :     /* Do we need an ALTER to add loose members? */
   15033          543 :     if (PQntuples(res_ops) > 0 || PQntuples(res_procs) > 0)
   15034              :     {
   15035           47 :         appendPQExpBuffer(q, "ALTER OPERATOR FAMILY %s",
   15036           47 :                           fmtQualifiedDumpable(opfinfo));
   15037           47 :         appendPQExpBuffer(q, " USING %s ADD\n    ",
   15038              :                           fmtId(amname));
   15039              : 
   15040           47 :         needComma = false;
   15041              : 
   15042              :         /*
   15043              :          * Now fetch and print the OPERATOR entries (pg_amop rows).
   15044              :          */
   15045           47 :         ntups = PQntuples(res_ops);
   15046              : 
   15047           47 :         i_amopstrategy = PQfnumber(res_ops, "amopstrategy");
   15048           47 :         i_amopopr = PQfnumber(res_ops, "amopopr");
   15049           47 :         i_sortfamily = PQfnumber(res_ops, "sortfamily");
   15050           47 :         i_sortfamilynsp = PQfnumber(res_ops, "sortfamilynsp");
   15051              : 
   15052          207 :         for (i = 0; i < ntups; i++)
   15053              :         {
   15054          160 :             amopstrategy = PQgetvalue(res_ops, i, i_amopstrategy);
   15055          160 :             amopopr = PQgetvalue(res_ops, i, i_amopopr);
   15056          160 :             sortfamily = PQgetvalue(res_ops, i, i_sortfamily);
   15057          160 :             sortfamilynsp = PQgetvalue(res_ops, i, i_sortfamilynsp);
   15058              : 
   15059          160 :             if (needComma)
   15060          128 :                 appendPQExpBufferStr(q, " ,\n    ");
   15061              : 
   15062          160 :             appendPQExpBuffer(q, "OPERATOR %s %s",
   15063              :                               amopstrategy, amopopr);
   15064              : 
   15065          160 :             if (strlen(sortfamily) > 0)
   15066              :             {
   15067            0 :                 appendPQExpBufferStr(q, " FOR ORDER BY ");
   15068            0 :                 appendPQExpBuffer(q, "%s.", fmtId(sortfamilynsp));
   15069            0 :                 appendPQExpBufferStr(q, fmtId(sortfamily));
   15070              :             }
   15071              : 
   15072          160 :             needComma = true;
   15073              :         }
   15074              : 
   15075              :         /*
   15076              :          * Now fetch and print the FUNCTION entries (pg_amproc rows).
   15077              :          */
   15078           47 :         ntups = PQntuples(res_procs);
   15079              : 
   15080           47 :         i_amprocnum = PQfnumber(res_procs, "amprocnum");
   15081           47 :         i_amproc = PQfnumber(res_procs, "amproc");
   15082           47 :         i_amproclefttype = PQfnumber(res_procs, "amproclefttype");
   15083           47 :         i_amprocrighttype = PQfnumber(res_procs, "amprocrighttype");
   15084              : 
   15085          222 :         for (i = 0; i < ntups; i++)
   15086              :         {
   15087          175 :             amprocnum = PQgetvalue(res_procs, i, i_amprocnum);
   15088          175 :             amproc = PQgetvalue(res_procs, i, i_amproc);
   15089          175 :             amproclefttype = PQgetvalue(res_procs, i, i_amproclefttype);
   15090          175 :             amprocrighttype = PQgetvalue(res_procs, i, i_amprocrighttype);
   15091              : 
   15092          175 :             if (needComma)
   15093          160 :                 appendPQExpBufferStr(q, " ,\n    ");
   15094              : 
   15095          175 :             appendPQExpBuffer(q, "FUNCTION %s (%s, %s) %s",
   15096              :                               amprocnum, amproclefttype, amprocrighttype,
   15097              :                               amproc);
   15098              : 
   15099          175 :             needComma = true;
   15100              :         }
   15101              : 
   15102           47 :         appendPQExpBufferStr(q, ";\n");
   15103              :     }
   15104              : 
   15105          543 :     appendPQExpBufferStr(nameusing, fmtId(opfinfo->dobj.name));
   15106          543 :     appendPQExpBuffer(nameusing, " USING %s",
   15107              :                       fmtId(amname));
   15108              : 
   15109          543 :     if (dopt->binary_upgrade)
   15110            9 :         binary_upgrade_extension_member(q, &opfinfo->dobj,
   15111            9 :                                         "OPERATOR FAMILY", nameusing->data,
   15112            9 :                                         opfinfo->dobj.namespace->dobj.name);
   15113              : 
   15114          543 :     if (opfinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   15115          543 :         ArchiveEntry(fout, opfinfo->dobj.catId, opfinfo->dobj.dumpId,
   15116          543 :                      ARCHIVE_OPTS(.tag = opfinfo->dobj.name,
   15117              :                                   .namespace = opfinfo->dobj.namespace->dobj.name,
   15118              :                                   .owner = opfinfo->rolname,
   15119              :                                   .description = "OPERATOR FAMILY",
   15120              :                                   .section = SECTION_PRE_DATA,
   15121              :                                   .createStmt = q->data,
   15122              :                                   .dropStmt = delq->data));
   15123              : 
   15124              :     /* Dump Operator Family Comments */
   15125          543 :     if (opfinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   15126            0 :         dumpComment(fout, "OPERATOR FAMILY", nameusing->data,
   15127            0 :                     opfinfo->dobj.namespace->dobj.name, opfinfo->rolname,
   15128            0 :                     opfinfo->dobj.catId, 0, opfinfo->dobj.dumpId);
   15129              : 
   15130          543 :     free(amname);
   15131          543 :     PQclear(res_ops);
   15132          543 :     PQclear(res_procs);
   15133          543 :     destroyPQExpBuffer(query);
   15134          543 :     destroyPQExpBuffer(q);
   15135          543 :     destroyPQExpBuffer(delq);
   15136          543 :     destroyPQExpBuffer(nameusing);
   15137              : }
   15138              : 
   15139              : /*
   15140              :  * dumpCollation
   15141              :  *    write out a single collation definition
   15142              :  */
   15143              : static void
   15144         2729 : dumpCollation(Archive *fout, const CollInfo *collinfo)
   15145              : {
   15146         2729 :     DumpOptions *dopt = fout->dopt;
   15147              :     PQExpBuffer query;
   15148              :     PQExpBuffer q;
   15149              :     PQExpBuffer delq;
   15150              :     char       *qcollname;
   15151              :     PGresult   *res;
   15152              :     int         i_collprovider;
   15153              :     int         i_collisdeterministic;
   15154              :     int         i_collcollate;
   15155              :     int         i_collctype;
   15156              :     int         i_colllocale;
   15157              :     int         i_collicurules;
   15158              :     const char *collprovider;
   15159              :     const char *collcollate;
   15160              :     const char *collctype;
   15161              :     const char *colllocale;
   15162              :     const char *collicurules;
   15163              : 
   15164              :     /* Do nothing if not dumping schema */
   15165         2729 :     if (!dopt->dumpSchema)
   15166           12 :         return;
   15167              : 
   15168         2717 :     query = createPQExpBuffer();
   15169         2717 :     q = createPQExpBuffer();
   15170         2717 :     delq = createPQExpBuffer();
   15171              : 
   15172         2717 :     qcollname = pg_strdup(fmtId(collinfo->dobj.name));
   15173              : 
   15174              :     /* Get collation-specific details */
   15175         2717 :     appendPQExpBufferStr(query, "SELECT ");
   15176              : 
   15177         2717 :     if (fout->remoteVersion >= 100000)
   15178         2717 :         appendPQExpBufferStr(query,
   15179              :                              "collprovider, "
   15180              :                              "collversion, ");
   15181              :     else
   15182            0 :         appendPQExpBufferStr(query,
   15183              :                              "'c' AS collprovider, "
   15184              :                              "NULL AS collversion, ");
   15185              : 
   15186         2717 :     if (fout->remoteVersion >= 120000)
   15187         2717 :         appendPQExpBufferStr(query,
   15188              :                              "collisdeterministic, ");
   15189              :     else
   15190            0 :         appendPQExpBufferStr(query,
   15191              :                              "true AS collisdeterministic, ");
   15192              : 
   15193         2717 :     if (fout->remoteVersion >= 170000)
   15194         2717 :         appendPQExpBufferStr(query,
   15195              :                              "colllocale, ");
   15196            0 :     else if (fout->remoteVersion >= 150000)
   15197            0 :         appendPQExpBufferStr(query,
   15198              :                              "colliculocale AS colllocale, ");
   15199              :     else
   15200            0 :         appendPQExpBufferStr(query,
   15201              :                              "NULL AS colllocale, ");
   15202              : 
   15203         2717 :     if (fout->remoteVersion >= 160000)
   15204         2717 :         appendPQExpBufferStr(query,
   15205              :                              "collicurules, ");
   15206              :     else
   15207            0 :         appendPQExpBufferStr(query,
   15208              :                              "NULL AS collicurules, ");
   15209              : 
   15210         2717 :     appendPQExpBuffer(query,
   15211              :                       "collcollate, "
   15212              :                       "collctype "
   15213              :                       "FROM pg_catalog.pg_collation c "
   15214              :                       "WHERE c.oid = '%u'::pg_catalog.oid",
   15215         2717 :                       collinfo->dobj.catId.oid);
   15216              : 
   15217         2717 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   15218              : 
   15219         2717 :     i_collprovider = PQfnumber(res, "collprovider");
   15220         2717 :     i_collisdeterministic = PQfnumber(res, "collisdeterministic");
   15221         2717 :     i_collcollate = PQfnumber(res, "collcollate");
   15222         2717 :     i_collctype = PQfnumber(res, "collctype");
   15223         2717 :     i_colllocale = PQfnumber(res, "colllocale");
   15224         2717 :     i_collicurules = PQfnumber(res, "collicurules");
   15225              : 
   15226         2717 :     collprovider = PQgetvalue(res, 0, i_collprovider);
   15227              : 
   15228         2717 :     if (!PQgetisnull(res, 0, i_collcollate))
   15229           46 :         collcollate = PQgetvalue(res, 0, i_collcollate);
   15230              :     else
   15231         2671 :         collcollate = NULL;
   15232              : 
   15233         2717 :     if (!PQgetisnull(res, 0, i_collctype))
   15234           46 :         collctype = PQgetvalue(res, 0, i_collctype);
   15235              :     else
   15236         2671 :         collctype = NULL;
   15237              : 
   15238              :     /*
   15239              :      * Before version 15, collcollate and collctype were of type NAME and
   15240              :      * non-nullable. Treat empty strings as NULL for consistency.
   15241              :      */
   15242         2717 :     if (fout->remoteVersion < 150000)
   15243              :     {
   15244            0 :         if (collcollate[0] == '\0')
   15245            0 :             collcollate = NULL;
   15246            0 :         if (collctype[0] == '\0')
   15247            0 :             collctype = NULL;
   15248              :     }
   15249              : 
   15250         2717 :     if (!PQgetisnull(res, 0, i_colllocale))
   15251         2668 :         colllocale = PQgetvalue(res, 0, i_colllocale);
   15252              :     else
   15253           49 :         colllocale = NULL;
   15254              : 
   15255         2717 :     if (!PQgetisnull(res, 0, i_collicurules))
   15256            0 :         collicurules = PQgetvalue(res, 0, i_collicurules);
   15257              :     else
   15258         2717 :         collicurules = NULL;
   15259              : 
   15260         2717 :     appendPQExpBuffer(delq, "DROP COLLATION %s;\n",
   15261         2717 :                       fmtQualifiedDumpable(collinfo));
   15262              : 
   15263         2717 :     appendPQExpBuffer(q, "CREATE COLLATION %s (",
   15264         2717 :                       fmtQualifiedDumpable(collinfo));
   15265              : 
   15266         2717 :     appendPQExpBufferStr(q, "provider = ");
   15267         2717 :     if (collprovider[0] == 'b')
   15268           19 :         appendPQExpBufferStr(q, "builtin");
   15269         2698 :     else if (collprovider[0] == 'c')
   15270           46 :         appendPQExpBufferStr(q, "libc");
   15271         2652 :     else if (collprovider[0] == 'i')
   15272         2649 :         appendPQExpBufferStr(q, "icu");
   15273            3 :     else if (collprovider[0] == 'd')
   15274              :         /* to allow dumping pg_catalog; not accepted on input */
   15275            3 :         appendPQExpBufferStr(q, "default");
   15276              :     else
   15277            0 :         pg_fatal("unrecognized collation provider: %s",
   15278              :                  collprovider);
   15279              : 
   15280         2717 :     if (strcmp(PQgetvalue(res, 0, i_collisdeterministic), "f") == 0)
   15281            0 :         appendPQExpBufferStr(q, ", deterministic = false");
   15282              : 
   15283         2717 :     if (collprovider[0] == 'd')
   15284              :     {
   15285            3 :         if (collcollate || collctype || colllocale || collicurules)
   15286            0 :             pg_log_warning("invalid collation \"%s\"", qcollname);
   15287              : 
   15288              :         /* no locale -- the default collation cannot be reloaded anyway */
   15289              :     }
   15290         2714 :     else if (collprovider[0] == 'b')
   15291              :     {
   15292           19 :         if (collcollate || collctype || !colllocale || collicurules)
   15293            0 :             pg_log_warning("invalid collation \"%s\"", qcollname);
   15294              : 
   15295           19 :         appendPQExpBufferStr(q, ", locale = ");
   15296           19 :         appendStringLiteralAH(q, colllocale ? colllocale : "",
   15297              :                               fout);
   15298              :     }
   15299         2695 :     else if (collprovider[0] == 'i')
   15300              :     {
   15301         2649 :         if (fout->remoteVersion >= 150000)
   15302              :         {
   15303         2649 :             if (collcollate || collctype || !colllocale)
   15304            0 :                 pg_log_warning("invalid collation \"%s\"", qcollname);
   15305              : 
   15306         2649 :             appendPQExpBufferStr(q, ", locale = ");
   15307         2649 :             appendStringLiteralAH(q, colllocale ? colllocale : "",
   15308              :                                   fout);
   15309              :         }
   15310              :         else
   15311              :         {
   15312            0 :             if (!collcollate || !collctype || colllocale ||
   15313            0 :                 strcmp(collcollate, collctype) != 0)
   15314            0 :                 pg_log_warning("invalid collation \"%s\"", qcollname);
   15315              : 
   15316            0 :             appendPQExpBufferStr(q, ", locale = ");
   15317            0 :             appendStringLiteralAH(q, collcollate ? collcollate : "", fout);
   15318              :         }
   15319              : 
   15320         2649 :         if (collicurules)
   15321              :         {
   15322            0 :             appendPQExpBufferStr(q, ", rules = ");
   15323            0 :             appendStringLiteralAH(q, collicurules ? collicurules : "", fout);
   15324              :         }
   15325              :     }
   15326           46 :     else if (collprovider[0] == 'c')
   15327              :     {
   15328           46 :         if (colllocale || collicurules || !collcollate || !collctype)
   15329            0 :             pg_log_warning("invalid collation \"%s\"", qcollname);
   15330              : 
   15331           46 :         if (collcollate && collctype && strcmp(collcollate, collctype) == 0)
   15332              :         {
   15333           46 :             appendPQExpBufferStr(q, ", locale = ");
   15334           46 :             appendStringLiteralAH(q, collcollate ? collcollate : "", fout);
   15335              :         }
   15336              :         else
   15337              :         {
   15338            0 :             appendPQExpBufferStr(q, ", lc_collate = ");
   15339            0 :             appendStringLiteralAH(q, collcollate ? collcollate : "", fout);
   15340            0 :             appendPQExpBufferStr(q, ", lc_ctype = ");
   15341            0 :             appendStringLiteralAH(q, collctype ? collctype : "", fout);
   15342              :         }
   15343              :     }
   15344              :     else
   15345            0 :         pg_fatal("unrecognized collation provider: %s", collprovider);
   15346              : 
   15347              :     /*
   15348              :      * For binary upgrade, carry over the collation version.  For normal
   15349              :      * dump/restore, omit the version, so that it is computed upon restore.
   15350              :      */
   15351         2717 :     if (dopt->binary_upgrade)
   15352              :     {
   15353              :         int         i_collversion;
   15354              : 
   15355            5 :         i_collversion = PQfnumber(res, "collversion");
   15356            5 :         if (!PQgetisnull(res, 0, i_collversion))
   15357              :         {
   15358            4 :             appendPQExpBufferStr(q, ", version = ");
   15359            4 :             appendStringLiteralAH(q,
   15360              :                                   PQgetvalue(res, 0, i_collversion),
   15361              :                                   fout);
   15362              :         }
   15363              :     }
   15364              : 
   15365         2717 :     appendPQExpBufferStr(q, ");\n");
   15366              : 
   15367         2717 :     if (dopt->binary_upgrade)
   15368            5 :         binary_upgrade_extension_member(q, &collinfo->dobj,
   15369              :                                         "COLLATION", qcollname,
   15370            5 :                                         collinfo->dobj.namespace->dobj.name);
   15371              : 
   15372         2717 :     if (collinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   15373         2717 :         ArchiveEntry(fout, collinfo->dobj.catId, collinfo->dobj.dumpId,
   15374         2717 :                      ARCHIVE_OPTS(.tag = collinfo->dobj.name,
   15375              :                                   .namespace = collinfo->dobj.namespace->dobj.name,
   15376              :                                   .owner = collinfo->rolname,
   15377              :                                   .description = "COLLATION",
   15378              :                                   .section = SECTION_PRE_DATA,
   15379              :                                   .createStmt = q->data,
   15380              :                                   .dropStmt = delq->data));
   15381              : 
   15382              :     /* Dump Collation Comments */
   15383         2717 :     if (collinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   15384         2611 :         dumpComment(fout, "COLLATION", qcollname,
   15385         2611 :                     collinfo->dobj.namespace->dobj.name, collinfo->rolname,
   15386         2611 :                     collinfo->dobj.catId, 0, collinfo->dobj.dumpId);
   15387              : 
   15388         2717 :     PQclear(res);
   15389              : 
   15390         2717 :     destroyPQExpBuffer(query);
   15391         2717 :     destroyPQExpBuffer(q);
   15392         2717 :     destroyPQExpBuffer(delq);
   15393         2717 :     free(qcollname);
   15394              : }
   15395              : 
   15396              : /*
   15397              :  * dumpConversion
   15398              :  *    write out a single conversion definition
   15399              :  */
   15400              : static void
   15401          332 : dumpConversion(Archive *fout, const ConvInfo *convinfo)
   15402              : {
   15403          332 :     DumpOptions *dopt = fout->dopt;
   15404              :     PQExpBuffer query;
   15405              :     PQExpBuffer q;
   15406              :     PQExpBuffer delq;
   15407              :     char       *qconvname;
   15408              :     PGresult   *res;
   15409              :     int         i_conforencoding;
   15410              :     int         i_contoencoding;
   15411              :     int         i_conproc;
   15412              :     int         i_condefault;
   15413              :     const char *conforencoding;
   15414              :     const char *contoencoding;
   15415              :     const char *conproc;
   15416              :     bool        condefault;
   15417              : 
   15418              :     /* Do nothing if not dumping schema */
   15419          332 :     if (!dopt->dumpSchema)
   15420            6 :         return;
   15421              : 
   15422          326 :     query = createPQExpBuffer();
   15423          326 :     q = createPQExpBuffer();
   15424          326 :     delq = createPQExpBuffer();
   15425              : 
   15426          326 :     qconvname = pg_strdup(fmtId(convinfo->dobj.name));
   15427              : 
   15428              :     /* Get conversion-specific details */
   15429          326 :     appendPQExpBuffer(query, "SELECT "
   15430              :                       "pg_catalog.pg_encoding_to_char(conforencoding) AS conforencoding, "
   15431              :                       "pg_catalog.pg_encoding_to_char(contoencoding) AS contoencoding, "
   15432              :                       "conproc, condefault "
   15433              :                       "FROM pg_catalog.pg_conversion c "
   15434              :                       "WHERE c.oid = '%u'::pg_catalog.oid",
   15435          326 :                       convinfo->dobj.catId.oid);
   15436              : 
   15437          326 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   15438              : 
   15439          326 :     i_conforencoding = PQfnumber(res, "conforencoding");
   15440          326 :     i_contoencoding = PQfnumber(res, "contoencoding");
   15441          326 :     i_conproc = PQfnumber(res, "conproc");
   15442          326 :     i_condefault = PQfnumber(res, "condefault");
   15443              : 
   15444          326 :     conforencoding = PQgetvalue(res, 0, i_conforencoding);
   15445          326 :     contoencoding = PQgetvalue(res, 0, i_contoencoding);
   15446          326 :     conproc = PQgetvalue(res, 0, i_conproc);
   15447          326 :     condefault = (PQgetvalue(res, 0, i_condefault)[0] == 't');
   15448              : 
   15449          326 :     appendPQExpBuffer(delq, "DROP CONVERSION %s;\n",
   15450          326 :                       fmtQualifiedDumpable(convinfo));
   15451              : 
   15452          326 :     appendPQExpBuffer(q, "CREATE %sCONVERSION %s FOR ",
   15453              :                       (condefault) ? "DEFAULT " : "",
   15454          326 :                       fmtQualifiedDumpable(convinfo));
   15455          326 :     appendStringLiteralAH(q, conforencoding, fout);
   15456          326 :     appendPQExpBufferStr(q, " TO ");
   15457          326 :     appendStringLiteralAH(q, contoencoding, fout);
   15458              :     /* regproc output is already sufficiently quoted */
   15459          326 :     appendPQExpBuffer(q, " FROM %s;\n", conproc);
   15460              : 
   15461          326 :     if (dopt->binary_upgrade)
   15462            1 :         binary_upgrade_extension_member(q, &convinfo->dobj,
   15463              :                                         "CONVERSION", qconvname,
   15464            1 :                                         convinfo->dobj.namespace->dobj.name);
   15465              : 
   15466          326 :     if (convinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   15467          326 :         ArchiveEntry(fout, convinfo->dobj.catId, convinfo->dobj.dumpId,
   15468          326 :                      ARCHIVE_OPTS(.tag = convinfo->dobj.name,
   15469              :                                   .namespace = convinfo->dobj.namespace->dobj.name,
   15470              :                                   .owner = convinfo->rolname,
   15471              :                                   .description = "CONVERSION",
   15472              :                                   .section = SECTION_PRE_DATA,
   15473              :                                   .createStmt = q->data,
   15474              :                                   .dropStmt = delq->data));
   15475              : 
   15476              :     /* Dump Conversion Comments */
   15477          326 :     if (convinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   15478          326 :         dumpComment(fout, "CONVERSION", qconvname,
   15479          326 :                     convinfo->dobj.namespace->dobj.name, convinfo->rolname,
   15480          326 :                     convinfo->dobj.catId, 0, convinfo->dobj.dumpId);
   15481              : 
   15482          326 :     PQclear(res);
   15483              : 
   15484          326 :     destroyPQExpBuffer(query);
   15485          326 :     destroyPQExpBuffer(q);
   15486          326 :     destroyPQExpBuffer(delq);
   15487          326 :     free(qconvname);
   15488              : }
   15489              : 
   15490              : /*
   15491              :  * format_aggregate_signature: generate aggregate name and argument list
   15492              :  *
   15493              :  * The argument type names are qualified if needed.  The aggregate name
   15494              :  * is never qualified.
   15495              :  */
   15496              : static char *
   15497          285 : format_aggregate_signature(const AggInfo *agginfo, Archive *fout, bool honor_quotes)
   15498              : {
   15499              :     PQExpBufferData buf;
   15500              :     int         j;
   15501              : 
   15502          285 :     initPQExpBuffer(&buf);
   15503          285 :     if (honor_quotes)
   15504            0 :         appendPQExpBufferStr(&buf, fmtId(agginfo->aggfn.dobj.name));
   15505              :     else
   15506          285 :         appendPQExpBufferStr(&buf, agginfo->aggfn.dobj.name);
   15507              : 
   15508          285 :     if (agginfo->aggfn.nargs == 0)
   15509           40 :         appendPQExpBufferStr(&buf, "(*)");
   15510              :     else
   15511              :     {
   15512          245 :         appendPQExpBufferChar(&buf, '(');
   15513          535 :         for (j = 0; j < agginfo->aggfn.nargs; j++)
   15514          290 :             appendPQExpBuffer(&buf, "%s%s",
   15515              :                               (j > 0) ? ", " : "",
   15516              :                               getFormattedTypeName(fout,
   15517          290 :                                                    agginfo->aggfn.argtypes[j],
   15518              :                                                    zeroIsError));
   15519          245 :         appendPQExpBufferChar(&buf, ')');
   15520              :     }
   15521          285 :     return buf.data;
   15522              : }
   15523              : 
   15524              : /*
   15525              :  * dumpAgg
   15526              :  *    write out a single aggregate definition
   15527              :  */
   15528              : static void
   15529          292 : dumpAgg(Archive *fout, const AggInfo *agginfo)
   15530              : {
   15531          292 :     DumpOptions *dopt = fout->dopt;
   15532              :     PQExpBuffer query;
   15533              :     PQExpBuffer q;
   15534              :     PQExpBuffer delq;
   15535              :     PQExpBuffer details;
   15536              :     char       *aggsig;         /* identity signature */
   15537          292 :     char       *aggfullsig = NULL;  /* full signature */
   15538              :     char       *aggsig_tag;
   15539              :     PGresult   *res;
   15540              :     int         i_agginitval;
   15541              :     int         i_aggminitval;
   15542              :     const char *aggtransfn;
   15543              :     const char *aggfinalfn;
   15544              :     const char *aggcombinefn;
   15545              :     const char *aggserialfn;
   15546              :     const char *aggdeserialfn;
   15547              :     const char *aggmtransfn;
   15548              :     const char *aggminvtransfn;
   15549              :     const char *aggmfinalfn;
   15550              :     bool        aggfinalextra;
   15551              :     bool        aggmfinalextra;
   15552              :     char        aggfinalmodify;
   15553              :     char        aggmfinalmodify;
   15554              :     const char *aggsortop;
   15555              :     char       *aggsortconvop;
   15556              :     char        aggkind;
   15557              :     const char *aggtranstype;
   15558              :     const char *aggtransspace;
   15559              :     const char *aggmtranstype;
   15560              :     const char *aggmtransspace;
   15561              :     const char *agginitval;
   15562              :     const char *aggminitval;
   15563              :     const char *proparallel;
   15564              :     char        defaultfinalmodify;
   15565              : 
   15566              :     /* Do nothing if not dumping schema */
   15567          292 :     if (!dopt->dumpSchema)
   15568            7 :         return;
   15569              : 
   15570          285 :     query = createPQExpBuffer();
   15571          285 :     q = createPQExpBuffer();
   15572          285 :     delq = createPQExpBuffer();
   15573          285 :     details = createPQExpBuffer();
   15574              : 
   15575          285 :     if (!fout->is_prepared[PREPQUERY_DUMPAGG])
   15576              :     {
   15577              :         /* Set up query for aggregate-specific details */
   15578           55 :         appendPQExpBufferStr(query,
   15579              :                              "PREPARE dumpAgg(pg_catalog.oid) AS\n");
   15580              : 
   15581           55 :         appendPQExpBufferStr(query,
   15582              :                              "SELECT "
   15583              :                              "aggtransfn,\n"
   15584              :                              "aggfinalfn,\n"
   15585              :                              "aggtranstype::pg_catalog.regtype,\n"
   15586              :                              "agginitval,\n"
   15587              :                              "aggsortop,\n"
   15588              :                              "pg_catalog.pg_get_function_arguments(p.oid) AS funcargs,\n"
   15589              :                              "pg_catalog.pg_get_function_identity_arguments(p.oid) AS funciargs,\n");
   15590              : 
   15591           55 :         if (fout->remoteVersion >= 90400)
   15592           55 :             appendPQExpBufferStr(query,
   15593              :                                  "aggkind,\n"
   15594              :                                  "aggmtransfn,\n"
   15595              :                                  "aggminvtransfn,\n"
   15596              :                                  "aggmfinalfn,\n"
   15597              :                                  "aggmtranstype::pg_catalog.regtype,\n"
   15598              :                                  "aggfinalextra,\n"
   15599              :                                  "aggmfinalextra,\n"
   15600              :                                  "aggtransspace,\n"
   15601              :                                  "aggmtransspace,\n"
   15602              :                                  "aggminitval,\n");
   15603              :         else
   15604            0 :             appendPQExpBufferStr(query,
   15605              :                                  "'n' AS aggkind,\n"
   15606              :                                  "'-' AS aggmtransfn,\n"
   15607              :                                  "'-' AS aggminvtransfn,\n"
   15608              :                                  "'-' AS aggmfinalfn,\n"
   15609              :                                  "0 AS aggmtranstype,\n"
   15610              :                                  "false AS aggfinalextra,\n"
   15611              :                                  "false AS aggmfinalextra,\n"
   15612              :                                  "0 AS aggtransspace,\n"
   15613              :                                  "0 AS aggmtransspace,\n"
   15614              :                                  "NULL AS aggminitval,\n");
   15615              : 
   15616           55 :         if (fout->remoteVersion >= 90600)
   15617           55 :             appendPQExpBufferStr(query,
   15618              :                                  "aggcombinefn,\n"
   15619              :                                  "aggserialfn,\n"
   15620              :                                  "aggdeserialfn,\n"
   15621              :                                  "proparallel,\n");
   15622              :         else
   15623            0 :             appendPQExpBufferStr(query,
   15624              :                                  "'-' AS aggcombinefn,\n"
   15625              :                                  "'-' AS aggserialfn,\n"
   15626              :                                  "'-' AS aggdeserialfn,\n"
   15627              :                                  "'u' AS proparallel,\n");
   15628              : 
   15629           55 :         if (fout->remoteVersion >= 110000)
   15630           55 :             appendPQExpBufferStr(query,
   15631              :                                  "aggfinalmodify,\n"
   15632              :                                  "aggmfinalmodify\n");
   15633              :         else
   15634            0 :             appendPQExpBufferStr(query,
   15635              :                                  "'0' AS aggfinalmodify,\n"
   15636              :                                  "'0' AS aggmfinalmodify\n");
   15637              : 
   15638           55 :         appendPQExpBufferStr(query,
   15639              :                              "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
   15640              :                              "WHERE a.aggfnoid = p.oid "
   15641              :                              "AND p.oid = $1");
   15642              : 
   15643           55 :         ExecuteSqlStatement(fout, query->data);
   15644              : 
   15645           55 :         fout->is_prepared[PREPQUERY_DUMPAGG] = true;
   15646              :     }
   15647              : 
   15648          285 :     printfPQExpBuffer(query,
   15649              :                       "EXECUTE dumpAgg('%u')",
   15650          285 :                       agginfo->aggfn.dobj.catId.oid);
   15651              : 
   15652          285 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   15653              : 
   15654          285 :     i_agginitval = PQfnumber(res, "agginitval");
   15655          285 :     i_aggminitval = PQfnumber(res, "aggminitval");
   15656              : 
   15657          285 :     aggtransfn = PQgetvalue(res, 0, PQfnumber(res, "aggtransfn"));
   15658          285 :     aggfinalfn = PQgetvalue(res, 0, PQfnumber(res, "aggfinalfn"));
   15659          285 :     aggcombinefn = PQgetvalue(res, 0, PQfnumber(res, "aggcombinefn"));
   15660          285 :     aggserialfn = PQgetvalue(res, 0, PQfnumber(res, "aggserialfn"));
   15661          285 :     aggdeserialfn = PQgetvalue(res, 0, PQfnumber(res, "aggdeserialfn"));
   15662          285 :     aggmtransfn = PQgetvalue(res, 0, PQfnumber(res, "aggmtransfn"));
   15663          285 :     aggminvtransfn = PQgetvalue(res, 0, PQfnumber(res, "aggminvtransfn"));
   15664          285 :     aggmfinalfn = PQgetvalue(res, 0, PQfnumber(res, "aggmfinalfn"));
   15665          285 :     aggfinalextra = (PQgetvalue(res, 0, PQfnumber(res, "aggfinalextra"))[0] == 't');
   15666          285 :     aggmfinalextra = (PQgetvalue(res, 0, PQfnumber(res, "aggmfinalextra"))[0] == 't');
   15667          285 :     aggfinalmodify = PQgetvalue(res, 0, PQfnumber(res, "aggfinalmodify"))[0];
   15668          285 :     aggmfinalmodify = PQgetvalue(res, 0, PQfnumber(res, "aggmfinalmodify"))[0];
   15669          285 :     aggsortop = PQgetvalue(res, 0, PQfnumber(res, "aggsortop"));
   15670          285 :     aggkind = PQgetvalue(res, 0, PQfnumber(res, "aggkind"))[0];
   15671          285 :     aggtranstype = PQgetvalue(res, 0, PQfnumber(res, "aggtranstype"));
   15672          285 :     aggtransspace = PQgetvalue(res, 0, PQfnumber(res, "aggtransspace"));
   15673          285 :     aggmtranstype = PQgetvalue(res, 0, PQfnumber(res, "aggmtranstype"));
   15674          285 :     aggmtransspace = PQgetvalue(res, 0, PQfnumber(res, "aggmtransspace"));
   15675          285 :     agginitval = PQgetvalue(res, 0, i_agginitval);
   15676          285 :     aggminitval = PQgetvalue(res, 0, i_aggminitval);
   15677          285 :     proparallel = PQgetvalue(res, 0, PQfnumber(res, "proparallel"));
   15678              : 
   15679              :     {
   15680              :         char       *funcargs;
   15681              :         char       *funciargs;
   15682              : 
   15683          285 :         funcargs = PQgetvalue(res, 0, PQfnumber(res, "funcargs"));
   15684          285 :         funciargs = PQgetvalue(res, 0, PQfnumber(res, "funciargs"));
   15685          285 :         aggfullsig = format_function_arguments(&agginfo->aggfn, funcargs, true);
   15686          285 :         aggsig = format_function_arguments(&agginfo->aggfn, funciargs, true);
   15687              :     }
   15688              : 
   15689          285 :     aggsig_tag = format_aggregate_signature(agginfo, fout, false);
   15690              : 
   15691              :     /* identify default modify flag for aggkind (must match DefineAggregate) */
   15692          285 :     defaultfinalmodify = (aggkind == AGGKIND_NORMAL) ? AGGMODIFY_READ_ONLY : AGGMODIFY_READ_WRITE;
   15693              :     /* replace omitted flags for old versions */
   15694          285 :     if (aggfinalmodify == '0')
   15695            0 :         aggfinalmodify = defaultfinalmodify;
   15696          285 :     if (aggmfinalmodify == '0')
   15697            0 :         aggmfinalmodify = defaultfinalmodify;
   15698              : 
   15699              :     /* regproc and regtype output is already sufficiently quoted */
   15700          285 :     appendPQExpBuffer(details, "    SFUNC = %s,\n    STYPE = %s",
   15701              :                       aggtransfn, aggtranstype);
   15702              : 
   15703          285 :     if (strcmp(aggtransspace, "0") != 0)
   15704              :     {
   15705            5 :         appendPQExpBuffer(details, ",\n    SSPACE = %s",
   15706              :                           aggtransspace);
   15707              :     }
   15708              : 
   15709          285 :     if (!PQgetisnull(res, 0, i_agginitval))
   15710              :     {
   15711          207 :         appendPQExpBufferStr(details, ",\n    INITCOND = ");
   15712          207 :         appendStringLiteralAH(details, agginitval, fout);
   15713              :     }
   15714              : 
   15715          285 :     if (strcmp(aggfinalfn, "-") != 0)
   15716              :     {
   15717          132 :         appendPQExpBuffer(details, ",\n    FINALFUNC = %s",
   15718              :                           aggfinalfn);
   15719          132 :         if (aggfinalextra)
   15720           10 :             appendPQExpBufferStr(details, ",\n    FINALFUNC_EXTRA");
   15721          132 :         if (aggfinalmodify != defaultfinalmodify)
   15722              :         {
   15723           32 :             switch (aggfinalmodify)
   15724              :             {
   15725            0 :                 case AGGMODIFY_READ_ONLY:
   15726            0 :                     appendPQExpBufferStr(details, ",\n    FINALFUNC_MODIFY = READ_ONLY");
   15727            0 :                     break;
   15728           32 :                 case AGGMODIFY_SHAREABLE:
   15729           32 :                     appendPQExpBufferStr(details, ",\n    FINALFUNC_MODIFY = SHAREABLE");
   15730           32 :                     break;
   15731            0 :                 case AGGMODIFY_READ_WRITE:
   15732            0 :                     appendPQExpBufferStr(details, ",\n    FINALFUNC_MODIFY = READ_WRITE");
   15733            0 :                     break;
   15734            0 :                 default:
   15735            0 :                     pg_fatal("unrecognized aggfinalmodify value for aggregate \"%s\"",
   15736              :                              agginfo->aggfn.dobj.name);
   15737              :                     break;
   15738              :             }
   15739              :         }
   15740              :     }
   15741              : 
   15742          285 :     if (strcmp(aggcombinefn, "-") != 0)
   15743            0 :         appendPQExpBuffer(details, ",\n    COMBINEFUNC = %s", aggcombinefn);
   15744              : 
   15745          285 :     if (strcmp(aggserialfn, "-") != 0)
   15746            0 :         appendPQExpBuffer(details, ",\n    SERIALFUNC = %s", aggserialfn);
   15747              : 
   15748          285 :     if (strcmp(aggdeserialfn, "-") != 0)
   15749            0 :         appendPQExpBuffer(details, ",\n    DESERIALFUNC = %s", aggdeserialfn);
   15750              : 
   15751          285 :     if (strcmp(aggmtransfn, "-") != 0)
   15752              :     {
   15753           30 :         appendPQExpBuffer(details, ",\n    MSFUNC = %s,\n    MINVFUNC = %s,\n    MSTYPE = %s",
   15754              :                           aggmtransfn,
   15755              :                           aggminvtransfn,
   15756              :                           aggmtranstype);
   15757              :     }
   15758              : 
   15759          285 :     if (strcmp(aggmtransspace, "0") != 0)
   15760              :     {
   15761            0 :         appendPQExpBuffer(details, ",\n    MSSPACE = %s",
   15762              :                           aggmtransspace);
   15763              :     }
   15764              : 
   15765          285 :     if (!PQgetisnull(res, 0, i_aggminitval))
   15766              :     {
   15767           10 :         appendPQExpBufferStr(details, ",\n    MINITCOND = ");
   15768           10 :         appendStringLiteralAH(details, aggminitval, fout);
   15769              :     }
   15770              : 
   15771          285 :     if (strcmp(aggmfinalfn, "-") != 0)
   15772              :     {
   15773            0 :         appendPQExpBuffer(details, ",\n    MFINALFUNC = %s",
   15774              :                           aggmfinalfn);
   15775            0 :         if (aggmfinalextra)
   15776            0 :             appendPQExpBufferStr(details, ",\n    MFINALFUNC_EXTRA");
   15777            0 :         if (aggmfinalmodify != defaultfinalmodify)
   15778              :         {
   15779            0 :             switch (aggmfinalmodify)
   15780              :             {
   15781            0 :                 case AGGMODIFY_READ_ONLY:
   15782            0 :                     appendPQExpBufferStr(details, ",\n    MFINALFUNC_MODIFY = READ_ONLY");
   15783            0 :                     break;
   15784            0 :                 case AGGMODIFY_SHAREABLE:
   15785            0 :                     appendPQExpBufferStr(details, ",\n    MFINALFUNC_MODIFY = SHAREABLE");
   15786            0 :                     break;
   15787            0 :                 case AGGMODIFY_READ_WRITE:
   15788            0 :                     appendPQExpBufferStr(details, ",\n    MFINALFUNC_MODIFY = READ_WRITE");
   15789            0 :                     break;
   15790            0 :                 default:
   15791            0 :                     pg_fatal("unrecognized aggmfinalmodify value for aggregate \"%s\"",
   15792              :                              agginfo->aggfn.dobj.name);
   15793              :                     break;
   15794              :             }
   15795              :         }
   15796              :     }
   15797              : 
   15798          285 :     aggsortconvop = getFormattedOperatorName(aggsortop);
   15799          285 :     if (aggsortconvop)
   15800              :     {
   15801            0 :         appendPQExpBuffer(details, ",\n    SORTOP = %s",
   15802              :                           aggsortconvop);
   15803            0 :         free(aggsortconvop);
   15804              :     }
   15805              : 
   15806          285 :     if (aggkind == AGGKIND_HYPOTHETICAL)
   15807            5 :         appendPQExpBufferStr(details, ",\n    HYPOTHETICAL");
   15808              : 
   15809          285 :     if (proparallel[0] != PROPARALLEL_UNSAFE)
   15810              :     {
   15811            5 :         if (proparallel[0] == PROPARALLEL_SAFE)
   15812            5 :             appendPQExpBufferStr(details, ",\n    PARALLEL = safe");
   15813            0 :         else if (proparallel[0] == PROPARALLEL_RESTRICTED)
   15814            0 :             appendPQExpBufferStr(details, ",\n    PARALLEL = restricted");
   15815            0 :         else if (proparallel[0] != PROPARALLEL_UNSAFE)
   15816            0 :             pg_fatal("unrecognized proparallel value for function \"%s\"",
   15817              :                      agginfo->aggfn.dobj.name);
   15818              :     }
   15819              : 
   15820          285 :     appendPQExpBuffer(delq, "DROP AGGREGATE %s.%s;\n",
   15821          285 :                       fmtId(agginfo->aggfn.dobj.namespace->dobj.name),
   15822              :                       aggsig);
   15823              : 
   15824          570 :     appendPQExpBuffer(q, "CREATE AGGREGATE %s.%s (\n%s\n);\n",
   15825          285 :                       fmtId(agginfo->aggfn.dobj.namespace->dobj.name),
   15826              :                       aggfullsig ? aggfullsig : aggsig, details->data);
   15827              : 
   15828          285 :     if (dopt->binary_upgrade)
   15829           49 :         binary_upgrade_extension_member(q, &agginfo->aggfn.dobj,
   15830              :                                         "AGGREGATE", aggsig,
   15831           49 :                                         agginfo->aggfn.dobj.namespace->dobj.name);
   15832              : 
   15833          285 :     if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_DEFINITION)
   15834          268 :         ArchiveEntry(fout, agginfo->aggfn.dobj.catId,
   15835          268 :                      agginfo->aggfn.dobj.dumpId,
   15836          268 :                      ARCHIVE_OPTS(.tag = aggsig_tag,
   15837              :                                   .namespace = agginfo->aggfn.dobj.namespace->dobj.name,
   15838              :                                   .owner = agginfo->aggfn.rolname,
   15839              :                                   .description = "AGGREGATE",
   15840              :                                   .section = SECTION_PRE_DATA,
   15841              :                                   .createStmt = q->data,
   15842              :                                   .dropStmt = delq->data));
   15843              : 
   15844              :     /* Dump Aggregate Comments */
   15845          285 :     if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_COMMENT)
   15846           10 :         dumpComment(fout, "AGGREGATE", aggsig,
   15847           10 :                     agginfo->aggfn.dobj.namespace->dobj.name,
   15848           10 :                     agginfo->aggfn.rolname,
   15849           10 :                     agginfo->aggfn.dobj.catId, 0, agginfo->aggfn.dobj.dumpId);
   15850              : 
   15851          285 :     if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_SECLABEL)
   15852            0 :         dumpSecLabel(fout, "AGGREGATE", aggsig,
   15853            0 :                      agginfo->aggfn.dobj.namespace->dobj.name,
   15854            0 :                      agginfo->aggfn.rolname,
   15855            0 :                      agginfo->aggfn.dobj.catId, 0, agginfo->aggfn.dobj.dumpId);
   15856              : 
   15857              :     /*
   15858              :      * Since there is no GRANT ON AGGREGATE syntax, we have to make the ACL
   15859              :      * command look like a function's GRANT; in particular this affects the
   15860              :      * syntax for zero-argument aggregates and ordered-set aggregates.
   15861              :      */
   15862          285 :     free(aggsig);
   15863              : 
   15864          285 :     aggsig = format_function_signature(fout, &agginfo->aggfn, true);
   15865              : 
   15866          285 :     if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_ACL)
   15867           18 :         dumpACL(fout, agginfo->aggfn.dobj.dumpId, InvalidDumpId,
   15868              :                 "FUNCTION", aggsig, NULL,
   15869           18 :                 agginfo->aggfn.dobj.namespace->dobj.name,
   15870           18 :                 NULL, agginfo->aggfn.rolname, &agginfo->aggfn.dacl);
   15871              : 
   15872          285 :     free(aggsig);
   15873          285 :     free(aggfullsig);
   15874          285 :     free(aggsig_tag);
   15875              : 
   15876          285 :     PQclear(res);
   15877              : 
   15878          285 :     destroyPQExpBuffer(query);
   15879          285 :     destroyPQExpBuffer(q);
   15880          285 :     destroyPQExpBuffer(delq);
   15881          285 :     destroyPQExpBuffer(details);
   15882              : }
   15883              : 
   15884              : /*
   15885              :  * dumpTSParser
   15886              :  *    write out a single text search parser
   15887              :  */
   15888              : static void
   15889           41 : dumpTSParser(Archive *fout, const TSParserInfo *prsinfo)
   15890              : {
   15891           41 :     DumpOptions *dopt = fout->dopt;
   15892              :     PQExpBuffer q;
   15893              :     PQExpBuffer delq;
   15894              :     char       *qprsname;
   15895              : 
   15896              :     /* Do nothing if not dumping schema */
   15897           41 :     if (!dopt->dumpSchema)
   15898            6 :         return;
   15899              : 
   15900           35 :     q = createPQExpBuffer();
   15901           35 :     delq = createPQExpBuffer();
   15902              : 
   15903           35 :     qprsname = pg_strdup(fmtId(prsinfo->dobj.name));
   15904              : 
   15905           35 :     appendPQExpBuffer(q, "CREATE TEXT SEARCH PARSER %s (\n",
   15906           35 :                       fmtQualifiedDumpable(prsinfo));
   15907              : 
   15908           35 :     appendPQExpBuffer(q, "    START = %s,\n",
   15909           35 :                       convertTSFunction(fout, prsinfo->prsstart));
   15910           35 :     appendPQExpBuffer(q, "    GETTOKEN = %s,\n",
   15911           35 :                       convertTSFunction(fout, prsinfo->prstoken));
   15912           35 :     appendPQExpBuffer(q, "    END = %s,\n",
   15913           35 :                       convertTSFunction(fout, prsinfo->prsend));
   15914           35 :     if (prsinfo->prsheadline != InvalidOid)
   15915            3 :         appendPQExpBuffer(q, "    HEADLINE = %s,\n",
   15916            3 :                           convertTSFunction(fout, prsinfo->prsheadline));
   15917           35 :     appendPQExpBuffer(q, "    LEXTYPES = %s );\n",
   15918           35 :                       convertTSFunction(fout, prsinfo->prslextype));
   15919              : 
   15920           35 :     appendPQExpBuffer(delq, "DROP TEXT SEARCH PARSER %s;\n",
   15921           35 :                       fmtQualifiedDumpable(prsinfo));
   15922              : 
   15923           35 :     if (dopt->binary_upgrade)
   15924            1 :         binary_upgrade_extension_member(q, &prsinfo->dobj,
   15925              :                                         "TEXT SEARCH PARSER", qprsname,
   15926            1 :                                         prsinfo->dobj.namespace->dobj.name);
   15927              : 
   15928           35 :     if (prsinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   15929           35 :         ArchiveEntry(fout, prsinfo->dobj.catId, prsinfo->dobj.dumpId,
   15930           35 :                      ARCHIVE_OPTS(.tag = prsinfo->dobj.name,
   15931              :                                   .namespace = prsinfo->dobj.namespace->dobj.name,
   15932              :                                   .description = "TEXT SEARCH PARSER",
   15933              :                                   .section = SECTION_PRE_DATA,
   15934              :                                   .createStmt = q->data,
   15935              :                                   .dropStmt = delq->data));
   15936              : 
   15937              :     /* Dump Parser Comments */
   15938           35 :     if (prsinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   15939           35 :         dumpComment(fout, "TEXT SEARCH PARSER", qprsname,
   15940           35 :                     prsinfo->dobj.namespace->dobj.name, "",
   15941           35 :                     prsinfo->dobj.catId, 0, prsinfo->dobj.dumpId);
   15942              : 
   15943           35 :     destroyPQExpBuffer(q);
   15944           35 :     destroyPQExpBuffer(delq);
   15945           35 :     free(qprsname);
   15946              : }
   15947              : 
   15948              : /*
   15949              :  * dumpTSDictionary
   15950              :  *    write out a single text search dictionary
   15951              :  */
   15952              : static void
   15953          179 : dumpTSDictionary(Archive *fout, const TSDictInfo *dictinfo)
   15954              : {
   15955          179 :     DumpOptions *dopt = fout->dopt;
   15956              :     PQExpBuffer q;
   15957              :     PQExpBuffer delq;
   15958              :     PQExpBuffer query;
   15959              :     char       *qdictname;
   15960              :     PGresult   *res;
   15961              :     char       *nspname;
   15962              :     char       *tmplname;
   15963              : 
   15964              :     /* Do nothing if not dumping schema */
   15965          179 :     if (!dopt->dumpSchema)
   15966            6 :         return;
   15967              : 
   15968          173 :     q = createPQExpBuffer();
   15969          173 :     delq = createPQExpBuffer();
   15970          173 :     query = createPQExpBuffer();
   15971              : 
   15972          173 :     qdictname = pg_strdup(fmtId(dictinfo->dobj.name));
   15973              : 
   15974              :     /* Fetch name and namespace of the dictionary's template */
   15975          173 :     appendPQExpBuffer(query, "SELECT nspname, tmplname "
   15976              :                       "FROM pg_ts_template p, pg_namespace n "
   15977              :                       "WHERE p.oid = '%u' AND n.oid = tmplnamespace",
   15978          173 :                       dictinfo->dicttemplate);
   15979          173 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   15980          173 :     nspname = PQgetvalue(res, 0, 0);
   15981          173 :     tmplname = PQgetvalue(res, 0, 1);
   15982              : 
   15983          173 :     appendPQExpBuffer(q, "CREATE TEXT SEARCH DICTIONARY %s (\n",
   15984          173 :                       fmtQualifiedDumpable(dictinfo));
   15985              : 
   15986          173 :     appendPQExpBufferStr(q, "    TEMPLATE = ");
   15987          173 :     appendPQExpBuffer(q, "%s.", fmtId(nspname));
   15988          173 :     appendPQExpBufferStr(q, fmtId(tmplname));
   15989              : 
   15990          173 :     PQclear(res);
   15991              : 
   15992              :     /* the dictinitoption can be dumped straight into the command */
   15993          173 :     if (dictinfo->dictinitoption)
   15994          138 :         appendPQExpBuffer(q, ",\n    %s", dictinfo->dictinitoption);
   15995              : 
   15996          173 :     appendPQExpBufferStr(q, " );\n");
   15997              : 
   15998          173 :     appendPQExpBuffer(delq, "DROP TEXT SEARCH DICTIONARY %s;\n",
   15999          173 :                       fmtQualifiedDumpable(dictinfo));
   16000              : 
   16001          173 :     if (dopt->binary_upgrade)
   16002           10 :         binary_upgrade_extension_member(q, &dictinfo->dobj,
   16003              :                                         "TEXT SEARCH DICTIONARY", qdictname,
   16004           10 :                                         dictinfo->dobj.namespace->dobj.name);
   16005              : 
   16006          173 :     if (dictinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   16007          173 :         ArchiveEntry(fout, dictinfo->dobj.catId, dictinfo->dobj.dumpId,
   16008          173 :                      ARCHIVE_OPTS(.tag = dictinfo->dobj.name,
   16009              :                                   .namespace = dictinfo->dobj.namespace->dobj.name,
   16010              :                                   .owner = dictinfo->rolname,
   16011              :                                   .description = "TEXT SEARCH DICTIONARY",
   16012              :                                   .section = SECTION_PRE_DATA,
   16013              :                                   .createStmt = q->data,
   16014              :                                   .dropStmt = delq->data));
   16015              : 
   16016              :     /* Dump Dictionary Comments */
   16017          173 :     if (dictinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   16018          128 :         dumpComment(fout, "TEXT SEARCH DICTIONARY", qdictname,
   16019          128 :                     dictinfo->dobj.namespace->dobj.name, dictinfo->rolname,
   16020          128 :                     dictinfo->dobj.catId, 0, dictinfo->dobj.dumpId);
   16021              : 
   16022          173 :     destroyPQExpBuffer(q);
   16023          173 :     destroyPQExpBuffer(delq);
   16024          173 :     destroyPQExpBuffer(query);
   16025          173 :     free(qdictname);
   16026              : }
   16027              : 
   16028              : /*
   16029              :  * dumpTSTemplate
   16030              :  *    write out a single text search template
   16031              :  */
   16032              : static void
   16033           53 : dumpTSTemplate(Archive *fout, const TSTemplateInfo *tmplinfo)
   16034              : {
   16035           53 :     DumpOptions *dopt = fout->dopt;
   16036              :     PQExpBuffer q;
   16037              :     PQExpBuffer delq;
   16038              :     char       *qtmplname;
   16039              : 
   16040              :     /* Do nothing if not dumping schema */
   16041           53 :     if (!dopt->dumpSchema)
   16042            6 :         return;
   16043              : 
   16044           47 :     q = createPQExpBuffer();
   16045           47 :     delq = createPQExpBuffer();
   16046              : 
   16047           47 :     qtmplname = pg_strdup(fmtId(tmplinfo->dobj.name));
   16048              : 
   16049           47 :     appendPQExpBuffer(q, "CREATE TEXT SEARCH TEMPLATE %s (\n",
   16050           47 :                       fmtQualifiedDumpable(tmplinfo));
   16051              : 
   16052           47 :     if (tmplinfo->tmplinit != InvalidOid)
   16053           15 :         appendPQExpBuffer(q, "    INIT = %s,\n",
   16054           15 :                           convertTSFunction(fout, tmplinfo->tmplinit));
   16055           47 :     appendPQExpBuffer(q, "    LEXIZE = %s );\n",
   16056           47 :                       convertTSFunction(fout, tmplinfo->tmpllexize));
   16057              : 
   16058           47 :     appendPQExpBuffer(delq, "DROP TEXT SEARCH TEMPLATE %s;\n",
   16059           47 :                       fmtQualifiedDumpable(tmplinfo));
   16060              : 
   16061           47 :     if (dopt->binary_upgrade)
   16062            1 :         binary_upgrade_extension_member(q, &tmplinfo->dobj,
   16063              :                                         "TEXT SEARCH TEMPLATE", qtmplname,
   16064            1 :                                         tmplinfo->dobj.namespace->dobj.name);
   16065              : 
   16066           47 :     if (tmplinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   16067           47 :         ArchiveEntry(fout, tmplinfo->dobj.catId, tmplinfo->dobj.dumpId,
   16068           47 :                      ARCHIVE_OPTS(.tag = tmplinfo->dobj.name,
   16069              :                                   .namespace = tmplinfo->dobj.namespace->dobj.name,
   16070              :                                   .description = "TEXT SEARCH TEMPLATE",
   16071              :                                   .section = SECTION_PRE_DATA,
   16072              :                                   .createStmt = q->data,
   16073              :                                   .dropStmt = delq->data));
   16074              : 
   16075              :     /* Dump Template Comments */
   16076           47 :     if (tmplinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   16077           47 :         dumpComment(fout, "TEXT SEARCH TEMPLATE", qtmplname,
   16078           47 :                     tmplinfo->dobj.namespace->dobj.name, "",
   16079           47 :                     tmplinfo->dobj.catId, 0, tmplinfo->dobj.dumpId);
   16080              : 
   16081           47 :     destroyPQExpBuffer(q);
   16082           47 :     destroyPQExpBuffer(delq);
   16083           47 :     free(qtmplname);
   16084              : }
   16085              : 
   16086              : /*
   16087              :  * dumpTSConfig
   16088              :  *    write out a single text search configuration
   16089              :  */
   16090              : static void
   16091          154 : dumpTSConfig(Archive *fout, const TSConfigInfo *cfginfo)
   16092              : {
   16093          154 :     DumpOptions *dopt = fout->dopt;
   16094              :     PQExpBuffer q;
   16095              :     PQExpBuffer delq;
   16096              :     PQExpBuffer query;
   16097              :     char       *qcfgname;
   16098              :     PGresult   *res;
   16099              :     char       *nspname;
   16100              :     char       *prsname;
   16101              :     int         ntups,
   16102              :                 i;
   16103              :     int         i_tokenname;
   16104              :     int         i_dictname;
   16105              : 
   16106              :     /* Do nothing if not dumping schema */
   16107          154 :     if (!dopt->dumpSchema)
   16108            6 :         return;
   16109              : 
   16110          148 :     q = createPQExpBuffer();
   16111          148 :     delq = createPQExpBuffer();
   16112          148 :     query = createPQExpBuffer();
   16113              : 
   16114          148 :     qcfgname = pg_strdup(fmtId(cfginfo->dobj.name));
   16115              : 
   16116              :     /* Fetch name and namespace of the config's parser */
   16117          148 :     appendPQExpBuffer(query, "SELECT nspname, prsname "
   16118              :                       "FROM pg_ts_parser p, pg_namespace n "
   16119              :                       "WHERE p.oid = '%u' AND n.oid = prsnamespace",
   16120          148 :                       cfginfo->cfgparser);
   16121          148 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   16122          148 :     nspname = PQgetvalue(res, 0, 0);
   16123          148 :     prsname = PQgetvalue(res, 0, 1);
   16124              : 
   16125          148 :     appendPQExpBuffer(q, "CREATE TEXT SEARCH CONFIGURATION %s (\n",
   16126          148 :                       fmtQualifiedDumpable(cfginfo));
   16127              : 
   16128          148 :     appendPQExpBuffer(q, "    PARSER = %s.", fmtId(nspname));
   16129          148 :     appendPQExpBuffer(q, "%s );\n", fmtId(prsname));
   16130              : 
   16131          148 :     PQclear(res);
   16132              : 
   16133          148 :     resetPQExpBuffer(query);
   16134          148 :     appendPQExpBuffer(query,
   16135              :                       "SELECT\n"
   16136              :                       "  ( SELECT alias FROM pg_catalog.ts_token_type('%u'::pg_catalog.oid) AS t\n"
   16137              :                       "    WHERE t.tokid = m.maptokentype ) AS tokenname,\n"
   16138              :                       "  m.mapdict::pg_catalog.regdictionary AS dictname\n"
   16139              :                       "FROM pg_catalog.pg_ts_config_map AS m\n"
   16140              :                       "WHERE m.mapcfg = '%u'\n"
   16141              :                       "ORDER BY m.mapcfg, m.maptokentype, m.mapseqno",
   16142          148 :                       cfginfo->cfgparser, cfginfo->dobj.catId.oid);
   16143              : 
   16144          148 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   16145          148 :     ntups = PQntuples(res);
   16146              : 
   16147          148 :     i_tokenname = PQfnumber(res, "tokenname");
   16148          148 :     i_dictname = PQfnumber(res, "dictname");
   16149              : 
   16150         3095 :     for (i = 0; i < ntups; i++)
   16151              :     {
   16152         2947 :         char       *tokenname = PQgetvalue(res, i, i_tokenname);
   16153         2947 :         char       *dictname = PQgetvalue(res, i, i_dictname);
   16154              : 
   16155         2947 :         if (i == 0 ||
   16156         2799 :             strcmp(tokenname, PQgetvalue(res, i - 1, i_tokenname)) != 0)
   16157              :         {
   16158              :             /* starting a new token type, so start a new command */
   16159         2812 :             if (i > 0)
   16160         2664 :                 appendPQExpBufferStr(q, ";\n");
   16161         2812 :             appendPQExpBuffer(q, "\nALTER TEXT SEARCH CONFIGURATION %s\n",
   16162         2812 :                               fmtQualifiedDumpable(cfginfo));
   16163              :             /* tokenname needs quoting, dictname does NOT */
   16164         2812 :             appendPQExpBuffer(q, "    ADD MAPPING FOR %s WITH %s",
   16165              :                               fmtId(tokenname), dictname);
   16166              :         }
   16167              :         else
   16168          135 :             appendPQExpBuffer(q, ", %s", dictname);
   16169              :     }
   16170              : 
   16171          148 :     if (ntups > 0)
   16172          148 :         appendPQExpBufferStr(q, ";\n");
   16173              : 
   16174          148 :     PQclear(res);
   16175              : 
   16176          148 :     appendPQExpBuffer(delq, "DROP TEXT SEARCH CONFIGURATION %s;\n",
   16177          148 :                       fmtQualifiedDumpable(cfginfo));
   16178              : 
   16179          148 :     if (dopt->binary_upgrade)
   16180            5 :         binary_upgrade_extension_member(q, &cfginfo->dobj,
   16181              :                                         "TEXT SEARCH CONFIGURATION", qcfgname,
   16182            5 :                                         cfginfo->dobj.namespace->dobj.name);
   16183              : 
   16184          148 :     if (cfginfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   16185          148 :         ArchiveEntry(fout, cfginfo->dobj.catId, cfginfo->dobj.dumpId,
   16186          148 :                      ARCHIVE_OPTS(.tag = cfginfo->dobj.name,
   16187              :                                   .namespace = cfginfo->dobj.namespace->dobj.name,
   16188              :                                   .owner = cfginfo->rolname,
   16189              :                                   .description = "TEXT SEARCH CONFIGURATION",
   16190              :                                   .section = SECTION_PRE_DATA,
   16191              :                                   .createStmt = q->data,
   16192              :                                   .dropStmt = delq->data));
   16193              : 
   16194              :     /* Dump Configuration Comments */
   16195          148 :     if (cfginfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   16196          128 :         dumpComment(fout, "TEXT SEARCH CONFIGURATION", qcfgname,
   16197          128 :                     cfginfo->dobj.namespace->dobj.name, cfginfo->rolname,
   16198          128 :                     cfginfo->dobj.catId, 0, cfginfo->dobj.dumpId);
   16199              : 
   16200          148 :     destroyPQExpBuffer(q);
   16201          148 :     destroyPQExpBuffer(delq);
   16202          148 :     destroyPQExpBuffer(query);
   16203          148 :     free(qcfgname);
   16204              : }
   16205              : 
   16206              : /*
   16207              :  * dumpForeignDataWrapper
   16208              :  *    write out a single foreign-data wrapper definition
   16209              :  */
   16210              : static void
   16211           52 : dumpForeignDataWrapper(Archive *fout, const FdwInfo *fdwinfo)
   16212              : {
   16213           52 :     DumpOptions *dopt = fout->dopt;
   16214              :     PQExpBuffer q;
   16215              :     PQExpBuffer delq;
   16216              :     char       *qfdwname;
   16217              : 
   16218              :     /* Do nothing if not dumping schema */
   16219           52 :     if (!dopt->dumpSchema)
   16220            7 :         return;
   16221              : 
   16222           45 :     q = createPQExpBuffer();
   16223           45 :     delq = createPQExpBuffer();
   16224              : 
   16225           45 :     qfdwname = pg_strdup(fmtId(fdwinfo->dobj.name));
   16226              : 
   16227           45 :     appendPQExpBuffer(q, "CREATE FOREIGN DATA WRAPPER %s",
   16228              :                       qfdwname);
   16229              : 
   16230           45 :     if (strcmp(fdwinfo->fdwhandler, "-") != 0)
   16231            0 :         appendPQExpBuffer(q, " HANDLER %s", fdwinfo->fdwhandler);
   16232              : 
   16233           45 :     if (strcmp(fdwinfo->fdwvalidator, "-") != 0)
   16234            0 :         appendPQExpBuffer(q, " VALIDATOR %s", fdwinfo->fdwvalidator);
   16235              : 
   16236           45 :     if (strcmp(fdwinfo->fdwconnection, "-") != 0)
   16237            0 :         appendPQExpBuffer(q, " CONNECTION %s", fdwinfo->fdwconnection);
   16238              : 
   16239           45 :     if (strlen(fdwinfo->fdwoptions) > 0)
   16240            0 :         appendPQExpBuffer(q, " OPTIONS (\n    %s\n)", fdwinfo->fdwoptions);
   16241              : 
   16242           45 :     appendPQExpBufferStr(q, ";\n");
   16243              : 
   16244           45 :     appendPQExpBuffer(delq, "DROP FOREIGN DATA WRAPPER %s;\n",
   16245              :                       qfdwname);
   16246              : 
   16247           45 :     if (dopt->binary_upgrade)
   16248            2 :         binary_upgrade_extension_member(q, &fdwinfo->dobj,
   16249              :                                         "FOREIGN DATA WRAPPER", qfdwname,
   16250              :                                         NULL);
   16251              : 
   16252           45 :     if (fdwinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   16253           45 :         ArchiveEntry(fout, fdwinfo->dobj.catId, fdwinfo->dobj.dumpId,
   16254           45 :                      ARCHIVE_OPTS(.tag = fdwinfo->dobj.name,
   16255              :                                   .owner = fdwinfo->rolname,
   16256              :                                   .description = "FOREIGN DATA WRAPPER",
   16257              :                                   .section = SECTION_PRE_DATA,
   16258              :                                   .createStmt = q->data,
   16259              :                                   .dropStmt = delq->data));
   16260              : 
   16261              :     /* Dump Foreign Data Wrapper Comments */
   16262           45 :     if (fdwinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   16263            0 :         dumpComment(fout, "FOREIGN DATA WRAPPER", qfdwname,
   16264            0 :                     NULL, fdwinfo->rolname,
   16265            0 :                     fdwinfo->dobj.catId, 0, fdwinfo->dobj.dumpId);
   16266              : 
   16267              :     /* Handle the ACL */
   16268           45 :     if (fdwinfo->dobj.dump & DUMP_COMPONENT_ACL)
   16269           31 :         dumpACL(fout, fdwinfo->dobj.dumpId, InvalidDumpId,
   16270              :                 "FOREIGN DATA WRAPPER", qfdwname, NULL, NULL,
   16271           31 :                 NULL, fdwinfo->rolname, &fdwinfo->dacl);
   16272              : 
   16273           45 :     free(qfdwname);
   16274              : 
   16275           45 :     destroyPQExpBuffer(q);
   16276           45 :     destroyPQExpBuffer(delq);
   16277              : }
   16278              : 
   16279              : /*
   16280              :  * dumpForeignServer
   16281              :  *    write out a foreign server definition
   16282              :  */
   16283              : static void
   16284           56 : dumpForeignServer(Archive *fout, const ForeignServerInfo *srvinfo)
   16285              : {
   16286           56 :     DumpOptions *dopt = fout->dopt;
   16287              :     PQExpBuffer q;
   16288              :     PQExpBuffer delq;
   16289              :     PQExpBuffer query;
   16290              :     PGresult   *res;
   16291              :     char       *qsrvname;
   16292              :     char       *fdwname;
   16293              : 
   16294              :     /* Do nothing if not dumping schema */
   16295           56 :     if (!dopt->dumpSchema)
   16296            9 :         return;
   16297              : 
   16298           47 :     q = createPQExpBuffer();
   16299           47 :     delq = createPQExpBuffer();
   16300           47 :     query = createPQExpBuffer();
   16301              : 
   16302           47 :     qsrvname = pg_strdup(fmtId(srvinfo->dobj.name));
   16303              : 
   16304              :     /* look up the foreign-data wrapper */
   16305           47 :     appendPQExpBuffer(query, "SELECT fdwname "
   16306              :                       "FROM pg_foreign_data_wrapper w "
   16307              :                       "WHERE w.oid = '%u'",
   16308           47 :                       srvinfo->srvfdw);
   16309           47 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   16310           47 :     fdwname = PQgetvalue(res, 0, 0);
   16311              : 
   16312           47 :     appendPQExpBuffer(q, "CREATE SERVER %s", qsrvname);
   16313           47 :     if (srvinfo->srvtype && strlen(srvinfo->srvtype) > 0)
   16314              :     {
   16315            0 :         appendPQExpBufferStr(q, " TYPE ");
   16316            0 :         appendStringLiteralAH(q, srvinfo->srvtype, fout);
   16317              :     }
   16318           47 :     if (srvinfo->srvversion && strlen(srvinfo->srvversion) > 0)
   16319              :     {
   16320            0 :         appendPQExpBufferStr(q, " VERSION ");
   16321            0 :         appendStringLiteralAH(q, srvinfo->srvversion, fout);
   16322              :     }
   16323              : 
   16324           47 :     appendPQExpBufferStr(q, " FOREIGN DATA WRAPPER ");
   16325           47 :     appendPQExpBufferStr(q, fmtId(fdwname));
   16326              : 
   16327           47 :     if (srvinfo->srvoptions && strlen(srvinfo->srvoptions) > 0)
   16328            0 :         appendPQExpBuffer(q, " OPTIONS (\n    %s\n)", srvinfo->srvoptions);
   16329              : 
   16330           47 :     appendPQExpBufferStr(q, ";\n");
   16331              : 
   16332           47 :     appendPQExpBuffer(delq, "DROP SERVER %s;\n",
   16333              :                       qsrvname);
   16334              : 
   16335           47 :     if (dopt->binary_upgrade)
   16336            2 :         binary_upgrade_extension_member(q, &srvinfo->dobj,
   16337              :                                         "SERVER", qsrvname, NULL);
   16338              : 
   16339           47 :     if (srvinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   16340           47 :         ArchiveEntry(fout, srvinfo->dobj.catId, srvinfo->dobj.dumpId,
   16341           47 :                      ARCHIVE_OPTS(.tag = srvinfo->dobj.name,
   16342              :                                   .owner = srvinfo->rolname,
   16343              :                                   .description = "SERVER",
   16344              :                                   .section = SECTION_PRE_DATA,
   16345              :                                   .createStmt = q->data,
   16346              :                                   .dropStmt = delq->data));
   16347              : 
   16348              :     /* Dump Foreign Server Comments */
   16349           47 :     if (srvinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   16350            0 :         dumpComment(fout, "SERVER", qsrvname,
   16351            0 :                     NULL, srvinfo->rolname,
   16352            0 :                     srvinfo->dobj.catId, 0, srvinfo->dobj.dumpId);
   16353              : 
   16354              :     /* Handle the ACL */
   16355           47 :     if (srvinfo->dobj.dump & DUMP_COMPONENT_ACL)
   16356           31 :         dumpACL(fout, srvinfo->dobj.dumpId, InvalidDumpId,
   16357              :                 "FOREIGN SERVER", qsrvname, NULL, NULL,
   16358           31 :                 NULL, srvinfo->rolname, &srvinfo->dacl);
   16359              : 
   16360              :     /* Dump user mappings */
   16361           47 :     if (srvinfo->dobj.dump & DUMP_COMPONENT_USERMAP)
   16362           47 :         dumpUserMappings(fout,
   16363           47 :                          srvinfo->dobj.name, NULL,
   16364           47 :                          srvinfo->rolname,
   16365           47 :                          srvinfo->dobj.catId, srvinfo->dobj.dumpId);
   16366              : 
   16367           47 :     PQclear(res);
   16368              : 
   16369           47 :     free(qsrvname);
   16370              : 
   16371           47 :     destroyPQExpBuffer(q);
   16372           47 :     destroyPQExpBuffer(delq);
   16373           47 :     destroyPQExpBuffer(query);
   16374              : }
   16375              : 
   16376              : /*
   16377              :  * dumpUserMappings
   16378              :  *
   16379              :  * This routine is used to dump any user mappings associated with the
   16380              :  * server handed to this routine. Should be called after ArchiveEntry()
   16381              :  * for the server.
   16382              :  */
   16383              : static void
   16384           47 : dumpUserMappings(Archive *fout,
   16385              :                  const char *servername, const char *namespace,
   16386              :                  const char *owner,
   16387              :                  CatalogId catalogId, DumpId dumpId)
   16388              : {
   16389              :     PQExpBuffer q;
   16390              :     PQExpBuffer delq;
   16391              :     PQExpBuffer query;
   16392              :     PQExpBuffer tag;
   16393              :     PGresult   *res;
   16394              :     int         ntups;
   16395              :     int         i_usename;
   16396              :     int         i_umoptions;
   16397              :     int         i;
   16398              : 
   16399           47 :     q = createPQExpBuffer();
   16400           47 :     tag = createPQExpBuffer();
   16401           47 :     delq = createPQExpBuffer();
   16402           47 :     query = createPQExpBuffer();
   16403              : 
   16404              :     /*
   16405              :      * We read from the publicly accessible view pg_user_mappings, so as not
   16406              :      * to fail if run by a non-superuser.  Note that the view will show
   16407              :      * umoptions as null if the user hasn't got privileges for the associated
   16408              :      * server; this means that pg_dump will dump such a mapping, but with no
   16409              :      * OPTIONS clause.  A possible alternative is to skip such mappings
   16410              :      * altogether, but it's not clear that that's an improvement.
   16411              :      */
   16412           47 :     appendPQExpBuffer(query,
   16413              :                       "SELECT usename, "
   16414              :                       "array_to_string(ARRAY("
   16415              :                       "SELECT quote_ident(option_name) || ' ' || "
   16416              :                       "quote_literal(option_value) "
   16417              :                       "FROM pg_options_to_table(umoptions) "
   16418              :                       "ORDER BY option_name"
   16419              :                       "), E',\n    ') AS umoptions "
   16420              :                       "FROM pg_user_mappings "
   16421              :                       "WHERE srvid = '%u' "
   16422              :                       "ORDER BY usename",
   16423              :                       catalogId.oid);
   16424              : 
   16425           47 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   16426              : 
   16427           47 :     ntups = PQntuples(res);
   16428           47 :     i_usename = PQfnumber(res, "usename");
   16429           47 :     i_umoptions = PQfnumber(res, "umoptions");
   16430              : 
   16431           78 :     for (i = 0; i < ntups; i++)
   16432              :     {
   16433              :         char       *usename;
   16434              :         char       *umoptions;
   16435              : 
   16436           31 :         usename = PQgetvalue(res, i, i_usename);
   16437           31 :         umoptions = PQgetvalue(res, i, i_umoptions);
   16438              : 
   16439           31 :         resetPQExpBuffer(q);
   16440           31 :         appendPQExpBuffer(q, "CREATE USER MAPPING FOR %s", fmtId(usename));
   16441           31 :         appendPQExpBuffer(q, " SERVER %s", fmtId(servername));
   16442              : 
   16443           31 :         if (umoptions && strlen(umoptions) > 0)
   16444            0 :             appendPQExpBuffer(q, " OPTIONS (\n    %s\n)", umoptions);
   16445              : 
   16446           31 :         appendPQExpBufferStr(q, ";\n");
   16447              : 
   16448           31 :         resetPQExpBuffer(delq);
   16449           31 :         appendPQExpBuffer(delq, "DROP USER MAPPING FOR %s", fmtId(usename));
   16450           31 :         appendPQExpBuffer(delq, " SERVER %s;\n", fmtId(servername));
   16451              : 
   16452           31 :         resetPQExpBuffer(tag);
   16453           31 :         appendPQExpBuffer(tag, "USER MAPPING %s SERVER %s",
   16454              :                           usename, servername);
   16455              : 
   16456           31 :         ArchiveEntry(fout, nilCatalogId, createDumpId(),
   16457           31 :                      ARCHIVE_OPTS(.tag = tag->data,
   16458              :                                   .namespace = namespace,
   16459              :                                   .owner = owner,
   16460              :                                   .description = "USER MAPPING",
   16461              :                                   .section = SECTION_PRE_DATA,
   16462              :                                   .createStmt = q->data,
   16463              :                                   .dropStmt = delq->data));
   16464              :     }
   16465              : 
   16466           47 :     PQclear(res);
   16467              : 
   16468           47 :     destroyPQExpBuffer(query);
   16469           47 :     destroyPQExpBuffer(delq);
   16470           47 :     destroyPQExpBuffer(tag);
   16471           47 :     destroyPQExpBuffer(q);
   16472           47 : }
   16473              : 
   16474              : /*
   16475              :  * Write out default privileges information
   16476              :  */
   16477              : static void
   16478          160 : dumpDefaultACL(Archive *fout, const DefaultACLInfo *daclinfo)
   16479              : {
   16480          160 :     DumpOptions *dopt = fout->dopt;
   16481              :     PQExpBuffer q;
   16482              :     PQExpBuffer tag;
   16483              :     const char *type;
   16484              : 
   16485              :     /* Do nothing if not dumping schema, or if we're skipping ACLs */
   16486          160 :     if (!dopt->dumpSchema || dopt->aclsSkip)
   16487           28 :         return;
   16488              : 
   16489          132 :     q = createPQExpBuffer();
   16490          132 :     tag = createPQExpBuffer();
   16491              : 
   16492          132 :     switch (daclinfo->defaclobjtype)
   16493              :     {
   16494           61 :         case DEFACLOBJ_RELATION:
   16495           61 :             type = "TABLES";
   16496           61 :             break;
   16497            0 :         case DEFACLOBJ_SEQUENCE:
   16498            0 :             type = "SEQUENCES";
   16499            0 :             break;
   16500           61 :         case DEFACLOBJ_FUNCTION:
   16501           61 :             type = "FUNCTIONS";
   16502           61 :             break;
   16503           10 :         case DEFACLOBJ_TYPE:
   16504           10 :             type = "TYPES";
   16505           10 :             break;
   16506            0 :         case DEFACLOBJ_NAMESPACE:
   16507            0 :             type = "SCHEMAS";
   16508            0 :             break;
   16509            0 :         case DEFACLOBJ_LARGEOBJECT:
   16510            0 :             type = "LARGE OBJECTS";
   16511            0 :             break;
   16512            0 :         default:
   16513              :             /* shouldn't get here */
   16514            0 :             pg_fatal("unrecognized object type in default privileges: %d",
   16515              :                      (int) daclinfo->defaclobjtype);
   16516              :             type = "";            /* keep compiler quiet */
   16517              :     }
   16518              : 
   16519          132 :     appendPQExpBuffer(tag, "DEFAULT PRIVILEGES FOR %s", type);
   16520              : 
   16521              :     /* build the actual command(s) for this tuple */
   16522          132 :     if (!buildDefaultACLCommands(type,
   16523          132 :                                  daclinfo->dobj.namespace != NULL ?
   16524           62 :                                  daclinfo->dobj.namespace->dobj.name : NULL,
   16525          132 :                                  daclinfo->dacl.acl,
   16526          132 :                                  daclinfo->dacl.acldefault,
   16527          132 :                                  daclinfo->defaclrole,
   16528              :                                  fout->remoteVersion,
   16529              :                                  q))
   16530            0 :         pg_fatal("could not parse default ACL list (%s)",
   16531              :                  daclinfo->dacl.acl);
   16532              : 
   16533          132 :     if (daclinfo->dobj.dump & DUMP_COMPONENT_ACL)
   16534          132 :         ArchiveEntry(fout, daclinfo->dobj.catId, daclinfo->dobj.dumpId,
   16535          132 :                      ARCHIVE_OPTS(.tag = tag->data,
   16536              :                                   .namespace = daclinfo->dobj.namespace ?
   16537              :                                   daclinfo->dobj.namespace->dobj.name : NULL,
   16538              :                                   .owner = daclinfo->defaclrole,
   16539              :                                   .description = "DEFAULT ACL",
   16540              :                                   .section = SECTION_POST_DATA,
   16541              :                                   .createStmt = q->data));
   16542              : 
   16543          132 :     destroyPQExpBuffer(tag);
   16544          132 :     destroyPQExpBuffer(q);
   16545              : }
   16546              : 
   16547              : /*----------
   16548              :  * Write out grant/revoke information
   16549              :  *
   16550              :  * 'objDumpId' is the dump ID of the underlying object.
   16551              :  * 'altDumpId' can be a second dumpId that the ACL entry must also depend on,
   16552              :  *      or InvalidDumpId if there is no need for a second dependency.
   16553              :  * 'type' must be one of
   16554              :  *      TABLE, SEQUENCE, FUNCTION, LANGUAGE, SCHEMA, DATABASE, TABLESPACE,
   16555              :  *      FOREIGN DATA WRAPPER, SERVER, or LARGE OBJECT.
   16556              :  * 'name' is the formatted name of the object.  Must be quoted etc. already.
   16557              :  * 'subname' is the formatted name of the sub-object, if any.  Must be quoted.
   16558              :  *      (Currently we assume that subname is only provided for table columns.)
   16559              :  * 'nspname' is the namespace the object is in (NULL if none).
   16560              :  * 'tag' is the tag to use for the ACL TOC entry; typically, this is NULL
   16561              :  *      to use the default for the object type.
   16562              :  * 'owner' is the owner, NULL if there is no owner (for languages).
   16563              :  * 'dacl' is the DumpableAcl struct for the object.
   16564              :  *
   16565              :  * Returns the dump ID assigned to the ACL TocEntry, or InvalidDumpId if
   16566              :  * no ACL entry was created.
   16567              :  *----------
   16568              :  */
   16569              : static DumpId
   16570        43681 : dumpACL(Archive *fout, DumpId objDumpId, DumpId altDumpId,
   16571              :         const char *type, const char *name, const char *subname,
   16572              :         const char *nspname, const char *tag, const char *owner,
   16573              :         const DumpableAcl *dacl)
   16574              : {
   16575        43681 :     DumpId      aclDumpId = InvalidDumpId;
   16576        43681 :     DumpOptions *dopt = fout->dopt;
   16577        43681 :     const char *acls = dacl->acl;
   16578        43681 :     const char *acldefault = dacl->acldefault;
   16579        43681 :     char        privtype = dacl->privtype;
   16580        43681 :     const char *initprivs = dacl->initprivs;
   16581              :     const char *baseacls;
   16582              :     PQExpBuffer sql;
   16583              : 
   16584              :     /* Do nothing if ACL dump is not enabled */
   16585        43681 :     if (dopt->aclsSkip)
   16586          347 :         return InvalidDumpId;
   16587              : 
   16588              :     /* --data-only skips ACLs *except* large object ACLs */
   16589        43334 :     if (!dopt->dumpSchema && strcmp(type, "LARGE OBJECT") != 0)
   16590            0 :         return InvalidDumpId;
   16591              : 
   16592        43334 :     sql = createPQExpBuffer();
   16593              : 
   16594              :     /*
   16595              :      * In binary upgrade mode, we don't run an extension's script but instead
   16596              :      * dump out the objects independently and then recreate them.  To preserve
   16597              :      * any initial privileges which were set on extension objects, we need to
   16598              :      * compute the set of GRANT and REVOKE commands necessary to get from the
   16599              :      * default privileges of an object to its initial privileges as recorded
   16600              :      * in pg_init_privs.
   16601              :      *
   16602              :      * At restore time, we apply these commands after having called
   16603              :      * binary_upgrade_set_record_init_privs(true).  That tells the backend to
   16604              :      * copy the results into pg_init_privs.  This is how we preserve the
   16605              :      * contents of that catalog across binary upgrades.
   16606              :      */
   16607        43334 :     if (dopt->binary_upgrade && privtype == 'e' &&
   16608           13 :         initprivs && *initprivs != '\0')
   16609              :     {
   16610           13 :         appendPQExpBufferStr(sql, "SELECT pg_catalog.binary_upgrade_set_record_init_privs(true);\n");
   16611           13 :         if (!buildACLCommands(name, subname, nspname, type,
   16612              :                               initprivs, acldefault, owner,
   16613              :                               "", fout->remoteVersion, sql))
   16614            0 :             pg_fatal("could not parse initial ACL list (%s) or default (%s) for object \"%s\" (%s)",
   16615              :                      initprivs, acldefault, name, type);
   16616           13 :         appendPQExpBufferStr(sql, "SELECT pg_catalog.binary_upgrade_set_record_init_privs(false);\n");
   16617              :     }
   16618              : 
   16619              :     /*
   16620              :      * Now figure the GRANT and REVOKE commands needed to get to the object's
   16621              :      * actual current ACL, starting from the initprivs if given, else from the
   16622              :      * object-type-specific default.  Also, while buildACLCommands will assume
   16623              :      * that a NULL/empty acls string means it needn't do anything, what that
   16624              :      * actually represents is the object-type-specific default; so we need to
   16625              :      * substitute the acldefault string to get the right results in that case.
   16626              :      */
   16627        43334 :     if (initprivs && *initprivs != '\0')
   16628              :     {
   16629        41416 :         baseacls = initprivs;
   16630        41416 :         if (acls == NULL || *acls == '\0')
   16631           17 :             acls = acldefault;
   16632              :     }
   16633              :     else
   16634         1918 :         baseacls = acldefault;
   16635              : 
   16636        43334 :     if (!buildACLCommands(name, subname, nspname, type,
   16637              :                           acls, baseacls, owner,
   16638              :                           "", fout->remoteVersion, sql))
   16639            0 :         pg_fatal("could not parse ACL list (%s) or default (%s) for object \"%s\" (%s)",
   16640              :                  acls, baseacls, name, type);
   16641              : 
   16642        43334 :     if (sql->len > 0)
   16643              :     {
   16644         1928 :         PQExpBuffer tagbuf = createPQExpBuffer();
   16645              :         DumpId      aclDeps[2];
   16646         1928 :         int         nDeps = 0;
   16647              : 
   16648         1928 :         if (tag)
   16649            0 :             appendPQExpBufferStr(tagbuf, tag);
   16650         1928 :         else if (subname)
   16651         1047 :             appendPQExpBuffer(tagbuf, "COLUMN %s.%s", name, subname);
   16652              :         else
   16653          881 :             appendPQExpBuffer(tagbuf, "%s %s", type, name);
   16654              : 
   16655         1928 :         aclDeps[nDeps++] = objDumpId;
   16656         1928 :         if (altDumpId != InvalidDumpId)
   16657          977 :             aclDeps[nDeps++] = altDumpId;
   16658              : 
   16659         1928 :         aclDumpId = createDumpId();
   16660              : 
   16661         1928 :         ArchiveEntry(fout, nilCatalogId, aclDumpId,
   16662         1928 :                      ARCHIVE_OPTS(.tag = tagbuf->data,
   16663              :                                   .namespace = nspname,
   16664              :                                   .owner = owner,
   16665              :                                   .description = "ACL",
   16666              :                                   .section = SECTION_NONE,
   16667              :                                   .createStmt = sql->data,
   16668              :                                   .deps = aclDeps,
   16669              :                                   .nDeps = nDeps));
   16670              : 
   16671         1928 :         destroyPQExpBuffer(tagbuf);
   16672              :     }
   16673              : 
   16674        43334 :     destroyPQExpBuffer(sql);
   16675              : 
   16676        43334 :     return aclDumpId;
   16677              : }
   16678              : 
   16679              : /*
   16680              :  * dumpSecLabel
   16681              :  *
   16682              :  * This routine is used to dump any security labels associated with the
   16683              :  * object handed to this routine. The routine takes the object type
   16684              :  * and object name (ready to print, except for schema decoration), plus
   16685              :  * the namespace and owner of the object (for labeling the ArchiveEntry),
   16686              :  * plus catalog ID and subid which are the lookup key for pg_seclabel,
   16687              :  * plus the dump ID for the object (for setting a dependency).
   16688              :  * If a matching pg_seclabel entry is found, it is dumped.
   16689              :  *
   16690              :  * Note: although this routine takes a dumpId for dependency purposes,
   16691              :  * that purpose is just to mark the dependency in the emitted dump file
   16692              :  * for possible future use by pg_restore.  We do NOT use it for determining
   16693              :  * ordering of the label in the dump file, because this routine is called
   16694              :  * after dependency sorting occurs.  This routine should be called just after
   16695              :  * calling ArchiveEntry() for the specified object.
   16696              :  */
   16697              : static void
   16698           10 : dumpSecLabel(Archive *fout, const char *type, const char *name,
   16699              :              const char *namespace, const char *owner,
   16700              :              CatalogId catalogId, int subid, DumpId dumpId)
   16701              : {
   16702           10 :     DumpOptions *dopt = fout->dopt;
   16703              :     SecLabelItem *labels;
   16704              :     int         nlabels;
   16705              :     int         i;
   16706              :     PQExpBuffer query;
   16707              : 
   16708              :     /* do nothing, if --no-security-labels is supplied */
   16709           10 :     if (dopt->no_security_labels)
   16710            0 :         return;
   16711              : 
   16712              :     /*
   16713              :      * Security labels are schema not data ... except large object labels are
   16714              :      * data
   16715              :      */
   16716           10 :     if (strcmp(type, "LARGE OBJECT") != 0)
   16717              :     {
   16718            0 :         if (!dopt->dumpSchema)
   16719            0 :             return;
   16720              :     }
   16721              :     else
   16722              :     {
   16723              :         /* We do dump large object security labels in binary-upgrade mode */
   16724           10 :         if (!dopt->dumpData && !dopt->binary_upgrade)
   16725            0 :             return;
   16726              :     }
   16727              : 
   16728              :     /* Search for security labels associated with catalogId, using table */
   16729           10 :     nlabels = findSecLabels(catalogId.tableoid, catalogId.oid, &labels);
   16730              : 
   16731           10 :     query = createPQExpBuffer();
   16732              : 
   16733           15 :     for (i = 0; i < nlabels; i++)
   16734              :     {
   16735              :         /*
   16736              :          * Ignore label entries for which the subid doesn't match.
   16737              :          */
   16738            5 :         if (labels[i].objsubid != subid)
   16739            0 :             continue;
   16740              : 
   16741            5 :         appendPQExpBuffer(query,
   16742              :                           "SECURITY LABEL FOR %s ON %s ",
   16743            5 :                           fmtId(labels[i].provider), type);
   16744            5 :         if (namespace && *namespace)
   16745            0 :             appendPQExpBuffer(query, "%s.", fmtId(namespace));
   16746            5 :         appendPQExpBuffer(query, "%s IS ", name);
   16747            5 :         appendStringLiteralAH(query, labels[i].label, fout);
   16748            5 :         appendPQExpBufferStr(query, ";\n");
   16749              :     }
   16750              : 
   16751           10 :     if (query->len > 0)
   16752              :     {
   16753            5 :         PQExpBuffer tag = createPQExpBuffer();
   16754              : 
   16755            5 :         appendPQExpBuffer(tag, "%s %s", type, name);
   16756            5 :         ArchiveEntry(fout, nilCatalogId, createDumpId(),
   16757            5 :                      ARCHIVE_OPTS(.tag = tag->data,
   16758              :                                   .namespace = namespace,
   16759              :                                   .owner = owner,
   16760              :                                   .description = "SECURITY LABEL",
   16761              :                                   .section = SECTION_NONE,
   16762              :                                   .createStmt = query->data,
   16763              :                                   .deps = &dumpId,
   16764              :                                   .nDeps = 1));
   16765            5 :         destroyPQExpBuffer(tag);
   16766              :     }
   16767              : 
   16768           10 :     destroyPQExpBuffer(query);
   16769              : }
   16770              : 
   16771              : /*
   16772              :  * dumpTableSecLabel
   16773              :  *
   16774              :  * As above, but dump security label for both the specified table (or view)
   16775              :  * and its columns.
   16776              :  */
   16777              : static void
   16778            0 : dumpTableSecLabel(Archive *fout, const TableInfo *tbinfo, const char *reltypename)
   16779              : {
   16780            0 :     DumpOptions *dopt = fout->dopt;
   16781              :     SecLabelItem *labels;
   16782              :     int         nlabels;
   16783              :     int         i;
   16784              :     PQExpBuffer query;
   16785              :     PQExpBuffer target;
   16786              : 
   16787              :     /* do nothing, if --no-security-labels is supplied */
   16788            0 :     if (dopt->no_security_labels)
   16789            0 :         return;
   16790              : 
   16791              :     /* SecLabel are SCHEMA not data */
   16792            0 :     if (!dopt->dumpSchema)
   16793            0 :         return;
   16794              : 
   16795              :     /* Search for comments associated with relation, using table */
   16796            0 :     nlabels = findSecLabels(tbinfo->dobj.catId.tableoid,
   16797            0 :                             tbinfo->dobj.catId.oid,
   16798              :                             &labels);
   16799              : 
   16800              :     /* If security labels exist, build SECURITY LABEL statements */
   16801            0 :     if (nlabels <= 0)
   16802            0 :         return;
   16803              : 
   16804            0 :     query = createPQExpBuffer();
   16805            0 :     target = createPQExpBuffer();
   16806              : 
   16807            0 :     for (i = 0; i < nlabels; i++)
   16808              :     {
   16809              :         const char *colname;
   16810            0 :         const char *provider = labels[i].provider;
   16811            0 :         const char *label = labels[i].label;
   16812            0 :         int         objsubid = labels[i].objsubid;
   16813              : 
   16814            0 :         resetPQExpBuffer(target);
   16815            0 :         if (objsubid == 0)
   16816              :         {
   16817            0 :             appendPQExpBuffer(target, "%s %s", reltypename,
   16818            0 :                               fmtQualifiedDumpable(tbinfo));
   16819              :         }
   16820              :         else
   16821              :         {
   16822            0 :             colname = getAttrName(objsubid, tbinfo);
   16823              :             /* first fmtXXX result must be consumed before calling again */
   16824            0 :             appendPQExpBuffer(target, "COLUMN %s",
   16825            0 :                               fmtQualifiedDumpable(tbinfo));
   16826            0 :             appendPQExpBuffer(target, ".%s", fmtId(colname));
   16827              :         }
   16828            0 :         appendPQExpBuffer(query, "SECURITY LABEL FOR %s ON %s IS ",
   16829              :                           fmtId(provider), target->data);
   16830            0 :         appendStringLiteralAH(query, label, fout);
   16831            0 :         appendPQExpBufferStr(query, ";\n");
   16832              :     }
   16833            0 :     if (query->len > 0)
   16834              :     {
   16835            0 :         resetPQExpBuffer(target);
   16836            0 :         appendPQExpBuffer(target, "%s %s", reltypename,
   16837            0 :                           fmtId(tbinfo->dobj.name));
   16838            0 :         ArchiveEntry(fout, nilCatalogId, createDumpId(),
   16839            0 :                      ARCHIVE_OPTS(.tag = target->data,
   16840              :                                   .namespace = tbinfo->dobj.namespace->dobj.name,
   16841              :                                   .owner = tbinfo->rolname,
   16842              :                                   .description = "SECURITY LABEL",
   16843              :                                   .section = SECTION_NONE,
   16844              :                                   .createStmt = query->data,
   16845              :                                   .deps = &(tbinfo->dobj.dumpId),
   16846              :                                   .nDeps = 1));
   16847              :     }
   16848            0 :     destroyPQExpBuffer(query);
   16849            0 :     destroyPQExpBuffer(target);
   16850              : }
   16851              : 
   16852              : /*
   16853              :  * findSecLabels
   16854              :  *
   16855              :  * Find the security label(s), if any, associated with the given object.
   16856              :  * All the objsubid values associated with the given classoid/objoid are
   16857              :  * found with one search.
   16858              :  */
   16859              : static int
   16860           10 : findSecLabels(Oid classoid, Oid objoid, SecLabelItem **items)
   16861              : {
   16862           10 :     SecLabelItem *middle = NULL;
   16863              :     SecLabelItem *low;
   16864              :     SecLabelItem *high;
   16865              :     int         nmatch;
   16866              : 
   16867           10 :     if (nseclabels <= 0)     /* no labels, so no match is possible */
   16868              :     {
   16869            0 :         *items = NULL;
   16870            0 :         return 0;
   16871              :     }
   16872              : 
   16873              :     /*
   16874              :      * Do binary search to find some item matching the object.
   16875              :      */
   16876           10 :     low = &seclabels[0];
   16877           10 :     high = &seclabels[nseclabels - 1];
   16878           15 :     while (low <= high)
   16879              :     {
   16880           10 :         middle = low + (high - low) / 2;
   16881              : 
   16882           10 :         if (classoid < middle->classoid)
   16883            0 :             high = middle - 1;
   16884           10 :         else if (classoid > middle->classoid)
   16885            0 :             low = middle + 1;
   16886           10 :         else if (objoid < middle->objoid)
   16887            5 :             high = middle - 1;
   16888            5 :         else if (objoid > middle->objoid)
   16889            0 :             low = middle + 1;
   16890              :         else
   16891            5 :             break;              /* found a match */
   16892              :     }
   16893              : 
   16894           10 :     if (low > high)              /* no matches */
   16895              :     {
   16896            5 :         *items = NULL;
   16897            5 :         return 0;
   16898              :     }
   16899              : 
   16900              :     /*
   16901              :      * Now determine how many items match the object.  The search loop
   16902              :      * invariant still holds: only items between low and high inclusive could
   16903              :      * match.
   16904              :      */
   16905            5 :     nmatch = 1;
   16906            5 :     while (middle > low)
   16907              :     {
   16908            0 :         if (classoid != middle[-1].classoid ||
   16909            0 :             objoid != middle[-1].objoid)
   16910              :             break;
   16911            0 :         middle--;
   16912            0 :         nmatch++;
   16913              :     }
   16914              : 
   16915            5 :     *items = middle;
   16916              : 
   16917            5 :     middle += nmatch;
   16918            5 :     while (middle <= high)
   16919              :     {
   16920            0 :         if (classoid != middle->classoid ||
   16921            0 :             objoid != middle->objoid)
   16922              :             break;
   16923            0 :         middle++;
   16924            0 :         nmatch++;
   16925              :     }
   16926              : 
   16927            5 :     return nmatch;
   16928              : }
   16929              : 
   16930              : /*
   16931              :  * collectSecLabels
   16932              :  *
   16933              :  * Construct a table of all security labels available for database objects;
   16934              :  * also set the has-seclabel component flag for each relevant object.
   16935              :  *
   16936              :  * The table is sorted by classoid/objid/objsubid for speed in lookup.
   16937              :  */
   16938              : static void
   16939          259 : collectSecLabels(Archive *fout)
   16940              : {
   16941              :     PGresult   *res;
   16942              :     PQExpBuffer query;
   16943              :     int         i_label;
   16944              :     int         i_provider;
   16945              :     int         i_classoid;
   16946              :     int         i_objoid;
   16947              :     int         i_objsubid;
   16948              :     int         ntups;
   16949              :     int         i;
   16950              :     DumpableObject *dobj;
   16951              : 
   16952          259 :     query = createPQExpBuffer();
   16953              : 
   16954          259 :     appendPQExpBufferStr(query,
   16955              :                          "SELECT label, provider, classoid, objoid, objsubid "
   16956              :                          "FROM pg_catalog.pg_seclabels "
   16957              :                          "ORDER BY classoid, objoid, objsubid");
   16958              : 
   16959          259 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   16960              : 
   16961              :     /* Construct lookup table containing OIDs in numeric form */
   16962          259 :     i_label = PQfnumber(res, "label");
   16963          259 :     i_provider = PQfnumber(res, "provider");
   16964          259 :     i_classoid = PQfnumber(res, "classoid");
   16965          259 :     i_objoid = PQfnumber(res, "objoid");
   16966          259 :     i_objsubid = PQfnumber(res, "objsubid");
   16967              : 
   16968          259 :     ntups = PQntuples(res);
   16969              : 
   16970          259 :     seclabels = pg_malloc_array(SecLabelItem, ntups);
   16971          259 :     nseclabels = 0;
   16972          259 :     dobj = NULL;
   16973              : 
   16974          264 :     for (i = 0; i < ntups; i++)
   16975              :     {
   16976              :         CatalogId   objId;
   16977              :         int         subid;
   16978              : 
   16979            5 :         objId.tableoid = atooid(PQgetvalue(res, i, i_classoid));
   16980            5 :         objId.oid = atooid(PQgetvalue(res, i, i_objoid));
   16981            5 :         subid = atoi(PQgetvalue(res, i, i_objsubid));
   16982              : 
   16983              :         /* We needn't remember labels that don't match any dumpable object */
   16984            5 :         if (dobj == NULL ||
   16985            0 :             dobj->catId.tableoid != objId.tableoid ||
   16986            0 :             dobj->catId.oid != objId.oid)
   16987            5 :             dobj = findObjectByCatalogId(objId);
   16988            5 :         if (dobj == NULL)
   16989            0 :             continue;
   16990              : 
   16991              :         /*
   16992              :          * Labels on columns of composite types are linked to the type's
   16993              :          * pg_class entry, but we need to set the DUMP_COMPONENT_SECLABEL flag
   16994              :          * in the type's own DumpableObject.
   16995              :          */
   16996            5 :         if (subid != 0 && dobj->objType == DO_TABLE &&
   16997            0 :             ((TableInfo *) dobj)->relkind == RELKIND_COMPOSITE_TYPE)
   16998            0 :         {
   16999              :             TypeInfo   *cTypeInfo;
   17000              : 
   17001            0 :             cTypeInfo = findTypeByOid(((TableInfo *) dobj)->reltype);
   17002            0 :             if (cTypeInfo)
   17003            0 :                 cTypeInfo->dobj.components |= DUMP_COMPONENT_SECLABEL;
   17004              :         }
   17005              :         else
   17006            5 :             dobj->components |= DUMP_COMPONENT_SECLABEL;
   17007              : 
   17008            5 :         seclabels[nseclabels].label = pg_strdup(PQgetvalue(res, i, i_label));
   17009            5 :         seclabels[nseclabels].provider = pg_strdup(PQgetvalue(res, i, i_provider));
   17010            5 :         seclabels[nseclabels].classoid = objId.tableoid;
   17011            5 :         seclabels[nseclabels].objoid = objId.oid;
   17012            5 :         seclabels[nseclabels].objsubid = subid;
   17013            5 :         nseclabels++;
   17014              :     }
   17015              : 
   17016          259 :     PQclear(res);
   17017          259 :     destroyPQExpBuffer(query);
   17018          259 : }
   17019              : 
   17020              : /*
   17021              :  * dumpTable
   17022              :  *    write out to fout the declarations (not data) of a user-defined table
   17023              :  */
   17024              : static void
   17025        44759 : dumpTable(Archive *fout, const TableInfo *tbinfo)
   17026              : {
   17027        44759 :     DumpOptions *dopt = fout->dopt;
   17028        44759 :     DumpId      tableAclDumpId = InvalidDumpId;
   17029              :     char       *namecopy;
   17030              : 
   17031              :     /* Do nothing if not dumping schema */
   17032        44759 :     if (!dopt->dumpSchema)
   17033         1612 :         return;
   17034              : 
   17035        43147 :     if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   17036              :     {
   17037         7270 :         if (tbinfo->relkind == RELKIND_SEQUENCE)
   17038          384 :             dumpSequence(fout, tbinfo);
   17039              :         else
   17040         6886 :             dumpTableSchema(fout, tbinfo);
   17041              :     }
   17042              : 
   17043              :     /* Handle the ACL here */
   17044        43147 :     namecopy = pg_strdup(fmtId(tbinfo->dobj.name));
   17045        43147 :     if (tbinfo->dobj.dump & DUMP_COMPONENT_ACL)
   17046              :     {
   17047              :         const char *objtype;
   17048              : 
   17049        36708 :         switch (tbinfo->relkind)
   17050              :         {
   17051           99 :             case RELKIND_SEQUENCE:
   17052           99 :                 objtype = "SEQUENCE";
   17053           99 :                 break;
   17054           37 :             case RELKIND_PROPGRAPH:
   17055           37 :                 objtype = "PROPERTY GRAPH";
   17056           37 :                 break;
   17057        36572 :             default:
   17058        36572 :                 objtype = "TABLE";
   17059        36572 :                 break;
   17060              :         }
   17061              : 
   17062              :         tableAclDumpId =
   17063        36708 :             dumpACL(fout, tbinfo->dobj.dumpId, InvalidDumpId,
   17064              :                     objtype, namecopy, NULL,
   17065        36708 :                     tbinfo->dobj.namespace->dobj.name,
   17066        36708 :                     NULL, tbinfo->rolname, &tbinfo->dacl);
   17067              :     }
   17068              : 
   17069              :     /*
   17070              :      * Handle column ACLs, if any.  Note: we pull these with a separate query
   17071              :      * rather than trying to fetch them during getTableAttrs, so that we won't
   17072              :      * miss ACLs on system columns.  Doing it this way also allows us to dump
   17073              :      * ACLs for catalogs that we didn't mark "interesting" back in getTables.
   17074              :      */
   17075        43147 :     if ((tbinfo->dobj.dump & DUMP_COMPONENT_ACL) && tbinfo->hascolumnACLs)
   17076              :     {
   17077          354 :         PQExpBuffer query = createPQExpBuffer();
   17078              :         PGresult   *res;
   17079              :         int         i;
   17080              : 
   17081          354 :         if (!fout->is_prepared[PREPQUERY_GETCOLUMNACLS])
   17082              :         {
   17083              :             /* Set up query for column ACLs */
   17084          233 :             appendPQExpBufferStr(query,
   17085              :                                  "PREPARE getColumnACLs(pg_catalog.oid) AS\n");
   17086              : 
   17087          233 :             if (fout->remoteVersion >= 90600)
   17088              :             {
   17089              :                 /*
   17090              :                  * In principle we should call acldefault('c', relowner) to
   17091              :                  * get the default ACL for a column.  However, we don't
   17092              :                  * currently store the numeric OID of the relowner in
   17093              :                  * TableInfo.  We could convert the owner name using regrole,
   17094              :                  * but that creates a risk of failure due to concurrent role
   17095              :                  * renames.  Given that the default ACL for columns is empty
   17096              :                  * and is likely to stay that way, it's not worth extra cycles
   17097              :                  * and risk to avoid hard-wiring that knowledge here.
   17098              :                  */
   17099          233 :                 appendPQExpBufferStr(query,
   17100              :                                      "SELECT at.attname, "
   17101              :                                      "at.attacl, "
   17102              :                                      "'{}' AS acldefault, "
   17103              :                                      "pip.privtype, pip.initprivs "
   17104              :                                      "FROM pg_catalog.pg_attribute at "
   17105              :                                      "LEFT JOIN pg_catalog.pg_init_privs pip ON "
   17106              :                                      "(at.attrelid = pip.objoid "
   17107              :                                      "AND pip.classoid = 'pg_catalog.pg_class'::pg_catalog.regclass "
   17108              :                                      "AND at.attnum = pip.objsubid) "
   17109              :                                      "WHERE at.attrelid = $1 AND "
   17110              :                                      "NOT at.attisdropped "
   17111              :                                      "AND (at.attacl IS NOT NULL OR pip.initprivs IS NOT NULL) "
   17112              :                                      "ORDER BY at.attnum");
   17113              :             }
   17114              :             else
   17115              :             {
   17116            0 :                 appendPQExpBufferStr(query,
   17117              :                                      "SELECT attname, attacl, '{}' AS acldefault, "
   17118              :                                      "NULL AS privtype, NULL AS initprivs "
   17119              :                                      "FROM pg_catalog.pg_attribute "
   17120              :                                      "WHERE attrelid = $1 AND NOT attisdropped "
   17121              :                                      "AND attacl IS NOT NULL "
   17122              :                                      "ORDER BY attnum");
   17123              :             }
   17124              : 
   17125          233 :             ExecuteSqlStatement(fout, query->data);
   17126              : 
   17127          233 :             fout->is_prepared[PREPQUERY_GETCOLUMNACLS] = true;
   17128              :         }
   17129              : 
   17130          354 :         printfPQExpBuffer(query,
   17131              :                           "EXECUTE getColumnACLs('%u')",
   17132          354 :                           tbinfo->dobj.catId.oid);
   17133              : 
   17134          354 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   17135              : 
   17136         6231 :         for (i = 0; i < PQntuples(res); i++)
   17137              :         {
   17138         5877 :             char       *attname = PQgetvalue(res, i, 0);
   17139         5877 :             char       *attacl = PQgetvalue(res, i, 1);
   17140         5877 :             char       *acldefault = PQgetvalue(res, i, 2);
   17141         5877 :             char        privtype = *(PQgetvalue(res, i, 3));
   17142         5877 :             char       *initprivs = PQgetvalue(res, i, 4);
   17143              :             DumpableAcl coldacl;
   17144              :             char       *attnamecopy;
   17145              : 
   17146         5877 :             coldacl.acl = attacl;
   17147         5877 :             coldacl.acldefault = acldefault;
   17148         5877 :             coldacl.privtype = privtype;
   17149         5877 :             coldacl.initprivs = initprivs;
   17150         5877 :             attnamecopy = pg_strdup(fmtId(attname));
   17151              : 
   17152              :             /*
   17153              :              * Column's GRANT type is always TABLE.  Each column ACL depends
   17154              :              * on the table-level ACL, since we can restore column ACLs in
   17155              :              * parallel but the table-level ACL has to be done first.
   17156              :              */
   17157         5877 :             dumpACL(fout, tbinfo->dobj.dumpId, tableAclDumpId,
   17158              :                     "TABLE", namecopy, attnamecopy,
   17159         5877 :                     tbinfo->dobj.namespace->dobj.name,
   17160         5877 :                     NULL, tbinfo->rolname, &coldacl);
   17161         5877 :             free(attnamecopy);
   17162              :         }
   17163          354 :         PQclear(res);
   17164          354 :         destroyPQExpBuffer(query);
   17165              :     }
   17166              : 
   17167        43147 :     free(namecopy);
   17168              : }
   17169              : 
   17170              : /*
   17171              :  * Create the AS clause for a view or materialized view. The semicolon is
   17172              :  * stripped because a materialized view must add a WITH NO DATA clause.
   17173              :  *
   17174              :  * This returns a new buffer which must be freed by the caller.
   17175              :  */
   17176              : static PQExpBuffer
   17177          903 : createViewAsClause(Archive *fout, const TableInfo *tbinfo)
   17178              : {
   17179          903 :     PQExpBuffer query = createPQExpBuffer();
   17180          903 :     PQExpBuffer result = createPQExpBuffer();
   17181              :     PGresult   *res;
   17182              :     int         len;
   17183              : 
   17184              :     /* Fetch the view definition */
   17185          903 :     appendPQExpBuffer(query,
   17186              :                       "SELECT pg_catalog.pg_get_viewdef('%u'::pg_catalog.oid) AS viewdef",
   17187          903 :                       tbinfo->dobj.catId.oid);
   17188              : 
   17189          903 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   17190              : 
   17191          903 :     if (PQntuples(res) != 1)
   17192              :     {
   17193            0 :         if (PQntuples(res) < 1)
   17194            0 :             pg_fatal("query to obtain definition of view \"%s\" returned no data",
   17195              :                      tbinfo->dobj.name);
   17196              :         else
   17197            0 :             pg_fatal("query to obtain definition of view \"%s\" returned more than one definition",
   17198              :                      tbinfo->dobj.name);
   17199              :     }
   17200              : 
   17201          903 :     len = PQgetlength(res, 0, 0);
   17202              : 
   17203          903 :     if (len == 0)
   17204            0 :         pg_fatal("definition of view \"%s\" appears to be empty (length zero)",
   17205              :                  tbinfo->dobj.name);
   17206              : 
   17207              :     /* Strip off the trailing semicolon so that other things may follow. */
   17208              :     Assert(PQgetvalue(res, 0, 0)[len - 1] == ';');
   17209          903 :     appendBinaryPQExpBuffer(result, PQgetvalue(res, 0, 0), len - 1);
   17210              : 
   17211          903 :     PQclear(res);
   17212          903 :     destroyPQExpBuffer(query);
   17213              : 
   17214          903 :     return result;
   17215              : }
   17216              : 
   17217              : /*
   17218              :  * Create a dummy AS clause for a view.  This is used when the real view
   17219              :  * definition has to be postponed because of circular dependencies.
   17220              :  * We must duplicate the view's external properties -- column names and types
   17221              :  * (including collation) -- so that it works for subsequent references.
   17222              :  *
   17223              :  * This returns a new buffer which must be freed by the caller.
   17224              :  */
   17225              : static PQExpBuffer
   17226           20 : createDummyViewAsClause(Archive *fout, const TableInfo *tbinfo)
   17227              : {
   17228           20 :     PQExpBuffer result = createPQExpBuffer();
   17229              :     int         j;
   17230              : 
   17231           20 :     appendPQExpBufferStr(result, "SELECT");
   17232              : 
   17233           40 :     for (j = 0; j < tbinfo->numatts; j++)
   17234              :     {
   17235           20 :         if (j > 0)
   17236           10 :             appendPQExpBufferChar(result, ',');
   17237           20 :         appendPQExpBufferStr(result, "\n    ");
   17238              : 
   17239           20 :         appendPQExpBuffer(result, "NULL::%s", tbinfo->atttypnames[j]);
   17240              : 
   17241              :         /*
   17242              :          * Must add collation if not default for the type, because CREATE OR
   17243              :          * REPLACE VIEW won't change it
   17244              :          */
   17245           20 :         if (OidIsValid(tbinfo->attcollation[j]))
   17246              :         {
   17247              :             CollInfo   *coll;
   17248              : 
   17249            0 :             coll = findCollationByOid(tbinfo->attcollation[j]);
   17250            0 :             if (coll)
   17251            0 :                 appendPQExpBuffer(result, " COLLATE %s",
   17252            0 :                                   fmtQualifiedDumpable(coll));
   17253              :         }
   17254              : 
   17255           20 :         appendPQExpBuffer(result, " AS %s", fmtId(tbinfo->attnames[j]));
   17256              :     }
   17257              : 
   17258           20 :     return result;
   17259              : }
   17260              : 
   17261              : /*
   17262              :  * dumpTableSchema
   17263              :  *    write the declaration (not data) of one user-defined table or view
   17264              :  */
   17265              : static void
   17266         6886 : dumpTableSchema(Archive *fout, const TableInfo *tbinfo)
   17267              : {
   17268         6886 :     DumpOptions *dopt = fout->dopt;
   17269         6886 :     PQExpBuffer q = createPQExpBuffer();
   17270         6886 :     PQExpBuffer delq = createPQExpBuffer();
   17271         6886 :     PQExpBuffer extra = createPQExpBuffer();
   17272              :     char       *qrelname;
   17273              :     char       *qualrelname;
   17274              :     int         numParents;
   17275              :     TableInfo **parents;
   17276              :     int         actual_atts;    /* number of attrs in this CREATE statement */
   17277              :     const char *reltypename;
   17278              :     char       *storage;
   17279              :     int         j,
   17280              :                 k;
   17281              : 
   17282              :     /* We had better have loaded per-column details about this table */
   17283              :     Assert(tbinfo->interesting);
   17284              : 
   17285         6886 :     qrelname = pg_strdup(fmtId(tbinfo->dobj.name));
   17286         6886 :     qualrelname = pg_strdup(fmtQualifiedDumpable(tbinfo));
   17287              : 
   17288         6886 :     if (tbinfo->hasoids)
   17289            0 :         pg_log_warning("WITH OIDS is not supported anymore (table \"%s\")",
   17290              :                        qrelname);
   17291              : 
   17292         6886 :     if (dopt->binary_upgrade)
   17293          948 :         binary_upgrade_set_type_oids_by_rel(fout, q, tbinfo);
   17294              : 
   17295              :     /* Is it a table or a view? */
   17296         6886 :     if (tbinfo->relkind == RELKIND_VIEW)
   17297              :     {
   17298              :         PQExpBuffer result;
   17299              : 
   17300              :         /*
   17301              :          * Note: keep this code in sync with the is_view case in dumpRule()
   17302              :          */
   17303              : 
   17304          568 :         reltypename = "VIEW";
   17305              : 
   17306          568 :         if (dopt->binary_upgrade)
   17307           56 :             binary_upgrade_set_pg_class_oids(fout, q,
   17308           56 :                                              tbinfo->dobj.catId.oid);
   17309              : 
   17310          568 :         appendPQExpBuffer(q, "CREATE VIEW %s", qualrelname);
   17311              : 
   17312          568 :         if (tbinfo->dummy_view)
   17313           10 :             result = createDummyViewAsClause(fout, tbinfo);
   17314              :         else
   17315              :         {
   17316          558 :             if (nonemptyReloptions(tbinfo->reloptions))
   17317              :             {
   17318           61 :                 appendPQExpBufferStr(q, " WITH (");
   17319           61 :                 appendReloptionsArrayAH(q, tbinfo->reloptions, "", fout);
   17320           61 :                 appendPQExpBufferChar(q, ')');
   17321              :             }
   17322          558 :             result = createViewAsClause(fout, tbinfo);
   17323              :         }
   17324          568 :         appendPQExpBuffer(q, " AS\n%s", result->data);
   17325          568 :         destroyPQExpBuffer(result);
   17326              : 
   17327          568 :         if (tbinfo->checkoption != NULL && !tbinfo->dummy_view)
   17328           32 :             appendPQExpBuffer(q, "\n  WITH %s CHECK OPTION", tbinfo->checkoption);
   17329          568 :         appendPQExpBufferStr(q, ";\n");
   17330              :     }
   17331         6318 :     else if (tbinfo->relkind == RELKIND_PROPGRAPH)
   17332              :     {
   17333           97 :         PQExpBuffer query = createPQExpBuffer();
   17334              :         PGresult   *res;
   17335              :         int         len;
   17336              : 
   17337           97 :         reltypename = "PROPERTY GRAPH";
   17338              : 
   17339           97 :         if (dopt->binary_upgrade)
   17340           14 :             binary_upgrade_set_pg_class_oids(fout, q,
   17341           14 :                                              tbinfo->dobj.catId.oid);
   17342              : 
   17343           97 :         appendPQExpBuffer(query,
   17344              :                           "SELECT pg_catalog.pg_get_propgraphdef('%u'::pg_catalog.oid) AS pgdef",
   17345           97 :                           tbinfo->dobj.catId.oid);
   17346              : 
   17347           97 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   17348              : 
   17349           97 :         if (PQntuples(res) != 1)
   17350              :         {
   17351            0 :             if (PQntuples(res) < 1)
   17352            0 :                 pg_fatal("query to obtain definition of property graph \"%s\" returned no data",
   17353              :                          tbinfo->dobj.name);
   17354              :             else
   17355            0 :                 pg_fatal("query to obtain definition of property graph \"%s\" returned more than one definition",
   17356              :                          tbinfo->dobj.name);
   17357              :         }
   17358              : 
   17359           97 :         len = PQgetlength(res, 0, 0);
   17360              : 
   17361           97 :         if (len == 0)
   17362            0 :             pg_fatal("definition of property graph \"%s\" appears to be empty (length zero)",
   17363              :                      tbinfo->dobj.name);
   17364              : 
   17365           97 :         appendPQExpBufferStr(q, PQgetvalue(res, 0, 0));
   17366              : 
   17367           97 :         PQclear(res);
   17368           97 :         destroyPQExpBuffer(query);
   17369              : 
   17370           97 :         appendPQExpBufferStr(q, ";\n");
   17371              :     }
   17372              :     else
   17373              :     {
   17374         6221 :         char       *partkeydef = NULL;
   17375         6221 :         char       *ftoptions = NULL;
   17376         6221 :         char       *srvname = NULL;
   17377         6221 :         const char *foreign = "";
   17378              : 
   17379              :         /*
   17380              :          * Set reltypename, and collect any relkind-specific data that we
   17381              :          * didn't fetch during getTables().
   17382              :          */
   17383         6221 :         switch (tbinfo->relkind)
   17384              :         {
   17385          596 :             case RELKIND_PARTITIONED_TABLE:
   17386              :                 {
   17387          596 :                     PQExpBuffer query = createPQExpBuffer();
   17388              :                     PGresult   *res;
   17389              : 
   17390          596 :                     reltypename = "TABLE";
   17391              : 
   17392              :                     /* retrieve partition key definition */
   17393          596 :                     appendPQExpBuffer(query,
   17394              :                                       "SELECT pg_get_partkeydef('%u')",
   17395          596 :                                       tbinfo->dobj.catId.oid);
   17396          596 :                     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   17397          596 :                     partkeydef = pg_strdup(PQgetvalue(res, 0, 0));
   17398          596 :                     PQclear(res);
   17399          596 :                     destroyPQExpBuffer(query);
   17400          596 :                     break;
   17401              :                 }
   17402           34 :             case RELKIND_FOREIGN_TABLE:
   17403              :                 {
   17404           34 :                     PQExpBuffer query = createPQExpBuffer();
   17405              :                     PGresult   *res;
   17406              :                     int         i_srvname;
   17407              :                     int         i_ftoptions;
   17408              : 
   17409           34 :                     reltypename = "FOREIGN TABLE";
   17410              : 
   17411              :                     /* retrieve name of foreign server and generic options */
   17412           34 :                     appendPQExpBuffer(query,
   17413              :                                       "SELECT fs.srvname, "
   17414              :                                       "pg_catalog.array_to_string(ARRAY("
   17415              :                                       "SELECT pg_catalog.quote_ident(option_name) || "
   17416              :                                       "' ' || pg_catalog.quote_literal(option_value) "
   17417              :                                       "FROM pg_catalog.pg_options_to_table(ftoptions) "
   17418              :                                       "ORDER BY option_name"
   17419              :                                       "), E',\n    ') AS ftoptions "
   17420              :                                       "FROM pg_catalog.pg_foreign_table ft "
   17421              :                                       "JOIN pg_catalog.pg_foreign_server fs "
   17422              :                                       "ON (fs.oid = ft.ftserver) "
   17423              :                                       "WHERE ft.ftrelid = '%u'",
   17424           34 :                                       tbinfo->dobj.catId.oid);
   17425           34 :                     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   17426           34 :                     i_srvname = PQfnumber(res, "srvname");
   17427           34 :                     i_ftoptions = PQfnumber(res, "ftoptions");
   17428           34 :                     srvname = pg_strdup(PQgetvalue(res, 0, i_srvname));
   17429           34 :                     ftoptions = pg_strdup(PQgetvalue(res, 0, i_ftoptions));
   17430           34 :                     PQclear(res);
   17431           34 :                     destroyPQExpBuffer(query);
   17432              : 
   17433           34 :                     foreign = "FOREIGN ";
   17434           34 :                     break;
   17435              :                 }
   17436          335 :             case RELKIND_MATVIEW:
   17437          335 :                 reltypename = "MATERIALIZED VIEW";
   17438          335 :                 break;
   17439         5256 :             default:
   17440         5256 :                 reltypename = "TABLE";
   17441         5256 :                 break;
   17442              :         }
   17443              : 
   17444         6221 :         numParents = tbinfo->numParents;
   17445         6221 :         parents = tbinfo->parents;
   17446              : 
   17447         6221 :         if (dopt->binary_upgrade)
   17448          878 :             binary_upgrade_set_pg_class_oids(fout, q,
   17449          878 :                                              tbinfo->dobj.catId.oid);
   17450              : 
   17451              :         /*
   17452              :          * PostgreSQL 18 has disabled UNLOGGED for partitioned tables, so
   17453              :          * ignore it when dumping if it was set in this case.
   17454              :          */
   17455         6221 :         appendPQExpBuffer(q, "CREATE %s%s %s",
   17456         6221 :                           (tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED &&
   17457           20 :                            tbinfo->relkind != RELKIND_PARTITIONED_TABLE) ?
   17458              :                           "UNLOGGED " : "",
   17459              :                           reltypename,
   17460              :                           qualrelname);
   17461              : 
   17462              :         /*
   17463              :          * Attach to type, if reloftype; except in case of a binary upgrade,
   17464              :          * we dump the table normally and attach it to the type afterward.
   17465              :          */
   17466         6221 :         if (OidIsValid(tbinfo->reloftype) && !dopt->binary_upgrade)
   17467           24 :             appendPQExpBuffer(q, " OF %s",
   17468           24 :                               getFormattedTypeName(fout, tbinfo->reloftype,
   17469              :                                                    zeroIsError));
   17470              : 
   17471         6221 :         if (tbinfo->relkind != RELKIND_MATVIEW)
   17472              :         {
   17473              :             /* Dump the attributes */
   17474         5886 :             actual_atts = 0;
   17475        27121 :             for (j = 0; j < tbinfo->numatts; j++)
   17476              :             {
   17477              :                 /*
   17478              :                  * Normally, dump if it's locally defined in this table, and
   17479              :                  * not dropped.  But for binary upgrade, we'll dump all the
   17480              :                  * columns, and then fix up the dropped and nonlocal cases
   17481              :                  * below.
   17482              :                  */
   17483        21235 :                 if (shouldPrintColumn(dopt, tbinfo, j))
   17484              :                 {
   17485              :                     bool        print_default;
   17486              :                     bool        print_notnull;
   17487              : 
   17488              :                     /*
   17489              :                      * Default value --- suppress if to be printed separately
   17490              :                      * or not at all.
   17491              :                      */
   17492        41374 :                     print_default = (tbinfo->attrdefs[j] != NULL &&
   17493        21189 :                                      tbinfo->attrdefs[j]->dobj.dump &&
   17494         1051 :                                      !tbinfo->attrdefs[j]->separate);
   17495              : 
   17496              :                     /*
   17497              :                      * Not Null constraint --- print it if it is locally
   17498              :                      * defined, or if binary upgrade.  (In the latter case, we
   17499              :                      * reset conislocal below.)
   17500              :                      */
   17501        22597 :                     print_notnull = (tbinfo->notnull_constrs[j] != NULL &&
   17502         2459 :                                      (tbinfo->notnull_islocal[j] ||
   17503          657 :                                       dopt->binary_upgrade ||
   17504          563 :                                       tbinfo->ispartition));
   17505              : 
   17506              :                     /*
   17507              :                      * Skip column if fully defined by reloftype, except in
   17508              :                      * binary upgrade
   17509              :                      */
   17510        20138 :                     if (OidIsValid(tbinfo->reloftype) &&
   17511           50 :                         !print_default && !print_notnull &&
   17512           30 :                         !dopt->binary_upgrade)
   17513           24 :                         continue;
   17514              : 
   17515              :                     /* Format properly if not first attr */
   17516        20114 :                     if (actual_atts == 0)
   17517         5513 :                         appendPQExpBufferStr(q, " (");
   17518              :                     else
   17519        14601 :                         appendPQExpBufferChar(q, ',');
   17520        20114 :                     appendPQExpBufferStr(q, "\n    ");
   17521        20114 :                     actual_atts++;
   17522              : 
   17523              :                     /* Attribute name */
   17524        20114 :                     appendPQExpBufferStr(q, fmtId(tbinfo->attnames[j]));
   17525              : 
   17526        20114 :                     if (tbinfo->attisdropped[j])
   17527              :                     {
   17528              :                         /*
   17529              :                          * ALTER TABLE DROP COLUMN clears
   17530              :                          * pg_attribute.atttypid, so we will not have gotten a
   17531              :                          * valid type name; insert INTEGER as a stopgap. We'll
   17532              :                          * clean things up later.
   17533              :                          */
   17534           85 :                         appendPQExpBufferStr(q, " INTEGER /* dummy */");
   17535              :                         /* and skip to the next column */
   17536           85 :                         continue;
   17537              :                     }
   17538              : 
   17539              :                     /*
   17540              :                      * Attribute type; print it except when creating a typed
   17541              :                      * table ('OF type_name'), but in binary-upgrade mode,
   17542              :                      * print it in that case too.
   17543              :                      */
   17544        20029 :                     if (dopt->binary_upgrade || !OidIsValid(tbinfo->reloftype))
   17545              :                     {
   17546        20013 :                         appendPQExpBuffer(q, " %s",
   17547        20013 :                                           tbinfo->atttypnames[j]);
   17548              :                     }
   17549              : 
   17550        20029 :                     if (print_default)
   17551              :                     {
   17552          921 :                         if (tbinfo->attgenerated[j] == ATTRIBUTE_GENERATED_STORED)
   17553          317 :                             appendPQExpBuffer(q, " GENERATED ALWAYS AS (%s) STORED",
   17554          317 :                                               tbinfo->attrdefs[j]->adef_expr);
   17555          604 :                         else if (tbinfo->attgenerated[j] == ATTRIBUTE_GENERATED_VIRTUAL)
   17556          223 :                             appendPQExpBuffer(q, " GENERATED ALWAYS AS (%s)",
   17557          223 :                                               tbinfo->attrdefs[j]->adef_expr);
   17558              :                         else
   17559          381 :                             appendPQExpBuffer(q, " DEFAULT %s",
   17560          381 :                                               tbinfo->attrdefs[j]->adef_expr);
   17561              :                     }
   17562              : 
   17563        20029 :                     if (print_notnull)
   17564              :                     {
   17565         2428 :                         if (tbinfo->notnull_constrs[j][0] == '\0')
   17566         1743 :                             appendPQExpBufferStr(q, " NOT NULL");
   17567              :                         else
   17568          685 :                             appendPQExpBuffer(q, " CONSTRAINT %s NOT NULL",
   17569          685 :                                               fmtId(tbinfo->notnull_constrs[j]));
   17570              : 
   17571         2428 :                         if (tbinfo->notnull_noinh[j])
   17572           33 :                             appendPQExpBufferStr(q, " NO INHERIT");
   17573              :                     }
   17574              : 
   17575              :                     /* Add collation if not default for the type */
   17576        20029 :                     if (OidIsValid(tbinfo->attcollation[j]))
   17577              :                     {
   17578              :                         CollInfo   *coll;
   17579              : 
   17580          213 :                         coll = findCollationByOid(tbinfo->attcollation[j]);
   17581          213 :                         if (coll)
   17582          213 :                             appendPQExpBuffer(q, " COLLATE %s",
   17583          213 :                                               fmtQualifiedDumpable(coll));
   17584              :                     }
   17585              :                 }
   17586              : 
   17587              :                 /*
   17588              :                  * On the other hand, if we choose not to print a column
   17589              :                  * (likely because it is created by inheritance), but the
   17590              :                  * column has a locally-defined not-null constraint, we need
   17591              :                  * to dump the constraint as a standalone object.
   17592              :                  *
   17593              :                  * This syntax isn't SQL-conforming, but if you wanted
   17594              :                  * standard output you wouldn't be creating non-standard
   17595              :                  * objects to begin with.
   17596              :                  */
   17597        21126 :                 if (!shouldPrintColumn(dopt, tbinfo, j) &&
   17598         1097 :                     !tbinfo->attisdropped[j] &&
   17599          730 :                     tbinfo->notnull_constrs[j] != NULL &&
   17600          208 :                     tbinfo->notnull_islocal[j])
   17601              :                 {
   17602              :                     /* Format properly if not first attr */
   17603           90 :                     if (actual_atts == 0)
   17604           86 :                         appendPQExpBufferStr(q, " (");
   17605              :                     else
   17606            4 :                         appendPQExpBufferChar(q, ',');
   17607           90 :                     appendPQExpBufferStr(q, "\n    ");
   17608           90 :                     actual_atts++;
   17609              : 
   17610           90 :                     if (tbinfo->notnull_constrs[j][0] == '\0')
   17611            8 :                         appendPQExpBuffer(q, "NOT NULL %s",
   17612            8 :                                           fmtId(tbinfo->attnames[j]));
   17613              :                     else
   17614          164 :                         appendPQExpBuffer(q, "CONSTRAINT %s NOT NULL %s",
   17615           82 :                                           tbinfo->notnull_constrs[j],
   17616           82 :                                           fmtId(tbinfo->attnames[j]));
   17617              : 
   17618           90 :                     if (tbinfo->notnull_noinh[j])
   17619           31 :                         appendPQExpBufferStr(q, " NO INHERIT");
   17620              :                 }
   17621              :             }
   17622              : 
   17623              :             /*
   17624              :              * Add non-inherited CHECK constraints, if any.
   17625              :              *
   17626              :              * For partitions, we need to include check constraints even if
   17627              :              * they're not defined locally, because the ALTER TABLE ATTACH
   17628              :              * PARTITION that we'll emit later expects the constraint to be
   17629              :              * there.  (No need to fix conislocal: ATTACH PARTITION does that)
   17630              :              */
   17631         6459 :             for (j = 0; j < tbinfo->ncheck; j++)
   17632              :             {
   17633          573 :                 ConstraintInfo *constr = &(tbinfo->checkexprs[j]);
   17634              : 
   17635          573 :                 if (constr->separate ||
   17636          503 :                     (!constr->conislocal && !tbinfo->ispartition))
   17637          107 :                     continue;
   17638              : 
   17639          466 :                 if (actual_atts == 0)
   17640           16 :                     appendPQExpBufferStr(q, " (\n    ");
   17641              :                 else
   17642          450 :                     appendPQExpBufferStr(q, ",\n    ");
   17643              : 
   17644          466 :                 appendPQExpBuffer(q, "CONSTRAINT %s ",
   17645          466 :                                   fmtId(constr->dobj.name));
   17646          466 :                 appendPQExpBufferStr(q, constr->condef);
   17647              : 
   17648          466 :                 actual_atts++;
   17649              :             }
   17650              : 
   17651         5886 :             if (actual_atts)
   17652         5615 :                 appendPQExpBufferStr(q, "\n)");
   17653          271 :             else if (!(OidIsValid(tbinfo->reloftype) && !dopt->binary_upgrade))
   17654              :             {
   17655              :                 /*
   17656              :                  * No attributes? we must have a parenthesized attribute list,
   17657              :                  * even though empty, when not using the OF TYPE syntax.
   17658              :                  */
   17659          259 :                 appendPQExpBufferStr(q, " (\n)");
   17660              :             }
   17661              : 
   17662              :             /*
   17663              :              * Emit the INHERITS clause (not for partitions), except in
   17664              :              * binary-upgrade mode.
   17665              :              */
   17666         5886 :             if (numParents > 0 && !tbinfo->ispartition &&
   17667          541 :                 !dopt->binary_upgrade)
   17668              :             {
   17669          472 :                 appendPQExpBufferStr(q, "\nINHERITS (");
   17670         1015 :                 for (k = 0; k < numParents; k++)
   17671              :                 {
   17672          543 :                     TableInfo  *parentRel = parents[k];
   17673              : 
   17674          543 :                     if (k > 0)
   17675           71 :                         appendPQExpBufferStr(q, ", ");
   17676          543 :                     appendPQExpBufferStr(q, fmtQualifiedDumpable(parentRel));
   17677              :                 }
   17678          472 :                 appendPQExpBufferChar(q, ')');
   17679              :             }
   17680              : 
   17681         5886 :             if (tbinfo->relkind == RELKIND_PARTITIONED_TABLE)
   17682          596 :                 appendPQExpBuffer(q, "\nPARTITION BY %s", partkeydef);
   17683              : 
   17684         5886 :             if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
   17685           34 :                 appendPQExpBuffer(q, "\nSERVER %s", fmtId(srvname));
   17686              :         }
   17687              : 
   17688        12289 :         if (nonemptyReloptions(tbinfo->reloptions) ||
   17689         6068 :             nonemptyReloptions(tbinfo->toast_reloptions))
   17690              :         {
   17691          153 :             bool        addcomma = false;
   17692              : 
   17693          153 :             appendPQExpBufferStr(q, "\nWITH (");
   17694          153 :             if (nonemptyReloptions(tbinfo->reloptions))
   17695              :             {
   17696          153 :                 addcomma = true;
   17697          153 :                 appendReloptionsArrayAH(q, tbinfo->reloptions, "", fout);
   17698              :             }
   17699          153 :             if (nonemptyReloptions(tbinfo->toast_reloptions))
   17700              :             {
   17701            5 :                 if (addcomma)
   17702            5 :                     appendPQExpBufferStr(q, ", ");
   17703            5 :                 appendReloptionsArrayAH(q, tbinfo->toast_reloptions, "toast.",
   17704              :                                         fout);
   17705              :             }
   17706          153 :             appendPQExpBufferChar(q, ')');
   17707              :         }
   17708              : 
   17709              :         /* Dump generic options if any */
   17710         6221 :         if (ftoptions && ftoptions[0])
   17711           32 :             appendPQExpBuffer(q, "\nOPTIONS (\n    %s\n)", ftoptions);
   17712              : 
   17713              :         /*
   17714              :          * For materialized views, create the AS clause just like a view. At
   17715              :          * this point, we always mark the view as not populated.
   17716              :          */
   17717         6221 :         if (tbinfo->relkind == RELKIND_MATVIEW)
   17718              :         {
   17719              :             PQExpBuffer result;
   17720              : 
   17721          335 :             result = createViewAsClause(fout, tbinfo);
   17722          335 :             appendPQExpBuffer(q, " AS\n%s\n  WITH NO DATA;\n",
   17723              :                               result->data);
   17724          335 :             destroyPQExpBuffer(result);
   17725              :         }
   17726              :         else
   17727         5886 :             appendPQExpBufferStr(q, ";\n");
   17728              : 
   17729              :         /* Materialized views can depend on extensions */
   17730         6221 :         if (tbinfo->relkind == RELKIND_MATVIEW)
   17731          335 :             append_depends_on_extension(fout, q, &tbinfo->dobj,
   17732              :                                         "pg_catalog.pg_class",
   17733              :                                         "MATERIALIZED VIEW",
   17734              :                                         qualrelname);
   17735              : 
   17736              :         /*
   17737              :          * in binary upgrade mode, update the catalog with any missing values
   17738              :          * that might be present.
   17739              :          */
   17740         6221 :         if (dopt->binary_upgrade)
   17741              :         {
   17742         4209 :             for (j = 0; j < tbinfo->numatts; j++)
   17743              :             {
   17744         3331 :                 if (tbinfo->attmissingval[j][0] != '\0')
   17745              :                 {
   17746            4 :                     appendPQExpBufferStr(q, "\n-- set missing value.\n");
   17747            4 :                     appendPQExpBufferStr(q,
   17748              :                                          "SELECT pg_catalog.binary_upgrade_set_missing_value(");
   17749            4 :                     appendStringLiteralAH(q, qualrelname, fout);
   17750            4 :                     appendPQExpBufferStr(q, "::pg_catalog.regclass,");
   17751            4 :                     appendStringLiteralAH(q, tbinfo->attnames[j], fout);
   17752            4 :                     appendPQExpBufferChar(q, ',');
   17753            4 :                     appendStringLiteralAH(q, tbinfo->attmissingval[j], fout);
   17754            4 :                     appendPQExpBufferStr(q, ");\n\n");
   17755              :                 }
   17756              :             }
   17757              :         }
   17758              : 
   17759              :         /*
   17760              :          * To create binary-compatible heap files, we have to ensure the same
   17761              :          * physical column order, including dropped columns, as in the
   17762              :          * original.  Therefore, we create dropped columns above and drop them
   17763              :          * here, also updating their attlen/attalign values so that the
   17764              :          * dropped column can be skipped properly.  (We do not bother with
   17765              :          * restoring the original attbyval setting.)  Also, inheritance
   17766              :          * relationships are set up by doing ALTER TABLE INHERIT rather than
   17767              :          * using an INHERITS clause --- the latter would possibly mess up the
   17768              :          * column order.  That also means we have to take care about setting
   17769              :          * attislocal correctly, plus fix up any inherited CHECK constraints.
   17770              :          * Analogously, we set up typed tables using ALTER TABLE / OF here.
   17771              :          *
   17772              :          * We process foreign and partitioned tables here, even though they
   17773              :          * lack heap storage, because they can participate in inheritance
   17774              :          * relationships and we want this stuff to be consistent across the
   17775              :          * inheritance tree.  We can exclude indexes, toast tables, sequences
   17776              :          * and matviews, even though they have storage, because we don't
   17777              :          * support altering or dropping columns in them, nor can they be part
   17778              :          * of inheritance trees.
   17779              :          */
   17780         6221 :         if (dopt->binary_upgrade &&
   17781          878 :             (tbinfo->relkind == RELKIND_RELATION ||
   17782          115 :              tbinfo->relkind == RELKIND_FOREIGN_TABLE ||
   17783          114 :              tbinfo->relkind == RELKIND_PARTITIONED_TABLE))
   17784              :         {
   17785              :             bool        firstitem;
   17786              :             bool        firstitem_extra;
   17787              : 
   17788              :             /*
   17789              :              * Drop any dropped columns.  Merge the pg_attribute manipulations
   17790              :              * into a single SQL command, so that we don't cause repeated
   17791              :              * relcache flushes on the target table.  Otherwise we risk O(N^2)
   17792              :              * relcache bloat while dropping N columns.
   17793              :              */
   17794          861 :             resetPQExpBuffer(extra);
   17795          861 :             firstitem = true;
   17796         4171 :             for (j = 0; j < tbinfo->numatts; j++)
   17797              :             {
   17798         3310 :                 if (tbinfo->attisdropped[j])
   17799              :                 {
   17800           85 :                     if (firstitem)
   17801              :                     {
   17802           39 :                         appendPQExpBufferStr(q, "\n-- For binary upgrade, recreate dropped columns.\n"
   17803              :                                              "UPDATE pg_catalog.pg_attribute\n"
   17804              :                                              "SET attlen = v.dlen, "
   17805              :                                              "attalign = v.dalign, "
   17806              :                                              "attbyval = false\n"
   17807              :                                              "FROM (VALUES ");
   17808           39 :                         firstitem = false;
   17809              :                     }
   17810              :                     else
   17811           46 :                         appendPQExpBufferStr(q, ",\n             ");
   17812           85 :                     appendPQExpBufferChar(q, '(');
   17813           85 :                     appendStringLiteralAH(q, tbinfo->attnames[j], fout);
   17814           85 :                     appendPQExpBuffer(q, ", %d, '%c')",
   17815           85 :                                       tbinfo->attlen[j],
   17816           85 :                                       tbinfo->attalign[j]);
   17817              :                     /* The ALTER ... DROP COLUMN commands must come after */
   17818           85 :                     appendPQExpBuffer(extra, "ALTER %sTABLE ONLY %s ",
   17819              :                                       foreign, qualrelname);
   17820           85 :                     appendPQExpBuffer(extra, "DROP COLUMN %s;\n",
   17821           85 :                                       fmtId(tbinfo->attnames[j]));
   17822              :                 }
   17823              :             }
   17824          861 :             if (!firstitem)
   17825              :             {
   17826           39 :                 appendPQExpBufferStr(q, ") v(dname, dlen, dalign)\n"
   17827              :                                      "WHERE attrelid = ");
   17828           39 :                 appendStringLiteralAH(q, qualrelname, fout);
   17829           39 :                 appendPQExpBufferStr(q, "::pg_catalog.regclass\n"
   17830              :                                      "  AND attname = v.dname;\n");
   17831              :                 /* Now we can issue the actual DROP COLUMN commands */
   17832           39 :                 appendBinaryPQExpBuffer(q, extra->data, extra->len);
   17833              :             }
   17834              : 
   17835              :             /*
   17836              :              * Fix up inherited columns.  As above, do the pg_attribute
   17837              :              * manipulations in a single SQL command.
   17838              :              */
   17839          861 :             firstitem = true;
   17840         4171 :             for (j = 0; j < tbinfo->numatts; j++)
   17841              :             {
   17842         3310 :                 if (!tbinfo->attisdropped[j] &&
   17843         3225 :                     !tbinfo->attislocal[j])
   17844              :                 {
   17845          648 :                     if (firstitem)
   17846              :                     {
   17847          282 :                         appendPQExpBufferStr(q, "\n-- For binary upgrade, recreate inherited columns.\n");
   17848          282 :                         appendPQExpBufferStr(q, "UPDATE pg_catalog.pg_attribute\n"
   17849              :                                              "SET attislocal = false\n"
   17850              :                                              "WHERE attrelid = ");
   17851          282 :                         appendStringLiteralAH(q, qualrelname, fout);
   17852          282 :                         appendPQExpBufferStr(q, "::pg_catalog.regclass\n"
   17853              :                                              "  AND attname IN (");
   17854          282 :                         firstitem = false;
   17855              :                     }
   17856              :                     else
   17857          366 :                         appendPQExpBufferStr(q, ", ");
   17858          648 :                     appendStringLiteralAH(q, tbinfo->attnames[j], fout);
   17859              :                 }
   17860              :             }
   17861          861 :             if (!firstitem)
   17862          282 :                 appendPQExpBufferStr(q, ");\n");
   17863              : 
   17864              :             /*
   17865              :              * Fix up not-null constraints that come from inheritance.  As
   17866              :              * above, do the pg_constraint manipulations in a single SQL
   17867              :              * command.  (Actually, two in special cases, if we're doing an
   17868              :              * upgrade from < 18).
   17869              :              */
   17870          861 :             firstitem = true;
   17871          861 :             firstitem_extra = true;
   17872          861 :             resetPQExpBuffer(extra);
   17873         4171 :             for (j = 0; j < tbinfo->numatts; j++)
   17874              :             {
   17875              :                 /*
   17876              :                  * If a not-null constraint comes from inheritance, reset
   17877              :                  * conislocal.  The inhcount is fixed by ALTER TABLE INHERIT,
   17878              :                  * below.  Special hack: in versions < 18, columns with no
   17879              :                  * local definition need their constraint to be matched by
   17880              :                  * column number in conkeys instead of by constraint name,
   17881              :                  * because the latter is not available.  (We distinguish the
   17882              :                  * case because the constraint name is the empty string.)
   17883              :                  */
   17884         3310 :                 if (tbinfo->notnull_constrs[j] != NULL &&
   17885          333 :                     !tbinfo->notnull_islocal[j])
   17886              :                 {
   17887           94 :                     if (tbinfo->notnull_constrs[j][0] != '\0')
   17888              :                     {
   17889           81 :                         if (firstitem)
   17890              :                         {
   17891           69 :                             appendPQExpBufferStr(q, "UPDATE pg_catalog.pg_constraint\n"
   17892              :                                                  "SET conislocal = false\n"
   17893              :                                                  "WHERE contype = 'n' AND conrelid = ");
   17894           69 :                             appendStringLiteralAH(q, qualrelname, fout);
   17895           69 :                             appendPQExpBufferStr(q, "::pg_catalog.regclass AND\n"
   17896              :                                                  "conname IN (");
   17897           69 :                             firstitem = false;
   17898              :                         }
   17899              :                         else
   17900           12 :                             appendPQExpBufferStr(q, ", ");
   17901           81 :                         appendStringLiteralAH(q, tbinfo->notnull_constrs[j], fout);
   17902              :                     }
   17903              :                     else
   17904              :                     {
   17905           13 :                         if (firstitem_extra)
   17906              :                         {
   17907           13 :                             appendPQExpBufferStr(extra, "UPDATE pg_catalog.pg_constraint\n"
   17908              :                                                  "SET conislocal = false\n"
   17909              :                                                  "WHERE contype = 'n' AND conrelid = ");
   17910           13 :                             appendStringLiteralAH(extra, qualrelname, fout);
   17911           13 :                             appendPQExpBufferStr(extra, "::pg_catalog.regclass AND\n"
   17912              :                                                  "conkey IN (");
   17913           13 :                             firstitem_extra = false;
   17914              :                         }
   17915              :                         else
   17916            0 :                             appendPQExpBufferStr(extra, ", ");
   17917           13 :                         appendPQExpBuffer(extra, "'{%d}'", j + 1);
   17918              :                     }
   17919              :                 }
   17920              :             }
   17921          861 :             if (!firstitem)
   17922           69 :                 appendPQExpBufferStr(q, ");\n");
   17923          861 :             if (!firstitem_extra)
   17924           13 :                 appendPQExpBufferStr(extra, ");\n");
   17925              : 
   17926          861 :             if (extra->len > 0)
   17927           13 :                 appendBinaryPQExpBuffer(q, extra->data, extra->len);
   17928              : 
   17929              :             /*
   17930              :              * Add inherited CHECK constraints, if any.
   17931              :              *
   17932              :              * For partitions, they were already dumped, and conislocal
   17933              :              * doesn't need fixing.
   17934              :              *
   17935              :              * As above, issue only one direct manipulation of pg_constraint.
   17936              :              * Although it is tempting to merge the ALTER ADD CONSTRAINT
   17937              :              * commands into one as well, refrain for now due to concern about
   17938              :              * possible backend memory bloat if there are many such
   17939              :              * constraints.
   17940              :              */
   17941          861 :             resetPQExpBuffer(extra);
   17942          861 :             firstitem = true;
   17943          923 :             for (k = 0; k < tbinfo->ncheck; k++)
   17944              :             {
   17945           62 :                 ConstraintInfo *constr = &(tbinfo->checkexprs[k]);
   17946              : 
   17947           62 :                 if (constr->separate || constr->conislocal || tbinfo->ispartition)
   17948           60 :                     continue;
   17949              : 
   17950            2 :                 if (firstitem)
   17951            2 :                     appendPQExpBufferStr(q, "\n-- For binary upgrade, set up inherited constraints.\n");
   17952            2 :                 appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s ADD CONSTRAINT %s %s;\n",
   17953              :                                   foreign, qualrelname,
   17954            2 :                                   fmtId(constr->dobj.name),
   17955              :                                   constr->condef);
   17956              :                 /* Update pg_constraint after all the ALTER TABLEs */
   17957            2 :                 if (firstitem)
   17958              :                 {
   17959            2 :                     appendPQExpBufferStr(extra, "UPDATE pg_catalog.pg_constraint\n"
   17960              :                                          "SET conislocal = false\n"
   17961              :                                          "WHERE contype = 'c' AND conrelid = ");
   17962            2 :                     appendStringLiteralAH(extra, qualrelname, fout);
   17963            2 :                     appendPQExpBufferStr(extra, "::pg_catalog.regclass\n");
   17964            2 :                     appendPQExpBufferStr(extra, "  AND conname IN (");
   17965            2 :                     firstitem = false;
   17966              :                 }
   17967              :                 else
   17968            0 :                     appendPQExpBufferStr(extra, ", ");
   17969            2 :                 appendStringLiteralAH(extra, constr->dobj.name, fout);
   17970              :             }
   17971          861 :             if (!firstitem)
   17972              :             {
   17973            2 :                 appendPQExpBufferStr(extra, ");\n");
   17974            2 :                 appendBinaryPQExpBuffer(q, extra->data, extra->len);
   17975              :             }
   17976              : 
   17977          861 :             if (numParents > 0 && !tbinfo->ispartition)
   17978              :             {
   17979           69 :                 appendPQExpBufferStr(q, "\n-- For binary upgrade, set up inheritance this way.\n");
   17980          149 :                 for (k = 0; k < numParents; k++)
   17981              :                 {
   17982           80 :                     TableInfo  *parentRel = parents[k];
   17983              : 
   17984           80 :                     appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s INHERIT %s;\n", foreign,
   17985              :                                       qualrelname,
   17986           80 :                                       fmtQualifiedDumpable(parentRel));
   17987              :                 }
   17988              :             }
   17989              : 
   17990          861 :             if (OidIsValid(tbinfo->reloftype))
   17991              :             {
   17992            6 :                 appendPQExpBufferStr(q, "\n-- For binary upgrade, set up typed tables this way.\n");
   17993            6 :                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s OF %s;\n",
   17994              :                                   qualrelname,
   17995            6 :                                   getFormattedTypeName(fout, tbinfo->reloftype,
   17996              :                                                        zeroIsError));
   17997              :             }
   17998              :         }
   17999              : 
   18000              :         /*
   18001              :          * In binary_upgrade mode, arrange to restore the old relfrozenxid and
   18002              :          * relminmxid of all vacuumable relations.  (While vacuum.c processes
   18003              :          * TOAST tables semi-independently, here we see them only as children
   18004              :          * of other relations; so this "if" lacks RELKIND_TOASTVALUE, and the
   18005              :          * child toast table is handled below.)
   18006              :          */
   18007         6221 :         if (dopt->binary_upgrade &&
   18008          878 :             (tbinfo->relkind == RELKIND_RELATION ||
   18009          115 :              tbinfo->relkind == RELKIND_MATVIEW))
   18010              :         {
   18011          780 :             appendPQExpBufferStr(q, "\n-- For binary upgrade, set heap's relfrozenxid and relminmxid\n");
   18012          780 :             appendPQExpBuffer(q, "UPDATE pg_catalog.pg_class\n"
   18013              :                               "SET relfrozenxid = '%u', relminmxid = '%u'\n"
   18014              :                               "WHERE oid = ",
   18015          780 :                               tbinfo->frozenxid, tbinfo->minmxid);
   18016          780 :             appendStringLiteralAH(q, qualrelname, fout);
   18017          780 :             appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
   18018              : 
   18019          780 :             if (tbinfo->toast_oid)
   18020              :             {
   18021              :                 /*
   18022              :                  * The toast table will have the same OID at restore, so we
   18023              :                  * can safely target it by OID.
   18024              :                  */
   18025          295 :                 appendPQExpBufferStr(q, "\n-- For binary upgrade, set toast's relfrozenxid and relminmxid\n");
   18026          295 :                 appendPQExpBuffer(q, "UPDATE pg_catalog.pg_class\n"
   18027              :                                   "SET relfrozenxid = '%u', relminmxid = '%u'\n"
   18028              :                                   "WHERE oid = '%u';\n",
   18029          295 :                                   tbinfo->toast_frozenxid,
   18030          295 :                                   tbinfo->toast_minmxid, tbinfo->toast_oid);
   18031              :             }
   18032              :         }
   18033              : 
   18034              :         /*
   18035              :          * In binary_upgrade mode, restore matviews' populated status by
   18036              :          * poking pg_class directly.  This is pretty ugly, but we can't use
   18037              :          * REFRESH MATERIALIZED VIEW since it's possible that some underlying
   18038              :          * matview is not populated even though this matview is; in any case,
   18039              :          * we want to transfer the matview's heap storage, not run REFRESH.
   18040              :          */
   18041         6221 :         if (dopt->binary_upgrade && tbinfo->relkind == RELKIND_MATVIEW &&
   18042           17 :             tbinfo->relispopulated)
   18043              :         {
   18044           15 :             appendPQExpBufferStr(q, "\n-- For binary upgrade, mark materialized view as populated\n");
   18045           15 :             appendPQExpBufferStr(q, "UPDATE pg_catalog.pg_class\n"
   18046              :                                  "SET relispopulated = 't'\n"
   18047              :                                  "WHERE oid = ");
   18048           15 :             appendStringLiteralAH(q, qualrelname, fout);
   18049           15 :             appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
   18050              :         }
   18051              : 
   18052              :         /*
   18053              :          * Dump additional per-column properties that we can't handle in the
   18054              :          * main CREATE TABLE command.
   18055              :          */
   18056        27865 :         for (j = 0; j < tbinfo->numatts; j++)
   18057              :         {
   18058              :             /* None of this applies to dropped columns */
   18059        21644 :             if (tbinfo->attisdropped[j])
   18060          452 :                 continue;
   18061              : 
   18062              :             /*
   18063              :              * Dump per-column statistics information. We only issue an ALTER
   18064              :              * TABLE statement if the attstattarget entry for this column is
   18065              :              * not the default value.
   18066              :              */
   18067        21192 :             if (tbinfo->attstattarget[j] >= 0)
   18068           32 :                 appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s ALTER COLUMN %s SET STATISTICS %d;\n",
   18069              :                                   foreign, qualrelname,
   18070           32 :                                   fmtId(tbinfo->attnames[j]),
   18071           32 :                                   tbinfo->attstattarget[j]);
   18072              : 
   18073              :             /*
   18074              :              * Dump per-column storage information.  The statement is only
   18075              :              * dumped if the storage has been changed from the type's default.
   18076              :              */
   18077        21192 :             if (tbinfo->attstorage[j] != tbinfo->typstorage[j])
   18078              :             {
   18079           79 :                 switch (tbinfo->attstorage[j])
   18080              :                 {
   18081           10 :                     case TYPSTORAGE_PLAIN:
   18082           10 :                         storage = "PLAIN";
   18083           10 :                         break;
   18084           37 :                     case TYPSTORAGE_EXTERNAL:
   18085           37 :                         storage = "EXTERNAL";
   18086           37 :                         break;
   18087            0 :                     case TYPSTORAGE_EXTENDED:
   18088            0 :                         storage = "EXTENDED";
   18089            0 :                         break;
   18090           32 :                     case TYPSTORAGE_MAIN:
   18091           32 :                         storage = "MAIN";
   18092           32 :                         break;
   18093            0 :                     default:
   18094            0 :                         storage = NULL;
   18095              :                 }
   18096              : 
   18097              :                 /*
   18098              :                  * Only dump the statement if it's a storage type we recognize
   18099              :                  */
   18100           79 :                 if (storage != NULL)
   18101           79 :                     appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s ALTER COLUMN %s SET STORAGE %s;\n",
   18102              :                                       foreign, qualrelname,
   18103           79 :                                       fmtId(tbinfo->attnames[j]),
   18104              :                                       storage);
   18105              :             }
   18106              : 
   18107              :             /*
   18108              :              * Dump per-column compression, if it's been set.
   18109              :              */
   18110        21192 :             if (!dopt->no_toast_compression)
   18111              :             {
   18112              :                 const char *cmname;
   18113              : 
   18114        21092 :                 switch (tbinfo->attcompression[j])
   18115              :                 {
   18116           71 :                     case 'p':
   18117           71 :                         cmname = "pglz";
   18118           71 :                         break;
   18119           39 :                     case 'l':
   18120           39 :                         cmname = "lz4";
   18121           39 :                         break;
   18122        20982 :                     default:
   18123        20982 :                         cmname = NULL;
   18124        20982 :                         break;
   18125              :                 }
   18126              : 
   18127        21092 :                 if (cmname != NULL)
   18128          110 :                     appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s ALTER COLUMN %s SET COMPRESSION %s;\n",
   18129              :                                       foreign, qualrelname,
   18130          110 :                                       fmtId(tbinfo->attnames[j]),
   18131              :                                       cmname);
   18132              :             }
   18133              : 
   18134              :             /*
   18135              :              * Dump per-column attributes.
   18136              :              */
   18137        21192 :             if (tbinfo->attoptions[j][0] != '\0')
   18138           32 :                 appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s ALTER COLUMN %s SET (%s);\n",
   18139              :                                   foreign, qualrelname,
   18140           32 :                                   fmtId(tbinfo->attnames[j]),
   18141           32 :                                   tbinfo->attoptions[j]);
   18142              : 
   18143              :             /*
   18144              :              * Dump per-column fdw options.
   18145              :              */
   18146        21192 :             if (tbinfo->relkind == RELKIND_FOREIGN_TABLE &&
   18147           34 :                 tbinfo->attfdwoptions[j][0] != '\0')
   18148           32 :                 appendPQExpBuffer(q,
   18149              :                                   "ALTER FOREIGN TABLE ONLY %s ALTER COLUMN %s OPTIONS (\n"
   18150              :                                   "    %s\n"
   18151              :                                   ");\n",
   18152              :                                   qualrelname,
   18153           32 :                                   fmtId(tbinfo->attnames[j]),
   18154           32 :                                   tbinfo->attfdwoptions[j]);
   18155              :         }                       /* end loop over columns */
   18156              : 
   18157         6221 :         free(partkeydef);
   18158         6221 :         free(ftoptions);
   18159         6221 :         free(srvname);
   18160              :     }
   18161              : 
   18162              :     /*
   18163              :      * dump properties we only have ALTER TABLE syntax for
   18164              :      */
   18165         6886 :     if ((tbinfo->relkind == RELKIND_RELATION ||
   18166         1630 :          tbinfo->relkind == RELKIND_PARTITIONED_TABLE ||
   18167         1034 :          tbinfo->relkind == RELKIND_MATVIEW) &&
   18168         6187 :         tbinfo->relreplident != REPLICA_IDENTITY_DEFAULT)
   18169              :     {
   18170          207 :         if (tbinfo->relreplident == REPLICA_IDENTITY_INDEX)
   18171              :         {
   18172              :             /* nothing to do, will be set when the index is dumped */
   18173              :         }
   18174          207 :         else if (tbinfo->relreplident == REPLICA_IDENTITY_NOTHING)
   18175              :         {
   18176          207 :             appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY NOTHING;\n",
   18177              :                               qualrelname);
   18178              :         }
   18179            0 :         else if (tbinfo->relreplident == REPLICA_IDENTITY_FULL)
   18180              :         {
   18181            0 :             appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY FULL;\n",
   18182              :                               qualrelname);
   18183              :         }
   18184              :     }
   18185              : 
   18186         6886 :     if (tbinfo->forcerowsec)
   18187           10 :         appendPQExpBuffer(q, "\nALTER TABLE ONLY %s FORCE ROW LEVEL SECURITY;\n",
   18188              :                           qualrelname);
   18189              : 
   18190         6886 :     appendPQExpBuffer(delq, "DROP %s %s;\n", reltypename, qualrelname);
   18191              : 
   18192         6886 :     if (dopt->binary_upgrade)
   18193          948 :         binary_upgrade_extension_member(q, &tbinfo->dobj,
   18194              :                                         reltypename, qrelname,
   18195          948 :                                         tbinfo->dobj.namespace->dobj.name);
   18196              : 
   18197         6886 :     if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   18198              :     {
   18199         6886 :         char       *tablespace = NULL;
   18200         6886 :         char       *tableam = NULL;
   18201              : 
   18202              :         /*
   18203              :          * _selectTablespace() relies on tablespace-enabled objects in the
   18204              :          * default tablespace to have a tablespace of "" (empty string) versus
   18205              :          * non-tablespace-enabled objects to have a tablespace of NULL.
   18206              :          * getTables() sets tbinfo->reltablespace to "" for the default
   18207              :          * tablespace (not NULL).
   18208              :          */
   18209         6886 :         if (RELKIND_HAS_TABLESPACE(tbinfo->relkind))
   18210         6187 :             tablespace = tbinfo->reltablespace;
   18211              : 
   18212         6886 :         if (RELKIND_HAS_TABLE_AM(tbinfo->relkind) ||
   18213         1295 :             tbinfo->relkind == RELKIND_PARTITIONED_TABLE)
   18214         6187 :             tableam = tbinfo->amname;
   18215              : 
   18216         6886 :         ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
   18217         6886 :                      ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
   18218              :                                   .namespace = tbinfo->dobj.namespace->dobj.name,
   18219              :                                   .tablespace = tablespace,
   18220              :                                   .tableam = tableam,
   18221              :                                   .relkind = tbinfo->relkind,
   18222              :                                   .owner = tbinfo->rolname,
   18223              :                                   .description = reltypename,
   18224              :                                   .section = tbinfo->postponed_def ?
   18225              :                                   SECTION_POST_DATA : SECTION_PRE_DATA,
   18226              :                                   .createStmt = q->data,
   18227              :                                   .dropStmt = delq->data));
   18228              :     }
   18229              : 
   18230              :     /* Dump Table Comments */
   18231         6886 :     if (tbinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   18232           74 :         dumpTableComment(fout, tbinfo, reltypename);
   18233              : 
   18234              :     /* Dump Table Security Labels */
   18235         6886 :     if (tbinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
   18236            0 :         dumpTableSecLabel(fout, tbinfo, reltypename);
   18237              : 
   18238              :     /*
   18239              :      * Dump comments for not-null constraints that aren't to be dumped
   18240              :      * separately (those are processed by collectComments/dumpComment).
   18241              :      */
   18242         6886 :     if (!fout->dopt->no_comments && dopt->dumpSchema &&
   18243         6886 :         fout->remoteVersion >= 180000)
   18244              :     {
   18245         6886 :         PQExpBuffer comment = NULL;
   18246         6886 :         PQExpBuffer tag = NULL;
   18247              : 
   18248        32203 :         for (j = 0; j < tbinfo->numatts; j++)
   18249              :         {
   18250        25317 :             if (tbinfo->notnull_constrs[j] != NULL &&
   18251         2667 :                 tbinfo->notnull_comment[j] != NULL)
   18252              :             {
   18253           42 :                 if (comment == NULL)
   18254              :                 {
   18255           42 :                     comment = createPQExpBuffer();
   18256           42 :                     tag = createPQExpBuffer();
   18257              :                 }
   18258              :                 else
   18259              :                 {
   18260            0 :                     resetPQExpBuffer(comment);
   18261            0 :                     resetPQExpBuffer(tag);
   18262              :                 }
   18263              : 
   18264           42 :                 appendPQExpBuffer(comment, "COMMENT ON CONSTRAINT %s ON %s IS ",
   18265           42 :                                   fmtId(tbinfo->notnull_constrs[j]), qualrelname);
   18266           42 :                 appendStringLiteralAH(comment, tbinfo->notnull_comment[j], fout);
   18267           42 :                 appendPQExpBufferStr(comment, ";\n");
   18268              : 
   18269           42 :                 appendPQExpBuffer(tag, "CONSTRAINT %s ON %s",
   18270           42 :                                   fmtId(tbinfo->notnull_constrs[j]), qrelname);
   18271              : 
   18272           42 :                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
   18273           42 :                              ARCHIVE_OPTS(.tag = tag->data,
   18274              :                                           .namespace = tbinfo->dobj.namespace->dobj.name,
   18275              :                                           .owner = tbinfo->rolname,
   18276              :                                           .description = "COMMENT",
   18277              :                                           .section = SECTION_NONE,
   18278              :                                           .createStmt = comment->data,
   18279              :                                           .deps = &(tbinfo->dobj.dumpId),
   18280              :                                           .nDeps = 1));
   18281              :             }
   18282              :         }
   18283              : 
   18284         6886 :         destroyPQExpBuffer(comment);
   18285         6886 :         destroyPQExpBuffer(tag);
   18286              :     }
   18287              : 
   18288              :     /* Dump comments on inlined table constraints */
   18289         7459 :     for (j = 0; j < tbinfo->ncheck; j++)
   18290              :     {
   18291          573 :         ConstraintInfo *constr = &(tbinfo->checkexprs[j]);
   18292              : 
   18293          573 :         if (constr->separate || !constr->conislocal)
   18294          244 :             continue;
   18295              : 
   18296          329 :         if (constr->dobj.dump & DUMP_COMPONENT_COMMENT)
   18297           37 :             dumpTableConstraintComment(fout, constr);
   18298              :     }
   18299              : 
   18300         6886 :     destroyPQExpBuffer(q);
   18301         6886 :     destroyPQExpBuffer(delq);
   18302         6886 :     destroyPQExpBuffer(extra);
   18303         6886 :     free(qrelname);
   18304         6886 :     free(qualrelname);
   18305         6886 : }
   18306              : 
   18307              : /*
   18308              :  * dumpTableAttach
   18309              :  *    write to fout the commands to attach a child partition
   18310              :  *
   18311              :  * Child partitions are always made by creating them separately
   18312              :  * and then using ATTACH PARTITION, rather than using
   18313              :  * CREATE TABLE ... PARTITION OF.  This is important for preserving
   18314              :  * any possible discrepancy in column layout, to allow assigning the
   18315              :  * correct tablespace if different, and so that it's possible to restore
   18316              :  * a partition without restoring its parent.  (You'll get an error from
   18317              :  * the ATTACH PARTITION command, but that can be ignored, or skipped
   18318              :  * using "pg_restore -L" if you prefer.)  The last point motivates
   18319              :  * treating ATTACH PARTITION as a completely separate ArchiveEntry
   18320              :  * rather than emitting it within the child partition's ArchiveEntry.
   18321              :  */
   18322              : static void
   18323         1431 : dumpTableAttach(Archive *fout, const TableAttachInfo *attachinfo)
   18324              : {
   18325         1431 :     DumpOptions *dopt = fout->dopt;
   18326              :     PQExpBuffer q;
   18327              :     PGresult   *res;
   18328              :     char       *partbound;
   18329              : 
   18330              :     /* Do nothing if not dumping schema */
   18331         1431 :     if (!dopt->dumpSchema)
   18332           54 :         return;
   18333              : 
   18334         1377 :     q = createPQExpBuffer();
   18335              : 
   18336         1377 :     if (!fout->is_prepared[PREPQUERY_DUMPTABLEATTACH])
   18337              :     {
   18338              :         /* Set up query for partbound details */
   18339           43 :         appendPQExpBufferStr(q,
   18340              :                              "PREPARE dumpTableAttach(pg_catalog.oid) AS\n");
   18341              : 
   18342           43 :         appendPQExpBufferStr(q,
   18343              :                              "SELECT pg_get_expr(c.relpartbound, c.oid) "
   18344              :                              "FROM pg_class c "
   18345              :                              "WHERE c.oid = $1");
   18346              : 
   18347           43 :         ExecuteSqlStatement(fout, q->data);
   18348              : 
   18349           43 :         fout->is_prepared[PREPQUERY_DUMPTABLEATTACH] = true;
   18350              :     }
   18351              : 
   18352         1377 :     printfPQExpBuffer(q,
   18353              :                       "EXECUTE dumpTableAttach('%u')",
   18354         1377 :                       attachinfo->partitionTbl->dobj.catId.oid);
   18355              : 
   18356         1377 :     res = ExecuteSqlQueryForSingleRow(fout, q->data);
   18357         1377 :     partbound = PQgetvalue(res, 0, 0);
   18358              : 
   18359              :     /* Perform ALTER TABLE on the parent */
   18360         1377 :     printfPQExpBuffer(q,
   18361              :                       "ALTER TABLE ONLY %s ",
   18362         1377 :                       fmtQualifiedDumpable(attachinfo->parentTbl));
   18363         1377 :     appendPQExpBuffer(q,
   18364              :                       "ATTACH PARTITION %s %s;\n",
   18365         1377 :                       fmtQualifiedDumpable(attachinfo->partitionTbl),
   18366              :                       partbound);
   18367              : 
   18368              :     /*
   18369              :      * There is no point in creating a drop query as the drop is done by table
   18370              :      * drop.  (If you think to change this, see also _printTocEntry().)
   18371              :      * Although this object doesn't really have ownership as such, set the
   18372              :      * owner field anyway to ensure that the command is run by the correct
   18373              :      * role at restore time.
   18374              :      */
   18375         1377 :     ArchiveEntry(fout, attachinfo->dobj.catId, attachinfo->dobj.dumpId,
   18376         1377 :                  ARCHIVE_OPTS(.tag = attachinfo->dobj.name,
   18377              :                               .namespace = attachinfo->dobj.namespace->dobj.name,
   18378              :                               .owner = attachinfo->partitionTbl->rolname,
   18379              :                               .description = "TABLE ATTACH",
   18380              :                               .section = SECTION_PRE_DATA,
   18381              :                               .createStmt = q->data));
   18382              : 
   18383         1377 :     PQclear(res);
   18384         1377 :     destroyPQExpBuffer(q);
   18385              : }
   18386              : 
   18387              : /*
   18388              :  * dumpAttrDef --- dump an attribute's default-value declaration
   18389              :  */
   18390              : static void
   18391         1087 : dumpAttrDef(Archive *fout, const AttrDefInfo *adinfo)
   18392              : {
   18393         1087 :     DumpOptions *dopt = fout->dopt;
   18394         1087 :     TableInfo  *tbinfo = adinfo->adtable;
   18395         1087 :     int         adnum = adinfo->adnum;
   18396              :     PQExpBuffer q;
   18397              :     PQExpBuffer delq;
   18398              :     char       *qualrelname;
   18399              :     char       *tag;
   18400              :     char       *foreign;
   18401              : 
   18402              :     /* Do nothing if not dumping schema */
   18403         1087 :     if (!dopt->dumpSchema)
   18404            0 :         return;
   18405              : 
   18406              :     /* Skip if not "separate"; it was dumped in the table's definition */
   18407         1087 :     if (!adinfo->separate)
   18408          921 :         return;
   18409              : 
   18410          166 :     q = createPQExpBuffer();
   18411          166 :     delq = createPQExpBuffer();
   18412              : 
   18413          166 :     qualrelname = pg_strdup(fmtQualifiedDumpable(tbinfo));
   18414              : 
   18415          166 :     foreign = tbinfo->relkind == RELKIND_FOREIGN_TABLE ? "FOREIGN " : "";
   18416              : 
   18417          166 :     appendPQExpBuffer(q,
   18418              :                       "ALTER %sTABLE ONLY %s ALTER COLUMN %s SET DEFAULT %s;\n",
   18419          166 :                       foreign, qualrelname, fmtId(tbinfo->attnames[adnum - 1]),
   18420          166 :                       adinfo->adef_expr);
   18421              : 
   18422          166 :     appendPQExpBuffer(delq, "ALTER %sTABLE %s ALTER COLUMN %s DROP DEFAULT;\n",
   18423              :                       foreign, qualrelname,
   18424          166 :                       fmtId(tbinfo->attnames[adnum - 1]));
   18425              : 
   18426          166 :     tag = psprintf("%s %s", tbinfo->dobj.name, tbinfo->attnames[adnum - 1]);
   18427              : 
   18428          166 :     if (adinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   18429          166 :         ArchiveEntry(fout, adinfo->dobj.catId, adinfo->dobj.dumpId,
   18430          166 :                      ARCHIVE_OPTS(.tag = tag,
   18431              :                                   .namespace = tbinfo->dobj.namespace->dobj.name,
   18432              :                                   .owner = tbinfo->rolname,
   18433              :                                   .description = "DEFAULT",
   18434              :                                   .section = SECTION_PRE_DATA,
   18435              :                                   .createStmt = q->data,
   18436              :                                   .dropStmt = delq->data));
   18437              : 
   18438          166 :     free(tag);
   18439          166 :     destroyPQExpBuffer(q);
   18440          166 :     destroyPQExpBuffer(delq);
   18441          166 :     free(qualrelname);
   18442              : }
   18443              : 
   18444              : /*
   18445              :  * getAttrName: extract the correct name for an attribute
   18446              :  *
   18447              :  * The array tblInfo->attnames[] only provides names of user attributes;
   18448              :  * if a system attribute number is supplied, we have to fake it.
   18449              :  * We also do a little bit of bounds checking for safety's sake.
   18450              :  */
   18451              : static const char *
   18452         2250 : getAttrName(int attrnum, const TableInfo *tblInfo)
   18453              : {
   18454         2250 :     if (attrnum > 0 && attrnum <= tblInfo->numatts)
   18455         2250 :         return tblInfo->attnames[attrnum - 1];
   18456            0 :     switch (attrnum)
   18457              :     {
   18458            0 :         case SelfItemPointerAttributeNumber:
   18459            0 :             return "ctid";
   18460            0 :         case MinTransactionIdAttributeNumber:
   18461            0 :             return "xmin";
   18462            0 :         case MinCommandIdAttributeNumber:
   18463            0 :             return "cmin";
   18464            0 :         case MaxTransactionIdAttributeNumber:
   18465            0 :             return "xmax";
   18466            0 :         case MaxCommandIdAttributeNumber:
   18467            0 :             return "cmax";
   18468            0 :         case TableOidAttributeNumber:
   18469            0 :             return "tableoid";
   18470              :     }
   18471            0 :     pg_fatal("invalid column number %d for table \"%s\"",
   18472              :              attrnum, tblInfo->dobj.name);
   18473              :     return NULL;                /* keep compiler quiet */
   18474              : }
   18475              : 
   18476              : /*
   18477              :  * dumpIndex
   18478              :  *    write out to fout a user-defined index
   18479              :  */
   18480              : static void
   18481         2768 : dumpIndex(Archive *fout, const IndxInfo *indxinfo)
   18482              : {
   18483         2768 :     DumpOptions *dopt = fout->dopt;
   18484         2768 :     TableInfo  *tbinfo = indxinfo->indextable;
   18485         2768 :     bool        is_constraint = (indxinfo->indexconstraint != 0);
   18486              :     PQExpBuffer q;
   18487              :     PQExpBuffer delq;
   18488              :     char       *qindxname;
   18489              :     char       *qqindxname;
   18490              : 
   18491              :     /* Do nothing if not dumping schema */
   18492         2768 :     if (!dopt->dumpSchema)
   18493          117 :         return;
   18494              : 
   18495         2651 :     q = createPQExpBuffer();
   18496         2651 :     delq = createPQExpBuffer();
   18497              : 
   18498         2651 :     qindxname = pg_strdup(fmtId(indxinfo->dobj.name));
   18499         2651 :     qqindxname = pg_strdup(fmtQualifiedDumpable(indxinfo));
   18500              : 
   18501              :     /*
   18502              :      * If there's an associated constraint, don't dump the index per se, but
   18503              :      * do dump any comment for it.  (This is safe because dependency ordering
   18504              :      * will have ensured the constraint is emitted first.)  Note that the
   18505              :      * emitted comment has to be shown as depending on the constraint, not the
   18506              :      * index, in such cases.
   18507              :      */
   18508         2651 :     if (!is_constraint)
   18509              :     {
   18510         1048 :         char       *indstatcols = indxinfo->indstatcols;
   18511         1048 :         char       *indstatvals = indxinfo->indstatvals;
   18512         1048 :         char      **indstatcolsarray = NULL;
   18513         1048 :         char      **indstatvalsarray = NULL;
   18514         1048 :         int         nstatcols = 0;
   18515         1048 :         int         nstatvals = 0;
   18516              : 
   18517         1048 :         if (dopt->binary_upgrade)
   18518          158 :             binary_upgrade_set_pg_class_oids(fout, q,
   18519          158 :                                              indxinfo->dobj.catId.oid);
   18520              : 
   18521              :         /* Plain secondary index */
   18522         1048 :         appendPQExpBuffer(q, "%s;\n", indxinfo->indexdef);
   18523              : 
   18524              :         /*
   18525              :          * Append ALTER TABLE commands as needed to set properties that we
   18526              :          * only have ALTER TABLE syntax for.  Keep this in sync with the
   18527              :          * similar code in dumpConstraint!
   18528              :          */
   18529              : 
   18530              :         /* If the index is clustered, we need to record that. */
   18531         1048 :         if (indxinfo->indisclustered)
   18532              :         {
   18533            5 :             appendPQExpBuffer(q, "\nALTER TABLE %s CLUSTER",
   18534            5 :                               fmtQualifiedDumpable(tbinfo));
   18535              :             /* index name is not qualified in this syntax */
   18536            5 :             appendPQExpBuffer(q, " ON %s;\n",
   18537              :                               qindxname);
   18538              :         }
   18539              : 
   18540              :         /*
   18541              :          * If the index has any statistics on some of its columns, generate
   18542              :          * the associated ALTER INDEX queries.
   18543              :          */
   18544         1048 :         if (strlen(indstatcols) != 0 || strlen(indstatvals) != 0)
   18545              :         {
   18546              :             int         j;
   18547              : 
   18548           32 :             if (!parsePGArray(indstatcols, &indstatcolsarray, &nstatcols))
   18549            0 :                 pg_fatal("could not parse index statistic columns");
   18550           32 :             if (!parsePGArray(indstatvals, &indstatvalsarray, &nstatvals))
   18551            0 :                 pg_fatal("could not parse index statistic values");
   18552           32 :             if (nstatcols != nstatvals)
   18553            0 :                 pg_fatal("mismatched number of columns and values for index statistics");
   18554              : 
   18555           96 :             for (j = 0; j < nstatcols; j++)
   18556              :             {
   18557           64 :                 appendPQExpBuffer(q, "ALTER INDEX %s ", qqindxname);
   18558              : 
   18559              :                 /*
   18560              :                  * Note that this is a column number, so no quotes should be
   18561              :                  * used.
   18562              :                  */
   18563           64 :                 appendPQExpBuffer(q, "ALTER COLUMN %s ",
   18564           64 :                                   indstatcolsarray[j]);
   18565           64 :                 appendPQExpBuffer(q, "SET STATISTICS %s;\n",
   18566           64 :                                   indstatvalsarray[j]);
   18567              :             }
   18568              :         }
   18569              : 
   18570              :         /* Indexes can depend on extensions */
   18571         1048 :         append_depends_on_extension(fout, q, &indxinfo->dobj,
   18572              :                                     "pg_catalog.pg_class",
   18573              :                                     "INDEX", qqindxname);
   18574              : 
   18575              :         /* If the index defines identity, we need to record that. */
   18576         1048 :         if (indxinfo->indisreplident)
   18577              :         {
   18578            0 :             appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY USING",
   18579            0 :                               fmtQualifiedDumpable(tbinfo));
   18580              :             /* index name is not qualified in this syntax */
   18581            0 :             appendPQExpBuffer(q, " INDEX %s;\n",
   18582              :                               qindxname);
   18583              :         }
   18584              : 
   18585              :         /*
   18586              :          * If this index is a member of a partitioned index, the backend will
   18587              :          * not allow us to drop it separately, so don't try.  It will go away
   18588              :          * automatically when we drop either the index's table or the
   18589              :          * partitioned index.  (If, in a selective restore with --clean, we
   18590              :          * drop neither of those, then this index will not be dropped either.
   18591              :          * But that's fine, and even if you think it's not, the backend won't
   18592              :          * let us do differently.)
   18593              :          */
   18594         1048 :         if (indxinfo->parentidx == 0)
   18595          866 :             appendPQExpBuffer(delq, "DROP INDEX %s;\n", qqindxname);
   18596              : 
   18597         1048 :         if (indxinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   18598         1048 :             ArchiveEntry(fout, indxinfo->dobj.catId, indxinfo->dobj.dumpId,
   18599         1048 :                          ARCHIVE_OPTS(.tag = indxinfo->dobj.name,
   18600              :                                       .namespace = tbinfo->dobj.namespace->dobj.name,
   18601              :                                       .tablespace = indxinfo->tablespace,
   18602              :                                       .owner = tbinfo->rolname,
   18603              :                                       .description = "INDEX",
   18604              :                                       .section = SECTION_POST_DATA,
   18605              :                                       .createStmt = q->data,
   18606              :                                       .dropStmt = delq->data));
   18607              : 
   18608         1048 :         free(indstatcolsarray);
   18609         1048 :         free(indstatvalsarray);
   18610              :     }
   18611              : 
   18612              :     /* Dump Index Comments */
   18613         2651 :     if (indxinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   18614           15 :         dumpComment(fout, "INDEX", qindxname,
   18615           15 :                     tbinfo->dobj.namespace->dobj.name,
   18616              :                     tbinfo->rolname,
   18617              :                     indxinfo->dobj.catId, 0,
   18618              :                     is_constraint ? indxinfo->indexconstraint :
   18619              :                     indxinfo->dobj.dumpId);
   18620              : 
   18621         2651 :     destroyPQExpBuffer(q);
   18622         2651 :     destroyPQExpBuffer(delq);
   18623         2651 :     free(qindxname);
   18624         2651 :     free(qqindxname);
   18625              : }
   18626              : 
   18627              : /*
   18628              :  * dumpIndexAttach
   18629              :  *    write out to fout a partitioned-index attachment clause
   18630              :  */
   18631              : static void
   18632          594 : dumpIndexAttach(Archive *fout, const IndexAttachInfo *attachinfo)
   18633              : {
   18634              :     /* Do nothing if not dumping schema */
   18635          594 :     if (!fout->dopt->dumpSchema)
   18636           48 :         return;
   18637              : 
   18638          546 :     if (attachinfo->partitionIdx->dobj.dump & DUMP_COMPONENT_DEFINITION)
   18639              :     {
   18640          546 :         PQExpBuffer q = createPQExpBuffer();
   18641              : 
   18642          546 :         appendPQExpBuffer(q, "ALTER INDEX %s ",
   18643          546 :                           fmtQualifiedDumpable(attachinfo->parentIdx));
   18644          546 :         appendPQExpBuffer(q, "ATTACH PARTITION %s;\n",
   18645          546 :                           fmtQualifiedDumpable(attachinfo->partitionIdx));
   18646              : 
   18647              :         /*
   18648              :          * There is no need for a dropStmt since the drop is done implicitly
   18649              :          * when we drop either the index's table or the partitioned index.
   18650              :          * Moreover, since there's no ALTER INDEX DETACH PARTITION command,
   18651              :          * there's no way to do it anyway.  (If you think to change this,
   18652              :          * consider also what to do with --if-exists.)
   18653              :          *
   18654              :          * Although this object doesn't really have ownership as such, set the
   18655              :          * owner field anyway to ensure that the command is run by the correct
   18656              :          * role at restore time.
   18657              :          */
   18658          546 :         ArchiveEntry(fout, attachinfo->dobj.catId, attachinfo->dobj.dumpId,
   18659          546 :                      ARCHIVE_OPTS(.tag = attachinfo->dobj.name,
   18660              :                                   .namespace = attachinfo->dobj.namespace->dobj.name,
   18661              :                                   .owner = attachinfo->parentIdx->indextable->rolname,
   18662              :                                   .description = "INDEX ATTACH",
   18663              :                                   .section = SECTION_POST_DATA,
   18664              :                                   .createStmt = q->data));
   18665              : 
   18666          546 :         destroyPQExpBuffer(q);
   18667              :     }
   18668              : }
   18669              : 
   18670              : /*
   18671              :  * dumpStatisticsExt
   18672              :  *    write out to fout an extended statistics object
   18673              :  */
   18674              : static void
   18675          171 : dumpStatisticsExt(Archive *fout, const StatsExtInfo *statsextinfo)
   18676              : {
   18677          171 :     DumpOptions *dopt = fout->dopt;
   18678              :     PQExpBuffer q;
   18679              :     PQExpBuffer delq;
   18680              :     PQExpBuffer query;
   18681              :     char       *qstatsextname;
   18682              :     PGresult   *res;
   18683              :     char       *stxdef;
   18684              : 
   18685              :     /* Do nothing if not dumping schema */
   18686          171 :     if (!dopt->dumpSchema)
   18687           24 :         return;
   18688              : 
   18689          147 :     q = createPQExpBuffer();
   18690          147 :     delq = createPQExpBuffer();
   18691          147 :     query = createPQExpBuffer();
   18692              : 
   18693          147 :     qstatsextname = pg_strdup(fmtId(statsextinfo->dobj.name));
   18694              : 
   18695          147 :     appendPQExpBuffer(query, "SELECT "
   18696              :                       "pg_catalog.pg_get_statisticsobjdef('%u'::pg_catalog.oid)",
   18697          147 :                       statsextinfo->dobj.catId.oid);
   18698              : 
   18699          147 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   18700              : 
   18701          147 :     stxdef = PQgetvalue(res, 0, 0);
   18702              : 
   18703              :     /* Result of pg_get_statisticsobjdef is complete except for semicolon */
   18704          147 :     appendPQExpBuffer(q, "%s;\n", stxdef);
   18705              : 
   18706              :     /*
   18707              :      * We only issue an ALTER STATISTICS statement if the stxstattarget entry
   18708              :      * for this statistics object is not the default value.
   18709              :      */
   18710          147 :     if (statsextinfo->stattarget >= 0)
   18711              :     {
   18712           32 :         appendPQExpBuffer(q, "ALTER STATISTICS %s ",
   18713           32 :                           fmtQualifiedDumpable(statsextinfo));
   18714           32 :         appendPQExpBuffer(q, "SET STATISTICS %d;\n",
   18715           32 :                           statsextinfo->stattarget);
   18716              :     }
   18717              : 
   18718          147 :     appendPQExpBuffer(delq, "DROP STATISTICS %s;\n",
   18719          147 :                       fmtQualifiedDumpable(statsextinfo));
   18720              : 
   18721          147 :     if (statsextinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   18722          147 :         ArchiveEntry(fout, statsextinfo->dobj.catId,
   18723          147 :                      statsextinfo->dobj.dumpId,
   18724          147 :                      ARCHIVE_OPTS(.tag = statsextinfo->dobj.name,
   18725              :                                   .namespace = statsextinfo->dobj.namespace->dobj.name,
   18726              :                                   .owner = statsextinfo->rolname,
   18727              :                                   .description = "STATISTICS",
   18728              :                                   .section = SECTION_POST_DATA,
   18729              :                                   .createStmt = q->data,
   18730              :                                   .dropStmt = delq->data));
   18731              : 
   18732              :     /* Dump Statistics Comments */
   18733          147 :     if (statsextinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   18734            0 :         dumpComment(fout, "STATISTICS", qstatsextname,
   18735            0 :                     statsextinfo->dobj.namespace->dobj.name,
   18736            0 :                     statsextinfo->rolname,
   18737              :                     statsextinfo->dobj.catId, 0,
   18738            0 :                     statsextinfo->dobj.dumpId);
   18739              : 
   18740          147 :     PQclear(res);
   18741          147 :     destroyPQExpBuffer(q);
   18742          147 :     destroyPQExpBuffer(delq);
   18743          147 :     destroyPQExpBuffer(query);
   18744          147 :     free(qstatsextname);
   18745              : }
   18746              : 
   18747              : /*
   18748              :  * dumpStatisticsExtStats
   18749              :  *    write out to fout the stats for an extended statistics object
   18750              :  */
   18751              : static void
   18752          171 : dumpStatisticsExtStats(Archive *fout, const StatsExtInfo *statsextinfo)
   18753              : {
   18754          171 :     DumpOptions *dopt = fout->dopt;
   18755              :     PQExpBuffer query;
   18756              :     PGresult   *res;
   18757              :     int         nstats;
   18758              : 
   18759              :     /* Do nothing if not dumping statistics */
   18760          171 :     if (!dopt->dumpStatistics)
   18761           40 :         return;
   18762              : 
   18763          131 :     if (!fout->is_prepared[PREPQUERY_DUMPEXTSTATSOBJSTATS])
   18764              :     {
   18765           33 :         PQExpBuffer pq = createPQExpBuffer();
   18766              : 
   18767              :         /*---------
   18768              :          * Set up query for details about extended statistics objects.
   18769              :          *
   18770              :          * The query depends on the backend version:
   18771              :          * - In v19 and newer versions, query directly the pg_stats_ext*
   18772              :          *   catalogs.
   18773              :          * - In v18 and older versions, ndistinct and dependencies have a
   18774              :          *   different format that needs translation.
   18775              :          * - In v14 and older versions, inherited does not exist.
   18776              :          * - In v11 and older versions, there is no pg_stats_ext, hence
   18777              :          *   the logic joins pg_statistic_ext and pg_namespace.
   18778              :          *---------
   18779              :          */
   18780              : 
   18781           33 :         appendPQExpBufferStr(pq,
   18782              :                              "PREPARE getExtStatsStats(pg_catalog.name, pg_catalog.name) AS\n"
   18783              :                              "SELECT ");
   18784              : 
   18785              :         /*
   18786              :          * Versions 15 and newer have inherited stats.
   18787              :          *
   18788              :          * Create this column in all versions because we need to order by it
   18789              :          * later.
   18790              :          */
   18791           33 :         if (fout->remoteVersion >= 150000)
   18792           33 :             appendPQExpBufferStr(pq, "e.inherited, ");
   18793              :         else
   18794            0 :             appendPQExpBufferStr(pq, "false AS inherited, ");
   18795              : 
   18796              :         /*--------
   18797              :          * The ndistinct and dependencies formats changed in v19, so
   18798              :          * everything before that needs to be translated.
   18799              :          *
   18800              :          * The ndistinct translation converts this kind of data:
   18801              :          * {"3, 4": 11, "3, 6": 11, "4, 6": 11, "3, 4, 6": 11}
   18802              :          *
   18803              :          * to this:
   18804              :          * [ {"attributes": [3,4], "ndistinct": 11},
   18805              :          *   {"attributes": [3,6], "ndistinct": 11},
   18806              :          *   {"attributes": [4,6], "ndistinct": 11},
   18807              :          *   {"attributes": [3,4,6], "ndistinct": 11} ]
   18808              :          *
   18809              :          * The dependencies translation converts this kind of data:
   18810              :          * {"3 => 4": 1.000000, "3 => 6": 1.000000,
   18811              :          *  "4 => 6": 1.000000, "3, 4 => 6": 1.000000,
   18812              :          *  "3, 6 => 4": 1.000000}
   18813              :          *
   18814              :          * to this:
   18815              :          * [ {"attributes": [3], "dependency": 4, "degree": 1.000000},
   18816              :          *   {"attributes": [3], "dependency": 6, "degree": 1.000000},
   18817              :          *   {"attributes": [4], "dependency": 6, "degree": 1.000000},
   18818              :          *   {"attributes": [3,4], "dependency": 6, "degree": 1.000000},
   18819              :          *   {"attributes": [3,6], "dependency": 4, "degree": 1.000000} ]
   18820              :          *--------
   18821              :          */
   18822           33 :         if (fout->remoteVersion >= 190000)
   18823           33 :             appendPQExpBufferStr(pq, "e.n_distinct, e.dependencies, ");
   18824              :         else
   18825            0 :             appendPQExpBufferStr(pq,
   18826              :                                  "( "
   18827              :                                  "SELECT json_agg( "
   18828              :                                  "  json_build_object( "
   18829              :                                  "    '" PG_NDISTINCT_KEY_ATTRIBUTES "', "
   18830              :                                  "    string_to_array(kv.key, ', ')::integer[], "
   18831              :                                  "    '" PG_NDISTINCT_KEY_NDISTINCT "', "
   18832              :                                  "    kv.value::bigint )) "
   18833              :                                  "FROM json_each_text(e.n_distinct::text::json) AS kv"
   18834              :                                  ") AS n_distinct, "
   18835              :                                  "( "
   18836              :                                  "SELECT json_agg( "
   18837              :                                  "  json_build_object( "
   18838              :                                  "    '" PG_DEPENDENCIES_KEY_ATTRIBUTES "', "
   18839              :                                  "    string_to_array( "
   18840              :                                  "      split_part(kv.key, ' => ', 1), "
   18841              :                                  "      ', ')::integer[], "
   18842              :                                  "    '" PG_DEPENDENCIES_KEY_DEPENDENCY "', "
   18843              :                                  "    split_part(kv.key, ' => ', 2)::integer, "
   18844              :                                  "    '" PG_DEPENDENCIES_KEY_DEGREE "', "
   18845              :                                  "    kv.value::double precision )) "
   18846              :                                  "FROM json_each_text(e.dependencies::text::json) AS kv "
   18847              :                                  ") AS dependencies, ");
   18848              : 
   18849              :         /* MCV was introduced v13 */
   18850           33 :         if (fout->remoteVersion >= 130000)
   18851           33 :             appendPQExpBufferStr(pq,
   18852              :                                  "e.most_common_vals, e.most_common_freqs, "
   18853              :                                  "e.most_common_base_freqs, ");
   18854              :         else
   18855            0 :             appendPQExpBufferStr(pq,
   18856              :                                  "NULL AS most_common_vals, NULL AS most_common_freqs, "
   18857              :                                  "NULL AS most_common_base_freqs, ");
   18858              : 
   18859              :         /* Expressions were introduced in v14 */
   18860           33 :         if (fout->remoteVersion >= 140000)
   18861              :         {
   18862              :             /*
   18863              :              * There is no ordering column in pg_stats_ext_exprs.  However, we
   18864              :              * can rely on the unnesting of pg_statistic_ext_data.stxdexpr to
   18865              :              * maintain the desired order of expression elements.
   18866              :              */
   18867           33 :             appendPQExpBufferStr(pq,
   18868              :                                  "( "
   18869              :                                  "SELECT jsonb_pretty(jsonb_agg("
   18870              :                                  "nullif(j.obj, '{}'::jsonb))) "
   18871              :                                  "FROM pg_stats_ext_exprs AS ee "
   18872              :                                  "CROSS JOIN LATERAL jsonb_strip_nulls("
   18873              :                                  "    jsonb_build_object( "
   18874              :                                  "       'null_frac', ee.null_frac::text, "
   18875              :                                  "       'avg_width', ee.avg_width::text, "
   18876              :                                  "       'n_distinct', ee.n_distinct::text, "
   18877              :                                  "       'most_common_vals', ee.most_common_vals::text, "
   18878              :                                  "       'most_common_freqs', ee.most_common_freqs::text, "
   18879              :                                  "       'histogram_bounds', ee.histogram_bounds::text, "
   18880              :                                  "       'correlation', ee.correlation::text, "
   18881              :                                  "       'most_common_elems', ee.most_common_elems::text, "
   18882              :                                  "       'most_common_elem_freqs', ee.most_common_elem_freqs::text, "
   18883              :                                  "       'elem_count_histogram', ee.elem_count_histogram::text");
   18884              : 
   18885              :             /* These three have been added to pg_stats_ext_exprs in v19. */
   18886           33 :             if (fout->remoteVersion >= 190000)
   18887           33 :                 appendPQExpBufferStr(pq,
   18888              :                                      ", "
   18889              :                                      "       'range_length_histogram', ee.range_length_histogram::text, "
   18890              :                                      "       'range_empty_frac', ee.range_empty_frac::text, "
   18891              :                                      "       'range_bounds_histogram', ee.range_bounds_histogram::text");
   18892              : 
   18893           33 :             appendPQExpBufferStr(pq,
   18894              :                                  "    )) AS j(obj)"
   18895              :                                  "WHERE ee.statistics_schemaname = $1 "
   18896              :                                  "AND ee.statistics_name = $2 ");
   18897              :             /* Inherited expressions introduced in v15 */
   18898           33 :             if (fout->remoteVersion >= 150000)
   18899           33 :                 appendPQExpBufferStr(pq, "AND ee.inherited = e.inherited");
   18900              : 
   18901           33 :             appendPQExpBufferStr(pq, ") AS exprs ");
   18902              :         }
   18903              :         else
   18904            0 :             appendPQExpBufferStr(pq, "NULL AS exprs ");
   18905              : 
   18906              :         /* pg_stats_ext introduced in v12 */
   18907           33 :         if (fout->remoteVersion >= 120000)
   18908           33 :             appendPQExpBufferStr(pq,
   18909              :                                  "FROM pg_catalog.pg_stats_ext AS e "
   18910              :                                  "WHERE e.statistics_schemaname = $1 "
   18911              :                                  "AND e.statistics_name = $2 ");
   18912              :         else
   18913            0 :             appendPQExpBufferStr(pq,
   18914              :                                  "FROM ( "
   18915              :                                  "SELECT s.stxndistinct AS n_distinct, "
   18916              :                                  "    s.stxdependencies AS dependencies "
   18917              :                                  "FROM pg_catalog.pg_statistic_ext AS s "
   18918              :                                  "JOIN pg_catalog.pg_namespace AS n "
   18919              :                                  "ON n.oid = s.stxnamespace "
   18920              :                                  "WHERE n.nspname = $1 "
   18921              :                                  "AND s.stxname = $2 "
   18922              :                                  ") AS e ");
   18923              : 
   18924              :         /* we always have an inherited column, but it may be a constant */
   18925           33 :         appendPQExpBufferStr(pq, "ORDER BY inherited");
   18926              : 
   18927           33 :         ExecuteSqlStatement(fout, pq->data);
   18928              : 
   18929           33 :         fout->is_prepared[PREPQUERY_DUMPEXTSTATSOBJSTATS] = true;
   18930              : 
   18931           33 :         destroyPQExpBuffer(pq);
   18932              :     }
   18933              : 
   18934          131 :     query = createPQExpBuffer();
   18935              : 
   18936          131 :     appendPQExpBufferStr(query, "EXECUTE getExtStatsStats(");
   18937          131 :     appendStringLiteralAH(query, statsextinfo->dobj.namespace->dobj.name, fout);
   18938          131 :     appendPQExpBufferStr(query, "::pg_catalog.name, ");
   18939          131 :     appendStringLiteralAH(query, statsextinfo->dobj.name, fout);
   18940          131 :     appendPQExpBufferStr(query, "::pg_catalog.name)");
   18941              : 
   18942          131 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   18943              : 
   18944          131 :     destroyPQExpBuffer(query);
   18945              : 
   18946          131 :     nstats = PQntuples(res);
   18947              : 
   18948          131 :     if (nstats > 0)
   18949              :     {
   18950           36 :         PQExpBuffer out = createPQExpBuffer();
   18951              : 
   18952           36 :         int         i_inherited = PQfnumber(res, "inherited");
   18953           36 :         int         i_ndistinct = PQfnumber(res, "n_distinct");
   18954           36 :         int         i_dependencies = PQfnumber(res, "dependencies");
   18955           36 :         int         i_mcv = PQfnumber(res, "most_common_vals");
   18956           36 :         int         i_mcf = PQfnumber(res, "most_common_freqs");
   18957           36 :         int         i_mcbf = PQfnumber(res, "most_common_base_freqs");
   18958           36 :         int         i_exprs = PQfnumber(res, "exprs");
   18959              : 
   18960           72 :         for (int i = 0; i < nstats; i++)
   18961              :         {
   18962           36 :             TableInfo  *tbinfo = statsextinfo->stattable;
   18963              : 
   18964           36 :             if (PQgetisnull(res, i, i_inherited))
   18965            0 :                 pg_fatal("inherited cannot be NULL");
   18966              : 
   18967           36 :             appendPQExpBufferStr(out,
   18968              :                                  "SELECT * FROM pg_catalog.pg_restore_extended_stats(\n");
   18969           36 :             appendPQExpBuffer(out, "\t'version', '%d'::integer,\n",
   18970              :                               fout->remoteVersion);
   18971              : 
   18972              :             /* Relation information */
   18973           36 :             appendPQExpBufferStr(out, "\t'schemaname', ");
   18974           36 :             appendStringLiteralAH(out, tbinfo->dobj.namespace->dobj.name, fout);
   18975           36 :             appendPQExpBufferStr(out, ",\n\t'relname', ");
   18976           36 :             appendStringLiteralAH(out, tbinfo->dobj.name, fout);
   18977              : 
   18978              :             /* Extended statistics information */
   18979           36 :             appendPQExpBufferStr(out, ",\n\t'statistics_schemaname', ");
   18980           36 :             appendStringLiteralAH(out, statsextinfo->dobj.namespace->dobj.name, fout);
   18981           36 :             appendPQExpBufferStr(out, ",\n\t'statistics_name', ");
   18982           36 :             appendStringLiteralAH(out, statsextinfo->dobj.name, fout);
   18983           36 :             appendNamedArgument(out, fout, "inherited", "boolean",
   18984           36 :                                 PQgetvalue(res, i, i_inherited));
   18985              : 
   18986           36 :             if (!PQgetisnull(res, i, i_ndistinct))
   18987           32 :                 appendNamedArgument(out, fout, "n_distinct", "pg_ndistinct",
   18988           32 :                                     PQgetvalue(res, i, i_ndistinct));
   18989              : 
   18990           36 :             if (!PQgetisnull(res, i, i_dependencies))
   18991           33 :                 appendNamedArgument(out, fout, "dependencies", "pg_dependencies",
   18992           33 :                                     PQgetvalue(res, i, i_dependencies));
   18993              : 
   18994           36 :             if (!PQgetisnull(res, i, i_mcv))
   18995           35 :                 appendNamedArgument(out, fout, "most_common_vals", "text[]",
   18996           35 :                                     PQgetvalue(res, i, i_mcv));
   18997              : 
   18998           36 :             if (!PQgetisnull(res, i, i_mcf))
   18999           35 :                 appendNamedArgument(out, fout, "most_common_freqs", "double precision[]",
   19000           35 :                                     PQgetvalue(res, i, i_mcf));
   19001              : 
   19002           36 :             if (!PQgetisnull(res, i, i_mcbf))
   19003           35 :                 appendNamedArgument(out, fout, "most_common_base_freqs", "double precision[]",
   19004           35 :                                     PQgetvalue(res, i, i_mcbf));
   19005              : 
   19006           36 :             if (!PQgetisnull(res, i, i_exprs))
   19007           33 :                 appendNamedArgument(out, fout, "exprs", "jsonb",
   19008           33 :                                     PQgetvalue(res, i, i_exprs));
   19009              : 
   19010           36 :             appendPQExpBufferStr(out, "\n);\n");
   19011              :         }
   19012              : 
   19013           36 :         ArchiveEntry(fout, nilCatalogId, createDumpId(),
   19014           36 :                      ARCHIVE_OPTS(.tag = statsextinfo->dobj.name,
   19015              :                                   .namespace = statsextinfo->dobj.namespace->dobj.name,
   19016              :                                   .owner = statsextinfo->rolname,
   19017              :                                   .description = "EXTENDED STATISTICS DATA",
   19018              :                                   .section = SECTION_POST_DATA,
   19019              :                                   .createStmt = out->data,
   19020              :                                   .deps = &statsextinfo->dobj.dumpId,
   19021              :                                   .nDeps = 1));
   19022           36 :         destroyPQExpBuffer(out);
   19023              :     }
   19024          131 :     PQclear(res);
   19025              : }
   19026              : 
   19027              : /*
   19028              :  * dumpConstraint
   19029              :  *    write out to fout a user-defined constraint
   19030              :  */
   19031              : static void
   19032         2734 : dumpConstraint(Archive *fout, const ConstraintInfo *coninfo)
   19033              : {
   19034         2734 :     DumpOptions *dopt = fout->dopt;
   19035         2734 :     TableInfo  *tbinfo = coninfo->contable;
   19036              :     PQExpBuffer q;
   19037              :     PQExpBuffer delq;
   19038         2734 :     char       *tag = NULL;
   19039              :     char       *foreign;
   19040              : 
   19041              :     /* Do nothing if not dumping schema */
   19042         2734 :     if (!dopt->dumpSchema)
   19043           98 :         return;
   19044              : 
   19045         2636 :     q = createPQExpBuffer();
   19046         2636 :     delq = createPQExpBuffer();
   19047              : 
   19048         5098 :     foreign = tbinfo &&
   19049         2636 :         tbinfo->relkind == RELKIND_FOREIGN_TABLE ? "FOREIGN " : "";
   19050              : 
   19051         2636 :     if (coninfo->contype == 'p' ||
   19052         1287 :         coninfo->contype == 'u' ||
   19053         1043 :         coninfo->contype == 'x')
   19054         1603 :     {
   19055              :         /* Index-related constraint */
   19056              :         IndxInfo   *indxinfo;
   19057              :         int         k;
   19058              : 
   19059         1603 :         indxinfo = (IndxInfo *) findObjectByDumpId(coninfo->conindex);
   19060              : 
   19061         1603 :         if (indxinfo == NULL)
   19062            0 :             pg_fatal("missing index for constraint \"%s\"",
   19063              :                      coninfo->dobj.name);
   19064              : 
   19065         1603 :         if (dopt->binary_upgrade)
   19066          177 :             binary_upgrade_set_pg_class_oids(fout, q,
   19067              :                                              indxinfo->dobj.catId.oid);
   19068              : 
   19069         1603 :         appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s\n", foreign,
   19070         1603 :                           fmtQualifiedDumpable(tbinfo));
   19071         1603 :         appendPQExpBuffer(q, "    ADD CONSTRAINT %s ",
   19072         1603 :                           fmtId(coninfo->dobj.name));
   19073              : 
   19074         1603 :         if (coninfo->condef)
   19075              :         {
   19076              :             /* pg_get_constraintdef should have provided everything */
   19077           10 :             appendPQExpBuffer(q, "%s;\n", coninfo->condef);
   19078              :         }
   19079              :         else
   19080              :         {
   19081         1593 :             appendPQExpBufferStr(q,
   19082         1593 :                                  coninfo->contype == 'p' ? "PRIMARY KEY" : "UNIQUE");
   19083              : 
   19084              :             /*
   19085              :              * PRIMARY KEY constraints should not be using NULLS NOT DISTINCT
   19086              :              * indexes. Being able to create this was fixed, but we need to
   19087              :              * make the index distinct in order to be able to restore the
   19088              :              * dump.
   19089              :              */
   19090         1593 :             if (indxinfo->indnullsnotdistinct && coninfo->contype != 'p')
   19091            0 :                 appendPQExpBufferStr(q, " NULLS NOT DISTINCT");
   19092         1593 :             appendPQExpBufferStr(q, " (");
   19093         3803 :             for (k = 0; k < indxinfo->indnkeyattrs; k++)
   19094              :             {
   19095         2210 :                 int         indkey = (int) indxinfo->indkeys[k];
   19096              :                 const char *attname;
   19097              : 
   19098         2210 :                 if (indkey == InvalidAttrNumber)
   19099            0 :                     break;
   19100         2210 :                 attname = getAttrName(indkey, tbinfo);
   19101              : 
   19102         2210 :                 appendPQExpBuffer(q, "%s%s",
   19103              :                                   (k == 0) ? "" : ", ",
   19104              :                                   fmtId(attname));
   19105              :             }
   19106         1593 :             if (coninfo->conperiod)
   19107          109 :                 appendPQExpBufferStr(q, " WITHOUT OVERLAPS");
   19108              : 
   19109         1593 :             if (indxinfo->indnkeyattrs < indxinfo->indnattrs)
   19110           20 :                 appendPQExpBufferStr(q, ") INCLUDE (");
   19111              : 
   19112         1633 :             for (k = indxinfo->indnkeyattrs; k < indxinfo->indnattrs; k++)
   19113              :             {
   19114           40 :                 int         indkey = (int) indxinfo->indkeys[k];
   19115              :                 const char *attname;
   19116              : 
   19117           40 :                 if (indkey == InvalidAttrNumber)
   19118            0 :                     break;
   19119           40 :                 attname = getAttrName(indkey, tbinfo);
   19120              : 
   19121           80 :                 appendPQExpBuffer(q, "%s%s",
   19122           40 :                                   (k == indxinfo->indnkeyattrs) ? "" : ", ",
   19123              :                                   fmtId(attname));
   19124              :             }
   19125              : 
   19126         1593 :             appendPQExpBufferChar(q, ')');
   19127              : 
   19128         1593 :             if (nonemptyReloptions(indxinfo->indreloptions))
   19129              :             {
   19130            0 :                 appendPQExpBufferStr(q, " WITH (");
   19131            0 :                 appendReloptionsArrayAH(q, indxinfo->indreloptions, "", fout);
   19132            0 :                 appendPQExpBufferChar(q, ')');
   19133              :             }
   19134              : 
   19135         1593 :             if (coninfo->condeferrable)
   19136              :             {
   19137           25 :                 appendPQExpBufferStr(q, " DEFERRABLE");
   19138           25 :                 if (coninfo->condeferred)
   19139           15 :                     appendPQExpBufferStr(q, " INITIALLY DEFERRED");
   19140              :             }
   19141              : 
   19142         1593 :             appendPQExpBufferStr(q, ";\n");
   19143              :         }
   19144              : 
   19145              :         /*
   19146              :          * Append ALTER TABLE commands as needed to set properties that we
   19147              :          * only have ALTER TABLE syntax for.  Keep this in sync with the
   19148              :          * similar code in dumpIndex!
   19149              :          */
   19150              : 
   19151              :         /* If the index is clustered, we need to record that. */
   19152         1603 :         if (indxinfo->indisclustered)
   19153              :         {
   19154           32 :             appendPQExpBuffer(q, "\nALTER TABLE %s CLUSTER",
   19155           32 :                               fmtQualifiedDumpable(tbinfo));
   19156              :             /* index name is not qualified in this syntax */
   19157           32 :             appendPQExpBuffer(q, " ON %s;\n",
   19158           32 :                               fmtId(indxinfo->dobj.name));
   19159              :         }
   19160              : 
   19161              :         /* If the index defines identity, we need to record that. */
   19162         1603 :         if (indxinfo->indisreplident)
   19163              :         {
   19164            0 :             appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY USING",
   19165            0 :                               fmtQualifiedDumpable(tbinfo));
   19166              :             /* index name is not qualified in this syntax */
   19167            0 :             appendPQExpBuffer(q, " INDEX %s;\n",
   19168            0 :                               fmtId(indxinfo->dobj.name));
   19169              :         }
   19170              : 
   19171              :         /* Indexes can depend on extensions */
   19172         1603 :         append_depends_on_extension(fout, q, &indxinfo->dobj,
   19173              :                                     "pg_catalog.pg_class", "INDEX",
   19174         1603 :                                     fmtQualifiedDumpable(indxinfo));
   19175              : 
   19176         1603 :         appendPQExpBuffer(delq, "ALTER %sTABLE ONLY %s ", foreign,
   19177         1603 :                           fmtQualifiedDumpable(tbinfo));
   19178         1603 :         appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
   19179         1603 :                           fmtId(coninfo->dobj.name));
   19180              : 
   19181         1603 :         tag = psprintf("%s %s", tbinfo->dobj.name, coninfo->dobj.name);
   19182              : 
   19183         1603 :         if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   19184         1603 :             ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
   19185         1603 :                          ARCHIVE_OPTS(.tag = tag,
   19186              :                                       .namespace = tbinfo->dobj.namespace->dobj.name,
   19187              :                                       .tablespace = indxinfo->tablespace,
   19188              :                                       .owner = tbinfo->rolname,
   19189              :                                       .description = "CONSTRAINT",
   19190              :                                       .section = SECTION_POST_DATA,
   19191              :                                       .createStmt = q->data,
   19192              :                                       .dropStmt = delq->data));
   19193              :     }
   19194         1033 :     else if (coninfo->contype == 'f')
   19195              :     {
   19196              :         char       *only;
   19197              : 
   19198              :         /*
   19199              :          * Foreign keys on partitioned tables are always declared as
   19200              :          * inheriting to partitions; for all other cases, emit them as
   19201              :          * applying ONLY directly to the named table, because that's how they
   19202              :          * work for regular inherited tables.
   19203              :          */
   19204          219 :         only = tbinfo->relkind == RELKIND_PARTITIONED_TABLE ? "" : "ONLY ";
   19205              : 
   19206              :         /*
   19207              :          * XXX Potentially wrap in a 'SET CONSTRAINTS OFF' block so that the
   19208              :          * current table data is not processed
   19209              :          */
   19210          219 :         appendPQExpBuffer(q, "ALTER %sTABLE %s%s\n", foreign,
   19211          219 :                           only, fmtQualifiedDumpable(tbinfo));
   19212          219 :         appendPQExpBuffer(q, "    ADD CONSTRAINT %s %s;\n",
   19213          219 :                           fmtId(coninfo->dobj.name),
   19214          219 :                           coninfo->condef);
   19215              : 
   19216          219 :         appendPQExpBuffer(delq, "ALTER %sTABLE %s%s ", foreign,
   19217          219 :                           only, fmtQualifiedDumpable(tbinfo));
   19218          219 :         appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
   19219          219 :                           fmtId(coninfo->dobj.name));
   19220              : 
   19221          219 :         tag = psprintf("%s %s", tbinfo->dobj.name, coninfo->dobj.name);
   19222              : 
   19223          219 :         if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   19224          219 :             ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
   19225          219 :                          ARCHIVE_OPTS(.tag = tag,
   19226              :                                       .namespace = tbinfo->dobj.namespace->dobj.name,
   19227              :                                       .owner = tbinfo->rolname,
   19228              :                                       .description = "FK CONSTRAINT",
   19229              :                                       .section = SECTION_POST_DATA,
   19230              :                                       .createStmt = q->data,
   19231              :                                       .dropStmt = delq->data));
   19232              :     }
   19233          814 :     else if ((coninfo->contype == 'c' || coninfo->contype == 'n') && tbinfo)
   19234              :     {
   19235              :         /* CHECK or invalid not-null constraint on a table */
   19236              : 
   19237              :         /* Ignore if not to be dumped separately, or if it was inherited */
   19238          640 :         if (coninfo->separate && coninfo->conislocal)
   19239              :         {
   19240              :             const char *keyword;
   19241              : 
   19242          107 :             if (coninfo->contype == 'c')
   19243           45 :                 keyword = "CHECK CONSTRAINT";
   19244              :             else
   19245           62 :                 keyword = "CONSTRAINT";
   19246              : 
   19247              :             /* not ONLY since we want it to propagate to children */
   19248          107 :             appendPQExpBuffer(q, "ALTER %sTABLE %s\n", foreign,
   19249          107 :                               fmtQualifiedDumpable(tbinfo));
   19250          107 :             appendPQExpBuffer(q, "    ADD CONSTRAINT %s %s;\n",
   19251          107 :                               fmtId(coninfo->dobj.name),
   19252          107 :                               coninfo->condef);
   19253              : 
   19254          107 :             appendPQExpBuffer(delq, "ALTER %sTABLE %s ", foreign,
   19255          107 :                               fmtQualifiedDumpable(tbinfo));
   19256          107 :             appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
   19257          107 :                               fmtId(coninfo->dobj.name));
   19258              : 
   19259          107 :             tag = psprintf("%s %s", tbinfo->dobj.name, coninfo->dobj.name);
   19260              : 
   19261          107 :             if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   19262          107 :                 ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
   19263          107 :                              ARCHIVE_OPTS(.tag = tag,
   19264              :                                           .namespace = tbinfo->dobj.namespace->dobj.name,
   19265              :                                           .owner = tbinfo->rolname,
   19266              :                                           .description = keyword,
   19267              :                                           .section = SECTION_POST_DATA,
   19268              :                                           .createStmt = q->data,
   19269              :                                           .dropStmt = delq->data));
   19270              :         }
   19271              :     }
   19272          174 :     else if (tbinfo == NULL)
   19273              :     {
   19274              :         /* CHECK, NOT NULL constraint on a domain */
   19275          174 :         TypeInfo   *tyinfo = coninfo->condomain;
   19276              : 
   19277              :         Assert(coninfo->contype == 'c' || coninfo->contype == 'n');
   19278              : 
   19279              :         /* Ignore if not to be dumped separately */
   19280          174 :         if (coninfo->separate)
   19281              :         {
   19282              :             const char *keyword;
   19283              : 
   19284            5 :             if (coninfo->contype == 'c')
   19285            5 :                 keyword = "CHECK CONSTRAINT";
   19286              :             else
   19287            0 :                 keyword = "CONSTRAINT";
   19288              : 
   19289            5 :             appendPQExpBuffer(q, "ALTER DOMAIN %s\n",
   19290            5 :                               fmtQualifiedDumpable(tyinfo));
   19291            5 :             appendPQExpBuffer(q, "    ADD CONSTRAINT %s %s;\n",
   19292            5 :                               fmtId(coninfo->dobj.name),
   19293            5 :                               coninfo->condef);
   19294              : 
   19295            5 :             appendPQExpBuffer(delq, "ALTER DOMAIN %s ",
   19296            5 :                               fmtQualifiedDumpable(tyinfo));
   19297            5 :             appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
   19298            5 :                               fmtId(coninfo->dobj.name));
   19299              : 
   19300            5 :             tag = psprintf("%s %s", tyinfo->dobj.name, coninfo->dobj.name);
   19301              : 
   19302            5 :             if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   19303            5 :                 ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
   19304            5 :                              ARCHIVE_OPTS(.tag = tag,
   19305              :                                           .namespace = tyinfo->dobj.namespace->dobj.name,
   19306              :                                           .owner = tyinfo->rolname,
   19307              :                                           .description = keyword,
   19308              :                                           .section = SECTION_POST_DATA,
   19309              :                                           .createStmt = q->data,
   19310              :                                           .dropStmt = delq->data));
   19311              : 
   19312            5 :             if (coninfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   19313              :             {
   19314            5 :                 PQExpBuffer conprefix = createPQExpBuffer();
   19315            5 :                 char       *qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
   19316              : 
   19317            5 :                 appendPQExpBuffer(conprefix, "CONSTRAINT %s ON DOMAIN",
   19318            5 :                                   fmtId(coninfo->dobj.name));
   19319              : 
   19320            5 :                 dumpComment(fout, conprefix->data, qtypname,
   19321            5 :                             tyinfo->dobj.namespace->dobj.name,
   19322              :                             tyinfo->rolname,
   19323            5 :                             coninfo->dobj.catId, 0, coninfo->dobj.dumpId);
   19324            5 :                 destroyPQExpBuffer(conprefix);
   19325            5 :                 free(qtypname);
   19326              :             }
   19327              :         }
   19328              :     }
   19329              :     else
   19330              :     {
   19331            0 :         pg_fatal("unrecognized constraint type: %c",
   19332              :                  coninfo->contype);
   19333              :     }
   19334              : 
   19335              :     /* Dump Constraint Comments --- only works for table constraints */
   19336         2636 :     if (tbinfo && coninfo->separate &&
   19337         1959 :         coninfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   19338           47 :         dumpTableConstraintComment(fout, coninfo);
   19339              : 
   19340         2636 :     free(tag);
   19341         2636 :     destroyPQExpBuffer(q);
   19342         2636 :     destroyPQExpBuffer(delq);
   19343              : }
   19344              : 
   19345              : /*
   19346              :  * dumpTableConstraintComment --- dump a constraint's comment if any
   19347              :  *
   19348              :  * This is split out because we need the function in two different places
   19349              :  * depending on whether the constraint is dumped as part of CREATE TABLE
   19350              :  * or as a separate ALTER command.
   19351              :  */
   19352              : static void
   19353           84 : dumpTableConstraintComment(Archive *fout, const ConstraintInfo *coninfo)
   19354              : {
   19355           84 :     TableInfo  *tbinfo = coninfo->contable;
   19356           84 :     PQExpBuffer conprefix = createPQExpBuffer();
   19357              :     char       *qtabname;
   19358              : 
   19359           84 :     qtabname = pg_strdup(fmtId(tbinfo->dobj.name));
   19360              : 
   19361           84 :     appendPQExpBuffer(conprefix, "CONSTRAINT %s ON",
   19362           84 :                       fmtId(coninfo->dobj.name));
   19363              : 
   19364           84 :     if (coninfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   19365           84 :         dumpComment(fout, conprefix->data, qtabname,
   19366           84 :                     tbinfo->dobj.namespace->dobj.name,
   19367              :                     tbinfo->rolname,
   19368              :                     coninfo->dobj.catId, 0,
   19369           84 :                     coninfo->separate ? coninfo->dobj.dumpId : tbinfo->dobj.dumpId);
   19370              : 
   19371           84 :     destroyPQExpBuffer(conprefix);
   19372           84 :     free(qtabname);
   19373           84 : }
   19374              : 
   19375              : static inline SeqType
   19376          647 : parse_sequence_type(const char *name)
   19377              : {
   19378         1452 :     for (int i = 0; i < lengthof(SeqTypeNames); i++)
   19379              :     {
   19380         1452 :         if (strcmp(SeqTypeNames[i], name) == 0)
   19381          647 :             return (SeqType) i;
   19382              :     }
   19383              : 
   19384            0 :     pg_fatal("unrecognized sequence type: %s", name);
   19385              :     return (SeqType) 0;         /* keep compiler quiet */
   19386              : }
   19387              : 
   19388              : /*
   19389              :  * bsearch() comparator for SequenceItem
   19390              :  */
   19391              : static int
   19392         2971 : SequenceItemCmp(const void *p1, const void *p2)
   19393              : {
   19394         2971 :     SequenceItem v1 = *((const SequenceItem *) p1);
   19395         2971 :     SequenceItem v2 = *((const SequenceItem *) p2);
   19396              : 
   19397         2971 :     return pg_cmp_u32(v1.oid, v2.oid);
   19398              : }
   19399              : 
   19400              : /*
   19401              :  * collectSequences
   19402              :  *
   19403              :  * Construct a table of sequence information.  This table is sorted by OID for
   19404              :  * speed in lookup.
   19405              :  */
   19406              : static void
   19407          259 : collectSequences(Archive *fout)
   19408              : {
   19409              :     PGresult   *res;
   19410              :     const char *query;
   19411              : 
   19412              :     /*
   19413              :      * Before Postgres 10, sequence metadata is in the sequence itself.  With
   19414              :      * some extra effort, we might be able to use the sorted table for those
   19415              :      * versions, but for now it seems unlikely to be worth it.
   19416              :      *
   19417              :      * Since version 18, we can gather the sequence data in this query with
   19418              :      * pg_get_sequence_data(), but we only do so for non-schema-only dumps.
   19419              :      */
   19420          259 :     if (fout->remoteVersion < 100000)
   19421            0 :         return;
   19422          259 :     else if (fout->remoteVersion < 180000 ||
   19423          259 :              (!fout->dopt->dumpData && !fout->dopt->sequence_data))
   19424            8 :         query = "SELECT seqrelid, format_type(seqtypid, NULL), "
   19425              :             "seqstart, seqincrement, "
   19426              :             "seqmax, seqmin, "
   19427              :             "seqcache, seqcycle, "
   19428              :             "NULL, 'f' "
   19429              :             "FROM pg_catalog.pg_sequence "
   19430              :             "ORDER BY seqrelid";
   19431              :     else
   19432          251 :         query = "SELECT seqrelid, format_type(seqtypid, NULL), "
   19433              :             "seqstart, seqincrement, "
   19434              :             "seqmax, seqmin, "
   19435              :             "seqcache, seqcycle, "
   19436              :             "last_value, is_called "
   19437              :             "FROM pg_catalog.pg_sequence, "
   19438              :             "pg_get_sequence_data(seqrelid) "
   19439              :             "ORDER BY seqrelid;";
   19440              : 
   19441          259 :     res = ExecuteSqlQuery(fout, query, PGRES_TUPLES_OK);
   19442              : 
   19443          259 :     nsequences = PQntuples(res);
   19444          259 :     sequences = pg_malloc_array(SequenceItem, nsequences);
   19445              : 
   19446          906 :     for (int i = 0; i < nsequences; i++)
   19447              :     {
   19448          647 :         sequences[i].oid = atooid(PQgetvalue(res, i, 0));
   19449          647 :         sequences[i].seqtype = parse_sequence_type(PQgetvalue(res, i, 1));
   19450          647 :         sequences[i].startv = strtoi64(PQgetvalue(res, i, 2), NULL, 10);
   19451          647 :         sequences[i].incby = strtoi64(PQgetvalue(res, i, 3), NULL, 10);
   19452          647 :         sequences[i].maxv = strtoi64(PQgetvalue(res, i, 4), NULL, 10);
   19453          647 :         sequences[i].minv = strtoi64(PQgetvalue(res, i, 5), NULL, 10);
   19454          647 :         sequences[i].cache = strtoi64(PQgetvalue(res, i, 6), NULL, 10);
   19455          647 :         sequences[i].cycled = (strcmp(PQgetvalue(res, i, 7), "t") == 0);
   19456          647 :         sequences[i].last_value = strtoi64(PQgetvalue(res, i, 8), NULL, 10);
   19457          647 :         sequences[i].is_called = (strcmp(PQgetvalue(res, i, 9), "t") == 0);
   19458          647 :         sequences[i].null_seqtuple = (PQgetisnull(res, i, 8) || PQgetisnull(res, i, 9));
   19459              :     }
   19460              : 
   19461          259 :     PQclear(res);
   19462              : }
   19463              : 
   19464              : /*
   19465              :  * dumpSequence
   19466              :  *    write the declaration (not data) of one user-defined sequence
   19467              :  */
   19468              : static void
   19469          384 : dumpSequence(Archive *fout, const TableInfo *tbinfo)
   19470              : {
   19471          384 :     DumpOptions *dopt = fout->dopt;
   19472              :     SequenceItem *seq;
   19473              :     bool        is_ascending;
   19474              :     int64       default_minv,
   19475              :                 default_maxv;
   19476          384 :     PQExpBuffer query = createPQExpBuffer();
   19477          384 :     PQExpBuffer delqry = createPQExpBuffer();
   19478              :     char       *qseqname;
   19479          384 :     TableInfo  *owning_tab = NULL;
   19480              : 
   19481          384 :     qseqname = pg_strdup(fmtId(tbinfo->dobj.name));
   19482              : 
   19483              :     /*
   19484              :      * For versions >= 10, the sequence information is gathered in a sorted
   19485              :      * table before any calls to dumpSequence().  See collectSequences() for
   19486              :      * more information.
   19487              :      */
   19488          384 :     if (fout->remoteVersion >= 100000)
   19489              :     {
   19490          384 :         SequenceItem key = {0};
   19491              : 
   19492              :         Assert(sequences);
   19493              : 
   19494          384 :         key.oid = tbinfo->dobj.catId.oid;
   19495          384 :         seq = bsearch(&key, sequences, nsequences,
   19496              :                       sizeof(SequenceItem), SequenceItemCmp);
   19497              :     }
   19498              :     else
   19499              :     {
   19500              :         PGresult   *res;
   19501              : 
   19502              :         /*
   19503              :          * Before PostgreSQL 10, sequence metadata is in the sequence itself.
   19504              :          *
   19505              :          * Note: it might seem that 'bigint' potentially needs to be
   19506              :          * schema-qualified, but actually that's a keyword.
   19507              :          */
   19508            0 :         appendPQExpBuffer(query,
   19509              :                           "SELECT 'bigint' AS sequence_type, "
   19510              :                           "start_value, increment_by, max_value, min_value, "
   19511              :                           "cache_value, is_cycled FROM %s",
   19512            0 :                           fmtQualifiedDumpable(tbinfo));
   19513              : 
   19514            0 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   19515              : 
   19516            0 :         if (PQntuples(res) != 1)
   19517            0 :             pg_fatal(ngettext("query to get data of sequence \"%s\" returned %d row (expected 1)",
   19518              :                               "query to get data of sequence \"%s\" returned %d rows (expected 1)",
   19519              :                               PQntuples(res)),
   19520              :                      tbinfo->dobj.name, PQntuples(res));
   19521              : 
   19522            0 :         seq = pg_malloc0_object(SequenceItem);
   19523            0 :         seq->seqtype = parse_sequence_type(PQgetvalue(res, 0, 0));
   19524            0 :         seq->startv = strtoi64(PQgetvalue(res, 0, 1), NULL, 10);
   19525            0 :         seq->incby = strtoi64(PQgetvalue(res, 0, 2), NULL, 10);
   19526            0 :         seq->maxv = strtoi64(PQgetvalue(res, 0, 3), NULL, 10);
   19527            0 :         seq->minv = strtoi64(PQgetvalue(res, 0, 4), NULL, 10);
   19528            0 :         seq->cache = strtoi64(PQgetvalue(res, 0, 5), NULL, 10);
   19529            0 :         seq->cycled = (strcmp(PQgetvalue(res, 0, 6), "t") == 0);
   19530              : 
   19531            0 :         PQclear(res);
   19532              :     }
   19533              : 
   19534              :     /* Calculate default limits for a sequence of this type */
   19535          384 :     is_ascending = (seq->incby >= 0);
   19536          384 :     if (seq->seqtype == SEQTYPE_SMALLINT)
   19537              :     {
   19538           25 :         default_minv = is_ascending ? 1 : PG_INT16_MIN;
   19539           25 :         default_maxv = is_ascending ? PG_INT16_MAX : -1;
   19540              :     }
   19541          359 :     else if (seq->seqtype == SEQTYPE_INTEGER)
   19542              :     {
   19543          284 :         default_minv = is_ascending ? 1 : PG_INT32_MIN;
   19544          284 :         default_maxv = is_ascending ? PG_INT32_MAX : -1;
   19545              :     }
   19546           75 :     else if (seq->seqtype == SEQTYPE_BIGINT)
   19547              :     {
   19548           75 :         default_minv = is_ascending ? 1 : PG_INT64_MIN;
   19549           75 :         default_maxv = is_ascending ? PG_INT64_MAX : -1;
   19550              :     }
   19551              :     else
   19552              :     {
   19553            0 :         pg_fatal("unrecognized sequence type: %d", seq->seqtype);
   19554              :         default_minv = default_maxv = 0;    /* keep compiler quiet */
   19555              :     }
   19556              : 
   19557              :     /*
   19558              :      * Identity sequences are not to be dropped separately.
   19559              :      */
   19560          384 :     if (!tbinfo->is_identity_sequence)
   19561              :     {
   19562          242 :         appendPQExpBuffer(delqry, "DROP SEQUENCE %s;\n",
   19563          242 :                           fmtQualifiedDumpable(tbinfo));
   19564              :     }
   19565              : 
   19566          384 :     resetPQExpBuffer(query);
   19567              : 
   19568          384 :     if (dopt->binary_upgrade)
   19569              :     {
   19570           66 :         binary_upgrade_set_pg_class_oids(fout, query,
   19571           66 :                                          tbinfo->dobj.catId.oid);
   19572              : 
   19573              :         /*
   19574              :          * In older PG versions a sequence will have a pg_type entry, but v14
   19575              :          * and up don't use that, so don't attempt to preserve the type OID.
   19576              :          */
   19577              :     }
   19578              : 
   19579          384 :     if (tbinfo->is_identity_sequence)
   19580              :     {
   19581          142 :         owning_tab = findTableByOid(tbinfo->owning_tab);
   19582              : 
   19583          142 :         appendPQExpBuffer(query,
   19584              :                           "ALTER TABLE %s ",
   19585          142 :                           fmtQualifiedDumpable(owning_tab));
   19586          142 :         appendPQExpBuffer(query,
   19587              :                           "ALTER COLUMN %s ADD GENERATED ",
   19588          142 :                           fmtId(owning_tab->attnames[tbinfo->owning_col - 1]));
   19589          142 :         if (owning_tab->attidentity[tbinfo->owning_col - 1] == ATTRIBUTE_IDENTITY_ALWAYS)
   19590          102 :             appendPQExpBufferStr(query, "ALWAYS");
   19591           40 :         else if (owning_tab->attidentity[tbinfo->owning_col - 1] == ATTRIBUTE_IDENTITY_BY_DEFAULT)
   19592           40 :             appendPQExpBufferStr(query, "BY DEFAULT");
   19593          142 :         appendPQExpBuffer(query, " AS IDENTITY (\n    SEQUENCE NAME %s\n",
   19594          142 :                           fmtQualifiedDumpable(tbinfo));
   19595              : 
   19596              :         /*
   19597              :          * Emit persistence option only if it's different from the owning
   19598              :          * table's.  This avoids using this new syntax unnecessarily.
   19599              :          */
   19600          142 :         if (tbinfo->relpersistence != owning_tab->relpersistence)
   19601           10 :             appendPQExpBuffer(query, "    %s\n",
   19602           10 :                               tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED ?
   19603              :                               "UNLOGGED" : "LOGGED");
   19604              :     }
   19605              :     else
   19606              :     {
   19607          242 :         appendPQExpBuffer(query,
   19608              :                           "CREATE %sSEQUENCE %s\n",
   19609          242 :                           tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED ?
   19610              :                           "UNLOGGED " : "",
   19611          242 :                           fmtQualifiedDumpable(tbinfo));
   19612              : 
   19613          242 :         if (seq->seqtype != SEQTYPE_BIGINT)
   19614          182 :             appendPQExpBuffer(query, "    AS %s\n", SeqTypeNames[seq->seqtype]);
   19615              :     }
   19616              : 
   19617          384 :     appendPQExpBuffer(query, "    START WITH " INT64_FORMAT "\n", seq->startv);
   19618              : 
   19619          384 :     appendPQExpBuffer(query, "    INCREMENT BY " INT64_FORMAT "\n", seq->incby);
   19620              : 
   19621          384 :     if (seq->minv != default_minv)
   19622           15 :         appendPQExpBuffer(query, "    MINVALUE " INT64_FORMAT "\n", seq->minv);
   19623              :     else
   19624          369 :         appendPQExpBufferStr(query, "    NO MINVALUE\n");
   19625              : 
   19626          384 :     if (seq->maxv != default_maxv)
   19627           15 :         appendPQExpBuffer(query, "    MAXVALUE " INT64_FORMAT "\n", seq->maxv);
   19628              :     else
   19629          369 :         appendPQExpBufferStr(query, "    NO MAXVALUE\n");
   19630              : 
   19631          384 :     appendPQExpBuffer(query,
   19632              :                       "    CACHE " INT64_FORMAT "%s",
   19633          384 :                       seq->cache, (seq->cycled ? "\n    CYCLE" : ""));
   19634              : 
   19635          384 :     if (tbinfo->is_identity_sequence)
   19636          142 :         appendPQExpBufferStr(query, "\n);\n");
   19637              :     else
   19638          242 :         appendPQExpBufferStr(query, ";\n");
   19639              : 
   19640              :     /* binary_upgrade:  no need to clear TOAST table oid */
   19641              : 
   19642          384 :     if (dopt->binary_upgrade)
   19643           66 :         binary_upgrade_extension_member(query, &tbinfo->dobj,
   19644              :                                         "SEQUENCE", qseqname,
   19645           66 :                                         tbinfo->dobj.namespace->dobj.name);
   19646              : 
   19647          384 :     if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   19648          384 :         ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
   19649          384 :                      ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
   19650              :                                   .namespace = tbinfo->dobj.namespace->dobj.name,
   19651              :                                   .owner = tbinfo->rolname,
   19652              :                                   .description = "SEQUENCE",
   19653              :                                   .section = SECTION_PRE_DATA,
   19654              :                                   .createStmt = query->data,
   19655              :                                   .dropStmt = delqry->data));
   19656              : 
   19657              :     /*
   19658              :      * If the sequence is owned by a table column, emit the ALTER for it as a
   19659              :      * separate TOC entry immediately following the sequence's own entry. It's
   19660              :      * OK to do this rather than using full sorting logic, because the
   19661              :      * dependency that tells us it's owned will have forced the table to be
   19662              :      * created first.  We can't just include the ALTER in the TOC entry
   19663              :      * because it will fail if we haven't reassigned the sequence owner to
   19664              :      * match the table's owner.
   19665              :      *
   19666              :      * We need not schema-qualify the table reference because both sequence
   19667              :      * and table must be in the same schema.
   19668              :      */
   19669          384 :     if (OidIsValid(tbinfo->owning_tab) && !tbinfo->is_identity_sequence)
   19670              :     {
   19671          137 :         owning_tab = findTableByOid(tbinfo->owning_tab);
   19672              : 
   19673          137 :         if (owning_tab == NULL)
   19674            0 :             pg_fatal("failed sanity check, parent table with OID %u of sequence with OID %u not found",
   19675              :                      tbinfo->owning_tab, tbinfo->dobj.catId.oid);
   19676              : 
   19677          137 :         if (owning_tab->dobj.dump & DUMP_COMPONENT_DEFINITION)
   19678              :         {
   19679          135 :             resetPQExpBuffer(query);
   19680          135 :             appendPQExpBuffer(query, "ALTER SEQUENCE %s",
   19681          135 :                               fmtQualifiedDumpable(tbinfo));
   19682          135 :             appendPQExpBuffer(query, " OWNED BY %s",
   19683          135 :                               fmtQualifiedDumpable(owning_tab));
   19684          135 :             appendPQExpBuffer(query, ".%s;\n",
   19685          135 :                               fmtId(owning_tab->attnames[tbinfo->owning_col - 1]));
   19686              : 
   19687          135 :             if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   19688          135 :                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
   19689          135 :                              ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
   19690              :                                           .namespace = tbinfo->dobj.namespace->dobj.name,
   19691              :                                           .owner = tbinfo->rolname,
   19692              :                                           .description = "SEQUENCE OWNED BY",
   19693              :                                           .section = SECTION_PRE_DATA,
   19694              :                                           .createStmt = query->data,
   19695              :                                           .deps = &(tbinfo->dobj.dumpId),
   19696              :                                           .nDeps = 1));
   19697              :         }
   19698              :     }
   19699              : 
   19700              :     /* Dump Sequence Comments and Security Labels */
   19701          384 :     if (tbinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   19702            0 :         dumpComment(fout, "SEQUENCE", qseqname,
   19703            0 :                     tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
   19704            0 :                     tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
   19705              : 
   19706          384 :     if (tbinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
   19707            0 :         dumpSecLabel(fout, "SEQUENCE", qseqname,
   19708            0 :                      tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
   19709            0 :                      tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
   19710              : 
   19711          384 :     if (fout->remoteVersion < 100000)
   19712            0 :         pg_free(seq);
   19713          384 :     destroyPQExpBuffer(query);
   19714          384 :     destroyPQExpBuffer(delqry);
   19715          384 :     free(qseqname);
   19716          384 : }
   19717              : 
   19718              : /*
   19719              :  * dumpSequenceData
   19720              :  *    write the data of one user-defined sequence
   19721              :  */
   19722              : static void
   19723          402 : dumpSequenceData(Archive *fout, const TableDataInfo *tdinfo)
   19724              : {
   19725          402 :     TableInfo  *tbinfo = tdinfo->tdtable;
   19726              :     int64       last;
   19727              :     bool        called;
   19728              :     PQExpBuffer query;
   19729              : 
   19730              :     /* needn't bother if not dumping sequence data */
   19731          402 :     if (!fout->dopt->dumpData && !fout->dopt->sequence_data)
   19732            1 :         return;
   19733              : 
   19734          401 :     query = createPQExpBuffer();
   19735              : 
   19736              :     /*
   19737              :      * For versions >= 18, the sequence information is gathered in the sorted
   19738              :      * array before any calls to dumpSequenceData().  See collectSequences()
   19739              :      * for more information.
   19740              :      *
   19741              :      * For older versions, we have to query the sequence relations
   19742              :      * individually.
   19743              :      */
   19744          401 :     if (fout->remoteVersion < 180000)
   19745              :     {
   19746              :         PGresult   *res;
   19747              : 
   19748            0 :         appendPQExpBuffer(query,
   19749              :                           "SELECT last_value, is_called FROM %s",
   19750            0 :                           fmtQualifiedDumpable(tbinfo));
   19751              : 
   19752            0 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   19753              : 
   19754            0 :         if (PQntuples(res) != 1)
   19755            0 :             pg_fatal(ngettext("query to get data of sequence \"%s\" returned %d row (expected 1)",
   19756              :                               "query to get data of sequence \"%s\" returned %d rows (expected 1)",
   19757              :                               PQntuples(res)),
   19758              :                      tbinfo->dobj.name, PQntuples(res));
   19759              : 
   19760            0 :         last = strtoi64(PQgetvalue(res, 0, 0), NULL, 10);
   19761            0 :         called = (strcmp(PQgetvalue(res, 0, 1), "t") == 0);
   19762              : 
   19763            0 :         PQclear(res);
   19764              :     }
   19765              :     else
   19766              :     {
   19767          401 :         SequenceItem key = {0};
   19768              :         SequenceItem *entry;
   19769              : 
   19770              :         Assert(sequences);
   19771              :         Assert(tbinfo->dobj.catId.oid);
   19772              : 
   19773          401 :         key.oid = tbinfo->dobj.catId.oid;
   19774          401 :         entry = bsearch(&key, sequences, nsequences,
   19775              :                         sizeof(SequenceItem), SequenceItemCmp);
   19776              : 
   19777          401 :         if (entry->null_seqtuple)
   19778            0 :             pg_fatal("failed to get data for sequence \"%s\"; user may lack "
   19779              :                      "SELECT privilege on the sequence or the sequence may "
   19780              :                      "have been concurrently dropped",
   19781              :                      tbinfo->dobj.name);
   19782              : 
   19783          401 :         last = entry->last_value;
   19784          401 :         called = entry->is_called;
   19785              :     }
   19786              : 
   19787          401 :     resetPQExpBuffer(query);
   19788          401 :     appendPQExpBufferStr(query, "SELECT pg_catalog.setval(");
   19789          401 :     appendStringLiteralAH(query, fmtQualifiedDumpable(tbinfo), fout);
   19790          401 :     appendPQExpBuffer(query, ", " INT64_FORMAT ", %s);\n",
   19791              :                       last, (called ? "true" : "false"));
   19792              : 
   19793          401 :     if (tdinfo->dobj.dump & DUMP_COMPONENT_DATA)
   19794          401 :         ArchiveEntry(fout, nilCatalogId, createDumpId(),
   19795          401 :                      ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
   19796              :                                   .namespace = tbinfo->dobj.namespace->dobj.name,
   19797              :                                   .owner = tbinfo->rolname,
   19798              :                                   .description = "SEQUENCE SET",
   19799              :                                   .section = SECTION_DATA,
   19800              :                                   .createStmt = query->data,
   19801              :                                   .deps = &(tbinfo->dobj.dumpId),
   19802              :                                   .nDeps = 1));
   19803              : 
   19804          401 :     destroyPQExpBuffer(query);
   19805              : }
   19806              : 
   19807              : /*
   19808              :  * dumpTrigger
   19809              :  *    write the declaration of one user-defined table trigger
   19810              :  */
   19811              : static void
   19812          523 : dumpTrigger(Archive *fout, const TriggerInfo *tginfo)
   19813              : {
   19814          523 :     DumpOptions *dopt = fout->dopt;
   19815          523 :     TableInfo  *tbinfo = tginfo->tgtable;
   19816              :     PQExpBuffer query;
   19817              :     PQExpBuffer delqry;
   19818              :     PQExpBuffer trigprefix;
   19819              :     PQExpBuffer trigidentity;
   19820              :     char       *qtabname;
   19821              :     char       *tag;
   19822              : 
   19823              :     /* Do nothing if not dumping schema */
   19824          523 :     if (!dopt->dumpSchema)
   19825           31 :         return;
   19826              : 
   19827          492 :     query = createPQExpBuffer();
   19828          492 :     delqry = createPQExpBuffer();
   19829          492 :     trigprefix = createPQExpBuffer();
   19830          492 :     trigidentity = createPQExpBuffer();
   19831              : 
   19832          492 :     qtabname = pg_strdup(fmtId(tbinfo->dobj.name));
   19833              : 
   19834          492 :     appendPQExpBuffer(trigidentity, "%s ", fmtId(tginfo->dobj.name));
   19835          492 :     appendPQExpBuffer(trigidentity, "ON %s", fmtQualifiedDumpable(tbinfo));
   19836              : 
   19837          492 :     appendPQExpBuffer(query, "%s;\n", tginfo->tgdef);
   19838          492 :     appendPQExpBuffer(delqry, "DROP TRIGGER %s;\n", trigidentity->data);
   19839              : 
   19840              :     /* Triggers can depend on extensions */
   19841          492 :     append_depends_on_extension(fout, query, &tginfo->dobj,
   19842              :                                 "pg_catalog.pg_trigger", "TRIGGER",
   19843          492 :                                 trigidentity->data);
   19844              : 
   19845          492 :     if (tginfo->tgispartition)
   19846              :     {
   19847              :         Assert(tbinfo->ispartition);
   19848              : 
   19849              :         /*
   19850              :          * Partition triggers only appear here because their 'tgenabled' flag
   19851              :          * differs from its parent's.  The trigger is created already, so
   19852              :          * remove the CREATE and replace it with an ALTER.  (Clear out the
   19853              :          * DROP query too, so that pg_dump --create does not cause errors.)
   19854              :          */
   19855          109 :         resetPQExpBuffer(query);
   19856          109 :         resetPQExpBuffer(delqry);
   19857          109 :         appendPQExpBuffer(query, "\nALTER %sTABLE %s ",
   19858          109 :                           tbinfo->relkind == RELKIND_FOREIGN_TABLE ? "FOREIGN " : "",
   19859          109 :                           fmtQualifiedDumpable(tbinfo));
   19860          109 :         switch (tginfo->tgenabled)
   19861              :         {
   19862           38 :             case 'f':
   19863              :             case 'D':
   19864           38 :                 appendPQExpBufferStr(query, "DISABLE");
   19865           38 :                 break;
   19866            0 :             case 't':
   19867              :             case 'O':
   19868            0 :                 appendPQExpBufferStr(query, "ENABLE");
   19869            0 :                 break;
   19870           33 :             case 'R':
   19871           33 :                 appendPQExpBufferStr(query, "ENABLE REPLICA");
   19872           33 :                 break;
   19873           38 :             case 'A':
   19874           38 :                 appendPQExpBufferStr(query, "ENABLE ALWAYS");
   19875           38 :                 break;
   19876              :         }
   19877          109 :         appendPQExpBuffer(query, " TRIGGER %s;\n",
   19878          109 :                           fmtId(tginfo->dobj.name));
   19879              :     }
   19880          383 :     else if (tginfo->tgenabled != 't' && tginfo->tgenabled != 'O')
   19881              :     {
   19882            0 :         appendPQExpBuffer(query, "\nALTER %sTABLE %s ",
   19883            0 :                           tbinfo->relkind == RELKIND_FOREIGN_TABLE ? "FOREIGN " : "",
   19884            0 :                           fmtQualifiedDumpable(tbinfo));
   19885            0 :         switch (tginfo->tgenabled)
   19886              :         {
   19887            0 :             case 'D':
   19888              :             case 'f':
   19889            0 :                 appendPQExpBufferStr(query, "DISABLE");
   19890            0 :                 break;
   19891            0 :             case 'A':
   19892            0 :                 appendPQExpBufferStr(query, "ENABLE ALWAYS");
   19893            0 :                 break;
   19894            0 :             case 'R':
   19895            0 :                 appendPQExpBufferStr(query, "ENABLE REPLICA");
   19896            0 :                 break;
   19897            0 :             default:
   19898            0 :                 appendPQExpBufferStr(query, "ENABLE");
   19899            0 :                 break;
   19900              :         }
   19901            0 :         appendPQExpBuffer(query, " TRIGGER %s;\n",
   19902            0 :                           fmtId(tginfo->dobj.name));
   19903              :     }
   19904              : 
   19905          492 :     appendPQExpBuffer(trigprefix, "TRIGGER %s ON",
   19906          492 :                       fmtId(tginfo->dobj.name));
   19907              : 
   19908          492 :     tag = psprintf("%s %s", tbinfo->dobj.name, tginfo->dobj.name);
   19909              : 
   19910          492 :     if (tginfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   19911          492 :         ArchiveEntry(fout, tginfo->dobj.catId, tginfo->dobj.dumpId,
   19912          492 :                      ARCHIVE_OPTS(.tag = tag,
   19913              :                                   .namespace = tbinfo->dobj.namespace->dobj.name,
   19914              :                                   .owner = tbinfo->rolname,
   19915              :                                   .description = "TRIGGER",
   19916              :                                   .section = SECTION_POST_DATA,
   19917              :                                   .createStmt = query->data,
   19918              :                                   .dropStmt = delqry->data));
   19919              : 
   19920          492 :     if (tginfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   19921            0 :         dumpComment(fout, trigprefix->data, qtabname,
   19922            0 :                     tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
   19923            0 :                     tginfo->dobj.catId, 0, tginfo->dobj.dumpId);
   19924              : 
   19925          492 :     free(tag);
   19926          492 :     destroyPQExpBuffer(query);
   19927          492 :     destroyPQExpBuffer(delqry);
   19928          492 :     destroyPQExpBuffer(trigprefix);
   19929          492 :     destroyPQExpBuffer(trigidentity);
   19930          492 :     free(qtabname);
   19931              : }
   19932              : 
   19933              : /*
   19934              :  * dumpEventTrigger
   19935              :  *    write the declaration of one user-defined event trigger
   19936              :  */
   19937              : static void
   19938           42 : dumpEventTrigger(Archive *fout, const EventTriggerInfo *evtinfo)
   19939              : {
   19940           42 :     DumpOptions *dopt = fout->dopt;
   19941              :     PQExpBuffer query;
   19942              :     PQExpBuffer delqry;
   19943              :     char       *qevtname;
   19944              : 
   19945              :     /* Do nothing if not dumping schema */
   19946           42 :     if (!dopt->dumpSchema)
   19947            6 :         return;
   19948              : 
   19949           36 :     query = createPQExpBuffer();
   19950           36 :     delqry = createPQExpBuffer();
   19951              : 
   19952           36 :     qevtname = pg_strdup(fmtId(evtinfo->dobj.name));
   19953              : 
   19954           36 :     appendPQExpBufferStr(query, "CREATE EVENT TRIGGER ");
   19955           36 :     appendPQExpBufferStr(query, qevtname);
   19956           36 :     appendPQExpBufferStr(query, " ON ");
   19957           36 :     appendPQExpBufferStr(query, fmtId(evtinfo->evtevent));
   19958              : 
   19959           36 :     if (strcmp("", evtinfo->evttags) != 0)
   19960              :     {
   19961            5 :         appendPQExpBufferStr(query, "\n         WHEN TAG IN (");
   19962            5 :         appendPQExpBufferStr(query, evtinfo->evttags);
   19963            5 :         appendPQExpBufferChar(query, ')');
   19964              :     }
   19965              : 
   19966           36 :     appendPQExpBufferStr(query, "\n   EXECUTE FUNCTION ");
   19967           36 :     appendPQExpBufferStr(query, evtinfo->evtfname);
   19968           36 :     appendPQExpBufferStr(query, "();\n");
   19969              : 
   19970           36 :     if (evtinfo->evtenabled != 'O')
   19971              :     {
   19972            0 :         appendPQExpBuffer(query, "\nALTER EVENT TRIGGER %s ",
   19973              :                           qevtname);
   19974            0 :         switch (evtinfo->evtenabled)
   19975              :         {
   19976            0 :             case 'D':
   19977            0 :                 appendPQExpBufferStr(query, "DISABLE");
   19978            0 :                 break;
   19979            0 :             case 'A':
   19980            0 :                 appendPQExpBufferStr(query, "ENABLE ALWAYS");
   19981            0 :                 break;
   19982            0 :             case 'R':
   19983            0 :                 appendPQExpBufferStr(query, "ENABLE REPLICA");
   19984            0 :                 break;
   19985            0 :             default:
   19986            0 :                 appendPQExpBufferStr(query, "ENABLE");
   19987            0 :                 break;
   19988              :         }
   19989            0 :         appendPQExpBufferStr(query, ";\n");
   19990              :     }
   19991              : 
   19992           36 :     appendPQExpBuffer(delqry, "DROP EVENT TRIGGER %s;\n",
   19993              :                       qevtname);
   19994              : 
   19995           36 :     if (dopt->binary_upgrade)
   19996            2 :         binary_upgrade_extension_member(query, &evtinfo->dobj,
   19997              :                                         "EVENT TRIGGER", qevtname, NULL);
   19998              : 
   19999           36 :     if (evtinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   20000           36 :         ArchiveEntry(fout, evtinfo->dobj.catId, evtinfo->dobj.dumpId,
   20001           36 :                      ARCHIVE_OPTS(.tag = evtinfo->dobj.name,
   20002              :                                   .owner = evtinfo->evtowner,
   20003              :                                   .description = "EVENT TRIGGER",
   20004              :                                   .section = SECTION_POST_DATA,
   20005              :                                   .createStmt = query->data,
   20006              :                                   .dropStmt = delqry->data));
   20007              : 
   20008           36 :     if (evtinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   20009            0 :         dumpComment(fout, "EVENT TRIGGER", qevtname,
   20010            0 :                     NULL, evtinfo->evtowner,
   20011            0 :                     evtinfo->dobj.catId, 0, evtinfo->dobj.dumpId);
   20012              : 
   20013           36 :     if (evtinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
   20014            0 :         dumpSecLabel(fout, "EVENT TRIGGER", qevtname,
   20015            0 :                      NULL, evtinfo->evtowner,
   20016            0 :                      evtinfo->dobj.catId, 0, evtinfo->dobj.dumpId);
   20017              : 
   20018           36 :     destroyPQExpBuffer(query);
   20019           36 :     destroyPQExpBuffer(delqry);
   20020           36 :     free(qevtname);
   20021              : }
   20022              : 
   20023              : /*
   20024              :  * dumpRule
   20025              :  *      Dump a rule
   20026              :  */
   20027              : static void
   20028         1164 : dumpRule(Archive *fout, const RuleInfo *rinfo)
   20029              : {
   20030         1164 :     DumpOptions *dopt = fout->dopt;
   20031         1164 :     TableInfo  *tbinfo = rinfo->ruletable;
   20032              :     bool        is_view;
   20033              :     PQExpBuffer query;
   20034              :     PQExpBuffer cmd;
   20035              :     PQExpBuffer delcmd;
   20036              :     PQExpBuffer ruleprefix;
   20037              :     char       *qtabname;
   20038              :     PGresult   *res;
   20039              :     char       *tag;
   20040              : 
   20041              :     /* Do nothing if not dumping schema */
   20042         1164 :     if (!dopt->dumpSchema)
   20043           60 :         return;
   20044              : 
   20045              :     /*
   20046              :      * If it is an ON SELECT rule that is created implicitly by CREATE VIEW,
   20047              :      * we do not want to dump it as a separate object.
   20048              :      */
   20049         1104 :     if (!rinfo->separate)
   20050          893 :         return;
   20051              : 
   20052              :     /*
   20053              :      * If it's an ON SELECT rule, we want to print it as a view definition,
   20054              :      * instead of a rule.
   20055              :      */
   20056          211 :     is_view = (rinfo->ev_type == '1' && rinfo->is_instead);
   20057              : 
   20058          211 :     query = createPQExpBuffer();
   20059          211 :     cmd = createPQExpBuffer();
   20060          211 :     delcmd = createPQExpBuffer();
   20061          211 :     ruleprefix = createPQExpBuffer();
   20062              : 
   20063          211 :     qtabname = pg_strdup(fmtId(tbinfo->dobj.name));
   20064              : 
   20065          211 :     if (is_view)
   20066              :     {
   20067              :         PQExpBuffer result;
   20068              : 
   20069              :         /*
   20070              :          * We need OR REPLACE here because we'll be replacing a dummy view.
   20071              :          * Otherwise this should look largely like the regular view dump code.
   20072              :          */
   20073           10 :         appendPQExpBuffer(cmd, "CREATE OR REPLACE VIEW %s",
   20074           10 :                           fmtQualifiedDumpable(tbinfo));
   20075           10 :         if (nonemptyReloptions(tbinfo->reloptions))
   20076              :         {
   20077            0 :             appendPQExpBufferStr(cmd, " WITH (");
   20078            0 :             appendReloptionsArrayAH(cmd, tbinfo->reloptions, "", fout);
   20079            0 :             appendPQExpBufferChar(cmd, ')');
   20080              :         }
   20081           10 :         result = createViewAsClause(fout, tbinfo);
   20082           10 :         appendPQExpBuffer(cmd, " AS\n%s", result->data);
   20083           10 :         destroyPQExpBuffer(result);
   20084           10 :         if (tbinfo->checkoption != NULL)
   20085            0 :             appendPQExpBuffer(cmd, "\n  WITH %s CHECK OPTION",
   20086              :                               tbinfo->checkoption);
   20087           10 :         appendPQExpBufferStr(cmd, ";\n");
   20088              :     }
   20089              :     else
   20090              :     {
   20091              :         /* In the rule case, just print pg_get_ruledef's result verbatim */
   20092          201 :         appendPQExpBuffer(query,
   20093              :                           "SELECT pg_catalog.pg_get_ruledef('%u'::pg_catalog.oid)",
   20094          201 :                           rinfo->dobj.catId.oid);
   20095              : 
   20096          201 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   20097              : 
   20098          201 :         if (PQntuples(res) != 1)
   20099            0 :             pg_fatal("query to get rule \"%s\" for table \"%s\" failed: wrong number of rows returned",
   20100              :                      rinfo->dobj.name, tbinfo->dobj.name);
   20101              : 
   20102          201 :         printfPQExpBuffer(cmd, "%s\n", PQgetvalue(res, 0, 0));
   20103              : 
   20104          201 :         PQclear(res);
   20105              :     }
   20106              : 
   20107              :     /*
   20108              :      * Add the command to alter the rules replication firing semantics if it
   20109              :      * differs from the default.
   20110              :      */
   20111          211 :     if (rinfo->ev_enabled != 'O')
   20112              :     {
   20113           15 :         appendPQExpBuffer(cmd, "ALTER TABLE %s ", fmtQualifiedDumpable(tbinfo));
   20114           15 :         switch (rinfo->ev_enabled)
   20115              :         {
   20116            0 :             case 'A':
   20117            0 :                 appendPQExpBuffer(cmd, "ENABLE ALWAYS RULE %s;\n",
   20118            0 :                                   fmtId(rinfo->dobj.name));
   20119            0 :                 break;
   20120            0 :             case 'R':
   20121            0 :                 appendPQExpBuffer(cmd, "ENABLE REPLICA RULE %s;\n",
   20122            0 :                                   fmtId(rinfo->dobj.name));
   20123            0 :                 break;
   20124           15 :             case 'D':
   20125           15 :                 appendPQExpBuffer(cmd, "DISABLE RULE %s;\n",
   20126           15 :                                   fmtId(rinfo->dobj.name));
   20127           15 :                 break;
   20128              :         }
   20129              :     }
   20130              : 
   20131          211 :     if (is_view)
   20132              :     {
   20133              :         /*
   20134              :          * We can't DROP a view's ON SELECT rule.  Instead, use CREATE OR
   20135              :          * REPLACE VIEW to replace the rule with something with minimal
   20136              :          * dependencies.
   20137              :          */
   20138              :         PQExpBuffer result;
   20139              : 
   20140           10 :         appendPQExpBuffer(delcmd, "CREATE OR REPLACE VIEW %s",
   20141           10 :                           fmtQualifiedDumpable(tbinfo));
   20142           10 :         result = createDummyViewAsClause(fout, tbinfo);
   20143           10 :         appendPQExpBuffer(delcmd, " AS\n%s;\n", result->data);
   20144           10 :         destroyPQExpBuffer(result);
   20145              :     }
   20146              :     else
   20147              :     {
   20148          201 :         appendPQExpBuffer(delcmd, "DROP RULE %s ",
   20149          201 :                           fmtId(rinfo->dobj.name));
   20150          201 :         appendPQExpBuffer(delcmd, "ON %s;\n",
   20151          201 :                           fmtQualifiedDumpable(tbinfo));
   20152              :     }
   20153              : 
   20154          211 :     appendPQExpBuffer(ruleprefix, "RULE %s ON",
   20155          211 :                       fmtId(rinfo->dobj.name));
   20156              : 
   20157          211 :     tag = psprintf("%s %s", tbinfo->dobj.name, rinfo->dobj.name);
   20158              : 
   20159          211 :     if (rinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   20160          211 :         ArchiveEntry(fout, rinfo->dobj.catId, rinfo->dobj.dumpId,
   20161          211 :                      ARCHIVE_OPTS(.tag = tag,
   20162              :                                   .namespace = tbinfo->dobj.namespace->dobj.name,
   20163              :                                   .owner = tbinfo->rolname,
   20164              :                                   .description = "RULE",
   20165              :                                   .section = SECTION_POST_DATA,
   20166              :                                   .createStmt = cmd->data,
   20167              :                                   .dropStmt = delcmd->data));
   20168              : 
   20169              :     /* Dump rule comments */
   20170          211 :     if (rinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   20171            0 :         dumpComment(fout, ruleprefix->data, qtabname,
   20172            0 :                     tbinfo->dobj.namespace->dobj.name,
   20173              :                     tbinfo->rolname,
   20174            0 :                     rinfo->dobj.catId, 0, rinfo->dobj.dumpId);
   20175              : 
   20176          211 :     free(tag);
   20177          211 :     destroyPQExpBuffer(query);
   20178          211 :     destroyPQExpBuffer(cmd);
   20179          211 :     destroyPQExpBuffer(delcmd);
   20180          211 :     destroyPQExpBuffer(ruleprefix);
   20181          211 :     free(qtabname);
   20182              : }
   20183              : 
   20184              : /*
   20185              :  * getExtensionMembership --- obtain extension membership data
   20186              :  *
   20187              :  * We need to identify objects that are extension members as soon as they're
   20188              :  * loaded, so that we can correctly determine whether they need to be dumped.
   20189              :  * Generally speaking, extension member objects will get marked as *not* to
   20190              :  * be dumped, as they will be recreated by the single CREATE EXTENSION
   20191              :  * command.  However, in binary upgrade mode we still need to dump the members
   20192              :  * individually.
   20193              :  */
   20194              : void
   20195          260 : getExtensionMembership(Archive *fout, ExtensionInfo extinfo[],
   20196              :                        int numExtensions)
   20197              : {
   20198              :     PQExpBuffer query;
   20199              :     PGresult   *res;
   20200              :     int         ntups,
   20201              :                 i;
   20202              :     int         i_classid,
   20203              :                 i_objid,
   20204              :                 i_refobjid;
   20205              :     ExtensionInfo *ext;
   20206              : 
   20207              :     /* Nothing to do if no extensions */
   20208          260 :     if (numExtensions == 0)
   20209            0 :         return;
   20210              : 
   20211          260 :     query = createPQExpBuffer();
   20212              : 
   20213              :     /* refclassid constraint is redundant but may speed the search */
   20214          260 :     appendPQExpBufferStr(query, "SELECT "
   20215              :                          "classid, objid, refobjid "
   20216              :                          "FROM pg_depend "
   20217              :                          "WHERE refclassid = 'pg_extension'::regclass "
   20218              :                          "AND deptype = 'e' "
   20219              :                          "ORDER BY 3");
   20220              : 
   20221          260 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   20222              : 
   20223          260 :     ntups = PQntuples(res);
   20224              : 
   20225          260 :     i_classid = PQfnumber(res, "classid");
   20226          260 :     i_objid = PQfnumber(res, "objid");
   20227          260 :     i_refobjid = PQfnumber(res, "refobjid");
   20228              : 
   20229              :     /*
   20230              :      * Since we ordered the SELECT by referenced ID, we can expect that
   20231              :      * multiple entries for the same extension will appear together; this
   20232              :      * saves on searches.
   20233              :      */
   20234          260 :     ext = NULL;
   20235              : 
   20236         1906 :     for (i = 0; i < ntups; i++)
   20237              :     {
   20238              :         CatalogId   objId;
   20239              :         Oid         extId;
   20240              : 
   20241         1646 :         objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
   20242         1646 :         objId.oid = atooid(PQgetvalue(res, i, i_objid));
   20243         1646 :         extId = atooid(PQgetvalue(res, i, i_refobjid));
   20244              : 
   20245         1646 :         if (ext == NULL ||
   20246         1386 :             ext->dobj.catId.oid != extId)
   20247          291 :             ext = findExtensionByOid(extId);
   20248              : 
   20249         1646 :         if (ext == NULL)
   20250              :         {
   20251              :             /* shouldn't happen */
   20252            0 :             pg_log_warning("could not find referenced extension %u", extId);
   20253            0 :             continue;
   20254              :         }
   20255              : 
   20256         1646 :         recordExtensionMembership(objId, ext);
   20257              :     }
   20258              : 
   20259          260 :     PQclear(res);
   20260              : 
   20261          260 :     destroyPQExpBuffer(query);
   20262              : }
   20263              : 
   20264              : /*
   20265              :  * processExtensionTables --- deal with extension configuration tables
   20266              :  *
   20267              :  * There are two parts to this process:
   20268              :  *
   20269              :  * 1. Identify and create dump records for extension configuration tables.
   20270              :  *
   20271              :  *    Extensions can mark tables as "configuration", which means that the user
   20272              :  *    is able and expected to modify those tables after the extension has been
   20273              :  *    loaded.  For these tables, we dump out only the data- the structure is
   20274              :  *    expected to be handled at CREATE EXTENSION time, including any indexes or
   20275              :  *    foreign keys, which brings us to-
   20276              :  *
   20277              :  * 2. Record FK dependencies between configuration tables.
   20278              :  *
   20279              :  *    Due to the FKs being created at CREATE EXTENSION time and therefore before
   20280              :  *    the data is loaded, we have to work out what the best order for reloading
   20281              :  *    the data is, to avoid FK violations when the tables are restored.  This is
   20282              :  *    not perfect- we can't handle circular dependencies and if any exist they
   20283              :  *    will cause an invalid dump to be produced (though at least all of the data
   20284              :  *    is included for a user to manually restore).  This is currently documented
   20285              :  *    but perhaps we can provide a better solution in the future.
   20286              :  */
   20287              : void
   20288          259 : processExtensionTables(Archive *fout, ExtensionInfo extinfo[],
   20289              :                        int numExtensions)
   20290              : {
   20291          259 :     DumpOptions *dopt = fout->dopt;
   20292              :     PQExpBuffer query;
   20293              :     PGresult   *res;
   20294              :     int         ntups,
   20295              :                 i;
   20296              :     int         i_conrelid,
   20297              :                 i_confrelid;
   20298              : 
   20299              :     /* Nothing to do if no extensions */
   20300          259 :     if (numExtensions == 0)
   20301            0 :         return;
   20302              : 
   20303              :     /*
   20304              :      * Identify extension configuration tables and create TableDataInfo
   20305              :      * objects for them, ensuring their data will be dumped even though the
   20306              :      * tables themselves won't be.
   20307              :      *
   20308              :      * Note that we create TableDataInfo objects even in schema-only mode, ie,
   20309              :      * user data in a configuration table is treated like schema data. This
   20310              :      * seems appropriate since system data in a config table would get
   20311              :      * reloaded by CREATE EXTENSION.  If the extension is not listed in the
   20312              :      * list of extensions to be included, none of its data is dumped.
   20313              :      */
   20314          549 :     for (i = 0; i < numExtensions; i++)
   20315              :     {
   20316          290 :         ExtensionInfo *curext = &(extinfo[i]);
   20317          290 :         char       *extconfig = curext->extconfig;
   20318          290 :         char       *extcondition = curext->extcondition;
   20319          290 :         char      **extconfigarray = NULL;
   20320          290 :         char      **extconditionarray = NULL;
   20321          290 :         int         nconfigitems = 0;
   20322          290 :         int         nconditionitems = 0;
   20323              : 
   20324              :         /*
   20325              :          * Check if this extension is listed as to include in the dump.  If
   20326              :          * not, any table data associated with it is discarded.
   20327              :          */
   20328          290 :         if (extension_include_oids.head != NULL &&
   20329            8 :             !simple_oid_list_member(&extension_include_oids,
   20330              :                                     curext->dobj.catId.oid))
   20331            6 :             continue;
   20332              : 
   20333              :         /*
   20334              :          * Check if this extension is listed as to exclude in the dump.  If
   20335              :          * yes, any table data associated with it is discarded.
   20336              :          */
   20337          290 :         if (extension_exclude_oids.head != NULL &&
   20338            4 :             simple_oid_list_member(&extension_exclude_oids,
   20339              :                                    curext->dobj.catId.oid))
   20340            2 :             continue;
   20341              : 
   20342          284 :         if (strlen(extconfig) != 0 || strlen(extcondition) != 0)
   20343              :         {
   20344              :             int         j;
   20345              : 
   20346           20 :             if (!parsePGArray(extconfig, &extconfigarray, &nconfigitems))
   20347            0 :                 pg_fatal("could not parse %s array", "extconfig");
   20348           20 :             if (!parsePGArray(extcondition, &extconditionarray, &nconditionitems))
   20349            0 :                 pg_fatal("could not parse %s array", "extcondition");
   20350           20 :             if (nconfigitems != nconditionitems)
   20351            0 :                 pg_fatal("mismatched number of configurations and conditions for extension");
   20352              : 
   20353           60 :             for (j = 0; j < nconfigitems; j++)
   20354              :             {
   20355              :                 TableInfo  *configtbl;
   20356           40 :                 Oid         configtbloid = atooid(extconfigarray[j]);
   20357           40 :                 bool        dumpobj =
   20358           40 :                     curext->dobj.dump & DUMP_COMPONENT_DEFINITION;
   20359              : 
   20360           40 :                 configtbl = findTableByOid(configtbloid);
   20361           40 :                 if (configtbl == NULL)
   20362            0 :                     continue;
   20363              : 
   20364              :                 /*
   20365              :                  * Tables of not-to-be-dumped extensions shouldn't be dumped
   20366              :                  * unless the table or its schema is explicitly included
   20367              :                  */
   20368           40 :                 if (!(curext->dobj.dump & DUMP_COMPONENT_DEFINITION))
   20369              :                 {
   20370              :                     /* check table explicitly requested */
   20371            2 :                     if (table_include_oids.head != NULL &&
   20372            0 :                         simple_oid_list_member(&table_include_oids,
   20373              :                                                configtbloid))
   20374            0 :                         dumpobj = true;
   20375              : 
   20376              :                     /* check table's schema explicitly requested */
   20377            2 :                     if (configtbl->dobj.namespace->dobj.dump &
   20378              :                         DUMP_COMPONENT_DATA)
   20379            2 :                         dumpobj = true;
   20380              :                 }
   20381              : 
   20382              :                 /* check table excluded by an exclusion switch */
   20383           44 :                 if (table_exclude_oids.head != NULL &&
   20384            4 :                     simple_oid_list_member(&table_exclude_oids,
   20385              :                                            configtbloid))
   20386            1 :                     dumpobj = false;
   20387              : 
   20388              :                 /* check schema excluded by an exclusion switch */
   20389           40 :                 if (simple_oid_list_member(&schema_exclude_oids,
   20390           40 :                                            configtbl->dobj.namespace->dobj.catId.oid))
   20391            0 :                     dumpobj = false;
   20392              : 
   20393           40 :                 if (dumpobj)
   20394              :                 {
   20395           39 :                     makeTableDataInfo(dopt, configtbl);
   20396           39 :                     if (configtbl->dataObj != NULL)
   20397              :                     {
   20398           39 :                         if (strlen(extconditionarray[j]) > 0)
   20399            0 :                             configtbl->dataObj->filtercond = pg_strdup(extconditionarray[j]);
   20400              :                     }
   20401              :                 }
   20402              :             }
   20403              :         }
   20404          284 :         if (extconfigarray)
   20405           20 :             free(extconfigarray);
   20406          284 :         if (extconditionarray)
   20407           20 :             free(extconditionarray);
   20408              :     }
   20409              : 
   20410              :     /*
   20411              :      * Now that all the TableDataInfo objects have been created for all the
   20412              :      * extensions, check their FK dependencies and register them to try and
   20413              :      * dump the data out in an order that they can be restored in.
   20414              :      *
   20415              :      * Note that this is not a problem for user tables as their FKs are
   20416              :      * recreated after the data has been loaded.
   20417              :      */
   20418              : 
   20419          259 :     query = createPQExpBuffer();
   20420              : 
   20421          259 :     printfPQExpBuffer(query,
   20422              :                       "SELECT conrelid, confrelid "
   20423              :                       "FROM pg_constraint "
   20424              :                       "JOIN pg_depend ON (objid = confrelid) "
   20425              :                       "WHERE contype = 'f' "
   20426              :                       "AND refclassid = 'pg_extension'::regclass "
   20427              :                       "AND classid = 'pg_class'::regclass;");
   20428              : 
   20429          259 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   20430          259 :     ntups = PQntuples(res);
   20431              : 
   20432          259 :     i_conrelid = PQfnumber(res, "conrelid");
   20433          259 :     i_confrelid = PQfnumber(res, "confrelid");
   20434              : 
   20435              :     /* Now get the dependencies and register them */
   20436          259 :     for (i = 0; i < ntups; i++)
   20437              :     {
   20438              :         Oid         conrelid,
   20439              :                     confrelid;
   20440              :         TableInfo  *reftable,
   20441              :                    *contable;
   20442              : 
   20443            0 :         conrelid = atooid(PQgetvalue(res, i, i_conrelid));
   20444            0 :         confrelid = atooid(PQgetvalue(res, i, i_confrelid));
   20445            0 :         contable = findTableByOid(conrelid);
   20446            0 :         reftable = findTableByOid(confrelid);
   20447              : 
   20448            0 :         if (reftable == NULL ||
   20449            0 :             reftable->dataObj == NULL ||
   20450            0 :             contable == NULL ||
   20451            0 :             contable->dataObj == NULL)
   20452            0 :             continue;
   20453              : 
   20454              :         /*
   20455              :          * Make referencing TABLE_DATA object depend on the referenced table's
   20456              :          * TABLE_DATA object.
   20457              :          */
   20458            0 :         addObjectDependency(&contable->dataObj->dobj,
   20459            0 :                             reftable->dataObj->dobj.dumpId);
   20460              :     }
   20461          259 :     PQclear(res);
   20462          259 :     destroyPQExpBuffer(query);
   20463              : }
   20464              : 
   20465              : /*
   20466              :  * getDependencies --- obtain available dependency data
   20467              :  */
   20468              : static void
   20469          259 : getDependencies(Archive *fout)
   20470              : {
   20471              :     PQExpBuffer query;
   20472              :     PGresult   *res;
   20473              :     int         ntups,
   20474              :                 i;
   20475              :     int         i_classid,
   20476              :                 i_objid,
   20477              :                 i_refclassid,
   20478              :                 i_refobjid,
   20479              :                 i_deptype;
   20480              :     DumpableObject *dobj,
   20481              :                *refdobj;
   20482              : 
   20483          259 :     pg_log_info("reading dependency data");
   20484              : 
   20485          259 :     query = createPQExpBuffer();
   20486              : 
   20487              :     /*
   20488              :      * Messy query to collect the dependency data we need.  Note that we
   20489              :      * ignore the sub-object column, so that dependencies of or on a column
   20490              :      * look the same as dependencies of or on a whole table.
   20491              :      *
   20492              :      * PIN dependencies aren't interesting, and EXTENSION dependencies were
   20493              :      * already processed by getExtensionMembership.
   20494              :      */
   20495          259 :     appendPQExpBufferStr(query, "SELECT "
   20496              :                          "classid, objid, refclassid, refobjid, deptype "
   20497              :                          "FROM pg_depend "
   20498              :                          "WHERE deptype != 'p' AND deptype != 'e'\n");
   20499              : 
   20500              :     /*
   20501              :      * Since we don't treat pg_amop entries as separate DumpableObjects, we
   20502              :      * have to translate their dependencies into dependencies of their parent
   20503              :      * opfamily.  Ignore internal dependencies though, as those will point to
   20504              :      * their parent opclass, which we needn't consider here (and if we did,
   20505              :      * it'd just result in circular dependencies).  Also, "loose" opfamily
   20506              :      * entries will have dependencies on their parent opfamily, which we
   20507              :      * should drop since they'd likewise become useless self-dependencies.
   20508              :      * (But be sure to keep deps on *other* opfamilies; see amopsortfamily.)
   20509              :      */
   20510          259 :     appendPQExpBufferStr(query, "UNION ALL\n"
   20511              :                          "SELECT 'pg_opfamily'::regclass AS classid, amopfamily AS objid, refclassid, refobjid, deptype "
   20512              :                          "FROM pg_depend d, pg_amop o "
   20513              :                          "WHERE deptype NOT IN ('p', 'e', 'i') AND "
   20514              :                          "classid = 'pg_amop'::regclass AND objid = o.oid "
   20515              :                          "AND NOT (refclassid = 'pg_opfamily'::regclass AND amopfamily = refobjid)\n");
   20516              : 
   20517              :     /* Likewise for pg_amproc entries */
   20518          259 :     appendPQExpBufferStr(query, "UNION ALL\n"
   20519              :                          "SELECT 'pg_opfamily'::regclass AS classid, amprocfamily AS objid, refclassid, refobjid, deptype "
   20520              :                          "FROM pg_depend d, pg_amproc p "
   20521              :                          "WHERE deptype NOT IN ('p', 'e', 'i') AND "
   20522              :                          "classid = 'pg_amproc'::regclass AND objid = p.oid "
   20523              :                          "AND NOT (refclassid = 'pg_opfamily'::regclass AND amprocfamily = refobjid)\n");
   20524              : 
   20525              :     /*
   20526              :      * Translate dependencies of pg_propgraph_element entries into
   20527              :      * dependencies of their parent pg_class entry.
   20528              :      */
   20529          259 :     if (fout->remoteVersion >= 190000)
   20530          259 :         appendPQExpBufferStr(query, "UNION ALL\n"
   20531              :                              "SELECT 'pg_class'::regclass AS classid, pgepgid AS objid, refclassid, refobjid, deptype "
   20532              :                              "FROM pg_depend d, pg_propgraph_element pge "
   20533              :                              "WHERE deptype NOT IN ('p', 'e', 'i') AND "
   20534              :                              "classid = 'pg_propgraph_element'::regclass AND objid = pge.oid\n");
   20535              : 
   20536              :     /* Sort the output for efficiency below */
   20537          259 :     appendPQExpBufferStr(query, "ORDER BY 1,2");
   20538              : 
   20539          259 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   20540              : 
   20541          259 :     ntups = PQntuples(res);
   20542              : 
   20543          259 :     i_classid = PQfnumber(res, "classid");
   20544          259 :     i_objid = PQfnumber(res, "objid");
   20545          259 :     i_refclassid = PQfnumber(res, "refclassid");
   20546          259 :     i_refobjid = PQfnumber(res, "refobjid");
   20547          259 :     i_deptype = PQfnumber(res, "deptype");
   20548              : 
   20549              :     /*
   20550              :      * Since we ordered the SELECT by referencing ID, we can expect that
   20551              :      * multiple entries for the same object will appear together; this saves
   20552              :      * on searches.
   20553              :      */
   20554          259 :     dobj = NULL;
   20555              : 
   20556       590233 :     for (i = 0; i < ntups; i++)
   20557              :     {
   20558              :         CatalogId   objId;
   20559              :         CatalogId   refobjId;
   20560              :         char        deptype;
   20561              : 
   20562       589974 :         objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
   20563       589974 :         objId.oid = atooid(PQgetvalue(res, i, i_objid));
   20564       589974 :         refobjId.tableoid = atooid(PQgetvalue(res, i, i_refclassid));
   20565       589974 :         refobjId.oid = atooid(PQgetvalue(res, i, i_refobjid));
   20566       589974 :         deptype = *(PQgetvalue(res, i, i_deptype));
   20567              : 
   20568       589974 :         if (dobj == NULL ||
   20569       554262 :             dobj->catId.tableoid != objId.tableoid ||
   20570       551689 :             dobj->catId.oid != objId.oid)
   20571       248942 :             dobj = findObjectByCatalogId(objId);
   20572              : 
   20573              :         /*
   20574              :          * Failure to find objects mentioned in pg_depend is not unexpected,
   20575              :          * since for example we don't collect info about TOAST tables.
   20576              :          */
   20577       589974 :         if (dobj == NULL)
   20578              :         {
   20579              : #ifdef NOT_USED
   20580              :             pg_log_warning("no referencing object %u %u",
   20581              :                            objId.tableoid, objId.oid);
   20582              : #endif
   20583        37017 :             continue;
   20584              :         }
   20585              : 
   20586       554514 :         refdobj = findObjectByCatalogId(refobjId);
   20587              : 
   20588       554514 :         if (refdobj == NULL)
   20589              :         {
   20590              : #ifdef NOT_USED
   20591              :             pg_log_warning("no referenced object %u %u",
   20592              :                            refobjId.tableoid, refobjId.oid);
   20593              : #endif
   20594         1557 :             continue;
   20595              :         }
   20596              : 
   20597              :         /*
   20598              :          * For 'x' dependencies, mark the object for later; we still add the
   20599              :          * normal dependency, for possible ordering purposes.  Currently
   20600              :          * pg_dump_sort.c knows to put extensions ahead of all object types
   20601              :          * that could possibly depend on them, but this is safer.
   20602              :          */
   20603       552957 :         if (deptype == 'x')
   20604           44 :             dobj->depends_on_ext = true;
   20605              : 
   20606              :         /*
   20607              :          * Ordinarily, table rowtypes have implicit dependencies on their
   20608              :          * tables.  However, for a composite type the implicit dependency goes
   20609              :          * the other way in pg_depend; which is the right thing for DROP but
   20610              :          * it doesn't produce the dependency ordering we need. So in that one
   20611              :          * case, we reverse the direction of the dependency.
   20612              :          */
   20613       552957 :         if (deptype == 'i' &&
   20614       152563 :             dobj->objType == DO_TABLE &&
   20615         1286 :             refdobj->objType == DO_TYPE)
   20616          182 :             addObjectDependency(refdobj, dobj->dumpId);
   20617              :         else
   20618              :             /* normal case */
   20619       552775 :             addObjectDependency(dobj, refdobj->dumpId);
   20620              :     }
   20621              : 
   20622          259 :     PQclear(res);
   20623              : 
   20624          259 :     destroyPQExpBuffer(query);
   20625          259 : }
   20626              : 
   20627              : 
   20628              : /*
   20629              :  * createBoundaryObjects - create dummy DumpableObjects to represent
   20630              :  * dump section boundaries.
   20631              :  */
   20632              : static DumpableObject *
   20633          259 : createBoundaryObjects(void)
   20634              : {
   20635              :     DumpableObject *dobjs;
   20636              : 
   20637          259 :     dobjs = pg_malloc_array(DumpableObject, 2);
   20638              : 
   20639          259 :     dobjs[0].objType = DO_PRE_DATA_BOUNDARY;
   20640          259 :     dobjs[0].catId = nilCatalogId;
   20641          259 :     AssignDumpId(dobjs + 0);
   20642          259 :     dobjs[0].name = pg_strdup("PRE-DATA BOUNDARY");
   20643              : 
   20644          259 :     dobjs[1].objType = DO_POST_DATA_BOUNDARY;
   20645          259 :     dobjs[1].catId = nilCatalogId;
   20646          259 :     AssignDumpId(dobjs + 1);
   20647          259 :     dobjs[1].name = pg_strdup("POST-DATA BOUNDARY");
   20648              : 
   20649          259 :     return dobjs;
   20650              : }
   20651              : 
   20652              : /*
   20653              :  * addBoundaryDependencies - add dependencies as needed to enforce the dump
   20654              :  * section boundaries.
   20655              :  */
   20656              : static void
   20657          259 : addBoundaryDependencies(DumpableObject **dobjs, int numObjs,
   20658              :                         DumpableObject *boundaryObjs)
   20659              : {
   20660          259 :     DumpableObject *preDataBound = boundaryObjs + 0;
   20661          259 :     DumpableObject *postDataBound = boundaryObjs + 1;
   20662              :     int         i;
   20663              : 
   20664       976294 :     for (i = 0; i < numObjs; i++)
   20665              :     {
   20666       976035 :         DumpableObject *dobj = dobjs[i];
   20667              : 
   20668              :         /*
   20669              :          * The classification of object types here must match the SECTION_xxx
   20670              :          * values assigned during subsequent ArchiveEntry calls!
   20671              :          */
   20672       976035 :         switch (dobj->objType)
   20673              :         {
   20674       914269 :             case DO_NAMESPACE:
   20675              :             case DO_EXTENSION:
   20676              :             case DO_TYPE:
   20677              :             case DO_SHELL_TYPE:
   20678              :             case DO_FUNC:
   20679              :             case DO_AGG:
   20680              :             case DO_OPERATOR:
   20681              :             case DO_ACCESS_METHOD:
   20682              :             case DO_OPCLASS:
   20683              :             case DO_OPFAMILY:
   20684              :             case DO_COLLATION:
   20685              :             case DO_CONVERSION:
   20686              :             case DO_TABLE:
   20687              :             case DO_TABLE_ATTACH:
   20688              :             case DO_ATTRDEF:
   20689              :             case DO_PROCLANG:
   20690              :             case DO_CAST:
   20691              :             case DO_DUMMY_TYPE:
   20692              :             case DO_TSPARSER:
   20693              :             case DO_TSDICT:
   20694              :             case DO_TSTEMPLATE:
   20695              :             case DO_TSCONFIG:
   20696              :             case DO_FDW:
   20697              :             case DO_FOREIGN_SERVER:
   20698              :             case DO_TRANSFORM:
   20699              :                 /* Pre-data objects: must come before the pre-data boundary */
   20700       914269 :                 addObjectDependency(preDataBound, dobj->dumpId);
   20701       914269 :                 break;
   20702         5226 :             case DO_TABLE_DATA:
   20703              :             case DO_SEQUENCE_SET:
   20704              :             case DO_LARGE_OBJECT:
   20705              :             case DO_LARGE_OBJECT_DATA:
   20706              :                 /* Data objects: must come between the boundaries */
   20707         5226 :                 addObjectDependency(dobj, preDataBound->dumpId);
   20708         5226 :                 addObjectDependency(postDataBound, dobj->dumpId);
   20709         5226 :                 break;
   20710         6121 :             case DO_INDEX:
   20711              :             case DO_INDEX_ATTACH:
   20712              :             case DO_STATSEXT:
   20713              :             case DO_REFRESH_MATVIEW:
   20714              :             case DO_TRIGGER:
   20715              :             case DO_EVENT_TRIGGER:
   20716              :             case DO_DEFAULT_ACL:
   20717              :             case DO_POLICY:
   20718              :             case DO_PUBLICATION:
   20719              :             case DO_PUBLICATION_REL:
   20720              :             case DO_PUBLICATION_TABLE_IN_SCHEMA:
   20721              :             case DO_SUBSCRIPTION:
   20722              :             case DO_SUBSCRIPTION_REL:
   20723              :                 /* Post-data objects: must come after the post-data boundary */
   20724         6121 :                 addObjectDependency(dobj, postDataBound->dumpId);
   20725         6121 :                 break;
   20726        43647 :             case DO_RULE:
   20727              :                 /* Rules are post-data, but only if dumped separately */
   20728        43647 :                 if (((RuleInfo *) dobj)->separate)
   20729          791 :                     addObjectDependency(dobj, postDataBound->dumpId);
   20730        43647 :                 break;
   20731         2778 :             case DO_CONSTRAINT:
   20732              :             case DO_FK_CONSTRAINT:
   20733              :                 /* Constraints are post-data, but only if dumped separately */
   20734         2778 :                 if (((ConstraintInfo *) dobj)->separate)
   20735         2050 :                     addObjectDependency(dobj, postDataBound->dumpId);
   20736         2778 :                 break;
   20737          259 :             case DO_PRE_DATA_BOUNDARY:
   20738              :                 /* nothing to do */
   20739          259 :                 break;
   20740          259 :             case DO_POST_DATA_BOUNDARY:
   20741              :                 /* must come after the pre-data boundary */
   20742          259 :                 addObjectDependency(dobj, preDataBound->dumpId);
   20743          259 :                 break;
   20744         3476 :             case DO_REL_STATS:
   20745              :                 /* stats section varies by parent object type, DATA or POST */
   20746         3476 :                 if (((RelStatsInfo *) dobj)->section == SECTION_DATA)
   20747              :                 {
   20748         2269 :                     addObjectDependency(dobj, preDataBound->dumpId);
   20749         2269 :                     addObjectDependency(postDataBound, dobj->dumpId);
   20750              :                 }
   20751              :                 else
   20752         1207 :                     addObjectDependency(dobj, postDataBound->dumpId);
   20753         3476 :                 break;
   20754              :         }
   20755              :     }
   20756          259 : }
   20757              : 
   20758              : 
   20759              : /*
   20760              :  * BuildArchiveDependencies - create dependency data for archive TOC entries
   20761              :  *
   20762              :  * The raw dependency data obtained by getDependencies() is not terribly
   20763              :  * useful in an archive dump, because in many cases there are dependency
   20764              :  * chains linking through objects that don't appear explicitly in the dump.
   20765              :  * For example, a view will depend on its _RETURN rule while the _RETURN rule
   20766              :  * will depend on other objects --- but the rule will not appear as a separate
   20767              :  * object in the dump.  We need to adjust the view's dependencies to include
   20768              :  * whatever the rule depends on that is included in the dump.
   20769              :  *
   20770              :  * Just to make things more complicated, there are also "special" dependencies
   20771              :  * such as the dependency of a TABLE DATA item on its TABLE, which we must
   20772              :  * not rearrange because pg_restore knows that TABLE DATA only depends on
   20773              :  * its table.  In these cases we must leave the dependencies strictly as-is
   20774              :  * even if they refer to not-to-be-dumped objects.
   20775              :  *
   20776              :  * To handle this, the convention is that "special" dependencies are created
   20777              :  * during ArchiveEntry calls, and an archive TOC item that has any such
   20778              :  * entries will not be touched here.  Otherwise, we recursively search the
   20779              :  * DumpableObject data structures to build the correct dependencies for each
   20780              :  * archive TOC item.
   20781              :  */
   20782              : static void
   20783          131 : BuildArchiveDependencies(Archive *fout)
   20784              : {
   20785          131 :     ArchiveHandle *AH = (ArchiveHandle *) fout;
   20786              :     TocEntry   *te;
   20787              : 
   20788              :     /* Scan all TOC entries in the archive */
   20789         7753 :     for (te = AH->toc->next; te != AH->toc; te = te->next)
   20790              :     {
   20791              :         DumpableObject *dobj;
   20792              :         DumpId     *dependencies;
   20793              :         int         nDeps;
   20794              :         int         allocDeps;
   20795              : 
   20796              :         /* No need to process entries that will not be dumped */
   20797         7622 :         if (te->reqs == 0)
   20798         3894 :             continue;
   20799              :         /* Ignore entries that already have "special" dependencies */
   20800         7615 :         if (te->nDeps > 0)
   20801         3125 :             continue;
   20802              :         /* Otherwise, look up the item's original DumpableObject, if any */
   20803         4490 :         dobj = findObjectByDumpId(te->dumpId);
   20804         4490 :         if (dobj == NULL)
   20805          657 :             continue;
   20806              :         /* No work if it has no dependencies */
   20807         3833 :         if (dobj->nDeps <= 0)
   20808          105 :             continue;
   20809              :         /* Set up work array */
   20810         3728 :         allocDeps = 64;
   20811         3728 :         dependencies = pg_malloc_array(DumpId, allocDeps);
   20812         3728 :         nDeps = 0;
   20813              :         /* Recursively find all dumpable dependencies */
   20814         3728 :         findDumpableDependencies(AH, dobj,
   20815              :                                  &dependencies, &nDeps, &allocDeps);
   20816              :         /* And save 'em ... */
   20817         3728 :         if (nDeps > 0)
   20818              :         {
   20819         2667 :             dependencies = pg_realloc_array(dependencies, DumpId, nDeps);
   20820         2667 :             te->dependencies = dependencies;
   20821         2667 :             te->nDeps = nDeps;
   20822              :         }
   20823              :         else
   20824         1061 :             free(dependencies);
   20825              :     }
   20826          131 : }
   20827              : 
   20828              : /* Recursive search subroutine for BuildArchiveDependencies */
   20829              : static void
   20830         9031 : findDumpableDependencies(ArchiveHandle *AH, const DumpableObject *dobj,
   20831              :                          DumpId **dependencies, int *nDeps, int *allocDeps)
   20832              : {
   20833              :     int         i;
   20834              : 
   20835              :     /*
   20836              :      * Ignore section boundary objects: if we search through them, we'll
   20837              :      * report lots of bogus dependencies.
   20838              :      */
   20839         9031 :     if (dobj->objType == DO_PRE_DATA_BOUNDARY ||
   20840         9014 :         dobj->objType == DO_POST_DATA_BOUNDARY)
   20841         1497 :         return;
   20842              : 
   20843        18568 :     for (i = 0; i < dobj->nDeps; i++)
   20844              :     {
   20845        11034 :         DumpId      depid = dobj->dependencies[i];
   20846              : 
   20847        11034 :         if (TocIDRequired(AH, depid) != 0)
   20848              :         {
   20849              :             /* Object will be dumped, so just reference it as a dependency */
   20850         5731 :             if (*nDeps >= *allocDeps)
   20851              :             {
   20852            0 :                 *allocDeps *= 2;
   20853            0 :                 *dependencies = pg_realloc_array(*dependencies, DumpId, *allocDeps);
   20854              :             }
   20855         5731 :             (*dependencies)[*nDeps] = depid;
   20856         5731 :             (*nDeps)++;
   20857              :         }
   20858              :         else
   20859              :         {
   20860              :             /*
   20861              :              * Object will not be dumped, so recursively consider its deps. We
   20862              :              * rely on the assumption that sortDumpableObjects already broke
   20863              :              * any dependency loops, else we might recurse infinitely.
   20864              :              */
   20865         5303 :             DumpableObject *otherdobj = findObjectByDumpId(depid);
   20866              : 
   20867         5303 :             if (otherdobj)
   20868         5303 :                 findDumpableDependencies(AH, otherdobj,
   20869              :                                          dependencies, nDeps, allocDeps);
   20870              :         }
   20871              :     }
   20872              : }
   20873              : 
   20874              : 
   20875              : /*
   20876              :  * getFormattedTypeName - retrieve a nicely-formatted type name for the
   20877              :  * given type OID.
   20878              :  *
   20879              :  * This does not guarantee to schema-qualify the output, so it should not
   20880              :  * be used to create the target object name for CREATE or ALTER commands.
   20881              :  *
   20882              :  * Note that the result is cached and must not be freed by the caller.
   20883              :  */
   20884              : static const char *
   20885         2375 : getFormattedTypeName(Archive *fout, Oid oid, OidOptions opts)
   20886              : {
   20887              :     TypeInfo   *typeInfo;
   20888              :     char       *result;
   20889              :     PQExpBuffer query;
   20890              :     PGresult   *res;
   20891              : 
   20892         2375 :     if (oid == 0)
   20893              :     {
   20894            0 :         if ((opts & zeroAsStar) != 0)
   20895            0 :             return "*";
   20896            0 :         else if ((opts & zeroAsNone) != 0)
   20897            0 :             return "NONE";
   20898              :     }
   20899              : 
   20900              :     /* see if we have the result cached in the type's TypeInfo record */
   20901         2375 :     typeInfo = findTypeByOid(oid);
   20902         2375 :     if (typeInfo && typeInfo->ftypname)
   20903         1898 :         return typeInfo->ftypname;
   20904              : 
   20905          477 :     query = createPQExpBuffer();
   20906          477 :     appendPQExpBuffer(query, "SELECT pg_catalog.format_type('%u'::pg_catalog.oid, NULL)",
   20907              :                       oid);
   20908              : 
   20909          477 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   20910              : 
   20911              :     /* result of format_type is already quoted */
   20912          477 :     result = pg_strdup(PQgetvalue(res, 0, 0));
   20913              : 
   20914          477 :     PQclear(res);
   20915          477 :     destroyPQExpBuffer(query);
   20916              : 
   20917              :     /*
   20918              :      * Cache the result for re-use in later requests, if possible.  If we
   20919              :      * don't have a TypeInfo for the type, the string will be leaked once the
   20920              :      * caller is done with it ... but that case really should not happen, so
   20921              :      * leaking if it does seems acceptable.
   20922              :      */
   20923          477 :     if (typeInfo)
   20924          477 :         typeInfo->ftypname = result;
   20925              : 
   20926          477 :     return result;
   20927              : }
   20928              : 
   20929              : /*
   20930              :  * Return a column list clause for the given relation.
   20931              :  *
   20932              :  * Special case: if there are no undropped columns in the relation, return
   20933              :  * "", not an invalid "()" column list.
   20934              :  */
   20935              : static const char *
   20936         9052 : fmtCopyColumnList(const TableInfo *ti, PQExpBuffer buffer)
   20937              : {
   20938         9052 :     int         numatts = ti->numatts;
   20939         9052 :     char      **attnames = ti->attnames;
   20940         9052 :     bool       *attisdropped = ti->attisdropped;
   20941         9052 :     char       *attgenerated = ti->attgenerated;
   20942              :     bool        needComma;
   20943              :     int         i;
   20944              : 
   20945         9052 :     appendPQExpBufferChar(buffer, '(');
   20946         9052 :     needComma = false;
   20947        43072 :     for (i = 0; i < numatts; i++)
   20948              :     {
   20949        34020 :         if (attisdropped[i])
   20950          606 :             continue;
   20951        33414 :         if (attgenerated[i])
   20952         1152 :             continue;
   20953        32262 :         if (needComma)
   20954        23434 :             appendPQExpBufferStr(buffer, ", ");
   20955        32262 :         appendPQExpBufferStr(buffer, fmtId(attnames[i]));
   20956        32262 :         needComma = true;
   20957              :     }
   20958              : 
   20959         9052 :     if (!needComma)
   20960          224 :         return "";                /* no undropped columns */
   20961              : 
   20962         8828 :     appendPQExpBufferChar(buffer, ')');
   20963         8828 :     return buffer->data;
   20964              : }
   20965              : 
   20966              : /*
   20967              :  * Check if a reloptions array is nonempty.
   20968              :  */
   20969              : static bool
   20970        14756 : nonemptyReloptions(const char *reloptions)
   20971              : {
   20972              :     /* Don't want to print it if it's just "{}" */
   20973        14756 :     return (reloptions != NULL && strlen(reloptions) > 2);
   20974              : }
   20975              : 
   20976              : /*
   20977              :  * Format a reloptions array and append it to the given buffer.
   20978              :  *
   20979              :  * "prefix" is prepended to the option names; typically it's "" or "toast.".
   20980              :  */
   20981              : static void
   20982          219 : appendReloptionsArrayAH(PQExpBuffer buffer, const char *reloptions,
   20983              :                         const char *prefix, Archive *fout)
   20984              : {
   20985              :     bool        res;
   20986              : 
   20987          219 :     res = appendReloptionsArray(buffer, reloptions, prefix, fout->encoding,
   20988          219 :                                 fout->std_strings);
   20989          219 :     if (!res)
   20990            0 :         pg_log_warning("could not parse %s array", "reloptions");
   20991          219 : }
   20992              : 
   20993              : /*
   20994              :  * read_dump_filters - retrieve object identifier patterns from file
   20995              :  *
   20996              :  * Parse the specified filter file for include and exclude patterns, and add
   20997              :  * them to the relevant lists.  If the filename is "-" then filters will be
   20998              :  * read from STDIN rather than a file.
   20999              :  */
   21000              : static void
   21001           26 : read_dump_filters(const char *filename, DumpOptions *dopt)
   21002              : {
   21003              :     FilterStateData fstate;
   21004              :     char       *objname;
   21005              :     FilterCommandType comtype;
   21006              :     FilterObjectType objtype;
   21007              : 
   21008           26 :     filter_init(&fstate, filename, exit_nicely);
   21009              : 
   21010           84 :     while (filter_read_item(&fstate, &objname, &comtype, &objtype))
   21011              :     {
   21012           33 :         if (comtype == FILTER_COMMAND_TYPE_INCLUDE)
   21013              :         {
   21014           17 :             switch (objtype)
   21015              :             {
   21016            0 :                 case FILTER_OBJECT_TYPE_NONE:
   21017            0 :                     break;
   21018            0 :                 case FILTER_OBJECT_TYPE_DATABASE:
   21019              :                 case FILTER_OBJECT_TYPE_FUNCTION:
   21020              :                 case FILTER_OBJECT_TYPE_INDEX:
   21021              :                 case FILTER_OBJECT_TYPE_TABLE_DATA:
   21022              :                 case FILTER_OBJECT_TYPE_TABLE_DATA_AND_CHILDREN:
   21023              :                 case FILTER_OBJECT_TYPE_TRIGGER:
   21024            0 :                     pg_log_filter_error(&fstate, _("%s filter for \"%s\" is not allowed"),
   21025              :                                         "include",
   21026              :                                         filter_object_type_name(objtype));
   21027            0 :                     exit_nicely(1);
   21028              :                     break;      /* unreachable */
   21029              : 
   21030            1 :                 case FILTER_OBJECT_TYPE_EXTENSION:
   21031            1 :                     simple_string_list_append(&extension_include_patterns, objname);
   21032            1 :                     break;
   21033            1 :                 case FILTER_OBJECT_TYPE_FOREIGN_DATA:
   21034            1 :                     simple_string_list_append(&foreign_servers_include_patterns, objname);
   21035            1 :                     break;
   21036            1 :                 case FILTER_OBJECT_TYPE_SCHEMA:
   21037            1 :                     simple_string_list_append(&schema_include_patterns, objname);
   21038            1 :                     dopt->include_everything = false;
   21039            1 :                     break;
   21040           13 :                 case FILTER_OBJECT_TYPE_TABLE:
   21041           13 :                     simple_string_list_append(&table_include_patterns, objname);
   21042           13 :                     dopt->include_everything = false;
   21043           13 :                     break;
   21044            1 :                 case FILTER_OBJECT_TYPE_TABLE_AND_CHILDREN:
   21045            1 :                     simple_string_list_append(&table_include_patterns_and_children,
   21046              :                                               objname);
   21047            1 :                     dopt->include_everything = false;
   21048            1 :                     break;
   21049              :             }
   21050              :         }
   21051           16 :         else if (comtype == FILTER_COMMAND_TYPE_EXCLUDE)
   21052              :         {
   21053            9 :             switch (objtype)
   21054              :             {
   21055            0 :                 case FILTER_OBJECT_TYPE_NONE:
   21056            0 :                     break;
   21057            1 :                 case FILTER_OBJECT_TYPE_DATABASE:
   21058              :                 case FILTER_OBJECT_TYPE_FUNCTION:
   21059              :                 case FILTER_OBJECT_TYPE_INDEX:
   21060              :                 case FILTER_OBJECT_TYPE_TRIGGER:
   21061              :                 case FILTER_OBJECT_TYPE_FOREIGN_DATA:
   21062            1 :                     pg_log_filter_error(&fstate, _("%s filter for \"%s\" is not allowed"),
   21063              :                                         "exclude",
   21064              :                                         filter_object_type_name(objtype));
   21065            1 :                     exit_nicely(1);
   21066              :                     break;
   21067              : 
   21068            1 :                 case FILTER_OBJECT_TYPE_EXTENSION:
   21069            1 :                     simple_string_list_append(&extension_exclude_patterns, objname);
   21070            1 :                     break;
   21071            1 :                 case FILTER_OBJECT_TYPE_TABLE_DATA:
   21072            1 :                     simple_string_list_append(&tabledata_exclude_patterns,
   21073              :                                               objname);
   21074            1 :                     break;
   21075            1 :                 case FILTER_OBJECT_TYPE_TABLE_DATA_AND_CHILDREN:
   21076            1 :                     simple_string_list_append(&tabledata_exclude_patterns_and_children,
   21077              :                                               objname);
   21078            1 :                     break;
   21079            2 :                 case FILTER_OBJECT_TYPE_SCHEMA:
   21080            2 :                     simple_string_list_append(&schema_exclude_patterns, objname);
   21081            2 :                     break;
   21082            2 :                 case FILTER_OBJECT_TYPE_TABLE:
   21083            2 :                     simple_string_list_append(&table_exclude_patterns, objname);
   21084            2 :                     break;
   21085            1 :                 case FILTER_OBJECT_TYPE_TABLE_AND_CHILDREN:
   21086            1 :                     simple_string_list_append(&table_exclude_patterns_and_children,
   21087              :                                               objname);
   21088            1 :                     break;
   21089              :             }
   21090              :         }
   21091              :         else
   21092              :         {
   21093              :             Assert(comtype == FILTER_COMMAND_TYPE_NONE);
   21094              :             Assert(objtype == FILTER_OBJECT_TYPE_NONE);
   21095              :         }
   21096              : 
   21097           32 :         if (objname)
   21098           25 :             free(objname);
   21099              :     }
   21100              : 
   21101           22 :     filter_free(&fstate);
   21102           22 : }
        

Generated by: LCOV version 2.0-1