LCOV - code coverage report
Current view: top level - src/bin/pg_dump - pg_dump.c (source / functions) Coverage Total Hit
Test: PostgreSQL 19beta1 Lines: 91.0 % 8539 7767
Test Date: 2026-06-17 20:16:38 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          392 : main(int argc, char **argv)
     419              : {
     420              :     int         c;
     421          392 :     const char *filename = NULL;
     422          392 :     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          392 :     bool        g_verbose = false;
     433          392 :     const char *dumpencoding = NULL;
     434          392 :     const char *dumpsnapshot = NULL;
     435          392 :     char       *use_role = NULL;
     436          392 :     int         numWorkers = 1;
     437          392 :     int         plainText = 0;
     438          392 :     ArchiveFormat archiveFormat = archUnknown;
     439              :     ArchiveMode archiveMode;
     440          392 :     pg_compress_specification compression_spec = {0};
     441          392 :     char       *compression_detail = NULL;
     442          392 :     char       *compression_algorithm_str = "none";
     443          392 :     char       *error_detail = NULL;
     444          392 :     bool        user_compression_defined = false;
     445          392 :     DataDirSyncMethod sync_method = DATA_DIR_SYNC_METHOD_FSYNC;
     446          392 :     bool        data_only = false;
     447          392 :     bool        schema_only = false;
     448          392 :     bool        statistics_only = false;
     449          392 :     bool        with_statistics = false;
     450          392 :     bool        no_data = false;
     451          392 :     bool        no_schema = false;
     452          392 :     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          392 :     pg_logging_init(argv[0]);
     543          392 :     pg_logging_set_level(PG_LOG_WARNING);
     544          392 :     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          392 :     init_parallel_dump_utils();
     551              : 
     552          392 :     progname = get_progname(argv[0]);
     553              : 
     554          392 :     if (argc > 1)
     555              :     {
     556          392 :         if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
     557              :         {
     558            1 :             help(progname);
     559            1 :             exit_nicely(0);
     560              :         }
     561          391 :         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          307 :     InitDumpOptions(&dopt);
     569              : 
     570         1689 :     while ((c = getopt_long(argc, argv, "abBcCd:e:E:f:F:h:j:n:N:Op:RsS:t:T:U:vwWxXZ:",
     571         1689 :                             long_options, &optindex)) != -1)
     572              :     {
     573         1390 :         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          339 :             case 'f':
     609          339 :                 filename = pg_strdup(optarg);
     610          339 :                 break;
     611              : 
     612          187 :             case 'F':
     613          187 :                 format = pg_strdup(optarg);
     614          187 :                 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           18 :             case 'n':           /* include schema(s) */
     628           18 :                 simple_string_list_append(&schema_include_patterns, optarg);
     629           18 :                 dopt.include_everything = false;
     630           18 :                 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          154 :             case 7:             /* no-sync */
     717          154 :                 dosync = false;
     718          154 :                 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            5 :             case 18:
     779            5 :                 statistics_only = true;
     780            5 :                 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           94 :             case 22:
     795           94 :                 with_statistics = true;
     796           94 :                 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          299 :     if (optind < argc && dopt.cparams.dbname == NULL)
     814          263 :         dopt.cparams.dbname = argv[optind++];
     815              : 
     816              :     /* Complain if any arguments remain */
     817          299 :     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          298 :     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          298 :     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          295 :     check_mut_excl_opts(data_only, "-a/--data-only",
     836              :                         no_data, "--no-data");
     837          295 :     check_mut_excl_opts(schema_only, "-s/--schema-only",
     838              :                         no_schema, "--no-schema");
     839          295 :     check_mut_excl_opts(statistics_only, "--statistics-only",
     840              :                         no_statistics, "--no-statistics");
     841              : 
     842              :     /* --statistics and --no-statistics are incompatible */
     843          294 :     check_mut_excl_opts(with_statistics, "--statistics",
     844              :                         no_statistics, "--no-statistics");
     845              : 
     846              :     /* --statistics is incompatible with *-only (except --statistics-only) */
     847          294 :     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          293 :     check_mut_excl_opts(foreign_servers_include_patterns.head, "--include-foreign-data",
     853              :                         schema_only, "-s/--schema-only");
     854              : 
     855          292 :     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          291 :     check_mut_excl_opts(dopt.outputClean, "-c/--clean",
     861              :                         data_only, "-a/--data-only");
     862              : 
     863          290 :     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          289 :     dopt.dumpData = ((dopt.dumpData && !schema_only && !statistics_only) ||
     873          578 :                      data_only) && !no_data;
     874          289 :     dopt.dumpSchema = ((dopt.dumpSchema && !data_only && !statistics_only) ||
     875          578 :                        schema_only) && !no_schema;
     876          289 :     dopt.dumpStatistics = ((dopt.dumpStatistics && !schema_only && !data_only) ||
     877          578 :                            (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          289 :     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          288 :     archiveFormat = parseArchiveFormat(format, &archiveMode);
     891              : 
     892              :     /* archiveFormat specific setup */
     893          287 :     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          135 :     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          287 :     if ((archiveFormat == archCustom || archiveFormat == archDirectory) &&
     917          124 :         !user_compression_defined)
     918              :     {
     919              : #ifdef HAVE_LIBZ
     920          118 :         compression_algorithm_str = "gzip";
     921              : #else
     922              :         compression_algorithm_str = "none";
     923              : #endif
     924              :     }
     925              : 
     926              :     /*
     927              :      * Compression options
     928              :      */
     929          287 :     if (!parse_compress_algorithm(compression_algorithm_str,
     930              :                                   &compression_algorithm))
     931            1 :         pg_fatal("unrecognized compression algorithm: \"%s\"",
     932              :                  compression_algorithm_str);
     933              : 
     934          286 :     parse_compress_specification(compression_algorithm, compression_detail,
     935              :                                  &compression_spec);
     936          286 :     error_detail = validate_compress_specification(&compression_spec);
     937          286 :     if (error_detail != NULL)
     938            3 :         pg_fatal("invalid compression specification: %s",
     939              :                  error_detail);
     940              : 
     941          283 :     error_detail = supports_compression(compression_spec);
     942          283 :     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          283 :     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          283 :     if (!plainText)
     959          135 :         dopt.outputCreateDB = 1;
     960              : 
     961              :     /* Parallel backup only in the directory archive format so far */
     962          283 :     if (archiveFormat != archDirectory && numWorkers > 1)
     963            1 :         pg_fatal("parallel backup only supported by the directory format");
     964              : 
     965              :     /* Open the output file */
     966          282 :     fout = CreateArchive(filename, archiveFormat, compression_spec,
     967              :                          dosync, archiveMode, setupDumpWorker, sync_method);
     968              : 
     969              :     /* Make dump options accessible right away */
     970          281 :     SetArchiveOptions(fout, &dopt, NULL);
     971              : 
     972              :     /* Register the cleanup hook */
     973          281 :     on_exit_close_archive(fout);
     974              : 
     975              :     /* Let the archiver know how noisy to be */
     976          281 :     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          281 :     fout->minRemoteVersion = 90200;
     984          281 :     fout->maxRemoteVersion = (PG_VERSION_NUM / 100) * 100 + 99;
     985              : 
     986          281 :     fout->numWorkers = numWorkers;
     987              : 
     988              :     /*
     989              :      * Open the database using the Archiver, so it knows about it. Errors mean
     990              :      * death.
     991              :      */
     992          281 :     ConnectDatabaseAhx(fout, &dopt.cparams, false);
     993          279 :     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          279 :     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          279 :     g_last_builtin_oid = FirstNormalObjectId - 1;
    1008              : 
    1009          279 :     pg_log_info("last built-in OID is %u", g_last_builtin_oid);
    1010              : 
    1011              :     /* Expand schema selection patterns into OID lists */
    1012          279 :     if (schema_include_patterns.head != NULL)
    1013              :     {
    1014           19 :         expand_schema_name_patterns(fout, &schema_include_patterns,
    1015              :                                     &schema_include_oids,
    1016              :                                     strict_names);
    1017           13 :         if (schema_include_oids.head == NULL)
    1018            1 :             pg_fatal("no matching schemas were found");
    1019              :     }
    1020          272 :     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          272 :     expand_table_name_patterns(fout, &table_include_patterns,
    1027              :                                &table_include_oids,
    1028              :                                strict_names, false);
    1029          267 :     expand_table_name_patterns(fout, &table_include_patterns_and_children,
    1030              :                                &table_include_oids,
    1031              :                                strict_names, true);
    1032          267 :     if ((table_include_patterns.head != NULL ||
    1033          256 :          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          265 :     expand_table_name_patterns(fout, &table_exclude_patterns,
    1038              :                                &table_exclude_oids,
    1039              :                                false, false);
    1040          265 :     expand_table_name_patterns(fout, &table_exclude_patterns_and_children,
    1041              :                                &table_exclude_oids,
    1042              :                                false, true);
    1043              : 
    1044          265 :     expand_table_name_patterns(fout, &tabledata_exclude_patterns,
    1045              :                                &tabledata_exclude_oids,
    1046              :                                false, false);
    1047          265 :     expand_table_name_patterns(fout, &tabledata_exclude_patterns_and_children,
    1048              :                                &tabledata_exclude_oids,
    1049              :                                false, true);
    1050              : 
    1051          265 :     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          264 :     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          263 :     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          263 :     if (dopt.include_everything && dopt.dumpData && !dopt.dontOutputLOs)
    1080          193 :         dopt.outputLOs = true;
    1081              : 
    1082              :     /*
    1083              :      * Collect role names so we can map object owner OIDs to names.
    1084              :      */
    1085          263 :     collectRoleNames(fout);
    1086              : 
    1087              :     /*
    1088              :      * Now scan the database and create DumpableObject structs for all the
    1089              :      * objects we intend to dump.
    1090              :      */
    1091          263 :     tblinfo = getSchemaData(fout, &numTables);
    1092              : 
    1093          262 :     if (dopt.dumpData)
    1094              :     {
    1095          217 :         getTableData(&dopt, tblinfo, numTables, 0);
    1096          217 :         buildMatViewRefreshDependencies(fout);
    1097          217 :         if (!dopt.dumpSchema)
    1098            7 :             getTableDataFKConstraints();
    1099              :     }
    1100              : 
    1101          262 :     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          262 :     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          262 :     if (dopt.outputLOs || dopt.binary_upgrade)
    1149          233 :         getLOs(fout);
    1150              : 
    1151              :     /*
    1152              :      * Collect dependency data to assist in ordering the objects.
    1153              :      */
    1154          262 :     getDependencies(fout);
    1155              : 
    1156              :     /*
    1157              :      * Collect ACLs, comments, and security labels, if wanted.
    1158              :      */
    1159          262 :     if (!dopt.aclsSkip)
    1160          260 :         getAdditionalACLs(fout);
    1161          262 :     if (!dopt.no_comments)
    1162          262 :         collectComments(fout);
    1163          262 :     if (!dopt.no_security_labels)
    1164          262 :         collectSecLabels(fout);
    1165              : 
    1166              :     /* For binary upgrade mode, collect required pg_class information. */
    1167          262 :     if (dopt.binary_upgrade)
    1168           40 :         collectBinaryUpgradeClassOids(fout);
    1169              : 
    1170              :     /* Collect sequence information. */
    1171          262 :     collectSequences(fout);
    1172              : 
    1173              :     /* Lastly, create dummy objects to represent the section boundaries */
    1174          262 :     boundaryObjs = createBoundaryObjects();
    1175              : 
    1176              :     /* Get pointers to all the known DumpableObjects */
    1177          262 :     getDumpableObjects(&dobjs, &numObjs);
    1178              : 
    1179              :     /*
    1180              :      * Add dummy dependencies to enforce the dump section ordering.
    1181              :      */
    1182          262 :     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          262 :     sortDumpableObjectsByTypeName(dobjs, numObjs);
    1192              : 
    1193          262 :     sortDumpableObjects(dobjs, numObjs,
    1194          262 :                         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          262 :     dumpEncoding(fout);
    1205          262 :     dumpStdStrings(fout);
    1206          262 :     dumpSearchPath(fout);
    1207              : 
    1208              :     /* The database items are always next, unless we don't want them at all */
    1209          262 :     if (dopt.outputCreateDB)
    1210          163 :         dumpDatabase(fout);
    1211              : 
    1212              :     /* Now the rearrangeable objects. */
    1213       987995 :     for (i = 0; i < numObjs; i++)
    1214       987733 :         dumpDumpableObject(fout, dobjs[i]);
    1215              : 
    1216              :     /*
    1217              :      * Set up options info to ensure we dump what we want.
    1218              :      */
    1219          262 :     ropt = NewRestoreOptions();
    1220          262 :     ropt->filename = filename;
    1221              : 
    1222              :     /* if you change this list, see dumpOptionsFromRestoreOptions */
    1223          262 :     ropt->cparams.dbname = dopt.cparams.dbname ? pg_strdup(dopt.cparams.dbname) : NULL;
    1224          262 :     ropt->cparams.pgport = dopt.cparams.pgport ? pg_strdup(dopt.cparams.pgport) : NULL;
    1225          262 :     ropt->cparams.pghost = dopt.cparams.pghost ? pg_strdup(dopt.cparams.pghost) : NULL;
    1226          262 :     ropt->cparams.username = dopt.cparams.username ? pg_strdup(dopt.cparams.username) : NULL;
    1227          262 :     ropt->cparams.promptPassword = dopt.cparams.promptPassword;
    1228          262 :     ropt->dropSchema = dopt.outputClean;
    1229          262 :     ropt->dumpData = dopt.dumpData;
    1230          262 :     ropt->dumpSchema = dopt.dumpSchema;
    1231          262 :     ropt->dumpStatistics = dopt.dumpStatistics;
    1232          262 :     ropt->if_exists = dopt.if_exists;
    1233          262 :     ropt->column_inserts = dopt.column_inserts;
    1234          262 :     ropt->dumpSections = dopt.dumpSections;
    1235          262 :     ropt->aclsSkip = dopt.aclsSkip;
    1236          262 :     ropt->superuser = dopt.outputSuperuser;
    1237          262 :     ropt->createDB = dopt.outputCreateDB;
    1238          262 :     ropt->noOwner = dopt.outputNoOwner;
    1239          262 :     ropt->noTableAm = dopt.outputNoTableAm;
    1240          262 :     ropt->noTablespace = dopt.outputNoTablespaces;
    1241          262 :     ropt->disable_triggers = dopt.disable_triggers;
    1242          262 :     ropt->use_setsessauth = dopt.use_setsessauth;
    1243          262 :     ropt->disable_dollar_quoting = dopt.disable_dollar_quoting;
    1244          262 :     ropt->dump_inserts = dopt.dump_inserts;
    1245          262 :     ropt->no_comments = dopt.no_comments;
    1246          262 :     ropt->no_policies = dopt.no_policies;
    1247          262 :     ropt->no_publications = dopt.no_publications;
    1248          262 :     ropt->no_security_labels = dopt.no_security_labels;
    1249          262 :     ropt->no_subscriptions = dopt.no_subscriptions;
    1250          262 :     ropt->lockWaitTimeout = dopt.lockWaitTimeout;
    1251          262 :     ropt->include_everything = dopt.include_everything;
    1252          262 :     ropt->enable_row_security = dopt.enable_row_security;
    1253          262 :     ropt->sequence_data = dopt.sequence_data;
    1254          262 :     ropt->binary_upgrade = dopt.binary_upgrade;
    1255          262 :     ropt->restrict_key = dopt.restrict_key ? pg_strdup(dopt.restrict_key) : NULL;
    1256              : 
    1257          262 :     ropt->compression_spec = compression_spec;
    1258              : 
    1259          262 :     ropt->suppressDumpWarnings = true;   /* We've already shown them */
    1260              : 
    1261          262 :     SetArchiveOptions(fout, &dopt, ropt);
    1262              : 
    1263              :     /* Mark which entries should be output */
    1264          262 :     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          262 :     if (!plainText)
    1272          134 :         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          262 :     if (plainText)
    1282          128 :         RestoreArchive(fout, false);
    1283              : 
    1284          261 :     CloseArchive(fout);
    1285              : 
    1286          261 :     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          295 : setup_connection(Archive *AH, const char *dumpencoding,
    1400              :                  const char *dumpsnapshot, char *use_role)
    1401              : {
    1402          295 :     DumpOptions *dopt = AH->dopt;
    1403          295 :     PGconn     *conn = GetConnection(AH);
    1404              : 
    1405          295 :     PQclear(ExecuteSqlQueryForSingleRow(AH, ALWAYS_SECURE_SEARCH_PATH_SQL));
    1406              : 
    1407              :     /*
    1408              :      * Set the client encoding if requested.
    1409              :      */
    1410          295 :     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          295 :     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          295 :     AH->std_strings = true;
    1432              : 
    1433              :     /*
    1434              :      * Get the active encoding, so we know how to escape strings.
    1435              :      */
    1436          295 :     AH->encoding = PQclientEncoding(conn);
    1437          295 :     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          295 :     if (!use_role && AH->use_role)
    1445            2 :         use_role = AH->use_role;
    1446              : 
    1447              :     /* Set the role if requested */
    1448          295 :     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          295 :     ExecuteSqlStatement(AH, "SET DATESTYLE = ISO");
    1463              : 
    1464              :     /* Likewise, avoid using sql_standard intervalstyle */
    1465          295 :     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          295 :     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          295 :         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          295 :     ExecuteSqlStatement(AH, "SET synchronize_seqscans TO off");
    1489              : 
    1490              :     /*
    1491              :      * Disable timeouts if supported.
    1492              :      */
    1493          295 :     ExecuteSqlStatement(AH, "SET statement_timeout = 0");
    1494          295 :     if (AH->remoteVersion >= 90300)
    1495          295 :         ExecuteSqlStatement(AH, "SET lock_timeout = 0");
    1496          295 :     if (AH->remoteVersion >= 90600)
    1497          295 :         ExecuteSqlStatement(AH, "SET idle_in_transaction_session_timeout = 0");
    1498          295 :     if (AH->remoteVersion >= 170000)
    1499          295 :         ExecuteSqlStatement(AH, "SET transaction_timeout = 0");
    1500              : 
    1501              :     /*
    1502              :      * Quote all identifiers, if requested.
    1503              :      */
    1504          295 :     if (quote_all_identifiers)
    1505           38 :         ExecuteSqlStatement(AH, "SET quote_all_identifiers = true");
    1506              : 
    1507              :     /*
    1508              :      * Adjust row-security mode, if supported.
    1509              :      */
    1510          295 :     if (AH->remoteVersion >= 90500)
    1511              :     {
    1512          295 :         if (dopt->enable_row_security)
    1513            0 :             ExecuteSqlStatement(AH, "SET row_security = on");
    1514              :         else
    1515          295 :             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          295 :     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          295 :     AH->is_prepared = pg_malloc0_array(bool, NUM_PREP_QUERIES);
    1530              : 
    1531              :     /*
    1532              :      * Start transaction-snapshot mode transaction to dump consistent data.
    1533              :      */
    1534          295 :     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          295 :     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          295 :         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          295 :     if (dumpsnapshot)
    1559            0 :         AH->sync_snapshot_id = pg_strdup(dumpsnapshot);
    1560              : 
    1561          295 :     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          279 :     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          295 : }
    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          288 : parseArchiveFormat(const char *format, ArchiveMode *mode)
    1610              : {
    1611              :     ArchiveFormat archiveFormat;
    1612              : 
    1613          288 :     *mode = archModeWrite;
    1614              : 
    1615          288 :     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          240 :     else if (pg_strcasecmp(format, "c") == 0)
    1622            0 :         archiveFormat = archCustom;
    1623          240 :     else if (pg_strcasecmp(format, "custom") == 0)
    1624           59 :         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          287 :     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          291 : 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          291 :     if (patterns->head == NULL)
    1658          269 :         return;                 /* nothing to do */
    1659              : 
    1660           22 :     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           38 :     for (cell = patterns->head; cell; cell = cell->next)
    1668              :     {
    1669              :         PQExpBufferData dbbuf;
    1670              :         int         dotcnt;
    1671              : 
    1672           22 :         appendPQExpBufferStr(query,
    1673              :                              "SELECT oid FROM pg_catalog.pg_namespace n\n");
    1674           22 :         initPQExpBuffer(&dbbuf);
    1675           22 :         processSQLNamePattern(GetConnection(fout), query, cell->val, false,
    1676              :                               false, NULL, "n.nspname", NULL, NULL, &dbbuf,
    1677              :                               &dotcnt);
    1678           22 :         if (dotcnt > 1)
    1679            2 :             pg_fatal("improper qualified name (too many dotted names): %s",
    1680              :                      cell->val);
    1681           20 :         else if (dotcnt == 1)
    1682            3 :             prohibit_crossdb_refs(GetConnection(fout), dbbuf.data, cell->val);
    1683           17 :         termPQExpBuffer(&dbbuf);
    1684              : 
    1685           17 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    1686           17 :         if (strict_names && PQntuples(res) == 0)
    1687            1 :             pg_fatal("no matching schemas were found for pattern \"%s\"", cell->val);
    1688              : 
    1689           31 :         for (i = 0; i < PQntuples(res); i++)
    1690              :         {
    1691           15 :             simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
    1692              :         }
    1693              : 
    1694           16 :         PQclear(res);
    1695           16 :         resetPQExpBuffer(query);
    1696              :     }
    1697              : 
    1698           16 :     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          268 : 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          268 :     if (patterns->head == NULL)
    1717          261 :         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          265 : 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          265 :     if (patterns->head == NULL)
    1769          262 :         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         1599 : 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         1599 :     if (patterns->head == NULL)
    1821         1570 :         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       844086 : checkExtensionMembership(DumpableObject *dobj, Archive *fout)
    1933              : {
    1934       844086 :     ExtensionInfo *ext = findOwningExtension(dobj->catId);
    1935              : 
    1936       844086 :     if (ext == NULL)
    1937       843198 :         return false;
    1938              : 
    1939          888 :     dobj->ext_member = true;
    1940              : 
    1941              :     /* Record dependency so that getDependencies needn't deal with that */
    1942          888 :     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          888 :     if (fout->dopt->binary_upgrade)
    1965          186 :         dobj->dump = ext->dobj.dump;
    1966              :     else
    1967              :     {
    1968          702 :         if (fout->remoteVersion < 90600)
    1969            0 :             dobj->dump = DUMP_COMPONENT_NONE;
    1970              :         else
    1971          702 :             dobj->dump = ext->dobj.dump_contains & (DUMP_COMPONENT_ACL);
    1972              :     }
    1973              : 
    1974          888 :     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         1773 : 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         1773 :     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         1773 :     if (table_include_oids.head != NULL)
    1997           50 :         nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
    1998         1723 :     else if (schema_include_oids.head != NULL)
    1999          201 :         nsinfo->dobj.dump_contains = nsinfo->dobj.dump =
    2000          201 :             simple_oid_list_member(&schema_include_oids,
    2001              :                                    nsinfo->dobj.catId.oid) ?
    2002          201 :             DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
    2003         1522 :     else if (fout->remoteVersion >= 90600 &&
    2004         1522 :              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          240 :         nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_ACL;
    2012              :     }
    2013         1282 :     else if (strncmp(nsinfo->dobj.name, "pg_", 3) == 0 ||
    2014          686 :              strcmp(nsinfo->dobj.name, "information_schema") == 0)
    2015              :     {
    2016              :         /* Other system schemas don't get dumped */
    2017          836 :         nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
    2018              :     }
    2019          446 :     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          236 :         nsinfo->create = false;
    2030          236 :         nsinfo->dobj.dump = DUMP_COMPONENT_ALL;
    2031          236 :         if (nsinfo->nspowner == ROLE_PG_DATABASE_OWNER)
    2032          192 :             nsinfo->dobj.dump &= ~DUMP_COMPONENT_DEFINITION;
    2033          236 :         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          236 :         nsinfo->dobj.components |= DUMP_COMPONENT_COMMENT;
    2041              :     }
    2042              :     else
    2043          210 :         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         2471 :     if (nsinfo->dobj.dump_contains &&
    2049          698 :         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         1773 :     (void) checkExtensionMembership(&nsinfo->dobj, fout);
    2061         1773 : }
    2062              : 
    2063              : /*
    2064              :  * selectDumpableTable: policy-setting subroutine
    2065              :  *      Mark a table as to be dumped or not
    2066              :  */
    2067              : static void
    2068        71724 : selectDumpableTable(TableInfo *tbinfo, Archive *fout)
    2069              : {
    2070        71724 :     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        71499 :     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        68676 :         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       116794 :     if (tbinfo->dobj.dump &&
    2088        45295 :         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       195349 : selectDumpableType(TypeInfo *tyinfo, Archive *fout)
    2108              : {
    2109              :     /* skip complex types, except for standalone composite types */
    2110       195349 :     if (OidIsValid(tyinfo->typrelid) &&
    2111        70821 :         tyinfo->typrelkind != RELKIND_COMPOSITE_TYPE)
    2112              :     {
    2113        70636 :         TableInfo  *tytable = findTableByOid(tyinfo->typrelid);
    2114              : 
    2115        70636 :         tyinfo->dobj.objType = DO_DUMMY_TYPE;
    2116        70636 :         if (tytable != NULL)
    2117        70636 :             tyinfo->dobj.dump = tytable->dobj.dump;
    2118              :         else
    2119            0 :             tyinfo->dobj.dump = DUMP_COMPONENT_NONE;
    2120        70636 :         return;
    2121              :     }
    2122              : 
    2123              :     /* skip auto-generated array and multirange types */
    2124       124713 :     if (tyinfo->isArray || tyinfo->isMultirange)
    2125              :     {
    2126        95565 :         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       124713 :     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       124563 :     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          206 : selectDumpableDefaultACL(DefaultACLInfo *dinfo, DumpOptions *dopt)
    2153              : {
    2154              :     /* Default ACLs can't be extension members */
    2155              : 
    2156          206 :     if (dinfo->dobj.namespace)
    2157              :         /* default ACLs are considered part of the namespace */
    2158           96 :         dinfo->dobj.dump = dinfo->dobj.namespace->dobj.dump_contains;
    2159              :     else
    2160          110 :         dinfo->dobj.dump = dopt->include_everything ?
    2161          110 :             DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
    2162          206 : }
    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        63756 : selectDumpableCast(CastInfo *cast, Archive *fout)
    2175              : {
    2176        63756 :     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        63756 :     if (cast->dobj.catId.oid <= g_last_builtin_oid)
    2184        63666 :         cast->dobj.dump = DUMP_COMPONENT_NONE;
    2185              :     else
    2186           90 :         cast->dobj.dump = fout->dopt->include_everything ?
    2187           90 :             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          310 : selectDumpableProcLang(ProcLangInfo *plang, Archive *fout)
    2200              : {
    2201          310 :     if (checkExtensionMembership(&plang->dobj, fout))
    2202          262 :         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           48 :     if (!fout->dopt->include_everything)
    2212            9 :         plang->dobj.dump = DUMP_COMPONENT_NONE;
    2213              :     else
    2214              :     {
    2215           39 :         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           39 :             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         1962 : selectDumpableAccessMethod(AccessMethodInfo *method, Archive *fout)
    2233              : {
    2234              :     /* see getAccessMethods() comment about v9.6. */
    2235         1962 :     if (fout->remoteVersion < 90600)
    2236              :     {
    2237            0 :         method->dobj.dump = DUMP_COMPONENT_NONE;
    2238            0 :         return;
    2239              :     }
    2240              : 
    2241         1962 :     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         1937 :     if (method->dobj.catId.oid <= g_last_builtin_oid)
    2249         1834 :         method->dobj.dump = DUMP_COMPONENT_NONE;
    2250              :     else
    2251          103 :         method->dobj.dump = fout->dopt->include_everything ?
    2252          103 :             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          294 : 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          294 :     if (extinfo->dobj.catId.oid <= g_last_builtin_oid)
    2275          263 :         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          294 : }
    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          502 : selectDumpablePublicationObject(DumpableObject *dobj, Archive *fout)
    2307              : {
    2308          502 :     if (checkExtensionMembership(dobj, fout))
    2309            0 :         return;                 /* extension membership overrides all else */
    2310              : 
    2311          502 :     dobj->dump = fout->dopt->include_everything ?
    2312          502 :         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          220 : selectDumpableStatisticsObject(StatsExtInfo *sobj, Archive *fout)
    2325              : {
    2326          220 :     if (checkExtensionMembership(&sobj->dobj, fout))
    2327            0 :         return;                 /* extension membership overrides all else */
    2328              : 
    2329          220 :     sobj->dobj.dump = sobj->dobj.namespace->dobj.dump_contains;
    2330          220 :     if (sobj->stattable == NULL ||
    2331          220 :         !(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       579126 : selectDumpableObject(DumpableObject *dobj, Archive *fout)
    2343              : {
    2344       579126 :     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       578925 :     if (dobj->namespace)
    2352       578010 :         dobj->dump = dobj->namespace->dobj.dump_contains;
    2353              :     else
    2354          915 :         dobj->dump = fout->dopt->include_everything ?
    2355          915 :             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         4565 : dumpTableData_copy(Archive *fout, const void *dcontext)
    2365              : {
    2366         4565 :     const TableDataInfo *tdinfo = dcontext;
    2367         4565 :     const TableInfo *tbinfo = tdinfo->tdtable;
    2368         4565 :     const char *classname = tbinfo->dobj.name;
    2369         4565 :     PQExpBuffer q = createPQExpBuffer();
    2370              : 
    2371              :     /*
    2372              :      * Note: can't use getThreadLocalPQExpBuffer() here, we're calling fmtId
    2373              :      * which uses it already.
    2374              :      */
    2375         4565 :     PQExpBuffer clistBuf = createPQExpBuffer();
    2376         4565 :     PGconn     *conn = GetConnection(fout);
    2377              :     PGresult   *res;
    2378              :     int         ret;
    2379              :     char       *copybuf;
    2380              :     const char *column_list;
    2381              : 
    2382         4565 :     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         4565 :     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         4565 :     if (tdinfo->filtercond || tbinfo->relkind == RELKIND_FOREIGN_TABLE ||
    2400         4524 :         (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         4524 :         appendPQExpBuffer(q, "COPY %s %s TO stdout;",
    2424         4524 :                           fmtQualifiedDumpable(tbinfo),
    2425              :                           column_list);
    2426              :     }
    2427         4565 :     res = ExecuteSqlQuery(fout, q->data, PGRES_COPY_OUT);
    2428         4564 :     PQclear(res);
    2429         4564 :     destroyPQExpBuffer(clistBuf);
    2430              : 
    2431              :     for (;;)
    2432              :     {
    2433      1824432 :         ret = PQgetCopyData(conn, &copybuf, 0);
    2434              : 
    2435      1824432 :         if (ret < 0)
    2436         4564 :             break;              /* done or error */
    2437              : 
    2438      1819868 :         if (copybuf)
    2439              :         {
    2440      1819868 :             WriteData(fout, copybuf, ret);
    2441      1819868 :             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         4564 :     archprintf(fout, "\\.\n\n\n");
    2491              : 
    2492         4564 :     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         4564 :     res = PQgetResult(conn);
    2503         4564 :     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         4564 :     PQclear(res);
    2511              : 
    2512              :     /* Do this to ensure we've pumped libpq back to idle state */
    2513         4564 :     if (PQgetResult(conn) != NULL)
    2514            0 :         pg_log_warning("unexpected extra results during COPY of table \"%s\"",
    2515              :                        classname);
    2516              : 
    2517         4564 :     destroyPQExpBuffer(q);
    2518              : 
    2519              :     /* Revert back the setting */
    2520         4564 :     if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
    2521            0 :         set_restrict_relation_kind(fout, "view, foreign-table");
    2522              : 
    2523         4564 :     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           83 : getRootTableInfo(const TableInfo *tbinfo)
    2805              : {
    2806              :     TableInfo  *parentTbinfo;
    2807              : 
    2808              :     Assert(tbinfo->ispartition);
    2809              :     Assert(tbinfo->numParents == 1);
    2810              : 
    2811           83 :     parentTbinfo = tbinfo->parents[0];
    2812           83 :     while (parentTbinfo->ispartition)
    2813              :     {
    2814              :         Assert(parentTbinfo->numParents == 1);
    2815            0 :         parentTbinfo = parentTbinfo->parents[0];
    2816              :     }
    2817              : 
    2818           83 :     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         1102 : forcePartitionRootLoad(const TableInfo *tbinfo)
    2830              : {
    2831              :     TableInfo  *parentTbinfo;
    2832              : 
    2833              :     Assert(tbinfo->ispartition);
    2834              :     Assert(tbinfo->numParents == 1);
    2835              : 
    2836         1102 :     parentTbinfo = tbinfo->parents[0];
    2837         1102 :     if (parentTbinfo->unsafe_partitions)
    2838           83 :         return true;
    2839         1239 :     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         1019 :     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         4738 : dumpTableData(Archive *fout, const TableDataInfo *tdinfo)
    2858              : {
    2859         4738 :     DumpOptions *dopt = fout->dopt;
    2860         4738 :     const TableInfo *tbinfo = tdinfo->tdtable;
    2861         4738 :     PQExpBuffer copyBuf = createPQExpBuffer();
    2862         4738 :     PQExpBuffer clistBuf = createPQExpBuffer();
    2863              :     DataDumperPtr dumpFn;
    2864         4738 :     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         4738 :     if (tbinfo->ispartition &&
    2878         2156 :         (dopt->load_via_partition_root ||
    2879         1078 :          forcePartitionRootLoad(tbinfo)))
    2880           76 :     {
    2881              :         const TableInfo *parentTbinfo;
    2882              :         char       *sanitized;
    2883              : 
    2884           76 :         parentTbinfo = getRootTableInfo(tbinfo);
    2885           76 :         copyFrom = fmtQualifiedDumpable(parentTbinfo);
    2886           76 :         sanitized = sanitize_line(copyFrom, true);
    2887           76 :         printfPQExpBuffer(copyBuf, "-- load via partition root %s",
    2888              :                           sanitized);
    2889           76 :         free(sanitized);
    2890           76 :         tdDefn = pg_strdup(copyBuf->data);
    2891              :     }
    2892              :     else
    2893         4662 :         copyFrom = fmtQualifiedDumpable(tbinfo);
    2894              : 
    2895         4738 :     if (dopt->dump_inserts == 0)
    2896              :     {
    2897              :         /* Dump/restore using COPY */
    2898         4651 :         dumpFn = dumpTableData_copy;
    2899              :         /* must use 2 steps here 'cause fmtId is nonreentrant */
    2900         4651 :         printfPQExpBuffer(copyBuf, "COPY %s ",
    2901              :                           copyFrom);
    2902         4651 :         appendPQExpBuffer(copyBuf, "%s FROM stdin;\n",
    2903              :                           fmtCopyColumnList(tbinfo, clistBuf));
    2904         4651 :         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         4738 :     if (tdinfo->dobj.dump & DUMP_COMPONENT_DATA)
    2919              :     {
    2920              :         TocEntry   *te;
    2921              : 
    2922         4738 :         te = ArchiveEntry(fout, tdinfo->dobj.catId, tdinfo->dobj.dumpId,
    2923         4738 :                           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         4738 :         te->dataLength = (BlockNumber) tbinfo->relpages;
    2947         4738 :         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         4738 :     destroyPQExpBuffer(copyBuf);
    2961         4738 :     destroyPQExpBuffer(clistBuf);
    2962         4738 : }
    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          363 : refreshMatViewData(Archive *fout, const TableDataInfo *tdinfo)
    2973              : {
    2974          363 :     TableInfo  *tbinfo = tdinfo->tdtable;
    2975              :     PQExpBuffer q;
    2976              : 
    2977              :     /* If the materialized view is not flagged as populated, skip this. */
    2978          363 :     if (!tbinfo->relispopulated)
    2979           72 :         return;
    2980              : 
    2981          291 :     q = createPQExpBuffer();
    2982              : 
    2983          291 :     appendPQExpBuffer(q, "REFRESH MATERIALIZED VIEW %s;\n",
    2984          291 :                       fmtQualifiedDumpable(tbinfo));
    2985              : 
    2986          291 :     if (tdinfo->dobj.dump & DUMP_COMPONENT_DATA)
    2987          291 :         ArchiveEntry(fout,
    2988              :                      tdinfo->dobj.catId, /* catalog ID */
    2989          291 :                      tdinfo->dobj.dumpId,    /* dump ID */
    2990          291 :                      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          291 :     destroyPQExpBuffer(q);
    3000              : }
    3001              : 
    3002              : /*
    3003              :  * getTableData -
    3004              :  *    set up dumpable objects representing the contents of tables
    3005              :  */
    3006              : static void
    3007          253 : getTableData(DumpOptions *dopt, TableInfo *tblinfo, int numTables, char relkind)
    3008              : {
    3009              :     int         i;
    3010              : 
    3011        69501 :     for (i = 0; i < numTables; i++)
    3012              :     {
    3013        69248 :         if (tblinfo[i].dobj.dump & DUMP_COMPONENT_DATA &&
    3014         1010 :             (!relkind || tblinfo[i].relkind == relkind))
    3015         6620 :             makeTableDataInfo(dopt, &(tblinfo[i]));
    3016              :     }
    3017          253 : }
    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         6699 : 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         6699 :     if (tbinfo->dataObj != NULL)
    3035            1 :         return;
    3036              : 
    3037              :     /* Skip property graphs (no data to dump) */
    3038         6698 :     if (tbinfo->relkind == RELKIND_PROPGRAPH)
    3039           88 :         return;
    3040              :     /* Skip VIEWs (no data to dump) */
    3041         6610 :     if (tbinfo->relkind == RELKIND_VIEW)
    3042          517 :         return;
    3043              :     /* Skip FOREIGN TABLEs (no data to dump) unless requested explicitly */
    3044         6093 :     if (tbinfo->relkind == RELKIND_FOREIGN_TABLE &&
    3045           40 :         (foreign_servers_include_oids.head == NULL ||
    3046            4 :          !simple_oid_list_member(&foreign_servers_include_oids,
    3047              :                                  tbinfo->foreign_server)))
    3048           39 :         return;
    3049              :     /* Skip partitioned tables (data in partitions) */
    3050         6054 :     if (tbinfo->relkind == RELKIND_PARTITIONED_TABLE)
    3051          519 :         return;
    3052              : 
    3053              :     /* Don't dump data in unlogged tables, if so requested */
    3054         5535 :     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         5517 :     if (simple_oid_list_member(&tabledata_exclude_oids,
    3060              :                                tbinfo->dobj.catId.oid))
    3061            8 :         return;
    3062              : 
    3063              :     /* OK, let's dump it */
    3064         5509 :     tdinfo = pg_malloc_object(TableDataInfo);
    3065              : 
    3066         5509 :     if (tbinfo->relkind == RELKIND_MATVIEW)
    3067          363 :         tdinfo->dobj.objType = DO_REFRESH_MATVIEW;
    3068         5146 :     else if (tbinfo->relkind == RELKIND_SEQUENCE)
    3069          408 :         tdinfo->dobj.objType = DO_SEQUENCE_SET;
    3070              :     else
    3071         4738 :         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         5509 :     tdinfo->dobj.catId.tableoid = 0;
    3078         5509 :     tdinfo->dobj.catId.oid = tbinfo->dobj.catId.oid;
    3079         5509 :     AssignDumpId(&tdinfo->dobj);
    3080         5509 :     tdinfo->dobj.name = tbinfo->dobj.name;
    3081         5509 :     tdinfo->dobj.namespace = tbinfo->dobj.namespace;
    3082         5509 :     tdinfo->tdtable = tbinfo;
    3083         5509 :     tdinfo->filtercond = NULL;   /* might get set later */
    3084         5509 :     addObjectDependency(&tdinfo->dobj, tbinfo->dobj.dumpId);
    3085              : 
    3086              :     /* A TableDataInfo contains data, of course */
    3087         5509 :     tdinfo->dobj.components |= DUMP_COMPONENT_DATA;
    3088              : 
    3089         5509 :     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         5509 :     if (tbinfo->relkind == RELKIND_MATVIEW && tbinfo->stats != NULL)
    3099              :     {
    3100          286 :         tbinfo->stats->section = SECTION_POST_DATA;
    3101          286 :         addObjectDependency(&tbinfo->stats->dobj, tdinfo->dobj.dumpId);
    3102              :     }
    3103              : 
    3104              :     /* Make sure that we'll collect per-column info for this table. */
    3105         5509 :     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          217 : 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          217 :     if (fout->remoteVersion < 90300)
    3128            0 :         return;
    3129              : 
    3130          217 :     query = createPQExpBuffer();
    3131              : 
    3132          217 :     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          217 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    3162              : 
    3163          217 :     ntups = PQntuples(res);
    3164              : 
    3165          217 :     i_classid = PQfnumber(res, "classid");
    3166          217 :     i_objid = PQfnumber(res, "objid");
    3167          217 :     i_refobjid = PQfnumber(res, "refobjid");
    3168              : 
    3169          493 :     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          276 :         objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
    3179          276 :         objId.oid = atooid(PQgetvalue(res, i, i_objid));
    3180          276 :         refobjId.tableoid = objId.tableoid;
    3181          276 :         refobjId.oid = atooid(PQgetvalue(res, i, i_refobjid));
    3182              : 
    3183          276 :         dobj = findObjectByCatalogId(objId);
    3184          276 :         if (dobj == NULL)
    3185           48 :             continue;
    3186              : 
    3187              :         Assert(dobj->objType == DO_TABLE);
    3188          276 :         tbinfo = (TableInfo *) dobj;
    3189              :         Assert(tbinfo->relkind == RELKIND_MATVIEW);
    3190          276 :         dobj = (DumpableObject *) tbinfo->dataObj;
    3191          276 :         if (dobj == NULL)
    3192           48 :             continue;
    3193              :         Assert(dobj->objType == DO_REFRESH_MATVIEW);
    3194              : 
    3195          228 :         refdobj = findObjectByCatalogId(refobjId);
    3196          228 :         if (refdobj == NULL)
    3197            0 :             continue;
    3198              : 
    3199              :         Assert(refdobj->objType == DO_TABLE);
    3200          228 :         reftbinfo = (TableInfo *) refdobj;
    3201              :         Assert(reftbinfo->relkind == RELKIND_MATVIEW);
    3202          228 :         refdobj = (DumpableObject *) reftbinfo->dataObj;
    3203          228 :         if (refdobj == NULL)
    3204            0 :             continue;
    3205              :         Assert(refdobj->objType == DO_REFRESH_MATVIEW);
    3206              : 
    3207          228 :         addObjectDependency(dobj, refdobj->dumpId);
    3208              : 
    3209          228 :         if (!reftbinfo->relispopulated)
    3210           36 :             tbinfo->relispopulated = false;
    3211              :     }
    3212              : 
    3213          217 :     PQclear(res);
    3214              : 
    3215          217 :     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        26789 :     for (i = 0; i < numObjs; i++)
    3240              :     {
    3241        26782 :         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          163 : dumpDatabase(Archive *fout)
    3273              : {
    3274          163 :     DumpOptions *dopt = fout->dopt;
    3275          163 :     PQExpBuffer dbQry = createPQExpBuffer();
    3276          163 :     PQExpBuffer delQry = createPQExpBuffer();
    3277          163 :     PQExpBuffer creaQry = createPQExpBuffer();
    3278          163 :     PQExpBuffer labelq = createPQExpBuffer();
    3279          163 :     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          163 :     pg_log_info("saving database definition");
    3318              : 
    3319              :     /*
    3320              :      * Fetch the database-level properties for this database.
    3321              :      */
    3322          163 :     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          163 :     if (fout->remoteVersion >= 90300)
    3329          163 :         appendPQExpBufferStr(dbQry, "datminmxid, ");
    3330              :     else
    3331            0 :         appendPQExpBufferStr(dbQry, "0 AS datminmxid, ");
    3332          163 :     if (fout->remoteVersion >= 170000)
    3333          163 :         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          163 :     if (fout->remoteVersion >= 160000)
    3339          163 :         appendPQExpBufferStr(dbQry, "daticurules, ");
    3340              :     else
    3341            0 :         appendPQExpBufferStr(dbQry, "NULL AS daticurules, ");
    3342          163 :     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          163 :     res = ExecuteSqlQueryForSingleRow(fout, dbQry->data);
    3349              : 
    3350          163 :     i_tableoid = PQfnumber(res, "tableoid");
    3351          163 :     i_oid = PQfnumber(res, "oid");
    3352          163 :     i_datname = PQfnumber(res, "datname");
    3353          163 :     i_datdba = PQfnumber(res, "datdba");
    3354          163 :     i_encoding = PQfnumber(res, "encoding");
    3355          163 :     i_datlocprovider = PQfnumber(res, "datlocprovider");
    3356          163 :     i_collate = PQfnumber(res, "datcollate");
    3357          163 :     i_ctype = PQfnumber(res, "datctype");
    3358          163 :     i_datlocale = PQfnumber(res, "datlocale");
    3359          163 :     i_daticurules = PQfnumber(res, "daticurules");
    3360          163 :     i_frozenxid = PQfnumber(res, "datfrozenxid");
    3361          163 :     i_minmxid = PQfnumber(res, "datminmxid");
    3362          163 :     i_datacl = PQfnumber(res, "datacl");
    3363          163 :     i_acldefault = PQfnumber(res, "acldefault");
    3364          163 :     i_datistemplate = PQfnumber(res, "datistemplate");
    3365          163 :     i_datconnlimit = PQfnumber(res, "datconnlimit");
    3366          163 :     i_datcollversion = PQfnumber(res, "datcollversion");
    3367          163 :     i_tablespace = PQfnumber(res, "tablespace");
    3368              : 
    3369          163 :     dbCatId.tableoid = atooid(PQgetvalue(res, 0, i_tableoid));
    3370          163 :     dbCatId.oid = atooid(PQgetvalue(res, 0, i_oid));
    3371          163 :     datname = PQgetvalue(res, 0, i_datname);
    3372          163 :     dba = getRoleName(PQgetvalue(res, 0, i_datdba));
    3373          163 :     encoding = PQgetvalue(res, 0, i_encoding);
    3374          163 :     datlocprovider = PQgetvalue(res, 0, i_datlocprovider);
    3375          163 :     collate = PQgetvalue(res, 0, i_collate);
    3376          163 :     ctype = PQgetvalue(res, 0, i_ctype);
    3377          163 :     if (!PQgetisnull(res, 0, i_datlocale))
    3378           14 :         locale = PQgetvalue(res, 0, i_datlocale);
    3379              :     else
    3380          149 :         locale = NULL;
    3381          163 :     if (!PQgetisnull(res, 0, i_daticurules))
    3382            0 :         icurules = PQgetvalue(res, 0, i_daticurules);
    3383              :     else
    3384          163 :         icurules = NULL;
    3385          163 :     frozenxid = atooid(PQgetvalue(res, 0, i_frozenxid));
    3386          163 :     minmxid = atooid(PQgetvalue(res, 0, i_minmxid));
    3387          163 :     dbdacl.acl = PQgetvalue(res, 0, i_datacl);
    3388          163 :     dbdacl.acldefault = PQgetvalue(res, 0, i_acldefault);
    3389          163 :     datistemplate = PQgetvalue(res, 0, i_datistemplate);
    3390          163 :     datconnlimit = PQgetvalue(res, 0, i_datconnlimit);
    3391          163 :     tablespace = PQgetvalue(res, 0, i_tablespace);
    3392              : 
    3393          163 :     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          163 :     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          124 :         appendPQExpBuffer(creaQry, "CREATE DATABASE %s WITH TEMPLATE = template0",
    3416              :                           qdatname);
    3417              :     }
    3418          163 :     if (strlen(encoding) > 0)
    3419              :     {
    3420          163 :         appendPQExpBufferStr(creaQry, " ENCODING = ");
    3421          163 :         appendStringLiteralAH(creaQry, encoding, fout);
    3422              :     }
    3423              : 
    3424          163 :     appendPQExpBufferStr(creaQry, " LOCALE_PROVIDER = ");
    3425          163 :     if (datlocprovider[0] == 'b')
    3426           14 :         appendPQExpBufferStr(creaQry, "builtin");
    3427          149 :     else if (datlocprovider[0] == 'c')
    3428          149 :         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          163 :     if (strlen(collate) > 0 && strcmp(collate, ctype) == 0)
    3436              :     {
    3437          163 :         appendPQExpBufferStr(creaQry, " LOCALE = ");
    3438          163 :         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          163 :     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          163 :     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          163 :     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          163 :     if (strlen(tablespace) > 0 && strcmp(tablespace, "pg_default") != 0 &&
    3493            5 :         !dopt->outputNoTablespaces)
    3494            5 :         appendPQExpBuffer(creaQry, " TABLESPACE = %s",
    3495              :                           fmtId(tablespace));
    3496          163 :     appendPQExpBufferStr(creaQry, ";\n");
    3497              : 
    3498          163 :     appendPQExpBuffer(delQry, "DROP DATABASE %s;\n",
    3499              :                       qdatname);
    3500              : 
    3501          163 :     dbDumpId = createDumpId();
    3502              : 
    3503          163 :     ArchiveEntry(fout,
    3504              :                  dbCatId,       /* catalog ID */
    3505              :                  dbDumpId,      /* dump ID */
    3506          163 :                  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          163 :     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          163 :         char       *comment = PQgetvalue(res, 0, PQfnumber(res, "description"));
    3524              : 
    3525          163 :         if (comment && *comment && !dopt->no_comments)
    3526              :         {
    3527           65 :             resetPQExpBuffer(dbQry);
    3528              : 
    3529              :             /*
    3530              :              * Generates warning when loaded into a differently-named
    3531              :              * database.
    3532              :              */
    3533           65 :             appendPQExpBuffer(dbQry, "COMMENT ON DATABASE %s IS ", qdatname);
    3534           65 :             appendStringLiteralAH(dbQry, comment, fout);
    3535           65 :             appendPQExpBufferStr(dbQry, ";\n");
    3536              : 
    3537           65 :             ArchiveEntry(fout, nilCatalogId, createDumpId(),
    3538           65 :                          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          163 :     if (!dopt->no_security_labels)
    3550              :     {
    3551              :         PGresult   *shres;
    3552              :         PQExpBuffer seclabelQry;
    3553              : 
    3554          163 :         seclabelQry = createPQExpBuffer();
    3555              : 
    3556          163 :         buildShSecLabelQuery("pg_database", dbCatId.oid, seclabelQry);
    3557          163 :         shres = ExecuteSqlQuery(fout, seclabelQry->data, PGRES_TUPLES_OK);
    3558          163 :         resetPQExpBuffer(seclabelQry);
    3559          163 :         emitShSecLabels(conn, shres, seclabelQry, "DATABASE", datname);
    3560          163 :         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          163 :         destroyPQExpBuffer(seclabelQry);
    3570          163 :         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          163 :     dbdacl.privtype = 0;
    3578          163 :     dbdacl.initprivs = NULL;
    3579              : 
    3580          163 :     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          163 :     resetPQExpBuffer(creaQry);
    3593          163 :     resetPQExpBuffer(delQry);
    3594              : 
    3595          163 :     if (strlen(datconnlimit) > 0 && strcmp(datconnlimit, "-1") != 0)
    3596            0 :         appendPQExpBuffer(creaQry, "ALTER DATABASE %s CONNECTION LIMIT = %s;\n",
    3597              :                           qdatname, datconnlimit);
    3598              : 
    3599          163 :     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          163 :     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          163 :     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          163 :     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          163 :     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          163 :     PQclear(res);
    3768              : 
    3769          163 :     free(qdatname);
    3770          163 :     destroyPQExpBuffer(dbQry);
    3771          163 :     destroyPQExpBuffer(delQry);
    3772          163 :     destroyPQExpBuffer(creaQry);
    3773          163 :     destroyPQExpBuffer(labelq);
    3774          163 : }
    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          163 : dumpDatabaseConfig(Archive *AH, PQExpBuffer outbuf,
    3782              :                    const char *dbname, Oid dboid)
    3783              : {
    3784          163 :     PGconn     *conn = GetConnection(AH);
    3785          163 :     PQExpBuffer buf = createPQExpBuffer();
    3786              :     PGresult   *res;
    3787              : 
    3788              :     /* First collect database-specific options */
    3789          163 :     printfPQExpBuffer(buf, "SELECT unnest(setconfig) FROM pg_db_role_setting "
    3790              :                       "WHERE setrole = 0 AND setdatabase = '%u'::oid",
    3791              :                       dboid);
    3792              : 
    3793          163 :     res = ExecuteSqlQuery(AH, buf->data, PGRES_TUPLES_OK);
    3794              : 
    3795          193 :     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          163 :     PQclear(res);
    3801              : 
    3802              :     /* Now look for role-and-database-specific options */
    3803          163 :     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          163 :     res = ExecuteSqlQuery(AH, buf->data, PGRES_TUPLES_OK);
    3809              : 
    3810          163 :     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          163 :     PQclear(res);
    3817              : 
    3818          163 :     destroyPQExpBuffer(buf);
    3819          163 : }
    3820              : 
    3821              : /*
    3822              :  * dumpEncoding: put the correct encoding into the archive
    3823              :  */
    3824              : static void
    3825          262 : dumpEncoding(Archive *AH)
    3826              : {
    3827          262 :     const char *encname = pg_encoding_to_char(AH->encoding);
    3828          262 :     PQExpBuffer qry = createPQExpBuffer();
    3829              : 
    3830          262 :     pg_log_info("saving encoding = %s", encname);
    3831              : 
    3832          262 :     appendPQExpBufferStr(qry, "SET client_encoding = ");
    3833          262 :     appendStringLiteralAH(qry, encname, AH);
    3834          262 :     appendPQExpBufferStr(qry, ";\n");
    3835              : 
    3836          262 :     ArchiveEntry(AH, nilCatalogId, createDumpId(),
    3837          262 :                  ARCHIVE_OPTS(.tag = "ENCODING",
    3838              :                               .description = "ENCODING",
    3839              :                               .section = SECTION_PRE_DATA,
    3840              :                               .createStmt = qry->data));
    3841              : 
    3842          262 :     destroyPQExpBuffer(qry);
    3843          262 : }
    3844              : 
    3845              : 
    3846              : /*
    3847              :  * dumpStdStrings: put the correct escape string behavior into the archive
    3848              :  */
    3849              : static void
    3850          262 : dumpStdStrings(Archive *AH)
    3851              : {
    3852          262 :     const char *stdstrings = AH->std_strings ? "on" : "off";
    3853          262 :     PQExpBuffer qry = createPQExpBuffer();
    3854              : 
    3855          262 :     pg_log_info("saving \"standard_conforming_strings = %s\"",
    3856              :                 stdstrings);
    3857              : 
    3858          262 :     appendPQExpBuffer(qry, "SET standard_conforming_strings = '%s';\n",
    3859              :                       stdstrings);
    3860              : 
    3861          262 :     ArchiveEntry(AH, nilCatalogId, createDumpId(),
    3862          262 :                  ARCHIVE_OPTS(.tag = "STDSTRINGS",
    3863              :                               .description = "STDSTRINGS",
    3864              :                               .section = SECTION_PRE_DATA,
    3865              :                               .createStmt = qry->data));
    3866              : 
    3867          262 :     destroyPQExpBuffer(qry);
    3868          262 : }
    3869              : 
    3870              : /*
    3871              :  * dumpSearchPath: record the active search_path in the archive
    3872              :  */
    3873              : static void
    3874          262 : dumpSearchPath(Archive *AH)
    3875              : {
    3876          262 :     PQExpBuffer qry = createPQExpBuffer();
    3877          262 :     PQExpBuffer path = createPQExpBuffer();
    3878              :     PGresult   *res;
    3879          262 :     char      **schemanames = NULL;
    3880          262 :     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          262 :     res = ExecuteSqlQueryForSingleRow(AH,
    3891              :                                       "SELECT pg_catalog.current_schemas(false)");
    3892              : 
    3893          262 :     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          262 :     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          262 :     appendPQExpBufferStr(qry, "SELECT pg_catalog.set_config('search_path', ");
    3910          262 :     appendStringLiteralAH(qry, path->data, AH);
    3911          262 :     appendPQExpBufferStr(qry, ", false);\n");
    3912              : 
    3913          262 :     pg_log_info("saving \"search_path = %s\"", path->data);
    3914              : 
    3915          262 :     ArchiveEntry(AH, nilCatalogId, createDumpId(),
    3916          262 :                  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          262 :     AH->searchpath = pg_strdup(qry->data);
    3923              : 
    3924          262 :     free(schemanames);
    3925          262 :     PQclear(res);
    3926          262 :     destroyPQExpBuffer(qry);
    3927          262 :     destroyPQExpBuffer(path);
    3928          262 : }
    3929              : 
    3930              : 
    3931              : /*
    3932              :  * getLOs:
    3933              :  *  Collect schema-level data about large objects
    3934              :  */
    3935              : static void
    3936          233 : getLOs(Archive *fout)
    3937              : {
    3938          233 :     DumpOptions *dopt = fout->dopt;
    3939          233 :     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          233 :     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          233 :     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          233 :     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          233 :     appendPQExpBufferStr(loQry,
    3976              :                          "ORDER BY lomowner, lomacl::pg_catalog.text, oid");
    3977              : 
    3978          233 :     res = ExecuteSqlQuery(fout, loQry->data, PGRES_TUPLES_OK);
    3979              : 
    3980          233 :     i_oid = PQfnumber(res, "oid");
    3981          233 :     i_lomowner = PQfnumber(res, "lomowner");
    3982          233 :     i_lomacl = PQfnumber(res, "lomacl");
    3983          233 :     i_acldefault = PQfnumber(res, "acldefault");
    3984              : 
    3985          233 :     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          321 :     for (i = 0; i < ntups; i += n)
    3996              :     {
    3997           88 :         Oid         thisoid = atooid(PQgetvalue(res, i, i_oid));
    3998           88 :         char       *thisowner = PQgetvalue(res, i, i_lomowner);
    3999           88 :         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           88 :         n = 1;
    4006          102 :         while (n < MAX_BLOBS_PER_ARCHIVE_ENTRY && i + n < ntups)
    4007              :         {
    4008           49 :             if (strcmp(thisowner, PQgetvalue(res, i + n, i_lomowner)) != 0 ||
    4009           49 :                 strcmp(thisacl, PQgetvalue(res, i + n, i_lomacl)) != 0)
    4010              :                 break;
    4011           14 :             n++;
    4012              :         }
    4013              : 
    4014              :         /* Build the metadata DumpableObject */
    4015           88 :         loinfo = (LoInfo *) pg_malloc(offsetof(LoInfo, looids) + n * sizeof(Oid));
    4016              : 
    4017           88 :         loinfo->dobj.objType = DO_LARGE_OBJECT;
    4018           88 :         loinfo->dobj.catId.tableoid = LargeObjectRelationId;
    4019           88 :         loinfo->dobj.catId.oid = thisoid;
    4020           88 :         AssignDumpId(&loinfo->dobj);
    4021              : 
    4022           88 :         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           78 :             snprintf(namebuf, sizeof(namebuf), "%u", thisoid);
    4027           88 :         loinfo->dobj.name = pg_strdup(namebuf);
    4028           88 :         loinfo->dacl.acl = pg_strdup(thisacl);
    4029           88 :         loinfo->dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
    4030           88 :         loinfo->dacl.privtype = 0;
    4031           88 :         loinfo->dacl.initprivs = NULL;
    4032           88 :         loinfo->rolname = getRoleName(thisowner);
    4033           88 :         loinfo->numlos = n;
    4034           88 :         loinfo->looids[0] = thisoid;
    4035              :         /* Collect OIDs of the remaining blobs in this group */
    4036          102 :         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           88 :         loinfo->dobj.components |= DUMP_COMPONENT_DATA;
    4050              : 
    4051              :         /* Mark whether LO group has a non-empty ACL */
    4052           88 :         if (!PQgetisnull(res, i, i_lomacl))
    4053           36 :             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           88 :         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           88 :         lodata = pg_malloc_object(DumpableObject);
    4069           88 :         lodata->objType = DO_LARGE_OBJECT_DATA;
    4070           88 :         lodata->catId = nilCatalogId;
    4071           88 :         AssignDumpId(lodata);
    4072           88 :         lodata->name = pg_strdup(namebuf);
    4073           88 :         lodata->components |= DUMP_COMPONENT_DATA;
    4074              :         /* Set up explicit dependency from data to metadata */
    4075           88 :         lodata->dependencies = pg_malloc_object(DumpId);
    4076           88 :         lodata->dependencies[0] = loinfo->dobj.dumpId;
    4077           88 :         lodata->nDeps = lodata->allocDeps = 1;
    4078              :     }
    4079              : 
    4080          233 :     PQclear(res);
    4081          233 :     destroyPQExpBuffer(loQry);
    4082          233 : }
    4083              : 
    4084              : /*
    4085              :  * dumpLO
    4086              :  *
    4087              :  * dump the definition (metadata) of the given large object group
    4088              :  */
    4089              : static void
    4090           88 : dumpLO(Archive *fout, const LoInfo *loinfo)
    4091              : {
    4092           88 :     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          190 :     for (int i = 0; i < loinfo->numlos; i++)
    4099          102 :         appendPQExpBuffer(cquery, "%u\n", loinfo->looids[i]);
    4100              : 
    4101           88 :     if (loinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
    4102           81 :         ArchiveEntry(fout, loinfo->dobj.catId, loinfo->dobj.dumpId,
    4103           81 :                      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           88 :     if (loinfo->dobj.dump & (DUMP_COMPONENT_COMMENT |
    4115              :                              DUMP_COMPONENT_SECLABEL))
    4116              :     {
    4117          106 :         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           60 :             catId.tableoid = loinfo->dobj.catId.tableoid;
    4124           60 :             catId.oid = loinfo->looids[i];
    4125           60 :             snprintf(namebuf, sizeof(namebuf), "%u", loinfo->looids[i]);
    4126              : 
    4127           60 :             if (loinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
    4128           60 :                 dumpComment(fout, "LARGE OBJECT", namebuf,
    4129           60 :                             NULL, loinfo->rolname,
    4130           60 :                             catId, 0, loinfo->dobj.dumpId);
    4131              : 
    4132           60 :             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           88 :     if (loinfo->dobj.dump & DUMP_COMPONENT_ACL)
    4147              :     {
    4148              :         char        namebuf[32];
    4149              : 
    4150              :         /* Build identifying info for the first blob */
    4151           35 :         snprintf(namebuf, sizeof(namebuf), "%u", loinfo->looids[0]);
    4152              : 
    4153           35 :         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           35 :             dumpACL(fout, loinfo->dobj.dumpId, InvalidDumpId,
    4167              :                     "LARGE OBJECT", namebuf, NULL, NULL,
    4168           35 :                     NULL, loinfo->rolname, &loinfo->dacl);
    4169              :         }
    4170              :     }
    4171              : 
    4172           88 :     destroyPQExpBuffer(cquery);
    4173           88 : }
    4174              : 
    4175              : /*
    4176              :  * dumpLOs:
    4177              :  *  dump the data contents of the large objects in the given group
    4178              :  */
    4179              : static int
    4180           77 : dumpLOs(Archive *fout, const void *arg)
    4181              : {
    4182           77 :     const LoInfo *loinfo = (const LoInfo *) arg;
    4183           77 :     PGconn     *conn = GetConnection(fout);
    4184              :     char        buf[LOBBUFSIZE];
    4185              : 
    4186           77 :     pg_log_info("saving large objects \"%s\"", loinfo->dobj.name);
    4187              : 
    4188          162 :     for (int i = 0; i < loinfo->numlos; i++)
    4189              :     {
    4190           85 :         Oid         loOid = loinfo->looids[i];
    4191              :         int         loFd;
    4192              :         int         cnt;
    4193              : 
    4194              :         /* Open the LO */
    4195           85 :         loFd = lo_open(conn, loOid, INV_READ);
    4196           85 :         if (loFd == -1)
    4197            0 :             pg_fatal("could not open large object %u: %s",
    4198              :                      loOid, PQerrorMessage(conn));
    4199              : 
    4200           85 :         StartLO(fout, loOid);
    4201              : 
    4202              :         /* Now read it in chunks, sending data to archive */
    4203              :         do
    4204              :         {
    4205          133 :             cnt = lo_read(conn, loFd, buf, LOBBUFSIZE);
    4206          133 :             if (cnt < 0)
    4207            0 :                 pg_fatal("error reading large object %u: %s",
    4208              :                          loOid, PQerrorMessage(conn));
    4209              : 
    4210          133 :             WriteData(fout, buf, cnt);
    4211          133 :         } while (cnt > 0);
    4212              : 
    4213           85 :         lo_close(conn, loFd);
    4214              : 
    4215           85 :         EndLO(fout, loOid);
    4216              :     }
    4217              : 
    4218           77 :     return 1;
    4219              : }
    4220              : 
    4221              : /*
    4222              :  * getPolicies
    4223              :  *    get information about all RLS policies on dumpable tables.
    4224              :  */
    4225              : void
    4226          262 : getPolicies(Archive *fout, TableInfo tblinfo[], int numTables)
    4227              : {
    4228          262 :     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          262 :     if (fout->remoteVersion < 90500)
    4248            0 :         return;
    4249              : 
    4250              :     /* Skip if --no-policies was specified */
    4251          262 :     if (dopt->no_policies)
    4252            1 :         return;
    4253              : 
    4254          261 :     query = createPQExpBuffer();
    4255          261 :     tbloids = createPQExpBuffer();
    4256              : 
    4257              :     /*
    4258              :      * Identify tables of interest, and check which ones have RLS enabled.
    4259              :      */
    4260          261 :     appendPQExpBufferChar(tbloids, '{');
    4261        71583 :     for (i = 0; i < numTables; i++)
    4262              :     {
    4263        71322 :         TableInfo  *tbinfo = &tblinfo[i];
    4264              : 
    4265              :         /* Ignore row security on tables not to be dumped */
    4266        71322 :         if (!(tbinfo->dobj.dump & DUMP_COMPONENT_POLICY))
    4267        63583 :             continue;
    4268              : 
    4269              :         /* It can't have RLS or policies if it's not a table */
    4270         7739 :         if (tbinfo->relkind != RELKIND_RELATION &&
    4271         2168 :             tbinfo->relkind != RELKIND_PARTITIONED_TABLE)
    4272         1541 :             continue;
    4273              : 
    4274              :         /* Add it to the list of table OIDs to be probed below */
    4275         6198 :         if (tbloids->len > 1) /* do we have more than the '{'? */
    4276         6020 :             appendPQExpBufferChar(tbloids, ',');
    4277         6198 :         appendPQExpBuffer(tbloids, "%u", tbinfo->dobj.catId.oid);
    4278              : 
    4279              :         /* Is RLS enabled?  (That's separate from whether it has policies) */
    4280         6198 :         if (tbinfo->rowsec)
    4281              :         {
    4282           66 :             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           66 :             polinfo = pg_malloc_object(PolicyInfo);
    4292           66 :             polinfo->dobj.objType = DO_POLICY;
    4293           66 :             polinfo->dobj.catId.tableoid = 0;
    4294           66 :             polinfo->dobj.catId.oid = tbinfo->dobj.catId.oid;
    4295           66 :             AssignDumpId(&polinfo->dobj);
    4296           66 :             polinfo->dobj.namespace = tbinfo->dobj.namespace;
    4297           66 :             polinfo->dobj.name = pg_strdup(tbinfo->dobj.name);
    4298           66 :             polinfo->poltable = tbinfo;
    4299           66 :             polinfo->polname = NULL;
    4300           66 :             polinfo->polcmd = '\0';
    4301           66 :             polinfo->polpermissive = 0;
    4302           66 :             polinfo->polroles = NULL;
    4303           66 :             polinfo->polqual = NULL;
    4304           66 :             polinfo->polwithcheck = NULL;
    4305              :         }
    4306              :     }
    4307          261 :     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          261 :     pg_log_info("reading row-level security policies");
    4316              : 
    4317          261 :     printfPQExpBuffer(query,
    4318              :                       "SELECT pol.oid, pol.tableoid, pol.polrelid, pol.polname, pol.polcmd, ");
    4319          261 :     if (fout->remoteVersion >= 100000)
    4320          261 :         appendPQExpBufferStr(query, "pol.polpermissive, ");
    4321              :     else
    4322            0 :         appendPQExpBufferStr(query, "'t' as polpermissive, ");
    4323          261 :     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          261 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    4333              : 
    4334          261 :     ntups = PQntuples(res);
    4335          261 :     if (ntups > 0)
    4336              :     {
    4337           46 :         i_oid = PQfnumber(res, "oid");
    4338           46 :         i_tableoid = PQfnumber(res, "tableoid");
    4339           46 :         i_polrelid = PQfnumber(res, "polrelid");
    4340           46 :         i_polname = PQfnumber(res, "polname");
    4341           46 :         i_polcmd = PQfnumber(res, "polcmd");
    4342           46 :         i_polpermissive = PQfnumber(res, "polpermissive");
    4343           46 :         i_polroles = PQfnumber(res, "polroles");
    4344           46 :         i_polqual = PQfnumber(res, "polqual");
    4345           46 :         i_polwithcheck = PQfnumber(res, "polwithcheck");
    4346              : 
    4347           46 :         polinfo = pg_malloc_array(PolicyInfo, ntups);
    4348              : 
    4349          337 :         for (j = 0; j < ntups; j++)
    4350              :         {
    4351          291 :             Oid         polrelid = atooid(PQgetvalue(res, j, i_polrelid));
    4352          291 :             TableInfo  *tbinfo = findTableByOid(polrelid);
    4353              : 
    4354          291 :             tbinfo->dobj.components |= DUMP_COMPONENT_POLICY;
    4355              : 
    4356          291 :             polinfo[j].dobj.objType = DO_POLICY;
    4357          291 :             polinfo[j].dobj.catId.tableoid =
    4358          291 :                 atooid(PQgetvalue(res, j, i_tableoid));
    4359          291 :             polinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
    4360          291 :             AssignDumpId(&polinfo[j].dobj);
    4361          291 :             polinfo[j].dobj.namespace = tbinfo->dobj.namespace;
    4362          291 :             polinfo[j].poltable = tbinfo;
    4363          291 :             polinfo[j].polname = pg_strdup(PQgetvalue(res, j, i_polname));
    4364          291 :             polinfo[j].dobj.name = pg_strdup(polinfo[j].polname);
    4365              : 
    4366          291 :             polinfo[j].polcmd = *(PQgetvalue(res, j, i_polcmd));
    4367          291 :             polinfo[j].polpermissive = *(PQgetvalue(res, j, i_polpermissive)) == 't';
    4368              : 
    4369          291 :             if (PQgetisnull(res, j, i_polroles))
    4370          127 :                 polinfo[j].polroles = NULL;
    4371              :             else
    4372          164 :                 polinfo[j].polroles = pg_strdup(PQgetvalue(res, j, i_polroles));
    4373              : 
    4374          291 :             if (PQgetisnull(res, j, i_polqual))
    4375           41 :                 polinfo[j].polqual = NULL;
    4376              :             else
    4377          250 :                 polinfo[j].polqual = pg_strdup(PQgetvalue(res, j, i_polqual));
    4378              : 
    4379          291 :             if (PQgetisnull(res, j, i_polwithcheck))
    4380          153 :                 polinfo[j].polwithcheck = NULL;
    4381              :             else
    4382          138 :                 polinfo[j].polwithcheck
    4383          138 :                     = pg_strdup(PQgetvalue(res, j, i_polwithcheck));
    4384              :         }
    4385              :     }
    4386              : 
    4387          261 :     PQclear(res);
    4388              : 
    4389          261 :     destroyPQExpBuffer(query);
    4390          261 :     destroyPQExpBuffer(tbloids);
    4391              : }
    4392              : 
    4393              : /*
    4394              :  * dumpPolicy
    4395              :  *    dump the definition of the given policy
    4396              :  */
    4397              : static void
    4398          357 : dumpPolicy(Archive *fout, const PolicyInfo *polinfo)
    4399              : {
    4400          357 :     DumpOptions *dopt = fout->dopt;
    4401          357 :     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          357 :     if (!dopt->dumpSchema)
    4411           56 :         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          301 :     if (polinfo->polname == NULL)
    4419              :     {
    4420           58 :         query = createPQExpBuffer();
    4421              : 
    4422           58 :         appendPQExpBuffer(query, "ALTER TABLE %s ENABLE ROW LEVEL SECURITY;",
    4423           58 :                           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           58 :         if (polinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
    4431           58 :             ArchiveEntry(fout, polinfo->dobj.catId, polinfo->dobj.dumpId,
    4432           58 :                          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           58 :         destroyPQExpBuffer(query);
    4442           58 :         return;
    4443              :     }
    4444              : 
    4445          243 :     if (polinfo->polcmd == '*')
    4446           81 :         cmd = "";
    4447          162 :     else if (polinfo->polcmd == 'r')
    4448           43 :         cmd = " FOR SELECT";
    4449          119 :     else if (polinfo->polcmd == 'a')
    4450           33 :         cmd = " FOR INSERT";
    4451           86 :     else if (polinfo->polcmd == 'w')
    4452           43 :         cmd = " FOR UPDATE";
    4453           43 :     else if (polinfo->polcmd == 'd')
    4454           43 :         cmd = " FOR DELETE";
    4455              :     else
    4456            0 :         pg_fatal("unexpected policy command type: %c",
    4457              :                  polinfo->polcmd);
    4458              : 
    4459          243 :     query = createPQExpBuffer();
    4460          243 :     delqry = createPQExpBuffer();
    4461          243 :     polprefix = createPQExpBuffer();
    4462              : 
    4463          243 :     qtabname = pg_strdup(fmtId(tbinfo->dobj.name));
    4464              : 
    4465          243 :     appendPQExpBuffer(query, "CREATE POLICY %s", fmtId(polinfo->polname));
    4466              : 
    4467          243 :     appendPQExpBuffer(query, " ON %s%s%s", fmtQualifiedDumpable(tbinfo),
    4468          243 :                       !polinfo->polpermissive ? " AS RESTRICTIVE" : "", cmd);
    4469              : 
    4470          243 :     if (polinfo->polroles != NULL)
    4471          132 :         appendPQExpBuffer(query, " TO %s", polinfo->polroles);
    4472              : 
    4473          243 :     if (polinfo->polqual != NULL)
    4474          210 :         appendPQExpBuffer(query, " USING (%s)", polinfo->polqual);
    4475              : 
    4476          243 :     if (polinfo->polwithcheck != NULL)
    4477          114 :         appendPQExpBuffer(query, " WITH CHECK (%s)", polinfo->polwithcheck);
    4478              : 
    4479          243 :     appendPQExpBufferStr(query, ";\n");
    4480              : 
    4481          243 :     appendPQExpBuffer(delqry, "DROP POLICY %s", fmtId(polinfo->polname));
    4482          243 :     appendPQExpBuffer(delqry, " ON %s;\n", fmtQualifiedDumpable(tbinfo));
    4483              : 
    4484          243 :     appendPQExpBuffer(polprefix, "POLICY %s ON",
    4485          243 :                       fmtId(polinfo->polname));
    4486              : 
    4487          243 :     tag = psprintf("%s %s", tbinfo->dobj.name, polinfo->dobj.name);
    4488              : 
    4489          243 :     if (polinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
    4490          243 :         ArchiveEntry(fout, polinfo->dobj.catId, polinfo->dobj.dumpId,
    4491          243 :                      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          243 :     if (polinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
    4500           33 :         dumpComment(fout, polprefix->data, qtabname,
    4501           33 :                     tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
    4502           33 :                     polinfo->dobj.catId, 0, polinfo->dobj.dumpId);
    4503              : 
    4504          243 :     free(tag);
    4505          243 :     destroyPQExpBuffer(query);
    4506          243 :     destroyPQExpBuffer(delqry);
    4507          243 :     destroyPQExpBuffer(polprefix);
    4508          243 :     free(qtabname);
    4509              : }
    4510              : 
    4511              : /*
    4512              :  * getPublications
    4513              :  *    get information about publications
    4514              :  */
    4515              : void
    4516          262 : getPublications(Archive *fout)
    4517              : {
    4518          262 :     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          262 :     if (dopt->no_publications || fout->remoteVersion < 100000)
    4538            0 :         return;
    4539              : 
    4540          262 :     query = createPQExpBuffer();
    4541              : 
    4542              :     /* Get the publications. */
    4543          262 :     appendPQExpBufferStr(query, "SELECT p.tableoid, p.oid, p.pubname, "
    4544              :                          "p.pubowner, p.puballtables, p.pubinsert, "
    4545              :                          "p.pubupdate, p.pubdelete, ");
    4546              : 
    4547          262 :     if (fout->remoteVersion >= 110000)
    4548          262 :         appendPQExpBufferStr(query, "p.pubtruncate, ");
    4549              :     else
    4550            0 :         appendPQExpBufferStr(query, "false AS pubtruncate, ");
    4551              : 
    4552          262 :     if (fout->remoteVersion >= 130000)
    4553          262 :         appendPQExpBufferStr(query, "p.pubviaroot, ");
    4554              :     else
    4555            0 :         appendPQExpBufferStr(query, "false AS pubviaroot, ");
    4556              : 
    4557          262 :     if (fout->remoteVersion >= 180000)
    4558          262 :         appendPQExpBufferStr(query, "p.pubgencols, ");
    4559              :     else
    4560            0 :         appendPQExpBuffer(query, "'%c' AS pubgencols, ", PUBLISH_GENCOLS_NONE);
    4561              : 
    4562          262 :     if (fout->remoteVersion >= 190000)
    4563          262 :         appendPQExpBufferStr(query, "p.puballsequences ");
    4564              :     else
    4565            0 :         appendPQExpBufferStr(query, "false AS puballsequences ");
    4566              : 
    4567          262 :     appendPQExpBufferStr(query, "FROM pg_publication p");
    4568              : 
    4569          262 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    4570              : 
    4571          262 :     ntups = PQntuples(res);
    4572              : 
    4573          262 :     if (ntups == 0)
    4574          206 :         goto cleanup;
    4575              : 
    4576           56 :     i_tableoid = PQfnumber(res, "tableoid");
    4577           56 :     i_oid = PQfnumber(res, "oid");
    4578           56 :     i_pubname = PQfnumber(res, "pubname");
    4579           56 :     i_pubowner = PQfnumber(res, "pubowner");
    4580           56 :     i_puballtables = PQfnumber(res, "puballtables");
    4581           56 :     i_puballsequences = PQfnumber(res, "puballsequences");
    4582           56 :     i_pubinsert = PQfnumber(res, "pubinsert");
    4583           56 :     i_pubupdate = PQfnumber(res, "pubupdate");
    4584           56 :     i_pubdelete = PQfnumber(res, "pubdelete");
    4585           56 :     i_pubtruncate = PQfnumber(res, "pubtruncate");
    4586           56 :     i_pubviaroot = PQfnumber(res, "pubviaroot");
    4587           56 :     i_pubgencols = PQfnumber(res, "pubgencols");
    4588              : 
    4589           56 :     pubinfo = pg_malloc_array(PublicationInfo, ntups);
    4590              : 
    4591          572 :     for (i = 0; i < ntups; i++)
    4592              :     {
    4593          516 :         pubinfo[i].dobj.objType = DO_PUBLICATION;
    4594          516 :         pubinfo[i].dobj.catId.tableoid =
    4595          516 :             atooid(PQgetvalue(res, i, i_tableoid));
    4596          516 :         pubinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    4597          516 :         AssignDumpId(&pubinfo[i].dobj);
    4598          516 :         pubinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_pubname));
    4599          516 :         pubinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_pubowner));
    4600          516 :         pubinfo[i].puballtables =
    4601          516 :             (strcmp(PQgetvalue(res, i, i_puballtables), "t") == 0);
    4602          516 :         pubinfo[i].puballsequences =
    4603          516 :             (strcmp(PQgetvalue(res, i, i_puballsequences), "t") == 0);
    4604          516 :         pubinfo[i].pubinsert =
    4605          516 :             (strcmp(PQgetvalue(res, i, i_pubinsert), "t") == 0);
    4606          516 :         pubinfo[i].pubupdate =
    4607          516 :             (strcmp(PQgetvalue(res, i, i_pubupdate), "t") == 0);
    4608          516 :         pubinfo[i].pubdelete =
    4609          516 :             (strcmp(PQgetvalue(res, i, i_pubdelete), "t") == 0);
    4610          516 :         pubinfo[i].pubtruncate =
    4611          516 :             (strcmp(PQgetvalue(res, i, i_pubtruncate), "t") == 0);
    4612          516 :         pubinfo[i].pubviaroot =
    4613          516 :             (strcmp(PQgetvalue(res, i, i_pubviaroot), "t") == 0);
    4614          516 :         pubinfo[i].pubgencols_type =
    4615          516 :             *(PQgetvalue(res, i, i_pubgencols));
    4616          516 :         pubinfo[i].except_tables = (SimplePtrList)
    4617              :         {
    4618              :             NULL, NULL
    4619              :         };
    4620              : 
    4621              :         /* Decide whether we want to dump it */
    4622          516 :         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          516 :         if (fout->remoteVersion >= 190000)
    4639              :         {
    4640              :             int         ntbls;
    4641              :             PGresult   *res_tbls;
    4642              : 
    4643          516 :             resetPQExpBuffer(query);
    4644          516 :             appendPQExpBuffer(query,
    4645              :                               "SELECT prrelid\n"
    4646              :                               "FROM pg_catalog.pg_publication_rel\n"
    4647              :                               "WHERE prpubid = %u AND prexcept",
    4648          516 :                               pubinfo[i].dobj.catId.oid);
    4649              : 
    4650          516 :             res_tbls = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    4651              : 
    4652          516 :             ntbls = PQntuples(res_tbls);
    4653              : 
    4654          756 :             for (int j = 0; j < ntbls; j++)
    4655              :             {
    4656              :                 Oid         prrelid;
    4657              :                 TableInfo  *tbinfo;
    4658              : 
    4659          240 :                 prrelid = atooid(PQgetvalue(res_tbls, j, 0));
    4660              : 
    4661          240 :                 tbinfo = findTableByOid(prrelid);
    4662              : 
    4663          240 :                 if (tbinfo != NULL)
    4664          240 :                     simple_ptr_list_append(&pubinfo[i].except_tables, tbinfo);
    4665              :             }
    4666              : 
    4667          516 :             PQclear(res_tbls);
    4668              :         }
    4669              :     }
    4670              : 
    4671           56 : cleanup:
    4672          262 :     PQclear(res);
    4673              : 
    4674          262 :     destroyPQExpBuffer(query);
    4675              : }
    4676              : 
    4677              : /*
    4678              :  * dumpPublication
    4679              :  *    dump the definition of the given publication
    4680              :  */
    4681              : static void
    4682          416 : dumpPublication(Archive *fout, const PublicationInfo *pubinfo)
    4683              : {
    4684          416 :     DumpOptions *dopt = fout->dopt;
    4685              :     PQExpBuffer delq;
    4686              :     PQExpBuffer query;
    4687              :     char       *qpubname;
    4688          416 :     bool        first = true;
    4689              : 
    4690              :     /* Do nothing if not dumping schema */
    4691          416 :     if (!dopt->dumpSchema)
    4692           60 :         return;
    4693              : 
    4694          356 :     delq = createPQExpBuffer();
    4695          356 :     query = createPQExpBuffer();
    4696              : 
    4697          356 :     qpubname = pg_strdup(fmtId(pubinfo->dobj.name));
    4698              : 
    4699          356 :     appendPQExpBuffer(delq, "DROP PUBLICATION %s;\n",
    4700              :                       qpubname);
    4701              : 
    4702          356 :     appendPQExpBuffer(query, "CREATE PUBLICATION %s",
    4703              :                       qpubname);
    4704              : 
    4705          356 :     if (pubinfo->puballtables)
    4706              :     {
    4707          166 :         int         n_except = 0;
    4708              : 
    4709          166 :         appendPQExpBufferStr(query, " FOR ALL TABLES");
    4710              : 
    4711              :         /* Include EXCEPT (TABLE) clause if there are except_tables. */
    4712          331 :         for (SimplePtrListCell *cell = pubinfo->except_tables.head; cell; cell = cell->next)
    4713              :         {
    4714          165 :             TableInfo  *tbinfo = (TableInfo *) cell->ptr;
    4715              : 
    4716          165 :             if (++n_except == 1)
    4717           99 :                 appendPQExpBufferStr(query, " EXCEPT (");
    4718              :             else
    4719           66 :                 appendPQExpBufferStr(query, ", ");
    4720          165 :             appendPQExpBuffer(query, "TABLE ONLY %s", fmtQualifiedDumpable(tbinfo));
    4721              :         }
    4722          166 :         if (n_except > 0)
    4723           99 :             appendPQExpBufferChar(query, ')');
    4724              : 
    4725          166 :         if (pubinfo->puballsequences)
    4726           33 :             appendPQExpBufferStr(query, ", ALL SEQUENCES");
    4727              :     }
    4728          190 :     else if (pubinfo->puballsequences)
    4729           33 :         appendPQExpBufferStr(query, " FOR ALL SEQUENCES");
    4730              : 
    4731          356 :     appendPQExpBufferStr(query, " WITH (publish = '");
    4732          356 :     if (pubinfo->pubinsert)
    4733              :     {
    4734          290 :         appendPQExpBufferStr(query, "insert");
    4735          290 :         first = false;
    4736              :     }
    4737              : 
    4738          356 :     if (pubinfo->pubupdate)
    4739              :     {
    4740          290 :         if (!first)
    4741          290 :             appendPQExpBufferStr(query, ", ");
    4742              : 
    4743          290 :         appendPQExpBufferStr(query, "update");
    4744          290 :         first = false;
    4745              :     }
    4746              : 
    4747          356 :     if (pubinfo->pubdelete)
    4748              :     {
    4749          290 :         if (!first)
    4750          290 :             appendPQExpBufferStr(query, ", ");
    4751              : 
    4752          290 :         appendPQExpBufferStr(query, "delete");
    4753          290 :         first = false;
    4754              :     }
    4755              : 
    4756          356 :     if (pubinfo->pubtruncate)
    4757              :     {
    4758          290 :         if (!first)
    4759          290 :             appendPQExpBufferStr(query, ", ");
    4760              : 
    4761          290 :         appendPQExpBufferStr(query, "truncate");
    4762          290 :         first = false;
    4763              :     }
    4764              : 
    4765          356 :     appendPQExpBufferChar(query, '\'');
    4766              : 
    4767          356 :     if (pubinfo->pubviaroot)
    4768            5 :         appendPQExpBufferStr(query, ", publish_via_partition_root = true");
    4769              : 
    4770          356 :     if (pubinfo->pubgencols_type == PUBLISH_GENCOLS_STORED)
    4771           33 :         appendPQExpBufferStr(query, ", publish_generated_columns = stored");
    4772              : 
    4773          356 :     appendPQExpBufferStr(query, ");\n");
    4774              : 
    4775          356 :     if (pubinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
    4776          356 :         ArchiveEntry(fout, pubinfo->dobj.catId, pubinfo->dobj.dumpId,
    4777          356 :                      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          356 :     if (pubinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
    4785           33 :         dumpComment(fout, "PUBLICATION", qpubname,
    4786           33 :                     NULL, pubinfo->rolname,
    4787           33 :                     pubinfo->dobj.catId, 0, pubinfo->dobj.dumpId);
    4788              : 
    4789          356 :     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          356 :     destroyPQExpBuffer(delq);
    4795          356 :     destroyPQExpBuffer(query);
    4796          356 :     free(qpubname);
    4797              : }
    4798              : 
    4799              : /*
    4800              :  * getPublicationNamespaces
    4801              :  *    get information about publication membership for dumpable schemas.
    4802              :  */
    4803              : void
    4804          262 : getPublicationNamespaces(Archive *fout)
    4805              : {
    4806              :     PQExpBuffer query;
    4807              :     PGresult   *res;
    4808              :     PublicationSchemaInfo *pubsinfo;
    4809          262 :     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          262 :     if (dopt->no_publications || fout->remoteVersion < 150000)
    4819            0 :         return;
    4820              : 
    4821          262 :     query = createPQExpBuffer();
    4822              : 
    4823              :     /* Collect all publication membership info. */
    4824          262 :     appendPQExpBufferStr(query,
    4825              :                          "SELECT tableoid, oid, pnpubid, pnnspid "
    4826              :                          "FROM pg_catalog.pg_publication_namespace");
    4827          262 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    4828              : 
    4829          262 :     ntups = PQntuples(res);
    4830              : 
    4831          262 :     i_tableoid = PQfnumber(res, "tableoid");
    4832          262 :     i_oid = PQfnumber(res, "oid");
    4833          262 :     i_pnpubid = PQfnumber(res, "pnpubid");
    4834          262 :     i_pnnspid = PQfnumber(res, "pnnspid");
    4835              : 
    4836              :     /* this allocation may be more than we need */
    4837          262 :     pubsinfo = pg_malloc_array(PublicationSchemaInfo, ntups);
    4838          262 :     j = 0;
    4839              : 
    4840          393 :     for (i = 0; i < ntups; i++)
    4841              :     {
    4842          131 :         Oid         pnpubid = atooid(PQgetvalue(res, i, i_pnpubid));
    4843          131 :         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          131 :         pubinfo = findPublicationByOid(pnpubid);
    4852          131 :         if (pubinfo == NULL)
    4853            0 :             continue;
    4854          131 :         nspinfo = findNamespaceByOid(pnnspid);
    4855          131 :         if (nspinfo == NULL)
    4856            0 :             continue;
    4857              : 
    4858              :         /* OK, make a DumpableObject for this relationship */
    4859          131 :         pubsinfo[j].dobj.objType = DO_PUBLICATION_TABLE_IN_SCHEMA;
    4860          131 :         pubsinfo[j].dobj.catId.tableoid =
    4861          131 :             atooid(PQgetvalue(res, i, i_tableoid));
    4862          131 :         pubsinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    4863          131 :         AssignDumpId(&pubsinfo[j].dobj);
    4864          131 :         pubsinfo[j].dobj.namespace = nspinfo->dobj.namespace;
    4865          131 :         pubsinfo[j].dobj.name = nspinfo->dobj.name;
    4866          131 :         pubsinfo[j].publication = pubinfo;
    4867          131 :         pubsinfo[j].pubschema = nspinfo;
    4868              : 
    4869              :         /* Decide whether we want to dump it */
    4870          131 :         selectDumpablePublicationObject(&(pubsinfo[j].dobj), fout);
    4871              : 
    4872          131 :         j++;
    4873              :     }
    4874              : 
    4875          262 :     PQclear(res);
    4876          262 :     destroyPQExpBuffer(query);
    4877              : }
    4878              : 
    4879              : /*
    4880              :  * getPublicationTables
    4881              :  *    get information about publication membership for dumpable tables.
    4882              :  */
    4883              : void
    4884          262 : getPublicationTables(Archive *fout, TableInfo tblinfo[], int numTables)
    4885              : {
    4886              :     PQExpBuffer query;
    4887              :     PGresult   *res;
    4888              :     PublicationRelInfo *pubrinfo;
    4889          262 :     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          262 :     if (dopt->no_publications || fout->remoteVersion < 100000)
    4901            0 :         return;
    4902              : 
    4903          262 :     query = createPQExpBuffer();
    4904              : 
    4905              :     /* Collect all publication membership info. */
    4906          262 :     if (fout->remoteVersion >= 150000)
    4907              :     {
    4908          262 :         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          262 :         if (fout->remoteVersion >= 190000)
    4921          262 :             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          262 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    4929              : 
    4930          262 :     ntups = PQntuples(res);
    4931              : 
    4932          262 :     i_tableoid = PQfnumber(res, "tableoid");
    4933          262 :     i_oid = PQfnumber(res, "oid");
    4934          262 :     i_prpubid = PQfnumber(res, "prpubid");
    4935          262 :     i_prrelid = PQfnumber(res, "prrelid");
    4936          262 :     i_prrelqual = PQfnumber(res, "prrelqual");
    4937          262 :     i_prattrs = PQfnumber(res, "prattrs");
    4938              : 
    4939              :     /* this allocation may be more than we need */
    4940          262 :     pubrinfo = pg_malloc_array(PublicationRelInfo, ntups);
    4941          262 :     j = 0;
    4942              : 
    4943          633 :     for (i = 0; i < ntups; i++)
    4944              :     {
    4945          371 :         Oid         prpubid = atooid(PQgetvalue(res, i, i_prpubid));
    4946          371 :         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          371 :         pubinfo = findPublicationByOid(prpubid);
    4955          371 :         if (pubinfo == NULL)
    4956            0 :             continue;
    4957          371 :         tbinfo = findTableByOid(prrelid);
    4958          371 :         if (tbinfo == NULL)
    4959            0 :             continue;
    4960              : 
    4961              :         /* OK, make a DumpableObject for this relationship */
    4962          371 :         pubrinfo[j].dobj.objType = DO_PUBLICATION_REL;
    4963          371 :         pubrinfo[j].dobj.catId.tableoid =
    4964          371 :             atooid(PQgetvalue(res, i, i_tableoid));
    4965          371 :         pubrinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    4966          371 :         AssignDumpId(&pubrinfo[j].dobj);
    4967          371 :         pubrinfo[j].dobj.namespace = tbinfo->dobj.namespace;
    4968          371 :         pubrinfo[j].dobj.name = tbinfo->dobj.name;
    4969          371 :         pubrinfo[j].publication = pubinfo;
    4970          371 :         pubrinfo[j].pubtable = tbinfo;
    4971          371 :         if (PQgetisnull(res, i, i_prrelqual))
    4972          206 :             pubrinfo[j].pubrelqual = NULL;
    4973              :         else
    4974          165 :             pubrinfo[j].pubrelqual = pg_strdup(PQgetvalue(res, i, i_prrelqual));
    4975              : 
    4976          371 :         if (!PQgetisnull(res, i, i_prattrs))
    4977              :         {
    4978              :             char      **attnames;
    4979              :             int         nattnames;
    4980              :             PQExpBuffer attribs;
    4981              : 
    4982          117 :             if (!parsePGArray(PQgetvalue(res, i, i_prattrs),
    4983              :                               &attnames, &nattnames))
    4984            0 :                 pg_fatal("could not parse %s array", "prattrs");
    4985          117 :             attribs = createPQExpBuffer();
    4986          337 :             for (int k = 0; k < nattnames; k++)
    4987              :             {
    4988          220 :                 if (k > 0)
    4989          103 :                     appendPQExpBufferStr(attribs, ", ");
    4990              : 
    4991          220 :                 appendPQExpBufferStr(attribs, fmtId(attnames[k]));
    4992              :             }
    4993          117 :             pubrinfo[j].pubrattrs = attribs->data;
    4994          117 :             free(attribs);      /* but not attribs->data */
    4995          117 :             free(attnames);
    4996              :         }
    4997              :         else
    4998          254 :             pubrinfo[j].pubrattrs = NULL;
    4999              : 
    5000              :         /* Decide whether we want to dump it */
    5001          371 :         selectDumpablePublicationObject(&(pubrinfo[j].dobj), fout);
    5002              : 
    5003          371 :         j++;
    5004              :     }
    5005              : 
    5006          262 :     PQclear(res);
    5007          262 :     destroyPQExpBuffer(query);
    5008              : }
    5009              : 
    5010              : /*
    5011              :  * dumpPublicationNamespace
    5012              :  *    dump the definition of the given publication schema mapping.
    5013              :  */
    5014              : static void
    5015          103 : dumpPublicationNamespace(Archive *fout, const PublicationSchemaInfo *pubsinfo)
    5016              : {
    5017          103 :     DumpOptions *dopt = fout->dopt;
    5018          103 :     NamespaceInfo *schemainfo = pubsinfo->pubschema;
    5019          103 :     PublicationInfo *pubinfo = pubsinfo->publication;
    5020              :     PQExpBuffer query;
    5021              :     char       *tag;
    5022              : 
    5023              :     /* Do nothing if not dumping schema */
    5024          103 :     if (!dopt->dumpSchema)
    5025           12 :         return;
    5026              : 
    5027           91 :     tag = psprintf("%s %s", pubinfo->dobj.name, schemainfo->dobj.name);
    5028              : 
    5029           91 :     query = createPQExpBuffer();
    5030              : 
    5031           91 :     appendPQExpBuffer(query, "ALTER PUBLICATION %s ", fmtId(pubinfo->dobj.name));
    5032           91 :     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           91 :     if (pubsinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
    5039           91 :         ArchiveEntry(fout, pubsinfo->dobj.catId, pubsinfo->dobj.dumpId,
    5040           91 :                      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           91 :     free(tag);
    5050           91 :     destroyPQExpBuffer(query);
    5051              : }
    5052              : 
    5053              : /*
    5054              :  * dumpPublicationTable
    5055              :  *    dump the definition of the given publication table mapping
    5056              :  */
    5057              : static void
    5058          298 : dumpPublicationTable(Archive *fout, const PublicationRelInfo *pubrinfo)
    5059              : {
    5060          298 :     DumpOptions *dopt = fout->dopt;
    5061          298 :     PublicationInfo *pubinfo = pubrinfo->publication;
    5062          298 :     TableInfo  *tbinfo = pubrinfo->pubtable;
    5063              :     PQExpBuffer query;
    5064              :     char       *tag;
    5065              : 
    5066              :     /* Do nothing if not dumping schema */
    5067          298 :     if (!dopt->dumpSchema)
    5068           42 :         return;
    5069              : 
    5070          256 :     tag = psprintf("%s %s", pubinfo->dobj.name, tbinfo->dobj.name);
    5071              : 
    5072          256 :     query = createPQExpBuffer();
    5073              : 
    5074          256 :     appendPQExpBuffer(query, "ALTER PUBLICATION %s ADD TABLE ONLY",
    5075          256 :                       fmtId(pubinfo->dobj.name));
    5076          256 :     appendPQExpBuffer(query, " %s",
    5077          256 :                       fmtQualifiedDumpable(tbinfo));
    5078              : 
    5079          256 :     if (pubrinfo->pubrattrs)
    5080           81 :         appendPQExpBuffer(query, " (%s)", pubrinfo->pubrattrs);
    5081              : 
    5082          256 :     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          114 :         appendPQExpBuffer(query, " WHERE (%s)", pubrinfo->pubrelqual);
    5090              :     }
    5091          256 :     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          256 :     if (pubrinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
    5101          256 :         ArchiveEntry(fout, pubrinfo->dobj.catId, pubrinfo->dobj.dumpId,
    5102          256 :                      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          256 :     free(tag);
    5112          256 :     destroyPQExpBuffer(query);
    5113              : }
    5114              : 
    5115              : /*
    5116              :  * Is the currently connected user a superuser?
    5117              :  */
    5118              : static bool
    5119          261 : is_superuser(Archive *fout)
    5120              : {
    5121          261 :     ArchiveHandle *AH = (ArchiveHandle *) fout;
    5122              :     const char *val;
    5123              : 
    5124          261 :     val = PQparameterStatus(AH->connection, "is_superuser");
    5125              : 
    5126          261 :     if (val && strcmp(val, "on") == 0)
    5127          258 :         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          296 : set_restrict_relation_kind(Archive *AH, const char *value)
    5139              : {
    5140          296 :     PQExpBuffer query = createPQExpBuffer();
    5141              :     PGresult   *res;
    5142              : 
    5143          296 :     appendPQExpBuffer(query,
    5144              :                       "SELECT set_config(name, '%s', false) "
    5145              :                       "FROM pg_settings "
    5146              :                       "WHERE name = 'restrict_nonsystem_relation_kind'",
    5147              :                       value);
    5148          296 :     res = ExecuteSqlQuery(AH, query->data, PGRES_TUPLES_OK);
    5149              : 
    5150          296 :     PQclear(res);
    5151          296 :     destroyPQExpBuffer(query);
    5152          296 : }
    5153              : 
    5154              : /*
    5155              :  * getSubscriptions
    5156              :  *    get information about subscriptions
    5157              :  */
    5158              : void
    5159          262 : getSubscriptions(Archive *fout)
    5160              : {
    5161          262 :     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          262 :     if (dopt->no_subscriptions || fout->remoteVersion < 100000)
    5191            1 :         return;
    5192              : 
    5193          261 :     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          258 :     query = createPQExpBuffer();
    5210              : 
    5211              :     /* Get the subscriptions in current database. */
    5212          258 :     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          258 :     if (fout->remoteVersion >= 140000)
    5219          258 :         appendPQExpBufferStr(query, " s.subbinary,\n");
    5220              :     else
    5221            0 :         appendPQExpBufferStr(query, " false AS subbinary,\n");
    5222              : 
    5223          258 :     if (fout->remoteVersion >= 140000)
    5224          258 :         appendPQExpBufferStr(query, " s.substream,\n");
    5225              :     else
    5226            0 :         appendPQExpBufferStr(query, " 'f' AS substream,\n");
    5227              : 
    5228          258 :     if (fout->remoteVersion >= 150000)
    5229          258 :         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          258 :     if (fout->remoteVersion >= 160000)
    5239          258 :         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          258 :     if (dopt->binary_upgrade && fout->remoteVersion >= 170000)
    5251           40 :         appendPQExpBufferStr(query, " o.remote_lsn AS suboriginremotelsn,\n"
    5252              :                              " s.subenabled,\n");
    5253              :     else
    5254          218 :         appendPQExpBufferStr(query, " NULL AS suboriginremotelsn,\n"
    5255              :                              " false AS subenabled,\n");
    5256              : 
    5257          258 :     if (fout->remoteVersion >= 170000)
    5258          258 :         appendPQExpBufferStr(query,
    5259              :                              " s.subfailover,\n");
    5260              :     else
    5261            0 :         appendPQExpBufferStr(query,
    5262              :                              " false AS subfailover,\n");
    5263              : 
    5264          258 :     if (fout->remoteVersion >= 190000)
    5265          258 :         appendPQExpBufferStr(query,
    5266              :                              " s.subretaindeadtuples,\n");
    5267              :     else
    5268            0 :         appendPQExpBufferStr(query,
    5269              :                              " false AS subretaindeadtuples,\n");
    5270              : 
    5271          258 :     if (fout->remoteVersion >= 190000)
    5272          258 :         appendPQExpBufferStr(query,
    5273              :                              " s.submaxretention,\n");
    5274              :     else
    5275            0 :         appendPQExpBufferStr(query, " 0 AS submaxretention,\n");
    5276              : 
    5277          258 :     if (fout->remoteVersion >= 190000)
    5278          258 :         appendPQExpBufferStr(query,
    5279              :                              " s.subwalrcvtimeout,\n");
    5280              :     else
    5281            0 :         appendPQExpBufferStr(query,
    5282              :                              " '-1' AS subwalrcvtimeout,\n");
    5283              : 
    5284          258 :     if (fout->remoteVersion >= 190000)
    5285          258 :         appendPQExpBufferStr(query, " fs.srvname AS subservername\n");
    5286              :     else
    5287            0 :         appendPQExpBufferStr(query, " NULL AS subservername\n");
    5288              : 
    5289          258 :     appendPQExpBufferStr(query,
    5290              :                          "FROM pg_subscription s\n");
    5291              : 
    5292          258 :     if (fout->remoteVersion >= 190000)
    5293          258 :         appendPQExpBufferStr(query,
    5294              :                              "LEFT JOIN pg_catalog.pg_foreign_server fs \n"
    5295              :                              "    ON fs.oid = s.subserver \n");
    5296              : 
    5297          258 :     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          258 :     appendPQExpBufferStr(query,
    5303              :                          "WHERE s.subdbid = (SELECT oid FROM pg_database\n"
    5304              :                          "                   WHERE datname = current_database())");
    5305              : 
    5306          258 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    5307              : 
    5308          258 :     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          258 :     i_tableoid = PQfnumber(res, "tableoid");
    5315          258 :     i_oid = PQfnumber(res, "oid");
    5316          258 :     i_subname = PQfnumber(res, "subname");
    5317          258 :     i_subowner = PQfnumber(res, "subowner");
    5318          258 :     i_subenabled = PQfnumber(res, "subenabled");
    5319          258 :     i_subbinary = PQfnumber(res, "subbinary");
    5320          258 :     i_substream = PQfnumber(res, "substream");
    5321          258 :     i_subtwophasestate = PQfnumber(res, "subtwophasestate");
    5322          258 :     i_subdisableonerr = PQfnumber(res, "subdisableonerr");
    5323          258 :     i_subpasswordrequired = PQfnumber(res, "subpasswordrequired");
    5324          258 :     i_subrunasowner = PQfnumber(res, "subrunasowner");
    5325          258 :     i_subfailover = PQfnumber(res, "subfailover");
    5326          258 :     i_subretaindeadtuples = PQfnumber(res, "subretaindeadtuples");
    5327          258 :     i_submaxretention = PQfnumber(res, "submaxretention");
    5328          258 :     i_subservername = PQfnumber(res, "subservername");
    5329          258 :     i_subconninfo = PQfnumber(res, "subconninfo");
    5330          258 :     i_subslotname = PQfnumber(res, "subslotname");
    5331          258 :     i_subsynccommit = PQfnumber(res, "subsynccommit");
    5332          258 :     i_subwalrcvtimeout = PQfnumber(res, "subwalrcvtimeout");
    5333          258 :     i_subpublications = PQfnumber(res, "subpublications");
    5334          258 :     i_suborigin = PQfnumber(res, "suborigin");
    5335          258 :     i_suboriginremotelsn = PQfnumber(res, "suboriginremotelsn");
    5336              : 
    5337          258 :     subinfo = pg_malloc_array(SubscriptionInfo, ntups);
    5338              : 
    5339          395 :     for (i = 0; i < ntups; i++)
    5340              :     {
    5341          137 :         subinfo[i].dobj.objType = DO_SUBSCRIPTION;
    5342          137 :         subinfo[i].dobj.catId.tableoid =
    5343          137 :             atooid(PQgetvalue(res, i, i_tableoid));
    5344          137 :         subinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    5345          137 :         AssignDumpId(&subinfo[i].dobj);
    5346          137 :         subinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_subname));
    5347          137 :         subinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_subowner));
    5348              : 
    5349          137 :         subinfo[i].subenabled =
    5350          137 :             (strcmp(PQgetvalue(res, i, i_subenabled), "t") == 0);
    5351          137 :         if (PQgetisnull(res, i, i_subservername))
    5352          137 :             subinfo[i].subservername = NULL;
    5353              :         else
    5354            0 :             subinfo[i].subservername = pg_strdup(PQgetvalue(res, i, i_subservername));
    5355          137 :         subinfo[i].subbinary =
    5356          137 :             (strcmp(PQgetvalue(res, i, i_subbinary), "t") == 0);
    5357          137 :         subinfo[i].substream = *(PQgetvalue(res, i, i_substream));
    5358          137 :         subinfo[i].subtwophasestate = *(PQgetvalue(res, i, i_subtwophasestate));
    5359          137 :         subinfo[i].subdisableonerr =
    5360          137 :             (strcmp(PQgetvalue(res, i, i_subdisableonerr), "t") == 0);
    5361          137 :         subinfo[i].subpasswordrequired =
    5362          137 :             (strcmp(PQgetvalue(res, i, i_subpasswordrequired), "t") == 0);
    5363          137 :         subinfo[i].subrunasowner =
    5364          137 :             (strcmp(PQgetvalue(res, i, i_subrunasowner), "t") == 0);
    5365          137 :         subinfo[i].subfailover =
    5366          137 :             (strcmp(PQgetvalue(res, i, i_subfailover), "t") == 0);
    5367          137 :         subinfo[i].subretaindeadtuples =
    5368          137 :             (strcmp(PQgetvalue(res, i, i_subretaindeadtuples), "t") == 0);
    5369          137 :         subinfo[i].submaxretention =
    5370          137 :             atoi(PQgetvalue(res, i, i_submaxretention));
    5371          137 :         if (PQgetisnull(res, i, i_subconninfo))
    5372            0 :             subinfo[i].subconninfo = NULL;
    5373              :         else
    5374          137 :             subinfo[i].subconninfo =
    5375          137 :                 pg_strdup(PQgetvalue(res, i, i_subconninfo));
    5376          137 :         if (PQgetisnull(res, i, i_subslotname))
    5377            0 :             subinfo[i].subslotname = NULL;
    5378              :         else
    5379          137 :             subinfo[i].subslotname =
    5380          137 :                 pg_strdup(PQgetvalue(res, i, i_subslotname));
    5381          274 :         subinfo[i].subsynccommit =
    5382          137 :             pg_strdup(PQgetvalue(res, i, i_subsynccommit));
    5383          274 :         subinfo[i].subwalrcvtimeout =
    5384          137 :             pg_strdup(PQgetvalue(res, i, i_subwalrcvtimeout));
    5385          274 :         subinfo[i].subpublications =
    5386          137 :             pg_strdup(PQgetvalue(res, i, i_subpublications));
    5387          137 :         subinfo[i].suborigin = pg_strdup(PQgetvalue(res, i, i_suborigin));
    5388          137 :         if (PQgetisnull(res, i, i_suboriginremotelsn))
    5389          136 :             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          137 :         selectDumpableObject(&(subinfo[i].dobj), fout);
    5396              :     }
    5397          258 :     PQclear(res);
    5398              : 
    5399          258 :     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          262 : getSubscriptionRelations(Archive *fout)
    5409              : {
    5410          262 :     DumpOptions *dopt = fout->dopt;
    5411          262 :     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          262 :     Oid         last_srsubid = InvalidOid;
    5420              : 
    5421          262 :     if (dopt->no_subscriptions || !dopt->binary_upgrade ||
    5422           40 :         fout->remoteVersion < 170000)
    5423          222 :         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          116 : dumpSubscription(Archive *fout, const SubscriptionInfo *subinfo)
    5564              : {
    5565          116 :     DumpOptions *dopt = fout->dopt;
    5566              :     PQExpBuffer delq;
    5567              :     PQExpBuffer query;
    5568              :     PQExpBuffer publications;
    5569              :     char       *qsubname;
    5570          116 :     char      **pubnames = NULL;
    5571          116 :     int         npubnames = 0;
    5572              :     int         i;
    5573              : 
    5574              :     /* Do nothing if not dumping schema */
    5575          116 :     if (!dopt->dumpSchema)
    5576           18 :         return;
    5577              : 
    5578           98 :     delq = createPQExpBuffer();
    5579           98 :     query = createPQExpBuffer();
    5580              : 
    5581           98 :     qsubname = pg_strdup(fmtId(subinfo->dobj.name));
    5582              : 
    5583           98 :     appendPQExpBuffer(delq, "DROP SUBSCRIPTION %s;\n",
    5584              :                       qsubname);
    5585              : 
    5586           98 :     appendPQExpBuffer(query, "CREATE SUBSCRIPTION %s ",
    5587              :                       qsubname);
    5588           98 :     if (subinfo->subservername)
    5589              :     {
    5590            0 :         appendPQExpBuffer(query, "SERVER %s", fmtId(subinfo->subservername));
    5591              :     }
    5592              :     else
    5593              :     {
    5594           98 :         appendPQExpBufferStr(query, "CONNECTION ");
    5595           98 :         appendStringLiteralAH(query, subinfo->subconninfo, fout);
    5596              :     }
    5597              : 
    5598              :     /* Build list of quoted publications and append them to query. */
    5599           98 :     if (!parsePGArray(subinfo->subpublications, &pubnames, &npubnames))
    5600            0 :         pg_fatal("could not parse %s array", "subpublications");
    5601              : 
    5602           98 :     publications = createPQExpBuffer();
    5603          196 :     for (i = 0; i < npubnames; i++)
    5604              :     {
    5605           98 :         if (i > 0)
    5606            0 :             appendPQExpBufferStr(publications, ", ");
    5607              : 
    5608           98 :         appendPQExpBufferStr(publications, fmtId(pubnames[i]));
    5609              :     }
    5610              : 
    5611           98 :     appendPQExpBuffer(query, " PUBLICATION %s WITH (connect = false, slot_name = ", publications->data);
    5612           98 :     if (subinfo->subslotname)
    5613           98 :         appendStringLiteralAH(query, subinfo->subslotname, fout);
    5614              :     else
    5615            0 :         appendPQExpBufferStr(query, "NONE");
    5616              : 
    5617           98 :     if (subinfo->subbinary)
    5618            0 :         appendPQExpBufferStr(query, ", binary = true");
    5619              : 
    5620           98 :     if (subinfo->substream == LOGICALREP_STREAM_ON)
    5621           32 :         appendPQExpBufferStr(query, ", streaming = on");
    5622           66 :     else if (subinfo->substream == LOGICALREP_STREAM_PARALLEL)
    5623           34 :         appendPQExpBufferStr(query, ", streaming = parallel");
    5624              :     else
    5625           32 :         appendPQExpBufferStr(query, ", streaming = off");
    5626              : 
    5627           98 :     if (subinfo->subtwophasestate != LOGICALREP_TWOPHASE_STATE_DISABLED)
    5628            0 :         appendPQExpBufferStr(query, ", two_phase = on");
    5629              : 
    5630           98 :     if (subinfo->subdisableonerr)
    5631            0 :         appendPQExpBufferStr(query, ", disable_on_error = true");
    5632              : 
    5633           98 :     if (!subinfo->subpasswordrequired)
    5634            0 :         appendPQExpBufferStr(query, ", password_required = false");
    5635              : 
    5636           98 :     if (subinfo->subrunasowner)
    5637            0 :         appendPQExpBufferStr(query, ", run_as_owner = true");
    5638              : 
    5639           98 :     if (subinfo->subfailover)
    5640            1 :         appendPQExpBufferStr(query, ", failover = true");
    5641              : 
    5642           98 :     if (subinfo->subretaindeadtuples)
    5643            1 :         appendPQExpBufferStr(query, ", retain_dead_tuples = true");
    5644              : 
    5645           98 :     if (subinfo->submaxretention)
    5646            0 :         appendPQExpBuffer(query, ", max_retention_duration = %d", subinfo->submaxretention);
    5647              : 
    5648           98 :     if (strcmp(subinfo->subsynccommit, "off") != 0)
    5649            0 :         appendPQExpBuffer(query, ", synchronous_commit = %s", fmtId(subinfo->subsynccommit));
    5650              : 
    5651           98 :     if (strcmp(subinfo->subwalrcvtimeout, "-1") != 0)
    5652            0 :         appendPQExpBuffer(query, ", wal_receiver_timeout = %s", fmtId(subinfo->subwalrcvtimeout));
    5653              : 
    5654           98 :     if (pg_strcasecmp(subinfo->suborigin, LOGICALREP_ORIGIN_ANY) != 0)
    5655           32 :         appendPQExpBuffer(query, ", origin = %s", subinfo->suborigin);
    5656              : 
    5657           98 :     appendPQExpBufferStr(query, ");\n");
    5658              : 
    5659              :     /*
    5660              :      * In binary-upgrade mode, we allow the replication to continue after the
    5661              :      * upgrade.
    5662              :      */
    5663           98 :     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           98 :     if (subinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
    5697           98 :         ArchiveEntry(fout, subinfo->dobj.catId, subinfo->dobj.dumpId,
    5698           98 :                      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           98 :     if (subinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
    5706           32 :         dumpComment(fout, "SUBSCRIPTION", qsubname,
    5707           32 :                     NULL, subinfo->rolname,
    5708           32 :                     subinfo->dobj.catId, 0, subinfo->dobj.dumpId);
    5709              : 
    5710           98 :     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           98 :     destroyPQExpBuffer(publications);
    5716           98 :     free(pubnames);
    5717              : 
    5718           98 :     destroyPQExpBuffer(delq);
    5719           98 :     destroyPQExpBuffer(query);
    5720           98 :     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         5400 : 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         5400 :     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         5400 : }
    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         1015 : 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         1015 :     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         1015 :     appendPQExpBufferStr(upgrade_buffer, "\n-- For binary upgrade, must preserve pg_type oid\n");
    5818         1015 :     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         1015 :     tinfo = findTypeByOid(pg_type_oid);
    5823         1015 :     if (tinfo)
    5824         1015 :         pg_type_array_oid = tinfo->typarray;
    5825              :     else
    5826            0 :         pg_type_array_oid = InvalidOid;
    5827              : 
    5828         1015 :     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         1015 :     if (OidIsValid(pg_type_array_oid))
    5832              :     {
    5833         1013 :         appendPQExpBufferStr(upgrade_buffer,
    5834              :                              "\n-- For binary upgrade, must preserve pg_type array oid\n");
    5835         1013 :         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         1015 :     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         1015 :     destroyPQExpBuffer(upgrade_query);
    5881         1015 : }
    5882              : 
    5883              : static void
    5884          949 : binary_upgrade_set_type_oids_by_rel(Archive *fout,
    5885              :                                     PQExpBuffer upgrade_buffer,
    5886              :                                     const TableInfo *tbinfo)
    5887              : {
    5888          949 :     Oid         pg_type_oid = tbinfo->reltype;
    5889              : 
    5890          949 :     if (OidIsValid(pg_type_oid))
    5891          935 :         binary_upgrade_set_type_oids_by_type_oid(fout, upgrade_buffer,
    5892              :                                                  pg_type_oid, false, false);
    5893          949 : }
    5894              : 
    5895              : /*
    5896              :  * bsearch() comparator for BinaryUpgradeClassOidItem
    5897              :  */
    5898              : static int
    5899        13733 : BinaryUpgradeClassOidItemCmp(const void *p1, const void *p2)
    5900              : {
    5901        13733 :     BinaryUpgradeClassOidItem v1 = *((const BinaryUpgradeClassOidItem *) p1);
    5902        13733 :     BinaryUpgradeClassOidItem v2 = *((const BinaryUpgradeClassOidItem *) p2);
    5903              : 
    5904        13733 :     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        20080 :     for (int i = 0; i < nbinaryUpgradeClassOids; i++)
    5935              :     {
    5936        20040 :         binaryUpgradeClassOids[i].oid = atooid(PQgetvalue(res, i, 0));
    5937        20040 :         binaryUpgradeClassOids[i].relkind = *PQgetvalue(res, i, 1);
    5938        20040 :         binaryUpgradeClassOids[i].relfilenumber = atooid(PQgetvalue(res, i, 2));
    5939        20040 :         binaryUpgradeClassOids[i].toast_oid = atooid(PQgetvalue(res, i, 3));
    5940        20040 :         binaryUpgradeClassOids[i].toast_relfilenumber = atooid(PQgetvalue(res, i, 4));
    5941        20040 :         binaryUpgradeClassOids[i].toast_index_oid = atooid(PQgetvalue(res, i, 5));
    5942        20040 :         binaryUpgradeClassOids[i].toast_index_relfilenumber = atooid(PQgetvalue(res, i, 6));
    5943              :     }
    5944              : 
    5945           40 :     PQclear(res);
    5946           40 : }
    5947              : 
    5948              : static void
    5949         1368 : binary_upgrade_set_pg_class_oids(Archive *fout,
    5950              :                                  PQExpBuffer upgrade_buffer, Oid pg_class_oid)
    5951              : {
    5952         1368 :     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         1368 :     key.oid = pg_class_oid;
    5969         1368 :     entry = bsearch(&key, binaryUpgradeClassOids, nbinaryUpgradeClassOids,
    5970              :                     sizeof(BinaryUpgradeClassOidItem),
    5971              :                     BinaryUpgradeClassOidItemCmp);
    5972              : 
    5973         1368 :     appendPQExpBufferStr(upgrade_buffer,
    5974              :                          "\n-- For binary upgrade, must preserve pg_class oids and relfilenodes\n");
    5975              : 
    5976         1368 :     if (entry->relkind != RELKIND_INDEX &&
    5977         1063 :         entry->relkind != RELKIND_PARTITIONED_INDEX)
    5978              :     {
    5979         1033 :         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         1033 :         if (RelFileNumberIsValid(entry->relfilenumber) &&
    5989          847 :             entry->relkind != RELKIND_PARTITIONED_TABLE)
    5990          847 :             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         1033 :         if (OidIsValid(entry->toast_oid) &&
    5999          296 :             entry->relkind != RELKIND_PARTITIONED_TABLE)
    6000              :         {
    6001          296 :             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          296 :             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          296 :             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          296 :             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         1368 :     appendPQExpBufferChar(upgrade_buffer, '\n');
    6029         1368 : }
    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         1617 : 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         1617 :     DumpableObject *extobj = NULL;
    6046              :     int         i;
    6047              : 
    6048         1617 :     if (!dobj->ext_member)
    6049         1595 :         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          263 : 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          263 :     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          263 :     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          263 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    6110              : 
    6111          263 :     ntups = PQntuples(res);
    6112              : 
    6113          263 :     nsinfo = pg_malloc_array(NamespaceInfo, ntups);
    6114              : 
    6115          263 :     i_tableoid = PQfnumber(res, "tableoid");
    6116          263 :     i_oid = PQfnumber(res, "oid");
    6117          263 :     i_nspname = PQfnumber(res, "nspname");
    6118          263 :     i_nspowner = PQfnumber(res, "nspowner");
    6119          263 :     i_nspacl = PQfnumber(res, "nspacl");
    6120          263 :     i_acldefault = PQfnumber(res, "acldefault");
    6121              : 
    6122         2036 :     for (i = 0; i < ntups; i++)
    6123              :     {
    6124              :         const char *nspowner;
    6125              : 
    6126         1773 :         nsinfo[i].dobj.objType = DO_NAMESPACE;
    6127         1773 :         nsinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    6128         1773 :         nsinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    6129         1773 :         AssignDumpId(&nsinfo[i].dobj);
    6130         1773 :         nsinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_nspname));
    6131         1773 :         nsinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_nspacl));
    6132         1773 :         nsinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
    6133         1773 :         nsinfo[i].dacl.privtype = 0;
    6134         1773 :         nsinfo[i].dacl.initprivs = NULL;
    6135         1773 :         nspowner = PQgetvalue(res, i, i_nspowner);
    6136         1773 :         nsinfo[i].nspowner = atooid(nspowner);
    6137         1773 :         nsinfo[i].rolname = getRoleName(nspowner);
    6138              : 
    6139              :         /* Decide whether to dump this namespace */
    6140         1773 :         selectDumpableNamespace(&nsinfo[i], fout);
    6141              : 
    6142              :         /* Mark whether namespace has an ACL */
    6143         1773 :         if (!PQgetisnull(res, i, i_nspacl))
    6144          891 :             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         1773 :         if (strcmp(nsinfo[i].dobj.name, "public") == 0)
    6163              :         {
    6164          259 :             PQExpBuffer aclarray = createPQExpBuffer();
    6165          259 :             PQExpBuffer aclitem = createPQExpBuffer();
    6166              : 
    6167              :             /* Standard ACL as of v15 is {owner=UC/owner,=U/owner} */
    6168          259 :             appendPQExpBufferChar(aclarray, '{');
    6169          259 :             quoteAclUserName(aclitem, nsinfo[i].rolname);
    6170          259 :             appendPQExpBufferStr(aclitem, "=UC/");
    6171          259 :             quoteAclUserName(aclitem, nsinfo[i].rolname);
    6172          259 :             appendPGArray(aclarray, aclitem->data);
    6173          259 :             resetPQExpBuffer(aclitem);
    6174          259 :             appendPQExpBufferStr(aclitem, "=U/");
    6175          259 :             quoteAclUserName(aclitem, nsinfo[i].rolname);
    6176          259 :             appendPGArray(aclarray, aclitem->data);
    6177          259 :             appendPQExpBufferChar(aclarray, '}');
    6178              : 
    6179          259 :             nsinfo[i].dacl.privtype = 'i';
    6180          259 :             nsinfo[i].dacl.initprivs = pstrdup(aclarray->data);
    6181          259 :             nsinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
    6182              : 
    6183          259 :             destroyPQExpBuffer(aclarray);
    6184          259 :             destroyPQExpBuffer(aclitem);
    6185              :         }
    6186              :     }
    6187              : 
    6188          263 :     PQclear(res);
    6189          263 :     destroyPQExpBuffer(query);
    6190          263 : }
    6191              : 
    6192              : /*
    6193              :  * findNamespace:
    6194              :  *      given a namespace OID, look up the info read by getNamespaces
    6195              :  */
    6196              : static NamespaceInfo *
    6197       845783 : findNamespace(Oid nsoid)
    6198              : {
    6199              :     NamespaceInfo *nsinfo;
    6200              : 
    6201       845783 :     nsinfo = findNamespaceByOid(nsoid);
    6202       845783 :     if (nsinfo == NULL)
    6203            0 :         pg_fatal("schema with OID %u does not exist", nsoid);
    6204       845783 :     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          263 : getExtensions(Archive *fout, int *numExtensions)
    6216              : {
    6217          263 :     DumpOptions *dopt = fout->dopt;
    6218              :     PGresult   *res;
    6219              :     int         ntups;
    6220              :     int         i;
    6221              :     PQExpBuffer query;
    6222          263 :     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          263 :     query = createPQExpBuffer();
    6233              : 
    6234          263 :     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          263 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    6240              : 
    6241          263 :     ntups = PQntuples(res);
    6242          263 :     if (ntups == 0)
    6243            0 :         goto cleanup;
    6244              : 
    6245          263 :     extinfo = pg_malloc_array(ExtensionInfo, ntups);
    6246              : 
    6247          263 :     i_tableoid = PQfnumber(res, "tableoid");
    6248          263 :     i_oid = PQfnumber(res, "oid");
    6249          263 :     i_extname = PQfnumber(res, "extname");
    6250          263 :     i_nspname = PQfnumber(res, "nspname");
    6251          263 :     i_extrelocatable = PQfnumber(res, "extrelocatable");
    6252          263 :     i_extversion = PQfnumber(res, "extversion");
    6253          263 :     i_extconfig = PQfnumber(res, "extconfig");
    6254          263 :     i_extcondition = PQfnumber(res, "extcondition");
    6255              : 
    6256          557 :     for (i = 0; i < ntups; i++)
    6257              :     {
    6258          294 :         extinfo[i].dobj.objType = DO_EXTENSION;
    6259          294 :         extinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    6260          294 :         extinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    6261          294 :         AssignDumpId(&extinfo[i].dobj);
    6262          294 :         extinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_extname));
    6263          294 :         extinfo[i].namespace = pg_strdup(PQgetvalue(res, i, i_nspname));
    6264          294 :         extinfo[i].relocatable = *(PQgetvalue(res, i, i_extrelocatable)) == 't';
    6265          294 :         extinfo[i].extversion = pg_strdup(PQgetvalue(res, i, i_extversion));
    6266          294 :         extinfo[i].extconfig = pg_strdup(PQgetvalue(res, i, i_extconfig));
    6267          294 :         extinfo[i].extcondition = pg_strdup(PQgetvalue(res, i, i_extcondition));
    6268              : 
    6269              :         /* Decide whether we want to dump it */
    6270          294 :         selectDumpableExtension(&(extinfo[i]), dopt);
    6271              :     }
    6272              : 
    6273          263 : cleanup:
    6274          263 :     PQclear(res);
    6275          263 :     destroyPQExpBuffer(query);
    6276              : 
    6277          263 :     *numExtensions = ntups;
    6278              : 
    6279          263 :     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          262 : getTypes(Archive *fout)
    6291              : {
    6292              :     PGresult   *res;
    6293              :     int         ntups;
    6294              :     int         i;
    6295          262 :     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          262 :     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          262 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    6341              : 
    6342          262 :     ntups = PQntuples(res);
    6343              : 
    6344          262 :     tyinfo = pg_malloc_array(TypeInfo, ntups);
    6345              : 
    6346          262 :     i_tableoid = PQfnumber(res, "tableoid");
    6347          262 :     i_oid = PQfnumber(res, "oid");
    6348          262 :     i_typname = PQfnumber(res, "typname");
    6349          262 :     i_typnamespace = PQfnumber(res, "typnamespace");
    6350          262 :     i_typacl = PQfnumber(res, "typacl");
    6351          262 :     i_acldefault = PQfnumber(res, "acldefault");
    6352          262 :     i_typowner = PQfnumber(res, "typowner");
    6353          262 :     i_typelem = PQfnumber(res, "typelem");
    6354          262 :     i_typrelid = PQfnumber(res, "typrelid");
    6355          262 :     i_typrelkind = PQfnumber(res, "typrelkind");
    6356          262 :     i_typtype = PQfnumber(res, "typtype");
    6357          262 :     i_typisdefined = PQfnumber(res, "typisdefined");
    6358          262 :     i_isarray = PQfnumber(res, "isarray");
    6359          262 :     i_typarray = PQfnumber(res, "typarray");
    6360              : 
    6361       195611 :     for (i = 0; i < ntups; i++)
    6362              :     {
    6363       195349 :         tyinfo[i].dobj.objType = DO_TYPE;
    6364       195349 :         tyinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    6365       195349 :         tyinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    6366       195349 :         AssignDumpId(&tyinfo[i].dobj);
    6367       195349 :         tyinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_typname));
    6368       390698 :         tyinfo[i].dobj.namespace =
    6369       195349 :             findNamespace(atooid(PQgetvalue(res, i, i_typnamespace)));
    6370       195349 :         tyinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_typacl));
    6371       195349 :         tyinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
    6372       195349 :         tyinfo[i].dacl.privtype = 0;
    6373       195349 :         tyinfo[i].dacl.initprivs = NULL;
    6374       195349 :         tyinfo[i].ftypname = NULL;  /* may get filled later */
    6375       195349 :         tyinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_typowner));
    6376       195349 :         tyinfo[i].typelem = atooid(PQgetvalue(res, i, i_typelem));
    6377       195349 :         tyinfo[i].typrelid = atooid(PQgetvalue(res, i, i_typrelid));
    6378       195349 :         tyinfo[i].typrelkind = *PQgetvalue(res, i, i_typrelkind);
    6379       195349 :         tyinfo[i].typtype = *PQgetvalue(res, i, i_typtype);
    6380       195349 :         tyinfo[i].shellType = NULL;
    6381              : 
    6382       195349 :         if (strcmp(PQgetvalue(res, i, i_typisdefined), "t") == 0)
    6383       195294 :             tyinfo[i].isDefined = true;
    6384              :         else
    6385           55 :             tyinfo[i].isDefined = false;
    6386              : 
    6387       195349 :         if (strcmp(PQgetvalue(res, i, i_isarray), "t") == 0)
    6388        93848 :             tyinfo[i].isArray = true;
    6389              :         else
    6390       101501 :             tyinfo[i].isArray = false;
    6391              : 
    6392       195349 :         tyinfo[i].typarray = atooid(PQgetvalue(res, i, i_typarray));
    6393              : 
    6394       195349 :         if (tyinfo[i].typtype == TYPTYPE_MULTIRANGE)
    6395         1717 :             tyinfo[i].isMultirange = true;
    6396              :         else
    6397       193632 :             tyinfo[i].isMultirange = false;
    6398              : 
    6399              :         /* Decide whether we want to dump it */
    6400       195349 :         selectDumpableType(&tyinfo[i], fout);
    6401              : 
    6402              :         /* Mark whether type has an ACL */
    6403       195349 :         if (!PQgetisnull(res, i, i_typacl))
    6404          217 :             tyinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
    6405              : 
    6406              :         /*
    6407              :          * If it's a domain, fetch info about its constraints, if any
    6408              :          */
    6409       195349 :         tyinfo[i].nDomChecks = 0;
    6410       195349 :         tyinfo[i].domChecks = NULL;
    6411       195349 :         tyinfo[i].notnull = NULL;
    6412       195349 :         if ((tyinfo[i].dobj.dump & DUMP_COMPONENT_DEFINITION) &&
    6413        16592 :             tyinfo[i].typtype == TYPTYPE_DOMAIN)
    6414          181 :             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       195349 :         if ((tyinfo[i].dobj.dump & DUMP_COMPONENT_DEFINITION) &&
    6427        16592 :             (tyinfo[i].typtype == TYPTYPE_BASE ||
    6428         8078 :              tyinfo[i].typtype == TYPTYPE_RANGE))
    6429              :         {
    6430         8649 :             stinfo = pg_malloc_object(ShellTypeInfo);
    6431         8649 :             stinfo->dobj.objType = DO_SHELL_TYPE;
    6432         8649 :             stinfo->dobj.catId = nilCatalogId;
    6433         8649 :             AssignDumpId(&stinfo->dobj);
    6434         8649 :             stinfo->dobj.name = pg_strdup(tyinfo[i].dobj.name);
    6435         8649 :             stinfo->dobj.namespace = tyinfo[i].dobj.namespace;
    6436         8649 :             stinfo->baseType = &(tyinfo[i]);
    6437         8649 :             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         8649 :             stinfo->dobj.dump = DUMP_COMPONENT_NONE;
    6445              :         }
    6446              :     }
    6447              : 
    6448          262 :     PQclear(res);
    6449              : 
    6450          262 :     destroyPQExpBuffer(query);
    6451          262 : }
    6452              : 
    6453              : /*
    6454              :  * getOperators:
    6455              :  *    get information about all operators in the system catalogs
    6456              :  */
    6457              : void
    6458          262 : getOperators(Archive *fout)
    6459              : {
    6460              :     PGresult   *res;
    6461              :     int         ntups;
    6462              :     int         i;
    6463          262 :     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          262 :     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          262 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    6490              : 
    6491          262 :     ntups = PQntuples(res);
    6492              : 
    6493          262 :     oprinfo = pg_malloc_array(OprInfo, ntups);
    6494              : 
    6495          262 :     i_tableoid = PQfnumber(res, "tableoid");
    6496          262 :     i_oid = PQfnumber(res, "oid");
    6497          262 :     i_oprname = PQfnumber(res, "oprname");
    6498          262 :     i_oprnamespace = PQfnumber(res, "oprnamespace");
    6499          262 :     i_oprowner = PQfnumber(res, "oprowner");
    6500          262 :     i_oprkind = PQfnumber(res, "oprkind");
    6501          262 :     i_oprleft = PQfnumber(res, "oprleft");
    6502          262 :     i_oprright = PQfnumber(res, "oprright");
    6503          262 :     i_oprcode = PQfnumber(res, "oprcode");
    6504              : 
    6505       211317 :     for (i = 0; i < ntups; i++)
    6506              :     {
    6507       211055 :         oprinfo[i].dobj.objType = DO_OPERATOR;
    6508       211055 :         oprinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    6509       211055 :         oprinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    6510       211055 :         AssignDumpId(&oprinfo[i].dobj);
    6511       211055 :         oprinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_oprname));
    6512       422110 :         oprinfo[i].dobj.namespace =
    6513       211055 :             findNamespace(atooid(PQgetvalue(res, i, i_oprnamespace)));
    6514       211055 :         oprinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_oprowner));
    6515       211055 :         oprinfo[i].oprkind = (PQgetvalue(res, i, i_oprkind))[0];
    6516       211055 :         oprinfo[i].oprleft = atooid(PQgetvalue(res, i, i_oprleft));
    6517       211055 :         oprinfo[i].oprright = atooid(PQgetvalue(res, i, i_oprright));
    6518       211055 :         oprinfo[i].oprcode = atooid(PQgetvalue(res, i, i_oprcode));
    6519              : 
    6520              :         /* Decide whether we want to dump it */
    6521       211055 :         selectDumpableObject(&(oprinfo[i].dobj), fout);
    6522              :     }
    6523              : 
    6524          262 :     PQclear(res);
    6525              : 
    6526          262 :     destroyPQExpBuffer(query);
    6527          262 : }
    6528              : 
    6529              : /*
    6530              :  * getCollations:
    6531              :  *    get information about all collations in the system catalogs
    6532              :  */
    6533              : void
    6534          262 : 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          262 :     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          262 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, collname, "
    6556              :                          "collnamespace, "
    6557              :                          "collowner, "
    6558              :                          "collencoding "
    6559              :                          "FROM pg_collation");
    6560              : 
    6561          262 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    6562              : 
    6563          262 :     ntups = PQntuples(res);
    6564              : 
    6565          262 :     collinfo = pg_malloc_array(CollInfo, ntups);
    6566              : 
    6567          262 :     i_tableoid = PQfnumber(res, "tableoid");
    6568          262 :     i_oid = PQfnumber(res, "oid");
    6569          262 :     i_collname = PQfnumber(res, "collname");
    6570          262 :     i_collnamespace = PQfnumber(res, "collnamespace");
    6571          262 :     i_collowner = PQfnumber(res, "collowner");
    6572          262 :     i_collencoding = PQfnumber(res, "collencoding");
    6573              : 
    6574       230939 :     for (i = 0; i < ntups; i++)
    6575              :     {
    6576       230677 :         collinfo[i].dobj.objType = DO_COLLATION;
    6577       230677 :         collinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    6578       230677 :         collinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    6579       230677 :         AssignDumpId(&collinfo[i].dobj);
    6580       230677 :         collinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_collname));
    6581       461354 :         collinfo[i].dobj.namespace =
    6582       230677 :             findNamespace(atooid(PQgetvalue(res, i, i_collnamespace)));
    6583       230677 :         collinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_collowner));
    6584       230677 :         collinfo[i].collencoding = atoi(PQgetvalue(res, i, i_collencoding));
    6585              : 
    6586              :         /* Decide whether we want to dump it */
    6587       230677 :         selectDumpableObject(&(collinfo[i].dobj), fout);
    6588              :     }
    6589              : 
    6590          262 :     PQclear(res);
    6591              : 
    6592          262 :     destroyPQExpBuffer(query);
    6593          262 : }
    6594              : 
    6595              : /*
    6596              :  * getConversions:
    6597              :  *    get information about all conversions in the system catalogs
    6598              :  */
    6599              : void
    6600          262 : 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          262 :     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          262 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, conname, "
    6621              :                          "connamespace, "
    6622              :                          "conowner "
    6623              :                          "FROM pg_conversion");
    6624              : 
    6625          262 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    6626              : 
    6627          262 :     ntups = PQntuples(res);
    6628              : 
    6629          262 :     convinfo = pg_malloc_array(ConvInfo, ntups);
    6630              : 
    6631          262 :     i_tableoid = PQfnumber(res, "tableoid");
    6632          262 :     i_oid = PQfnumber(res, "oid");
    6633          262 :     i_conname = PQfnumber(res, "conname");
    6634          262 :     i_connamespace = PQfnumber(res, "connamespace");
    6635          262 :     i_conowner = PQfnumber(res, "conowner");
    6636              : 
    6637        25986 :     for (i = 0; i < ntups; i++)
    6638              :     {
    6639        25724 :         convinfo[i].dobj.objType = DO_CONVERSION;
    6640        25724 :         convinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    6641        25724 :         convinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    6642        25724 :         AssignDumpId(&convinfo[i].dobj);
    6643        25724 :         convinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_conname));
    6644        51448 :         convinfo[i].dobj.namespace =
    6645        25724 :             findNamespace(atooid(PQgetvalue(res, i, i_connamespace)));
    6646        25724 :         convinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_conowner));
    6647              : 
    6648              :         /* Decide whether we want to dump it */
    6649        25724 :         selectDumpableObject(&(convinfo[i].dobj), fout);
    6650              :     }
    6651              : 
    6652          262 :     PQclear(res);
    6653              : 
    6654          262 :     destroyPQExpBuffer(query);
    6655          262 : }
    6656              : 
    6657              : /*
    6658              :  * getAccessMethods:
    6659              :  *    get information about all user-defined access methods
    6660              :  */
    6661              : void
    6662          262 : 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          262 :     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          262 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, amname, ");
    6688          262 :     if (fout->remoteVersion >= 90600)
    6689          262 :         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          262 :     appendPQExpBufferStr(query, "FROM pg_am");
    6697              : 
    6698          262 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    6699              : 
    6700          262 :     ntups = PQntuples(res);
    6701              : 
    6702          262 :     aminfo = pg_malloc_array(AccessMethodInfo, ntups);
    6703              : 
    6704          262 :     i_tableoid = PQfnumber(res, "tableoid");
    6705          262 :     i_oid = PQfnumber(res, "oid");
    6706          262 :     i_amname = PQfnumber(res, "amname");
    6707          262 :     i_amhandler = PQfnumber(res, "amhandler");
    6708          262 :     i_amtype = PQfnumber(res, "amtype");
    6709              : 
    6710         2224 :     for (i = 0; i < ntups; i++)
    6711              :     {
    6712         1962 :         aminfo[i].dobj.objType = DO_ACCESS_METHOD;
    6713         1962 :         aminfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    6714         1962 :         aminfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    6715         1962 :         AssignDumpId(&aminfo[i].dobj);
    6716         1962 :         aminfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_amname));
    6717         1962 :         aminfo[i].dobj.namespace = NULL;
    6718         1962 :         aminfo[i].amhandler = pg_strdup(PQgetvalue(res, i, i_amhandler));
    6719         1962 :         aminfo[i].amtype = *(PQgetvalue(res, i, i_amtype));
    6720              : 
    6721              :         /* Decide whether we want to dump it */
    6722         1962 :         selectDumpableAccessMethod(&(aminfo[i]), fout);
    6723              :     }
    6724              : 
    6725          262 :     PQclear(res);
    6726              : 
    6727          262 :     destroyPQExpBuffer(query);
    6728          262 : }
    6729              : 
    6730              : 
    6731              : /*
    6732              :  * getOpclasses:
    6733              :  *    get information about all opclasses in the system catalogs
    6734              :  */
    6735              : void
    6736          262 : getOpclasses(Archive *fout)
    6737              : {
    6738              :     PGresult   *res;
    6739              :     int         ntups;
    6740              :     int         i;
    6741          262 :     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          262 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, opcmethod, opcname, "
    6756              :                          "opcnamespace, "
    6757              :                          "opcowner "
    6758              :                          "FROM pg_opclass");
    6759              : 
    6760          262 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    6761              : 
    6762          262 :     ntups = PQntuples(res);
    6763              : 
    6764          262 :     opcinfo = pg_malloc_array(OpclassInfo, ntups);
    6765              : 
    6766          262 :     i_tableoid = PQfnumber(res, "tableoid");
    6767          262 :     i_oid = PQfnumber(res, "oid");
    6768          262 :     i_opcmethod = PQfnumber(res, "opcmethod");
    6769          262 :     i_opcname = PQfnumber(res, "opcname");
    6770          262 :     i_opcnamespace = PQfnumber(res, "opcnamespace");
    6771          262 :     i_opcowner = PQfnumber(res, "opcowner");
    6772              : 
    6773        47325 :     for (i = 0; i < ntups; i++)
    6774              :     {
    6775        47063 :         opcinfo[i].dobj.objType = DO_OPCLASS;
    6776        47063 :         opcinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    6777        47063 :         opcinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    6778        47063 :         AssignDumpId(&opcinfo[i].dobj);
    6779        47063 :         opcinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_opcname));
    6780        94126 :         opcinfo[i].dobj.namespace =
    6781        47063 :             findNamespace(atooid(PQgetvalue(res, i, i_opcnamespace)));
    6782        47063 :         opcinfo[i].opcmethod = atooid(PQgetvalue(res, i, i_opcmethod));
    6783        47063 :         opcinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_opcowner));
    6784              : 
    6785              :         /* Decide whether we want to dump it */
    6786        47063 :         selectDumpableObject(&(opcinfo[i].dobj), fout);
    6787              :     }
    6788              : 
    6789          262 :     PQclear(res);
    6790              : 
    6791          262 :     destroyPQExpBuffer(query);
    6792          262 : }
    6793              : 
    6794              : /*
    6795              :  * getOpfamilies:
    6796              :  *    get information about all opfamilies in the system catalogs
    6797              :  */
    6798              : void
    6799          262 : 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          262 :     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          262 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, opfmethod, opfname, "
    6821              :                          "opfnamespace, "
    6822              :                          "opfowner "
    6823              :                          "FROM pg_opfamily");
    6824              : 
    6825          262 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    6826              : 
    6827          262 :     ntups = PQntuples(res);
    6828              : 
    6829          262 :     opfinfo = pg_malloc_array(OpfamilyInfo, ntups);
    6830              : 
    6831          262 :     i_tableoid = PQfnumber(res, "tableoid");
    6832          262 :     i_oid = PQfnumber(res, "oid");
    6833          262 :     i_opfname = PQfnumber(res, "opfname");
    6834          262 :     i_opfmethod = PQfnumber(res, "opfmethod");
    6835          262 :     i_opfnamespace = PQfnumber(res, "opfnamespace");
    6836          262 :     i_opfowner = PQfnumber(res, "opfowner");
    6837              : 
    6838        39183 :     for (i = 0; i < ntups; i++)
    6839              :     {
    6840        38921 :         opfinfo[i].dobj.objType = DO_OPFAMILY;
    6841        38921 :         opfinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    6842        38921 :         opfinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    6843        38921 :         AssignDumpId(&opfinfo[i].dobj);
    6844        38921 :         opfinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_opfname));
    6845        77842 :         opfinfo[i].dobj.namespace =
    6846        38921 :             findNamespace(atooid(PQgetvalue(res, i, i_opfnamespace)));
    6847        38921 :         opfinfo[i].opfmethod = atooid(PQgetvalue(res, i, i_opfmethod));
    6848        38921 :         opfinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_opfowner));
    6849              : 
    6850              :         /* Decide whether we want to dump it */
    6851        38921 :         selectDumpableObject(&(opfinfo[i].dobj), fout);
    6852              :     }
    6853              : 
    6854          262 :     PQclear(res);
    6855              : 
    6856          262 :     destroyPQExpBuffer(query);
    6857          262 : }
    6858              : 
    6859              : /*
    6860              :  * getAggregates:
    6861              :  *    get information about all user-defined aggregates in the system catalogs
    6862              :  */
    6863              : void
    6864          262 : getAggregates(Archive *fout)
    6865              : {
    6866          262 :     DumpOptions *dopt = fout->dopt;
    6867              :     PGresult   *res;
    6868              :     int         ntups;
    6869              :     int         i;
    6870          262 :     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          262 :     if (fout->remoteVersion >= 90600)
    6887              :     {
    6888              :         const char *agg_check;
    6889              : 
    6890          524 :         agg_check = (fout->remoteVersion >= 110000 ? "p.prokind = 'a'"
    6891          262 :                      : "p.proisagg");
    6892              : 
    6893          262 :         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          262 :         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          262 :         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          262 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    6944              : 
    6945          262 :     ntups = PQntuples(res);
    6946              : 
    6947          262 :     agginfo = pg_malloc_array(AggInfo, ntups);
    6948              : 
    6949          262 :     i_tableoid = PQfnumber(res, "tableoid");
    6950          262 :     i_oid = PQfnumber(res, "oid");
    6951          262 :     i_aggname = PQfnumber(res, "aggname");
    6952          262 :     i_aggnamespace = PQfnumber(res, "aggnamespace");
    6953          262 :     i_pronargs = PQfnumber(res, "pronargs");
    6954          262 :     i_proargtypes = PQfnumber(res, "proargtypes");
    6955          262 :     i_proowner = PQfnumber(res, "proowner");
    6956          262 :     i_aggacl = PQfnumber(res, "aggacl");
    6957          262 :     i_acldefault = PQfnumber(res, "acldefault");
    6958              : 
    6959          664 :     for (i = 0; i < ntups; i++)
    6960              :     {
    6961          402 :         agginfo[i].aggfn.dobj.objType = DO_AGG;
    6962          402 :         agginfo[i].aggfn.dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    6963          402 :         agginfo[i].aggfn.dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    6964          402 :         AssignDumpId(&agginfo[i].aggfn.dobj);
    6965          402 :         agginfo[i].aggfn.dobj.name = pg_strdup(PQgetvalue(res, i, i_aggname));
    6966          804 :         agginfo[i].aggfn.dobj.namespace =
    6967          402 :             findNamespace(atooid(PQgetvalue(res, i, i_aggnamespace)));
    6968          402 :         agginfo[i].aggfn.dacl.acl = pg_strdup(PQgetvalue(res, i, i_aggacl));
    6969          402 :         agginfo[i].aggfn.dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
    6970          402 :         agginfo[i].aggfn.dacl.privtype = 0;
    6971          402 :         agginfo[i].aggfn.dacl.initprivs = NULL;
    6972          402 :         agginfo[i].aggfn.rolname = getRoleName(PQgetvalue(res, i, i_proowner));
    6973          402 :         agginfo[i].aggfn.lang = InvalidOid; /* not currently interesting */
    6974          402 :         agginfo[i].aggfn.prorettype = InvalidOid;   /* not saved */
    6975          402 :         agginfo[i].aggfn.nargs = atoi(PQgetvalue(res, i, i_pronargs));
    6976          402 :         if (agginfo[i].aggfn.nargs == 0)
    6977           56 :             agginfo[i].aggfn.argtypes = NULL;
    6978              :         else
    6979              :         {
    6980          346 :             agginfo[i].aggfn.argtypes = pg_malloc_array(Oid, agginfo[i].aggfn.nargs);
    6981          346 :             parseOidArray(PQgetvalue(res, i, i_proargtypes),
    6982          346 :                           agginfo[i].aggfn.argtypes,
    6983          346 :                           agginfo[i].aggfn.nargs);
    6984              :         }
    6985          402 :         agginfo[i].aggfn.postponed_def = false; /* might get set during sort */
    6986              : 
    6987              :         /* Decide whether we want to dump it */
    6988          402 :         selectDumpableObject(&(agginfo[i].aggfn.dobj), fout);
    6989              : 
    6990              :         /* Mark whether aggregate has an ACL */
    6991          402 :         if (!PQgetisnull(res, i, i_aggacl))
    6992           25 :             agginfo[i].aggfn.dobj.components |= DUMP_COMPONENT_ACL;
    6993              :     }
    6994              : 
    6995          262 :     PQclear(res);
    6996              : 
    6997          262 :     destroyPQExpBuffer(query);
    6998          262 : }
    6999              : 
    7000              : /*
    7001              :  * getFuncs:
    7002              :  *    get information about all user-defined functions in the system catalogs
    7003              :  */
    7004              : void
    7005          262 : getFuncs(Archive *fout)
    7006              : {
    7007          262 :     DumpOptions *dopt = fout->dopt;
    7008              :     PGresult   *res;
    7009              :     int         ntups;
    7010              :     int         i;
    7011          262 :     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          262 :     if (fout->remoteVersion >= 90600)
    7047              :     {
    7048              :         const char *not_agg_check;
    7049              : 
    7050          524 :         not_agg_check = (fout->remoteVersion >= 110000 ? "p.prokind <> 'a'"
    7051          262 :                          : "NOT p.proisagg");
    7052              : 
    7053          262 :         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          262 :         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          262 :         appendPQExpBufferStr(query,
    7091              :                              "\n  OR p.proacl IS DISTINCT FROM pip.initprivs");
    7092          262 :         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          262 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    7135              : 
    7136          262 :     ntups = PQntuples(res);
    7137              : 
    7138          262 :     finfo = pg_malloc0_array(FuncInfo, ntups);
    7139              : 
    7140          262 :     i_tableoid = PQfnumber(res, "tableoid");
    7141          262 :     i_oid = PQfnumber(res, "oid");
    7142          262 :     i_proname = PQfnumber(res, "proname");
    7143          262 :     i_pronamespace = PQfnumber(res, "pronamespace");
    7144          262 :     i_proowner = PQfnumber(res, "proowner");
    7145          262 :     i_prolang = PQfnumber(res, "prolang");
    7146          262 :     i_pronargs = PQfnumber(res, "pronargs");
    7147          262 :     i_proargtypes = PQfnumber(res, "proargtypes");
    7148          262 :     i_prorettype = PQfnumber(res, "prorettype");
    7149          262 :     i_proacl = PQfnumber(res, "proacl");
    7150          262 :     i_acldefault = PQfnumber(res, "acldefault");
    7151              : 
    7152         6005 :     for (i = 0; i < ntups; i++)
    7153              :     {
    7154         5743 :         finfo[i].dobj.objType = DO_FUNC;
    7155         5743 :         finfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    7156         5743 :         finfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    7157         5743 :         AssignDumpId(&finfo[i].dobj);
    7158         5743 :         finfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_proname));
    7159        11486 :         finfo[i].dobj.namespace =
    7160         5743 :             findNamespace(atooid(PQgetvalue(res, i, i_pronamespace)));
    7161         5743 :         finfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_proacl));
    7162         5743 :         finfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
    7163         5743 :         finfo[i].dacl.privtype = 0;
    7164         5743 :         finfo[i].dacl.initprivs = NULL;
    7165         5743 :         finfo[i].rolname = getRoleName(PQgetvalue(res, i, i_proowner));
    7166         5743 :         finfo[i].lang = atooid(PQgetvalue(res, i, i_prolang));
    7167         5743 :         finfo[i].prorettype = atooid(PQgetvalue(res, i, i_prorettype));
    7168         5743 :         finfo[i].nargs = atoi(PQgetvalue(res, i, i_pronargs));
    7169         5743 :         if (finfo[i].nargs == 0)
    7170         1130 :             finfo[i].argtypes = NULL;
    7171              :         else
    7172              :         {
    7173         4613 :             finfo[i].argtypes = pg_malloc_array(Oid, finfo[i].nargs);
    7174         4613 :             parseOidArray(PQgetvalue(res, i, i_proargtypes),
    7175         4613 :                           finfo[i].argtypes, finfo[i].nargs);
    7176              :         }
    7177         5743 :         finfo[i].postponed_def = false; /* might get set during sort */
    7178              : 
    7179              :         /* Decide whether we want to dump it */
    7180         5743 :         selectDumpableObject(&(finfo[i].dobj), fout);
    7181              : 
    7182              :         /* Mark whether function has an ACL */
    7183         5743 :         if (!PQgetisnull(res, i, i_proacl))
    7184          155 :             finfo[i].dobj.components |= DUMP_COMPONENT_ACL;
    7185              :     }
    7186              : 
    7187          262 :     PQclear(res);
    7188              : 
    7189          262 :     destroyPQExpBuffer(query);
    7190          262 : }
    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        10678 : getRelationStatistics(Archive *fout, DumpableObject *rel, int32 relpages,
    7201              :                       char *reltuples, int32 relallvisible,
    7202              :                       int32 relallfrozen, char relkind,
    7203              :                       char **indAttNames, int nindAttNames)
    7204              : {
    7205        10678 :     if (!fout->dopt->dumpStatistics)
    7206         6699 :         return NULL;
    7207              : 
    7208         3979 :     if ((relkind == RELKIND_RELATION) ||
    7209         1654 :         (relkind == RELKIND_PARTITIONED_TABLE) ||
    7210         1000 :         (relkind == RELKIND_INDEX) ||
    7211          666 :         (relkind == RELKIND_PARTITIONED_INDEX) ||
    7212          336 :         (relkind == RELKIND_MATVIEW ||
    7213              :          relkind == RELKIND_FOREIGN_TABLE))
    7214              :     {
    7215         3678 :         RelStatsInfo *info = pg_malloc0_object(RelStatsInfo);
    7216         3678 :         DumpableObject *dobj = &info->dobj;
    7217              : 
    7218         3678 :         dobj->objType = DO_REL_STATS;
    7219         3678 :         dobj->catId.tableoid = 0;
    7220         3678 :         dobj->catId.oid = 0;
    7221         3678 :         AssignDumpId(dobj);
    7222         3678 :         dobj->dependencies = pg_malloc_object(DumpId);
    7223         3678 :         dobj->dependencies[0] = rel->dumpId;
    7224         3678 :         dobj->nDeps = 1;
    7225         3678 :         dobj->allocDeps = 1;
    7226         3678 :         dobj->components |= DUMP_COMPONENT_STATISTICS;
    7227         3678 :         dobj->name = pg_strdup(rel->name);
    7228         3678 :         dobj->namespace = rel->namespace;
    7229         3678 :         info->relid = rel->catId.oid;
    7230         3678 :         info->relpages = relpages;
    7231         3678 :         info->reltuples = pstrdup(reltuples);
    7232         3678 :         info->relallvisible = relallvisible;
    7233         3678 :         info->relallfrozen = relallfrozen;
    7234         3678 :         info->relkind = relkind;
    7235         3678 :         info->indAttNames = indAttNames;
    7236         3678 :         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         3678 :         switch (info->relkind)
    7249              :         {
    7250         2690 :             case RELKIND_RELATION:
    7251              :             case RELKIND_PARTITIONED_TABLE:
    7252              :             case RELKIND_MATVIEW:
    7253              :             case RELKIND_FOREIGN_TABLE:
    7254         2690 :                 info->section = SECTION_DATA;
    7255         2690 :                 break;
    7256          988 :             case RELKIND_INDEX:
    7257              :             case RELKIND_PARTITIONED_INDEX:
    7258          988 :                 info->section = SECTION_POST_DATA;
    7259          988 :                 break;
    7260            0 :             default:
    7261            0 :                 pg_fatal("cannot dump statistics for relation kind \"%c\"",
    7262              :                          info->relkind);
    7263              :         }
    7264              : 
    7265         3678 :         return info;
    7266              :     }
    7267          301 :     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          263 : getTables(Archive *fout, int *numTables)
    7279              : {
    7280          263 :     DumpOptions *dopt = fout->dopt;
    7281              :     PGresult   *res;
    7282              :     int         ntups;
    7283              :     int         i;
    7284          263 :     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          263 :     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          263 :     if (fout->remoteVersion >= 180000)
    7353          263 :         appendPQExpBufferStr(query, "c.relallfrozen, ");
    7354              :     else
    7355            0 :         appendPQExpBufferStr(query, "0 AS relallfrozen, ");
    7356              : 
    7357          263 :     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          263 :     if (fout->remoteVersion >= 120000)
    7375          263 :         appendPQExpBufferStr(query,
    7376              :                              "false AS relhasoids, ");
    7377              :     else
    7378            0 :         appendPQExpBufferStr(query,
    7379              :                              "c.relhasoids, ");
    7380              : 
    7381          263 :     if (fout->remoteVersion >= 90300)
    7382          263 :         appendPQExpBufferStr(query,
    7383              :                              "c.relispopulated, ");
    7384              :     else
    7385            0 :         appendPQExpBufferStr(query,
    7386              :                              "'t' as relispopulated, ");
    7387              : 
    7388          263 :     if (fout->remoteVersion >= 90400)
    7389          263 :         appendPQExpBufferStr(query,
    7390              :                              "c.relreplident, ");
    7391              :     else
    7392            0 :         appendPQExpBufferStr(query,
    7393              :                              "'d' AS relreplident, ");
    7394              : 
    7395          263 :     if (fout->remoteVersion >= 90500)
    7396          263 :         appendPQExpBufferStr(query,
    7397              :                              "c.relrowsecurity, c.relforcerowsecurity, ");
    7398              :     else
    7399            0 :         appendPQExpBufferStr(query,
    7400              :                              "false AS relrowsecurity, "
    7401              :                              "false AS relforcerowsecurity, ");
    7402              : 
    7403          263 :     if (fout->remoteVersion >= 90300)
    7404          263 :         appendPQExpBufferStr(query,
    7405              :                              "c.relminmxid, tc.relminmxid AS tminmxid, ");
    7406              :     else
    7407            0 :         appendPQExpBufferStr(query,
    7408              :                              "0 AS relminmxid, 0 AS tminmxid, ");
    7409              : 
    7410          263 :     if (fout->remoteVersion >= 90300)
    7411          263 :         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          263 :     if (fout->remoteVersion >= 90600)
    7420          263 :         appendPQExpBufferStr(query,
    7421              :                              "am.amname, ");
    7422              :     else
    7423            0 :         appendPQExpBufferStr(query,
    7424              :                              "NULL AS amname, ");
    7425              : 
    7426          263 :     if (fout->remoteVersion >= 90600)
    7427          263 :         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          263 :     if (fout->remoteVersion >= 100000)
    7434          263 :         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          263 :     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          263 :     if (fout->remoteVersion >= 90600)
    7459          263 :         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          263 :     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          263 :     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          263 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    7495              : 
    7496          263 :     ntups = PQntuples(res);
    7497              : 
    7498          263 :     *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          263 :     tblinfo = pg_malloc0_array(TableInfo, ntups);
    7510              : 
    7511          263 :     i_reltableoid = PQfnumber(res, "tableoid");
    7512          263 :     i_reloid = PQfnumber(res, "oid");
    7513          263 :     i_relname = PQfnumber(res, "relname");
    7514          263 :     i_relnamespace = PQfnumber(res, "relnamespace");
    7515          263 :     i_relkind = PQfnumber(res, "relkind");
    7516          263 :     i_reltype = PQfnumber(res, "reltype");
    7517          263 :     i_relowner = PQfnumber(res, "relowner");
    7518          263 :     i_relchecks = PQfnumber(res, "relchecks");
    7519          263 :     i_relhasindex = PQfnumber(res, "relhasindex");
    7520          263 :     i_relhasrules = PQfnumber(res, "relhasrules");
    7521          263 :     i_relpages = PQfnumber(res, "relpages");
    7522          263 :     i_reltuples = PQfnumber(res, "reltuples");
    7523          263 :     i_relallvisible = PQfnumber(res, "relallvisible");
    7524          263 :     i_relallfrozen = PQfnumber(res, "relallfrozen");
    7525          263 :     i_toastpages = PQfnumber(res, "toastpages");
    7526          263 :     i_owning_tab = PQfnumber(res, "owning_tab");
    7527          263 :     i_owning_col = PQfnumber(res, "owning_col");
    7528          263 :     i_reltablespace = PQfnumber(res, "reltablespace");
    7529          263 :     i_relhasoids = PQfnumber(res, "relhasoids");
    7530          263 :     i_relhastriggers = PQfnumber(res, "relhastriggers");
    7531          263 :     i_relpersistence = PQfnumber(res, "relpersistence");
    7532          263 :     i_relispopulated = PQfnumber(res, "relispopulated");
    7533          263 :     i_relreplident = PQfnumber(res, "relreplident");
    7534          263 :     i_relrowsec = PQfnumber(res, "relrowsecurity");
    7535          263 :     i_relforcerowsec = PQfnumber(res, "relforcerowsecurity");
    7536          263 :     i_relfrozenxid = PQfnumber(res, "relfrozenxid");
    7537          263 :     i_toastfrozenxid = PQfnumber(res, "tfrozenxid");
    7538          263 :     i_toastoid = PQfnumber(res, "toid");
    7539          263 :     i_relminmxid = PQfnumber(res, "relminmxid");
    7540          263 :     i_toastminmxid = PQfnumber(res, "tminmxid");
    7541          263 :     i_reloptions = PQfnumber(res, "reloptions");
    7542          263 :     i_checkoption = PQfnumber(res, "checkoption");
    7543          263 :     i_toastreloptions = PQfnumber(res, "toast_reloptions");
    7544          263 :     i_reloftype = PQfnumber(res, "reloftype");
    7545          263 :     i_foreignserver = PQfnumber(res, "foreignserver");
    7546          263 :     i_amname = PQfnumber(res, "amname");
    7547          263 :     i_is_identity_sequence = PQfnumber(res, "is_identity_sequence");
    7548          263 :     i_relacl = PQfnumber(res, "relacl");
    7549          263 :     i_acldefault = PQfnumber(res, "acldefault");
    7550          263 :     i_ispartition = PQfnumber(res, "ispartition");
    7551              : 
    7552          263 :     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          263 :     resetPQExpBuffer(query);
    7568              : 
    7569        72173 :     for (i = 0; i < ntups; i++)
    7570              :     {
    7571        71910 :         int32       relallvisible = atoi(PQgetvalue(res, i, i_relallvisible));
    7572        71910 :         int32       relallfrozen = atoi(PQgetvalue(res, i, i_relallfrozen));
    7573              : 
    7574        71910 :         tblinfo[i].dobj.objType = DO_TABLE;
    7575        71910 :         tblinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_reltableoid));
    7576        71910 :         tblinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_reloid));
    7577        71910 :         AssignDumpId(&tblinfo[i].dobj);
    7578        71910 :         tblinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_relname));
    7579       143820 :         tblinfo[i].dobj.namespace =
    7580        71910 :             findNamespace(atooid(PQgetvalue(res, i, i_relnamespace)));
    7581        71910 :         tblinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_relacl));
    7582        71910 :         tblinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
    7583        71910 :         tblinfo[i].dacl.privtype = 0;
    7584        71910 :         tblinfo[i].dacl.initprivs = NULL;
    7585        71910 :         tblinfo[i].relkind = *(PQgetvalue(res, i, i_relkind));
    7586        71910 :         tblinfo[i].reltype = atooid(PQgetvalue(res, i, i_reltype));
    7587        71910 :         tblinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_relowner));
    7588        71910 :         tblinfo[i].ncheck = atoi(PQgetvalue(res, i, i_relchecks));
    7589        71910 :         tblinfo[i].hasindex = (strcmp(PQgetvalue(res, i, i_relhasindex), "t") == 0);
    7590        71910 :         tblinfo[i].hasrules = (strcmp(PQgetvalue(res, i, i_relhasrules), "t") == 0);
    7591        71910 :         tblinfo[i].relpages = atoi(PQgetvalue(res, i, i_relpages));
    7592        71910 :         if (PQgetisnull(res, i, i_toastpages))
    7593        58558 :             tblinfo[i].toastpages = 0;
    7594              :         else
    7595        13352 :             tblinfo[i].toastpages = atoi(PQgetvalue(res, i, i_toastpages));
    7596        71910 :         if (PQgetisnull(res, i, i_owning_tab))
    7597              :         {
    7598        71486 :             tblinfo[i].owning_tab = InvalidOid;
    7599        71486 :             tblinfo[i].owning_col = 0;
    7600              :         }
    7601              :         else
    7602              :         {
    7603          424 :             tblinfo[i].owning_tab = atooid(PQgetvalue(res, i, i_owning_tab));
    7604          424 :             tblinfo[i].owning_col = atoi(PQgetvalue(res, i, i_owning_col));
    7605              :         }
    7606        71910 :         tblinfo[i].reltablespace = pg_strdup(PQgetvalue(res, i, i_reltablespace));
    7607        71910 :         tblinfo[i].hasoids = (strcmp(PQgetvalue(res, i, i_relhasoids), "t") == 0);
    7608        71910 :         tblinfo[i].hastriggers = (strcmp(PQgetvalue(res, i, i_relhastriggers), "t") == 0);
    7609        71910 :         tblinfo[i].relpersistence = *(PQgetvalue(res, i, i_relpersistence));
    7610        71910 :         tblinfo[i].relispopulated = (strcmp(PQgetvalue(res, i, i_relispopulated), "t") == 0);
    7611        71910 :         tblinfo[i].relreplident = *(PQgetvalue(res, i, i_relreplident));
    7612        71910 :         tblinfo[i].rowsec = (strcmp(PQgetvalue(res, i, i_relrowsec), "t") == 0);
    7613        71910 :         tblinfo[i].forcerowsec = (strcmp(PQgetvalue(res, i, i_relforcerowsec), "t") == 0);
    7614        71910 :         tblinfo[i].frozenxid = atooid(PQgetvalue(res, i, i_relfrozenxid));
    7615        71910 :         tblinfo[i].toast_frozenxid = atooid(PQgetvalue(res, i, i_toastfrozenxid));
    7616        71910 :         tblinfo[i].toast_oid = atooid(PQgetvalue(res, i, i_toastoid));
    7617        71910 :         tblinfo[i].minmxid = atooid(PQgetvalue(res, i, i_relminmxid));
    7618        71910 :         tblinfo[i].toast_minmxid = atooid(PQgetvalue(res, i, i_toastminmxid));
    7619        71910 :         tblinfo[i].reloptions = pg_strdup(PQgetvalue(res, i, i_reloptions));
    7620        71910 :         if (PQgetisnull(res, i, i_checkoption))
    7621        71861 :             tblinfo[i].checkoption = NULL;
    7622              :         else
    7623           49 :             tblinfo[i].checkoption = pg_strdup(PQgetvalue(res, i, i_checkoption));
    7624        71910 :         tblinfo[i].toast_reloptions = pg_strdup(PQgetvalue(res, i, i_toastreloptions));
    7625        71910 :         tblinfo[i].reloftype = atooid(PQgetvalue(res, i, i_reloftype));
    7626        71910 :         tblinfo[i].foreign_server = atooid(PQgetvalue(res, i, i_foreignserver));
    7627        71910 :         if (PQgetisnull(res, i, i_amname))
    7628        44880 :             tblinfo[i].amname = NULL;
    7629              :         else
    7630        27030 :             tblinfo[i].amname = pg_strdup(PQgetvalue(res, i, i_amname));
    7631        71910 :         tblinfo[i].is_identity_sequence = (strcmp(PQgetvalue(res, i, i_is_identity_sequence), "t") == 0);
    7632        71910 :         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        71910 :         if (tblinfo[i].relkind == RELKIND_COMPOSITE_TYPE)
    7640          186 :             tblinfo[i].dobj.dump = DUMP_COMPONENT_NONE;
    7641              :         else
    7642        71724 :             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        71910 :         tblinfo[i].interesting = (tblinfo[i].dobj.dump &
    7656              :                                   (DUMP_COMPONENT_DEFINITION |
    7657              :                                    DUMP_COMPONENT_DATA |
    7658        71910 :                                    DUMP_COMPONENT_STATISTICS)) != 0;
    7659              : 
    7660        71910 :         tblinfo[i].dummy_view = false;  /* might get set during sort */
    7661        71910 :         tblinfo[i].postponed_def = false;   /* might get set during sort */
    7662              : 
    7663              :         /* Tables have data */
    7664        71910 :         tblinfo[i].dobj.components |= DUMP_COMPONENT_DATA;
    7665              : 
    7666              :         /* Mark whether table has an ACL */
    7667        71910 :         if (!PQgetisnull(res, i, i_relacl))
    7668        60659 :             tblinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
    7669        71910 :         tblinfo[i].hascolumnACLs = false;   /* may get set later */
    7670              : 
    7671              :         /* Add statistics */
    7672        71910 :         if (tblinfo[i].interesting)
    7673              :         {
    7674              :             RelStatsInfo *stats;
    7675              : 
    7676        15704 :             stats = getRelationStatistics(fout, &tblinfo[i].dobj,
    7677         7852 :                                           tblinfo[i].relpages,
    7678              :                                           PQgetvalue(res, i, i_reltuples),
    7679              :                                           relallvisible, relallfrozen,
    7680         7852 :                                           tblinfo[i].relkind, NULL, 0);
    7681         7852 :             if (tblinfo[i].relkind == RELKIND_MATVIEW)
    7682          425 :                 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        71910 :         if ((tblinfo[i].dobj.dump & DUMP_COMPONENTS_REQUIRING_LOCK) &&
    7701         7852 :             (tblinfo[i].relkind == RELKIND_RELATION ||
    7702         2203 :              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         6284 :             if (query->len == 0)
    7710          180 :                 appendPQExpBuffer(query, "LOCK TABLE %s",
    7711          180 :                                   fmtQualifiedDumpable(&tblinfo[i]));
    7712              :             else
    7713              :             {
    7714         6104 :                 appendPQExpBuffer(query, ", %s",
    7715         6104 :                                   fmtQualifiedDumpable(&tblinfo[i]));
    7716              : 
    7717              :                 /* Arbitrarily end a batch when query length reaches 100K. */
    7718         6104 :                 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          263 :     if (query->len != 0)
    7730              :     {
    7731              :         /* Lock the tables in the last batch. */
    7732          180 :         appendPQExpBufferStr(query, " IN ACCESS SHARE MODE");
    7733          180 :         ExecuteSqlStatement(fout, query->data);
    7734              :     }
    7735              : 
    7736          262 :     if (dopt->lockWaitTimeout)
    7737              :     {
    7738            2 :         ExecuteSqlStatement(fout, "SET statement_timeout = 0");
    7739              :     }
    7740              : 
    7741          262 :     PQclear(res);
    7742              : 
    7743          262 :     destroyPQExpBuffer(query);
    7744              : 
    7745          262 :     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          262 : 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        71878 :     for (i = 0; i < numTables; i++)
    7765              :     {
    7766        71616 :         TableInfo  *seqinfo = &tblinfo[i];
    7767              :         TableInfo  *owning_tab;
    7768              : 
    7769        71616 :         if (!OidIsValid(seqinfo->owning_tab))
    7770        71195 :             continue;           /* not an owned sequence */
    7771              : 
    7772          421 :         owning_tab = findTableByOid(seqinfo->owning_tab);
    7773          421 :         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          421 :         if (seqinfo->is_identity_sequence)
    7800          202 :             seqinfo->dobj.dump = owning_tab->dobj.dump;
    7801              :         else
    7802          219 :             seqinfo->dobj.dump |= owning_tab->dobj.dump;
    7803              : 
    7804              :         /* Make sure that necessary data is available if we're dumping it */
    7805          421 :         if (seqinfo->dobj.dump != DUMP_COMPONENT_NONE)
    7806              :         {
    7807          325 :             seqinfo->interesting = true;
    7808          325 :             owning_tab->interesting = true;
    7809              :         }
    7810              :     }
    7811          262 : }
    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          262 : getInherits(Archive *fout, int *numInherits)
    7822              : {
    7823              :     PGresult   *res;
    7824              :     int         ntups;
    7825              :     int         i;
    7826          262 :     PQExpBuffer query = createPQExpBuffer();
    7827              :     InhInfo    *inhinfo;
    7828              : 
    7829              :     int         i_inhrelid;
    7830              :     int         i_inhparent;
    7831              : 
    7832              :     /* find all the inheritance information */
    7833          262 :     appendPQExpBufferStr(query, "SELECT inhrelid, inhparent FROM pg_inherits");
    7834              : 
    7835          262 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    7836              : 
    7837          262 :     ntups = PQntuples(res);
    7838              : 
    7839          262 :     *numInherits = ntups;
    7840              : 
    7841          262 :     inhinfo = pg_malloc_array(InhInfo, ntups);
    7842              : 
    7843          262 :     i_inhrelid = PQfnumber(res, "inhrelid");
    7844          262 :     i_inhparent = PQfnumber(res, "inhparent");
    7845              : 
    7846         3890 :     for (i = 0; i < ntups; i++)
    7847              :     {
    7848         3628 :         inhinfo[i].inhrelid = atooid(PQgetvalue(res, i, i_inhrelid));
    7849         3628 :         inhinfo[i].inhparent = atooid(PQgetvalue(res, i, i_inhparent));
    7850              :     }
    7851              : 
    7852          262 :     PQclear(res);
    7853              : 
    7854          262 :     destroyPQExpBuffer(query);
    7855              : 
    7856          262 :     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          262 : getPartitioningInfo(Archive *fout)
    7878              : {
    7879              :     PQExpBuffer query;
    7880              :     PGresult   *res;
    7881              :     int         ntups;
    7882              : 
    7883              :     /* hash partitioning didn't exist before v11 */
    7884          262 :     if (fout->remoteVersion < 110000)
    7885            0 :         return;
    7886              :     /* needn't bother if not dumping data */
    7887          262 :     if (!fout->dopt->dumpData)
    7888           45 :         return;
    7889              : 
    7890          217 :     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          217 :     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          217 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    7909              : 
    7910          217 :     ntups = PQntuples(res);
    7911              : 
    7912          262 :     for (int i = 0; i < ntups; i++)
    7913              :     {
    7914           45 :         Oid         tabrelid = atooid(PQgetvalue(res, i, 0));
    7915              :         TableInfo  *tbinfo;
    7916              : 
    7917           45 :         tbinfo = findTableByOid(tabrelid);
    7918           45 :         if (tbinfo == NULL)
    7919            0 :             pg_fatal("failed sanity check, table OID %u appearing in pg_partitioned_table not found",
    7920              :                      tabrelid);
    7921           45 :         tbinfo->unsafe_partitions = true;
    7922              :     }
    7923              : 
    7924          217 :     PQclear(res);
    7925              : 
    7926          217 :     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          262 : getIndexes(Archive *fout, TableInfo tblinfo[], int numTables)
    7938              : {
    7939          262 :     PQExpBuffer query = createPQExpBuffer();
    7940          262 :     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          262 :     appendPQExpBufferChar(tbloids, '{');
    7984        71878 :     for (int i = 0; i < numTables; i++)
    7985              :     {
    7986        71616 :         TableInfo  *tbinfo = &tblinfo[i];
    7987              : 
    7988        71616 :         if (!tbinfo->hasindex)
    7989        50919 :             continue;
    7990              : 
    7991              :         /*
    7992              :          * We can ignore indexes of uninteresting tables.
    7993              :          */
    7994        20697 :         if (!tbinfo->interesting)
    7995        18510 :             continue;
    7996              : 
    7997              :         /* OK, we need info for this table */
    7998         2187 :         if (tbloids->len > 1) /* do we have more than the '{'? */
    7999         2105 :             appendPQExpBufferChar(tbloids, ',');
    8000         2187 :         appendPQExpBuffer(tbloids, "%u", tbinfo->dobj.catId.oid);
    8001              :     }
    8002          262 :     appendPQExpBufferChar(tbloids, '}');
    8003              : 
    8004          262 :     appendPQExpBufferStr(query,
    8005              :                          "SELECT t.tableoid, t.oid, i.indrelid, "
    8006              :                          "t.relname AS indexname, "
    8007              :                          "t.relpages, t.reltuples, t.relallvisible, ");
    8008              : 
    8009          262 :     if (fout->remoteVersion >= 180000)
    8010          262 :         appendPQExpBufferStr(query, "t.relallfrozen, ");
    8011              :     else
    8012            0 :         appendPQExpBufferStr(query, "0 AS relallfrozen, ");
    8013              : 
    8014          262 :     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          262 :     if (fout->remoteVersion >= 90400)
    8032          262 :         appendPQExpBufferStr(query,
    8033              :                              "i.indisreplident, ");
    8034              :     else
    8035            0 :         appendPQExpBufferStr(query,
    8036              :                              "false AS indisreplident, ");
    8037              : 
    8038          262 :     if (fout->remoteVersion >= 110000)
    8039          262 :         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          262 :     if (fout->remoteVersion >= 150000)
    8060          262 :         appendPQExpBufferStr(query,
    8061              :                              "i.indnullsnotdistinct, ");
    8062              :     else
    8063            0 :         appendPQExpBufferStr(query,
    8064              :                              "false AS indnullsnotdistinct, ");
    8065              : 
    8066          262 :     if (fout->remoteVersion >= 180000)
    8067          262 :         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          262 :     if (fout->remoteVersion >= 110000)
    8083              :     {
    8084          262 :         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          262 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    8120              : 
    8121          262 :     ntups = PQntuples(res);
    8122              : 
    8123          262 :     i_tableoid = PQfnumber(res, "tableoid");
    8124          262 :     i_oid = PQfnumber(res, "oid");
    8125          262 :     i_indrelid = PQfnumber(res, "indrelid");
    8126          262 :     i_indexname = PQfnumber(res, "indexname");
    8127          262 :     i_relpages = PQfnumber(res, "relpages");
    8128          262 :     i_reltuples = PQfnumber(res, "reltuples");
    8129          262 :     i_relallvisible = PQfnumber(res, "relallvisible");
    8130          262 :     i_relallfrozen = PQfnumber(res, "relallfrozen");
    8131          262 :     i_parentidx = PQfnumber(res, "parentidx");
    8132          262 :     i_indexdef = PQfnumber(res, "indexdef");
    8133          262 :     i_indnkeyatts = PQfnumber(res, "indnkeyatts");
    8134          262 :     i_indnatts = PQfnumber(res, "indnatts");
    8135          262 :     i_indkey = PQfnumber(res, "indkey");
    8136          262 :     i_indisclustered = PQfnumber(res, "indisclustered");
    8137          262 :     i_indisreplident = PQfnumber(res, "indisreplident");
    8138          262 :     i_indnullsnotdistinct = PQfnumber(res, "indnullsnotdistinct");
    8139          262 :     i_contype = PQfnumber(res, "contype");
    8140          262 :     i_conname = PQfnumber(res, "conname");
    8141          262 :     i_condeferrable = PQfnumber(res, "condeferrable");
    8142          262 :     i_condeferred = PQfnumber(res, "condeferred");
    8143          262 :     i_conperiod = PQfnumber(res, "conperiod");
    8144          262 :     i_contableoid = PQfnumber(res, "contableoid");
    8145          262 :     i_conoid = PQfnumber(res, "conoid");
    8146          262 :     i_condef = PQfnumber(res, "condef");
    8147          262 :     i_indattnames = PQfnumber(res, "indattnames");
    8148          262 :     i_tablespace = PQfnumber(res, "tablespace");
    8149          262 :     i_indreloptions = PQfnumber(res, "indreloptions");
    8150          262 :     i_indstatcols = PQfnumber(res, "indstatcols");
    8151          262 :     i_indstatvals = PQfnumber(res, "indstatvals");
    8152              : 
    8153          262 :     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          262 :     curtblindx = -1;
    8160         2437 :     for (int j = 0; j < ntups;)
    8161              :     {
    8162         2175 :         Oid         indrelid = atooid(PQgetvalue(res, j, i_indrelid));
    8163         2175 :         TableInfo  *tbinfo = NULL;
    8164              :         int         numinds;
    8165              : 
    8166              :         /* Count rows for this table */
    8167         2826 :         for (numinds = 1; numinds < ntups - j; numinds++)
    8168         2744 :             if (atooid(PQgetvalue(res, j + numinds, i_indrelid)) != indrelid)
    8169         2093 :                 break;
    8170              : 
    8171              :         /*
    8172              :          * Locate the associated TableInfo; we rely on tblinfo[] being in OID
    8173              :          * order.
    8174              :          */
    8175        26278 :         while (++curtblindx < numTables)
    8176              :         {
    8177        26278 :             tbinfo = &tblinfo[curtblindx];
    8178        26278 :             if (tbinfo->dobj.catId.oid == indrelid)
    8179         2175 :                 break;
    8180              :         }
    8181         2175 :         if (curtblindx >= numTables)
    8182            0 :             pg_fatal("unrecognized table OID %u", indrelid);
    8183              :         /* cross-check that we only got requested tables */
    8184         2175 :         if (!tbinfo->hasindex ||
    8185         2175 :             !tbinfo->interesting)
    8186            0 :             pg_fatal("unexpected index data for table \"%s\"",
    8187              :                      tbinfo->dobj.name);
    8188              : 
    8189              :         /* Save data for this table */
    8190         2175 :         tbinfo->indexes = indxinfo + j;
    8191         2175 :         tbinfo->numIndexes = numinds;
    8192              : 
    8193         5001 :         for (int c = 0; c < numinds; c++, j++)
    8194              :         {
    8195              :             char        contype;
    8196              :             char        indexkind;
    8197         2826 :             char      **indAttNames = NULL;
    8198         2826 :             int         nindAttNames = 0;
    8199              :             RelStatsInfo *relstats;
    8200         2826 :             int32       relpages = atoi(PQgetvalue(res, j, i_relpages));
    8201         2826 :             int32       relallvisible = atoi(PQgetvalue(res, j, i_relallvisible));
    8202         2826 :             int32       relallfrozen = atoi(PQgetvalue(res, j, i_relallfrozen));
    8203              : 
    8204         2826 :             indxinfo[j].dobj.objType = DO_INDEX;
    8205         2826 :             indxinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
    8206         2826 :             indxinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
    8207         2826 :             AssignDumpId(&indxinfo[j].dobj);
    8208         2826 :             indxinfo[j].dobj.dump = tbinfo->dobj.dump;
    8209         2826 :             indxinfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_indexname));
    8210         2826 :             indxinfo[j].dobj.namespace = tbinfo->dobj.namespace;
    8211         2826 :             indxinfo[j].indextable = tbinfo;
    8212         2826 :             indxinfo[j].indexdef = pg_strdup(PQgetvalue(res, j, i_indexdef));
    8213         2826 :             indxinfo[j].indnkeyattrs = atoi(PQgetvalue(res, j, i_indnkeyatts));
    8214         2826 :             indxinfo[j].indnattrs = atoi(PQgetvalue(res, j, i_indnatts));
    8215         2826 :             indxinfo[j].tablespace = pg_strdup(PQgetvalue(res, j, i_tablespace));
    8216         2826 :             indxinfo[j].indreloptions = pg_strdup(PQgetvalue(res, j, i_indreloptions));
    8217         2826 :             indxinfo[j].indstatcols = pg_strdup(PQgetvalue(res, j, i_indstatcols));
    8218         2826 :             indxinfo[j].indstatvals = pg_strdup(PQgetvalue(res, j, i_indstatvals));
    8219         2826 :             indxinfo[j].indkeys = pg_malloc_array(Oid, indxinfo[j].indnattrs);
    8220         2826 :             parseOidArray(PQgetvalue(res, j, i_indkey),
    8221         2826 :                           indxinfo[j].indkeys, indxinfo[j].indnattrs);
    8222         2826 :             indxinfo[j].indisclustered = (PQgetvalue(res, j, i_indisclustered)[0] == 't');
    8223         2826 :             indxinfo[j].indisreplident = (PQgetvalue(res, j, i_indisreplident)[0] == 't');
    8224         2826 :             indxinfo[j].indnullsnotdistinct = (PQgetvalue(res, j, i_indnullsnotdistinct)[0] == 't');
    8225         2826 :             indxinfo[j].parentidx = atooid(PQgetvalue(res, j, i_parentidx));
    8226         2826 :             indxinfo[j].partattaches = (SimplePtrList)
    8227              :             {
    8228              :                 NULL, NULL
    8229              :             };
    8230              : 
    8231         2826 :             if (indxinfo[j].parentidx == 0)
    8232         2216 :                 indexkind = RELKIND_INDEX;
    8233              :             else
    8234          610 :                 indexkind = RELKIND_PARTITIONED_INDEX;
    8235              : 
    8236         2826 :             if (!PQgetisnull(res, j, i_indattnames))
    8237              :             {
    8238          152 :                 if (!parsePGArray(PQgetvalue(res, j, i_indattnames),
    8239              :                                   &indAttNames, &nindAttNames))
    8240            0 :                     pg_fatal("could not parse %s array", "indattnames");
    8241              :             }
    8242              : 
    8243         2826 :             relstats = getRelationStatistics(fout, &indxinfo[j].dobj, relpages,
    8244              :                                              PQgetvalue(res, j, i_reltuples),
    8245              :                                              relallvisible, relallfrozen, indexkind,
    8246              :                                              indAttNames, nindAttNames);
    8247              : 
    8248         2826 :             contype = *(PQgetvalue(res, j, i_contype));
    8249         2826 :             if (contype == 'p' || contype == 'u' || contype == 'x')
    8250         1714 :             {
    8251              :                 /*
    8252              :                  * If we found a constraint matching the index, create an
    8253              :                  * entry for it.
    8254              :                  */
    8255              :                 ConstraintInfo *constrinfo;
    8256              : 
    8257         1714 :                 constrinfo = pg_malloc_object(ConstraintInfo);
    8258         1714 :                 constrinfo->dobj.objType = DO_CONSTRAINT;
    8259         1714 :                 constrinfo->dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_contableoid));
    8260         1714 :                 constrinfo->dobj.catId.oid = atooid(PQgetvalue(res, j, i_conoid));
    8261         1714 :                 AssignDumpId(&constrinfo->dobj);
    8262         1714 :                 constrinfo->dobj.dump = tbinfo->dobj.dump;
    8263         1714 :                 constrinfo->dobj.name = pg_strdup(PQgetvalue(res, j, i_conname));
    8264         1714 :                 constrinfo->dobj.namespace = tbinfo->dobj.namespace;
    8265         1714 :                 constrinfo->contable = tbinfo;
    8266         1714 :                 constrinfo->condomain = NULL;
    8267         1714 :                 constrinfo->contype = contype;
    8268         1714 :                 if (contype == 'x')
    8269           10 :                     constrinfo->condef = pg_strdup(PQgetvalue(res, j, i_condef));
    8270              :                 else
    8271         1704 :                     constrinfo->condef = NULL;
    8272         1714 :                 constrinfo->confrelid = InvalidOid;
    8273         1714 :                 constrinfo->conindex = indxinfo[j].dobj.dumpId;
    8274         1714 :                 constrinfo->condeferrable = *(PQgetvalue(res, j, i_condeferrable)) == 't';
    8275         1714 :                 constrinfo->condeferred = *(PQgetvalue(res, j, i_condeferred)) == 't';
    8276         1714 :                 constrinfo->conperiod = *(PQgetvalue(res, j, i_conperiod)) == 't';
    8277         1714 :                 constrinfo->conislocal = true;
    8278         1714 :                 constrinfo->separate = true;
    8279              : 
    8280         1714 :                 indxinfo[j].indexconstraint = constrinfo->dobj.dumpId;
    8281         1714 :                 if (relstats != NULL)
    8282          589 :                     addObjectDependency(&relstats->dobj, constrinfo->dobj.dumpId);
    8283              :             }
    8284              :             else
    8285              :             {
    8286              :                 /* Plain secondary index */
    8287         1112 :                 indxinfo[j].indexconstraint = 0;
    8288              :             }
    8289              :         }
    8290              :     }
    8291              : 
    8292          262 :     PQclear(res);
    8293              : 
    8294          262 :     destroyPQExpBuffer(query);
    8295          262 :     destroyPQExpBuffer(tbloids);
    8296          262 : }
    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          262 : 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          262 :     if (fout->remoteVersion < 100000)
    8323            0 :         return;
    8324              : 
    8325          262 :     query = createPQExpBuffer();
    8326              : 
    8327          262 :     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          262 :         appendPQExpBufferStr(query, "SELECT tableoid, oid, stxname, "
    8333              :                              "stxnamespace, stxowner, stxrelid, stxstattarget "
    8334              :                              "FROM pg_catalog.pg_statistic_ext");
    8335              : 
    8336          262 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    8337              : 
    8338          262 :     ntups = PQntuples(res);
    8339              : 
    8340          262 :     i_tableoid = PQfnumber(res, "tableoid");
    8341          262 :     i_oid = PQfnumber(res, "oid");
    8342          262 :     i_stxname = PQfnumber(res, "stxname");
    8343          262 :     i_stxnamespace = PQfnumber(res, "stxnamespace");
    8344          262 :     i_stxowner = PQfnumber(res, "stxowner");
    8345          262 :     i_stxrelid = PQfnumber(res, "stxrelid");
    8346          262 :     i_stattarget = PQfnumber(res, "stxstattarget");
    8347              : 
    8348          262 :     statsextinfo = pg_malloc_array(StatsExtInfo, ntups);
    8349              : 
    8350          482 :     for (i = 0; i < ntups; i++)
    8351              :     {
    8352          220 :         statsextinfo[i].dobj.objType = DO_STATSEXT;
    8353          220 :         statsextinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    8354          220 :         statsextinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    8355          220 :         AssignDumpId(&statsextinfo[i].dobj);
    8356          220 :         statsextinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_stxname));
    8357          440 :         statsextinfo[i].dobj.namespace =
    8358          220 :             findNamespace(atooid(PQgetvalue(res, i, i_stxnamespace)));
    8359          220 :         statsextinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_stxowner));
    8360          440 :         statsextinfo[i].stattable =
    8361          220 :             findTableByOid(atooid(PQgetvalue(res, i, i_stxrelid)));
    8362          220 :         if (PQgetisnull(res, i, i_stattarget))
    8363          172 :             statsextinfo[i].stattarget = -1;
    8364              :         else
    8365           48 :             statsextinfo[i].stattarget = atoi(PQgetvalue(res, i, i_stattarget));
    8366              : 
    8367              :         /* Decide whether we want to dump it */
    8368          220 :         selectDumpableStatisticsObject(&(statsextinfo[i]), fout);
    8369              : 
    8370          220 :         if (fout->dopt->dumpStatistics)
    8371          164 :             statsextinfo[i].dobj.components |= DUMP_COMPONENT_STATISTICS;
    8372              :     }
    8373              : 
    8374          262 :     PQclear(res);
    8375          262 :     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          262 : getConstraints(Archive *fout, TableInfo tblinfo[], int numTables)
    8389              : {
    8390          262 :     PQExpBuffer query = createPQExpBuffer();
    8391          262 :     PQExpBuffer tbloids = createPQExpBuffer();
    8392              :     PGresult   *res;
    8393              :     int         ntups;
    8394              :     int         curtblindx;
    8395          262 :     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          262 :     appendPQExpBufferChar(tbloids, '{');
    8414        71878 :     for (int i = 0; i < numTables; i++)
    8415              :     {
    8416        71616 :         TableInfo  *tinfo = &tblinfo[i];
    8417              : 
    8418        71616 :         if (!(tinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
    8419        63819 :             continue;
    8420              : 
    8421              :         /* OK, we need info for this table */
    8422         7797 :         if (tbloids->len > 1) /* do we have more than the '{'? */
    8423         7616 :             appendPQExpBufferChar(tbloids, ',');
    8424         7797 :         appendPQExpBuffer(tbloids, "%u", tinfo->dobj.catId.oid);
    8425              :     }
    8426          262 :     appendPQExpBufferChar(tbloids, '}');
    8427              : 
    8428          262 :     appendPQExpBufferStr(query,
    8429              :                          "SELECT c.tableoid, c.oid, "
    8430              :                          "conrelid, conname, confrelid, ");
    8431          262 :     if (fout->remoteVersion >= 110000)
    8432          262 :         appendPQExpBufferStr(query, "conindid, ");
    8433              :     else
    8434            0 :         appendPQExpBufferStr(query, "0 AS conindid, ");
    8435          262 :     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          262 :     if (fout->remoteVersion >= 110000)
    8442          262 :         appendPQExpBufferStr(query,
    8443              :                              "AND conparentid = 0 ");
    8444          262 :     appendPQExpBufferStr(query,
    8445              :                          "ORDER BY conrelid, conname");
    8446              : 
    8447          262 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    8448              : 
    8449          262 :     ntups = PQntuples(res);
    8450              : 
    8451          262 :     i_contableoid = PQfnumber(res, "tableoid");
    8452          262 :     i_conoid = PQfnumber(res, "oid");
    8453          262 :     i_conrelid = PQfnumber(res, "conrelid");
    8454          262 :     i_conname = PQfnumber(res, "conname");
    8455          262 :     i_confrelid = PQfnumber(res, "confrelid");
    8456          262 :     i_conindid = PQfnumber(res, "conindid");
    8457          262 :     i_condef = PQfnumber(res, "condef");
    8458              : 
    8459          262 :     constrinfo = pg_malloc_array(ConstraintInfo, ntups);
    8460              : 
    8461          262 :     curtblindx = -1;
    8462          499 :     for (int j = 0; j < ntups; j++)
    8463              :     {
    8464          237 :         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          237 :         if (tbinfo == NULL || tbinfo->dobj.catId.oid != conrelid)
    8472              :         {
    8473        16458 :             while (++curtblindx < numTables)
    8474              :             {
    8475        16458 :                 tbinfo = &tblinfo[curtblindx];
    8476        16458 :                 if (tbinfo->dobj.catId.oid == conrelid)
    8477          197 :                     break;
    8478              :             }
    8479          197 :             if (curtblindx >= numTables)
    8480            0 :                 pg_fatal("unrecognized table OID %u", conrelid);
    8481              :         }
    8482              : 
    8483          237 :         constrinfo[j].dobj.objType = DO_FK_CONSTRAINT;
    8484          237 :         constrinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_contableoid));
    8485          237 :         constrinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_conoid));
    8486          237 :         AssignDumpId(&constrinfo[j].dobj);
    8487          237 :         constrinfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_conname));
    8488          237 :         constrinfo[j].dobj.namespace = tbinfo->dobj.namespace;
    8489          237 :         constrinfo[j].contable = tbinfo;
    8490          237 :         constrinfo[j].condomain = NULL;
    8491          237 :         constrinfo[j].contype = 'f';
    8492          237 :         constrinfo[j].condef = pg_strdup(PQgetvalue(res, j, i_condef));
    8493          237 :         constrinfo[j].confrelid = atooid(PQgetvalue(res, j, i_confrelid));
    8494          237 :         constrinfo[j].conindex = 0;
    8495          237 :         constrinfo[j].condeferrable = false;
    8496          237 :         constrinfo[j].condeferred = false;
    8497          237 :         constrinfo[j].conislocal = true;
    8498          237 :         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          237 :         reftable = findTableByOid(constrinfo[j].confrelid);
    8507          237 :         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          262 :     PQclear(res);
    8530              : 
    8531          262 :     destroyPQExpBuffer(query);
    8532          262 :     destroyPQExpBuffer(tbloids);
    8533          262 : }
    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          181 : getDomainConstraints(Archive *fout, TypeInfo *tyinfo)
    8571              : {
    8572              :     ConstraintInfo *constrinfo;
    8573          181 :     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          181 :     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           46 :         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           46 :                           fout->remoteVersion < 170000 ? "'c'" : "'c', 'n'");
    8599              : 
    8600           46 :         ExecuteSqlStatement(fout, query->data);
    8601              : 
    8602           46 :         fout->is_prepared[PREPQUERY_GETDOMAINCONSTRAINTS] = true;
    8603              :     }
    8604              : 
    8605          181 :     printfPQExpBuffer(query,
    8606              :                       "EXECUTE getDomainConstraints('%u')",
    8607              :                       tyinfo->dobj.catId.oid);
    8608              : 
    8609          181 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    8610              : 
    8611          181 :     ntups = PQntuples(res);
    8612              : 
    8613          181 :     i_tableoid = PQfnumber(res, "tableoid");
    8614          181 :     i_oid = PQfnumber(res, "oid");
    8615          181 :     i_conname = PQfnumber(res, "conname");
    8616          181 :     i_consrc = PQfnumber(res, "consrc");
    8617          181 :     i_convalidated = PQfnumber(res, "convalidated");
    8618          181 :     i_contype = PQfnumber(res, "contype");
    8619              : 
    8620          181 :     constrinfo = pg_malloc_array(ConstraintInfo, ntups);
    8621          181 :     tyinfo->domChecks = constrinfo;
    8622              : 
    8623              :     /* 'i' tracks result rows; 'j' counts CHECK constraints */
    8624          373 :     for (int i = 0, j = 0; i < ntups; i++)
    8625              :     {
    8626          192 :         bool        validated = PQgetvalue(res, i, i_convalidated)[0] == 't';
    8627          192 :         char        contype = (PQgetvalue(res, i, i_contype))[0];
    8628              :         ConstraintInfo *constraint;
    8629              : 
    8630          192 :         if (contype == CONSTRAINT_CHECK)
    8631              :         {
    8632          136 :             constraint = &constrinfo[j++];
    8633          136 :             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           56 :             tyinfo->notnull = &(constrinfo[ntups - 1]);
    8641           56 :             constraint = tyinfo->notnull;
    8642              :         }
    8643              : 
    8644          192 :         constraint->dobj.objType = DO_CONSTRAINT;
    8645          192 :         constraint->dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    8646          192 :         constraint->dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    8647          192 :         AssignDumpId(&(constraint->dobj));
    8648          192 :         constraint->dobj.name = pg_strdup(PQgetvalue(res, i, i_conname));
    8649          192 :         constraint->dobj.namespace = tyinfo->dobj.namespace;
    8650          192 :         constraint->contable = NULL;
    8651          192 :         constraint->condomain = tyinfo;
    8652          192 :         constraint->contype = contype;
    8653          192 :         constraint->condef = pg_strdup(PQgetvalue(res, i, i_consrc));
    8654          192 :         constraint->confrelid = InvalidOid;
    8655          192 :         constraint->conindex = 0;
    8656          192 :         constraint->condeferrable = false;
    8657          192 :         constraint->condeferred = false;
    8658          192 :         constraint->conislocal = true;
    8659              : 
    8660          192 :         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          192 :         if (validated)
    8669          187 :             addObjectDependency(&tyinfo->dobj, constraint->dobj.dumpId);
    8670              :     }
    8671              : 
    8672          181 :     PQclear(res);
    8673              : 
    8674          181 :     destroyPQExpBuffer(query);
    8675          181 : }
    8676              : 
    8677              : /*
    8678              :  * getRules
    8679              :  *    get basic information about every rule in the system
    8680              :  */
    8681              : void
    8682          262 : getRules(Archive *fout)
    8683              : {
    8684              :     PGresult   *res;
    8685              :     int         ntups;
    8686              :     int         i;
    8687          262 :     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          262 :     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          262 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    8705              : 
    8706          262 :     ntups = PQntuples(res);
    8707              : 
    8708          262 :     ruleinfo = pg_malloc_array(RuleInfo, ntups);
    8709              : 
    8710          262 :     i_tableoid = PQfnumber(res, "tableoid");
    8711          262 :     i_oid = PQfnumber(res, "oid");
    8712          262 :     i_rulename = PQfnumber(res, "rulename");
    8713          262 :     i_ruletable = PQfnumber(res, "ruletable");
    8714          262 :     i_ev_type = PQfnumber(res, "ev_type");
    8715          262 :     i_is_instead = PQfnumber(res, "is_instead");
    8716          262 :     i_ev_enabled = PQfnumber(res, "ev_enabled");
    8717              : 
    8718        44431 :     for (i = 0; i < ntups; i++)
    8719              :     {
    8720              :         Oid         ruletableoid;
    8721              : 
    8722        44169 :         ruleinfo[i].dobj.objType = DO_RULE;
    8723        44169 :         ruleinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    8724        44169 :         ruleinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    8725        44169 :         AssignDumpId(&ruleinfo[i].dobj);
    8726        44169 :         ruleinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_rulename));
    8727        44169 :         ruletableoid = atooid(PQgetvalue(res, i, i_ruletable));
    8728        44169 :         ruleinfo[i].ruletable = findTableByOid(ruletableoid);
    8729        44169 :         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        44169 :         ruleinfo[i].dobj.namespace = ruleinfo[i].ruletable->dobj.namespace;
    8733        44169 :         ruleinfo[i].dobj.dump = ruleinfo[i].ruletable->dobj.dump;
    8734        44169 :         ruleinfo[i].ev_type = *(PQgetvalue(res, i, i_ev_type));
    8735        44169 :         ruleinfo[i].is_instead = *(PQgetvalue(res, i, i_is_instead)) == 't';
    8736        44169 :         ruleinfo[i].ev_enabled = *(PQgetvalue(res, i, i_ev_enabled));
    8737        44169 :         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        44169 :             if ((ruleinfo[i].ruletable->relkind == RELKIND_VIEW ||
    8747          726 :                  ruleinfo[i].ruletable->relkind == RELKIND_MATVIEW) &&
    8748        43938 :                 ruleinfo[i].ev_type == '1' && ruleinfo[i].is_instead)
    8749              :             {
    8750        43372 :                 addObjectDependency(&ruleinfo[i].ruletable->dobj,
    8751        43372 :                                     ruleinfo[i].dobj.dumpId);
    8752              :                 /* We'll merge the rule into CREATE VIEW, if possible */
    8753        43372 :                 ruleinfo[i].separate = false;
    8754              :             }
    8755              :             else
    8756              :             {
    8757          797 :                 addObjectDependency(&ruleinfo[i].dobj,
    8758          797 :                                     ruleinfo[i].ruletable->dobj.dumpId);
    8759          797 :                 ruleinfo[i].separate = true;
    8760              :             }
    8761              :         }
    8762              :         else
    8763            0 :             ruleinfo[i].separate = true;
    8764              :     }
    8765              : 
    8766          262 :     PQclear(res);
    8767              : 
    8768          262 :     destroyPQExpBuffer(query);
    8769          262 : }
    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          262 : getTriggers(Archive *fout, TableInfo tblinfo[], int numTables)
    8780              : {
    8781          262 :     PQExpBuffer query = createPQExpBuffer();
    8782          262 :     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          262 :     appendPQExpBufferChar(tbloids, '{');
    8804        71878 :     for (int i = 0; i < numTables; i++)
    8805              :     {
    8806        71616 :         TableInfo  *tbinfo = &tblinfo[i];
    8807              : 
    8808        71616 :         if (!tbinfo->hastriggers ||
    8809         1260 :             !(tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
    8810        70656 :             continue;
    8811              : 
    8812              :         /* OK, we need info for this table */
    8813          960 :         if (tbloids->len > 1) /* do we have more than the '{'? */
    8814          906 :             appendPQExpBufferChar(tbloids, ',');
    8815          960 :         appendPQExpBuffer(tbloids, "%u", tbinfo->dobj.catId.oid);
    8816              :     }
    8817          262 :     appendPQExpBufferChar(tbloids, '}');
    8818              : 
    8819          262 :     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          262 :         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          262 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    8903              : 
    8904          262 :     ntups = PQntuples(res);
    8905              : 
    8906          262 :     i_tableoid = PQfnumber(res, "tableoid");
    8907          262 :     i_oid = PQfnumber(res, "oid");
    8908          262 :     i_tgrelid = PQfnumber(res, "tgrelid");
    8909          262 :     i_tgname = PQfnumber(res, "tgname");
    8910          262 :     i_tgenabled = PQfnumber(res, "tgenabled");
    8911          262 :     i_tgispartition = PQfnumber(res, "tgispartition");
    8912          262 :     i_tgdef = PQfnumber(res, "tgdef");
    8913              : 
    8914          262 :     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          262 :     curtblindx = -1;
    8921          580 :     for (int j = 0; j < ntups;)
    8922              :     {
    8923          318 :         Oid         tgrelid = atooid(PQgetvalue(res, j, i_tgrelid));
    8924          318 :         TableInfo  *tbinfo = NULL;
    8925              :         int         numtrigs;
    8926              : 
    8927              :         /* Count rows for this table */
    8928          535 :         for (numtrigs = 1; numtrigs < ntups - j; numtrigs++)
    8929          481 :             if (atooid(PQgetvalue(res, j + numtrigs, i_tgrelid)) != tgrelid)
    8930          264 :                 break;
    8931              : 
    8932              :         /*
    8933              :          * Locate the associated TableInfo; we rely on tblinfo[] being in OID
    8934              :          * order.
    8935              :          */
    8936        18247 :         while (++curtblindx < numTables)
    8937              :         {
    8938        18247 :             tbinfo = &tblinfo[curtblindx];
    8939        18247 :             if (tbinfo->dobj.catId.oid == tgrelid)
    8940          318 :                 break;
    8941              :         }
    8942          318 :         if (curtblindx >= numTables)
    8943            0 :             pg_fatal("unrecognized table OID %u", tgrelid);
    8944              : 
    8945              :         /* Save data for this table */
    8946          318 :         tbinfo->triggers = tginfo + j;
    8947          318 :         tbinfo->numTriggers = numtrigs;
    8948              : 
    8949          853 :         for (int c = 0; c < numtrigs; c++, j++)
    8950              :         {
    8951          535 :             tginfo[j].dobj.objType = DO_TRIGGER;
    8952          535 :             tginfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
    8953          535 :             tginfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
    8954          535 :             AssignDumpId(&tginfo[j].dobj);
    8955          535 :             tginfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_tgname));
    8956          535 :             tginfo[j].dobj.namespace = tbinfo->dobj.namespace;
    8957          535 :             tginfo[j].tgtable = tbinfo;
    8958          535 :             tginfo[j].tgenabled = *(PQgetvalue(res, j, i_tgenabled));
    8959          535 :             tginfo[j].tgispartition = *(PQgetvalue(res, j, i_tgispartition)) == 't';
    8960          535 :             tginfo[j].tgdef = pg_strdup(PQgetvalue(res, j, i_tgdef));
    8961              :         }
    8962              :     }
    8963              : 
    8964          262 :     PQclear(res);
    8965              : 
    8966          262 :     destroyPQExpBuffer(query);
    8967          262 :     destroyPQExpBuffer(tbloids);
    8968          262 : }
    8969              : 
    8970              : /*
    8971              :  * getEventTriggers
    8972              :  *    get information about event triggers
    8973              :  */
    8974              : void
    8975          262 : 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          262 :     if (fout->remoteVersion < 90300)
    8993            0 :         return;
    8994              : 
    8995          262 :     query = createPQExpBuffer();
    8996              : 
    8997          262 :     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          262 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    9008              : 
    9009          262 :     ntups = PQntuples(res);
    9010              : 
    9011          262 :     evtinfo = pg_malloc_array(EventTriggerInfo, ntups);
    9012              : 
    9013          262 :     i_tableoid = PQfnumber(res, "tableoid");
    9014          262 :     i_oid = PQfnumber(res, "oid");
    9015          262 :     i_evtname = PQfnumber(res, "evtname");
    9016          262 :     i_evtevent = PQfnumber(res, "evtevent");
    9017          262 :     i_evtowner = PQfnumber(res, "evtowner");
    9018          262 :     i_evttags = PQfnumber(res, "evttags");
    9019          262 :     i_evtfname = PQfnumber(res, "evtfname");
    9020          262 :     i_evtenabled = PQfnumber(res, "evtenabled");
    9021              : 
    9022          317 :     for (i = 0; i < ntups; i++)
    9023              :     {
    9024           55 :         evtinfo[i].dobj.objType = DO_EVENT_TRIGGER;
    9025           55 :         evtinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    9026           55 :         evtinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    9027           55 :         AssignDumpId(&evtinfo[i].dobj);
    9028           55 :         evtinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_evtname));
    9029           55 :         evtinfo[i].evtname = pg_strdup(PQgetvalue(res, i, i_evtname));
    9030           55 :         evtinfo[i].evtevent = pg_strdup(PQgetvalue(res, i, i_evtevent));
    9031           55 :         evtinfo[i].evtowner = getRoleName(PQgetvalue(res, i, i_evtowner));
    9032           55 :         evtinfo[i].evttags = pg_strdup(PQgetvalue(res, i, i_evttags));
    9033           55 :         evtinfo[i].evtfname = pg_strdup(PQgetvalue(res, i, i_evtfname));
    9034           55 :         evtinfo[i].evtenabled = *(PQgetvalue(res, i, i_evtenabled));
    9035              : 
    9036              :         /* Decide whether we want to dump it */
    9037           55 :         selectDumpableObject(&(evtinfo[i].dobj), fout);
    9038              :     }
    9039              : 
    9040          262 :     PQclear(res);
    9041              : 
    9042          262 :     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          262 : getProcLangs(Archive *fout)
    9054              : {
    9055              :     PGresult   *res;
    9056              :     int         ntups;
    9057              :     int         i;
    9058          262 :     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          262 :     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          262 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    9082              : 
    9083          262 :     ntups = PQntuples(res);
    9084              : 
    9085          262 :     planginfo = pg_malloc_array(ProcLangInfo, ntups);
    9086              : 
    9087          262 :     i_tableoid = PQfnumber(res, "tableoid");
    9088          262 :     i_oid = PQfnumber(res, "oid");
    9089          262 :     i_lanname = PQfnumber(res, "lanname");
    9090          262 :     i_lanpltrusted = PQfnumber(res, "lanpltrusted");
    9091          262 :     i_lanplcallfoid = PQfnumber(res, "lanplcallfoid");
    9092          262 :     i_laninline = PQfnumber(res, "laninline");
    9093          262 :     i_lanvalidator = PQfnumber(res, "lanvalidator");
    9094          262 :     i_lanacl = PQfnumber(res, "lanacl");
    9095          262 :     i_acldefault = PQfnumber(res, "acldefault");
    9096          262 :     i_lanowner = PQfnumber(res, "lanowner");
    9097              : 
    9098          572 :     for (i = 0; i < ntups; i++)
    9099              :     {
    9100          310 :         planginfo[i].dobj.objType = DO_PROCLANG;
    9101          310 :         planginfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    9102          310 :         planginfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    9103          310 :         AssignDumpId(&planginfo[i].dobj);
    9104              : 
    9105          310 :         planginfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_lanname));
    9106          310 :         planginfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_lanacl));
    9107          310 :         planginfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
    9108          310 :         planginfo[i].dacl.privtype = 0;
    9109          310 :         planginfo[i].dacl.initprivs = NULL;
    9110          310 :         planginfo[i].lanpltrusted = *(PQgetvalue(res, i, i_lanpltrusted)) == 't';
    9111          310 :         planginfo[i].lanplcallfoid = atooid(PQgetvalue(res, i, i_lanplcallfoid));
    9112          310 :         planginfo[i].laninline = atooid(PQgetvalue(res, i, i_laninline));
    9113          310 :         planginfo[i].lanvalidator = atooid(PQgetvalue(res, i, i_lanvalidator));
    9114          310 :         planginfo[i].lanowner = getRoleName(PQgetvalue(res, i, i_lanowner));
    9115              : 
    9116              :         /* Decide whether we want to dump it */
    9117          310 :         selectDumpableProcLang(&(planginfo[i]), fout);
    9118              : 
    9119              :         /* Mark whether language has an ACL */
    9120          310 :         if (!PQgetisnull(res, i, i_lanacl))
    9121           48 :             planginfo[i].dobj.components |= DUMP_COMPONENT_ACL;
    9122              :     }
    9123              : 
    9124          262 :     PQclear(res);
    9125              : 
    9126          262 :     destroyPQExpBuffer(query);
    9127          262 : }
    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          262 : getCasts(Archive *fout)
    9138              : {
    9139              :     PGresult   *res;
    9140              :     int         ntups;
    9141              :     int         i;
    9142          262 :     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          262 :     if (fout->remoteVersion >= 140000)
    9153              :     {
    9154          262 :         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          262 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    9174              : 
    9175          262 :     ntups = PQntuples(res);
    9176              : 
    9177          262 :     castinfo = pg_malloc_array(CastInfo, ntups);
    9178              : 
    9179          262 :     i_tableoid = PQfnumber(res, "tableoid");
    9180          262 :     i_oid = PQfnumber(res, "oid");
    9181          262 :     i_castsource = PQfnumber(res, "castsource");
    9182          262 :     i_casttarget = PQfnumber(res, "casttarget");
    9183          262 :     i_castfunc = PQfnumber(res, "castfunc");
    9184          262 :     i_castcontext = PQfnumber(res, "castcontext");
    9185          262 :     i_castmethod = PQfnumber(res, "castmethod");
    9186              : 
    9187        64018 :     for (i = 0; i < ntups; i++)
    9188              :     {
    9189              :         PQExpBufferData namebuf;
    9190              :         TypeInfo   *sTypeInfo;
    9191              :         TypeInfo   *tTypeInfo;
    9192              : 
    9193        63756 :         castinfo[i].dobj.objType = DO_CAST;
    9194        63756 :         castinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    9195        63756 :         castinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    9196        63756 :         AssignDumpId(&castinfo[i].dobj);
    9197        63756 :         castinfo[i].castsource = atooid(PQgetvalue(res, i, i_castsource));
    9198        63756 :         castinfo[i].casttarget = atooid(PQgetvalue(res, i, i_casttarget));
    9199        63756 :         castinfo[i].castfunc = atooid(PQgetvalue(res, i, i_castfunc));
    9200        63756 :         castinfo[i].castcontext = *(PQgetvalue(res, i, i_castcontext));
    9201        63756 :         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        63756 :         initPQExpBuffer(&namebuf);
    9209        63756 :         sTypeInfo = findTypeByOid(castinfo[i].castsource);
    9210        63756 :         tTypeInfo = findTypeByOid(castinfo[i].casttarget);
    9211        63756 :         if (sTypeInfo && tTypeInfo)
    9212        63756 :             appendPQExpBuffer(&namebuf, "%s %s",
    9213              :                               sTypeInfo->dobj.name, tTypeInfo->dobj.name);
    9214        63756 :         castinfo[i].dobj.name = namebuf.data;
    9215              : 
    9216              :         /* Decide whether we want to dump it */
    9217        63756 :         selectDumpableCast(&(castinfo[i]), fout);
    9218              :     }
    9219              : 
    9220          262 :     PQclear(res);
    9221              : 
    9222          262 :     destroyPQExpBuffer(query);
    9223          262 : }
    9224              : 
    9225              : static char *
    9226           93 : get_language_name(Archive *fout, Oid langid)
    9227              : {
    9228              :     PQExpBuffer query;
    9229              :     PGresult   *res;
    9230              :     char       *lanname;
    9231              : 
    9232           93 :     query = createPQExpBuffer();
    9233           93 :     appendPQExpBuffer(query, "SELECT lanname FROM pg_language WHERE oid = %u", langid);
    9234           93 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
    9235           93 :     lanname = pg_strdup(fmtId(PQgetvalue(res, 0, 0)));
    9236           93 :     destroyPQExpBuffer(query);
    9237           93 :     PQclear(res);
    9238              : 
    9239           93 :     return lanname;
    9240              : }
    9241              : 
    9242              : /*
    9243              :  * getTransforms
    9244              :  *    get basic information about every transform in the system
    9245              :  */
    9246              : void
    9247          262 : 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          262 :     if (fout->remoteVersion < 90500)
    9263            0 :         return;
    9264              : 
    9265          262 :     query = createPQExpBuffer();
    9266              : 
    9267          262 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, "
    9268              :                          "trftype, trflang, trffromsql::oid, trftosql::oid "
    9269              :                          "FROM pg_transform "
    9270              :                          "ORDER BY 3,4");
    9271              : 
    9272          262 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    9273              : 
    9274          262 :     ntups = PQntuples(res);
    9275              : 
    9276          262 :     transforminfo = pg_malloc_array(TransformInfo, ntups);
    9277              : 
    9278          262 :     i_tableoid = PQfnumber(res, "tableoid");
    9279          262 :     i_oid = PQfnumber(res, "oid");
    9280          262 :     i_trftype = PQfnumber(res, "trftype");
    9281          262 :     i_trflang = PQfnumber(res, "trflang");
    9282          262 :     i_trffromsql = PQfnumber(res, "trffromsql");
    9283          262 :     i_trftosql = PQfnumber(res, "trftosql");
    9284              : 
    9285          317 :     for (i = 0; i < ntups; i++)
    9286              :     {
    9287              :         PQExpBufferData namebuf;
    9288              :         TypeInfo   *typeInfo;
    9289              :         char       *lanname;
    9290              : 
    9291           55 :         transforminfo[i].dobj.objType = DO_TRANSFORM;
    9292           55 :         transforminfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    9293           55 :         transforminfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    9294           55 :         AssignDumpId(&transforminfo[i].dobj);
    9295           55 :         transforminfo[i].trftype = atooid(PQgetvalue(res, i, i_trftype));
    9296           55 :         transforminfo[i].trflang = atooid(PQgetvalue(res, i, i_trflang));
    9297           55 :         transforminfo[i].trffromsql = atooid(PQgetvalue(res, i, i_trffromsql));
    9298           55 :         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           55 :         initPQExpBuffer(&namebuf);
    9306           55 :         typeInfo = findTypeByOid(transforminfo[i].trftype);
    9307           55 :         lanname = get_language_name(fout, transforminfo[i].trflang);
    9308           55 :         if (typeInfo && lanname)
    9309           55 :             appendPQExpBuffer(&namebuf, "%s %s",
    9310              :                               typeInfo->dobj.name, lanname);
    9311           55 :         transforminfo[i].dobj.name = namebuf.data;
    9312           55 :         free(lanname);
    9313              : 
    9314              :         /* Decide whether we want to dump it */
    9315           55 :         selectDumpableObject(&(transforminfo[i].dobj), fout);
    9316              :     }
    9317              : 
    9318          262 :     PQclear(res);
    9319              : 
    9320          262 :     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          262 : getTableAttrs(Archive *fout, TableInfo *tblinfo, int numTables)
    9332              : {
    9333          262 :     DumpOptions *dopt = fout->dopt;
    9334          262 :     PQExpBuffer q = createPQExpBuffer();
    9335          262 :     PQExpBuffer tbloids = createPQExpBuffer();
    9336          262 :     PQExpBuffer checkoids = createPQExpBuffer();
    9337          262 :     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          262 :     appendPQExpBufferChar(tbloids, '{');
    9377          262 :     appendPQExpBufferChar(checkoids, '{');
    9378        71878 :     for (int i = 0; i < numTables; i++)
    9379              :     {
    9380        71616 :         TableInfo  *tbinfo = &tblinfo[i];
    9381              : 
    9382              :         /* Don't bother to collect info for sequences */
    9383        71616 :         if (tbinfo->relkind == RELKIND_SEQUENCE)
    9384          656 :             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        70960 :         if (!tbinfo->interesting &&
    9395        63534 :             !(fout->dopt->binary_upgrade &&
    9396         9418 :               (tbinfo->dobj.catId.oid == LargeObjectMetadataRelationId ||
    9397         9378 :                tbinfo->dobj.catId.oid == SharedDependRelationId)))
    9398        63454 :             continue;
    9399              : 
    9400              :         /* OK, we need info for this table */
    9401         7506 :         if (tbloids->len > 1) /* do we have more than the '{'? */
    9402         7304 :             appendPQExpBufferChar(tbloids, ',');
    9403         7506 :         appendPQExpBuffer(tbloids, "%u", tbinfo->dobj.catId.oid);
    9404              : 
    9405         7506 :         if (tbinfo->ncheck > 0)
    9406              :         {
    9407              :             /* Also make a list of the ones with check constraints */
    9408          548 :             if (checkoids->len > 1) /* do we have more than the '{'? */
    9409          476 :                 appendPQExpBufferChar(checkoids, ',');
    9410          548 :             appendPQExpBuffer(checkoids, "%u", tbinfo->dobj.catId.oid);
    9411              :         }
    9412              :     }
    9413          262 :     appendPQExpBufferChar(tbloids, '}');
    9414          262 :     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          262 :     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          262 :     if (fout->remoteVersion >= 180000)
    9466          262 :         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          262 :     if (fout->remoteVersion >= 140000)
    9486          262 :         appendPQExpBufferStr(q,
    9487              :                              "a.attcompression AS attcompression,\n");
    9488              :     else
    9489            0 :         appendPQExpBufferStr(q,
    9490              :                              "'' AS attcompression,\n");
    9491              : 
    9492          262 :     if (fout->remoteVersion >= 100000)
    9493          262 :         appendPQExpBufferStr(q,
    9494              :                              "a.attidentity,\n");
    9495              :     else
    9496            0 :         appendPQExpBufferStr(q,
    9497              :                              "'' AS attidentity,\n");
    9498              : 
    9499          262 :     if (fout->remoteVersion >= 110000)
    9500          262 :         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          262 :     if (fout->remoteVersion >= 120000)
    9508          262 :         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          262 :     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          262 :     if (fout->remoteVersion >= 180000)
    9527          262 :         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          262 :     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          262 :     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          262 :     appendPQExpBufferStr(q,
    9548              :                          "ORDER BY a.attrelid, a.attnum");
    9549              : 
    9550          262 :     res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
    9551              : 
    9552          262 :     ntups = PQntuples(res);
    9553              : 
    9554          262 :     i_attrelid = PQfnumber(res, "attrelid");
    9555          262 :     i_attnum = PQfnumber(res, "attnum");
    9556          262 :     i_attname = PQfnumber(res, "attname");
    9557          262 :     i_atttypname = PQfnumber(res, "atttypname");
    9558          262 :     i_attstattarget = PQfnumber(res, "attstattarget");
    9559          262 :     i_attstorage = PQfnumber(res, "attstorage");
    9560          262 :     i_typstorage = PQfnumber(res, "typstorage");
    9561          262 :     i_attidentity = PQfnumber(res, "attidentity");
    9562          262 :     i_attgenerated = PQfnumber(res, "attgenerated");
    9563          262 :     i_attisdropped = PQfnumber(res, "attisdropped");
    9564          262 :     i_attlen = PQfnumber(res, "attlen");
    9565          262 :     i_attalign = PQfnumber(res, "attalign");
    9566          262 :     i_attislocal = PQfnumber(res, "attislocal");
    9567          262 :     i_notnull_name = PQfnumber(res, "notnull_name");
    9568          262 :     i_notnull_comment = PQfnumber(res, "notnull_comment");
    9569          262 :     i_notnull_invalidoid = PQfnumber(res, "notnull_invalidoid");
    9570          262 :     i_notnull_noinherit = PQfnumber(res, "notnull_noinherit");
    9571          262 :     i_notnull_islocal = PQfnumber(res, "notnull_islocal");
    9572          262 :     i_attoptions = PQfnumber(res, "attoptions");
    9573          262 :     i_attcollation = PQfnumber(res, "attcollation");
    9574          262 :     i_attcompression = PQfnumber(res, "attcompression");
    9575          262 :     i_attfdwoptions = PQfnumber(res, "attfdwoptions");
    9576          262 :     i_attmissingval = PQfnumber(res, "attmissingval");
    9577          262 :     i_atthasdef = PQfnumber(res, "atthasdef");
    9578              : 
    9579              :     /* Within the next loop, we'll accumulate OIDs of tables with defaults */
    9580          262 :     resetPQExpBuffer(tbloids);
    9581          262 :     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          262 :     curtblindx = -1;
    9588         7515 :     for (int r = 0; r < ntups;)
    9589              :     {
    9590         7253 :         Oid         attrelid = atooid(PQgetvalue(res, r, i_attrelid));
    9591         7253 :         TableInfo  *tbinfo = NULL;
    9592              :         int         numatts;
    9593              :         bool        hasdefaults;
    9594              : 
    9595              :         /* Count rows for this table */
    9596        26714 :         for (numatts = 1; numatts < ntups - r; numatts++)
    9597        26515 :             if (atooid(PQgetvalue(res, r + numatts, i_attrelid)) != attrelid)
    9598         7054 :                 break;
    9599              : 
    9600              :         /*
    9601              :          * Locate the associated TableInfo; we rely on tblinfo[] being in OID
    9602              :          * order.
    9603              :          */
    9604        50667 :         while (++curtblindx < numTables)
    9605              :         {
    9606        50667 :             tbinfo = &tblinfo[curtblindx];
    9607        50667 :             if (tbinfo->dobj.catId.oid == attrelid)
    9608         7253 :                 break;
    9609              :         }
    9610         7253 :         if (curtblindx >= numTables)
    9611            0 :             pg_fatal("unrecognized table OID %u", attrelid);
    9612              :         /* cross-check that we only got requested tables */
    9613         7253 :         if (tbinfo->relkind == RELKIND_SEQUENCE ||
    9614         7253 :             (!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         7253 :         tbinfo->numatts = numatts;
    9623         7253 :         tbinfo->attnames = pg_malloc_array(char *, numatts);
    9624         7253 :         tbinfo->atttypnames = pg_malloc_array(char *, numatts);
    9625         7253 :         tbinfo->attstattarget = pg_malloc_array(int, numatts);
    9626         7253 :         tbinfo->attstorage = pg_malloc_array(char, numatts);
    9627         7253 :         tbinfo->typstorage = pg_malloc_array(char, numatts);
    9628         7253 :         tbinfo->attidentity = pg_malloc_array(char, numatts);
    9629         7253 :         tbinfo->attgenerated = pg_malloc_array(char, numatts);
    9630         7253 :         tbinfo->attisdropped = pg_malloc_array(bool, numatts);
    9631         7253 :         tbinfo->attlen = pg_malloc_array(int, numatts);
    9632         7253 :         tbinfo->attalign = pg_malloc_array(char, numatts);
    9633         7253 :         tbinfo->attislocal = pg_malloc_array(bool, numatts);
    9634         7253 :         tbinfo->attoptions = pg_malloc_array(char *, numatts);
    9635         7253 :         tbinfo->attcollation = pg_malloc_array(Oid, numatts);
    9636         7253 :         tbinfo->attcompression = pg_malloc_array(char, numatts);
    9637         7253 :         tbinfo->attfdwoptions = pg_malloc_array(char *, numatts);
    9638         7253 :         tbinfo->attmissingval = pg_malloc_array(char *, numatts);
    9639         7253 :         tbinfo->notnull_constrs = pg_malloc_array(char *, numatts);
    9640         7253 :         tbinfo->notnull_comment = pg_malloc_array(char *, numatts);
    9641         7253 :         tbinfo->notnull_invalid = pg_malloc_array(bool, numatts);
    9642         7253 :         tbinfo->notnull_noinh = pg_malloc_array(bool, numatts);
    9643         7253 :         tbinfo->notnull_islocal = pg_malloc_array(bool, numatts);
    9644         7253 :         tbinfo->attrdefs = pg_malloc_array(AttrDefInfo *, numatts);
    9645         7253 :         hasdefaults = false;
    9646              : 
    9647        33967 :         for (int j = 0; j < numatts; j++, r++)
    9648              :         {
    9649        26714 :             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        26714 :             tbinfo->attnames[j] = pg_strdup(PQgetvalue(res, r, i_attname));
    9655        26714 :             tbinfo->atttypnames[j] = pg_strdup(PQgetvalue(res, r, i_atttypname));
    9656        26714 :             if (PQgetisnull(res, r, i_attstattarget))
    9657        26671 :                 tbinfo->attstattarget[j] = -1;
    9658              :             else
    9659           43 :                 tbinfo->attstattarget[j] = atoi(PQgetvalue(res, r, i_attstattarget));
    9660        26714 :             tbinfo->attstorage[j] = *(PQgetvalue(res, r, i_attstorage));
    9661        26714 :             tbinfo->typstorage[j] = *(PQgetvalue(res, r, i_typstorage));
    9662        26714 :             tbinfo->attidentity[j] = *(PQgetvalue(res, r, i_attidentity));
    9663        26714 :             tbinfo->attgenerated[j] = *(PQgetvalue(res, r, i_attgenerated));
    9664        26714 :             tbinfo->needs_override = tbinfo->needs_override || (tbinfo->attidentity[j] == ATTRIBUTE_IDENTITY_ALWAYS);
    9665        26714 :             tbinfo->attisdropped[j] = (PQgetvalue(res, r, i_attisdropped)[0] == 't');
    9666        26714 :             tbinfo->attlen[j] = atoi(PQgetvalue(res, r, i_attlen));
    9667        26714 :             tbinfo->attalign[j] = *(PQgetvalue(res, r, i_attalign));
    9668        26714 :             tbinfo->attislocal[j] = (PQgetvalue(res, r, i_attislocal)[0] == 't');
    9669              : 
    9670              :             /* Handle not-null constraint name and flags */
    9671        26714 :             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        26714 :             tbinfo->notnull_comment[j] = PQgetisnull(res, r, i_notnull_comment) ?
    9681        26714 :                 NULL : pg_strdup(PQgetvalue(res, r, i_notnull_comment));
    9682        26714 :             tbinfo->attoptions[j] = pg_strdup(PQgetvalue(res, r, i_attoptions));
    9683        26714 :             tbinfo->attcollation[j] = atooid(PQgetvalue(res, r, i_attcollation));
    9684        26714 :             tbinfo->attcompression[j] = *(PQgetvalue(res, r, i_attcompression));
    9685        26714 :             tbinfo->attfdwoptions[j] = pg_strdup(PQgetvalue(res, r, i_attfdwoptions));
    9686        26714 :             tbinfo->attmissingval[j] = pg_strdup(PQgetvalue(res, r, i_attmissingval));
    9687        26714 :             tbinfo->attrdefs[j] = NULL; /* fix below */
    9688        26714 :             if (PQgetvalue(res, r, i_atthasdef)[0] == 't')
    9689         1366 :                 hasdefaults = true;
    9690              :         }
    9691              : 
    9692         7253 :         if (hasdefaults)
    9693              :         {
    9694              :             /* Collect OIDs of interesting tables that have defaults */
    9695         1016 :             if (tbloids->len > 1) /* do we have more than the '{'? */
    9696          945 :                 appendPQExpBufferChar(tbloids, ',');
    9697         1016 :             appendPQExpBuffer(tbloids, "%u", tbinfo->dobj.catId.oid);
    9698              :         }
    9699              :     }
    9700              : 
    9701              :     /* If invalidnotnulloids has any data, finalize it */
    9702          262 :     if (invalidnotnulloids != NULL)
    9703           46 :         appendPQExpBufferChar(invalidnotnulloids, '}');
    9704              : 
    9705          262 :     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          262 :     if (dopt->dumpSchema && tbloids->len > 1)
    9712              :     {
    9713              :         AttrDefInfo *attrdefs;
    9714              :         int         numDefaults;
    9715           62 :         TableInfo  *tbinfo = NULL;
    9716              : 
    9717           62 :         pg_log_info("finding table default expressions");
    9718              : 
    9719           62 :         appendPQExpBufferChar(tbloids, '}');
    9720              : 
    9721           62 :         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           62 :         res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
    9729              : 
    9730           62 :         numDefaults = PQntuples(res);
    9731           62 :         attrdefs = pg_malloc_array(AttrDefInfo, numDefaults);
    9732              : 
    9733           62 :         curtblindx = -1;
    9734         1319 :         for (int j = 0; j < numDefaults; j++)
    9735              :         {
    9736         1257 :             Oid         adtableoid = atooid(PQgetvalue(res, j, 0));
    9737         1257 :             Oid         adoid = atooid(PQgetvalue(res, j, 1));
    9738         1257 :             Oid         adrelid = atooid(PQgetvalue(res, j, 2));
    9739         1257 :             int         adnum = atoi(PQgetvalue(res, j, 3));
    9740         1257 :             char       *adsrc = PQgetvalue(res, j, 4);
    9741              : 
    9742              :             /*
    9743              :              * Locate the associated TableInfo; we rely on tblinfo[] being in
    9744              :              * OID order.
    9745              :              */
    9746         1257 :             if (tbinfo == NULL || tbinfo->dobj.catId.oid != adrelid)
    9747              :             {
    9748        20889 :                 while (++curtblindx < numTables)
    9749              :                 {
    9750        20889 :                     tbinfo = &tblinfo[curtblindx];
    9751        20889 :                     if (tbinfo->dobj.catId.oid == adrelid)
    9752          941 :                         break;
    9753              :                 }
    9754          941 :                 if (curtblindx >= numTables)
    9755            0 :                     pg_fatal("unrecognized table OID %u", adrelid);
    9756              :             }
    9757              : 
    9758         1257 :             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         1257 :             if (tbinfo->attisdropped[adnum - 1])
    9767            0 :                 continue;
    9768              : 
    9769         1257 :             attrdefs[j].dobj.objType = DO_ATTRDEF;
    9770         1257 :             attrdefs[j].dobj.catId.tableoid = adtableoid;
    9771         1257 :             attrdefs[j].dobj.catId.oid = adoid;
    9772         1257 :             AssignDumpId(&attrdefs[j].dobj);
    9773         1257 :             attrdefs[j].adtable = tbinfo;
    9774         1257 :             attrdefs[j].adnum = adnum;
    9775         1257 :             attrdefs[j].adef_expr = pg_strdup(adsrc);
    9776              : 
    9777         1257 :             attrdefs[j].dobj.name = pg_strdup(tbinfo->dobj.name);
    9778         1257 :             attrdefs[j].dobj.namespace = tbinfo->dobj.namespace;
    9779              : 
    9780         1257 :             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         1257 :             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          712 :                 attrdefs[j].separate = false;
    9800              :             }
    9801          545 :             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           34 :                 attrdefs[j].separate = true;
    9808              :             }
    9809          511 :             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          507 :                 attrdefs[j].separate = false;
    9817              :             }
    9818              : 
    9819         1257 :             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         1219 :                 addObjectDependency(&tbinfo->dobj,
    9828         1219 :                                     attrdefs[j].dobj.dumpId);
    9829              :             }
    9830              : 
    9831         1257 :             tbinfo->attrdefs[adnum - 1] = &attrdefs[j];
    9832              :         }
    9833              : 
    9834           62 :         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          262 :     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           39 :         pg_log_info("finding invalid not-null constraints");
    9853              : 
    9854           39 :         resetPQExpBuffer(q);
    9855           39 :         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           39 :                           invalidnotnulloids->data);
    9863              : 
    9864           39 :         res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
    9865              : 
    9866           39 :         numConstrs = PQntuples(res);
    9867           39 :         constrs = pg_malloc_array(ConstraintInfo, numConstrs);
    9868              : 
    9869           39 :         i_tableoid = PQfnumber(res, "tableoid");
    9870           39 :         i_oid = PQfnumber(res, "oid");
    9871           39 :         i_conrelid = PQfnumber(res, "conrelid");
    9872           39 :         i_conname = PQfnumber(res, "conname");
    9873           39 :         i_consrc = PQfnumber(res, "consrc");
    9874           39 :         i_conislocal = PQfnumber(res, "conislocal");
    9875              : 
    9876              :         /* As above, this loop iterates once per table, not once per row */
    9877           39 :         curtblindx = -1;
    9878          108 :         for (int j = 0; j < numConstrs;)
    9879              :         {
    9880           69 :             Oid         conrelid = atooid(PQgetvalue(res, j, i_conrelid));
    9881           69 :             TableInfo  *tbinfo = NULL;
    9882              :             int         numcons;
    9883              : 
    9884              :             /* Count rows for this table */
    9885           69 :             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        14357 :             while (++curtblindx < numTables)
    9894              :             {
    9895        14357 :                 tbinfo = &tblinfo[curtblindx];
    9896        14357 :                 if (tbinfo->dobj.catId.oid == conrelid)
    9897           69 :                     break;
    9898              :             }
    9899           69 :             if (curtblindx >= numTables)
    9900            0 :                 pg_fatal("unrecognized table OID %u", conrelid);
    9901              : 
    9902          138 :             for (int c = 0; c < numcons; c++, j++)
    9903              :             {
    9904           69 :                 constrs[j].dobj.objType = DO_CONSTRAINT;
    9905           69 :                 constrs[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
    9906           69 :                 constrs[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
    9907           69 :                 AssignDumpId(&constrs[j].dobj);
    9908           69 :                 constrs[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_conname));
    9909           69 :                 constrs[j].dobj.namespace = tbinfo->dobj.namespace;
    9910           69 :                 constrs[j].contable = tbinfo;
    9911           69 :                 constrs[j].condomain = NULL;
    9912           69 :                 constrs[j].contype = 'n';
    9913           69 :                 constrs[j].condef = pg_strdup(PQgetvalue(res, j, i_consrc));
    9914           69 :                 constrs[j].confrelid = InvalidOid;
    9915           69 :                 constrs[j].conindex = 0;
    9916           69 :                 constrs[j].condeferrable = false;
    9917           69 :                 constrs[j].condeferred = false;
    9918           69 :                 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           69 :                 constrs[j].separate = true;
    9927              : 
    9928           69 :                 constrs[j].dobj.dump = tbinfo->dobj.dump;
    9929              :             }
    9930              :         }
    9931           39 :         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          262 :     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           63 :         pg_log_info("finding table check constraints");
    9951              : 
    9952           63 :         resetPQExpBuffer(q);
    9953           63 :         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           63 :         res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
    9964              : 
    9965           63 :         numConstrs = PQntuples(res);
    9966           63 :         constrs = pg_malloc_array(ConstraintInfo, numConstrs);
    9967              : 
    9968           63 :         i_tableoid = PQfnumber(res, "tableoid");
    9969           63 :         i_oid = PQfnumber(res, "oid");
    9970           63 :         i_conrelid = PQfnumber(res, "conrelid");
    9971           63 :         i_conname = PQfnumber(res, "conname");
    9972           63 :         i_consrc = PQfnumber(res, "consrc");
    9973           63 :         i_conislocal = PQfnumber(res, "conislocal");
    9974           63 :         i_convalidated = PQfnumber(res, "convalidated");
    9975              : 
    9976              :         /* As above, this loop iterates once per table, not once per row */
    9977           63 :         curtblindx = -1;
    9978          556 :         for (int j = 0; j < numConstrs;)
    9979              :         {
    9980          493 :             Oid         conrelid = atooid(PQgetvalue(res, j, i_conrelid));
    9981          493 :             TableInfo  *tbinfo = NULL;
    9982              :             int         numcons;
    9983              : 
    9984              :             /* Count rows for this table */
    9985          632 :             for (numcons = 1; numcons < numConstrs - j; numcons++)
    9986          569 :                 if (atooid(PQgetvalue(res, j + numcons, i_conrelid)) != conrelid)
    9987          430 :                     break;
    9988              : 
    9989              :             /*
    9990              :              * Locate the associated TableInfo; we rely on tblinfo[] being in
    9991              :              * OID order.
    9992              :              */
    9993        20160 :             while (++curtblindx < numTables)
    9994              :             {
    9995        20160 :                 tbinfo = &tblinfo[curtblindx];
    9996        20160 :                 if (tbinfo->dobj.catId.oid == conrelid)
    9997          493 :                     break;
    9998              :             }
    9999          493 :             if (curtblindx >= numTables)
   10000            0 :                 pg_fatal("unrecognized table OID %u", conrelid);
   10001              : 
   10002          493 :             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          493 :             tbinfo->checkexprs = constrs + j;
   10013              : 
   10014         1125 :             for (int c = 0; c < numcons; c++, j++)
   10015              :             {
   10016          632 :                 bool        validated = PQgetvalue(res, j, i_convalidated)[0] == 't';
   10017              : 
   10018          632 :                 constrs[j].dobj.objType = DO_CONSTRAINT;
   10019          632 :                 constrs[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
   10020          632 :                 constrs[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
   10021          632 :                 AssignDumpId(&constrs[j].dobj);
   10022          632 :                 constrs[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_conname));
   10023          632 :                 constrs[j].dobj.namespace = tbinfo->dobj.namespace;
   10024          632 :                 constrs[j].contable = tbinfo;
   10025          632 :                 constrs[j].condomain = NULL;
   10026          632 :                 constrs[j].contype = 'c';
   10027          632 :                 constrs[j].condef = pg_strdup(PQgetvalue(res, j, i_consrc));
   10028          632 :                 constrs[j].confrelid = InvalidOid;
   10029          632 :                 constrs[j].conindex = 0;
   10030          632 :                 constrs[j].condeferrable = false;
   10031          632 :                 constrs[j].condeferred = false;
   10032          632 :                 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          632 :                 constrs[j].separate = !validated;
   10040              : 
   10041          632 :                 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          632 :                 if (!constrs[j].separate)
   10053          567 :                     addObjectDependency(&tbinfo->dobj,
   10054          567 :                                         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           63 :         PQclear(res);
   10064              :     }
   10065              : 
   10066          262 :     destroyPQExpBuffer(q);
   10067          262 :     destroyPQExpBuffer(tbloids);
   10068          262 :     destroyPQExpBuffer(checkoids);
   10069          262 : }
   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        26714 : 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        26714 :     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        26714 :     if (!PQgetisnull(res, r, i_notnull_invalidoid))
   10140              :     {
   10141           76 :         char       *constroid = PQgetvalue(res, r, i_notnull_invalidoid);
   10142              : 
   10143           76 :         if (*invalidnotnulloids == NULL)
   10144              :         {
   10145           46 :             *invalidnotnulloids = createPQExpBuffer();
   10146           46 :             appendPQExpBufferChar(*invalidnotnulloids, '{');
   10147           46 :             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           76 :         tbinfo->notnull_invalid[j] = true;
   10157              : 
   10158              :         /* nothing else to do */
   10159           76 :         tbinfo->notnull_constrs[j] = NULL;
   10160           76 :         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        26638 :     tbinfo->notnull_noinh[j] = PQgetvalue(res, r, i_notnull_noinherit)[0] == 't';
   10168        26638 :     tbinfo->notnull_islocal[j] = PQgetvalue(res, r, i_notnull_islocal)[0] == 't';
   10169        26638 :     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        26638 :     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        26638 :         if (PQgetisnull(res, r, i_notnull_name))
   10191        23667 :             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         2971 :             if ((dopt->binary_upgrade &&
   10200          373 :                  !tbinfo->ispartition &&
   10201         3235 :                  !tbinfo->notnull_islocal[j]) ||
   10202         2950 :                 !PQgetisnull(res, r, i_notnull_comment))
   10203              :             {
   10204           70 :                 tbinfo->notnull_constrs[j] =
   10205           70 :                     pstrdup(PQgetvalue(res, r, i_notnull_name));
   10206              :             }
   10207              :             else
   10208              :             {
   10209              :                 char       *default_name;
   10210              : 
   10211              :                 /* XXX should match ChooseConstraintName better */
   10212         2901 :                 default_name = psprintf("%s_%s_not_null", tbinfo->dobj.name,
   10213         2901 :                                         tbinfo->attnames[j]);
   10214         2901 :                 if (strcmp(default_name,
   10215         2901 :                            PQgetvalue(res, r, i_notnull_name)) == 0)
   10216         1937 :                     tbinfo->notnull_constrs[j] = "";
   10217              :                 else
   10218              :                 {
   10219          964 :                     tbinfo->notnull_constrs[j] =
   10220          964 :                         pstrdup(PQgetvalue(res, r, i_notnull_name));
   10221              :                 }
   10222         2901 :                 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        43282 : shouldPrintColumn(const DumpOptions *dopt, const TableInfo *tbinfo, int colno)
   10247              : {
   10248        43282 :     if (dopt->binary_upgrade)
   10249         6602 :         return true;
   10250        36680 :     if (tbinfo->attisdropped[colno])
   10251          738 :         return false;
   10252        35942 :     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          262 : 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          262 :     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          262 :     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          262 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   10291              : 
   10292          262 :     ntups = PQntuples(res);
   10293              : 
   10294          262 :     prsinfo = pg_malloc_array(TSParserInfo, ntups);
   10295              : 
   10296          262 :     i_tableoid = PQfnumber(res, "tableoid");
   10297          262 :     i_oid = PQfnumber(res, "oid");
   10298          262 :     i_prsname = PQfnumber(res, "prsname");
   10299          262 :     i_prsnamespace = PQfnumber(res, "prsnamespace");
   10300          262 :     i_prsstart = PQfnumber(res, "prsstart");
   10301          262 :     i_prstoken = PQfnumber(res, "prstoken");
   10302          262 :     i_prsend = PQfnumber(res, "prsend");
   10303          262 :     i_prsheadline = PQfnumber(res, "prsheadline");
   10304          262 :     i_prslextype = PQfnumber(res, "prslextype");
   10305              : 
   10306          572 :     for (i = 0; i < ntups; i++)
   10307              :     {
   10308          310 :         prsinfo[i].dobj.objType = DO_TSPARSER;
   10309          310 :         prsinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
   10310          310 :         prsinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
   10311          310 :         AssignDumpId(&prsinfo[i].dobj);
   10312          310 :         prsinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_prsname));
   10313          620 :         prsinfo[i].dobj.namespace =
   10314          310 :             findNamespace(atooid(PQgetvalue(res, i, i_prsnamespace)));
   10315          310 :         prsinfo[i].prsstart = atooid(PQgetvalue(res, i, i_prsstart));
   10316          310 :         prsinfo[i].prstoken = atooid(PQgetvalue(res, i, i_prstoken));
   10317          310 :         prsinfo[i].prsend = atooid(PQgetvalue(res, i, i_prsend));
   10318          310 :         prsinfo[i].prsheadline = atooid(PQgetvalue(res, i, i_prsheadline));
   10319          310 :         prsinfo[i].prslextype = atooid(PQgetvalue(res, i, i_prslextype));
   10320              : 
   10321              :         /* Decide whether we want to dump it */
   10322          310 :         selectDumpableObject(&(prsinfo[i].dobj), fout);
   10323              :     }
   10324              : 
   10325          262 :     PQclear(res);
   10326              : 
   10327          262 :     destroyPQExpBuffer(query);
   10328          262 : }
   10329              : 
   10330              : /*
   10331              :  * getTSDictionaries:
   10332              :  *    get information about all text search dictionaries in the system catalogs
   10333              :  */
   10334              : void
   10335          262 : 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          262 :     query = createPQExpBuffer();
   10351              : 
   10352          262 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, dictname, "
   10353              :                          "dictnamespace, dictowner, "
   10354              :                          "dicttemplate, dictinitoption "
   10355              :                          "FROM pg_ts_dict");
   10356              : 
   10357          262 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   10358              : 
   10359          262 :     ntups = PQntuples(res);
   10360              : 
   10361          262 :     dictinfo = pg_malloc_array(TSDictInfo, ntups);
   10362              : 
   10363          262 :     i_tableoid = PQfnumber(res, "tableoid");
   10364          262 :     i_oid = PQfnumber(res, "oid");
   10365          262 :     i_dictname = PQfnumber(res, "dictname");
   10366          262 :     i_dictnamespace = PQfnumber(res, "dictnamespace");
   10367          262 :     i_dictowner = PQfnumber(res, "dictowner");
   10368          262 :     i_dictinitoption = PQfnumber(res, "dictinitoption");
   10369          262 :     i_dicttemplate = PQfnumber(res, "dicttemplate");
   10370              : 
   10371         8757 :     for (i = 0; i < ntups; i++)
   10372              :     {
   10373         8495 :         dictinfo[i].dobj.objType = DO_TSDICT;
   10374         8495 :         dictinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
   10375         8495 :         dictinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
   10376         8495 :         AssignDumpId(&dictinfo[i].dobj);
   10377         8495 :         dictinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_dictname));
   10378        16990 :         dictinfo[i].dobj.namespace =
   10379         8495 :             findNamespace(atooid(PQgetvalue(res, i, i_dictnamespace)));
   10380         8495 :         dictinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_dictowner));
   10381         8495 :         dictinfo[i].dicttemplate = atooid(PQgetvalue(res, i, i_dicttemplate));
   10382         8495 :         if (PQgetisnull(res, i, i_dictinitoption))
   10383          310 :             dictinfo[i].dictinitoption = NULL;
   10384              :         else
   10385         8185 :             dictinfo[i].dictinitoption = pg_strdup(PQgetvalue(res, i, i_dictinitoption));
   10386              : 
   10387              :         /* Decide whether we want to dump it */
   10388         8495 :         selectDumpableObject(&(dictinfo[i].dobj), fout);
   10389              :     }
   10390              : 
   10391          262 :     PQclear(res);
   10392              : 
   10393          262 :     destroyPQExpBuffer(query);
   10394          262 : }
   10395              : 
   10396              : /*
   10397              :  * getTSTemplates:
   10398              :  *    get information about all text search templates in the system catalogs
   10399              :  */
   10400              : void
   10401          262 : 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          262 :     query = createPQExpBuffer();
   10416              : 
   10417          262 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, tmplname, "
   10418              :                          "tmplnamespace, tmplinit::oid, tmpllexize::oid "
   10419              :                          "FROM pg_ts_template");
   10420              : 
   10421          262 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   10422              : 
   10423          262 :     ntups = PQntuples(res);
   10424              : 
   10425          262 :     tmplinfo = pg_malloc_array(TSTemplateInfo, ntups);
   10426              : 
   10427          262 :     i_tableoid = PQfnumber(res, "tableoid");
   10428          262 :     i_oid = PQfnumber(res, "oid");
   10429          262 :     i_tmplname = PQfnumber(res, "tmplname");
   10430          262 :     i_tmplnamespace = PQfnumber(res, "tmplnamespace");
   10431          262 :     i_tmplinit = PQfnumber(res, "tmplinit");
   10432          262 :     i_tmpllexize = PQfnumber(res, "tmpllexize");
   10433              : 
   10434         1620 :     for (i = 0; i < ntups; i++)
   10435              :     {
   10436         1358 :         tmplinfo[i].dobj.objType = DO_TSTEMPLATE;
   10437         1358 :         tmplinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
   10438         1358 :         tmplinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
   10439         1358 :         AssignDumpId(&tmplinfo[i].dobj);
   10440         1358 :         tmplinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_tmplname));
   10441         2716 :         tmplinfo[i].dobj.namespace =
   10442         1358 :             findNamespace(atooid(PQgetvalue(res, i, i_tmplnamespace)));
   10443         1358 :         tmplinfo[i].tmplinit = atooid(PQgetvalue(res, i, i_tmplinit));
   10444         1358 :         tmplinfo[i].tmpllexize = atooid(PQgetvalue(res, i, i_tmpllexize));
   10445              : 
   10446              :         /* Decide whether we want to dump it */
   10447         1358 :         selectDumpableObject(&(tmplinfo[i].dobj), fout);
   10448              :     }
   10449              : 
   10450          262 :     PQclear(res);
   10451              : 
   10452          262 :     destroyPQExpBuffer(query);
   10453          262 : }
   10454              : 
   10455              : /*
   10456              :  * getTSConfigurations:
   10457              :  *    get information about all text search configurations
   10458              :  */
   10459              : void
   10460          262 : 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          262 :     query = createPQExpBuffer();
   10475              : 
   10476          262 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, cfgname, "
   10477              :                          "cfgnamespace, cfgowner, cfgparser "
   10478              :                          "FROM pg_ts_config");
   10479              : 
   10480          262 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   10481              : 
   10482          262 :     ntups = PQntuples(res);
   10483              : 
   10484          262 :     cfginfo = pg_malloc_array(TSConfigInfo, ntups);
   10485              : 
   10486          262 :     i_tableoid = PQfnumber(res, "tableoid");
   10487          262 :     i_oid = PQfnumber(res, "oid");
   10488          262 :     i_cfgname = PQfnumber(res, "cfgname");
   10489          262 :     i_cfgnamespace = PQfnumber(res, "cfgnamespace");
   10490          262 :     i_cfgowner = PQfnumber(res, "cfgowner");
   10491          262 :     i_cfgparser = PQfnumber(res, "cfgparser");
   10492              : 
   10493         8722 :     for (i = 0; i < ntups; i++)
   10494              :     {
   10495         8460 :         cfginfo[i].dobj.objType = DO_TSCONFIG;
   10496         8460 :         cfginfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
   10497         8460 :         cfginfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
   10498         8460 :         AssignDumpId(&cfginfo[i].dobj);
   10499         8460 :         cfginfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_cfgname));
   10500        16920 :         cfginfo[i].dobj.namespace =
   10501         8460 :             findNamespace(atooid(PQgetvalue(res, i, i_cfgnamespace)));
   10502         8460 :         cfginfo[i].rolname = getRoleName(PQgetvalue(res, i, i_cfgowner));
   10503         8460 :         cfginfo[i].cfgparser = atooid(PQgetvalue(res, i, i_cfgparser));
   10504              : 
   10505              :         /* Decide whether we want to dump it */
   10506         8460 :         selectDumpableObject(&(cfginfo[i].dobj), fout);
   10507              :     }
   10508              : 
   10509          262 :     PQclear(res);
   10510              : 
   10511          262 :     destroyPQExpBuffer(query);
   10512          262 : }
   10513              : 
   10514              : /*
   10515              :  * getForeignDataWrappers:
   10516              :  *    get information about all foreign-data wrappers in the system catalogs
   10517              :  */
   10518              : void
   10519          262 : 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          262 :     query = createPQExpBuffer();
   10538              : 
   10539          262 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, fdwname, "
   10540              :                          "fdwowner, "
   10541              :                          "fdwhandler::pg_catalog.regproc, "
   10542              :                          "fdwvalidator::pg_catalog.regproc, ");
   10543              : 
   10544          262 :     if (fout->remoteVersion >= 190000)
   10545          262 :         appendPQExpBufferStr(query, "fdwconnection::pg_catalog.regproc, ");
   10546              :     else
   10547            0 :         appendPQExpBufferStr(query, "'-' AS fdwconnection, ");
   10548              : 
   10549          262 :     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          262 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   10561              : 
   10562          262 :     ntups = PQntuples(res);
   10563              : 
   10564          262 :     fdwinfo = pg_malloc_array(FdwInfo, ntups);
   10565              : 
   10566          262 :     i_tableoid = PQfnumber(res, "tableoid");
   10567          262 :     i_oid = PQfnumber(res, "oid");
   10568          262 :     i_fdwname = PQfnumber(res, "fdwname");
   10569          262 :     i_fdwowner = PQfnumber(res, "fdwowner");
   10570          262 :     i_fdwhandler = PQfnumber(res, "fdwhandler");
   10571          262 :     i_fdwvalidator = PQfnumber(res, "fdwvalidator");
   10572          262 :     i_fdwconnection = PQfnumber(res, "fdwconnection");
   10573          262 :     i_fdwacl = PQfnumber(res, "fdwacl");
   10574          262 :     i_acldefault = PQfnumber(res, "acldefault");
   10575          262 :     i_fdwoptions = PQfnumber(res, "fdwoptions");
   10576              : 
   10577          336 :     for (i = 0; i < ntups; i++)
   10578              :     {
   10579           74 :         fdwinfo[i].dobj.objType = DO_FDW;
   10580           74 :         fdwinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
   10581           74 :         fdwinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
   10582           74 :         AssignDumpId(&fdwinfo[i].dobj);
   10583           74 :         fdwinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_fdwname));
   10584           74 :         fdwinfo[i].dobj.namespace = NULL;
   10585           74 :         fdwinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_fdwacl));
   10586           74 :         fdwinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
   10587           74 :         fdwinfo[i].dacl.privtype = 0;
   10588           74 :         fdwinfo[i].dacl.initprivs = NULL;
   10589           74 :         fdwinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_fdwowner));
   10590           74 :         fdwinfo[i].fdwhandler = pg_strdup(PQgetvalue(res, i, i_fdwhandler));
   10591           74 :         fdwinfo[i].fdwvalidator = pg_strdup(PQgetvalue(res, i, i_fdwvalidator));
   10592           74 :         fdwinfo[i].fdwconnection = pg_strdup(PQgetvalue(res, i, i_fdwconnection));
   10593           74 :         fdwinfo[i].fdwoptions = pg_strdup(PQgetvalue(res, i, i_fdwoptions));
   10594              : 
   10595              :         /* Decide whether we want to dump it */
   10596           74 :         selectDumpableObject(&(fdwinfo[i].dobj), fout);
   10597              : 
   10598              :         /* Mark whether FDW has an ACL */
   10599           74 :         if (!PQgetisnull(res, i, i_fdwacl))
   10600           48 :             fdwinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
   10601              :     }
   10602              : 
   10603          262 :     PQclear(res);
   10604              : 
   10605          262 :     destroyPQExpBuffer(query);
   10606          262 : }
   10607              : 
   10608              : /*
   10609              :  * getForeignServers:
   10610              :  *    get information about all foreign servers in the system catalogs
   10611              :  */
   10612              : void
   10613          262 : 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          262 :     query = createPQExpBuffer();
   10632              : 
   10633          262 :     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          262 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   10646              : 
   10647          262 :     ntups = PQntuples(res);
   10648              : 
   10649          262 :     srvinfo = pg_malloc_array(ForeignServerInfo, ntups);
   10650              : 
   10651          262 :     i_tableoid = PQfnumber(res, "tableoid");
   10652          262 :     i_oid = PQfnumber(res, "oid");
   10653          262 :     i_srvname = PQfnumber(res, "srvname");
   10654          262 :     i_srvowner = PQfnumber(res, "srvowner");
   10655          262 :     i_srvfdw = PQfnumber(res, "srvfdw");
   10656          262 :     i_srvtype = PQfnumber(res, "srvtype");
   10657          262 :     i_srvversion = PQfnumber(res, "srvversion");
   10658          262 :     i_srvacl = PQfnumber(res, "srvacl");
   10659          262 :     i_acldefault = PQfnumber(res, "acldefault");
   10660          262 :     i_srvoptions = PQfnumber(res, "srvoptions");
   10661              : 
   10662          340 :     for (i = 0; i < ntups; i++)
   10663              :     {
   10664           78 :         srvinfo[i].dobj.objType = DO_FOREIGN_SERVER;
   10665           78 :         srvinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
   10666           78 :         srvinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
   10667           78 :         AssignDumpId(&srvinfo[i].dobj);
   10668           78 :         srvinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_srvname));
   10669           78 :         srvinfo[i].dobj.namespace = NULL;
   10670           78 :         srvinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_srvacl));
   10671           78 :         srvinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
   10672           78 :         srvinfo[i].dacl.privtype = 0;
   10673           78 :         srvinfo[i].dacl.initprivs = NULL;
   10674           78 :         srvinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_srvowner));
   10675           78 :         srvinfo[i].srvfdw = atooid(PQgetvalue(res, i, i_srvfdw));
   10676           78 :         srvinfo[i].srvtype = pg_strdup(PQgetvalue(res, i, i_srvtype));
   10677           78 :         srvinfo[i].srvversion = pg_strdup(PQgetvalue(res, i, i_srvversion));
   10678           78 :         srvinfo[i].srvoptions = pg_strdup(PQgetvalue(res, i, i_srvoptions));
   10679              : 
   10680              :         /* Decide whether we want to dump it */
   10681           78 :         selectDumpableObject(&(srvinfo[i].dobj), fout);
   10682              : 
   10683              :         /* Servers have user mappings */
   10684           78 :         srvinfo[i].dobj.components |= DUMP_COMPONENT_USERMAP;
   10685              : 
   10686              :         /* Mark whether server has an ACL */
   10687           78 :         if (!PQgetisnull(res, i, i_srvacl))
   10688           48 :             srvinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
   10689              :     }
   10690              : 
   10691          262 :     PQclear(res);
   10692              : 
   10693          262 :     destroyPQExpBuffer(query);
   10694          262 : }
   10695              : 
   10696              : /*
   10697              :  * getDefaultACLs:
   10698              :  *    get information about all default ACL information in the system catalogs
   10699              :  */
   10700              : void
   10701          262 : getDefaultACLs(Archive *fout)
   10702              : {
   10703          262 :     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          262 :     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          262 :     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          262 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   10744              : 
   10745          262 :     ntups = PQntuples(res);
   10746              : 
   10747          262 :     daclinfo = pg_malloc_array(DefaultACLInfo, ntups);
   10748              : 
   10749          262 :     i_oid = PQfnumber(res, "oid");
   10750          262 :     i_tableoid = PQfnumber(res, "tableoid");
   10751          262 :     i_defaclrole = PQfnumber(res, "defaclrole");
   10752          262 :     i_defaclnamespace = PQfnumber(res, "defaclnamespace");
   10753          262 :     i_defaclobjtype = PQfnumber(res, "defaclobjtype");
   10754          262 :     i_defaclacl = PQfnumber(res, "defaclacl");
   10755          262 :     i_acldefault = PQfnumber(res, "acldefault");
   10756              : 
   10757          468 :     for (i = 0; i < ntups; i++)
   10758              :     {
   10759          206 :         Oid         nspid = atooid(PQgetvalue(res, i, i_defaclnamespace));
   10760              : 
   10761          206 :         daclinfo[i].dobj.objType = DO_DEFAULT_ACL;
   10762          206 :         daclinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
   10763          206 :         daclinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
   10764          206 :         AssignDumpId(&daclinfo[i].dobj);
   10765              :         /* cheesy ... is it worth coming up with a better object name? */
   10766          206 :         daclinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_defaclobjtype));
   10767              : 
   10768          206 :         if (nspid != InvalidOid)
   10769           96 :             daclinfo[i].dobj.namespace = findNamespace(nspid);
   10770              :         else
   10771          110 :             daclinfo[i].dobj.namespace = NULL;
   10772              : 
   10773          206 :         daclinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_defaclacl));
   10774          206 :         daclinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
   10775          206 :         daclinfo[i].dacl.privtype = 0;
   10776          206 :         daclinfo[i].dacl.initprivs = NULL;
   10777          206 :         daclinfo[i].defaclrole = getRoleName(PQgetvalue(res, i, i_defaclrole));
   10778          206 :         daclinfo[i].defaclobjtype = *(PQgetvalue(res, i, i_defaclobjtype));
   10779              : 
   10780              :         /* Default ACLs are ACLs, of course */
   10781          206 :         daclinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
   10782              : 
   10783              :         /* Decide whether we want to dump it */
   10784          206 :         selectDumpableDefaultACL(&(daclinfo[i]), dopt);
   10785              :     }
   10786              : 
   10787          262 :     PQclear(res);
   10788              : 
   10789          262 :     destroyPQExpBuffer(query);
   10790          262 : }
   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       847419 : getRoleName(const char *roleoid_str)
   10799              : {
   10800       847419 :     Oid         roleoid = atooid(roleoid_str);
   10801              : 
   10802              :     /*
   10803              :      * Do binary search to find the appropriate item.
   10804              :      */
   10805       847419 :     if (nrolenames > 0)
   10806              :     {
   10807       847419 :         RoleNameItem *low = &rolenames[0];
   10808       847419 :         RoleNameItem *high = &rolenames[nrolenames - 1];
   10809              : 
   10810      3389741 :         while (low <= high)
   10811              :         {
   10812      3389741 :             RoleNameItem *middle = low + (high - low) / 2;
   10813              : 
   10814      3389741 :             if (roleoid < middle->roleoid)
   10815      2540981 :                 high = middle - 1;
   10816       848760 :             else if (roleoid > middle->roleoid)
   10817         1341 :                 low = middle + 1;
   10818              :             else
   10819       847419 :                 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          263 : collectRoleNames(Archive *fout)
   10835              : {
   10836              :     PGresult   *res;
   10837              :     const char *query;
   10838              :     int         i;
   10839              : 
   10840          263 :     query = "SELECT oid, rolname FROM pg_catalog.pg_roles ORDER BY 1";
   10841              : 
   10842          263 :     res = ExecuteSqlQuery(fout, query, PGRES_TUPLES_OK);
   10843              : 
   10844          263 :     nrolenames = PQntuples(res);
   10845              : 
   10846          263 :     rolenames = pg_malloc_array(RoleNameItem, nrolenames);
   10847              : 
   10848         5832 :     for (i = 0; i < nrolenames; i++)
   10849              :     {
   10850         5569 :         rolenames[i].roleoid = atooid(PQgetvalue(res, i, 0));
   10851         5569 :         rolenames[i].rolename = pg_strdup(PQgetvalue(res, i, 1));
   10852              :     }
   10853              : 
   10854          263 :     PQclear(res);
   10855          263 : }
   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          260 : getAdditionalACLs(Archive *fout)
   10870              : {
   10871          260 :     PQExpBuffer query = createPQExpBuffer();
   10872              :     PGresult   *res;
   10873              :     int         ntups,
   10874              :                 i;
   10875              : 
   10876              :     /* Check for per-column ACLs */
   10877          260 :     appendPQExpBufferStr(query,
   10878              :                          "SELECT DISTINCT attrelid FROM pg_attribute "
   10879              :                          "WHERE attacl IS NOT NULL");
   10880              : 
   10881          260 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   10882              : 
   10883          260 :     ntups = PQntuples(res);
   10884          699 :     for (i = 0; i < ntups; i++)
   10885              :     {
   10886          439 :         Oid         relid = atooid(PQgetvalue(res, i, 0));
   10887              :         TableInfo  *tblinfo;
   10888              : 
   10889          439 :         tblinfo = findTableByOid(relid);
   10890              :         /* OK to ignore tables we haven't got a DumpableObject for */
   10891          439 :         if (tblinfo)
   10892              :         {
   10893          439 :             tblinfo->dobj.components |= DUMP_COMPONENT_ACL;
   10894          439 :             tblinfo->hascolumnACLs = true;
   10895              :         }
   10896              :     }
   10897          260 :     PQclear(res);
   10898              : 
   10899              :     /* Fetch initial-privileges data */
   10900          260 :     if (fout->remoteVersion >= 90600)
   10901              :     {
   10902          260 :         printfPQExpBuffer(query,
   10903              :                           "SELECT objoid, classoid, objsubid, privtype, initprivs "
   10904              :                           "FROM pg_init_privs");
   10905              : 
   10906          260 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   10907              : 
   10908          260 :         ntups = PQntuples(res);
   10909        65308 :         for (i = 0; i < ntups; i++)
   10910              :         {
   10911        65048 :             Oid         objoid = atooid(PQgetvalue(res, i, 0));
   10912        65048 :             Oid         classoid = atooid(PQgetvalue(res, i, 1));
   10913        65048 :             int         objsubid = atoi(PQgetvalue(res, i, 2));
   10914        65048 :             char        privtype = *(PQgetvalue(res, i, 3));
   10915        65048 :             char       *initprivs = PQgetvalue(res, i, 4);
   10916              :             CatalogId   objId;
   10917              :             DumpableObject *dobj;
   10918              : 
   10919        65048 :             objId.tableoid = classoid;
   10920        65048 :             objId.oid = objoid;
   10921        65048 :             dobj = findObjectByCatalogId(objId);
   10922              :             /* OK to ignore entries we haven't got a DumpableObject for */
   10923        65048 :             if (dobj)
   10924              :             {
   10925              :                 /* Cope with sub-object initprivs */
   10926        47155 :                 if (objsubid != 0)
   10927              :                 {
   10928         5744 :                     if (dobj->objType == DO_TABLE)
   10929              :                     {
   10930              :                         /* For a column initprivs, set the table's ACL flags */
   10931         5744 :                         dobj->components |= DUMP_COMPONENT_ACL;
   10932         5744 :                         ((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         6000 :                     continue;
   10938              :                 }
   10939              : 
   10940              :                 /*
   10941              :                  * We ignore any pg_init_privs.initprivs entry for the public
   10942              :                  * schema, as explained in getNamespaces().
   10943              :                  */
   10944        41411 :                 if (dobj->objType == DO_NAMESPACE &&
   10945          516 :                     strcmp(dobj->name, "public") == 0)
   10946          256 :                     continue;
   10947              : 
   10948              :                 /* Else it had better be of a type we think has ACLs */
   10949        41155 :                 if (dobj->objType == DO_NAMESPACE ||
   10950        40895 :                     dobj->objType == DO_TYPE ||
   10951        40871 :                     dobj->objType == DO_FUNC ||
   10952        40776 :                     dobj->objType == DO_AGG ||
   10953        40752 :                     dobj->objType == DO_TABLE ||
   10954            0 :                     dobj->objType == DO_PROCLANG ||
   10955            0 :                     dobj->objType == DO_FDW ||
   10956            0 :                     dobj->objType == DO_FOREIGN_SERVER)
   10957        41155 :                 {
   10958        41155 :                     DumpableObjectWithAcl *daobj = (DumpableObjectWithAcl *) dobj;
   10959              : 
   10960        41155 :                     daobj->dacl.privtype = privtype;
   10961        41155 :                     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          260 :         PQclear(res);
   10969              :     }
   10970              : 
   10971          260 :     destroyPQExpBuffer(query);
   10972          260 : }
   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         6714 : 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         6714 :     DumpOptions *dopt = fout->dopt;
   11005              :     CommentItem *comments;
   11006              :     int         ncomments;
   11007              : 
   11008              :     /* do nothing, if --no-comments is supplied */
   11009         6714 :     if (dopt->no_comments)
   11010            0 :         return;
   11011              : 
   11012              :     /* Comments are schema not data ... except LO comments are data */
   11013         6714 :     if (strcmp(type, "LARGE OBJECT") != 0)
   11014              :     {
   11015         6654 :         if (!dopt->dumpSchema)
   11016            0 :             return;
   11017              :     }
   11018              :     else
   11019              :     {
   11020              :         /* We do dump LO comments in binary-upgrade mode */
   11021           60 :         if (!dopt->dumpData && !dopt->binary_upgrade)
   11022            0 :             return;
   11023              :     }
   11024              : 
   11025              :     /* Search for comments associated with catalogId, using table */
   11026         6714 :     ncomments = findComments(catalogId.tableoid, catalogId.oid,
   11027              :                              &comments);
   11028              : 
   11029              :     /* Is there one matching the subid? */
   11030         6714 :     while (ncomments > 0)
   11031              :     {
   11032         6667 :         if (comments->objsubid == subid)
   11033         6667 :             break;
   11034            0 :         comments++;
   11035            0 :         ncomments--;
   11036              :     }
   11037              : 
   11038         6714 :     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          188 :         if (ncomments == 0)
   11049              :         {
   11050            4 :             comments = &empty_comment;
   11051            4 :             ncomments = 1;
   11052              :         }
   11053          184 :         else if (strcmp(comments->descr, initdb_comment) == 0)
   11054          184 :             ncomments = 0;
   11055              :     }
   11056              : 
   11057              :     /* If a comment exists, build COMMENT ON statement */
   11058         6714 :     if (ncomments > 0)
   11059              :     {
   11060         6487 :         PQExpBuffer query = createPQExpBuffer();
   11061         6487 :         PQExpBuffer tag = createPQExpBuffer();
   11062              : 
   11063         6487 :         appendPQExpBuffer(query, "COMMENT ON %s ", type);
   11064         6487 :         if (namespace && *namespace)
   11065         6300 :             appendPQExpBuffer(query, "%s.", fmtId(namespace));
   11066         6487 :         appendPQExpBuffer(query, "%s IS ", name);
   11067         6487 :         appendStringLiteralAH(query, comments->descr, fout);
   11068         6487 :         appendPQExpBufferStr(query, ";\n");
   11069              : 
   11070         6487 :         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         6487 :         ArchiveEntry(fout, nilCatalogId, createDumpId(),
   11078         6487 :                      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         6487 :         destroyPQExpBuffer(query);
   11088         6487 :         destroyPQExpBuffer(tag);
   11089              :     }
   11090              : }
   11091              : 
   11092              : /*
   11093              :  * dumpComment --
   11094              :  *
   11095              :  * Typical simplification of the above function.
   11096              :  */
   11097              : static inline void
   11098         6483 : 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         6483 :     dumpCommentExtended(fout, type, name, namespace, owner,
   11104              :                         catalogId, subid, dumpId, NULL);
   11105         6483 : }
   11106              : 
   11107              : /*
   11108              :  * appendNamedArgument --
   11109              :  *
   11110              :  * Convenience routine for constructing parameters of the form:
   11111              :  * 'paraname', 'value'::type
   11112              :  */
   11113              : static void
   11114         5825 : appendNamedArgument(PQExpBuffer out, Archive *fout, const char *argname,
   11115              :                     const char *argtype, const char *argval)
   11116              : {
   11117         5825 :     appendPQExpBufferStr(out, ",\n\t");
   11118              : 
   11119         5825 :     appendStringLiteralAH(out, argname, fout);
   11120         5825 :     appendPQExpBufferStr(out, ", ");
   11121              : 
   11122         5825 :     appendStringLiteralAH(out, argval, fout);
   11123         5825 :     appendPQExpBuffer(out, "::%s", argtype);
   11124         5825 : }
   11125              : 
   11126              : /*
   11127              :  * fetchAttributeStats --
   11128              :  *
   11129              :  * Fetch next batch of attribute statistics for dumpRelationStats_dumper().
   11130              :  */
   11131              : static PGresult *
   11132         1104 : fetchAttributeStats(Archive *fout)
   11133              : {
   11134         1104 :     ArchiveHandle *AH = (ArchiveHandle *) fout;
   11135         1104 :     PQExpBuffer relids = createPQExpBuffer();
   11136         1104 :     PQExpBuffer nspnames = createPQExpBuffer();
   11137         1104 :     PQExpBuffer relnames = createPQExpBuffer();
   11138         1104 :     int         count = 0;
   11139         1104 :     PGresult   *res = NULL;
   11140              :     static TocEntry *te;
   11141              :     static bool restarted;
   11142         1104 :     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         1104 :     if (fout->remoteVersion < 90400)
   11151            0 :         max_rels = 1;
   11152              : 
   11153              :     /* If we're just starting, set our TOC pointer. */
   11154         1104 :     if (!te)
   11155           65 :         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         1104 :     if (!restarted && te == AH->toc && AH->format == archTar)
   11166              :     {
   11167            1 :         te = AH->toc->next;
   11168            1 :         restarted = true;
   11169              :     }
   11170              : 
   11171         1104 :     appendPQExpBufferChar(relids, '{');
   11172         1104 :     appendPQExpBufferChar(nspnames, '{');
   11173         1104 :     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        17272 :     for (; te != AH->toc && count < max_rels; te = te->next)
   11182              :     {
   11183        16168 :         if ((te->reqs & REQ_STATS) == 0 ||
   11184         3644 :             strcmp(te->desc, "STATISTICS DATA") != 0)
   11185        12562 :             continue;
   11186              : 
   11187         3606 :         if (fout->remoteVersion >= 190000)
   11188              :         {
   11189         3606 :             const RelStatsInfo *rsinfo = (const RelStatsInfo *) te->defnDumperArg;
   11190              :             char        relid[32];
   11191              : 
   11192         3606 :             sprintf(relid, "%u", rsinfo->relid);
   11193         3606 :             appendPGArray(relids, relid);
   11194              :         }
   11195              :         else
   11196              :         {
   11197            0 :             appendPGArray(nspnames, te->namespace);
   11198            0 :             appendPGArray(relnames, te->tag);
   11199              :         }
   11200              : 
   11201         3606 :         count++;
   11202              :     }
   11203              : 
   11204         1104 :     appendPQExpBufferChar(relids, '}');
   11205         1104 :     appendPQExpBufferChar(nspnames, '}');
   11206         1104 :     appendPQExpBufferChar(relnames, '}');
   11207              : 
   11208              :     /* Execute the query for the next batch of relations. */
   11209         1104 :     if (count > 0)
   11210              :     {
   11211          112 :         PQExpBuffer query = createPQExpBuffer();
   11212              : 
   11213          112 :         appendPQExpBufferStr(query, "EXECUTE getAttributeStats(");
   11214              : 
   11215          112 :         if (fout->remoteVersion >= 190000)
   11216              :         {
   11217          112 :             appendStringLiteralAH(query, relids->data, fout);
   11218          112 :             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          112 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   11229          112 :         destroyPQExpBuffer(query);
   11230              :     }
   11231              : 
   11232         1104 :     destroyPQExpBuffer(relids);
   11233         1104 :     destroyPQExpBuffer(nspnames);
   11234         1104 :     destroyPQExpBuffer(relnames);
   11235         1104 :     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         3606 : dumpRelationStats_dumper(Archive *fout, const void *userArg, const TocEntry *te)
   11247              : {
   11248         3606 :     const RelStatsInfo *rsinfo = userArg;
   11249              :     static PGresult *res;
   11250              :     static int  rownum;
   11251              :     PQExpBuffer query;
   11252              :     PQExpBufferData out_data;
   11253         3606 :     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         3606 :     if (!expected_te)
   11278           65 :         expected_te = ((ArchiveHandle *) fout)->toc;
   11279              : 
   11280         3606 :     expected_te = expected_te->next;
   11281        14116 :     while ((expected_te->reqs & REQ_STATS) == 0 ||
   11282         3607 :            strcmp(expected_te->desc, "STATISTICS DATA") != 0)
   11283        10510 :         expected_te = expected_te->next;
   11284              : 
   11285         3606 :     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         3606 :     query = createPQExpBuffer();
   11291         3606 :     if (!fout->is_prepared[PREPQUERY_GETATTRIBUTESTATS])
   11292              :     {
   11293           65 :         if (fout->remoteVersion >= 190000)
   11294           65 :             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           65 :         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           65 :         if (fout->remoteVersion >= 170000)
   11309           65 :             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           65 :         if (fout->remoteVersion >= 190000)
   11335           65 :             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           65 :         ExecuteSqlStatement(fout, query->data);
   11356              : 
   11357           65 :         fout->is_prepared[PREPQUERY_GETATTRIBUTESTATS] = true;
   11358           65 :         resetPQExpBuffer(query);
   11359              :     }
   11360              : 
   11361         3606 :     initPQExpBuffer(out);
   11362              : 
   11363              :     /* restore relation stats */
   11364         3606 :     appendPQExpBufferStr(out, "SELECT * FROM pg_catalog.pg_restore_relation_stats(\n");
   11365         3606 :     appendPQExpBuffer(out, "\t'version', '%d'::integer,\n",
   11366              :                       fout->remoteVersion);
   11367         3606 :     appendPQExpBufferStr(out, "\t'schemaname', ");
   11368         3606 :     appendStringLiteralAH(out, rsinfo->dobj.namespace->dobj.name, fout);
   11369         3606 :     appendPQExpBufferStr(out, ",\n");
   11370         3606 :     appendPQExpBufferStr(out, "\t'relname', ");
   11371         3606 :     appendStringLiteralAH(out, rsinfo->dobj.name, fout);
   11372         3606 :     appendPQExpBufferStr(out, ",\n");
   11373         3606 :     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         3606 :     if (fout->remoteVersion < 140000 && strcmp("0", rsinfo->reltuples) == 0)
   11384            0 :         appendPQExpBufferStr(out, "\t'reltuples', '-1'::real,\n");
   11385              :     else
   11386         3606 :         appendPQExpBuffer(out, "\t'reltuples', '%s'::real,\n", rsinfo->reltuples);
   11387              : 
   11388         3606 :     appendPQExpBuffer(out, "\t'relallvisible', '%d'::integer",
   11389         3606 :                       rsinfo->relallvisible);
   11390              : 
   11391         3606 :     if (fout->remoteVersion >= 180000)
   11392         3606 :         appendPQExpBuffer(out, ",\n\t'relallfrozen', '%d'::integer", rsinfo->relallfrozen);
   11393              : 
   11394         3606 :     appendPQExpBufferStr(out, "\n);\n");
   11395              : 
   11396              :     /* Fetch the next batch of attribute statistics if needed. */
   11397         3606 :     if (rownum >= PQntuples(res))
   11398              :     {
   11399         1104 :         PQclear(res);
   11400         1104 :         res = fetchAttributeStats(fout);
   11401         1104 :         rownum = 0;
   11402              :     }
   11403              : 
   11404         3606 :     i_schemaname = PQfnumber(res, "schemaname");
   11405         3606 :     i_tablename = PQfnumber(res, "tablename");
   11406         3606 :     i_attname = PQfnumber(res, "attname");
   11407         3606 :     i_inherited = PQfnumber(res, "inherited");
   11408         3606 :     i_null_frac = PQfnumber(res, "null_frac");
   11409         3606 :     i_avg_width = PQfnumber(res, "avg_width");
   11410         3606 :     i_n_distinct = PQfnumber(res, "n_distinct");
   11411         3606 :     i_most_common_vals = PQfnumber(res, "most_common_vals");
   11412         3606 :     i_most_common_freqs = PQfnumber(res, "most_common_freqs");
   11413         3606 :     i_histogram_bounds = PQfnumber(res, "histogram_bounds");
   11414         3606 :     i_correlation = PQfnumber(res, "correlation");
   11415         3606 :     i_most_common_elems = PQfnumber(res, "most_common_elems");
   11416         3606 :     i_most_common_elem_freqs = PQfnumber(res, "most_common_elem_freqs");
   11417         3606 :     i_elem_count_histogram = PQfnumber(res, "elem_count_histogram");
   11418         3606 :     i_range_length_histogram = PQfnumber(res, "range_length_histogram");
   11419         3606 :     i_range_empty_frac = PQfnumber(res, "range_empty_frac");
   11420         3606 :     i_range_bounds_histogram = PQfnumber(res, "range_bounds_histogram");
   11421              : 
   11422              :     /* restore attribute stats */
   11423         4445 :     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         3341 :         if (strcmp(te->tag, PQgetvalue(res, rownum, i_tablename)) != 0 ||
   11429          839 :             strcmp(te->namespace, PQgetvalue(res, rownum, i_schemaname)) != 0)
   11430              :             break;
   11431              : 
   11432          839 :         appendPQExpBufferStr(out, "SELECT * FROM pg_catalog.pg_restore_attribute_stats(\n");
   11433          839 :         appendPQExpBuffer(out, "\t'version', '%d'::integer,\n",
   11434              :                           fout->remoteVersion);
   11435          839 :         appendPQExpBufferStr(out, "\t'schemaname', ");
   11436          839 :         appendStringLiteralAH(out, rsinfo->dobj.namespace->dobj.name, fout);
   11437          839 :         appendPQExpBufferStr(out, ",\n\t'relname', ");
   11438          839 :         appendStringLiteralAH(out, rsinfo->dobj.name, fout);
   11439              : 
   11440          839 :         if (PQgetisnull(res, rownum, i_attname))
   11441            0 :             pg_fatal("unexpected null attname");
   11442          839 :         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          839 :         if (rsinfo->nindAttNames == 0)
   11450              :         {
   11451          801 :             appendPQExpBufferStr(out, ",\n\t'attname', ");
   11452          801 :             appendStringLiteralAH(out, attname, fout);
   11453              :         }
   11454              :         else
   11455              :         {
   11456           38 :             bool        found = false;
   11457              : 
   11458           72 :             for (int i = 0; i < rsinfo->nindAttNames; i++)
   11459              :             {
   11460           72 :                 if (strcmp(attname, rsinfo->indAttNames[i]) == 0)
   11461              :                 {
   11462           38 :                     appendPQExpBuffer(out, ",\n\t'attnum', '%d'::smallint",
   11463              :                                       i + 1);
   11464           38 :                     found = true;
   11465           38 :                     break;
   11466              :                 }
   11467              :             }
   11468              : 
   11469           38 :             if (!found)
   11470            0 :                 pg_fatal("could not find index attname \"%s\"", attname);
   11471              :         }
   11472              : 
   11473          839 :         if (!PQgetisnull(res, rownum, i_inherited))
   11474          839 :             appendNamedArgument(out, fout, "inherited", "boolean",
   11475          839 :                                 PQgetvalue(res, rownum, i_inherited));
   11476          839 :         if (!PQgetisnull(res, rownum, i_null_frac))
   11477          839 :             appendNamedArgument(out, fout, "null_frac", "real",
   11478          839 :                                 PQgetvalue(res, rownum, i_null_frac));
   11479          839 :         if (!PQgetisnull(res, rownum, i_avg_width))
   11480          839 :             appendNamedArgument(out, fout, "avg_width", "integer",
   11481          839 :                                 PQgetvalue(res, rownum, i_avg_width));
   11482          839 :         if (!PQgetisnull(res, rownum, i_n_distinct))
   11483          839 :             appendNamedArgument(out, fout, "n_distinct", "real",
   11484          839 :                                 PQgetvalue(res, rownum, i_n_distinct));
   11485          839 :         if (!PQgetisnull(res, rownum, i_most_common_vals))
   11486          418 :             appendNamedArgument(out, fout, "most_common_vals", "text",
   11487          418 :                                 PQgetvalue(res, rownum, i_most_common_vals));
   11488          839 :         if (!PQgetisnull(res, rownum, i_most_common_freqs))
   11489          418 :             appendNamedArgument(out, fout, "most_common_freqs", "real[]",
   11490          418 :                                 PQgetvalue(res, rownum, i_most_common_freqs));
   11491          839 :         if (!PQgetisnull(res, rownum, i_histogram_bounds))
   11492          535 :             appendNamedArgument(out, fout, "histogram_bounds", "text",
   11493          535 :                                 PQgetvalue(res, rownum, i_histogram_bounds));
   11494          839 :         if (!PQgetisnull(res, rownum, i_correlation))
   11495          806 :             appendNamedArgument(out, fout, "correlation", "real",
   11496          806 :                                 PQgetvalue(res, rownum, i_correlation));
   11497          839 :         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          839 :         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          839 :         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          839 :         if (fout->remoteVersion >= 170000)
   11507              :         {
   11508          839 :             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          839 :             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          839 :             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          839 :         appendPQExpBufferStr(out, "\n);\n");
   11519              :     }
   11520              : 
   11521         3606 :     destroyPQExpBuffer(query);
   11522         3606 :     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         3678 : dumpRelationStats(Archive *fout, const RelStatsInfo *rsinfo)
   11534              : {
   11535         3678 :     const DumpableObject *dobj = &rsinfo->dobj;
   11536              : 
   11537              :     /* nothing to do if we are not dumping statistics */
   11538         3678 :     if (!fout->dopt->dumpStatistics)
   11539            0 :         return;
   11540              : 
   11541         3678 :     ArchiveEntry(fout, nilCatalogId, createDumpId(),
   11542         3678 :                  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           78 : dumpTableComment(Archive *fout, const TableInfo *tbinfo,
   11560              :                  const char *reltypename)
   11561              : {
   11562           78 :     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           78 :     if (dopt->no_comments)
   11570            0 :         return;
   11571              : 
   11572              :     /* Comments are SCHEMA not data */
   11573           78 :     if (!dopt->dumpSchema)
   11574            0 :         return;
   11575              : 
   11576              :     /* Search for comments associated with relation, using table */
   11577           78 :     ncomments = findComments(tbinfo->dobj.catId.tableoid,
   11578           78 :                              tbinfo->dobj.catId.oid,
   11579              :                              &comments);
   11580              : 
   11581              :     /* If comments exist, build COMMENT ON statements */
   11582           78 :     if (ncomments <= 0)
   11583            0 :         return;
   11584              : 
   11585           78 :     query = createPQExpBuffer();
   11586           78 :     tag = createPQExpBuffer();
   11587              : 
   11588          224 :     while (ncomments > 0)
   11589              :     {
   11590          146 :         const char *descr = comments->descr;
   11591          146 :         int         objsubid = comments->objsubid;
   11592              : 
   11593          146 :         if (objsubid == 0)
   11594              :         {
   11595           34 :             resetPQExpBuffer(tag);
   11596           34 :             appendPQExpBuffer(tag, "%s %s", reltypename,
   11597           34 :                               fmtId(tbinfo->dobj.name));
   11598              : 
   11599           34 :             resetPQExpBuffer(query);
   11600           34 :             appendPQExpBuffer(query, "COMMENT ON %s %s IS ", reltypename,
   11601           34 :                               fmtQualifiedDumpable(tbinfo));
   11602           34 :             appendStringLiteralAH(query, descr, fout);
   11603           34 :             appendPQExpBufferStr(query, ";\n");
   11604              : 
   11605           34 :             ArchiveEntry(fout, nilCatalogId, createDumpId(),
   11606           34 :                          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          112 :         else if (objsubid > 0 && objsubid <= tbinfo->numatts)
   11616              :         {
   11617          112 :             resetPQExpBuffer(tag);
   11618          112 :             appendPQExpBuffer(tag, "COLUMN %s.",
   11619          112 :                               fmtId(tbinfo->dobj.name));
   11620          112 :             appendPQExpBufferStr(tag, fmtId(tbinfo->attnames[objsubid - 1]));
   11621              : 
   11622          112 :             resetPQExpBuffer(query);
   11623          112 :             appendPQExpBuffer(query, "COMMENT ON COLUMN %s.",
   11624          112 :                               fmtQualifiedDumpable(tbinfo));
   11625          112 :             appendPQExpBuffer(query, "%s IS ",
   11626          112 :                               fmtId(tbinfo->attnames[objsubid - 1]));
   11627          112 :             appendStringLiteralAH(query, descr, fout);
   11628          112 :             appendPQExpBufferStr(query, ";\n");
   11629              : 
   11630          112 :             ArchiveEntry(fout, nilCatalogId, createDumpId(),
   11631          112 :                          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          146 :         comments++;
   11642          146 :         ncomments--;
   11643              :     }
   11644              : 
   11645           78 :     destroyPQExpBuffer(query);
   11646           78 :     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         6826 : findComments(Oid classoid, Oid objoid, CommentItem **items)
   11658              : {
   11659         6826 :     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         6826 :     low = &comments[0];
   11668         6826 :     high = &comments[ncomments - 1];
   11669        68117 :     while (low <= high)
   11670              :     {
   11671        68070 :         middle = low + (high - low) / 2;
   11672              : 
   11673        68070 :         if (classoid < middle->classoid)
   11674         7329 :             high = middle - 1;
   11675        60741 :         else if (classoid > middle->classoid)
   11676         7528 :             low = middle + 1;
   11677        53213 :         else if (objoid < middle->objoid)
   11678        22623 :             high = middle - 1;
   11679        30590 :         else if (objoid > middle->objoid)
   11680        23811 :             low = middle + 1;
   11681              :         else
   11682         6779 :             break;              /* found a match */
   11683              :     }
   11684              : 
   11685         6826 :     if (low > high)              /* no matches */
   11686              :     {
   11687           47 :         *items = NULL;
   11688           47 :         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         6779 :     nmatch = 1;
   11697         6779 :     while (middle > low)
   11698              :     {
   11699         3378 :         if (classoid != middle[-1].classoid ||
   11700         3215 :             objoid != middle[-1].objoid)
   11701              :             break;
   11702            0 :         middle--;
   11703            0 :         nmatch++;
   11704              :     }
   11705              : 
   11706         6779 :     *items = middle;
   11707              : 
   11708         6779 :     middle += nmatch;
   11709         6847 :     while (middle <= high)
   11710              :     {
   11711         3644 :         if (classoid != middle->classoid ||
   11712         3176 :             objoid != middle->objoid)
   11713              :             break;
   11714           68 :         middle++;
   11715           68 :         nmatch++;
   11716              :     }
   11717              : 
   11718         6779 :     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          262 : 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          262 :     query = createPQExpBuffer();
   11747              : 
   11748          262 :     appendPQExpBufferStr(query, "SELECT description, classoid, objoid, objsubid "
   11749              :                          "FROM pg_catalog.pg_description "
   11750              :                          "ORDER BY classoid, objoid, objsubid");
   11751              : 
   11752          262 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   11753              : 
   11754              :     /* Construct lookup table containing OIDs in numeric form */
   11755              : 
   11756          262 :     i_description = PQfnumber(res, "description");
   11757          262 :     i_classoid = PQfnumber(res, "classoid");
   11758          262 :     i_objoid = PQfnumber(res, "objoid");
   11759          262 :     i_objsubid = PQfnumber(res, "objsubid");
   11760              : 
   11761          262 :     ntups = PQntuples(res);
   11762              : 
   11763          262 :     comments = pg_malloc_array(CommentItem, ntups);
   11764          262 :     ncomments = 0;
   11765          262 :     dobj = NULL;
   11766              : 
   11767      1410596 :     for (i = 0; i < ntups; i++)
   11768              :     {
   11769              :         CatalogId   objId;
   11770              :         int         subid;
   11771              : 
   11772      1410334 :         objId.tableoid = atooid(PQgetvalue(res, i, i_classoid));
   11773      1410334 :         objId.oid = atooid(PQgetvalue(res, i, i_objoid));
   11774      1410334 :         subid = atoi(PQgetvalue(res, i, i_objsubid));
   11775              : 
   11776              :         /* We needn't remember comments that don't match any dumpable object */
   11777      1410334 :         if (dobj == NULL ||
   11778       513093 :             dobj->catId.tableoid != objId.tableoid ||
   11779       509960 :             dobj->catId.oid != objId.oid)
   11780      1410238 :             dobj = findObjectByCatalogId(objId);
   11781      1410334 :         if (dobj == NULL)
   11782       896985 :             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       513349 :         if (subid != 0 && dobj->objType == DO_TABLE &&
   11790          206 :             ((TableInfo *) dobj)->relkind == RELKIND_COMPOSITE_TYPE)
   11791           48 :         {
   11792              :             TypeInfo   *cTypeInfo;
   11793              : 
   11794           48 :             cTypeInfo = findTypeByOid(((TableInfo *) dobj)->reltype);
   11795           48 :             if (cTypeInfo)
   11796           48 :                 cTypeInfo->dobj.components |= DUMP_COMPONENT_COMMENT;
   11797              :         }
   11798              :         else
   11799       513301 :             dobj->components |= DUMP_COMPONENT_COMMENT;
   11800              : 
   11801       513349 :         comments[ncomments].descr = pg_strdup(PQgetvalue(res, i, i_description));
   11802       513349 :         comments[ncomments].classoid = objId.tableoid;
   11803       513349 :         comments[ncomments].objoid = objId.oid;
   11804       513349 :         comments[ncomments].objsubid = subid;
   11805       513349 :         ncomments++;
   11806              :     }
   11807              : 
   11808          262 :     PQclear(res);
   11809          262 :     destroyPQExpBuffer(query);
   11810          262 : }
   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       987733 : 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       987733 :     dobj->dump &= dobj->components;
   11827              : 
   11828              :     /* Now, short-circuit if there's nothing to be done here. */
   11829       987733 :     if (dobj->dump == 0)
   11830       893129 :         return;
   11831              : 
   11832        94604 :     switch (dobj->objType)
   11833              :     {
   11834          669 :         case DO_NAMESPACE:
   11835          669 :             dumpNamespace(fout, (const NamespaceInfo *) dobj);
   11836          669 :             break;
   11837           25 :         case DO_EXTENSION:
   11838           25 :             dumpExtension(fout, (const ExtensionInfo *) dobj);
   11839           25 :             break;
   11840          971 :         case DO_TYPE:
   11841          971 :             dumpType(fout, (const TypeInfo *) dobj);
   11842          971 :             break;
   11843           76 :         case DO_SHELL_TYPE:
   11844           76 :             dumpShellType(fout, (const ShellTypeInfo *) dobj);
   11845           76 :             break;
   11846         1926 :         case DO_FUNC:
   11847         1926 :             dumpFunc(fout, (const FuncInfo *) dobj);
   11848         1926 :             break;
   11849          295 :         case DO_AGG:
   11850          295 :             dumpAgg(fout, (const AggInfo *) dobj);
   11851          295 :             break;
   11852         2525 :         case DO_OPERATOR:
   11853         2525 :             dumpOpr(fout, (const OprInfo *) dobj);
   11854         2525 :             break;
   11855           84 :         case DO_ACCESS_METHOD:
   11856           84 :             dumpAccessMethod(fout, (const AccessMethodInfo *) dobj);
   11857           84 :             break;
   11858          675 :         case DO_OPCLASS:
   11859          675 :             dumpOpclass(fout, (const OpclassInfo *) dobj);
   11860          675 :             break;
   11861          561 :         case DO_OPFAMILY:
   11862          561 :             dumpOpfamily(fout, (const OpfamilyInfo *) dobj);
   11863          561 :             break;
   11864         2733 :         case DO_COLLATION:
   11865         2733 :             dumpCollation(fout, (const CollInfo *) dobj);
   11866         2733 :             break;
   11867          335 :         case DO_CONVERSION:
   11868          335 :             dumpConversion(fout, (const ConvInfo *) dobj);
   11869          335 :             break;
   11870        45243 :         case DO_TABLE:
   11871        45243 :             dumpTable(fout, (const TableInfo *) dobj);
   11872        45243 :             break;
   11873         1452 :         case DO_TABLE_ATTACH:
   11874         1452 :             dumpTableAttach(fout, (const TableAttachInfo *) dobj);
   11875         1452 :             break;
   11876         1111 :         case DO_ATTRDEF:
   11877         1111 :             dumpAttrDef(fout, (const AttrDefInfo *) dobj);
   11878         1111 :             break;
   11879         2817 :         case DO_INDEX:
   11880         2817 :             dumpIndex(fout, (const IndxInfo *) dobj);
   11881         2817 :             break;
   11882          610 :         case DO_INDEX_ATTACH:
   11883          610 :             dumpIndexAttach(fout, (const IndexAttachInfo *) dobj);
   11884          610 :             break;
   11885          183 :         case DO_STATSEXT:
   11886          183 :             dumpStatisticsExt(fout, (const StatsExtInfo *) dobj);
   11887          183 :             dumpStatisticsExtStats(fout, (const StatsExtInfo *) dobj);
   11888          183 :             break;
   11889          363 :         case DO_REFRESH_MATVIEW:
   11890          363 :             refreshMatViewData(fout, (const TableDataInfo *) dobj);
   11891          363 :             break;
   11892         1194 :         case DO_RULE:
   11893         1194 :             dumpRule(fout, (const RuleInfo *) dobj);
   11894         1194 :             break;
   11895          535 :         case DO_TRIGGER:
   11896          535 :             dumpTrigger(fout, (const TriggerInfo *) dobj);
   11897          535 :             break;
   11898           44 :         case DO_EVENT_TRIGGER:
   11899           44 :             dumpEventTrigger(fout, (const EventTriggerInfo *) dobj);
   11900           44 :             break;
   11901         2563 :         case DO_CONSTRAINT:
   11902         2563 :             dumpConstraint(fout, (const ConstraintInfo *) dobj);
   11903         2563 :             break;
   11904          237 :         case DO_FK_CONSTRAINT:
   11905          237 :             dumpConstraint(fout, (const ConstraintInfo *) dobj);
   11906          237 :             break;
   11907           87 :         case DO_PROCLANG:
   11908           87 :             dumpProcLang(fout, (const ProcLangInfo *) dobj);
   11909           87 :             break;
   11910           69 :         case DO_CAST:
   11911           69 :             dumpCast(fout, (const CastInfo *) dobj);
   11912           69 :             break;
   11913           44 :         case DO_TRANSFORM:
   11914           44 :             dumpTransform(fout, (const TransformInfo *) dobj);
   11915           44 :             break;
   11916          408 :         case DO_SEQUENCE_SET:
   11917          408 :             dumpSequenceData(fout, (const TableDataInfo *) dobj);
   11918          408 :             break;
   11919         4738 :         case DO_TABLE_DATA:
   11920         4738 :             dumpTableData(fout, (const TableDataInfo *) dobj);
   11921         4738 :             break;
   11922        15639 :         case DO_DUMMY_TYPE:
   11923              :             /* table rowtypes and array types are never dumped separately */
   11924        15639 :             break;
   11925           44 :         case DO_TSPARSER:
   11926           44 :             dumpTSParser(fout, (const TSParserInfo *) dobj);
   11927           44 :             break;
   11928          182 :         case DO_TSDICT:
   11929          182 :             dumpTSDictionary(fout, (const TSDictInfo *) dobj);
   11930          182 :             break;
   11931           56 :         case DO_TSTEMPLATE:
   11932           56 :             dumpTSTemplate(fout, (const TSTemplateInfo *) dobj);
   11933           56 :             break;
   11934          157 :         case DO_TSCONFIG:
   11935          157 :             dumpTSConfig(fout, (const TSConfigInfo *) dobj);
   11936          157 :             break;
   11937           54 :         case DO_FDW:
   11938           54 :             dumpForeignDataWrapper(fout, (const FdwInfo *) dobj);
   11939           54 :             break;
   11940           58 :         case DO_FOREIGN_SERVER:
   11941           58 :             dumpForeignServer(fout, (const ForeignServerInfo *) dobj);
   11942           58 :             break;
   11943          170 :         case DO_DEFAULT_ACL:
   11944          170 :             dumpDefaultACL(fout, (const DefaultACLInfo *) dobj);
   11945          170 :             break;
   11946           88 :         case DO_LARGE_OBJECT:
   11947           88 :             dumpLO(fout, (const LoInfo *) dobj);
   11948           88 :             break;
   11949           88 :         case DO_LARGE_OBJECT_DATA:
   11950           88 :             if (dobj->dump & DUMP_COMPONENT_DATA)
   11951              :             {
   11952              :                 LoInfo     *loinfo;
   11953              :                 TocEntry   *te;
   11954              : 
   11955           88 :                 loinfo = (LoInfo *) findObjectByDumpId(dobj->dependencies[0]);
   11956           88 :                 if (loinfo == NULL)
   11957            0 :                     pg_fatal("missing metadata for large objects \"%s\"",
   11958              :                              dobj->name);
   11959              : 
   11960           88 :                 te = ArchiveEntry(fout, dobj->catId, dobj->dumpId,
   11961           88 :                                   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           88 :                 te->dataLength = loinfo->numlos * (pgoff_t) 8192;
   11980              :             }
   11981           88 :             break;
   11982          357 :         case DO_POLICY:
   11983          357 :             dumpPolicy(fout, (const PolicyInfo *) dobj);
   11984          357 :             break;
   11985          416 :         case DO_PUBLICATION:
   11986          416 :             dumpPublication(fout, (const PublicationInfo *) dobj);
   11987          416 :             break;
   11988          298 :         case DO_PUBLICATION_REL:
   11989          298 :             dumpPublicationTable(fout, (const PublicationRelInfo *) dobj);
   11990          298 :             break;
   11991          103 :         case DO_PUBLICATION_TABLE_IN_SCHEMA:
   11992          103 :             dumpPublicationNamespace(fout,
   11993              :                                      (const PublicationSchemaInfo *) dobj);
   11994          103 :             break;
   11995          116 :         case DO_SUBSCRIPTION:
   11996          116 :             dumpSubscription(fout, (const SubscriptionInfo *) dobj);
   11997          116 :             break;
   11998            3 :         case DO_SUBSCRIPTION_REL:
   11999            3 :             dumpSubscriptionTable(fout, (const SubRelInfo *) dobj);
   12000            3 :             break;
   12001         3678 :         case DO_REL_STATS:
   12002         3678 :             dumpRelationStats(fout, (const RelStatsInfo *) dobj);
   12003         3678 :             break;
   12004          524 :         case DO_PRE_DATA_BOUNDARY:
   12005              :         case DO_POST_DATA_BOUNDARY:
   12006              :             /* never dumped, nothing to do */
   12007          524 :             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          669 : dumpNamespace(Archive *fout, const NamespaceInfo *nspinfo)
   12017              : {
   12018          669 :     DumpOptions *dopt = fout->dopt;
   12019              :     PQExpBuffer q;
   12020              :     PQExpBuffer delq;
   12021              :     char       *qnspname;
   12022              : 
   12023              :     /* Do nothing if not dumping schema */
   12024          669 :     if (!dopt->dumpSchema)
   12025           29 :         return;
   12026              : 
   12027          640 :     q = createPQExpBuffer();
   12028          640 :     delq = createPQExpBuffer();
   12029              : 
   12030          640 :     qnspname = pg_strdup(fmtId(nspinfo->dobj.name));
   12031              : 
   12032          640 :     if (nspinfo->create)
   12033              :     {
   12034          414 :         appendPQExpBuffer(delq, "DROP SCHEMA %s;\n", qnspname);
   12035          414 :         appendPQExpBuffer(q, "CREATE SCHEMA %s;\n", qnspname);
   12036              :     }
   12037              :     else
   12038              :     {
   12039              :         /* see selectDumpableNamespace() */
   12040          226 :         appendPQExpBufferStr(delq,
   12041              :                              "-- *not* dropping schema, since initdb creates it\n");
   12042          226 :         appendPQExpBufferStr(q,
   12043              :                              "-- *not* creating schema, since initdb creates it\n");
   12044              :     }
   12045              : 
   12046          640 :     if (dopt->binary_upgrade)
   12047          102 :         binary_upgrade_extension_member(q, &nspinfo->dobj,
   12048              :                                         "SCHEMA", qnspname, NULL);
   12049              : 
   12050          640 :     if (nspinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   12051          220 :         ArchiveEntry(fout, nspinfo->dobj.catId, nspinfo->dobj.dumpId,
   12052          220 :                      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          640 :     if (nspinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   12061              :     {
   12062          231 :         const char *initdb_comment = NULL;
   12063              : 
   12064          231 :         if (!nspinfo->create && strcmp(qnspname, "public") == 0)
   12065          188 :             initdb_comment = "standard public schema";
   12066          231 :         dumpCommentExtended(fout, "SCHEMA", qnspname,
   12067          231 :                             NULL, nspinfo->rolname,
   12068          231 :                             nspinfo->dobj.catId, 0, nspinfo->dobj.dumpId,
   12069              :                             initdb_comment);
   12070              :     }
   12071              : 
   12072          640 :     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          640 :     if (nspinfo->dobj.dump & DUMP_COMPONENT_ACL)
   12078          536 :         dumpACL(fout, nspinfo->dobj.dumpId, InvalidDumpId, "SCHEMA",
   12079              :                 qnspname, NULL, NULL,
   12080          536 :                 NULL, nspinfo->rolname, &nspinfo->dacl);
   12081              : 
   12082          640 :     free(qnspname);
   12083              : 
   12084          640 :     destroyPQExpBuffer(q);
   12085          640 :     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          971 : dumpType(Archive *fout, const TypeInfo *tyinfo)
   12217              : {
   12218          971 :     DumpOptions *dopt = fout->dopt;
   12219              : 
   12220              :     /* Do nothing if not dumping schema */
   12221          971 :     if (!dopt->dumpSchema)
   12222           56 :         return;
   12223              : 
   12224              :     /* Dump out in proper style */
   12225          915 :     if (tyinfo->typtype == TYPTYPE_BASE)
   12226          285 :         dumpBaseType(fout, tyinfo);
   12227          630 :     else if (tyinfo->typtype == TYPTYPE_DOMAIN)
   12228          174 :         dumpDomain(fout, tyinfo);
   12229          456 :     else if (tyinfo->typtype == TYPTYPE_COMPOSITE)
   12230          132 :         dumpCompositeType(fout, tyinfo);
   12231          324 :     else if (tyinfo->typtype == TYPTYPE_ENUM)
   12232           89 :         dumpEnumType(fout, tyinfo);
   12233          235 :     else if (tyinfo->typtype == TYPTYPE_RANGE)
   12234          121 :         dumpRangeType(fout, tyinfo);
   12235          114 :     else if (tyinfo->typtype == TYPTYPE_PSEUDO && !tyinfo->isDefined)
   12236           39 :         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           89 : dumpEnumType(Archive *fout, const TypeInfo *tyinfo)
   12248              : {
   12249           89 :     DumpOptions *dopt = fout->dopt;
   12250           89 :     PQExpBuffer q = createPQExpBuffer();
   12251           89 :     PQExpBuffer delq = createPQExpBuffer();
   12252           89 :     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           89 :     if (!fout->is_prepared[PREPQUERY_DUMPENUMTYPE])
   12264              :     {
   12265              :         /* Set up query for enum-specific details */
   12266           42 :         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           42 :         ExecuteSqlStatement(fout, query->data);
   12274              : 
   12275           42 :         fout->is_prepared[PREPQUERY_DUMPENUMTYPE] = true;
   12276              :     }
   12277              : 
   12278           89 :     printfPQExpBuffer(query,
   12279              :                       "EXECUTE dumpEnumType('%u')",
   12280           89 :                       tyinfo->dobj.catId.oid);
   12281              : 
   12282           89 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   12283              : 
   12284           89 :     num = PQntuples(res);
   12285              : 
   12286           89 :     qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
   12287           89 :     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           89 :     appendPQExpBuffer(delq, "DROP TYPE %s;\n", qualtypname);
   12294              : 
   12295           89 :     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           89 :     appendPQExpBuffer(q, "CREATE TYPE %s AS ENUM (",
   12301              :                       qualtypname);
   12302              : 
   12303           89 :     if (!dopt->binary_upgrade)
   12304              :     {
   12305           83 :         i_enumlabel = PQfnumber(res, "enumlabel");
   12306              : 
   12307              :         /* Labels with server-assigned oids */
   12308          498 :         for (i = 0; i < num; i++)
   12309              :         {
   12310          415 :             label = PQgetvalue(res, i, i_enumlabel);
   12311          415 :             if (i > 0)
   12312          332 :                 appendPQExpBufferChar(q, ',');
   12313          415 :             appendPQExpBufferStr(q, "\n    ");
   12314          415 :             appendStringLiteralAH(q, label, fout);
   12315              :         }
   12316              :     }
   12317              : 
   12318           89 :     appendPQExpBufferStr(q, "\n);\n");
   12319              : 
   12320           89 :     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           89 :     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           89 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   12348           89 :         ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
   12349           89 :                      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           89 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   12359           34 :         dumpComment(fout, "TYPE", qtypname,
   12360           34 :                     tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
   12361           34 :                     tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
   12362              : 
   12363           89 :     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           89 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
   12369           34 :         dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
   12370              :                 qtypname, NULL,
   12371           34 :                 tyinfo->dobj.namespace->dobj.name,
   12372           34 :                 NULL, tyinfo->rolname, &tyinfo->dacl);
   12373              : 
   12374           89 :     PQclear(res);
   12375           89 :     destroyPQExpBuffer(q);
   12376           89 :     destroyPQExpBuffer(delq);
   12377           89 :     destroyPQExpBuffer(query);
   12378           89 :     free(qtypname);
   12379           89 :     free(qualtypname);
   12380           89 : }
   12381              : 
   12382              : /*
   12383              :  * dumpRangeType
   12384              :  *    writes out to fout the queries to recreate a user-defined range type
   12385              :  */
   12386              : static void
   12387          121 : dumpRangeType(Archive *fout, const TypeInfo *tyinfo)
   12388              : {
   12389          121 :     DumpOptions *dopt = fout->dopt;
   12390          121 :     PQExpBuffer q = createPQExpBuffer();
   12391          121 :     PQExpBuffer delq = createPQExpBuffer();
   12392          121 :     PQExpBuffer query = createPQExpBuffer();
   12393              :     PGresult   *res;
   12394              :     Oid         collationOid;
   12395              :     char       *qtypname;
   12396              :     char       *qualtypname;
   12397              :     char       *procname;
   12398              : 
   12399          121 :     if (!fout->is_prepared[PREPQUERY_DUMPRANGETYPE])
   12400              :     {
   12401              :         /* Set up query for range-specific details */
   12402           42 :         appendPQExpBufferStr(query,
   12403              :                              "PREPARE dumpRangeType(pg_catalog.oid) AS\n");
   12404              : 
   12405           42 :         appendPQExpBufferStr(query,
   12406              :                              "SELECT ");
   12407              : 
   12408           42 :         if (fout->remoteVersion >= 140000)
   12409           42 :             appendPQExpBufferStr(query,
   12410              :                                  "pg_catalog.format_type(rngmultitypid, NULL) AS rngmultitype, ");
   12411              :         else
   12412            0 :             appendPQExpBufferStr(query,
   12413              :                                  "NULL AS rngmultitype, ");
   12414              : 
   12415           42 :         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           42 :         ExecuteSqlStatement(fout, query->data);
   12430              : 
   12431           42 :         fout->is_prepared[PREPQUERY_DUMPRANGETYPE] = true;
   12432              :     }
   12433              : 
   12434          121 :     printfPQExpBuffer(query,
   12435              :                       "EXECUTE dumpRangeType('%u')",
   12436          121 :                       tyinfo->dobj.catId.oid);
   12437              : 
   12438          121 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   12439              : 
   12440          121 :     qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
   12441          121 :     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          121 :     appendPQExpBuffer(delq, "DROP TYPE %s;\n", qualtypname);
   12448              : 
   12449          121 :     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          121 :     appendPQExpBuffer(q, "CREATE TYPE %s AS RANGE (",
   12455              :                       qualtypname);
   12456              : 
   12457          121 :     appendPQExpBuffer(q, "\n    subtype = %s",
   12458              :                       PQgetvalue(res, 0, PQfnumber(res, "rngsubtype")));
   12459              : 
   12460          121 :     if (!PQgetisnull(res, 0, PQfnumber(res, "rngmultitype")))
   12461          121 :         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          121 :     if (PQgetvalue(res, 0, PQfnumber(res, "opcdefault"))[0] != 't')
   12466              :     {
   12467           34 :         char       *opcname = PQgetvalue(res, 0, PQfnumber(res, "opcname"));
   12468           34 :         char       *nspname = PQgetvalue(res, 0, PQfnumber(res, "opcnsp"));
   12469              : 
   12470           34 :         appendPQExpBuffer(q, ",\n    subtype_opclass = %s.",
   12471              :                           fmtId(nspname));
   12472           34 :         appendPQExpBufferStr(q, fmtId(opcname));
   12473              :     }
   12474              : 
   12475          121 :     collationOid = atooid(PQgetvalue(res, 0, PQfnumber(res, "collation")));
   12476          121 :     if (OidIsValid(collationOid))
   12477              :     {
   12478           39 :         CollInfo   *coll = findCollationByOid(collationOid);
   12479              : 
   12480           39 :         if (coll)
   12481           39 :             appendPQExpBuffer(q, ",\n    collation = %s",
   12482           39 :                               fmtQualifiedDumpable(coll));
   12483              :     }
   12484              : 
   12485          121 :     procname = PQgetvalue(res, 0, PQfnumber(res, "rngcanonical"));
   12486          121 :     if (strcmp(procname, "-") != 0)
   12487            9 :         appendPQExpBuffer(q, ",\n    canonical = %s", procname);
   12488              : 
   12489          121 :     procname = PQgetvalue(res, 0, PQfnumber(res, "rngsubdiff"));
   12490          121 :     if (strcmp(procname, "-") != 0)
   12491           23 :         appendPQExpBuffer(q, ",\n    subtype_diff = %s", procname);
   12492              : 
   12493          121 :     appendPQExpBufferStr(q, "\n);\n");
   12494              : 
   12495          121 :     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          121 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   12501          121 :         ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
   12502          121 :                      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          121 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   12512           52 :         dumpComment(fout, "TYPE", qtypname,
   12513           52 :                     tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
   12514           52 :                     tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
   12515              : 
   12516          121 :     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          121 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
   12522           34 :         dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
   12523              :                 qtypname, NULL,
   12524           34 :                 tyinfo->dobj.namespace->dobj.name,
   12525           34 :                 NULL, tyinfo->rolname, &tyinfo->dacl);
   12526              : 
   12527          121 :     PQclear(res);
   12528          121 :     destroyPQExpBuffer(q);
   12529          121 :     destroyPQExpBuffer(delq);
   12530          121 :     destroyPQExpBuffer(query);
   12531          121 :     free(qtypname);
   12532          121 :     free(qualtypname);
   12533          121 : }
   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           39 : dumpUndefinedType(Archive *fout, const TypeInfo *tyinfo)
   12546              : {
   12547           39 :     DumpOptions *dopt = fout->dopt;
   12548           39 :     PQExpBuffer q = createPQExpBuffer();
   12549           39 :     PQExpBuffer delq = createPQExpBuffer();
   12550              :     char       *qtypname;
   12551              :     char       *qualtypname;
   12552              : 
   12553           39 :     qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
   12554           39 :     qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
   12555              : 
   12556           39 :     appendPQExpBuffer(delq, "DROP TYPE %s;\n", qualtypname);
   12557              : 
   12558           39 :     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           39 :     appendPQExpBuffer(q, "CREATE TYPE %s;\n",
   12564              :                       qualtypname);
   12565              : 
   12566           39 :     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           39 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   12572           39 :         ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
   12573           39 :                      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           39 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   12583           34 :         dumpComment(fout, "TYPE", qtypname,
   12584           34 :                     tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
   12585           34 :                     tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
   12586              : 
   12587           39 :     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           39 :     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           39 :     destroyPQExpBuffer(q);
   12599           39 :     destroyPQExpBuffer(delq);
   12600           39 :     free(qtypname);
   12601           39 :     free(qualtypname);
   12602           39 : }
   12603              : 
   12604              : /*
   12605              :  * dumpBaseType
   12606              :  *    writes out to fout the queries to recreate a user-defined base type
   12607              :  */
   12608              : static void
   12609          285 : dumpBaseType(Archive *fout, const TypeInfo *tyinfo)
   12610              : {
   12611          285 :     DumpOptions *dopt = fout->dopt;
   12612          285 :     PQExpBuffer q = createPQExpBuffer();
   12613          285 :     PQExpBuffer delq = createPQExpBuffer();
   12614          285 :     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          285 :     bool        typdefault_is_literal = false;
   12642              : 
   12643          285 :     if (!fout->is_prepared[PREPQUERY_DUMPBASETYPE])
   12644              :     {
   12645              :         /* Set up query for type-specific details */
   12646           42 :         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           42 :         if (fout->remoteVersion >= 140000)
   12663           42 :             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           42 :         appendPQExpBufferStr(query, "FROM pg_catalog.pg_type "
   12671              :                              "WHERE oid = $1");
   12672              : 
   12673           42 :         ExecuteSqlStatement(fout, query->data);
   12674              : 
   12675           42 :         fout->is_prepared[PREPQUERY_DUMPBASETYPE] = true;
   12676              :     }
   12677              : 
   12678          285 :     printfPQExpBuffer(query,
   12679              :                       "EXECUTE dumpBaseType('%u')",
   12680          285 :                       tyinfo->dobj.catId.oid);
   12681              : 
   12682          285 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   12683              : 
   12684          285 :     typlen = PQgetvalue(res, 0, PQfnumber(res, "typlen"));
   12685          285 :     typinput = PQgetvalue(res, 0, PQfnumber(res, "typinput"));
   12686          285 :     typoutput = PQgetvalue(res, 0, PQfnumber(res, "typoutput"));
   12687          285 :     typreceive = PQgetvalue(res, 0, PQfnumber(res, "typreceive"));
   12688          285 :     typsend = PQgetvalue(res, 0, PQfnumber(res, "typsend"));
   12689          285 :     typmodin = PQgetvalue(res, 0, PQfnumber(res, "typmodin"));
   12690          285 :     typmodout = PQgetvalue(res, 0, PQfnumber(res, "typmodout"));
   12691          285 :     typanalyze = PQgetvalue(res, 0, PQfnumber(res, "typanalyze"));
   12692          285 :     typsubscript = PQgetvalue(res, 0, PQfnumber(res, "typsubscript"));
   12693          285 :     typreceiveoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typreceiveoid")));
   12694          285 :     typsendoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typsendoid")));
   12695          285 :     typmodinoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typmodinoid")));
   12696          285 :     typmodoutoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typmodoutoid")));
   12697          285 :     typanalyzeoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typanalyzeoid")));
   12698          285 :     typsubscriptoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typsubscriptoid")));
   12699          285 :     typcategory = PQgetvalue(res, 0, PQfnumber(res, "typcategory"));
   12700          285 :     typispreferred = PQgetvalue(res, 0, PQfnumber(res, "typispreferred"));
   12701          285 :     typdelim = PQgetvalue(res, 0, PQfnumber(res, "typdelim"));
   12702          285 :     typbyval = PQgetvalue(res, 0, PQfnumber(res, "typbyval"));
   12703          285 :     typalign = PQgetvalue(res, 0, PQfnumber(res, "typalign"));
   12704          285 :     typstorage = PQgetvalue(res, 0, PQfnumber(res, "typstorage"));
   12705          285 :     typcollatable = PQgetvalue(res, 0, PQfnumber(res, "typcollatable"));
   12706          285 :     if (!PQgetisnull(res, 0, PQfnumber(res, "typdefaultbin")))
   12707            0 :         typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefaultbin"));
   12708          285 :     else if (!PQgetisnull(res, 0, PQfnumber(res, "typdefault")))
   12709              :     {
   12710           44 :         typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefault"));
   12711           44 :         typdefault_is_literal = true;   /* it needs quotes */
   12712              :     }
   12713              :     else
   12714          241 :         typdefault = NULL;
   12715              : 
   12716          285 :     qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
   12717          285 :     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          285 :     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          285 :     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          285 :     appendPQExpBuffer(q,
   12736              :                       "CREATE TYPE %s (\n"
   12737              :                       "    INTERNALLENGTH = %s",
   12738              :                       qualtypname,
   12739          285 :                       (strcmp(typlen, "-1") == 0) ? "variable" : typlen);
   12740              : 
   12741              :     /* regproc result is sufficiently quoted already */
   12742          285 :     appendPQExpBuffer(q, ",\n    INPUT = %s", typinput);
   12743          285 :     appendPQExpBuffer(q, ",\n    OUTPUT = %s", typoutput);
   12744          285 :     if (OidIsValid(typreceiveoid))
   12745          210 :         appendPQExpBuffer(q, ",\n    RECEIVE = %s", typreceive);
   12746          285 :     if (OidIsValid(typsendoid))
   12747          210 :         appendPQExpBuffer(q, ",\n    SEND = %s", typsend);
   12748          285 :     if (OidIsValid(typmodinoid))
   12749           35 :         appendPQExpBuffer(q, ",\n    TYPMOD_IN = %s", typmodin);
   12750          285 :     if (OidIsValid(typmodoutoid))
   12751           35 :         appendPQExpBuffer(q, ",\n    TYPMOD_OUT = %s", typmodout);
   12752          285 :     if (OidIsValid(typanalyzeoid))
   12753            3 :         appendPQExpBuffer(q, ",\n    ANALYZE = %s", typanalyze);
   12754              : 
   12755          285 :     if (strcmp(typcollatable, "t") == 0)
   12756           30 :         appendPQExpBufferStr(q, ",\n    COLLATABLE = true");
   12757              : 
   12758          285 :     if (typdefault != NULL)
   12759              :     {
   12760           44 :         appendPQExpBufferStr(q, ",\n    DEFAULT = ");
   12761           44 :         if (typdefault_is_literal)
   12762           44 :             appendStringLiteralAH(q, typdefault, fout);
   12763              :         else
   12764            0 :             appendPQExpBufferStr(q, typdefault);
   12765              :     }
   12766              : 
   12767          285 :     if (OidIsValid(typsubscriptoid))
   12768           29 :         appendPQExpBuffer(q, ",\n    SUBSCRIPT = %s", typsubscript);
   12769              : 
   12770          285 :     if (OidIsValid(tyinfo->typelem))
   12771           26 :         appendPQExpBuffer(q, ",\n    ELEMENT = %s",
   12772           26 :                           getFormattedTypeName(fout, tyinfo->typelem,
   12773              :                                                zeroIsError));
   12774              : 
   12775          285 :     if (strcmp(typcategory, "U") != 0)
   12776              :     {
   12777          161 :         appendPQExpBufferStr(q, ",\n    CATEGORY = ");
   12778          161 :         appendStringLiteralAH(q, typcategory, fout);
   12779              :     }
   12780              : 
   12781          285 :     if (strcmp(typispreferred, "t") == 0)
   12782           29 :         appendPQExpBufferStr(q, ",\n    PREFERRED = true");
   12783              : 
   12784          285 :     if (typdelim && strcmp(typdelim, ",") != 0)
   12785              :     {
   12786            3 :         appendPQExpBufferStr(q, ",\n    DELIMITER = ");
   12787            3 :         appendStringLiteralAH(q, typdelim, fout);
   12788              :     }
   12789              : 
   12790          285 :     if (*typalign == TYPALIGN_CHAR)
   12791           12 :         appendPQExpBufferStr(q, ",\n    ALIGNMENT = char");
   12792          273 :     else if (*typalign == TYPALIGN_SHORT)
   12793            6 :         appendPQExpBufferStr(q, ",\n    ALIGNMENT = int2");
   12794          267 :     else if (*typalign == TYPALIGN_INT)
   12795          189 :         appendPQExpBufferStr(q, ",\n    ALIGNMENT = int4");
   12796           78 :     else if (*typalign == TYPALIGN_DOUBLE)
   12797           78 :         appendPQExpBufferStr(q, ",\n    ALIGNMENT = double");
   12798              : 
   12799          285 :     if (*typstorage == TYPSTORAGE_PLAIN)
   12800          210 :         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          285 :     if (strcmp(typbyval, "t") == 0)
   12809          139 :         appendPQExpBufferStr(q, ",\n    PASSEDBYVALUE");
   12810              : 
   12811          285 :     appendPQExpBufferStr(q, "\n);\n");
   12812              : 
   12813          285 :     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          285 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   12819          285 :         ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
   12820          285 :                      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          285 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   12830          250 :         dumpComment(fout, "TYPE", qtypname,
   12831          250 :                     tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
   12832          250 :                     tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
   12833              : 
   12834          285 :     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          285 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
   12840           34 :         dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
   12841              :                 qtypname, NULL,
   12842           34 :                 tyinfo->dobj.namespace->dobj.name,
   12843           34 :                 NULL, tyinfo->rolname, &tyinfo->dacl);
   12844              : 
   12845          285 :     PQclear(res);
   12846          285 :     destroyPQExpBuffer(q);
   12847          285 :     destroyPQExpBuffer(delq);
   12848          285 :     destroyPQExpBuffer(query);
   12849          285 :     free(qtypname);
   12850          285 :     free(qualtypname);
   12851          285 : }
   12852              : 
   12853              : /*
   12854              :  * dumpDomain
   12855              :  *    writes out to fout the queries to recreate a user-defined domain
   12856              :  */
   12857              : static void
   12858          174 : dumpDomain(Archive *fout, const TypeInfo *tyinfo)
   12859              : {
   12860          174 :     DumpOptions *dopt = fout->dopt;
   12861          174 :     PQExpBuffer q = createPQExpBuffer();
   12862          174 :     PQExpBuffer delq = createPQExpBuffer();
   12863          174 :     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          174 :     bool        typdefault_is_literal = false;
   12873              : 
   12874          174 :     if (!fout->is_prepared[PREPQUERY_DUMPDOMAIN])
   12875              :     {
   12876              :         /* Set up query for domain-specific details */
   12877           39 :         appendPQExpBufferStr(query,
   12878              :                              "PREPARE dumpDomain(pg_catalog.oid) AS\n");
   12879              : 
   12880           39 :         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           39 :         ExecuteSqlStatement(fout, query->data);
   12891              : 
   12892           39 :         fout->is_prepared[PREPQUERY_DUMPDOMAIN] = true;
   12893              :     }
   12894              : 
   12895          174 :     printfPQExpBuffer(query,
   12896              :                       "EXECUTE dumpDomain('%u')",
   12897          174 :                       tyinfo->dobj.catId.oid);
   12898              : 
   12899          174 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   12900              : 
   12901          174 :     typnotnull = PQgetvalue(res, 0, PQfnumber(res, "typnotnull"));
   12902          174 :     typdefn = PQgetvalue(res, 0, PQfnumber(res, "typdefn"));
   12903          174 :     if (!PQgetisnull(res, 0, PQfnumber(res, "typdefaultbin")))
   12904           39 :         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          174 :     typcollation = atooid(PQgetvalue(res, 0, PQfnumber(res, "typcollation")));
   12913              : 
   12914          174 :     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          174 :     qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
   12921          174 :     qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
   12922              : 
   12923          174 :     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          174 :     if (OidIsValid(typcollation))
   12930              :     {
   12931              :         CollInfo   *coll;
   12932              : 
   12933           34 :         coll = findCollationByOid(typcollation);
   12934           34 :         if (coll)
   12935           34 :             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          174 :     if (typnotnull[0] == 't')
   12945              :     {
   12946           49 :         if (fout->remoteVersion < 170000 || tyinfo->notnull == NULL)
   12947            0 :             appendPQExpBufferStr(q, " NOT NULL");
   12948              :         else
   12949              :         {
   12950           49 :             ConstraintInfo *notnull = tyinfo->notnull;
   12951              : 
   12952           49 :             if (!notnull->separate)
   12953              :             {
   12954              :                 char       *default_name;
   12955              : 
   12956              :                 /* XXX should match ChooseConstraintName better */
   12957           49 :                 default_name = psprintf("%s_not_null", tyinfo->dobj.name);
   12958              : 
   12959           49 :                 if (strcmp(default_name, notnull->dobj.name) == 0)
   12960           15 :                     appendPQExpBufferStr(q, " NOT NULL");
   12961              :                 else
   12962           34 :                     appendPQExpBuffer(q, " CONSTRAINT %s %s",
   12963           34 :                                       fmtId(notnull->dobj.name), notnull->condef);
   12964           49 :                 free(default_name);
   12965              :             }
   12966              :         }
   12967              :     }
   12968              : 
   12969          174 :     if (typdefault != NULL)
   12970              :     {
   12971           39 :         appendPQExpBufferStr(q, " DEFAULT ");
   12972           39 :         if (typdefault_is_literal)
   12973            0 :             appendStringLiteralAH(q, typdefault, fout);
   12974              :         else
   12975           39 :             appendPQExpBufferStr(q, typdefault);
   12976              :     }
   12977              : 
   12978          174 :     PQclear(res);
   12979              : 
   12980              :     /*
   12981              :      * Add any CHECK constraints for the domain
   12982              :      */
   12983          303 :     for (i = 0; i < tyinfo->nDomChecks; i++)
   12984              :     {
   12985          129 :         ConstraintInfo *domcheck = &(tyinfo->domChecks[i]);
   12986              : 
   12987          129 :         if (!domcheck->separate && domcheck->contype == 'c')
   12988          124 :             appendPQExpBuffer(q, "\n\tCONSTRAINT %s %s",
   12989          124 :                               fmtId(domcheck->dobj.name), domcheck->condef);
   12990              :     }
   12991              : 
   12992          174 :     appendPQExpBufferStr(q, ";\n");
   12993              : 
   12994          174 :     appendPQExpBuffer(delq, "DROP DOMAIN %s;\n", qualtypname);
   12995              : 
   12996          174 :     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          174 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   13002          174 :         ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
   13003          174 :                      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          174 :     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          174 :     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          174 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
   13023           34 :         dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
   13024              :                 qtypname, NULL,
   13025           34 :                 tyinfo->dobj.namespace->dobj.name,
   13026           34 :                 NULL, tyinfo->rolname, &tyinfo->dacl);
   13027              : 
   13028              :     /* Dump any per-constraint comments */
   13029          303 :     for (i = 0; i < tyinfo->nDomChecks; i++)
   13030              :     {
   13031          129 :         ConstraintInfo *domcheck = &(tyinfo->domChecks[i]);
   13032              :         PQExpBuffer conprefix;
   13033              : 
   13034              :         /* but only if the constraint itself was dumped here */
   13035          129 :         if (domcheck->separate)
   13036            5 :             continue;
   13037              : 
   13038          124 :         conprefix = createPQExpBuffer();
   13039          124 :         appendPQExpBuffer(conprefix, "CONSTRAINT %s ON DOMAIN",
   13040          124 :                           fmtId(domcheck->dobj.name));
   13041              : 
   13042          124 :         if (domcheck->dobj.dump & DUMP_COMPONENT_COMMENT)
   13043           34 :             dumpComment(fout, conprefix->data, qtypname,
   13044           34 :                         tyinfo->dobj.namespace->dobj.name,
   13045           34 :                         tyinfo->rolname,
   13046           34 :                         domcheck->dobj.catId, 0, tyinfo->dobj.dumpId);
   13047              : 
   13048          124 :         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          174 :     if (tyinfo->notnull != NULL && !tyinfo->notnull->separate)
   13056              :     {
   13057           49 :         PQExpBuffer conprefix = createPQExpBuffer();
   13058              : 
   13059           49 :         appendPQExpBuffer(conprefix, "CONSTRAINT %s ON DOMAIN",
   13060           49 :                           fmtId(tyinfo->notnull->dobj.name));
   13061              : 
   13062           49 :         if (tyinfo->notnull->dobj.dump & DUMP_COMPONENT_COMMENT)
   13063           34 :             dumpComment(fout, conprefix->data, qtypname,
   13064           34 :                         tyinfo->dobj.namespace->dobj.name,
   13065           34 :                         tyinfo->rolname,
   13066           34 :                         tyinfo->notnull->dobj.catId, 0, tyinfo->dobj.dumpId);
   13067           49 :         destroyPQExpBuffer(conprefix);
   13068              :     }
   13069              : 
   13070          174 :     destroyPQExpBuffer(q);
   13071          174 :     destroyPQExpBuffer(delq);
   13072          174 :     destroyPQExpBuffer(query);
   13073          174 :     free(qtypname);
   13074          174 :     free(qualtypname);
   13075          174 : }
   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          132 : dumpCompositeType(Archive *fout, const TypeInfo *tyinfo)
   13084              : {
   13085          132 :     DumpOptions *dopt = fout->dopt;
   13086          132 :     PQExpBuffer q = createPQExpBuffer();
   13087          132 :     PQExpBuffer dropped = createPQExpBuffer();
   13088          132 :     PQExpBuffer delq = createPQExpBuffer();
   13089          132 :     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          132 :     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           57 :         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           57 :         ExecuteSqlStatement(fout, query->data);
   13127              : 
   13128           57 :         fout->is_prepared[PREPQUERY_DUMPCOMPOSITETYPE] = true;
   13129              :     }
   13130              : 
   13131          132 :     printfPQExpBuffer(query,
   13132              :                       "EXECUTE dumpCompositeType('%u')",
   13133          132 :                       tyinfo->dobj.catId.oid);
   13134              : 
   13135          132 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   13136              : 
   13137          132 :     ntups = PQntuples(res);
   13138              : 
   13139          132 :     i_attname = PQfnumber(res, "attname");
   13140          132 :     i_atttypdefn = PQfnumber(res, "atttypdefn");
   13141          132 :     i_attlen = PQfnumber(res, "attlen");
   13142          132 :     i_attalign = PQfnumber(res, "attalign");
   13143          132 :     i_attisdropped = PQfnumber(res, "attisdropped");
   13144          132 :     i_attcollation = PQfnumber(res, "attcollation");
   13145              : 
   13146          132 :     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          132 :     qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
   13155          132 :     qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
   13156              : 
   13157          132 :     appendPQExpBuffer(q, "CREATE TYPE %s AS (",
   13158              :                       qualtypname);
   13159              : 
   13160          132 :     actual_atts = 0;
   13161          418 :     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          286 :         attname = PQgetvalue(res, i, i_attname);
   13171          286 :         atttypdefn = PQgetvalue(res, i, i_atttypdefn);
   13172          286 :         attlen = PQgetvalue(res, i, i_attlen);
   13173          286 :         attalign = PQgetvalue(res, i, i_attalign);
   13174          286 :         attisdropped = (PQgetvalue(res, i, i_attisdropped)[0] == 't');
   13175          286 :         attcollation = atooid(PQgetvalue(res, i, i_attcollation));
   13176              : 
   13177          286 :         if (attisdropped && !dopt->binary_upgrade)
   13178            8 :             continue;
   13179              : 
   13180              :         /* Format properly if not first attr */
   13181          278 :         if (actual_atts++ > 0)
   13182          146 :             appendPQExpBufferChar(q, ',');
   13183          278 :         appendPQExpBufferStr(q, "\n\t");
   13184              : 
   13185          278 :         if (!attisdropped)
   13186              :         {
   13187          276 :             appendPQExpBuffer(q, "%s %s", fmtId(attname), atttypdefn);
   13188              : 
   13189              :             /* Add collation if not default for the column type */
   13190          276 :             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          132 :     appendPQExpBufferStr(q, "\n);\n");
   13229          132 :     appendPQExpBufferStr(q, dropped->data);
   13230              : 
   13231          132 :     appendPQExpBuffer(delq, "DROP TYPE %s;\n", qualtypname);
   13232              : 
   13233          132 :     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          132 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   13239          115 :         ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
   13240          115 :                      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          132 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   13251           34 :         dumpComment(fout, "TYPE", qtypname,
   13252           34 :                     tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
   13253           34 :                     tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
   13254              : 
   13255          132 :     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          132 :     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          132 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   13268           34 :         dumpCompositeTypeColComments(fout, tyinfo, res);
   13269              : 
   13270          132 :     PQclear(res);
   13271          132 :     destroyPQExpBuffer(q);
   13272          132 :     destroyPQExpBuffer(dropped);
   13273          132 :     destroyPQExpBuffer(delq);
   13274          132 :     destroyPQExpBuffer(query);
   13275          132 :     free(qtypname);
   13276          132 :     free(qualtypname);
   13277          132 : }
   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           34 : 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           34 :     if (fout->dopt->no_comments)
   13304            0 :         return;
   13305              : 
   13306              :     /* Search for comments associated with type's pg_class OID */
   13307           34 :     ncomments = findComments(RelationRelationId, tyinfo->typrelid,
   13308              :                              &comments);
   13309              : 
   13310              :     /* If no comments exist, we're done */
   13311           34 :     if (ncomments <= 0)
   13312            0 :         return;
   13313              : 
   13314              :     /* Build COMMENT ON statements */
   13315           34 :     query = createPQExpBuffer();
   13316           34 :     target = createPQExpBuffer();
   13317              : 
   13318           34 :     ntups = PQntuples(res);
   13319           34 :     i_attnum = PQfnumber(res, "attnum");
   13320           34 :     i_attname = PQfnumber(res, "attname");
   13321           34 :     i_attisdropped = PQfnumber(res, "attisdropped");
   13322           68 :     while (ncomments > 0)
   13323              :     {
   13324              :         const char *attname;
   13325              : 
   13326           34 :         attname = NULL;
   13327           34 :         for (i = 0; i < ntups; i++)
   13328              :         {
   13329           34 :             if (atoi(PQgetvalue(res, i, i_attnum)) == comments->objsubid &&
   13330           34 :                 PQgetvalue(res, i, i_attisdropped)[0] != 't')
   13331              :             {
   13332           34 :                 attname = PQgetvalue(res, i, i_attname);
   13333           34 :                 break;
   13334              :             }
   13335              :         }
   13336           34 :         if (attname)            /* just in case we don't find it */
   13337              :         {
   13338           34 :             const char *descr = comments->descr;
   13339              : 
   13340           34 :             resetPQExpBuffer(target);
   13341           34 :             appendPQExpBuffer(target, "COLUMN %s.",
   13342           34 :                               fmtId(tyinfo->dobj.name));
   13343           34 :             appendPQExpBufferStr(target, fmtId(attname));
   13344              : 
   13345           34 :             resetPQExpBuffer(query);
   13346           34 :             appendPQExpBuffer(query, "COMMENT ON COLUMN %s.",
   13347           34 :                               fmtQualifiedDumpable(tyinfo));
   13348           34 :             appendPQExpBuffer(query, "%s IS ", fmtId(attname));
   13349           34 :             appendStringLiteralAH(query, descr, fout);
   13350           34 :             appendPQExpBufferStr(query, ";\n");
   13351              : 
   13352           34 :             ArchiveEntry(fout, nilCatalogId, createDumpId(),
   13353           34 :                          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           34 :         comments++;
   13364           34 :         ncomments--;
   13365              :     }
   13366              : 
   13367           34 :     destroyPQExpBuffer(query);
   13368           34 :     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           76 : dumpShellType(Archive *fout, const ShellTypeInfo *stinfo)
   13379              : {
   13380           76 :     DumpOptions *dopt = fout->dopt;
   13381              :     PQExpBuffer q;
   13382              : 
   13383              :     /* Do nothing if not dumping schema */
   13384           76 :     if (!dopt->dumpSchema)
   13385            7 :         return;
   13386              : 
   13387           69 :     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           69 :     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           69 :     appendPQExpBuffer(q, "CREATE TYPE %s;\n",
   13404           69 :                       fmtQualifiedDumpable(stinfo));
   13405              : 
   13406           69 :     if (stinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   13407           69 :         ArchiveEntry(fout, stinfo->dobj.catId, stinfo->dobj.dumpId,
   13408           69 :                      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           69 :     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           87 : dumpProcLang(Archive *fout, const ProcLangInfo *plang)
   13425              : {
   13426           87 :     DumpOptions *dopt = fout->dopt;
   13427              :     PQExpBuffer defqry;
   13428              :     PQExpBuffer delqry;
   13429              :     bool        useParams;
   13430              :     char       *qlanname;
   13431              :     FuncInfo   *funcInfo;
   13432           87 :     FuncInfo   *inlineInfo = NULL;
   13433           87 :     FuncInfo   *validatorInfo = NULL;
   13434              : 
   13435              :     /* Do nothing if not dumping schema */
   13436           87 :     if (!dopt->dumpSchema)
   13437           14 :         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           73 :     funcInfo = findFuncByOid(plang->lanplcallfoid);
   13448           73 :     if (funcInfo != NULL && !funcInfo->dobj.dump)
   13449            2 :         funcInfo = NULL;        /* treat not-dumped same as not-found */
   13450              : 
   13451           73 :     if (OidIsValid(plang->laninline))
   13452              :     {
   13453           40 :         inlineInfo = findFuncByOid(plang->laninline);
   13454           40 :         if (inlineInfo != NULL && !inlineInfo->dobj.dump)
   13455            1 :             inlineInfo = NULL;
   13456              :     }
   13457              : 
   13458           73 :     if (OidIsValid(plang->lanvalidator))
   13459              :     {
   13460           40 :         validatorInfo = findFuncByOid(plang->lanvalidator);
   13461           40 :         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           32 :     useParams = (funcInfo != NULL &&
   13471          137 :                  (inlineInfo != NULL || !OidIsValid(plang->laninline)) &&
   13472           32 :                  (validatorInfo != NULL || !OidIsValid(plang->lanvalidator)));
   13473              : 
   13474           73 :     defqry = createPQExpBuffer();
   13475           73 :     delqry = createPQExpBuffer();
   13476              : 
   13477           73 :     qlanname = pg_strdup(fmtId(plang->dobj.name));
   13478              : 
   13479           73 :     appendPQExpBuffer(delqry, "DROP PROCEDURAL LANGUAGE %s;\n",
   13480              :                       qlanname);
   13481              : 
   13482           73 :     if (useParams)
   13483              :     {
   13484           32 :         appendPQExpBuffer(defqry, "CREATE %sPROCEDURAL LANGUAGE %s",
   13485           32 :                           plang->lanpltrusted ? "TRUSTED " : "",
   13486              :                           qlanname);
   13487           32 :         appendPQExpBuffer(defqry, " HANDLER %s",
   13488           32 :                           fmtQualifiedDumpable(funcInfo));
   13489           32 :         if (OidIsValid(plang->laninline))
   13490            0 :             appendPQExpBuffer(defqry, " INLINE %s",
   13491            0 :                               fmtQualifiedDumpable(inlineInfo));
   13492           32 :         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           41 :         appendPQExpBuffer(defqry, "CREATE OR REPLACE PROCEDURAL LANGUAGE %s",
   13508              :                           qlanname);
   13509              :     }
   13510           73 :     appendPQExpBufferStr(defqry, ";\n");
   13511              : 
   13512           73 :     if (dopt->binary_upgrade)
   13513            2 :         binary_upgrade_extension_member(defqry, &plang->dobj,
   13514              :                                         "LANGUAGE", qlanname, NULL);
   13515              : 
   13516           73 :     if (plang->dobj.dump & DUMP_COMPONENT_DEFINITION)
   13517           33 :         ArchiveEntry(fout, plang->dobj.catId, plang->dobj.dumpId,
   13518           33 :                      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           73 :     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           73 :     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           73 :     if (plang->lanpltrusted && plang->dobj.dump & DUMP_COMPONENT_ACL)
   13538           40 :         dumpACL(fout, plang->dobj.dumpId, InvalidDumpId, "LANGUAGE",
   13539              :                 qlanname, NULL, NULL,
   13540           40 :                 NULL, plang->lanowner, &plang->dacl);
   13541              : 
   13542           73 :     free(qlanname);
   13543              : 
   13544           73 :     destroyPQExpBuffer(defqry);
   13545           73 :     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         4286 : format_function_arguments(const FuncInfo *finfo, const char *funcargs, bool is_agg)
   13557              : {
   13558              :     PQExpBufferData fn;
   13559              : 
   13560         4286 :     initPQExpBuffer(&fn);
   13561         4286 :     appendPQExpBufferStr(&fn, fmtId(finfo->dobj.name));
   13562         4286 :     if (is_agg && finfo->nargs == 0)
   13563           80 :         appendPQExpBufferStr(&fn, "(*)");
   13564              :     else
   13565         4206 :         appendPQExpBuffer(&fn, "(%s)", funcargs);
   13566         4286 :     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         2257 : format_function_signature(Archive *fout, const FuncInfo *finfo, bool honor_quotes)
   13580              : {
   13581              :     PQExpBufferData fn;
   13582              :     int         j;
   13583              : 
   13584         2257 :     initPQExpBuffer(&fn);
   13585         2257 :     if (honor_quotes)
   13586          401 :         appendPQExpBuffer(&fn, "%s(", fmtId(finfo->dobj.name));
   13587              :     else
   13588         1856 :         appendPQExpBuffer(&fn, "%s(", finfo->dobj.name);
   13589         4144 :     for (j = 0; j < finfo->nargs; j++)
   13590              :     {
   13591         1887 :         if (j > 0)
   13592          452 :             appendPQExpBufferStr(&fn, ", ");
   13593              : 
   13594         1887 :         appendPQExpBufferStr(&fn,
   13595         1887 :                              getFormattedTypeName(fout, finfo->argtypes[j],
   13596              :                                                   zeroIsError));
   13597              :     }
   13598         2257 :     appendPQExpBufferChar(&fn, ')');
   13599         2257 :     return fn.data;
   13600              : }
   13601              : 
   13602              : 
   13603              : /*
   13604              :  * dumpFunc:
   13605              :  *    dump out one function
   13606              :  */
   13607              : static void
   13608         1926 : dumpFunc(Archive *fout, const FuncInfo *finfo)
   13609              : {
   13610         1926 :     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         1926 :     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         1926 :     char      **configitems = NULL;
   13640         1926 :     int         nconfigitems = 0;
   13641              :     const char *keyword;
   13642              : 
   13643              :     /* Do nothing if not dumping schema */
   13644         1926 :     if (!dopt->dumpSchema)
   13645           70 :         return;
   13646              : 
   13647         1856 :     query = createPQExpBuffer();
   13648         1856 :     q = createPQExpBuffer();
   13649         1856 :     delqry = createPQExpBuffer();
   13650         1856 :     asPart = createPQExpBuffer();
   13651              : 
   13652         1856 :     if (!fout->is_prepared[PREPQUERY_DUMPFUNC])
   13653              :     {
   13654              :         /* Set up query for function-specific details */
   13655           78 :         appendPQExpBufferStr(query,
   13656              :                              "PREPARE dumpFunc(pg_catalog.oid) AS\n");
   13657              : 
   13658           78 :         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           78 :         if (fout->remoteVersion >= 90500)
   13676           78 :             appendPQExpBufferStr(query,
   13677              :                                  "array_to_string(protrftypes, ' ') AS protrftypes,\n");
   13678              :         else
   13679            0 :             appendPQExpBufferStr(query,
   13680              :                                  "NULL AS protrftypes,\n");
   13681              : 
   13682           78 :         if (fout->remoteVersion >= 90600)
   13683           78 :             appendPQExpBufferStr(query,
   13684              :                                  "proparallel,\n");
   13685              :         else
   13686            0 :             appendPQExpBufferStr(query,
   13687              :                                  "'u' AS proparallel,\n");
   13688              : 
   13689           78 :         if (fout->remoteVersion >= 110000)
   13690           78 :             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           78 :         if (fout->remoteVersion >= 120000)
   13697           78 :             appendPQExpBufferStr(query,
   13698              :                                  "prosupport,\n");
   13699              :         else
   13700            0 :             appendPQExpBufferStr(query,
   13701              :                                  "'-' AS prosupport,\n");
   13702              : 
   13703           78 :         if (fout->remoteVersion >= 140000)
   13704           78 :             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           78 :         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           78 :         ExecuteSqlStatement(fout, query->data);
   13716              : 
   13717           78 :         fout->is_prepared[PREPQUERY_DUMPFUNC] = true;
   13718              :     }
   13719              : 
   13720         1856 :     printfPQExpBuffer(query,
   13721              :                       "EXECUTE dumpFunc('%u')",
   13722         1856 :                       finfo->dobj.catId.oid);
   13723              : 
   13724         1856 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   13725              : 
   13726         1856 :     proretset = PQgetvalue(res, 0, PQfnumber(res, "proretset"));
   13727         1856 :     if (PQgetisnull(res, 0, PQfnumber(res, "prosqlbody")))
   13728              :     {
   13729         1806 :         prosrc = PQgetvalue(res, 0, PQfnumber(res, "prosrc"));
   13730         1806 :         probin = PQgetvalue(res, 0, PQfnumber(res, "probin"));
   13731         1806 :         prosqlbody = NULL;
   13732              :     }
   13733              :     else
   13734              :     {
   13735           50 :         prosrc = NULL;
   13736           50 :         probin = NULL;
   13737           50 :         prosqlbody = PQgetvalue(res, 0, PQfnumber(res, "prosqlbody"));
   13738              :     }
   13739         1856 :     funcargs = PQgetvalue(res, 0, PQfnumber(res, "funcargs"));
   13740         1856 :     funciargs = PQgetvalue(res, 0, PQfnumber(res, "funciargs"));
   13741         1856 :     funcresult = PQgetvalue(res, 0, PQfnumber(res, "funcresult"));
   13742         1856 :     protrftypes = PQgetvalue(res, 0, PQfnumber(res, "protrftypes"));
   13743         1856 :     prokind = PQgetvalue(res, 0, PQfnumber(res, "prokind"));
   13744         1856 :     provolatile = PQgetvalue(res, 0, PQfnumber(res, "provolatile"));
   13745         1856 :     proisstrict = PQgetvalue(res, 0, PQfnumber(res, "proisstrict"));
   13746         1856 :     prosecdef = PQgetvalue(res, 0, PQfnumber(res, "prosecdef"));
   13747         1856 :     proleakproof = PQgetvalue(res, 0, PQfnumber(res, "proleakproof"));
   13748         1856 :     proconfig = PQgetvalue(res, 0, PQfnumber(res, "proconfig"));
   13749         1856 :     procost = PQgetvalue(res, 0, PQfnumber(res, "procost"));
   13750         1856 :     prorows = PQgetvalue(res, 0, PQfnumber(res, "prorows"));
   13751         1856 :     prosupport = PQgetvalue(res, 0, PQfnumber(res, "prosupport"));
   13752         1856 :     proparallel = PQgetvalue(res, 0, PQfnumber(res, "proparallel"));
   13753         1856 :     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         1856 :     if (prosqlbody)
   13760              :     {
   13761           50 :         appendPQExpBufferStr(asPart, prosqlbody);
   13762              :     }
   13763         1806 :     else if (probin[0] != '\0')
   13764              :     {
   13765          160 :         appendPQExpBufferStr(asPart, "AS ");
   13766          160 :         appendStringLiteralAH(asPart, probin, fout);
   13767          160 :         if (prosrc[0] != '\0')
   13768              :         {
   13769          160 :             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          160 :             if (dopt->disable_dollar_quoting ||
   13776          160 :                 (strchr(prosrc, '\'') == NULL && strchr(prosrc, '\\') == NULL))
   13777          160 :                 appendStringLiteralAH(asPart, prosrc, fout);
   13778              :             else
   13779            0 :                 appendStringLiteralDQ(asPart, prosrc, NULL);
   13780              :         }
   13781              :     }
   13782              :     else
   13783              :     {
   13784         1646 :         appendPQExpBufferStr(asPart, "AS ");
   13785              :         /* with no bin, dollar quote src unconditionally if allowed */
   13786         1646 :         if (dopt->disable_dollar_quoting)
   13787            0 :             appendStringLiteralAH(asPart, prosrc, fout);
   13788              :         else
   13789         1646 :             appendStringLiteralDQ(asPart, prosrc, NULL);
   13790              :     }
   13791              : 
   13792         1856 :     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         1841 :         configitems = NULL;
   13800         1841 :         nconfigitems = 0;
   13801              :     }
   13802              : 
   13803         1856 :     funcfullsig = format_function_arguments(finfo, funcargs, false);
   13804         1856 :     funcsig = format_function_arguments(finfo, funciargs, false);
   13805              : 
   13806         1856 :     funcsig_tag = format_function_signature(fout, finfo, false);
   13807              : 
   13808         1856 :     qual_funcsig = psprintf("%s.%s",
   13809         1856 :                             fmtId(finfo->dobj.namespace->dobj.name),
   13810              :                             funcsig);
   13811              : 
   13812         1856 :     if (prokind[0] == PROKIND_PROCEDURE)
   13813           94 :         keyword = "PROCEDURE";
   13814              :     else
   13815         1762 :         keyword = "FUNCTION"; /* works for window functions too */
   13816              : 
   13817         1856 :     appendPQExpBuffer(delqry, "DROP %s %s;\n",
   13818              :                       keyword, qual_funcsig);
   13819              : 
   13820         3712 :     appendPQExpBuffer(q, "CREATE %s %s.%s",
   13821              :                       keyword,
   13822         1856 :                       fmtId(finfo->dobj.namespace->dobj.name),
   13823              :                       funcfullsig ? funcfullsig :
   13824              :                       funcsig);
   13825              : 
   13826         1856 :     if (prokind[0] == PROKIND_PROCEDURE)
   13827              :          /* no result type to output */ ;
   13828         1762 :     else if (funcresult)
   13829         1762 :         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         1856 :     appendPQExpBuffer(q, "\n    LANGUAGE %s", fmtId(lanname));
   13837              : 
   13838         1856 :     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         1856 :     if (prokind[0] == PROKIND_WINDOW)
   13857            5 :         appendPQExpBufferStr(q, " WINDOW");
   13858              : 
   13859         1856 :     if (provolatile[0] != PROVOLATILE_VOLATILE)
   13860              :     {
   13861          355 :         if (provolatile[0] == PROVOLATILE_IMMUTABLE)
   13862          334 :             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         1856 :     if (proisstrict[0] == 't')
   13871          364 :         appendPQExpBufferStr(q, " STRICT");
   13872              : 
   13873         1856 :     if (prosecdef[0] == 't')
   13874            0 :         appendPQExpBufferStr(q, " SECURITY DEFINER");
   13875              : 
   13876         1856 :     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         1856 :     if (strcmp(procost, "0") != 0)
   13885              :     {
   13886         1856 :         if (strcmp(lanname, "internal") == 0 || strcmp(lanname, "c") == 0)
   13887              :         {
   13888              :             /* default cost is 1 */
   13889          397 :             if (strcmp(procost, "1") != 0)
   13890            0 :                 appendPQExpBuffer(q, " COST %s", procost);
   13891              :         }
   13892              :         else
   13893              :         {
   13894              :             /* default cost is 100 */
   13895         1459 :             if (strcmp(procost, "100") != 0)
   13896           11 :                 appendPQExpBuffer(q, " COST %s", procost);
   13897              :         }
   13898              :     }
   13899         1856 :     if (proretset[0] == 't' &&
   13900          194 :         strcmp(prorows, "0") != 0 && strcmp(prorows, "1000") != 0)
   13901            0 :         appendPQExpBuffer(q, " ROWS %s", prorows);
   13902              : 
   13903         1856 :     if (strcmp(prosupport, "-") != 0)
   13904              :     {
   13905              :         /* We rely on regprocout to provide quoting and qualification */
   13906           44 :         appendPQExpBuffer(q, " SUPPORT %s", prosupport);
   13907              :     }
   13908              : 
   13909         1856 :     if (proparallel[0] != PROPARALLEL_UNSAFE)
   13910              :     {
   13911          120 :         if (proparallel[0] == PROPARALLEL_SAFE)
   13912          115 :             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         1896 :     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         1856 :     appendPQExpBuffer(q, "\n    %s;\n", asPart->data);
   13974              : 
   13975         1856 :     append_depends_on_extension(fout, q, &finfo->dobj,
   13976              :                                 "pg_catalog.pg_proc", keyword,
   13977              :                                 qual_funcsig);
   13978              : 
   13979         1856 :     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         1856 :     if (finfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   13985         1756 :         ArchiveEntry(fout, finfo->dobj.catId, finfo->dobj.dumpId,
   13986         1756 :                      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         1856 :     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         1856 :     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         1856 :     if (finfo->dobj.dump & DUMP_COMPONENT_ACL)
   14007          113 :         dumpACL(fout, finfo->dobj.dumpId, InvalidDumpId, keyword,
   14008              :                 funcsig, NULL,
   14009          113 :                 finfo->dobj.namespace->dobj.name,
   14010          113 :                 NULL, finfo->rolname, &finfo->dacl);
   14011              : 
   14012         1856 :     PQclear(res);
   14013              : 
   14014         1856 :     destroyPQExpBuffer(query);
   14015         1856 :     destroyPQExpBuffer(q);
   14016         1856 :     destroyPQExpBuffer(delqry);
   14017         1856 :     destroyPQExpBuffer(asPart);
   14018         1856 :     free(funcsig);
   14019         1856 :     free(funcfullsig);
   14020         1856 :     free(funcsig_tag);
   14021         1856 :     free(qual_funcsig);
   14022         1856 :     free(configitems);
   14023              : }
   14024              : 
   14025              : 
   14026              : /*
   14027              :  * Dump a user-defined cast
   14028              :  */
   14029              : static void
   14030           69 : dumpCast(Archive *fout, const CastInfo *cast)
   14031              : {
   14032           69 :     DumpOptions *dopt = fout->dopt;
   14033              :     PQExpBuffer defqry;
   14034              :     PQExpBuffer delqry;
   14035              :     PQExpBuffer labelq;
   14036              :     PQExpBuffer castargs;
   14037           69 :     FuncInfo   *funcInfo = NULL;
   14038              :     const char *sourceType;
   14039              :     const char *targetType;
   14040              : 
   14041              :     /* Do nothing if not dumping schema */
   14042           69 :     if (!dopt->dumpSchema)
   14043            6 :         return;
   14044              : 
   14045              :     /* Cannot dump if we don't have the cast function's info */
   14046           63 :     if (OidIsValid(cast->castfunc))
   14047              :     {
   14048           38 :         funcInfo = findFuncByOid(cast->castfunc);
   14049           38 :         if (funcInfo == NULL)
   14050            0 :             pg_fatal("could not find function definition for function with OID %u",
   14051              :                      cast->castfunc);
   14052              :     }
   14053              : 
   14054           63 :     defqry = createPQExpBuffer();
   14055           63 :     delqry = createPQExpBuffer();
   14056           63 :     labelq = createPQExpBuffer();
   14057           63 :     castargs = createPQExpBuffer();
   14058              : 
   14059           63 :     sourceType = getFormattedTypeName(fout, cast->castsource, zeroAsNone);
   14060           63 :     targetType = getFormattedTypeName(fout, cast->casttarget, zeroAsNone);
   14061           63 :     appendPQExpBuffer(delqry, "DROP CAST (%s AS %s);\n",
   14062              :                       sourceType, targetType);
   14063              : 
   14064           63 :     appendPQExpBuffer(defqry, "CREATE CAST (%s AS %s) ",
   14065              :                       sourceType, targetType);
   14066              : 
   14067           63 :     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           38 :         case COERCION_METHOD_FUNCTION:
   14076           38 :             if (funcInfo)
   14077              :             {
   14078           38 :                 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           38 :                 appendPQExpBuffer(defqry, "WITH FUNCTION %s.%s",
   14085           38 :                                   fmtId(funcInfo->dobj.namespace->dobj.name), fsig);
   14086           38 :                 free(fsig);
   14087              :             }
   14088              :             else
   14089            0 :                 pg_log_warning("bogus value in pg_cast.castfunc or pg_cast.castmethod field");
   14090           38 :             break;
   14091            0 :         default:
   14092            0 :             pg_log_warning("bogus value in pg_cast.castmethod field");
   14093              :     }
   14094              : 
   14095           63 :     if (cast->castcontext == 'a')
   14096           33 :         appendPQExpBufferStr(defqry, " AS ASSIGNMENT");
   14097           30 :     else if (cast->castcontext == 'i')
   14098           10 :         appendPQExpBufferStr(defqry, " AS IMPLICIT");
   14099           63 :     appendPQExpBufferStr(defqry, ";\n");
   14100              : 
   14101           63 :     appendPQExpBuffer(labelq, "CAST (%s AS %s)",
   14102              :                       sourceType, targetType);
   14103              : 
   14104           63 :     appendPQExpBuffer(castargs, "(%s AS %s)",
   14105              :                       sourceType, targetType);
   14106              : 
   14107           63 :     if (dopt->binary_upgrade)
   14108            7 :         binary_upgrade_extension_member(defqry, &cast->dobj,
   14109            7 :                                         "CAST", castargs->data, NULL);
   14110              : 
   14111           63 :     if (cast->dobj.dump & DUMP_COMPONENT_DEFINITION)
   14112           63 :         ArchiveEntry(fout, cast->dobj.catId, cast->dobj.dumpId,
   14113           63 :                      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           63 :     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           63 :     destroyPQExpBuffer(defqry);
   14126           63 :     destroyPQExpBuffer(delqry);
   14127           63 :     destroyPQExpBuffer(labelq);
   14128           63 :     destroyPQExpBuffer(castargs);
   14129              : }
   14130              : 
   14131              : /*
   14132              :  * Dump a transform
   14133              :  */
   14134              : static void
   14135           44 : dumpTransform(Archive *fout, const TransformInfo *transform)
   14136              : {
   14137           44 :     DumpOptions *dopt = fout->dopt;
   14138              :     PQExpBuffer defqry;
   14139              :     PQExpBuffer delqry;
   14140              :     PQExpBuffer labelq;
   14141              :     PQExpBuffer transformargs;
   14142           44 :     FuncInfo   *fromsqlFuncInfo = NULL;
   14143           44 :     FuncInfo   *tosqlFuncInfo = NULL;
   14144              :     char       *lanname;
   14145              :     const char *transformType;
   14146              : 
   14147              :     /* Do nothing if not dumping schema */
   14148           44 :     if (!dopt->dumpSchema)
   14149            6 :         return;
   14150              : 
   14151              :     /* Cannot dump if we don't have the transform functions' info */
   14152           38 :     if (OidIsValid(transform->trffromsql))
   14153              :     {
   14154           38 :         fromsqlFuncInfo = findFuncByOid(transform->trffromsql);
   14155           38 :         if (fromsqlFuncInfo == NULL)
   14156            0 :             pg_fatal("could not find function definition for function with OID %u",
   14157              :                      transform->trffromsql);
   14158              :     }
   14159           38 :     if (OidIsValid(transform->trftosql))
   14160              :     {
   14161           38 :         tosqlFuncInfo = findFuncByOid(transform->trftosql);
   14162           38 :         if (tosqlFuncInfo == NULL)
   14163            0 :             pg_fatal("could not find function definition for function with OID %u",
   14164              :                      transform->trftosql);
   14165              :     }
   14166              : 
   14167           38 :     defqry = createPQExpBuffer();
   14168           38 :     delqry = createPQExpBuffer();
   14169           38 :     labelq = createPQExpBuffer();
   14170           38 :     transformargs = createPQExpBuffer();
   14171              : 
   14172           38 :     lanname = get_language_name(fout, transform->trflang);
   14173           38 :     transformType = getFormattedTypeName(fout, transform->trftype, zeroAsNone);
   14174              : 
   14175           38 :     appendPQExpBuffer(delqry, "DROP TRANSFORM FOR %s LANGUAGE %s;\n",
   14176              :                       transformType, lanname);
   14177              : 
   14178           38 :     appendPQExpBuffer(defqry, "CREATE TRANSFORM FOR %s LANGUAGE %s (",
   14179              :                       transformType, lanname);
   14180              : 
   14181           38 :     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           38 :     if (transform->trffromsql)
   14185              :     {
   14186           38 :         if (fromsqlFuncInfo)
   14187              :         {
   14188           38 :             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           38 :             appendPQExpBuffer(defqry, "FROM SQL WITH FUNCTION %s.%s",
   14195           38 :                               fmtId(fromsqlFuncInfo->dobj.namespace->dobj.name), fsig);
   14196           38 :             free(fsig);
   14197              :         }
   14198              :         else
   14199            0 :             pg_log_warning("bogus value in pg_transform.trffromsql field");
   14200              :     }
   14201              : 
   14202           38 :     if (transform->trftosql)
   14203              :     {
   14204           38 :         if (transform->trffromsql)
   14205           38 :             appendPQExpBufferStr(defqry, ", ");
   14206              : 
   14207           38 :         if (tosqlFuncInfo)
   14208              :         {
   14209           38 :             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           38 :             appendPQExpBuffer(defqry, "TO SQL WITH FUNCTION %s.%s",
   14216           38 :                               fmtId(tosqlFuncInfo->dobj.namespace->dobj.name), fsig);
   14217           38 :             free(fsig);
   14218              :         }
   14219              :         else
   14220            0 :             pg_log_warning("bogus value in pg_transform.trftosql field");
   14221              :     }
   14222              : 
   14223           38 :     appendPQExpBufferStr(defqry, ");\n");
   14224              : 
   14225           38 :     appendPQExpBuffer(labelq, "TRANSFORM FOR %s LANGUAGE %s",
   14226              :                       transformType, lanname);
   14227              : 
   14228           38 :     appendPQExpBuffer(transformargs, "FOR %s LANGUAGE %s",
   14229              :                       transformType, lanname);
   14230              : 
   14231           38 :     if (dopt->binary_upgrade)
   14232            2 :         binary_upgrade_extension_member(defqry, &transform->dobj,
   14233            2 :                                         "TRANSFORM", transformargs->data, NULL);
   14234              : 
   14235           38 :     if (transform->dobj.dump & DUMP_COMPONENT_DEFINITION)
   14236           38 :         ArchiveEntry(fout, transform->dobj.catId, transform->dobj.dumpId,
   14237           38 :                      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           38 :     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           38 :     free(lanname);
   14252           38 :     destroyPQExpBuffer(defqry);
   14253           38 :     destroyPQExpBuffer(delqry);
   14254           38 :     destroyPQExpBuffer(labelq);
   14255           38 :     destroyPQExpBuffer(transformargs);
   14256              : }
   14257              : 
   14258              : 
   14259              : /*
   14260              :  * dumpOpr
   14261              :  *    write out a single operator definition
   14262              :  */
   14263              : static void
   14264         2525 : dumpOpr(Archive *fout, const OprInfo *oprinfo)
   14265              : {
   14266         2525 :     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         2525 :     if (!dopt->dumpSchema)
   14298            7 :         return;
   14299              : 
   14300              :     /*
   14301              :      * some operators are invalid because they were the result of user
   14302              :      * defining operators before commutators exist
   14303              :      */
   14304         2518 :     if (!OidIsValid(oprinfo->oprcode))
   14305           14 :         return;
   14306              : 
   14307         2504 :     query = createPQExpBuffer();
   14308         2504 :     q = createPQExpBuffer();
   14309         2504 :     delq = createPQExpBuffer();
   14310         2504 :     oprid = createPQExpBuffer();
   14311         2504 :     details = createPQExpBuffer();
   14312              : 
   14313         2504 :     if (!fout->is_prepared[PREPQUERY_DUMPOPR])
   14314              :     {
   14315              :         /* Set up query for operator-specific details */
   14316           42 :         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           42 :         ExecuteSqlStatement(fout, query->data);
   14331              : 
   14332           42 :         fout->is_prepared[PREPQUERY_DUMPOPR] = true;
   14333              :     }
   14334              : 
   14335         2504 :     printfPQExpBuffer(query,
   14336              :                       "EXECUTE dumpOpr('%u')",
   14337         2504 :                       oprinfo->dobj.catId.oid);
   14338              : 
   14339         2504 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   14340              : 
   14341         2504 :     i_oprkind = PQfnumber(res, "oprkind");
   14342         2504 :     i_oprcode = PQfnumber(res, "oprcode");
   14343         2504 :     i_oprleft = PQfnumber(res, "oprleft");
   14344         2504 :     i_oprright = PQfnumber(res, "oprright");
   14345         2504 :     i_oprcom = PQfnumber(res, "oprcom");
   14346         2504 :     i_oprnegate = PQfnumber(res, "oprnegate");
   14347         2504 :     i_oprrest = PQfnumber(res, "oprrest");
   14348         2504 :     i_oprjoin = PQfnumber(res, "oprjoin");
   14349         2504 :     i_oprcanmerge = PQfnumber(res, "oprcanmerge");
   14350         2504 :     i_oprcanhash = PQfnumber(res, "oprcanhash");
   14351              : 
   14352         2504 :     oprkind = PQgetvalue(res, 0, i_oprkind);
   14353         2504 :     oprcode = PQgetvalue(res, 0, i_oprcode);
   14354         2504 :     oprleft = PQgetvalue(res, 0, i_oprleft);
   14355         2504 :     oprright = PQgetvalue(res, 0, i_oprright);
   14356         2504 :     oprcom = PQgetvalue(res, 0, i_oprcom);
   14357         2504 :     oprnegate = PQgetvalue(res, 0, i_oprnegate);
   14358         2504 :     oprrest = PQgetvalue(res, 0, i_oprrest);
   14359         2504 :     oprjoin = PQgetvalue(res, 0, i_oprjoin);
   14360         2504 :     oprcanmerge = PQgetvalue(res, 0, i_oprcanmerge);
   14361         2504 :     oprcanhash = PQgetvalue(res, 0, i_oprcanhash);
   14362              : 
   14363              :     /* In PG14 upwards postfix operator support does not exist anymore. */
   14364         2504 :     if (strcmp(oprkind, "r") == 0)
   14365            0 :         pg_log_warning("postfix operators are not supported anymore (operator \"%s\")",
   14366              :                        oprcode);
   14367              : 
   14368         2504 :     oprregproc = convertRegProcReference(oprcode);
   14369         2504 :     if (oprregproc)
   14370              :     {
   14371         2504 :         appendPQExpBuffer(details, "    FUNCTION = %s", oprregproc);
   14372         2504 :         free(oprregproc);
   14373              :     }
   14374              : 
   14375         2504 :     appendPQExpBuffer(oprid, "%s (",
   14376         2504 :                       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         2504 :     if (strcmp(oprkind, "r") == 0 ||
   14384         2504 :         strcmp(oprkind, "b") == 0)
   14385              :     {
   14386         2361 :         appendPQExpBuffer(details, ",\n    LEFTARG = %s", oprleft);
   14387         2361 :         appendPQExpBufferStr(oprid, oprleft);
   14388              :     }
   14389              :     else
   14390          143 :         appendPQExpBufferStr(oprid, "NONE");
   14391              : 
   14392         2504 :     if (strcmp(oprkind, "l") == 0 ||
   14393         2361 :         strcmp(oprkind, "b") == 0)
   14394              :     {
   14395         2504 :         appendPQExpBuffer(details, ",\n    RIGHTARG = %s", oprright);
   14396         2504 :         appendPQExpBuffer(oprid, ", %s)", oprright);
   14397              :     }
   14398              :     else
   14399            0 :         appendPQExpBufferStr(oprid, ", NONE)");
   14400              : 
   14401         2504 :     oprref = getFormattedOperatorName(oprcom);
   14402         2504 :     if (oprref)
   14403              :     {
   14404         1679 :         appendPQExpBuffer(details, ",\n    COMMUTATOR = %s", oprref);
   14405         1679 :         free(oprref);
   14406              :     }
   14407              : 
   14408         2504 :     oprref = getFormattedOperatorName(oprnegate);
   14409         2504 :     if (oprref)
   14410              :     {
   14411         1181 :         appendPQExpBuffer(details, ",\n    NEGATOR = %s", oprref);
   14412         1181 :         free(oprref);
   14413              :     }
   14414              : 
   14415         2504 :     if (strcmp(oprcanmerge, "t") == 0)
   14416          188 :         appendPQExpBufferStr(details, ",\n    MERGES");
   14417              : 
   14418         2504 :     if (strcmp(oprcanhash, "t") == 0)
   14419          141 :         appendPQExpBufferStr(details, ",\n    HASHES");
   14420              : 
   14421         2504 :     oprregproc = convertRegProcReference(oprrest);
   14422         2504 :     if (oprregproc)
   14423              :     {
   14424         1532 :         appendPQExpBuffer(details, ",\n    RESTRICT = %s", oprregproc);
   14425         1532 :         free(oprregproc);
   14426              :     }
   14427              : 
   14428         2504 :     oprregproc = convertRegProcReference(oprjoin);
   14429         2504 :     if (oprregproc)
   14430              :     {
   14431         1532 :         appendPQExpBuffer(details, ",\n    JOIN = %s", oprregproc);
   14432         1532 :         free(oprregproc);
   14433              :     }
   14434              : 
   14435         2504 :     appendPQExpBuffer(delq, "DROP OPERATOR %s.%s;\n",
   14436         2504 :                       fmtId(oprinfo->dobj.namespace->dobj.name),
   14437              :                       oprid->data);
   14438              : 
   14439         2504 :     appendPQExpBuffer(q, "CREATE OPERATOR %s.%s (\n%s\n);\n",
   14440         2504 :                       fmtId(oprinfo->dobj.namespace->dobj.name),
   14441         2504 :                       oprinfo->dobj.name, details->data);
   14442              : 
   14443         2504 :     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         2504 :     if (oprinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   14449         2504 :         ArchiveEntry(fout, oprinfo->dobj.catId, oprinfo->dobj.dumpId,
   14450         2504 :                      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         2504 :     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         2504 :     PQclear(res);
   14465              : 
   14466         2504 :     destroyPQExpBuffer(query);
   14467         2504 :     destroyPQExpBuffer(q);
   14468         2504 :     destroyPQExpBuffer(delq);
   14469         2504 :     destroyPQExpBuffer(oprid);
   14470         2504 :     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         7512 : convertRegProcReference(const char *proc)
   14484              : {
   14485              :     char       *name;
   14486              :     char       *paren;
   14487              :     bool        inquote;
   14488              : 
   14489              :     /* In all cases "-" means a null reference */
   14490         7512 :     if (strcmp(proc, "-") == 0)
   14491         1944 :         return NULL;
   14492              : 
   14493         5568 :     name = pg_strdup(proc);
   14494              :     /* find non-double-quoted left paren */
   14495         5568 :     inquote = false;
   14496        67010 :     for (paren = name; *paren; paren++)
   14497              :     {
   14498        67010 :         if (*paren == '(' && !inquote)
   14499              :         {
   14500         5568 :             *paren = '\0';
   14501         5568 :             break;
   14502              :         }
   14503        61442 :         if (*paren == '"')
   14504           50 :             inquote = !inquote;
   14505              :     }
   14506         5568 :     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         5295 : getFormattedOperatorName(const char *oproid)
   14525              : {
   14526              :     OprInfo    *oprInfo;
   14527              : 
   14528              :     /* In all cases "0" means a null reference */
   14529         5295 :     if (strcmp(oproid, "0") == 0)
   14530         2435 :         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          215 : convertTSFunction(Archive *fout, Oid funcOid)
   14555              : {
   14556              :     char       *result;
   14557              :     char        query[128];
   14558              :     PGresult   *res;
   14559              : 
   14560          215 :     snprintf(query, sizeof(query),
   14561              :              "SELECT '%u'::pg_catalog.regproc", funcOid);
   14562          215 :     res = ExecuteSqlQueryForSingleRow(fout, query);
   14563              : 
   14564          215 :     result = pg_strdup(PQgetvalue(res, 0, 0));
   14565              : 
   14566          215 :     PQclear(res);
   14567              : 
   14568          215 :     return result;
   14569              : }
   14570              : 
   14571              : /*
   14572              :  * dumpAccessMethod
   14573              :  *    write out a single access method definition
   14574              :  */
   14575              : static void
   14576           84 : dumpAccessMethod(Archive *fout, const AccessMethodInfo *aminfo)
   14577              : {
   14578           84 :     DumpOptions *dopt = fout->dopt;
   14579              :     PQExpBuffer q;
   14580              :     PQExpBuffer delq;
   14581              :     char       *qamname;
   14582              : 
   14583              :     /* Do nothing if not dumping schema */
   14584           84 :     if (!dopt->dumpSchema)
   14585           12 :         return;
   14586              : 
   14587           72 :     q = createPQExpBuffer();
   14588           72 :     delq = createPQExpBuffer();
   14589              : 
   14590           72 :     qamname = pg_strdup(fmtId(aminfo->dobj.name));
   14591              : 
   14592           72 :     appendPQExpBuffer(q, "CREATE ACCESS METHOD %s ", qamname);
   14593              : 
   14594           72 :     switch (aminfo->amtype)
   14595              :     {
   14596           34 :         case AMTYPE_INDEX:
   14597           34 :             appendPQExpBufferStr(q, "TYPE INDEX ");
   14598           34 :             break;
   14599           38 :         case AMTYPE_TABLE:
   14600           38 :             appendPQExpBufferStr(q, "TYPE TABLE ");
   14601           38 :             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           72 :     appendPQExpBuffer(q, "HANDLER %s;\n", aminfo->amhandler);
   14612              : 
   14613           72 :     appendPQExpBuffer(delq, "DROP ACCESS METHOD %s;\n",
   14614              :                       qamname);
   14615              : 
   14616           72 :     if (dopt->binary_upgrade)
   14617            4 :         binary_upgrade_extension_member(q, &aminfo->dobj,
   14618              :                                         "ACCESS METHOD", qamname, NULL);
   14619              : 
   14620           72 :     if (aminfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   14621           72 :         ArchiveEntry(fout, aminfo->dobj.catId, aminfo->dobj.dumpId,
   14622           72 :                      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           72 :     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           72 :     destroyPQExpBuffer(q);
   14635           72 :     destroyPQExpBuffer(delq);
   14636           72 :     free(qamname);
   14637              : }
   14638              : 
   14639              : /*
   14640              :  * dumpOpclass
   14641              :  *    write out a single operator class definition
   14642              :  */
   14643              : static void
   14644          675 : dumpOpclass(Archive *fout, const OpclassInfo *opcinfo)
   14645              : {
   14646          675 :     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          675 :     if (!dopt->dumpSchema)
   14688           21 :         return;
   14689              : 
   14690          654 :     query = createPQExpBuffer();
   14691          654 :     q = createPQExpBuffer();
   14692          654 :     delq = createPQExpBuffer();
   14693          654 :     nameusing = createPQExpBuffer();
   14694              : 
   14695              :     /* Get additional fields from the pg_opclass row */
   14696          654 :     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          654 :                       opcinfo->dobj.catId.oid);
   14707              : 
   14708          654 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   14709              : 
   14710          654 :     i_opcintype = PQfnumber(res, "opcintype");
   14711          654 :     i_opckeytype = PQfnumber(res, "opckeytype");
   14712          654 :     i_opcdefault = PQfnumber(res, "opcdefault");
   14713          654 :     i_opcfamily = PQfnumber(res, "opcfamily");
   14714          654 :     i_opcfamilyname = PQfnumber(res, "opcfamilyname");
   14715          654 :     i_opcfamilynsp = PQfnumber(res, "opcfamilynsp");
   14716          654 :     i_amname = PQfnumber(res, "amname");
   14717              : 
   14718              :     /* opcintype may still be needed after we PQclear res */
   14719          654 :     opcintype = pg_strdup(PQgetvalue(res, 0, i_opcintype));
   14720          654 :     opckeytype = PQgetvalue(res, 0, i_opckeytype);
   14721          654 :     opcdefault = PQgetvalue(res, 0, i_opcdefault);
   14722              :     /* opcfamily will still be needed after we PQclear res */
   14723          654 :     opcfamily = pg_strdup(PQgetvalue(res, 0, i_opcfamily));
   14724          654 :     opcfamilyname = PQgetvalue(res, 0, i_opcfamilyname);
   14725          654 :     opcfamilynsp = PQgetvalue(res, 0, i_opcfamilynsp);
   14726              :     /* amname will still be needed after we PQclear res */
   14727          654 :     amname = pg_strdup(PQgetvalue(res, 0, i_amname));
   14728              : 
   14729          654 :     appendPQExpBuffer(delq, "DROP OPERATOR CLASS %s",
   14730          654 :                       fmtQualifiedDumpable(opcinfo));
   14731          654 :     appendPQExpBuffer(delq, " USING %s;\n",
   14732              :                       fmtId(amname));
   14733              : 
   14734              :     /* Build the fixed portion of the CREATE command */
   14735          654 :     appendPQExpBuffer(q, "CREATE OPERATOR CLASS %s\n    ",
   14736          654 :                       fmtQualifiedDumpable(opcinfo));
   14737          654 :     if (strcmp(opcdefault, "t") == 0)
   14738          366 :         appendPQExpBufferStr(q, "DEFAULT ");
   14739          654 :     appendPQExpBuffer(q, "FOR TYPE %s USING %s",
   14740              :                       opcintype,
   14741              :                       fmtId(amname));
   14742          654 :     if (strlen(opcfamilyname) > 0)
   14743              :     {
   14744          654 :         appendPQExpBufferStr(q, " FAMILY ");
   14745          654 :         appendPQExpBuffer(q, "%s.", fmtId(opcfamilynsp));
   14746          654 :         appendPQExpBufferStr(q, fmtId(opcfamilyname));
   14747              :     }
   14748          654 :     appendPQExpBufferStr(q, " AS\n    ");
   14749              : 
   14750          654 :     needComma = false;
   14751              : 
   14752          654 :     if (strcmp(opckeytype, "-") != 0)
   14753              :     {
   14754          252 :         appendPQExpBuffer(q, "STORAGE %s",
   14755              :                           opckeytype);
   14756          252 :         needComma = true;
   14757              :     }
   14758              : 
   14759          654 :     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          654 :     resetPQExpBuffer(query);
   14768          654 :     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          654 :                       opcinfo->dobj.catId.oid,
   14781              :                       opcfamily);
   14782              : 
   14783          654 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   14784              : 
   14785          654 :     ntups = PQntuples(res);
   14786              : 
   14787          654 :     i_amopstrategy = PQfnumber(res, "amopstrategy");
   14788          654 :     i_amopopr = PQfnumber(res, "amopopr");
   14789          654 :     i_sortfamily = PQfnumber(res, "sortfamily");
   14790          654 :     i_sortfamilynsp = PQfnumber(res, "sortfamilynsp");
   14791              : 
   14792          868 :     for (i = 0; i < ntups; i++)
   14793              :     {
   14794          214 :         amopstrategy = PQgetvalue(res, i, i_amopstrategy);
   14795          214 :         amopopr = PQgetvalue(res, i, i_amopopr);
   14796          214 :         sortfamily = PQgetvalue(res, i, i_sortfamily);
   14797          214 :         sortfamilynsp = PQgetvalue(res, i, i_sortfamilynsp);
   14798              : 
   14799          214 :         if (needComma)
   14800          136 :             appendPQExpBufferStr(q, " ,\n    ");
   14801              : 
   14802          214 :         appendPQExpBuffer(q, "OPERATOR %s %s",
   14803              :                           amopstrategy, amopopr);
   14804              : 
   14805          214 :         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          214 :         needComma = true;
   14813              :     }
   14814              : 
   14815          654 :     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          654 :     resetPQExpBuffer(query);
   14828              : 
   14829          654 :     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          654 :                       opcinfo->dobj.catId.oid);
   14840              : 
   14841          654 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   14842              : 
   14843          654 :     ntups = PQntuples(res);
   14844              : 
   14845          654 :     i_amprocnum = PQfnumber(res, "amprocnum");
   14846          654 :     i_amproc = PQfnumber(res, "amproc");
   14847          654 :     i_amproclefttype = PQfnumber(res, "amproclefttype");
   14848          654 :     i_amprocrighttype = PQfnumber(res, "amprocrighttype");
   14849              : 
   14850          688 :     for (i = 0; i < ntups; i++)
   14851              :     {
   14852           34 :         amprocnum = PQgetvalue(res, i, i_amprocnum);
   14853           34 :         amproc = PQgetvalue(res, i, i_amproc);
   14854           34 :         amproclefttype = PQgetvalue(res, i, i_amproclefttype);
   14855           34 :         amprocrighttype = PQgetvalue(res, i, i_amprocrighttype);
   14856              : 
   14857           34 :         if (needComma)
   14858           34 :             appendPQExpBufferStr(q, " ,\n    ");
   14859              : 
   14860           34 :         appendPQExpBuffer(q, "FUNCTION %s", amprocnum);
   14861              : 
   14862           34 :         if (*amproclefttype && *amprocrighttype)
   14863           34 :             appendPQExpBuffer(q, " (%s, %s)", amproclefttype, amprocrighttype);
   14864              : 
   14865           34 :         appendPQExpBuffer(q, " %s", amproc);
   14866              : 
   14867           34 :         needComma = true;
   14868              :     }
   14869              : 
   14870          654 :     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          654 :     if (!needComma)
   14879          324 :         appendPQExpBuffer(q, "STORAGE %s", opcintype);
   14880              : 
   14881          654 :     appendPQExpBufferStr(q, ";\n");
   14882              : 
   14883          654 :     appendPQExpBufferStr(nameusing, fmtId(opcinfo->dobj.name));
   14884          654 :     appendPQExpBuffer(nameusing, " USING %s",
   14885              :                       fmtId(amname));
   14886              : 
   14887          654 :     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          654 :     if (opcinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   14893          654 :         ArchiveEntry(fout, opcinfo->dobj.catId, opcinfo->dobj.dumpId,
   14894          654 :                      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          654 :     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          654 :     free(opcintype);
   14909          654 :     free(opcfamily);
   14910          654 :     free(amname);
   14911          654 :     destroyPQExpBuffer(query);
   14912          654 :     destroyPQExpBuffer(q);
   14913          654 :     destroyPQExpBuffer(delq);
   14914          654 :     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          561 : dumpOpfamily(Archive *fout, const OpfamilyInfo *opfinfo)
   14926              : {
   14927          561 :     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          561 :     if (!dopt->dumpSchema)
   14959           14 :         return;
   14960              : 
   14961          547 :     query = createPQExpBuffer();
   14962          547 :     q = createPQExpBuffer();
   14963          547 :     delq = createPQExpBuffer();
   14964          547 :     nameusing = createPQExpBuffer();
   14965              : 
   14966              :     /*
   14967              :      * Fetch only those opfamily members that are tied directly to the
   14968              :      * opfamily by pg_depend entries.
   14969              :      */
   14970          547 :     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          547 :                       opfinfo->dobj.catId.oid,
   14983          547 :                       opfinfo->dobj.catId.oid);
   14984              : 
   14985          547 :     res_ops = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   14986              : 
   14987          547 :     resetPQExpBuffer(query);
   14988              : 
   14989          547 :     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          547 :                       opfinfo->dobj.catId.oid);
   15000              : 
   15001          547 :     res_procs = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   15002              : 
   15003              :     /* Get additional fields from the pg_opfamily row */
   15004          547 :     resetPQExpBuffer(query);
   15005              : 
   15006          547 :     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          547 :                       opfinfo->dobj.catId.oid);
   15011              : 
   15012          547 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   15013              : 
   15014          547 :     i_amname = PQfnumber(res, "amname");
   15015              : 
   15016              :     /* amname will still be needed after we PQclear res */
   15017          547 :     amname = pg_strdup(PQgetvalue(res, 0, i_amname));
   15018              : 
   15019          547 :     appendPQExpBuffer(delq, "DROP OPERATOR FAMILY %s",
   15020          547 :                       fmtQualifiedDumpable(opfinfo));
   15021          547 :     appendPQExpBuffer(delq, " USING %s;\n",
   15022              :                       fmtId(amname));
   15023              : 
   15024              :     /* Build the fixed portion of the CREATE command */
   15025          547 :     appendPQExpBuffer(q, "CREATE OPERATOR FAMILY %s",
   15026          547 :                       fmtQualifiedDumpable(opfinfo));
   15027          547 :     appendPQExpBuffer(q, " USING %s;\n",
   15028              :                       fmtId(amname));
   15029              : 
   15030          547 :     PQclear(res);
   15031              : 
   15032              :     /* Do we need an ALTER to add loose members? */
   15033          547 :     if (PQntuples(res_ops) > 0 || PQntuples(res_procs) > 0)
   15034              :     {
   15035           49 :         appendPQExpBuffer(q, "ALTER OPERATOR FAMILY %s",
   15036           49 :                           fmtQualifiedDumpable(opfinfo));
   15037           49 :         appendPQExpBuffer(q, " USING %s ADD\n    ",
   15038              :                           fmtId(amname));
   15039              : 
   15040           49 :         needComma = false;
   15041              : 
   15042              :         /*
   15043              :          * Now fetch and print the OPERATOR entries (pg_amop rows).
   15044              :          */
   15045           49 :         ntups = PQntuples(res_ops);
   15046              : 
   15047           49 :         i_amopstrategy = PQfnumber(res_ops, "amopstrategy");
   15048           49 :         i_amopopr = PQfnumber(res_ops, "amopopr");
   15049           49 :         i_sortfamily = PQfnumber(res_ops, "sortfamily");
   15050           49 :         i_sortfamilynsp = PQfnumber(res_ops, "sortfamilynsp");
   15051              : 
   15052          219 :         for (i = 0; i < ntups; i++)
   15053              :         {
   15054          170 :             amopstrategy = PQgetvalue(res_ops, i, i_amopstrategy);
   15055          170 :             amopopr = PQgetvalue(res_ops, i, i_amopopr);
   15056          170 :             sortfamily = PQgetvalue(res_ops, i, i_sortfamily);
   15057          170 :             sortfamilynsp = PQgetvalue(res_ops, i, i_sortfamilynsp);
   15058              : 
   15059          170 :             if (needComma)
   15060          136 :                 appendPQExpBufferStr(q, " ,\n    ");
   15061              : 
   15062          170 :             appendPQExpBuffer(q, "OPERATOR %s %s",
   15063              :                               amopstrategy, amopopr);
   15064              : 
   15065          170 :             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          170 :             needComma = true;
   15073              :         }
   15074              : 
   15075              :         /*
   15076              :          * Now fetch and print the FUNCTION entries (pg_amproc rows).
   15077              :          */
   15078           49 :         ntups = PQntuples(res_procs);
   15079              : 
   15080           49 :         i_amprocnum = PQfnumber(res_procs, "amprocnum");
   15081           49 :         i_amproc = PQfnumber(res_procs, "amproc");
   15082           49 :         i_amproclefttype = PQfnumber(res_procs, "amproclefttype");
   15083           49 :         i_amprocrighttype = PQfnumber(res_procs, "amprocrighttype");
   15084              : 
   15085          234 :         for (i = 0; i < ntups; i++)
   15086              :         {
   15087          185 :             amprocnum = PQgetvalue(res_procs, i, i_amprocnum);
   15088          185 :             amproc = PQgetvalue(res_procs, i, i_amproc);
   15089          185 :             amproclefttype = PQgetvalue(res_procs, i, i_amproclefttype);
   15090          185 :             amprocrighttype = PQgetvalue(res_procs, i, i_amprocrighttype);
   15091              : 
   15092          185 :             if (needComma)
   15093          170 :                 appendPQExpBufferStr(q, " ,\n    ");
   15094              : 
   15095          185 :             appendPQExpBuffer(q, "FUNCTION %s (%s, %s) %s",
   15096              :                               amprocnum, amproclefttype, amprocrighttype,
   15097              :                               amproc);
   15098              : 
   15099          185 :             needComma = true;
   15100              :         }
   15101              : 
   15102           49 :         appendPQExpBufferStr(q, ";\n");
   15103              :     }
   15104              : 
   15105          547 :     appendPQExpBufferStr(nameusing, fmtId(opfinfo->dobj.name));
   15106          547 :     appendPQExpBuffer(nameusing, " USING %s",
   15107              :                       fmtId(amname));
   15108              : 
   15109          547 :     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          547 :     if (opfinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   15115          547 :         ArchiveEntry(fout, opfinfo->dobj.catId, opfinfo->dobj.dumpId,
   15116          547 :                      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          547 :     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          547 :     free(amname);
   15131          547 :     PQclear(res_ops);
   15132          547 :     PQclear(res_procs);
   15133          547 :     destroyPQExpBuffer(query);
   15134          547 :     destroyPQExpBuffer(q);
   15135          547 :     destroyPQExpBuffer(delq);
   15136          547 :     destroyPQExpBuffer(nameusing);
   15137              : }
   15138              : 
   15139              : /*
   15140              :  * dumpCollation
   15141              :  *    write out a single collation definition
   15142              :  */
   15143              : static void
   15144         2733 : dumpCollation(Archive *fout, const CollInfo *collinfo)
   15145              : {
   15146         2733 :     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         2733 :     if (!dopt->dumpSchema)
   15166           12 :         return;
   15167              : 
   15168         2721 :     query = createPQExpBuffer();
   15169         2721 :     q = createPQExpBuffer();
   15170         2721 :     delq = createPQExpBuffer();
   15171              : 
   15172         2721 :     qcollname = pg_strdup(fmtId(collinfo->dobj.name));
   15173              : 
   15174              :     /* Get collation-specific details */
   15175         2721 :     appendPQExpBufferStr(query, "SELECT ");
   15176              : 
   15177         2721 :     if (fout->remoteVersion >= 100000)
   15178         2721 :         appendPQExpBufferStr(query,
   15179              :                              "collprovider, "
   15180              :                              "collversion, ");
   15181              :     else
   15182            0 :         appendPQExpBufferStr(query,
   15183              :                              "'c' AS collprovider, "
   15184              :                              "NULL AS collversion, ");
   15185              : 
   15186         2721 :     if (fout->remoteVersion >= 120000)
   15187         2721 :         appendPQExpBufferStr(query,
   15188              :                              "collisdeterministic, ");
   15189              :     else
   15190            0 :         appendPQExpBufferStr(query,
   15191              :                              "true AS collisdeterministic, ");
   15192              : 
   15193         2721 :     if (fout->remoteVersion >= 170000)
   15194         2721 :         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         2721 :     if (fout->remoteVersion >= 160000)
   15204         2721 :         appendPQExpBufferStr(query,
   15205              :                              "collicurules, ");
   15206              :     else
   15207            0 :         appendPQExpBufferStr(query,
   15208              :                              "NULL AS collicurules, ");
   15209              : 
   15210         2721 :     appendPQExpBuffer(query,
   15211              :                       "collcollate, "
   15212              :                       "collctype "
   15213              :                       "FROM pg_catalog.pg_collation c "
   15214              :                       "WHERE c.oid = '%u'::pg_catalog.oid",
   15215         2721 :                       collinfo->dobj.catId.oid);
   15216              : 
   15217         2721 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   15218              : 
   15219         2721 :     i_collprovider = PQfnumber(res, "collprovider");
   15220         2721 :     i_collisdeterministic = PQfnumber(res, "collisdeterministic");
   15221         2721 :     i_collcollate = PQfnumber(res, "collcollate");
   15222         2721 :     i_collctype = PQfnumber(res, "collctype");
   15223         2721 :     i_colllocale = PQfnumber(res, "colllocale");
   15224         2721 :     i_collicurules = PQfnumber(res, "collicurules");
   15225              : 
   15226         2721 :     collprovider = PQgetvalue(res, 0, i_collprovider);
   15227              : 
   15228         2721 :     if (!PQgetisnull(res, 0, i_collcollate))
   15229           48 :         collcollate = PQgetvalue(res, 0, i_collcollate);
   15230              :     else
   15231         2673 :         collcollate = NULL;
   15232              : 
   15233         2721 :     if (!PQgetisnull(res, 0, i_collctype))
   15234           48 :         collctype = PQgetvalue(res, 0, i_collctype);
   15235              :     else
   15236         2673 :         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         2721 :     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         2721 :     if (!PQgetisnull(res, 0, i_colllocale))
   15251         2670 :         colllocale = PQgetvalue(res, 0, i_colllocale);
   15252              :     else
   15253           51 :         colllocale = NULL;
   15254              : 
   15255         2721 :     if (!PQgetisnull(res, 0, i_collicurules))
   15256            0 :         collicurules = PQgetvalue(res, 0, i_collicurules);
   15257              :     else
   15258         2721 :         collicurules = NULL;
   15259              : 
   15260         2721 :     appendPQExpBuffer(delq, "DROP COLLATION %s;\n",
   15261         2721 :                       fmtQualifiedDumpable(collinfo));
   15262              : 
   15263         2721 :     appendPQExpBuffer(q, "CREATE COLLATION %s (",
   15264         2721 :                       fmtQualifiedDumpable(collinfo));
   15265              : 
   15266         2721 :     appendPQExpBufferStr(q, "provider = ");
   15267         2721 :     if (collprovider[0] == 'b')
   15268           19 :         appendPQExpBufferStr(q, "builtin");
   15269         2702 :     else if (collprovider[0] == 'c')
   15270           48 :         appendPQExpBufferStr(q, "libc");
   15271         2654 :     else if (collprovider[0] == 'i')
   15272         2651 :         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         2721 :     if (strcmp(PQgetvalue(res, 0, i_collisdeterministic), "f") == 0)
   15281            0 :         appendPQExpBufferStr(q, ", deterministic = false");
   15282              : 
   15283         2721 :     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         2718 :     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         2699 :     else if (collprovider[0] == 'i')
   15300              :     {
   15301         2651 :         if (fout->remoteVersion >= 150000)
   15302              :         {
   15303         2651 :             if (collcollate || collctype || !colllocale)
   15304            0 :                 pg_log_warning("invalid collation \"%s\"", qcollname);
   15305              : 
   15306         2651 :             appendPQExpBufferStr(q, ", locale = ");
   15307         2651 :             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         2651 :         if (collicurules)
   15321              :         {
   15322            0 :             appendPQExpBufferStr(q, ", rules = ");
   15323            0 :             appendStringLiteralAH(q, collicurules ? collicurules : "", fout);
   15324              :         }
   15325              :     }
   15326           48 :     else if (collprovider[0] == 'c')
   15327              :     {
   15328           48 :         if (colllocale || collicurules || !collcollate || !collctype)
   15329            0 :             pg_log_warning("invalid collation \"%s\"", qcollname);
   15330              : 
   15331           48 :         if (collcollate && collctype && strcmp(collcollate, collctype) == 0)
   15332              :         {
   15333           48 :             appendPQExpBufferStr(q, ", locale = ");
   15334           48 :             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         2721 :     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         2721 :     appendPQExpBufferStr(q, ");\n");
   15366              : 
   15367         2721 :     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         2721 :     if (collinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   15373         2721 :         ArchiveEntry(fout, collinfo->dobj.catId, collinfo->dobj.dumpId,
   15374         2721 :                      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         2721 :     if (collinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   15384         2613 :         dumpComment(fout, "COLLATION", qcollname,
   15385         2613 :                     collinfo->dobj.namespace->dobj.name, collinfo->rolname,
   15386         2613 :                     collinfo->dobj.catId, 0, collinfo->dobj.dumpId);
   15387              : 
   15388         2721 :     PQclear(res);
   15389              : 
   15390         2721 :     destroyPQExpBuffer(query);
   15391         2721 :     destroyPQExpBuffer(q);
   15392         2721 :     destroyPQExpBuffer(delq);
   15393         2721 :     free(qcollname);
   15394              : }
   15395              : 
   15396              : /*
   15397              :  * dumpConversion
   15398              :  *    write out a single conversion definition
   15399              :  */
   15400              : static void
   15401          335 : dumpConversion(Archive *fout, const ConvInfo *convinfo)
   15402              : {
   15403          335 :     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          335 :     if (!dopt->dumpSchema)
   15420            7 :         return;
   15421              : 
   15422          328 :     query = createPQExpBuffer();
   15423          328 :     q = createPQExpBuffer();
   15424          328 :     delq = createPQExpBuffer();
   15425              : 
   15426          328 :     qconvname = pg_strdup(fmtId(convinfo->dobj.name));
   15427              : 
   15428              :     /* Get conversion-specific details */
   15429          328 :     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          328 :                       convinfo->dobj.catId.oid);
   15436              : 
   15437          328 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   15438              : 
   15439          328 :     i_conforencoding = PQfnumber(res, "conforencoding");
   15440          328 :     i_contoencoding = PQfnumber(res, "contoencoding");
   15441          328 :     i_conproc = PQfnumber(res, "conproc");
   15442          328 :     i_condefault = PQfnumber(res, "condefault");
   15443              : 
   15444          328 :     conforencoding = PQgetvalue(res, 0, i_conforencoding);
   15445          328 :     contoencoding = PQgetvalue(res, 0, i_contoencoding);
   15446          328 :     conproc = PQgetvalue(res, 0, i_conproc);
   15447          328 :     condefault = (PQgetvalue(res, 0, i_condefault)[0] == 't');
   15448              : 
   15449          328 :     appendPQExpBuffer(delq, "DROP CONVERSION %s;\n",
   15450          328 :                       fmtQualifiedDumpable(convinfo));
   15451              : 
   15452          328 :     appendPQExpBuffer(q, "CREATE %sCONVERSION %s FOR ",
   15453              :                       (condefault) ? "DEFAULT " : "",
   15454          328 :                       fmtQualifiedDumpable(convinfo));
   15455          328 :     appendStringLiteralAH(q, conforencoding, fout);
   15456          328 :     appendPQExpBufferStr(q, " TO ");
   15457          328 :     appendStringLiteralAH(q, contoencoding, fout);
   15458              :     /* regproc output is already sufficiently quoted */
   15459          328 :     appendPQExpBuffer(q, " FROM %s;\n", conproc);
   15460              : 
   15461          328 :     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          328 :     if (convinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   15467          328 :         ArchiveEntry(fout, convinfo->dobj.catId, convinfo->dobj.dumpId,
   15468          328 :                      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          328 :     if (convinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   15478          328 :         dumpComment(fout, "CONVERSION", qconvname,
   15479          328 :                     convinfo->dobj.namespace->dobj.name, convinfo->rolname,
   15480          328 :                     convinfo->dobj.catId, 0, convinfo->dobj.dumpId);
   15481              : 
   15482          328 :     PQclear(res);
   15483              : 
   15484          328 :     destroyPQExpBuffer(query);
   15485          328 :     destroyPQExpBuffer(q);
   15486          328 :     destroyPQExpBuffer(delq);
   15487          328 :     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          287 : format_aggregate_signature(const AggInfo *agginfo, Archive *fout, bool honor_quotes)
   15498              : {
   15499              :     PQExpBufferData buf;
   15500              :     int         j;
   15501              : 
   15502          287 :     initPQExpBuffer(&buf);
   15503          287 :     if (honor_quotes)
   15504            0 :         appendPQExpBufferStr(&buf, fmtId(agginfo->aggfn.dobj.name));
   15505              :     else
   15506          287 :         appendPQExpBufferStr(&buf, agginfo->aggfn.dobj.name);
   15507              : 
   15508          287 :     if (agginfo->aggfn.nargs == 0)
   15509           40 :         appendPQExpBufferStr(&buf, "(*)");
   15510              :     else
   15511              :     {
   15512          247 :         appendPQExpBufferChar(&buf, '(');
   15513          539 :         for (j = 0; j < agginfo->aggfn.nargs; j++)
   15514          292 :             appendPQExpBuffer(&buf, "%s%s",
   15515              :                               (j > 0) ? ", " : "",
   15516              :                               getFormattedTypeName(fout,
   15517          292 :                                                    agginfo->aggfn.argtypes[j],
   15518              :                                                    zeroIsError));
   15519          247 :         appendPQExpBufferChar(&buf, ')');
   15520              :     }
   15521          287 :     return buf.data;
   15522              : }
   15523              : 
   15524              : /*
   15525              :  * dumpAgg
   15526              :  *    write out a single aggregate definition
   15527              :  */
   15528              : static void
   15529          295 : dumpAgg(Archive *fout, const AggInfo *agginfo)
   15530              : {
   15531          295 :     DumpOptions *dopt = fout->dopt;
   15532              :     PQExpBuffer query;
   15533              :     PQExpBuffer q;
   15534              :     PQExpBuffer delq;
   15535              :     PQExpBuffer details;
   15536              :     char       *aggsig;         /* identity signature */
   15537          295 :     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          295 :     if (!dopt->dumpSchema)
   15568            8 :         return;
   15569              : 
   15570          287 :     query = createPQExpBuffer();
   15571          287 :     q = createPQExpBuffer();
   15572          287 :     delq = createPQExpBuffer();
   15573          287 :     details = createPQExpBuffer();
   15574              : 
   15575          287 :     if (!fout->is_prepared[PREPQUERY_DUMPAGG])
   15576              :     {
   15577              :         /* Set up query for aggregate-specific details */
   15578           57 :         appendPQExpBufferStr(query,
   15579              :                              "PREPARE dumpAgg(pg_catalog.oid) AS\n");
   15580              : 
   15581           57 :         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           57 :         if (fout->remoteVersion >= 90400)
   15592           57 :             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           57 :         if (fout->remoteVersion >= 90600)
   15617           57 :             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           57 :         if (fout->remoteVersion >= 110000)
   15630           57 :             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           57 :         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           57 :         ExecuteSqlStatement(fout, query->data);
   15644              : 
   15645           57 :         fout->is_prepared[PREPQUERY_DUMPAGG] = true;
   15646              :     }
   15647              : 
   15648          287 :     printfPQExpBuffer(query,
   15649              :                       "EXECUTE dumpAgg('%u')",
   15650          287 :                       agginfo->aggfn.dobj.catId.oid);
   15651              : 
   15652          287 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   15653              : 
   15654          287 :     i_agginitval = PQfnumber(res, "agginitval");
   15655          287 :     i_aggminitval = PQfnumber(res, "aggminitval");
   15656              : 
   15657          287 :     aggtransfn = PQgetvalue(res, 0, PQfnumber(res, "aggtransfn"));
   15658          287 :     aggfinalfn = PQgetvalue(res, 0, PQfnumber(res, "aggfinalfn"));
   15659          287 :     aggcombinefn = PQgetvalue(res, 0, PQfnumber(res, "aggcombinefn"));
   15660          287 :     aggserialfn = PQgetvalue(res, 0, PQfnumber(res, "aggserialfn"));
   15661          287 :     aggdeserialfn = PQgetvalue(res, 0, PQfnumber(res, "aggdeserialfn"));
   15662          287 :     aggmtransfn = PQgetvalue(res, 0, PQfnumber(res, "aggmtransfn"));
   15663          287 :     aggminvtransfn = PQgetvalue(res, 0, PQfnumber(res, "aggminvtransfn"));
   15664          287 :     aggmfinalfn = PQgetvalue(res, 0, PQfnumber(res, "aggmfinalfn"));
   15665          287 :     aggfinalextra = (PQgetvalue(res, 0, PQfnumber(res, "aggfinalextra"))[0] == 't');
   15666          287 :     aggmfinalextra = (PQgetvalue(res, 0, PQfnumber(res, "aggmfinalextra"))[0] == 't');
   15667          287 :     aggfinalmodify = PQgetvalue(res, 0, PQfnumber(res, "aggfinalmodify"))[0];
   15668          287 :     aggmfinalmodify = PQgetvalue(res, 0, PQfnumber(res, "aggmfinalmodify"))[0];
   15669          287 :     aggsortop = PQgetvalue(res, 0, PQfnumber(res, "aggsortop"));
   15670          287 :     aggkind = PQgetvalue(res, 0, PQfnumber(res, "aggkind"))[0];
   15671          287 :     aggtranstype = PQgetvalue(res, 0, PQfnumber(res, "aggtranstype"));
   15672          287 :     aggtransspace = PQgetvalue(res, 0, PQfnumber(res, "aggtransspace"));
   15673          287 :     aggmtranstype = PQgetvalue(res, 0, PQfnumber(res, "aggmtranstype"));
   15674          287 :     aggmtransspace = PQgetvalue(res, 0, PQfnumber(res, "aggmtransspace"));
   15675          287 :     agginitval = PQgetvalue(res, 0, i_agginitval);
   15676          287 :     aggminitval = PQgetvalue(res, 0, i_aggminitval);
   15677          287 :     proparallel = PQgetvalue(res, 0, PQfnumber(res, "proparallel"));
   15678              : 
   15679              :     {
   15680              :         char       *funcargs;
   15681              :         char       *funciargs;
   15682              : 
   15683          287 :         funcargs = PQgetvalue(res, 0, PQfnumber(res, "funcargs"));
   15684          287 :         funciargs = PQgetvalue(res, 0, PQfnumber(res, "funciargs"));
   15685          287 :         aggfullsig = format_function_arguments(&agginfo->aggfn, funcargs, true);
   15686          287 :         aggsig = format_function_arguments(&agginfo->aggfn, funciargs, true);
   15687              :     }
   15688              : 
   15689          287 :     aggsig_tag = format_aggregate_signature(agginfo, fout, false);
   15690              : 
   15691              :     /* identify default modify flag for aggkind (must match DefineAggregate) */
   15692          287 :     defaultfinalmodify = (aggkind == AGGKIND_NORMAL) ? AGGMODIFY_READ_ONLY : AGGMODIFY_READ_WRITE;
   15693              :     /* replace omitted flags for old versions */
   15694          287 :     if (aggfinalmodify == '0')
   15695            0 :         aggfinalmodify = defaultfinalmodify;
   15696          287 :     if (aggmfinalmodify == '0')
   15697            0 :         aggmfinalmodify = defaultfinalmodify;
   15698              : 
   15699              :     /* regproc and regtype output is already sufficiently quoted */
   15700          287 :     appendPQExpBuffer(details, "    SFUNC = %s,\n    STYPE = %s",
   15701              :                       aggtransfn, aggtranstype);
   15702              : 
   15703          287 :     if (strcmp(aggtransspace, "0") != 0)
   15704              :     {
   15705            5 :         appendPQExpBuffer(details, ",\n    SSPACE = %s",
   15706              :                           aggtransspace);
   15707              :     }
   15708              : 
   15709          287 :     if (!PQgetisnull(res, 0, i_agginitval))
   15710              :     {
   15711          209 :         appendPQExpBufferStr(details, ",\n    INITCOND = ");
   15712          209 :         appendStringLiteralAH(details, agginitval, fout);
   15713              :     }
   15714              : 
   15715          287 :     if (strcmp(aggfinalfn, "-") != 0)
   15716              :     {
   15717          134 :         appendPQExpBuffer(details, ",\n    FINALFUNC = %s",
   15718              :                           aggfinalfn);
   15719          134 :         if (aggfinalextra)
   15720           10 :             appendPQExpBufferStr(details, ",\n    FINALFUNC_EXTRA");
   15721          134 :         if (aggfinalmodify != defaultfinalmodify)
   15722              :         {
   15723           34 :             switch (aggfinalmodify)
   15724              :             {
   15725            0 :                 case AGGMODIFY_READ_ONLY:
   15726            0 :                     appendPQExpBufferStr(details, ",\n    FINALFUNC_MODIFY = READ_ONLY");
   15727            0 :                     break;
   15728           34 :                 case AGGMODIFY_SHAREABLE:
   15729           34 :                     appendPQExpBufferStr(details, ",\n    FINALFUNC_MODIFY = SHAREABLE");
   15730           34 :                     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          287 :     if (strcmp(aggcombinefn, "-") != 0)
   15743            0 :         appendPQExpBuffer(details, ",\n    COMBINEFUNC = %s", aggcombinefn);
   15744              : 
   15745          287 :     if (strcmp(aggserialfn, "-") != 0)
   15746            0 :         appendPQExpBuffer(details, ",\n    SERIALFUNC = %s", aggserialfn);
   15747              : 
   15748          287 :     if (strcmp(aggdeserialfn, "-") != 0)
   15749            0 :         appendPQExpBuffer(details, ",\n    DESERIALFUNC = %s", aggdeserialfn);
   15750              : 
   15751          287 :     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          287 :     if (strcmp(aggmtransspace, "0") != 0)
   15760              :     {
   15761            0 :         appendPQExpBuffer(details, ",\n    MSSPACE = %s",
   15762              :                           aggmtransspace);
   15763              :     }
   15764              : 
   15765          287 :     if (!PQgetisnull(res, 0, i_aggminitval))
   15766              :     {
   15767           10 :         appendPQExpBufferStr(details, ",\n    MINITCOND = ");
   15768           10 :         appendStringLiteralAH(details, aggminitval, fout);
   15769              :     }
   15770              : 
   15771          287 :     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          287 :     aggsortconvop = getFormattedOperatorName(aggsortop);
   15799          287 :     if (aggsortconvop)
   15800              :     {
   15801            0 :         appendPQExpBuffer(details, ",\n    SORTOP = %s",
   15802              :                           aggsortconvop);
   15803            0 :         free(aggsortconvop);
   15804              :     }
   15805              : 
   15806          287 :     if (aggkind == AGGKIND_HYPOTHETICAL)
   15807            5 :         appendPQExpBufferStr(details, ",\n    HYPOTHETICAL");
   15808              : 
   15809          287 :     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          287 :     appendPQExpBuffer(delq, "DROP AGGREGATE %s.%s;\n",
   15821          287 :                       fmtId(agginfo->aggfn.dobj.namespace->dobj.name),
   15822              :                       aggsig);
   15823              : 
   15824          574 :     appendPQExpBuffer(q, "CREATE AGGREGATE %s.%s (\n%s\n);\n",
   15825          287 :                       fmtId(agginfo->aggfn.dobj.namespace->dobj.name),
   15826              :                       aggfullsig ? aggfullsig : aggsig, details->data);
   15827              : 
   15828          287 :     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          287 :     if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_DEFINITION)
   15834          270 :         ArchiveEntry(fout, agginfo->aggfn.dobj.catId,
   15835          270 :                      agginfo->aggfn.dobj.dumpId,
   15836          270 :                      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          287 :     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          287 :     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          287 :     free(aggsig);
   15863              : 
   15864          287 :     aggsig = format_function_signature(fout, &agginfo->aggfn, true);
   15865              : 
   15866          287 :     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          287 :     free(aggsig);
   15873          287 :     free(aggfullsig);
   15874          287 :     free(aggsig_tag);
   15875              : 
   15876          287 :     PQclear(res);
   15877              : 
   15878          287 :     destroyPQExpBuffer(query);
   15879          287 :     destroyPQExpBuffer(q);
   15880          287 :     destroyPQExpBuffer(delq);
   15881          287 :     destroyPQExpBuffer(details);
   15882              : }
   15883              : 
   15884              : /*
   15885              :  * dumpTSParser
   15886              :  *    write out a single text search parser
   15887              :  */
   15888              : static void
   15889           44 : dumpTSParser(Archive *fout, const TSParserInfo *prsinfo)
   15890              : {
   15891           44 :     DumpOptions *dopt = fout->dopt;
   15892              :     PQExpBuffer q;
   15893              :     PQExpBuffer delq;
   15894              :     char       *qprsname;
   15895              : 
   15896              :     /* Do nothing if not dumping schema */
   15897           44 :     if (!dopt->dumpSchema)
   15898            7 :         return;
   15899              : 
   15900           37 :     q = createPQExpBuffer();
   15901           37 :     delq = createPQExpBuffer();
   15902              : 
   15903           37 :     qprsname = pg_strdup(fmtId(prsinfo->dobj.name));
   15904              : 
   15905           37 :     appendPQExpBuffer(q, "CREATE TEXT SEARCH PARSER %s (\n",
   15906           37 :                       fmtQualifiedDumpable(prsinfo));
   15907              : 
   15908           37 :     appendPQExpBuffer(q, "    START = %s,\n",
   15909           37 :                       convertTSFunction(fout, prsinfo->prsstart));
   15910           37 :     appendPQExpBuffer(q, "    GETTOKEN = %s,\n",
   15911           37 :                       convertTSFunction(fout, prsinfo->prstoken));
   15912           37 :     appendPQExpBuffer(q, "    END = %s,\n",
   15913           37 :                       convertTSFunction(fout, prsinfo->prsend));
   15914           37 :     if (prsinfo->prsheadline != InvalidOid)
   15915            3 :         appendPQExpBuffer(q, "    HEADLINE = %s,\n",
   15916            3 :                           convertTSFunction(fout, prsinfo->prsheadline));
   15917           37 :     appendPQExpBuffer(q, "    LEXTYPES = %s );\n",
   15918           37 :                       convertTSFunction(fout, prsinfo->prslextype));
   15919              : 
   15920           37 :     appendPQExpBuffer(delq, "DROP TEXT SEARCH PARSER %s;\n",
   15921           37 :                       fmtQualifiedDumpable(prsinfo));
   15922              : 
   15923           37 :     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           37 :     if (prsinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   15929           37 :         ArchiveEntry(fout, prsinfo->dobj.catId, prsinfo->dobj.dumpId,
   15930           37 :                      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           37 :     if (prsinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   15939           37 :         dumpComment(fout, "TEXT SEARCH PARSER", qprsname,
   15940           37 :                     prsinfo->dobj.namespace->dobj.name, "",
   15941           37 :                     prsinfo->dobj.catId, 0, prsinfo->dobj.dumpId);
   15942              : 
   15943           37 :     destroyPQExpBuffer(q);
   15944           37 :     destroyPQExpBuffer(delq);
   15945           37 :     free(qprsname);
   15946              : }
   15947              : 
   15948              : /*
   15949              :  * dumpTSDictionary
   15950              :  *    write out a single text search dictionary
   15951              :  */
   15952              : static void
   15953          182 : dumpTSDictionary(Archive *fout, const TSDictInfo *dictinfo)
   15954              : {
   15955          182 :     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          182 :     if (!dopt->dumpSchema)
   15966            7 :         return;
   15967              : 
   15968          175 :     q = createPQExpBuffer();
   15969          175 :     delq = createPQExpBuffer();
   15970          175 :     query = createPQExpBuffer();
   15971              : 
   15972          175 :     qdictname = pg_strdup(fmtId(dictinfo->dobj.name));
   15973              : 
   15974              :     /* Fetch name and namespace of the dictionary's template */
   15975          175 :     appendPQExpBuffer(query, "SELECT nspname, tmplname "
   15976              :                       "FROM pg_ts_template p, pg_namespace n "
   15977              :                       "WHERE p.oid = '%u' AND n.oid = tmplnamespace",
   15978          175 :                       dictinfo->dicttemplate);
   15979          175 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   15980          175 :     nspname = PQgetvalue(res, 0, 0);
   15981          175 :     tmplname = PQgetvalue(res, 0, 1);
   15982              : 
   15983          175 :     appendPQExpBuffer(q, "CREATE TEXT SEARCH DICTIONARY %s (\n",
   15984          175 :                       fmtQualifiedDumpable(dictinfo));
   15985              : 
   15986          175 :     appendPQExpBufferStr(q, "    TEMPLATE = ");
   15987          175 :     appendPQExpBuffer(q, "%s.", fmtId(nspname));
   15988          175 :     appendPQExpBufferStr(q, fmtId(tmplname));
   15989              : 
   15990          175 :     PQclear(res);
   15991              : 
   15992              :     /* the dictinitoption can be dumped straight into the command */
   15993          175 :     if (dictinfo->dictinitoption)
   15994          138 :         appendPQExpBuffer(q, ",\n    %s", dictinfo->dictinitoption);
   15995              : 
   15996          175 :     appendPQExpBufferStr(q, " );\n");
   15997              : 
   15998          175 :     appendPQExpBuffer(delq, "DROP TEXT SEARCH DICTIONARY %s;\n",
   15999          175 :                       fmtQualifiedDumpable(dictinfo));
   16000              : 
   16001          175 :     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          175 :     if (dictinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   16007          175 :         ArchiveEntry(fout, dictinfo->dobj.catId, dictinfo->dobj.dumpId,
   16008          175 :                      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          175 :     if (dictinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   16018          130 :         dumpComment(fout, "TEXT SEARCH DICTIONARY", qdictname,
   16019          130 :                     dictinfo->dobj.namespace->dobj.name, dictinfo->rolname,
   16020          130 :                     dictinfo->dobj.catId, 0, dictinfo->dobj.dumpId);
   16021              : 
   16022          175 :     destroyPQExpBuffer(q);
   16023          175 :     destroyPQExpBuffer(delq);
   16024          175 :     destroyPQExpBuffer(query);
   16025          175 :     free(qdictname);
   16026              : }
   16027              : 
   16028              : /*
   16029              :  * dumpTSTemplate
   16030              :  *    write out a single text search template
   16031              :  */
   16032              : static void
   16033           56 : dumpTSTemplate(Archive *fout, const TSTemplateInfo *tmplinfo)
   16034              : {
   16035           56 :     DumpOptions *dopt = fout->dopt;
   16036              :     PQExpBuffer q;
   16037              :     PQExpBuffer delq;
   16038              :     char       *qtmplname;
   16039              : 
   16040              :     /* Do nothing if not dumping schema */
   16041           56 :     if (!dopt->dumpSchema)
   16042            7 :         return;
   16043              : 
   16044           49 :     q = createPQExpBuffer();
   16045           49 :     delq = createPQExpBuffer();
   16046              : 
   16047           49 :     qtmplname = pg_strdup(fmtId(tmplinfo->dobj.name));
   16048              : 
   16049           49 :     appendPQExpBuffer(q, "CREATE TEXT SEARCH TEMPLATE %s (\n",
   16050           49 :                       fmtQualifiedDumpable(tmplinfo));
   16051              : 
   16052           49 :     if (tmplinfo->tmplinit != InvalidOid)
   16053           15 :         appendPQExpBuffer(q, "    INIT = %s,\n",
   16054           15 :                           convertTSFunction(fout, tmplinfo->tmplinit));
   16055           49 :     appendPQExpBuffer(q, "    LEXIZE = %s );\n",
   16056           49 :                       convertTSFunction(fout, tmplinfo->tmpllexize));
   16057              : 
   16058           49 :     appendPQExpBuffer(delq, "DROP TEXT SEARCH TEMPLATE %s;\n",
   16059           49 :                       fmtQualifiedDumpable(tmplinfo));
   16060              : 
   16061           49 :     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           49 :     if (tmplinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   16067           49 :         ArchiveEntry(fout, tmplinfo->dobj.catId, tmplinfo->dobj.dumpId,
   16068           49 :                      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           49 :     if (tmplinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   16077           49 :         dumpComment(fout, "TEXT SEARCH TEMPLATE", qtmplname,
   16078           49 :                     tmplinfo->dobj.namespace->dobj.name, "",
   16079           49 :                     tmplinfo->dobj.catId, 0, tmplinfo->dobj.dumpId);
   16080              : 
   16081           49 :     destroyPQExpBuffer(q);
   16082           49 :     destroyPQExpBuffer(delq);
   16083           49 :     free(qtmplname);
   16084              : }
   16085              : 
   16086              : /*
   16087              :  * dumpTSConfig
   16088              :  *    write out a single text search configuration
   16089              :  */
   16090              : static void
   16091          157 : dumpTSConfig(Archive *fout, const TSConfigInfo *cfginfo)
   16092              : {
   16093          157 :     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          157 :     if (!dopt->dumpSchema)
   16108            7 :         return;
   16109              : 
   16110          150 :     q = createPQExpBuffer();
   16111          150 :     delq = createPQExpBuffer();
   16112          150 :     query = createPQExpBuffer();
   16113              : 
   16114          150 :     qcfgname = pg_strdup(fmtId(cfginfo->dobj.name));
   16115              : 
   16116              :     /* Fetch name and namespace of the config's parser */
   16117          150 :     appendPQExpBuffer(query, "SELECT nspname, prsname "
   16118              :                       "FROM pg_ts_parser p, pg_namespace n "
   16119              :                       "WHERE p.oid = '%u' AND n.oid = prsnamespace",
   16120          150 :                       cfginfo->cfgparser);
   16121          150 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   16122          150 :     nspname = PQgetvalue(res, 0, 0);
   16123          150 :     prsname = PQgetvalue(res, 0, 1);
   16124              : 
   16125          150 :     appendPQExpBuffer(q, "CREATE TEXT SEARCH CONFIGURATION %s (\n",
   16126          150 :                       fmtQualifiedDumpable(cfginfo));
   16127              : 
   16128          150 :     appendPQExpBuffer(q, "    PARSER = %s.", fmtId(nspname));
   16129          150 :     appendPQExpBuffer(q, "%s );\n", fmtId(prsname));
   16130              : 
   16131          150 :     PQclear(res);
   16132              : 
   16133          150 :     resetPQExpBuffer(query);
   16134          150 :     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          150 :                       cfginfo->cfgparser, cfginfo->dobj.catId.oid);
   16143              : 
   16144          150 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   16145          150 :     ntups = PQntuples(res);
   16146              : 
   16147          150 :     i_tokenname = PQfnumber(res, "tokenname");
   16148          150 :     i_dictname = PQfnumber(res, "dictname");
   16149              : 
   16150         3135 :     for (i = 0; i < ntups; i++)
   16151              :     {
   16152         2985 :         char       *tokenname = PQgetvalue(res, i, i_tokenname);
   16153         2985 :         char       *dictname = PQgetvalue(res, i, i_dictname);
   16154              : 
   16155         2985 :         if (i == 0 ||
   16156         2835 :             strcmp(tokenname, PQgetvalue(res, i - 1, i_tokenname)) != 0)
   16157              :         {
   16158              :             /* starting a new token type, so start a new command */
   16159         2850 :             if (i > 0)
   16160         2700 :                 appendPQExpBufferStr(q, ";\n");
   16161         2850 :             appendPQExpBuffer(q, "\nALTER TEXT SEARCH CONFIGURATION %s\n",
   16162         2850 :                               fmtQualifiedDumpable(cfginfo));
   16163              :             /* tokenname needs quoting, dictname does NOT */
   16164         2850 :             appendPQExpBuffer(q, "    ADD MAPPING FOR %s WITH %s",
   16165              :                               fmtId(tokenname), dictname);
   16166              :         }
   16167              :         else
   16168          135 :             appendPQExpBuffer(q, ", %s", dictname);
   16169              :     }
   16170              : 
   16171          150 :     if (ntups > 0)
   16172          150 :         appendPQExpBufferStr(q, ";\n");
   16173              : 
   16174          150 :     PQclear(res);
   16175              : 
   16176          150 :     appendPQExpBuffer(delq, "DROP TEXT SEARCH CONFIGURATION %s;\n",
   16177          150 :                       fmtQualifiedDumpable(cfginfo));
   16178              : 
   16179          150 :     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          150 :     if (cfginfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   16185          150 :         ArchiveEntry(fout, cfginfo->dobj.catId, cfginfo->dobj.dumpId,
   16186          150 :                      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          150 :     if (cfginfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   16196          130 :         dumpComment(fout, "TEXT SEARCH CONFIGURATION", qcfgname,
   16197          130 :                     cfginfo->dobj.namespace->dobj.name, cfginfo->rolname,
   16198          130 :                     cfginfo->dobj.catId, 0, cfginfo->dobj.dumpId);
   16199              : 
   16200          150 :     destroyPQExpBuffer(q);
   16201          150 :     destroyPQExpBuffer(delq);
   16202          150 :     destroyPQExpBuffer(query);
   16203          150 :     free(qcfgname);
   16204              : }
   16205              : 
   16206              : /*
   16207              :  * dumpForeignDataWrapper
   16208              :  *    write out a single foreign-data wrapper definition
   16209              :  */
   16210              : static void
   16211           54 : dumpForeignDataWrapper(Archive *fout, const FdwInfo *fdwinfo)
   16212              : {
   16213           54 :     DumpOptions *dopt = fout->dopt;
   16214              :     PQExpBuffer q;
   16215              :     PQExpBuffer delq;
   16216              :     char       *qfdwname;
   16217              : 
   16218              :     /* Do nothing if not dumping schema */
   16219           54 :     if (!dopt->dumpSchema)
   16220            7 :         return;
   16221              : 
   16222           47 :     q = createPQExpBuffer();
   16223           47 :     delq = createPQExpBuffer();
   16224              : 
   16225           47 :     qfdwname = pg_strdup(fmtId(fdwinfo->dobj.name));
   16226              : 
   16227           47 :     appendPQExpBuffer(q, "CREATE FOREIGN DATA WRAPPER %s",
   16228              :                       qfdwname);
   16229              : 
   16230           47 :     if (strcmp(fdwinfo->fdwhandler, "-") != 0)
   16231            0 :         appendPQExpBuffer(q, " HANDLER %s", fdwinfo->fdwhandler);
   16232              : 
   16233           47 :     if (strcmp(fdwinfo->fdwvalidator, "-") != 0)
   16234            0 :         appendPQExpBuffer(q, " VALIDATOR %s", fdwinfo->fdwvalidator);
   16235              : 
   16236           47 :     if (strcmp(fdwinfo->fdwconnection, "-") != 0)
   16237            0 :         appendPQExpBuffer(q, " CONNECTION %s", fdwinfo->fdwconnection);
   16238              : 
   16239           47 :     if (strlen(fdwinfo->fdwoptions) > 0)
   16240            0 :         appendPQExpBuffer(q, " OPTIONS (\n    %s\n)", fdwinfo->fdwoptions);
   16241              : 
   16242           47 :     appendPQExpBufferStr(q, ";\n");
   16243              : 
   16244           47 :     appendPQExpBuffer(delq, "DROP FOREIGN DATA WRAPPER %s;\n",
   16245              :                       qfdwname);
   16246              : 
   16247           47 :     if (dopt->binary_upgrade)
   16248            2 :         binary_upgrade_extension_member(q, &fdwinfo->dobj,
   16249              :                                         "FOREIGN DATA WRAPPER", qfdwname,
   16250              :                                         NULL);
   16251              : 
   16252           47 :     if (fdwinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   16253           47 :         ArchiveEntry(fout, fdwinfo->dobj.catId, fdwinfo->dobj.dumpId,
   16254           47 :                      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           47 :     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           47 :     if (fdwinfo->dobj.dump & DUMP_COMPONENT_ACL)
   16269           33 :         dumpACL(fout, fdwinfo->dobj.dumpId, InvalidDumpId,
   16270              :                 "FOREIGN DATA WRAPPER", qfdwname, NULL, NULL,
   16271           33 :                 NULL, fdwinfo->rolname, &fdwinfo->dacl);
   16272              : 
   16273           47 :     free(qfdwname);
   16274              : 
   16275           47 :     destroyPQExpBuffer(q);
   16276           47 :     destroyPQExpBuffer(delq);
   16277              : }
   16278              : 
   16279              : /*
   16280              :  * dumpForeignServer
   16281              :  *    write out a foreign server definition
   16282              :  */
   16283              : static void
   16284           58 : dumpForeignServer(Archive *fout, const ForeignServerInfo *srvinfo)
   16285              : {
   16286           58 :     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           58 :     if (!dopt->dumpSchema)
   16296            9 :         return;
   16297              : 
   16298           49 :     q = createPQExpBuffer();
   16299           49 :     delq = createPQExpBuffer();
   16300           49 :     query = createPQExpBuffer();
   16301              : 
   16302           49 :     qsrvname = pg_strdup(fmtId(srvinfo->dobj.name));
   16303              : 
   16304              :     /* look up the foreign-data wrapper */
   16305           49 :     appendPQExpBuffer(query, "SELECT fdwname "
   16306              :                       "FROM pg_foreign_data_wrapper w "
   16307              :                       "WHERE w.oid = '%u'",
   16308           49 :                       srvinfo->srvfdw);
   16309           49 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   16310           49 :     fdwname = PQgetvalue(res, 0, 0);
   16311              : 
   16312           49 :     appendPQExpBuffer(q, "CREATE SERVER %s", qsrvname);
   16313           49 :     if (srvinfo->srvtype && strlen(srvinfo->srvtype) > 0)
   16314              :     {
   16315            0 :         appendPQExpBufferStr(q, " TYPE ");
   16316            0 :         appendStringLiteralAH(q, srvinfo->srvtype, fout);
   16317              :     }
   16318           49 :     if (srvinfo->srvversion && strlen(srvinfo->srvversion) > 0)
   16319              :     {
   16320            0 :         appendPQExpBufferStr(q, " VERSION ");
   16321            0 :         appendStringLiteralAH(q, srvinfo->srvversion, fout);
   16322              :     }
   16323              : 
   16324           49 :     appendPQExpBufferStr(q, " FOREIGN DATA WRAPPER ");
   16325           49 :     appendPQExpBufferStr(q, fmtId(fdwname));
   16326              : 
   16327           49 :     if (srvinfo->srvoptions && strlen(srvinfo->srvoptions) > 0)
   16328            0 :         appendPQExpBuffer(q, " OPTIONS (\n    %s\n)", srvinfo->srvoptions);
   16329              : 
   16330           49 :     appendPQExpBufferStr(q, ";\n");
   16331              : 
   16332           49 :     appendPQExpBuffer(delq, "DROP SERVER %s;\n",
   16333              :                       qsrvname);
   16334              : 
   16335           49 :     if (dopt->binary_upgrade)
   16336            2 :         binary_upgrade_extension_member(q, &srvinfo->dobj,
   16337              :                                         "SERVER", qsrvname, NULL);
   16338              : 
   16339           49 :     if (srvinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   16340           49 :         ArchiveEntry(fout, srvinfo->dobj.catId, srvinfo->dobj.dumpId,
   16341           49 :                      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           49 :     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           49 :     if (srvinfo->dobj.dump & DUMP_COMPONENT_ACL)
   16356           33 :         dumpACL(fout, srvinfo->dobj.dumpId, InvalidDumpId,
   16357              :                 "FOREIGN SERVER", qsrvname, NULL, NULL,
   16358           33 :                 NULL, srvinfo->rolname, &srvinfo->dacl);
   16359              : 
   16360              :     /* Dump user mappings */
   16361           49 :     if (srvinfo->dobj.dump & DUMP_COMPONENT_USERMAP)
   16362           49 :         dumpUserMappings(fout,
   16363           49 :                          srvinfo->dobj.name, NULL,
   16364           49 :                          srvinfo->rolname,
   16365           49 :                          srvinfo->dobj.catId, srvinfo->dobj.dumpId);
   16366              : 
   16367           49 :     PQclear(res);
   16368              : 
   16369           49 :     free(qsrvname);
   16370              : 
   16371           49 :     destroyPQExpBuffer(q);
   16372           49 :     destroyPQExpBuffer(delq);
   16373           49 :     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           49 : 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           49 :     q = createPQExpBuffer();
   16400           49 :     tag = createPQExpBuffer();
   16401           49 :     delq = createPQExpBuffer();
   16402           49 :     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           49 :     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           49 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   16426              : 
   16427           49 :     ntups = PQntuples(res);
   16428           49 :     i_usename = PQfnumber(res, "usename");
   16429           49 :     i_umoptions = PQfnumber(res, "umoptions");
   16430              : 
   16431           82 :     for (i = 0; i < ntups; i++)
   16432              :     {
   16433              :         char       *usename;
   16434              :         char       *umoptions;
   16435              : 
   16436           33 :         usename = PQgetvalue(res, i, i_usename);
   16437           33 :         umoptions = PQgetvalue(res, i, i_umoptions);
   16438              : 
   16439           33 :         resetPQExpBuffer(q);
   16440           33 :         appendPQExpBuffer(q, "CREATE USER MAPPING FOR %s", fmtId(usename));
   16441           33 :         appendPQExpBuffer(q, " SERVER %s", fmtId(servername));
   16442              : 
   16443           33 :         if (umoptions && strlen(umoptions) > 0)
   16444            0 :             appendPQExpBuffer(q, " OPTIONS (\n    %s\n)", umoptions);
   16445              : 
   16446           33 :         appendPQExpBufferStr(q, ";\n");
   16447              : 
   16448           33 :         resetPQExpBuffer(delq);
   16449           33 :         appendPQExpBuffer(delq, "DROP USER MAPPING FOR %s", fmtId(usename));
   16450           33 :         appendPQExpBuffer(delq, " SERVER %s;\n", fmtId(servername));
   16451              : 
   16452           33 :         resetPQExpBuffer(tag);
   16453           33 :         appendPQExpBuffer(tag, "USER MAPPING %s SERVER %s",
   16454              :                           usename, servername);
   16455              : 
   16456           33 :         ArchiveEntry(fout, nilCatalogId, createDumpId(),
   16457           33 :                      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           49 :     PQclear(res);
   16467              : 
   16468           49 :     destroyPQExpBuffer(query);
   16469           49 :     destroyPQExpBuffer(delq);
   16470           49 :     destroyPQExpBuffer(tag);
   16471           49 :     destroyPQExpBuffer(q);
   16472           49 : }
   16473              : 
   16474              : /*
   16475              :  * Write out default privileges information
   16476              :  */
   16477              : static void
   16478          170 : dumpDefaultACL(Archive *fout, const DefaultACLInfo *daclinfo)
   16479              : {
   16480          170 :     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          170 :     if (!dopt->dumpSchema || dopt->aclsSkip)
   16487           30 :         return;
   16488              : 
   16489          140 :     q = createPQExpBuffer();
   16490          140 :     tag = createPQExpBuffer();
   16491              : 
   16492          140 :     switch (daclinfo->defaclobjtype)
   16493              :     {
   16494           65 :         case DEFACLOBJ_RELATION:
   16495           65 :             type = "TABLES";
   16496           65 :             break;
   16497            0 :         case DEFACLOBJ_SEQUENCE:
   16498            0 :             type = "SEQUENCES";
   16499            0 :             break;
   16500           65 :         case DEFACLOBJ_FUNCTION:
   16501           65 :             type = "FUNCTIONS";
   16502           65 :             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          140 :     appendPQExpBuffer(tag, "DEFAULT PRIVILEGES FOR %s", type);
   16520              : 
   16521              :     /* build the actual command(s) for this tuple */
   16522          140 :     if (!buildDefaultACLCommands(type,
   16523          140 :                                  daclinfo->dobj.namespace != NULL ?
   16524           66 :                                  daclinfo->dobj.namespace->dobj.name : NULL,
   16525          140 :                                  daclinfo->dacl.acl,
   16526          140 :                                  daclinfo->dacl.acldefault,
   16527          140 :                                  daclinfo->defaclrole,
   16528              :                                  fout->remoteVersion,
   16529              :                                  q))
   16530            0 :         pg_fatal("could not parse default ACL list (%s)",
   16531              :                  daclinfo->dacl.acl);
   16532              : 
   16533          140 :     if (daclinfo->dobj.dump & DUMP_COMPONENT_ACL)
   16534          140 :         ArchiveEntry(fout, daclinfo->dobj.catId, daclinfo->dobj.dumpId,
   16535          140 :                      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          140 :     destroyPQExpBuffer(tag);
   16544          140 :     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        44376 : 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        44376 :     DumpId      aclDumpId = InvalidDumpId;
   16576        44376 :     DumpOptions *dopt = fout->dopt;
   16577        44376 :     const char *acls = dacl->acl;
   16578        44376 :     const char *acldefault = dacl->acldefault;
   16579        44376 :     char        privtype = dacl->privtype;
   16580        44376 :     const char *initprivs = dacl->initprivs;
   16581              :     const char *baseacls;
   16582              :     PQExpBuffer sql;
   16583              : 
   16584              :     /* Do nothing if ACL dump is not enabled */
   16585        44376 :     if (dopt->aclsSkip)
   16586          347 :         return InvalidDumpId;
   16587              : 
   16588              :     /* --data-only skips ACLs *except* large object ACLs */
   16589        44029 :     if (!dopt->dumpSchema && strcmp(type, "LARGE OBJECT") != 0)
   16590            1 :         return InvalidDumpId;
   16591              : 
   16592        44028 :     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        44028 :     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        44028 :     if (initprivs && *initprivs != '\0')
   16628              :     {
   16629        42008 :         baseacls = initprivs;
   16630        42008 :         if (acls == NULL || *acls == '\0')
   16631           17 :             acls = acldefault;
   16632              :     }
   16633              :     else
   16634         2020 :         baseacls = acldefault;
   16635              : 
   16636        44028 :     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        44028 :     if (sql->len > 0)
   16643              :     {
   16644         2025 :         PQExpBuffer tagbuf = createPQExpBuffer();
   16645              :         DumpId      aclDeps[2];
   16646         2025 :         int         nDeps = 0;
   16647              : 
   16648         2025 :         if (tag)
   16649            0 :             appendPQExpBufferStr(tagbuf, tag);
   16650         2025 :         else if (subname)
   16651         1111 :             appendPQExpBuffer(tagbuf, "COLUMN %s.%s", name, subname);
   16652              :         else
   16653          914 :             appendPQExpBuffer(tagbuf, "%s %s", type, name);
   16654              : 
   16655         2025 :         aclDeps[nDeps++] = objDumpId;
   16656         2025 :         if (altDumpId != InvalidDumpId)
   16657         1025 :             aclDeps[nDeps++] = altDumpId;
   16658              : 
   16659         2025 :         aclDumpId = createDumpId();
   16660              : 
   16661         2025 :         ArchiveEntry(fout, nilCatalogId, aclDumpId,
   16662         2025 :                      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         2025 :         destroyPQExpBuffer(tagbuf);
   16672              :     }
   16673              : 
   16674        44028 :     destroyPQExpBuffer(sql);
   16675              : 
   16676        44028 :     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          262 : 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          262 :     query = createPQExpBuffer();
   16953              : 
   16954          262 :     appendPQExpBufferStr(query,
   16955              :                          "SELECT label, provider, classoid, objoid, objsubid "
   16956              :                          "FROM pg_catalog.pg_seclabels "
   16957              :                          "ORDER BY classoid, objoid, objsubid");
   16958              : 
   16959          262 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   16960              : 
   16961              :     /* Construct lookup table containing OIDs in numeric form */
   16962          262 :     i_label = PQfnumber(res, "label");
   16963          262 :     i_provider = PQfnumber(res, "provider");
   16964          262 :     i_classoid = PQfnumber(res, "classoid");
   16965          262 :     i_objoid = PQfnumber(res, "objoid");
   16966          262 :     i_objsubid = PQfnumber(res, "objsubid");
   16967              : 
   16968          262 :     ntups = PQntuples(res);
   16969              : 
   16970          262 :     seclabels = pg_malloc_array(SecLabelItem, ntups);
   16971          262 :     nseclabels = 0;
   16972          262 :     dobj = NULL;
   16973              : 
   16974          267 :     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          262 :     PQclear(res);
   17017          262 :     destroyPQExpBuffer(query);
   17018          262 : }
   17019              : 
   17020              : /*
   17021              :  * dumpTable
   17022              :  *    write out to fout the declarations (not data) of a user-defined table
   17023              :  */
   17024              : static void
   17025        45243 : dumpTable(Archive *fout, const TableInfo *tbinfo)
   17026              : {
   17027        45243 :     DumpOptions *dopt = fout->dopt;
   17028        45243 :     DumpId      tableAclDumpId = InvalidDumpId;
   17029              :     char       *namecopy;
   17030              : 
   17031              :     /* Do nothing if not dumping schema */
   17032        45243 :     if (!dopt->dumpSchema)
   17033         1663 :         return;
   17034              : 
   17035        43580 :     if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   17036              :     {
   17037         7391 :         if (tbinfo->relkind == RELKIND_SEQUENCE)
   17038          390 :             dumpSequence(fout, tbinfo);
   17039              :         else
   17040         7001 :             dumpTableSchema(fout, tbinfo);
   17041              :     }
   17042              : 
   17043              :     /* Handle the ACL here */
   17044        43580 :     namecopy = pg_strdup(fmtId(tbinfo->dobj.name));
   17045        43580 :     if (tbinfo->dobj.dump & DUMP_COMPONENT_ACL)
   17046              :     {
   17047              :         const char *objtype;
   17048              : 
   17049        37036 :         switch (tbinfo->relkind)
   17050              :         {
   17051           99 :             case RELKIND_SEQUENCE:
   17052           99 :                 objtype = "SEQUENCE";
   17053           99 :                 break;
   17054           39 :             case RELKIND_PROPGRAPH:
   17055           39 :                 objtype = "PROPERTY GRAPH";
   17056           39 :                 break;
   17057        36898 :             default:
   17058        36898 :                 objtype = "TABLE";
   17059        36898 :                 break;
   17060              :         }
   17061              : 
   17062              :         tableAclDumpId =
   17063        37036 :             dumpACL(fout, tbinfo->dobj.dumpId, InvalidDumpId,
   17064              :                     objtype, namecopy, NULL,
   17065        37036 :                     tbinfo->dobj.namespace->dobj.name,
   17066        37036 :                     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        43580 :     if ((tbinfo->dobj.dump & DUMP_COMPONENT_ACL) && tbinfo->hascolumnACLs)
   17076              :     {
   17077          362 :         PQExpBuffer query = createPQExpBuffer();
   17078              :         PGresult   *res;
   17079              :         int         i;
   17080              : 
   17081          362 :         if (!fout->is_prepared[PREPQUERY_GETCOLUMNACLS])
   17082              :         {
   17083              :             /* Set up query for column ACLs */
   17084          235 :             appendPQExpBufferStr(query,
   17085              :                                  "PREPARE getColumnACLs(pg_catalog.oid) AS\n");
   17086              : 
   17087          235 :             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          235 :                 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          235 :             ExecuteSqlStatement(fout, query->data);
   17126              : 
   17127          235 :             fout->is_prepared[PREPQUERY_GETCOLUMNACLS] = true;
   17128              :         }
   17129              : 
   17130          362 :         printfPQExpBuffer(query,
   17131              :                           "EXECUTE getColumnACLs('%u')",
   17132          362 :                           tbinfo->dobj.catId.oid);
   17133              : 
   17134          362 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   17135              : 
   17136         6577 :         for (i = 0; i < PQntuples(res); i++)
   17137              :         {
   17138         6215 :             char       *attname = PQgetvalue(res, i, 0);
   17139         6215 :             char       *attacl = PQgetvalue(res, i, 1);
   17140         6215 :             char       *acldefault = PQgetvalue(res, i, 2);
   17141         6215 :             char        privtype = *(PQgetvalue(res, i, 3));
   17142         6215 :             char       *initprivs = PQgetvalue(res, i, 4);
   17143              :             DumpableAcl coldacl;
   17144              :             char       *attnamecopy;
   17145              : 
   17146         6215 :             coldacl.acl = attacl;
   17147         6215 :             coldacl.acldefault = acldefault;
   17148         6215 :             coldacl.privtype = privtype;
   17149         6215 :             coldacl.initprivs = initprivs;
   17150         6215 :             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         6215 :             dumpACL(fout, tbinfo->dobj.dumpId, tableAclDumpId,
   17158              :                     "TABLE", namecopy, attnamecopy,
   17159         6215 :                     tbinfo->dobj.namespace->dobj.name,
   17160         6215 :                     NULL, tbinfo->rolname, &coldacl);
   17161         6215 :             free(attnamecopy);
   17162              :         }
   17163          362 :         PQclear(res);
   17164          362 :         destroyPQExpBuffer(query);
   17165              :     }
   17166              : 
   17167        43580 :     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          923 : createViewAsClause(Archive *fout, const TableInfo *tbinfo)
   17178              : {
   17179          923 :     PQExpBuffer query = createPQExpBuffer();
   17180          923 :     PQExpBuffer result = createPQExpBuffer();
   17181              :     PGresult   *res;
   17182              :     int         len;
   17183              : 
   17184              :     /* Fetch the view definition */
   17185          923 :     appendPQExpBuffer(query,
   17186              :                       "SELECT pg_catalog.pg_get_viewdef('%u'::pg_catalog.oid) AS viewdef",
   17187          923 :                       tbinfo->dobj.catId.oid);
   17188              : 
   17189          923 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   17190              : 
   17191          923 :     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          923 :     len = PQgetlength(res, 0, 0);
   17202              : 
   17203          923 :     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          923 :     appendBinaryPQExpBuffer(result, PQgetvalue(res, 0, 0), len - 1);
   17210              : 
   17211          923 :     PQclear(res);
   17212          923 :     destroyPQExpBuffer(query);
   17213              : 
   17214          923 :     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         7001 : dumpTableSchema(Archive *fout, const TableInfo *tbinfo)
   17267              : {
   17268         7001 :     DumpOptions *dopt = fout->dopt;
   17269         7001 :     PQExpBuffer q = createPQExpBuffer();
   17270         7001 :     PQExpBuffer delq = createPQExpBuffer();
   17271         7001 :     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         7001 :     qrelname = pg_strdup(fmtId(tbinfo->dobj.name));
   17286         7001 :     qualrelname = pg_strdup(fmtQualifiedDumpable(tbinfo));
   17287              : 
   17288         7001 :     if (tbinfo->hasoids)
   17289            0 :         pg_log_warning("WITH OIDS is not supported anymore (table \"%s\")",
   17290              :                        qrelname);
   17291              : 
   17292         7001 :     if (dopt->binary_upgrade)
   17293          949 :         binary_upgrade_set_type_oids_by_rel(fout, q, tbinfo);
   17294              : 
   17295              :     /* Is it a table or a view? */
   17296         7001 :     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          570 :         reltypename = "VIEW";
   17305              : 
   17306          570 :         if (dopt->binary_upgrade)
   17307           56 :             binary_upgrade_set_pg_class_oids(fout, q,
   17308           56 :                                              tbinfo->dobj.catId.oid);
   17309              : 
   17310          570 :         appendPQExpBuffer(q, "CREATE VIEW %s", qualrelname);
   17311              : 
   17312          570 :         if (tbinfo->dummy_view)
   17313           10 :             result = createDummyViewAsClause(fout, tbinfo);
   17314              :         else
   17315              :         {
   17316          560 :             if (nonemptyReloptions(tbinfo->reloptions))
   17317              :             {
   17318           63 :                 appendPQExpBufferStr(q, " WITH (");
   17319           63 :                 appendReloptionsArrayAH(q, tbinfo->reloptions, "", fout);
   17320           63 :                 appendPQExpBufferChar(q, ')');
   17321              :             }
   17322          560 :             result = createViewAsClause(fout, tbinfo);
   17323              :         }
   17324          570 :         appendPQExpBuffer(q, " AS\n%s", result->data);
   17325          570 :         destroyPQExpBuffer(result);
   17326              : 
   17327          570 :         if (tbinfo->checkoption != NULL && !tbinfo->dummy_view)
   17328           34 :             appendPQExpBuffer(q, "\n  WITH %s CHECK OPTION", tbinfo->checkoption);
   17329          570 :         appendPQExpBufferStr(q, ";\n");
   17330              :     }
   17331         6431 :     else if (tbinfo->relkind == RELKIND_PROPGRAPH)
   17332              :     {
   17333           99 :         PQExpBuffer query = createPQExpBuffer();
   17334              :         PGresult   *res;
   17335              :         int         len;
   17336              : 
   17337           99 :         reltypename = "PROPERTY GRAPH";
   17338              : 
   17339           99 :         if (dopt->binary_upgrade)
   17340           14 :             binary_upgrade_set_pg_class_oids(fout, q,
   17341           14 :                                              tbinfo->dobj.catId.oid);
   17342              : 
   17343           99 :         appendPQExpBuffer(query,
   17344              :                           "SELECT pg_catalog.pg_get_propgraphdef('%u'::pg_catalog.oid) AS pgdef",
   17345           99 :                           tbinfo->dobj.catId.oid);
   17346              : 
   17347           99 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   17348              : 
   17349           99 :         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           99 :         len = PQgetlength(res, 0, 0);
   17360              : 
   17361           99 :         if (len == 0)
   17362            0 :             pg_fatal("definition of property graph \"%s\" appears to be empty (length zero)",
   17363              :                      tbinfo->dobj.name);
   17364              : 
   17365           99 :         appendPQExpBufferStr(q, PQgetvalue(res, 0, 0));
   17366              : 
   17367           99 :         PQclear(res);
   17368           99 :         destroyPQExpBuffer(query);
   17369              : 
   17370           99 :         appendPQExpBufferStr(q, ";\n");
   17371              :     }
   17372              :     else
   17373              :     {
   17374         6332 :         char       *partkeydef = NULL;
   17375         6332 :         char       *ftoptions = NULL;
   17376         6332 :         char       *srvname = NULL;
   17377         6332 :         const char *foreign = "";
   17378              : 
   17379              :         /*
   17380              :          * Set reltypename, and collect any relkind-specific data that we
   17381              :          * didn't fetch during getTables().
   17382              :          */
   17383         6332 :         switch (tbinfo->relkind)
   17384              :         {
   17385          604 :             case RELKIND_PARTITIONED_TABLE:
   17386              :                 {
   17387          604 :                     PQExpBuffer query = createPQExpBuffer();
   17388              :                     PGresult   *res;
   17389              : 
   17390          604 :                     reltypename = "TABLE";
   17391              : 
   17392              :                     /* retrieve partition key definition */
   17393          604 :                     appendPQExpBuffer(query,
   17394              :                                       "SELECT pg_get_partkeydef('%u')",
   17395          604 :                                       tbinfo->dobj.catId.oid);
   17396          604 :                     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   17397          604 :                     partkeydef = pg_strdup(PQgetvalue(res, 0, 0));
   17398          604 :                     PQclear(res);
   17399          604 :                     destroyPQExpBuffer(query);
   17400          604 :                     break;
   17401              :                 }
   17402           36 :             case RELKIND_FOREIGN_TABLE:
   17403              :                 {
   17404           36 :                     PQExpBuffer query = createPQExpBuffer();
   17405              :                     PGresult   *res;
   17406              :                     int         i_srvname;
   17407              :                     int         i_ftoptions;
   17408              : 
   17409           36 :                     reltypename = "FOREIGN TABLE";
   17410              : 
   17411              :                     /* retrieve name of foreign server and generic options */
   17412           36 :                     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           36 :                                       tbinfo->dobj.catId.oid);
   17425           36 :                     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   17426           36 :                     i_srvname = PQfnumber(res, "srvname");
   17427           36 :                     i_ftoptions = PQfnumber(res, "ftoptions");
   17428           36 :                     srvname = pg_strdup(PQgetvalue(res, 0, i_srvname));
   17429           36 :                     ftoptions = pg_strdup(PQgetvalue(res, 0, i_ftoptions));
   17430           36 :                     PQclear(res);
   17431           36 :                     destroyPQExpBuffer(query);
   17432              : 
   17433           36 :                     foreign = "FOREIGN ";
   17434           36 :                     break;
   17435              :                 }
   17436          353 :             case RELKIND_MATVIEW:
   17437          353 :                 reltypename = "MATERIALIZED VIEW";
   17438          353 :                 break;
   17439         5339 :             default:
   17440         5339 :                 reltypename = "TABLE";
   17441         5339 :                 break;
   17442              :         }
   17443              : 
   17444         6332 :         numParents = tbinfo->numParents;
   17445         6332 :         parents = tbinfo->parents;
   17446              : 
   17447         6332 :         if (dopt->binary_upgrade)
   17448          879 :             binary_upgrade_set_pg_class_oids(fout, q,
   17449          879 :                                              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         6332 :         appendPQExpBuffer(q, "CREATE %s%s %s",
   17456         6332 :                           (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         6332 :         if (OidIsValid(tbinfo->reloftype) && !dopt->binary_upgrade)
   17467           24 :             appendPQExpBuffer(q, " OF %s",
   17468           24 :                               getFormattedTypeName(fout, tbinfo->reloftype,
   17469              :                                                    zeroIsError));
   17470              : 
   17471         6332 :         if (tbinfo->relkind != RELKIND_MATVIEW)
   17472              :         {
   17473              :             /* Dump the attributes */
   17474         5979 :             actual_atts = 0;
   17475        27399 :             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        21420 :                 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        41728 :                     print_default = (tbinfo->attrdefs[j] != NULL &&
   17493        21376 :                                      tbinfo->attrdefs[j]->dobj.dump &&
   17494         1073 :                                      !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        22808 :                     print_notnull = (tbinfo->notnull_constrs[j] != NULL &&
   17502         2505 :                                      (tbinfo->notnull_islocal[j] ||
   17503          675 :                                       dopt->binary_upgrade ||
   17504          581 :                                       tbinfo->ispartition));
   17505              : 
   17506              :                     /*
   17507              :                      * Skip column if fully defined by reloftype, except in
   17508              :                      * binary upgrade
   17509              :                      */
   17510        20303 :                     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        20279 :                     if (actual_atts == 0)
   17517         5592 :                         appendPQExpBufferStr(q, " (");
   17518              :                     else
   17519        14687 :                         appendPQExpBufferChar(q, ',');
   17520        20279 :                     appendPQExpBufferStr(q, "\n    ");
   17521        20279 :                     actual_atts++;
   17522              : 
   17523              :                     /* Attribute name */
   17524        20279 :                     appendPQExpBufferStr(q, fmtId(tbinfo->attnames[j]));
   17525              : 
   17526        20279 :                     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        20194 :                     if (dopt->binary_upgrade || !OidIsValid(tbinfo->reloftype))
   17545              :                     {
   17546        20178 :                         appendPQExpBuffer(q, " %s",
   17547        20178 :                                           tbinfo->atttypnames[j]);
   17548              :                     }
   17549              : 
   17550        20194 :                     if (print_default)
   17551              :                     {
   17552          939 :                         if (tbinfo->attgenerated[j] == ATTRIBUTE_GENERATED_STORED)
   17553          323 :                             appendPQExpBuffer(q, " GENERATED ALWAYS AS (%s) STORED",
   17554          323 :                                               tbinfo->attrdefs[j]->adef_expr);
   17555          616 :                         else if (tbinfo->attgenerated[j] == ATTRIBUTE_GENERATED_VIRTUAL)
   17556          225 :                             appendPQExpBuffer(q, " GENERATED ALWAYS AS (%s)",
   17557          225 :                                               tbinfo->attrdefs[j]->adef_expr);
   17558              :                         else
   17559          391 :                             appendPQExpBuffer(q, " DEFAULT %s",
   17560          391 :                                               tbinfo->attrdefs[j]->adef_expr);
   17561              :                     }
   17562              : 
   17563        20194 :                     if (print_notnull)
   17564              :                     {
   17565         2472 :                         if (tbinfo->notnull_constrs[j][0] == '\0')
   17566         1769 :                             appendPQExpBufferStr(q, " NOT NULL");
   17567              :                         else
   17568          703 :                             appendPQExpBuffer(q, " CONSTRAINT %s NOT NULL",
   17569          703 :                                               fmtId(tbinfo->notnull_constrs[j]));
   17570              : 
   17571         2472 :                         if (tbinfo->notnull_noinh[j])
   17572           35 :                             appendPQExpBufferStr(q, " NO INHERIT");
   17573              :                     }
   17574              : 
   17575              :                     /* Add collation if not default for the type */
   17576        20194 :                     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        21311 :                 if (!shouldPrintColumn(dopt, tbinfo, j) &&
   17598         1117 :                     !tbinfo->attisdropped[j] &&
   17599          748 :                     tbinfo->notnull_constrs[j] != NULL &&
   17600          216 :                     tbinfo->notnull_islocal[j])
   17601              :                 {
   17602              :                     /* Format properly if not first attr */
   17603           94 :                     if (actual_atts == 0)
   17604           90 :                         appendPQExpBufferStr(q, " (");
   17605              :                     else
   17606            4 :                         appendPQExpBufferChar(q, ',');
   17607           94 :                     appendPQExpBufferStr(q, "\n    ");
   17608           94 :                     actual_atts++;
   17609              : 
   17610           94 :                     if (tbinfo->notnull_constrs[j][0] == '\0')
   17611            8 :                         appendPQExpBuffer(q, "NOT NULL %s",
   17612            8 :                                           fmtId(tbinfo->attnames[j]));
   17613              :                     else
   17614          172 :                         appendPQExpBuffer(q, "CONSTRAINT %s NOT NULL %s",
   17615           86 :                                           tbinfo->notnull_constrs[j],
   17616           86 :                                           fmtId(tbinfo->attnames[j]));
   17617              : 
   17618           94 :                     if (tbinfo->notnull_noinh[j])
   17619           33 :                         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         6572 :             for (j = 0; j < tbinfo->ncheck; j++)
   17632              :             {
   17633          593 :                 ConstraintInfo *constr = &(tbinfo->checkexprs[j]);
   17634              : 
   17635          593 :                 if (constr->separate ||
   17636          523 :                     (!constr->conislocal && !tbinfo->ispartition))
   17637          109 :                     continue;
   17638              : 
   17639          484 :                 if (actual_atts == 0)
   17640           16 :                     appendPQExpBufferStr(q, " (\n    ");
   17641              :                 else
   17642          468 :                     appendPQExpBufferStr(q, ",\n    ");
   17643              : 
   17644          484 :                 appendPQExpBuffer(q, "CONSTRAINT %s ",
   17645          484 :                                   fmtId(constr->dobj.name));
   17646          484 :                 appendPQExpBufferStr(q, constr->condef);
   17647              : 
   17648          484 :                 actual_atts++;
   17649              :             }
   17650              : 
   17651         5979 :             if (actual_atts)
   17652         5698 :                 appendPQExpBufferStr(q, "\n)");
   17653          281 :             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          269 :                 appendPQExpBufferStr(q, " (\n)");
   17660              :             }
   17661              : 
   17662              :             /*
   17663              :              * Emit the INHERITS clause (not for partitions), except in
   17664              :              * binary-upgrade mode.
   17665              :              */
   17666         5979 :             if (numParents > 0 && !tbinfo->ispartition &&
   17667          555 :                 !dopt->binary_upgrade)
   17668              :             {
   17669          486 :                 appendPQExpBufferStr(q, "\nINHERITS (");
   17670         1045 :                 for (k = 0; k < numParents; k++)
   17671              :                 {
   17672          559 :                     TableInfo  *parentRel = parents[k];
   17673              : 
   17674          559 :                     if (k > 0)
   17675           73 :                         appendPQExpBufferStr(q, ", ");
   17676          559 :                     appendPQExpBufferStr(q, fmtQualifiedDumpable(parentRel));
   17677              :                 }
   17678          486 :                 appendPQExpBufferChar(q, ')');
   17679              :             }
   17680              : 
   17681         5979 :             if (tbinfo->relkind == RELKIND_PARTITIONED_TABLE)
   17682          604 :                 appendPQExpBuffer(q, "\nPARTITION BY %s", partkeydef);
   17683              : 
   17684         5979 :             if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
   17685           36 :                 appendPQExpBuffer(q, "\nSERVER %s", fmtId(srvname));
   17686              :         }
   17687              : 
   17688        12509 :         if (nonemptyReloptions(tbinfo->reloptions) ||
   17689         6177 :             nonemptyReloptions(tbinfo->toast_reloptions))
   17690              :         {
   17691          155 :             bool        addcomma = false;
   17692              : 
   17693          155 :             appendPQExpBufferStr(q, "\nWITH (");
   17694          155 :             if (nonemptyReloptions(tbinfo->reloptions))
   17695              :             {
   17696          155 :                 addcomma = true;
   17697          155 :                 appendReloptionsArrayAH(q, tbinfo->reloptions, "", fout);
   17698              :             }
   17699          155 :             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          155 :             appendPQExpBufferChar(q, ')');
   17707              :         }
   17708              : 
   17709              :         /* Dump generic options if any */
   17710         6332 :         if (ftoptions && ftoptions[0])
   17711           34 :             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         6332 :         if (tbinfo->relkind == RELKIND_MATVIEW)
   17718              :         {
   17719              :             PQExpBuffer result;
   17720              : 
   17721          353 :             result = createViewAsClause(fout, tbinfo);
   17722          353 :             appendPQExpBuffer(q, " AS\n%s\n  WITH NO DATA;\n",
   17723              :                               result->data);
   17724          353 :             destroyPQExpBuffer(result);
   17725              :         }
   17726              :         else
   17727         5979 :             appendPQExpBufferStr(q, ";\n");
   17728              : 
   17729              :         /* Materialized views can depend on extensions */
   17730         6332 :         if (tbinfo->relkind == RELKIND_MATVIEW)
   17731          353 :             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         6332 :         if (dopt->binary_upgrade)
   17741              :         {
   17742         4211 :             for (j = 0; j < tbinfo->numatts; j++)
   17743              :             {
   17744         3332 :                 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         6332 :         if (dopt->binary_upgrade &&
   17781          879 :             (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          862 :             resetPQExpBuffer(extra);
   17795          862 :             firstitem = true;
   17796         4173 :             for (j = 0; j < tbinfo->numatts; j++)
   17797              :             {
   17798         3311 :                 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          862 :             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          862 :             firstitem = true;
   17840         4173 :             for (j = 0; j < tbinfo->numatts; j++)
   17841              :             {
   17842         3311 :                 if (!tbinfo->attisdropped[j] &&
   17843         3226 :                     !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          862 :             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          862 :             firstitem = true;
   17871          862 :             firstitem_extra = true;
   17872          862 :             resetPQExpBuffer(extra);
   17873         4173 :             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         3311 :                 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          862 :             if (!firstitem)
   17922           69 :                 appendPQExpBufferStr(q, ");\n");
   17923          862 :             if (!firstitem_extra)
   17924           13 :                 appendPQExpBufferStr(extra, ");\n");
   17925              : 
   17926          862 :             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          862 :             resetPQExpBuffer(extra);
   17942          862 :             firstitem = true;
   17943          924 :             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          862 :             if (!firstitem)
   17972              :             {
   17973            2 :                 appendPQExpBufferStr(extra, ");\n");
   17974            2 :                 appendBinaryPQExpBuffer(q, extra->data, extra->len);
   17975              :             }
   17976              : 
   17977          862 :             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          862 :             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         6332 :         if (dopt->binary_upgrade &&
   18008          879 :             (tbinfo->relkind == RELKIND_RELATION ||
   18009          115 :              tbinfo->relkind == RELKIND_MATVIEW))
   18010              :         {
   18011          781 :             appendPQExpBufferStr(q, "\n-- For binary upgrade, set heap's relfrozenxid and relminmxid\n");
   18012          781 :             appendPQExpBuffer(q, "UPDATE pg_catalog.pg_class\n"
   18013              :                               "SET relfrozenxid = '%u', relminmxid = '%u'\n"
   18014              :                               "WHERE oid = ",
   18015          781 :                               tbinfo->frozenxid, tbinfo->minmxid);
   18016          781 :             appendStringLiteralAH(q, qualrelname, fout);
   18017          781 :             appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
   18018              : 
   18019          781 :             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          296 :                 appendPQExpBufferStr(q, "\n-- For binary upgrade, set toast's relfrozenxid and relminmxid\n");
   18026          296 :                 appendPQExpBuffer(q, "UPDATE pg_catalog.pg_class\n"
   18027              :                                   "SET relfrozenxid = '%u', relminmxid = '%u'\n"
   18028              :                                   "WHERE oid = '%u';\n",
   18029          296 :                                   tbinfo->toast_frozenxid,
   18030          296 :                                   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         6332 :         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        28183 :         for (j = 0; j < tbinfo->numatts; j++)
   18057              :         {
   18058              :             /* None of this applies to dropped columns */
   18059        21851 :             if (tbinfo->attisdropped[j])
   18060          454 :                 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        21397 :             if (tbinfo->attstattarget[j] >= 0)
   18068           34 :                 appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s ALTER COLUMN %s SET STATISTICS %d;\n",
   18069              :                                   foreign, qualrelname,
   18070           34 :                                   fmtId(tbinfo->attnames[j]),
   18071           34 :                                   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        21397 :             if (tbinfo->attstorage[j] != tbinfo->typstorage[j])
   18078              :             {
   18079           83 :                 switch (tbinfo->attstorage[j])
   18080              :                 {
   18081           10 :                     case TYPSTORAGE_PLAIN:
   18082           10 :                         storage = "PLAIN";
   18083           10 :                         break;
   18084           39 :                     case TYPSTORAGE_EXTERNAL:
   18085           39 :                         storage = "EXTERNAL";
   18086           39 :                         break;
   18087            0 :                     case TYPSTORAGE_EXTENDED:
   18088            0 :                         storage = "EXTENDED";
   18089            0 :                         break;
   18090           34 :                     case TYPSTORAGE_MAIN:
   18091           34 :                         storage = "MAIN";
   18092           34 :                         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           83 :                 if (storage != NULL)
   18101           83 :                     appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s ALTER COLUMN %s SET STORAGE %s;\n",
   18102              :                                       foreign, qualrelname,
   18103           83 :                                       fmtId(tbinfo->attnames[j]),
   18104              :                                       storage);
   18105              :             }
   18106              : 
   18107              :             /*
   18108              :              * Dump per-column compression, if it's been set.
   18109              :              */
   18110        21397 :             if (!dopt->no_toast_compression)
   18111              :             {
   18112              :                 const char *cmname;
   18113              : 
   18114        21297 :                 switch (tbinfo->attcompression[j])
   18115              :                 {
   18116           73 :                     case 'p':
   18117           73 :                         cmname = "pglz";
   18118           73 :                         break;
   18119           39 :                     case 'l':
   18120           39 :                         cmname = "lz4";
   18121           39 :                         break;
   18122        21185 :                     default:
   18123        21185 :                         cmname = NULL;
   18124        21185 :                         break;
   18125              :                 }
   18126              : 
   18127        21297 :                 if (cmname != NULL)
   18128          112 :                     appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s ALTER COLUMN %s SET COMPRESSION %s;\n",
   18129              :                                       foreign, qualrelname,
   18130          112 :                                       fmtId(tbinfo->attnames[j]),
   18131              :                                       cmname);
   18132              :             }
   18133              : 
   18134              :             /*
   18135              :              * Dump per-column attributes.
   18136              :              */
   18137        21397 :             if (tbinfo->attoptions[j][0] != '\0')
   18138           34 :                 appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s ALTER COLUMN %s SET (%s);\n",
   18139              :                                   foreign, qualrelname,
   18140           34 :                                   fmtId(tbinfo->attnames[j]),
   18141           34 :                                   tbinfo->attoptions[j]);
   18142              : 
   18143              :             /*
   18144              :              * Dump per-column fdw options.
   18145              :              */
   18146        21397 :             if (tbinfo->relkind == RELKIND_FOREIGN_TABLE &&
   18147           36 :                 tbinfo->attfdwoptions[j][0] != '\0')
   18148           34 :                 appendPQExpBuffer(q,
   18149              :                                   "ALTER FOREIGN TABLE ONLY %s ALTER COLUMN %s OPTIONS (\n"
   18150              :                                   "    %s\n"
   18151              :                                   ");\n",
   18152              :                                   qualrelname,
   18153           34 :                                   fmtId(tbinfo->attnames[j]),
   18154           34 :                                   tbinfo->attfdwoptions[j]);
   18155              :         }                       /* end loop over columns */
   18156              : 
   18157         6332 :         free(partkeydef);
   18158         6332 :         free(ftoptions);
   18159         6332 :         free(srvname);
   18160              :     }
   18161              : 
   18162              :     /*
   18163              :      * dump properties we only have ALTER TABLE syntax for
   18164              :      */
   18165         7001 :     if ((tbinfo->relkind == RELKIND_RELATION ||
   18166         1662 :          tbinfo->relkind == RELKIND_PARTITIONED_TABLE ||
   18167         1058 :          tbinfo->relkind == RELKIND_MATVIEW) &&
   18168         6296 :         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         7001 :     if (tbinfo->forcerowsec)
   18187           10 :         appendPQExpBuffer(q, "\nALTER TABLE ONLY %s FORCE ROW LEVEL SECURITY;\n",
   18188              :                           qualrelname);
   18189              : 
   18190         7001 :     appendPQExpBuffer(delq, "DROP %s %s;\n", reltypename, qualrelname);
   18191              : 
   18192         7001 :     if (dopt->binary_upgrade)
   18193          949 :         binary_upgrade_extension_member(q, &tbinfo->dobj,
   18194              :                                         reltypename, qrelname,
   18195          949 :                                         tbinfo->dobj.namespace->dobj.name);
   18196              : 
   18197         7001 :     if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   18198              :     {
   18199         7001 :         char       *tablespace = NULL;
   18200         7001 :         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         7001 :         if (RELKIND_HAS_TABLESPACE(tbinfo->relkind))
   18210         6296 :             tablespace = tbinfo->reltablespace;
   18211              : 
   18212         7001 :         if (RELKIND_HAS_TABLE_AM(tbinfo->relkind) ||
   18213         1309 :             tbinfo->relkind == RELKIND_PARTITIONED_TABLE)
   18214         6296 :             tableam = tbinfo->amname;
   18215              : 
   18216         7001 :         ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
   18217         7001 :                      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         7001 :     if (tbinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   18232           78 :         dumpTableComment(fout, tbinfo, reltypename);
   18233              : 
   18234              :     /* Dump Table Security Labels */
   18235         7001 :     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         7001 :     if (!fout->dopt->no_comments && dopt->dumpSchema &&
   18243         7001 :         fout->remoteVersion >= 180000)
   18244              :     {
   18245         7001 :         PQExpBuffer comment = NULL;
   18246         7001 :         PQExpBuffer tag = NULL;
   18247              : 
   18248        32537 :         for (j = 0; j < tbinfo->numatts; j++)
   18249              :         {
   18250        25536 :             if (tbinfo->notnull_constrs[j] != NULL &&
   18251         2721 :                 tbinfo->notnull_comment[j] != NULL)
   18252              :             {
   18253           44 :                 if (comment == NULL)
   18254              :                 {
   18255           44 :                     comment = createPQExpBuffer();
   18256           44 :                     tag = createPQExpBuffer();
   18257              :                 }
   18258              :                 else
   18259              :                 {
   18260            0 :                     resetPQExpBuffer(comment);
   18261            0 :                     resetPQExpBuffer(tag);
   18262              :                 }
   18263              : 
   18264           44 :                 appendPQExpBuffer(comment, "COMMENT ON CONSTRAINT %s ON %s IS ",
   18265           44 :                                   fmtId(tbinfo->notnull_constrs[j]), qualrelname);
   18266           44 :                 appendStringLiteralAH(comment, tbinfo->notnull_comment[j], fout);
   18267           44 :                 appendPQExpBufferStr(comment, ";\n");
   18268              : 
   18269           44 :                 appendPQExpBuffer(tag, "CONSTRAINT %s ON %s",
   18270           44 :                                   fmtId(tbinfo->notnull_constrs[j]), qrelname);
   18271              : 
   18272           44 :                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
   18273           44 :                              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         7001 :         destroyPQExpBuffer(comment);
   18285         7001 :         destroyPQExpBuffer(tag);
   18286              :     }
   18287              : 
   18288              :     /* Dump comments on inlined table constraints */
   18289         7594 :     for (j = 0; j < tbinfo->ncheck; j++)
   18290              :     {
   18291          593 :         ConstraintInfo *constr = &(tbinfo->checkexprs[j]);
   18292              : 
   18293          593 :         if (constr->separate || !constr->conislocal)
   18294          254 :             continue;
   18295              : 
   18296          339 :         if (constr->dobj.dump & DUMP_COMPONENT_COMMENT)
   18297           39 :             dumpTableConstraintComment(fout, constr);
   18298              :     }
   18299              : 
   18300         7001 :     destroyPQExpBuffer(q);
   18301         7001 :     destroyPQExpBuffer(delq);
   18302         7001 :     destroyPQExpBuffer(extra);
   18303         7001 :     free(qrelname);
   18304         7001 :     free(qualrelname);
   18305         7001 : }
   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         1452 : dumpTableAttach(Archive *fout, const TableAttachInfo *attachinfo)
   18324              : {
   18325         1452 :     DumpOptions *dopt = fout->dopt;
   18326              :     PQExpBuffer q;
   18327              :     PGresult   *res;
   18328              :     char       *partbound;
   18329              : 
   18330              :     /* Do nothing if not dumping schema */
   18331         1452 :     if (!dopt->dumpSchema)
   18332           57 :         return;
   18333              : 
   18334         1395 :     q = createPQExpBuffer();
   18335              : 
   18336         1395 :     if (!fout->is_prepared[PREPQUERY_DUMPTABLEATTACH])
   18337              :     {
   18338              :         /* Set up query for partbound details */
   18339           45 :         appendPQExpBufferStr(q,
   18340              :                              "PREPARE dumpTableAttach(pg_catalog.oid) AS\n");
   18341              : 
   18342           45 :         appendPQExpBufferStr(q,
   18343              :                              "SELECT pg_get_expr(c.relpartbound, c.oid) "
   18344              :                              "FROM pg_class c "
   18345              :                              "WHERE c.oid = $1");
   18346              : 
   18347           45 :         ExecuteSqlStatement(fout, q->data);
   18348              : 
   18349           45 :         fout->is_prepared[PREPQUERY_DUMPTABLEATTACH] = true;
   18350              :     }
   18351              : 
   18352         1395 :     printfPQExpBuffer(q,
   18353              :                       "EXECUTE dumpTableAttach('%u')",
   18354         1395 :                       attachinfo->partitionTbl->dobj.catId.oid);
   18355              : 
   18356         1395 :     res = ExecuteSqlQueryForSingleRow(fout, q->data);
   18357         1395 :     partbound = PQgetvalue(res, 0, 0);
   18358              : 
   18359              :     /* Perform ALTER TABLE on the parent */
   18360         1395 :     printfPQExpBuffer(q,
   18361              :                       "ALTER TABLE ONLY %s ",
   18362         1395 :                       fmtQualifiedDumpable(attachinfo->parentTbl));
   18363         1395 :     appendPQExpBuffer(q,
   18364              :                       "ATTACH PARTITION %s %s;\n",
   18365         1395 :                       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         1395 :     ArchiveEntry(fout, attachinfo->dobj.catId, attachinfo->dobj.dumpId,
   18376         1395 :                  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         1395 :     PQclear(res);
   18384         1395 :     destroyPQExpBuffer(q);
   18385              : }
   18386              : 
   18387              : /*
   18388              :  * dumpAttrDef --- dump an attribute's default-value declaration
   18389              :  */
   18390              : static void
   18391         1111 : dumpAttrDef(Archive *fout, const AttrDefInfo *adinfo)
   18392              : {
   18393         1111 :     DumpOptions *dopt = fout->dopt;
   18394         1111 :     TableInfo  *tbinfo = adinfo->adtable;
   18395         1111 :     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         1111 :     if (!dopt->dumpSchema)
   18404            0 :         return;
   18405              : 
   18406              :     /* Skip if not "separate"; it was dumped in the table's definition */
   18407         1111 :     if (!adinfo->separate)
   18408          939 :         return;
   18409              : 
   18410          172 :     q = createPQExpBuffer();
   18411          172 :     delq = createPQExpBuffer();
   18412              : 
   18413          172 :     qualrelname = pg_strdup(fmtQualifiedDumpable(tbinfo));
   18414              : 
   18415          172 :     foreign = tbinfo->relkind == RELKIND_FOREIGN_TABLE ? "FOREIGN " : "";
   18416              : 
   18417          172 :     appendPQExpBuffer(q,
   18418              :                       "ALTER %sTABLE ONLY %s ALTER COLUMN %s SET DEFAULT %s;\n",
   18419          172 :                       foreign, qualrelname, fmtId(tbinfo->attnames[adnum - 1]),
   18420          172 :                       adinfo->adef_expr);
   18421              : 
   18422          172 :     appendPQExpBuffer(delq, "ALTER %sTABLE %s ALTER COLUMN %s DROP DEFAULT;\n",
   18423              :                       foreign, qualrelname,
   18424          172 :                       fmtId(tbinfo->attnames[adnum - 1]));
   18425              : 
   18426          172 :     tag = psprintf("%s %s", tbinfo->dobj.name, tbinfo->attnames[adnum - 1]);
   18427              : 
   18428          172 :     if (adinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   18429          172 :         ArchiveEntry(fout, adinfo->dobj.catId, adinfo->dobj.dumpId,
   18430          172 :                      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          172 :     free(tag);
   18439          172 :     destroyPQExpBuffer(q);
   18440          172 :     destroyPQExpBuffer(delq);
   18441          172 :     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         2288 : getAttrName(int attrnum, const TableInfo *tblInfo)
   18453              : {
   18454         2288 :     if (attrnum > 0 && attrnum <= tblInfo->numatts)
   18455         2288 :         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         2817 : dumpIndex(Archive *fout, const IndxInfo *indxinfo)
   18482              : {
   18483         2817 :     DumpOptions *dopt = fout->dopt;
   18484         2817 :     TableInfo  *tbinfo = indxinfo->indextable;
   18485         2817 :     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         2817 :     if (!dopt->dumpSchema)
   18493          128 :         return;
   18494              : 
   18495         2689 :     q = createPQExpBuffer();
   18496         2689 :     delq = createPQExpBuffer();
   18497              : 
   18498         2689 :     qindxname = pg_strdup(fmtId(indxinfo->dobj.name));
   18499         2689 :     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         2689 :     if (!is_constraint)
   18509              :     {
   18510         1062 :         char       *indstatcols = indxinfo->indstatcols;
   18511         1062 :         char       *indstatvals = indxinfo->indstatvals;
   18512         1062 :         char      **indstatcolsarray = NULL;
   18513         1062 :         char      **indstatvalsarray = NULL;
   18514         1062 :         int         nstatcols = 0;
   18515         1062 :         int         nstatvals = 0;
   18516              : 
   18517         1062 :         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         1062 :         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         1062 :         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         1062 :         if (strlen(indstatcols) != 0 || strlen(indstatvals) != 0)
   18545              :         {
   18546              :             int         j;
   18547              : 
   18548           34 :             if (!parsePGArray(indstatcols, &indstatcolsarray, &nstatcols))
   18549            0 :                 pg_fatal("could not parse index statistic columns");
   18550           34 :             if (!parsePGArray(indstatvals, &indstatvalsarray, &nstatvals))
   18551            0 :                 pg_fatal("could not parse index statistic values");
   18552           34 :             if (nstatcols != nstatvals)
   18553            0 :                 pg_fatal("mismatched number of columns and values for index statistics");
   18554              : 
   18555          102 :             for (j = 0; j < nstatcols; j++)
   18556              :             {
   18557           68 :                 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           68 :                 appendPQExpBuffer(q, "ALTER COLUMN %s ",
   18564           68 :                                   indstatcolsarray[j]);
   18565           68 :                 appendPQExpBuffer(q, "SET STATISTICS %s;\n",
   18566           68 :                                   indstatvalsarray[j]);
   18567              :             }
   18568              :         }
   18569              : 
   18570              :         /* Indexes can depend on extensions */
   18571         1062 :         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         1062 :         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         1062 :         if (indxinfo->parentidx == 0)
   18595          872 :             appendPQExpBuffer(delq, "DROP INDEX %s;\n", qqindxname);
   18596              : 
   18597         1062 :         if (indxinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   18598         1062 :             ArchiveEntry(fout, indxinfo->dobj.catId, indxinfo->dobj.dumpId,
   18599         1062 :                          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         1062 :         free(indstatcolsarray);
   18609         1062 :         free(indstatvalsarray);
   18610              :     }
   18611              : 
   18612              :     /* Dump Index Comments */
   18613         2689 :     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         2689 :     destroyPQExpBuffer(q);
   18622         2689 :     destroyPQExpBuffer(delq);
   18623         2689 :     free(qindxname);
   18624         2689 :     free(qqindxname);
   18625              : }
   18626              : 
   18627              : /*
   18628              :  * dumpIndexAttach
   18629              :  *    write out to fout a partitioned-index attachment clause
   18630              :  */
   18631              : static void
   18632          610 : dumpIndexAttach(Archive *fout, const IndexAttachInfo *attachinfo)
   18633              : {
   18634              :     /* Do nothing if not dumping schema */
   18635          610 :     if (!fout->dopt->dumpSchema)
   18636           48 :         return;
   18637              : 
   18638          562 :     if (attachinfo->partitionIdx->dobj.dump & DUMP_COMPONENT_DEFINITION)
   18639              :     {
   18640          562 :         PQExpBuffer q = createPQExpBuffer();
   18641              : 
   18642          562 :         appendPQExpBuffer(q, "ALTER INDEX %s ",
   18643          562 :                           fmtQualifiedDumpable(attachinfo->parentIdx));
   18644          562 :         appendPQExpBuffer(q, "ATTACH PARTITION %s;\n",
   18645          562 :                           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          562 :         ArchiveEntry(fout, attachinfo->dobj.catId, attachinfo->dobj.dumpId,
   18659          562 :                      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          562 :         destroyPQExpBuffer(q);
   18667              :     }
   18668              : }
   18669              : 
   18670              : /*
   18671              :  * dumpStatisticsExt
   18672              :  *    write out to fout an extended statistics object
   18673              :  */
   18674              : static void
   18675          183 : dumpStatisticsExt(Archive *fout, const StatsExtInfo *statsextinfo)
   18676              : {
   18677          183 :     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          183 :     if (!dopt->dumpSchema)
   18687           28 :         return;
   18688              : 
   18689          155 :     q = createPQExpBuffer();
   18690          155 :     delq = createPQExpBuffer();
   18691          155 :     query = createPQExpBuffer();
   18692              : 
   18693          155 :     qstatsextname = pg_strdup(fmtId(statsextinfo->dobj.name));
   18694              : 
   18695          155 :     appendPQExpBuffer(query, "SELECT "
   18696              :                       "pg_catalog.pg_get_statisticsobjdef('%u'::pg_catalog.oid)",
   18697          155 :                       statsextinfo->dobj.catId.oid);
   18698              : 
   18699          155 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   18700              : 
   18701          155 :     stxdef = PQgetvalue(res, 0, 0);
   18702              : 
   18703              :     /* Result of pg_get_statisticsobjdef is complete except for semicolon */
   18704          155 :     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          155 :     if (statsextinfo->stattarget >= 0)
   18711              :     {
   18712           34 :         appendPQExpBuffer(q, "ALTER STATISTICS %s ",
   18713           34 :                           fmtQualifiedDumpable(statsextinfo));
   18714           34 :         appendPQExpBuffer(q, "SET STATISTICS %d;\n",
   18715           34 :                           statsextinfo->stattarget);
   18716              :     }
   18717              : 
   18718          155 :     appendPQExpBuffer(delq, "DROP STATISTICS %s;\n",
   18719          155 :                       fmtQualifiedDumpable(statsextinfo));
   18720              : 
   18721          155 :     if (statsextinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   18722          155 :         ArchiveEntry(fout, statsextinfo->dobj.catId,
   18723          155 :                      statsextinfo->dobj.dumpId,
   18724          155 :                      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          155 :     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          155 :     PQclear(res);
   18741          155 :     destroyPQExpBuffer(q);
   18742          155 :     destroyPQExpBuffer(delq);
   18743          155 :     destroyPQExpBuffer(query);
   18744          155 :     free(qstatsextname);
   18745              : }
   18746              : 
   18747              : /*
   18748              :  * dumpStatisticsExtStats
   18749              :  *    write out to fout the stats for an extended statistics object
   18750              :  */
   18751              : static void
   18752          183 : dumpStatisticsExtStats(Archive *fout, const StatsExtInfo *statsextinfo)
   18753              : {
   18754          183 :     DumpOptions *dopt = fout->dopt;
   18755              :     PQExpBuffer query;
   18756              :     PGresult   *res;
   18757              :     int         nstats;
   18758              : 
   18759              :     /* Do nothing if not dumping statistics */
   18760          183 :     if (!dopt->dumpStatistics)
   18761           40 :         return;
   18762              : 
   18763          143 :     if (!fout->is_prepared[PREPQUERY_DUMPEXTSTATSOBJSTATS])
   18764              :     {
   18765           36 :         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           36 :         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           36 :         if (fout->remoteVersion >= 150000)
   18792           36 :             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           36 :         if (fout->remoteVersion >= 190000)
   18823           36 :             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           36 :         if (fout->remoteVersion >= 130000)
   18851           36 :             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           36 :         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           36 :             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           36 :             if (fout->remoteVersion >= 190000)
   18887           36 :                 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           36 :             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           36 :             if (fout->remoteVersion >= 150000)
   18899           36 :                 appendPQExpBufferStr(pq, "AND ee.inherited = e.inherited");
   18900              : 
   18901           36 :             appendPQExpBufferStr(pq, ") AS exprs ");
   18902              :         }
   18903              :         else
   18904            0 :             appendPQExpBufferStr(pq, "NULL AS exprs ");
   18905              : 
   18906              :         /* pg_stats_ext introduced in v12 */
   18907           36 :         if (fout->remoteVersion >= 120000)
   18908           36 :             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           36 :         appendPQExpBufferStr(pq, "ORDER BY inherited");
   18926              : 
   18927           36 :         ExecuteSqlStatement(fout, pq->data);
   18928              : 
   18929           36 :         fout->is_prepared[PREPQUERY_DUMPEXTSTATSOBJSTATS] = true;
   18930              : 
   18931           36 :         destroyPQExpBuffer(pq);
   18932              :     }
   18933              : 
   18934          143 :     query = createPQExpBuffer();
   18935              : 
   18936          143 :     appendPQExpBufferStr(query, "EXECUTE getExtStatsStats(");
   18937          143 :     appendStringLiteralAH(query, statsextinfo->dobj.namespace->dobj.name, fout);
   18938          143 :     appendPQExpBufferStr(query, "::pg_catalog.name, ");
   18939          143 :     appendStringLiteralAH(query, statsextinfo->dobj.name, fout);
   18940          143 :     appendPQExpBufferStr(query, "::pg_catalog.name)");
   18941              : 
   18942          143 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   18943              : 
   18944          143 :     destroyPQExpBuffer(query);
   18945              : 
   18946          143 :     nstats = PQntuples(res);
   18947              : 
   18948          143 :     if (nstats > 0)
   18949              :     {
   18950           39 :         PQExpBuffer out = createPQExpBuffer();
   18951              : 
   18952           39 :         int         i_inherited = PQfnumber(res, "inherited");
   18953           39 :         int         i_ndistinct = PQfnumber(res, "n_distinct");
   18954           39 :         int         i_dependencies = PQfnumber(res, "dependencies");
   18955           39 :         int         i_mcv = PQfnumber(res, "most_common_vals");
   18956           39 :         int         i_mcf = PQfnumber(res, "most_common_freqs");
   18957           39 :         int         i_mcbf = PQfnumber(res, "most_common_base_freqs");
   18958           39 :         int         i_exprs = PQfnumber(res, "exprs");
   18959              : 
   18960           78 :         for (int i = 0; i < nstats; i++)
   18961              :         {
   18962           39 :             TableInfo  *tbinfo = statsextinfo->stattable;
   18963              : 
   18964           39 :             if (PQgetisnull(res, i, i_inherited))
   18965            0 :                 pg_fatal("inherited cannot be NULL");
   18966              : 
   18967           39 :             appendPQExpBufferStr(out,
   18968              :                                  "SELECT * FROM pg_catalog.pg_restore_extended_stats(\n");
   18969           39 :             appendPQExpBuffer(out, "\t'version', '%d'::integer,\n",
   18970              :                               fout->remoteVersion);
   18971              : 
   18972              :             /* Relation information */
   18973           39 :             appendPQExpBufferStr(out, "\t'schemaname', ");
   18974           39 :             appendStringLiteralAH(out, tbinfo->dobj.namespace->dobj.name, fout);
   18975           39 :             appendPQExpBufferStr(out, ",\n\t'relname', ");
   18976           39 :             appendStringLiteralAH(out, tbinfo->dobj.name, fout);
   18977              : 
   18978              :             /* Extended statistics information */
   18979           39 :             appendPQExpBufferStr(out, ",\n\t'statistics_schemaname', ");
   18980           39 :             appendStringLiteralAH(out, statsextinfo->dobj.namespace->dobj.name, fout);
   18981           39 :             appendPQExpBufferStr(out, ",\n\t'statistics_name', ");
   18982           39 :             appendStringLiteralAH(out, statsextinfo->dobj.name, fout);
   18983           39 :             appendNamedArgument(out, fout, "inherited", "boolean",
   18984           39 :                                 PQgetvalue(res, i, i_inherited));
   18985              : 
   18986           39 :             if (!PQgetisnull(res, i, i_ndistinct))
   18987           35 :                 appendNamedArgument(out, fout, "n_distinct", "pg_ndistinct",
   18988           35 :                                     PQgetvalue(res, i, i_ndistinct));
   18989              : 
   18990           39 :             if (!PQgetisnull(res, i, i_dependencies))
   18991           36 :                 appendNamedArgument(out, fout, "dependencies", "pg_dependencies",
   18992           36 :                                     PQgetvalue(res, i, i_dependencies));
   18993              : 
   18994           39 :             if (!PQgetisnull(res, i, i_mcv))
   18995           38 :                 appendNamedArgument(out, fout, "most_common_vals", "text[]",
   18996           38 :                                     PQgetvalue(res, i, i_mcv));
   18997              : 
   18998           39 :             if (!PQgetisnull(res, i, i_mcf))
   18999           38 :                 appendNamedArgument(out, fout, "most_common_freqs", "double precision[]",
   19000           38 :                                     PQgetvalue(res, i, i_mcf));
   19001              : 
   19002           39 :             if (!PQgetisnull(res, i, i_mcbf))
   19003           38 :                 appendNamedArgument(out, fout, "most_common_base_freqs", "double precision[]",
   19004           38 :                                     PQgetvalue(res, i, i_mcbf));
   19005              : 
   19006           39 :             if (!PQgetisnull(res, i, i_exprs))
   19007           36 :                 appendNamedArgument(out, fout, "exprs", "jsonb",
   19008           36 :                                     PQgetvalue(res, i, i_exprs));
   19009              : 
   19010           39 :             appendPQExpBufferStr(out, "\n);\n");
   19011              :         }
   19012              : 
   19013           39 :         ArchiveEntry(fout, nilCatalogId, createDumpId(),
   19014           39 :                      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           39 :         destroyPQExpBuffer(out);
   19023              :     }
   19024          143 :     PQclear(res);
   19025              : }
   19026              : 
   19027              : /*
   19028              :  * dumpConstraint
   19029              :  *    write out to fout a user-defined constraint
   19030              :  */
   19031              : static void
   19032         2800 : dumpConstraint(Archive *fout, const ConstraintInfo *coninfo)
   19033              : {
   19034         2800 :     DumpOptions *dopt = fout->dopt;
   19035         2800 :     TableInfo  *tbinfo = coninfo->contable;
   19036              :     PQExpBuffer q;
   19037              :     PQExpBuffer delq;
   19038         2800 :     char       *tag = NULL;
   19039              :     char       *foreign;
   19040              : 
   19041              :     /* Do nothing if not dumping schema */
   19042         2800 :     if (!dopt->dumpSchema)
   19043          110 :         return;
   19044              : 
   19045         2690 :     q = createPQExpBuffer();
   19046         2690 :     delq = createPQExpBuffer();
   19047              : 
   19048         5202 :     foreign = tbinfo &&
   19049         2690 :         tbinfo->relkind == RELKIND_FOREIGN_TABLE ? "FOREIGN " : "";
   19050              : 
   19051         2690 :     if (coninfo->contype == 'p' ||
   19052         1319 :         coninfo->contype == 'u' ||
   19053         1073 :         coninfo->contype == 'x')
   19054         1627 :     {
   19055              :         /* Index-related constraint */
   19056              :         IndxInfo   *indxinfo;
   19057              :         int         k;
   19058              : 
   19059         1627 :         indxinfo = (IndxInfo *) findObjectByDumpId(coninfo->conindex);
   19060              : 
   19061         1627 :         if (indxinfo == NULL)
   19062            0 :             pg_fatal("missing index for constraint \"%s\"",
   19063              :                      coninfo->dobj.name);
   19064              : 
   19065         1627 :         if (dopt->binary_upgrade)
   19066          177 :             binary_upgrade_set_pg_class_oids(fout, q,
   19067              :                                              indxinfo->dobj.catId.oid);
   19068              : 
   19069         1627 :         appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s\n", foreign,
   19070         1627 :                           fmtQualifiedDumpable(tbinfo));
   19071         1627 :         appendPQExpBuffer(q, "    ADD CONSTRAINT %s ",
   19072         1627 :                           fmtId(coninfo->dobj.name));
   19073              : 
   19074         1627 :         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         1617 :             appendPQExpBufferStr(q,
   19082         1617 :                                  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         1617 :             if (indxinfo->indnullsnotdistinct && coninfo->contype != 'p')
   19091            0 :                 appendPQExpBufferStr(q, " NULLS NOT DISTINCT");
   19092         1617 :             appendPQExpBufferStr(q, " (");
   19093         3865 :             for (k = 0; k < indxinfo->indnkeyattrs; k++)
   19094              :             {
   19095         2248 :                 int         indkey = (int) indxinfo->indkeys[k];
   19096              :                 const char *attname;
   19097              : 
   19098         2248 :                 if (indkey == InvalidAttrNumber)
   19099            0 :                     break;
   19100         2248 :                 attname = getAttrName(indkey, tbinfo);
   19101              : 
   19102         2248 :                 appendPQExpBuffer(q, "%s%s",
   19103              :                                   (k == 0) ? "" : ", ",
   19104              :                                   fmtId(attname));
   19105              :             }
   19106         1617 :             if (coninfo->conperiod)
   19107          113 :                 appendPQExpBufferStr(q, " WITHOUT OVERLAPS");
   19108              : 
   19109         1617 :             if (indxinfo->indnkeyattrs < indxinfo->indnattrs)
   19110           20 :                 appendPQExpBufferStr(q, ") INCLUDE (");
   19111              : 
   19112         1657 :             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         1617 :             appendPQExpBufferChar(q, ')');
   19127              : 
   19128         1617 :             if (nonemptyReloptions(indxinfo->indreloptions))
   19129              :             {
   19130            0 :                 appendPQExpBufferStr(q, " WITH (");
   19131            0 :                 appendReloptionsArrayAH(q, indxinfo->indreloptions, "", fout);
   19132            0 :                 appendPQExpBufferChar(q, ')');
   19133              :             }
   19134              : 
   19135         1617 :             if (coninfo->condeferrable)
   19136              :             {
   19137           25 :                 appendPQExpBufferStr(q, " DEFERRABLE");
   19138           25 :                 if (coninfo->condeferred)
   19139           15 :                     appendPQExpBufferStr(q, " INITIALLY DEFERRED");
   19140              :             }
   19141              : 
   19142         1617 :             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         1627 :         if (indxinfo->indisclustered)
   19153              :         {
   19154           34 :             appendPQExpBuffer(q, "\nALTER TABLE %s CLUSTER",
   19155           34 :                               fmtQualifiedDumpable(tbinfo));
   19156              :             /* index name is not qualified in this syntax */
   19157           34 :             appendPQExpBuffer(q, " ON %s;\n",
   19158           34 :                               fmtId(indxinfo->dobj.name));
   19159              :         }
   19160              : 
   19161              :         /* If the index defines identity, we need to record that. */
   19162         1627 :         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         1627 :         append_depends_on_extension(fout, q, &indxinfo->dobj,
   19173              :                                     "pg_catalog.pg_class", "INDEX",
   19174         1627 :                                     fmtQualifiedDumpable(indxinfo));
   19175              : 
   19176         1627 :         appendPQExpBuffer(delq, "ALTER %sTABLE ONLY %s ", foreign,
   19177         1627 :                           fmtQualifiedDumpable(tbinfo));
   19178         1627 :         appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
   19179         1627 :                           fmtId(coninfo->dobj.name));
   19180              : 
   19181         1627 :         tag = psprintf("%s %s", tbinfo->dobj.name, coninfo->dobj.name);
   19182              : 
   19183         1627 :         if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   19184         1627 :             ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
   19185         1627 :                          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         1063 :     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          223 :         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          223 :         appendPQExpBuffer(q, "ALTER %sTABLE %s%s\n", foreign,
   19211          223 :                           only, fmtQualifiedDumpable(tbinfo));
   19212          223 :         appendPQExpBuffer(q, "    ADD CONSTRAINT %s %s;\n",
   19213          223 :                           fmtId(coninfo->dobj.name),
   19214          223 :                           coninfo->condef);
   19215              : 
   19216          223 :         appendPQExpBuffer(delq, "ALTER %sTABLE %s%s ", foreign,
   19217          223 :                           only, fmtQualifiedDumpable(tbinfo));
   19218          223 :         appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
   19219          223 :                           fmtId(coninfo->dobj.name));
   19220              : 
   19221          223 :         tag = psprintf("%s %s", tbinfo->dobj.name, coninfo->dobj.name);
   19222              : 
   19223          223 :         if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   19224          223 :             ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
   19225          223 :                          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          840 :     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          662 :         if (coninfo->separate && coninfo->conislocal)
   19239              :         {
   19240              :             const char *keyword;
   19241              : 
   19242          109 :             if (coninfo->contype == 'c')
   19243           45 :                 keyword = "CHECK CONSTRAINT";
   19244              :             else
   19245           64 :                 keyword = "CONSTRAINT";
   19246              : 
   19247              :             /* not ONLY since we want it to propagate to children */
   19248          109 :             appendPQExpBuffer(q, "ALTER %sTABLE %s\n", foreign,
   19249          109 :                               fmtQualifiedDumpable(tbinfo));
   19250          109 :             appendPQExpBuffer(q, "    ADD CONSTRAINT %s %s;\n",
   19251          109 :                               fmtId(coninfo->dobj.name),
   19252          109 :                               coninfo->condef);
   19253              : 
   19254          109 :             appendPQExpBuffer(delq, "ALTER %sTABLE %s ", foreign,
   19255          109 :                               fmtQualifiedDumpable(tbinfo));
   19256          109 :             appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
   19257          109 :                               fmtId(coninfo->dobj.name));
   19258              : 
   19259          109 :             tag = psprintf("%s %s", tbinfo->dobj.name, coninfo->dobj.name);
   19260              : 
   19261          109 :             if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   19262          109 :                 ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
   19263          109 :                              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          178 :     else if (tbinfo == NULL)
   19273              :     {
   19274              :         /* CHECK, NOT NULL constraint on a domain */
   19275          178 :         TypeInfo   *tyinfo = coninfo->condomain;
   19276              : 
   19277              :         Assert(coninfo->contype == 'c' || coninfo->contype == 'n');
   19278              : 
   19279              :         /* Ignore if not to be dumped separately */
   19280          178 :         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         2690 :     if (tbinfo && coninfo->separate &&
   19337         1989 :         coninfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   19338           49 :         dumpTableConstraintComment(fout, coninfo);
   19339              : 
   19340         2690 :     free(tag);
   19341         2690 :     destroyPQExpBuffer(q);
   19342         2690 :     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           88 : dumpTableConstraintComment(Archive *fout, const ConstraintInfo *coninfo)
   19354              : {
   19355           88 :     TableInfo  *tbinfo = coninfo->contable;
   19356           88 :     PQExpBuffer conprefix = createPQExpBuffer();
   19357              :     char       *qtabname;
   19358              : 
   19359           88 :     qtabname = pg_strdup(fmtId(tbinfo->dobj.name));
   19360              : 
   19361           88 :     appendPQExpBuffer(conprefix, "CONSTRAINT %s ON",
   19362           88 :                       fmtId(coninfo->dobj.name));
   19363              : 
   19364           88 :     if (coninfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   19365           88 :         dumpComment(fout, conprefix->data, qtabname,
   19366           88 :                     tbinfo->dobj.namespace->dobj.name,
   19367              :                     tbinfo->rolname,
   19368              :                     coninfo->dobj.catId, 0,
   19369           88 :                     coninfo->separate ? coninfo->dobj.dumpId : tbinfo->dobj.dumpId);
   19370              : 
   19371           88 :     destroyPQExpBuffer(conprefix);
   19372           88 :     free(qtabname);
   19373           88 : }
   19374              : 
   19375              : static inline SeqType
   19376          656 : parse_sequence_type(const char *name)
   19377              : {
   19378         1470 :     for (int i = 0; i < lengthof(SeqTypeNames); i++)
   19379              :     {
   19380         1470 :         if (strcmp(SeqTypeNames[i], name) == 0)
   19381          656 :             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         2991 : SequenceItemCmp(const void *p1, const void *p2)
   19393              : {
   19394         2991 :     SequenceItem v1 = *((const SequenceItem *) p1);
   19395         2991 :     SequenceItem v2 = *((const SequenceItem *) p2);
   19396              : 
   19397         2991 :     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          262 : 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          262 :     if (fout->remoteVersion < 100000)
   19421            0 :         return;
   19422          262 :     else if (fout->remoteVersion < 180000 ||
   19423          262 :              (!fout->dopt->dumpData && !fout->dopt->sequence_data))
   19424            9 :         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          253 :         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          262 :     res = ExecuteSqlQuery(fout, query, PGRES_TUPLES_OK);
   19442              : 
   19443          262 :     nsequences = PQntuples(res);
   19444          262 :     sequences = pg_malloc_array(SequenceItem, nsequences);
   19445              : 
   19446          918 :     for (int i = 0; i < nsequences; i++)
   19447              :     {
   19448          656 :         sequences[i].oid = atooid(PQgetvalue(res, i, 0));
   19449          656 :         sequences[i].seqtype = parse_sequence_type(PQgetvalue(res, i, 1));
   19450          656 :         sequences[i].startv = strtoi64(PQgetvalue(res, i, 2), NULL, 10);
   19451          656 :         sequences[i].incby = strtoi64(PQgetvalue(res, i, 3), NULL, 10);
   19452          656 :         sequences[i].maxv = strtoi64(PQgetvalue(res, i, 4), NULL, 10);
   19453          656 :         sequences[i].minv = strtoi64(PQgetvalue(res, i, 5), NULL, 10);
   19454          656 :         sequences[i].cache = strtoi64(PQgetvalue(res, i, 6), NULL, 10);
   19455          656 :         sequences[i].cycled = (strcmp(PQgetvalue(res, i, 7), "t") == 0);
   19456          656 :         sequences[i].last_value = strtoi64(PQgetvalue(res, i, 8), NULL, 10);
   19457          656 :         sequences[i].is_called = (strcmp(PQgetvalue(res, i, 9), "t") == 0);
   19458          656 :         sequences[i].null_seqtuple = (PQgetisnull(res, i, 8) || PQgetisnull(res, i, 9));
   19459              :     }
   19460              : 
   19461          262 :     PQclear(res);
   19462              : }
   19463              : 
   19464              : /*
   19465              :  * dumpSequence
   19466              :  *    write the declaration (not data) of one user-defined sequence
   19467              :  */
   19468              : static void
   19469          390 : dumpSequence(Archive *fout, const TableInfo *tbinfo)
   19470              : {
   19471          390 :     DumpOptions *dopt = fout->dopt;
   19472              :     SequenceItem *seq;
   19473              :     bool        is_ascending;
   19474              :     int64       default_minv,
   19475              :                 default_maxv;
   19476          390 :     PQExpBuffer query = createPQExpBuffer();
   19477          390 :     PQExpBuffer delqry = createPQExpBuffer();
   19478              :     char       *qseqname;
   19479          390 :     TableInfo  *owning_tab = NULL;
   19480              : 
   19481          390 :     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          390 :     if (fout->remoteVersion >= 100000)
   19489              :     {
   19490          390 :         SequenceItem key = {0};
   19491              : 
   19492              :         Assert(sequences);
   19493              : 
   19494          390 :         key.oid = tbinfo->dobj.catId.oid;
   19495          390 :         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          390 :     is_ascending = (seq->incby >= 0);
   19536          390 :     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          365 :     else if (seq->seqtype == SEQTYPE_INTEGER)
   19542              :     {
   19543          290 :         default_minv = is_ascending ? 1 : PG_INT32_MIN;
   19544          290 :         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          390 :     if (!tbinfo->is_identity_sequence)
   19561              :     {
   19562          246 :         appendPQExpBuffer(delqry, "DROP SEQUENCE %s;\n",
   19563          246 :                           fmtQualifiedDumpable(tbinfo));
   19564              :     }
   19565              : 
   19566          390 :     resetPQExpBuffer(query);
   19567              : 
   19568          390 :     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          390 :     if (tbinfo->is_identity_sequence)
   19580              :     {
   19581          144 :         owning_tab = findTableByOid(tbinfo->owning_tab);
   19582              : 
   19583          144 :         appendPQExpBuffer(query,
   19584              :                           "ALTER TABLE %s ",
   19585          144 :                           fmtQualifiedDumpable(owning_tab));
   19586          144 :         appendPQExpBuffer(query,
   19587              :                           "ALTER COLUMN %s ADD GENERATED ",
   19588          144 :                           fmtId(owning_tab->attnames[tbinfo->owning_col - 1]));
   19589          144 :         if (owning_tab->attidentity[tbinfo->owning_col - 1] == ATTRIBUTE_IDENTITY_ALWAYS)
   19590          104 :             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          144 :         appendPQExpBuffer(query, " AS IDENTITY (\n    SEQUENCE NAME %s\n",
   19594          144 :                           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          144 :         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          246 :         appendPQExpBuffer(query,
   19608              :                           "CREATE %sSEQUENCE %s\n",
   19609          246 :                           tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED ?
   19610              :                           "UNLOGGED " : "",
   19611          246 :                           fmtQualifiedDumpable(tbinfo));
   19612              : 
   19613          246 :         if (seq->seqtype != SEQTYPE_BIGINT)
   19614          186 :             appendPQExpBuffer(query, "    AS %s\n", SeqTypeNames[seq->seqtype]);
   19615              :     }
   19616              : 
   19617          390 :     appendPQExpBuffer(query, "    START WITH " INT64_FORMAT "\n", seq->startv);
   19618              : 
   19619          390 :     appendPQExpBuffer(query, "    INCREMENT BY " INT64_FORMAT "\n", seq->incby);
   19620              : 
   19621          390 :     if (seq->minv != default_minv)
   19622           15 :         appendPQExpBuffer(query, "    MINVALUE " INT64_FORMAT "\n", seq->minv);
   19623              :     else
   19624          375 :         appendPQExpBufferStr(query, "    NO MINVALUE\n");
   19625              : 
   19626          390 :     if (seq->maxv != default_maxv)
   19627           15 :         appendPQExpBuffer(query, "    MAXVALUE " INT64_FORMAT "\n", seq->maxv);
   19628              :     else
   19629          375 :         appendPQExpBufferStr(query, "    NO MAXVALUE\n");
   19630              : 
   19631          390 :     appendPQExpBuffer(query,
   19632              :                       "    CACHE " INT64_FORMAT "%s",
   19633          390 :                       seq->cache, (seq->cycled ? "\n    CYCLE" : ""));
   19634              : 
   19635          390 :     if (tbinfo->is_identity_sequence)
   19636          144 :         appendPQExpBufferStr(query, "\n);\n");
   19637              :     else
   19638          246 :         appendPQExpBufferStr(query, ";\n");
   19639              : 
   19640              :     /* binary_upgrade:  no need to clear TOAST table oid */
   19641              : 
   19642          390 :     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          390 :     if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   19648          390 :         ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
   19649          390 :                      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          390 :     if (OidIsValid(tbinfo->owning_tab) && !tbinfo->is_identity_sequence)
   19670              :     {
   19671          141 :         owning_tab = findTableByOid(tbinfo->owning_tab);
   19672              : 
   19673          141 :         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          141 :         if (owning_tab->dobj.dump & DUMP_COMPONENT_DEFINITION)
   19678              :         {
   19679          139 :             resetPQExpBuffer(query);
   19680          139 :             appendPQExpBuffer(query, "ALTER SEQUENCE %s",
   19681          139 :                               fmtQualifiedDumpable(tbinfo));
   19682          139 :             appendPQExpBuffer(query, " OWNED BY %s",
   19683          139 :                               fmtQualifiedDumpable(owning_tab));
   19684          139 :             appendPQExpBuffer(query, ".%s;\n",
   19685          139 :                               fmtId(owning_tab->attnames[tbinfo->owning_col - 1]));
   19686              : 
   19687          139 :             if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   19688          139 :                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
   19689          139 :                              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          390 :     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          390 :     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          390 :     if (fout->remoteVersion < 100000)
   19712            0 :         pg_free(seq);
   19713          390 :     destroyPQExpBuffer(query);
   19714          390 :     destroyPQExpBuffer(delqry);
   19715          390 :     free(qseqname);
   19716          390 : }
   19717              : 
   19718              : /*
   19719              :  * dumpSequenceData
   19720              :  *    write the data of one user-defined sequence
   19721              :  */
   19722              : static void
   19723          408 : dumpSequenceData(Archive *fout, const TableDataInfo *tdinfo)
   19724              : {
   19725          408 :     TableInfo  *tbinfo = tdinfo->tdtable;
   19726              :     int64       last;
   19727              :     bool        called;
   19728              :     PQExpBuffer query;
   19729              : 
   19730              :     /* needn't bother if not dumping sequence data */
   19731          408 :     if (!fout->dopt->dumpData && !fout->dopt->sequence_data)
   19732            1 :         return;
   19733              : 
   19734          407 :     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          407 :     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          407 :         SequenceItem key = {0};
   19768              :         SequenceItem *entry;
   19769              : 
   19770              :         Assert(sequences);
   19771              :         Assert(tbinfo->dobj.catId.oid);
   19772              : 
   19773          407 :         key.oid = tbinfo->dobj.catId.oid;
   19774          407 :         entry = bsearch(&key, sequences, nsequences,
   19775              :                         sizeof(SequenceItem), SequenceItemCmp);
   19776              : 
   19777          407 :         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          407 :         last = entry->last_value;
   19784          407 :         called = entry->is_called;
   19785              :     }
   19786              : 
   19787          407 :     resetPQExpBuffer(query);
   19788          407 :     appendPQExpBufferStr(query, "SELECT pg_catalog.setval(");
   19789          407 :     appendStringLiteralAH(query, fmtQualifiedDumpable(tbinfo), fout);
   19790          407 :     appendPQExpBuffer(query, ", " INT64_FORMAT ", %s);\n",
   19791              :                       last, (called ? "true" : "false"));
   19792              : 
   19793          407 :     if (tdinfo->dobj.dump & DUMP_COMPONENT_DATA)
   19794          407 :         ArchiveEntry(fout, nilCatalogId, createDumpId(),
   19795          407 :                      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          407 :     destroyPQExpBuffer(query);
   19805              : }
   19806              : 
   19807              : /*
   19808              :  * dumpTrigger
   19809              :  *    write the declaration of one user-defined table trigger
   19810              :  */
   19811              : static void
   19812          535 : dumpTrigger(Archive *fout, const TriggerInfo *tginfo)
   19813              : {
   19814          535 :     DumpOptions *dopt = fout->dopt;
   19815          535 :     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          535 :     if (!dopt->dumpSchema)
   19825           33 :         return;
   19826              : 
   19827          502 :     query = createPQExpBuffer();
   19828          502 :     delqry = createPQExpBuffer();
   19829          502 :     trigprefix = createPQExpBuffer();
   19830          502 :     trigidentity = createPQExpBuffer();
   19831              : 
   19832          502 :     qtabname = pg_strdup(fmtId(tbinfo->dobj.name));
   19833              : 
   19834          502 :     appendPQExpBuffer(trigidentity, "%s ", fmtId(tginfo->dobj.name));
   19835          502 :     appendPQExpBuffer(trigidentity, "ON %s", fmtQualifiedDumpable(tbinfo));
   19836              : 
   19837          502 :     appendPQExpBuffer(query, "%s;\n", tginfo->tgdef);
   19838          502 :     appendPQExpBuffer(delqry, "DROP TRIGGER %s;\n", trigidentity->data);
   19839              : 
   19840              :     /* Triggers can depend on extensions */
   19841          502 :     append_depends_on_extension(fout, query, &tginfo->dobj,
   19842              :                                 "pg_catalog.pg_trigger", "TRIGGER",
   19843          502 :                                 trigidentity->data);
   19844              : 
   19845          502 :     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          115 :         resetPQExpBuffer(query);
   19856          115 :         resetPQExpBuffer(delqry);
   19857          115 :         appendPQExpBuffer(query, "\nALTER %sTABLE %s ",
   19858          115 :                           tbinfo->relkind == RELKIND_FOREIGN_TABLE ? "FOREIGN " : "",
   19859          115 :                           fmtQualifiedDumpable(tbinfo));
   19860          115 :         switch (tginfo->tgenabled)
   19861              :         {
   19862           40 :             case 'f':
   19863              :             case 'D':
   19864           40 :                 appendPQExpBufferStr(query, "DISABLE");
   19865           40 :                 break;
   19866            0 :             case 't':
   19867              :             case 'O':
   19868            0 :                 appendPQExpBufferStr(query, "ENABLE");
   19869            0 :                 break;
   19870           35 :             case 'R':
   19871           35 :                 appendPQExpBufferStr(query, "ENABLE REPLICA");
   19872           35 :                 break;
   19873           40 :             case 'A':
   19874           40 :                 appendPQExpBufferStr(query, "ENABLE ALWAYS");
   19875           40 :                 break;
   19876              :         }
   19877          115 :         appendPQExpBuffer(query, " TRIGGER %s;\n",
   19878          115 :                           fmtId(tginfo->dobj.name));
   19879              :     }
   19880          387 :     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          502 :     appendPQExpBuffer(trigprefix, "TRIGGER %s ON",
   19906          502 :                       fmtId(tginfo->dobj.name));
   19907              : 
   19908          502 :     tag = psprintf("%s %s", tbinfo->dobj.name, tginfo->dobj.name);
   19909              : 
   19910          502 :     if (tginfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   19911          502 :         ArchiveEntry(fout, tginfo->dobj.catId, tginfo->dobj.dumpId,
   19912          502 :                      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          502 :     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          502 :     free(tag);
   19926          502 :     destroyPQExpBuffer(query);
   19927          502 :     destroyPQExpBuffer(delqry);
   19928          502 :     destroyPQExpBuffer(trigprefix);
   19929          502 :     destroyPQExpBuffer(trigidentity);
   19930          502 :     free(qtabname);
   19931              : }
   19932              : 
   19933              : /*
   19934              :  * dumpEventTrigger
   19935              :  *    write the declaration of one user-defined event trigger
   19936              :  */
   19937              : static void
   19938           44 : dumpEventTrigger(Archive *fout, const EventTriggerInfo *evtinfo)
   19939              : {
   19940           44 :     DumpOptions *dopt = fout->dopt;
   19941              :     PQExpBuffer query;
   19942              :     PQExpBuffer delqry;
   19943              :     char       *qevtname;
   19944              : 
   19945              :     /* Do nothing if not dumping schema */
   19946           44 :     if (!dopt->dumpSchema)
   19947            6 :         return;
   19948              : 
   19949           38 :     query = createPQExpBuffer();
   19950           38 :     delqry = createPQExpBuffer();
   19951              : 
   19952           38 :     qevtname = pg_strdup(fmtId(evtinfo->dobj.name));
   19953              : 
   19954           38 :     appendPQExpBufferStr(query, "CREATE EVENT TRIGGER ");
   19955           38 :     appendPQExpBufferStr(query, qevtname);
   19956           38 :     appendPQExpBufferStr(query, " ON ");
   19957           38 :     appendPQExpBufferStr(query, fmtId(evtinfo->evtevent));
   19958              : 
   19959           38 :     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           38 :     appendPQExpBufferStr(query, "\n   EXECUTE FUNCTION ");
   19967           38 :     appendPQExpBufferStr(query, evtinfo->evtfname);
   19968           38 :     appendPQExpBufferStr(query, "();\n");
   19969              : 
   19970           38 :     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           38 :     appendPQExpBuffer(delqry, "DROP EVENT TRIGGER %s;\n",
   19993              :                       qevtname);
   19994              : 
   19995           38 :     if (dopt->binary_upgrade)
   19996            2 :         binary_upgrade_extension_member(query, &evtinfo->dobj,
   19997              :                                         "EVENT TRIGGER", qevtname, NULL);
   19998              : 
   19999           38 :     if (evtinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   20000           38 :         ArchiveEntry(fout, evtinfo->dobj.catId, evtinfo->dobj.dumpId,
   20001           38 :                      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           38 :     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           38 :     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           38 :     destroyPQExpBuffer(query);
   20019           38 :     destroyPQExpBuffer(delqry);
   20020           38 :     free(qevtname);
   20021              : }
   20022              : 
   20023              : /*
   20024              :  * dumpRule
   20025              :  *      Dump a rule
   20026              :  */
   20027              : static void
   20028         1194 : dumpRule(Archive *fout, const RuleInfo *rinfo)
   20029              : {
   20030         1194 :     DumpOptions *dopt = fout->dopt;
   20031         1194 :     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         1194 :     if (!dopt->dumpSchema)
   20043           70 :         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         1124 :     if (!rinfo->separate)
   20050          913 :         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          263 : 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          263 :     if (numExtensions == 0)
   20209            0 :         return;
   20210              : 
   20211          263 :     query = createPQExpBuffer();
   20212              : 
   20213              :     /* refclassid constraint is redundant but may speed the search */
   20214          263 :     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          263 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   20222              : 
   20223          263 :     ntups = PQntuples(res);
   20224              : 
   20225          263 :     i_classid = PQfnumber(res, "classid");
   20226          263 :     i_objid = PQfnumber(res, "objid");
   20227          263 :     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          263 :     ext = NULL;
   20235              : 
   20236         1921 :     for (i = 0; i < ntups; i++)
   20237              :     {
   20238              :         CatalogId   objId;
   20239              :         Oid         extId;
   20240              : 
   20241         1658 :         objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
   20242         1658 :         objId.oid = atooid(PQgetvalue(res, i, i_objid));
   20243         1658 :         extId = atooid(PQgetvalue(res, i, i_refobjid));
   20244              : 
   20245         1658 :         if (ext == NULL ||
   20246         1395 :             ext->dobj.catId.oid != extId)
   20247          294 :             ext = findExtensionByOid(extId);
   20248              : 
   20249         1658 :         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         1658 :         recordExtensionMembership(objId, ext);
   20257              :     }
   20258              : 
   20259          263 :     PQclear(res);
   20260              : 
   20261          263 :     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          262 : processExtensionTables(Archive *fout, ExtensionInfo extinfo[],
   20289              :                        int numExtensions)
   20290              : {
   20291          262 :     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          262 :     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          555 :     for (i = 0; i < numExtensions; i++)
   20315              :     {
   20316          293 :         ExtensionInfo *curext = &(extinfo[i]);
   20317          293 :         char       *extconfig = curext->extconfig;
   20318          293 :         char       *extcondition = curext->extcondition;
   20319          293 :         char      **extconfigarray = NULL;
   20320          293 :         char      **extconditionarray = NULL;
   20321          293 :         int         nconfigitems = 0;
   20322          293 :         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          293 :         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          293 :         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          287 :         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          287 :         if (extconfigarray)
   20405           20 :             free(extconfigarray);
   20406          287 :         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          262 :     query = createPQExpBuffer();
   20420              : 
   20421          262 :     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          262 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   20430          262 :     ntups = PQntuples(res);
   20431              : 
   20432          262 :     i_conrelid = PQfnumber(res, "conrelid");
   20433          262 :     i_confrelid = PQfnumber(res, "confrelid");
   20434              : 
   20435              :     /* Now get the dependencies and register them */
   20436          262 :     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          262 :     PQclear(res);
   20462          262 :     destroyPQExpBuffer(query);
   20463              : }
   20464              : 
   20465              : /*
   20466              :  * getDependencies --- obtain available dependency data
   20467              :  */
   20468              : static void
   20469          262 : 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          262 :     pg_log_info("reading dependency data");
   20484              : 
   20485          262 :     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          262 :     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          262 :     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          262 :     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          262 :     if (fout->remoteVersion >= 190000)
   20530          262 :         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          262 :     appendPQExpBufferStr(query, "ORDER BY 1,2");
   20538              : 
   20539          262 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   20540              : 
   20541          262 :     ntups = PQntuples(res);
   20542              : 
   20543          262 :     i_classid = PQfnumber(res, "classid");
   20544          262 :     i_objid = PQfnumber(res, "objid");
   20545          262 :     i_refclassid = PQfnumber(res, "refclassid");
   20546          262 :     i_refobjid = PQfnumber(res, "refobjid");
   20547          262 :     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          262 :     dobj = NULL;
   20555              : 
   20556       597688 :     for (i = 0; i < ntups; i++)
   20557              :     {
   20558              :         CatalogId   objId;
   20559              :         CatalogId   refobjId;
   20560              :         char        deptype;
   20561              : 
   20562       597426 :         objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
   20563       597426 :         objId.oid = atooid(PQgetvalue(res, i, i_objid));
   20564       597426 :         refobjId.tableoid = atooid(PQgetvalue(res, i, i_refclassid));
   20565       597426 :         refobjId.oid = atooid(PQgetvalue(res, i, i_refobjid));
   20566       597426 :         deptype = *(PQgetvalue(res, i, i_deptype));
   20567              : 
   20568       597426 :         if (dobj == NULL ||
   20569       561133 :             dobj->catId.tableoid != objId.tableoid ||
   20570       558506 :             dobj->catId.oid != objId.oid)
   20571       252134 :             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       597426 :         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        37722 :             continue;
   20584              :         }
   20585              : 
   20586       561388 :         refdobj = findObjectByCatalogId(refobjId);
   20587              : 
   20588       561388 :         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         1684 :             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       559704 :         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       559704 :         if (deptype == 'i' &&
   20614       154255 :             dobj->objType == DO_TABLE &&
   20615         1304 :             refdobj->objType == DO_TYPE)
   20616          185 :             addObjectDependency(refdobj, dobj->dumpId);
   20617              :         else
   20618              :             /* normal case */
   20619       559519 :             addObjectDependency(dobj, refdobj->dumpId);
   20620              :     }
   20621              : 
   20622          262 :     PQclear(res);
   20623              : 
   20624          262 :     destroyPQExpBuffer(query);
   20625          262 : }
   20626              : 
   20627              : 
   20628              : /*
   20629              :  * createBoundaryObjects - create dummy DumpableObjects to represent
   20630              :  * dump section boundaries.
   20631              :  */
   20632              : static DumpableObject *
   20633          262 : createBoundaryObjects(void)
   20634              : {
   20635              :     DumpableObject *dobjs;
   20636              : 
   20637          262 :     dobjs = pg_malloc_array(DumpableObject, 2);
   20638              : 
   20639          262 :     dobjs[0].objType = DO_PRE_DATA_BOUNDARY;
   20640          262 :     dobjs[0].catId = nilCatalogId;
   20641          262 :     AssignDumpId(dobjs + 0);
   20642          262 :     dobjs[0].name = pg_strdup("PRE-DATA BOUNDARY");
   20643              : 
   20644          262 :     dobjs[1].objType = DO_POST_DATA_BOUNDARY;
   20645          262 :     dobjs[1].catId = nilCatalogId;
   20646          262 :     AssignDumpId(dobjs + 1);
   20647          262 :     dobjs[1].name = pg_strdup("POST-DATA BOUNDARY");
   20648              : 
   20649          262 :     return dobjs;
   20650              : }
   20651              : 
   20652              : /*
   20653              :  * addBoundaryDependencies - add dependencies as needed to enforce the dump
   20654              :  * section boundaries.
   20655              :  */
   20656              : static void
   20657          262 : addBoundaryDependencies(DumpableObject **dobjs, int numObjs,
   20658              :                         DumpableObject *boundaryObjs)
   20659              : {
   20660          262 :     DumpableObject *preDataBound = boundaryObjs + 0;
   20661          262 :     DumpableObject *postDataBound = boundaryObjs + 1;
   20662              :     int         i;
   20663              : 
   20664       987995 :     for (i = 0; i < numObjs; i++)
   20665              :     {
   20666       987733 :         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       987733 :         switch (dobj->objType)
   20673              :         {
   20674       924866 :             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       924866 :                 addObjectDependency(preDataBound, dobj->dumpId);
   20701       924866 :                 break;
   20702         5322 :             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         5322 :                 addObjectDependency(dobj, preDataBound->dumpId);
   20708         5322 :                 addObjectDependency(postDataBound, dobj->dumpId);
   20709         5322 :                 break;
   20710         6330 :             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         6330 :                 addObjectDependency(dobj, postDataBound->dumpId);
   20725         6330 :                 break;
   20726        44169 :             case DO_RULE:
   20727              :                 /* Rules are post-data, but only if dumped separately */
   20728        44169 :                 if (((RuleInfo *) dobj)->separate)
   20729          797 :                     addObjectDependency(dobj, postDataBound->dumpId);
   20730        44169 :                 break;
   20731         2844 :             case DO_CONSTRAINT:
   20732              :             case DO_FK_CONSTRAINT:
   20733              :                 /* Constraints are post-data, but only if dumped separately */
   20734         2844 :                 if (((ConstraintInfo *) dobj)->separate)
   20735         2090 :                     addObjectDependency(dobj, postDataBound->dumpId);
   20736         2844 :                 break;
   20737          262 :             case DO_PRE_DATA_BOUNDARY:
   20738              :                 /* nothing to do */
   20739          262 :                 break;
   20740          262 :             case DO_POST_DATA_BOUNDARY:
   20741              :                 /* must come after the pre-data boundary */
   20742          262 :                 addObjectDependency(dobj, preDataBound->dumpId);
   20743          262 :                 break;
   20744         3678 :             case DO_REL_STATS:
   20745              :                 /* stats section varies by parent object type, DATA or POST */
   20746         3678 :                 if (((RelStatsInfo *) dobj)->section == SECTION_DATA)
   20747              :                 {
   20748         2404 :                     addObjectDependency(dobj, preDataBound->dumpId);
   20749         2404 :                     addObjectDependency(postDataBound, dobj->dumpId);
   20750              :                 }
   20751              :                 else
   20752         1274 :                     addObjectDependency(dobj, postDataBound->dumpId);
   20753         3678 :                 break;
   20754              :         }
   20755              :     }
   20756          262 : }
   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          134 : BuildArchiveDependencies(Archive *fout)
   20784              : {
   20785          134 :     ArchiveHandle *AH = (ArchiveHandle *) fout;
   20786              :     TocEntry   *te;
   20787              : 
   20788              :     /* Scan all TOC entries in the archive */
   20789         8608 :     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         8474 :         if (te->reqs == 0)
   20798         4393 :             continue;
   20799              :         /* Ignore entries that already have "special" dependencies */
   20800         8466 :         if (te->nDeps > 0)
   20801         3591 :             continue;
   20802              :         /* Otherwise, look up the item's original DumpableObject, if any */
   20803         4875 :         dobj = findObjectByDumpId(te->dumpId);
   20804         4875 :         if (dobj == NULL)
   20805          671 :             continue;
   20806              :         /* No work if it has no dependencies */
   20807         4204 :         if (dobj->nDeps <= 0)
   20808          123 :             continue;
   20809              :         /* Set up work array */
   20810         4081 :         allocDeps = 64;
   20811         4081 :         dependencies = pg_malloc_array(DumpId, allocDeps);
   20812         4081 :         nDeps = 0;
   20813              :         /* Recursively find all dumpable dependencies */
   20814         4081 :         findDumpableDependencies(AH, dobj,
   20815              :                                  &dependencies, &nDeps, &allocDeps);
   20816              :         /* And save 'em ... */
   20817         4081 :         if (nDeps > 0)
   20818              :         {
   20819         2986 :             dependencies = pg_realloc_array(dependencies, DumpId, nDeps);
   20820         2986 :             te->dependencies = dependencies;
   20821         2986 :             te->nDeps = nDeps;
   20822              :         }
   20823              :         else
   20824         1095 :             free(dependencies);
   20825              :     }
   20826          134 : }
   20827              : 
   20828              : /* Recursive search subroutine for BuildArchiveDependencies */
   20829              : static void
   20830         9674 : 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         9674 :     if (dobj->objType == DO_PRE_DATA_BOUNDARY ||
   20840         9653 :         dobj->objType == DO_POST_DATA_BOUNDARY)
   20841         1673 :         return;
   20842              : 
   20843        19991 :     for (i = 0; i < dobj->nDeps; i++)
   20844              :     {
   20845        11990 :         DumpId      depid = dobj->dependencies[i];
   20846              : 
   20847        11990 :         if (TocIDRequired(AH, depid) != 0)
   20848              :         {
   20849              :             /* Object will be dumped, so just reference it as a dependency */
   20850         6397 :             if (*nDeps >= *allocDeps)
   20851              :             {
   20852            0 :                 *allocDeps *= 2;
   20853            0 :                 *dependencies = pg_realloc_array(*dependencies, DumpId, *allocDeps);
   20854              :             }
   20855         6397 :             (*dependencies)[*nDeps] = depid;
   20856         6397 :             (*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         5593 :             DumpableObject *otherdobj = findObjectByDumpId(depid);
   20866              : 
   20867         5593 :             if (otherdobj)
   20868         5593 :                 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         2399 : getFormattedTypeName(Archive *fout, Oid oid, OidOptions opts)
   20886              : {
   20887              :     TypeInfo   *typeInfo;
   20888              :     char       *result;
   20889              :     PQExpBuffer query;
   20890              :     PGresult   *res;
   20891              : 
   20892         2399 :     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         2399 :     typeInfo = findTypeByOid(oid);
   20902         2399 :     if (typeInfo && typeInfo->ftypname)
   20903         1908 :         return typeInfo->ftypname;
   20904              : 
   20905          491 :     query = createPQExpBuffer();
   20906          491 :     appendPQExpBuffer(query, "SELECT pg_catalog.format_type('%u'::pg_catalog.oid, NULL)",
   20907              :                       oid);
   20908              : 
   20909          491 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   20910              : 
   20911              :     /* result of format_type is already quoted */
   20912          491 :     result = pg_strdup(PQgetvalue(res, 0, 0));
   20913              : 
   20914          491 :     PQclear(res);
   20915          491 :     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          491 :     if (typeInfo)
   20924          491 :         typeInfo->ftypname = result;
   20925              : 
   20926          491 :     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         9216 : fmtCopyColumnList(const TableInfo *ti, PQExpBuffer buffer)
   20937              : {
   20938         9216 :     int         numatts = ti->numatts;
   20939         9216 :     char      **attnames = ti->attnames;
   20940         9216 :     bool       *attisdropped = ti->attisdropped;
   20941         9216 :     char       *attgenerated = ti->attgenerated;
   20942              :     bool        needComma;
   20943              :     int         i;
   20944              : 
   20945         9216 :     appendPQExpBufferChar(buffer, '(');
   20946         9216 :     needComma = false;
   20947        43572 :     for (i = 0; i < numatts; i++)
   20948              :     {
   20949        34356 :         if (attisdropped[i])
   20950          610 :             continue;
   20951        33746 :         if (attgenerated[i])
   20952         1184 :             continue;
   20953        32562 :         if (needComma)
   20954        23582 :             appendPQExpBufferStr(buffer, ", ");
   20955        32562 :         appendPQExpBufferStr(buffer, fmtId(attnames[i]));
   20956        32562 :         needComma = true;
   20957              :     }
   20958              : 
   20959         9216 :     if (!needComma)
   20960          236 :         return "";                /* no undropped columns */
   20961              : 
   20962         8980 :     appendPQExpBufferChar(buffer, ')');
   20963         8980 :     return buffer->data;
   20964              : }
   20965              : 
   20966              : /*
   20967              :  * Check if a reloptions array is nonempty.
   20968              :  */
   20969              : static bool
   20970        15006 : nonemptyReloptions(const char *reloptions)
   20971              : {
   20972              :     /* Don't want to print it if it's just "{}" */
   20973        15006 :     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          223 : appendReloptionsArrayAH(PQExpBuffer buffer, const char *reloptions,
   20983              :                         const char *prefix, Archive *fout)
   20984              : {
   20985              :     bool        res;
   20986              : 
   20987          223 :     res = appendReloptionsArray(buffer, reloptions, prefix, fout->encoding,
   20988          223 :                                 fout->std_strings);
   20989          223 :     if (!res)
   20990            0 :         pg_log_warning("could not parse %s array", "reloptions");
   20991          223 : }
   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