LCOV - code coverage report
Current view: top level - src/bin/pg_dump - pg_dump.c (source / functions) Coverage Total Hit
Test: PostgreSQL 19devel Lines: 91.0 % 8458 7697
Test Date: 2026-03-03 13:15:30 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          370 : main(int argc, char **argv)
     419              : {
     420              :     int         c;
     421          370 :     const char *filename = NULL;
     422          370 :     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          370 :     bool        g_verbose = false;
     433          370 :     const char *dumpencoding = NULL;
     434          370 :     const char *dumpsnapshot = NULL;
     435          370 :     char       *use_role = NULL;
     436          370 :     int         numWorkers = 1;
     437          370 :     int         plainText = 0;
     438          370 :     ArchiveFormat archiveFormat = archUnknown;
     439              :     ArchiveMode archiveMode;
     440          370 :     pg_compress_specification compression_spec = {0};
     441          370 :     char       *compression_detail = NULL;
     442          370 :     char       *compression_algorithm_str = "none";
     443          370 :     char       *error_detail = NULL;
     444          370 :     bool        user_compression_defined = false;
     445          370 :     DataDirSyncMethod sync_method = DATA_DIR_SYNC_METHOD_FSYNC;
     446          370 :     bool        data_only = false;
     447          370 :     bool        schema_only = false;
     448          370 :     bool        statistics_only = false;
     449          370 :     bool        with_statistics = false;
     450          370 :     bool        no_data = false;
     451          370 :     bool        no_schema = false;
     452          370 :     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          370 :     pg_logging_init(argv[0]);
     543          370 :     pg_logging_set_level(PG_LOG_WARNING);
     544          370 :     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          370 :     init_parallel_dump_utils();
     551              : 
     552          370 :     progname = get_progname(argv[0]);
     553              : 
     554          370 :     if (argc > 1)
     555              :     {
     556          370 :         if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
     557              :         {
     558            1 :             help(progname);
     559            1 :             exit_nicely(0);
     560              :         }
     561          369 :         if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
     562              :         {
     563           75 :             puts("pg_dump (PostgreSQL) " PG_VERSION);
     564           75 :             exit_nicely(0);
     565              :         }
     566              :     }
     567              : 
     568          294 :     InitDumpOptions(&dopt);
     569              : 
     570         1611 :     while ((c = getopt_long(argc, argv, "abBcCd:e:E:f:F:h:j:n:N:Op:RsS:t:T:U:vwWxXZ:",
     571         1611 :                             long_options, &optindex)) != -1)
     572              :     {
     573         1325 :         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           76 :             case 'C':           /* Create DB */
     592           76 :                 dopt.outputCreateDB = 1;
     593           76 :                 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          318 :             case 'f':
     609          318 :                 filename = pg_strdup(optarg);
     610          318 :                 break;
     611              : 
     612          174 :             case 'F':
     613          174 :                 format = pg_strdup(optarg);
     614          174 :                 break;
     615              : 
     616           36 :             case 'h':           /* server host */
     617           36 :                 dopt.cparams.pghost = pg_strdup(optarg);
     618           36 :                 break;
     619              : 
     620           11 :             case 'j':           /* number of dump jobs */
     621           11 :                 if (!option_parse_int(optarg, "-j/--jobs", 1,
     622              :                                       PG_MAX_JOBS,
     623              :                                       &numWorkers))
     624            1 :                     exit_nicely(1);
     625           10 :                 break;
     626              : 
     627           17 :             case 'n':           /* include schema(s) */
     628           17 :                 simple_string_list_append(&schema_include_patterns, optarg);
     629           17 :                 dopt.include_everything = false;
     630           17 :                 break;
     631              : 
     632            1 :             case 'N':           /* exclude schema(s) */
     633            1 :                 simple_string_list_append(&schema_exclude_patterns, optarg);
     634            1 :                 break;
     635              : 
     636            2 :             case 'O':           /* Don't reconnect to match owner */
     637            2 :                 dopt.outputNoOwner = 1;
     638            2 :                 break;
     639              : 
     640           75 :             case 'p':           /* server port */
     641           75 :                 dopt.cparams.pgport = pg_strdup(optarg);
     642           75 :                 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           38 :             case 'U':
     666           38 :                 dopt.cparams.username = pg_strdup(optarg);
     667           38 :                 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          135 :             case 0:
     693              :                 /* This covers the long options. */
     694          135 :                 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          149 :             case 7:             /* no-sync */
     717          149 :                 dosync = false;
     718          149 :                 break;
     719              : 
     720            1 :             case 8:
     721            1 :                 have_extra_float_digits = true;
     722            1 :                 if (!option_parse_int(optarg, "--extra-float-digits", -15, 3,
     723              :                                       &extra_float_digits))
     724            1 :                     exit_nicely(1);
     725            0 :                 break;
     726              : 
     727            2 :             case 9:             /* inserts */
     728              : 
     729              :                 /*
     730              :                  * dump_inserts also stores --rows-per-insert, careful not to
     731              :                  * overwrite that.
     732              :                  */
     733            2 :                 if (dopt.dump_inserts == 0)
     734            2 :                     dopt.dump_inserts = DUMP_DEFAULT_ROWS_PER_INSERT;
     735            2 :                 break;
     736              : 
     737            2 :             case 10:            /* rows per insert */
     738            2 :                 if (!option_parse_int(optarg, "--rows-per-insert", 1, INT_MAX,
     739              :                                       &dopt.dump_inserts))
     740            1 :                     exit_nicely(1);
     741            1 :                 break;
     742              : 
     743            4 :             case 11:            /* include foreign data */
     744            4 :                 simple_string_list_append(&foreign_servers_include_patterns,
     745              :                                           optarg);
     746            4 :                 break;
     747              : 
     748            1 :             case 12:            /* include table(s) and their children */
     749            1 :                 simple_string_list_append(&table_include_patterns_and_children,
     750              :                                           optarg);
     751            1 :                 dopt.include_everything = false;
     752            1 :                 break;
     753              : 
     754            1 :             case 13:            /* exclude table(s) and their children */
     755            1 :                 simple_string_list_append(&table_exclude_patterns_and_children,
     756              :                                           optarg);
     757            1 :                 break;
     758              : 
     759            1 :             case 14:            /* exclude data of table(s) and children */
     760            1 :                 simple_string_list_append(&tabledata_exclude_patterns_and_children,
     761              :                                           optarg);
     762            1 :                 break;
     763              : 
     764            0 :             case 15:
     765            0 :                 if (!parse_sync_method(optarg, &sync_method))
     766            0 :                     exit_nicely(1);
     767            0 :                 break;
     768              : 
     769           26 :             case 16:            /* read object filters from file */
     770           26 :                 read_dump_filters(optarg, &dopt);
     771           22 :                 break;
     772              : 
     773            1 :             case 17:            /* exclude extension(s) */
     774            1 :                 simple_string_list_append(&extension_exclude_patterns,
     775              :                                           optarg);
     776            1 :                 break;
     777              : 
     778            4 :             case 18:
     779            4 :                 statistics_only = true;
     780            4 :                 break;
     781              : 
     782           38 :             case 19:
     783           38 :                 no_data = true;
     784           38 :                 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           90 :             case 22:
     795           90 :                 with_statistics = true;
     796           90 :                 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          286 :     if (optind < argc && dopt.cparams.dbname == NULL)
     814          250 :         dopt.cparams.dbname = argv[optind++];
     815              : 
     816              :     /* Complain if any arguments remain */
     817          286 :     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          285 :     if (dopt.column_inserts && dopt.dump_inserts == 0)
     827            1 :         dopt.dump_inserts = DUMP_DEFAULT_ROWS_PER_INSERT;
     828              : 
     829              :     /* reject conflicting "-only" options */
     830          285 :     if (data_only && schema_only)
     831            1 :         pg_fatal("options %s and %s cannot be used together",
     832              :                  "-s/--schema-only", "-a/--data-only");
     833          284 :     if (schema_only && statistics_only)
     834            1 :         pg_fatal("options %s and %s cannot be used together",
     835              :                  "-s/--schema-only", "--statistics-only");
     836          283 :     if (data_only && statistics_only)
     837            1 :         pg_fatal("options %s and %s cannot be used together",
     838              :                  "-a/--data-only", "--statistics-only");
     839              : 
     840              :     /* reject conflicting "-only" and "no-" options */
     841          282 :     if (data_only && no_data)
     842            0 :         pg_fatal("options %s and %s cannot be used together",
     843              :                  "-a/--data-only", "--no-data");
     844          282 :     if (schema_only && no_schema)
     845            0 :         pg_fatal("options %s and %s cannot be used together",
     846              :                  "-s/--schema-only", "--no-schema");
     847          282 :     if (statistics_only && no_statistics)
     848            1 :         pg_fatal("options %s and %s cannot be used together",
     849              :                  "--statistics-only", "--no-statistics");
     850              : 
     851              :     /* reject conflicting "no-" options */
     852          281 :     if (with_statistics && no_statistics)
     853            0 :         pg_fatal("options %s and %s cannot be used together",
     854              :                  "--statistics", "--no-statistics");
     855              : 
     856              :     /* reject conflicting "-only" options */
     857          281 :     if (data_only && with_statistics)
     858            0 :         pg_fatal("options %s and %s cannot be used together",
     859              :                  "-a/--data-only", "--statistics");
     860          281 :     if (schema_only && with_statistics)
     861            1 :         pg_fatal("options %s and %s cannot be used together",
     862              :                  "-s/--schema-only", "--statistics");
     863              : 
     864          280 :     if (schema_only && foreign_servers_include_patterns.head != NULL)
     865            1 :         pg_fatal("options %s and %s cannot be used together",
     866              :                  "-s/--schema-only", "--include-foreign-data");
     867              : 
     868          279 :     if (numWorkers > 1 && foreign_servers_include_patterns.head != NULL)
     869            1 :         pg_fatal("option %s is not supported with parallel backup",
     870              :                  "--include-foreign-data");
     871              : 
     872          278 :     if (data_only && dopt.outputClean)
     873            1 :         pg_fatal("options %s and %s cannot be used together",
     874              :                  "-c/--clean", "-a/--data-only");
     875              : 
     876          277 :     if (dopt.if_exists && !dopt.outputClean)
     877            1 :         pg_fatal("option %s requires option %s",
     878              :                  "--if-exists", "-c/--clean");
     879              : 
     880              :     /*
     881              :      * Set derivative flags. Ambiguous or nonsensical combinations, e.g.
     882              :      * "--schema-only --no-schema", will have already caused an error in one
     883              :      * of the checks above.
     884              :      */
     885          276 :     dopt.dumpData = ((dopt.dumpData && !schema_only && !statistics_only) ||
     886          552 :                      data_only) && !no_data;
     887          276 :     dopt.dumpSchema = ((dopt.dumpSchema && !data_only && !statistics_only) ||
     888          552 :                        schema_only) && !no_schema;
     889          276 :     dopt.dumpStatistics = ((dopt.dumpStatistics && !schema_only && !data_only) ||
     890          552 :                            (statistics_only || with_statistics)) && !no_statistics;
     891              : 
     892              : 
     893              :     /*
     894              :      * --inserts are already implied above if --column-inserts or
     895              :      * --rows-per-insert were specified.
     896              :      */
     897          276 :     if (dopt.do_nothing && dopt.dump_inserts == 0)
     898            1 :         pg_fatal("option %s requires option %s, %s, or %s",
     899              :                  "--on-conflict-do-nothing",
     900              :                  "--inserts", "--rows-per-insert", "--column-inserts");
     901              : 
     902              :     /* Identify archive format to emit */
     903          275 :     archiveFormat = parseArchiveFormat(format, &archiveMode);
     904              : 
     905              :     /* archiveFormat specific setup */
     906          274 :     if (archiveFormat == archNull)
     907              :     {
     908          152 :         plainText = 1;
     909              : 
     910              :         /*
     911              :          * If you don't provide a restrict key, one will be appointed for you.
     912              :          */
     913          152 :         if (!dopt.restrict_key)
     914          126 :             dopt.restrict_key = generate_restrict_key();
     915          152 :         if (!dopt.restrict_key)
     916            0 :             pg_fatal("could not generate restrict key");
     917          152 :         if (!valid_restrict_key(dopt.restrict_key))
     918            0 :             pg_fatal("invalid restrict key");
     919              :     }
     920          122 :     else if (dopt.restrict_key)
     921            0 :         pg_fatal("option %s can only be used with %s",
     922              :                  "--restrict-key", "--format=plain");
     923              : 
     924              :     /*
     925              :      * Custom and directory formats are compressed by default with gzip when
     926              :      * available, not the others.  If gzip is not available, no compression is
     927              :      * done by default.
     928              :      */
     929          274 :     if ((archiveFormat == archCustom || archiveFormat == archDirectory) &&
     930          111 :         !user_compression_defined)
     931              :     {
     932              : #ifdef HAVE_LIBZ
     933          105 :         compression_algorithm_str = "gzip";
     934              : #else
     935              :         compression_algorithm_str = "none";
     936              : #endif
     937              :     }
     938              : 
     939              :     /*
     940              :      * Compression options
     941              :      */
     942          274 :     if (!parse_compress_algorithm(compression_algorithm_str,
     943              :                                   &compression_algorithm))
     944            1 :         pg_fatal("unrecognized compression algorithm: \"%s\"",
     945              :                  compression_algorithm_str);
     946              : 
     947          273 :     parse_compress_specification(compression_algorithm, compression_detail,
     948              :                                  &compression_spec);
     949          273 :     error_detail = validate_compress_specification(&compression_spec);
     950          273 :     if (error_detail != NULL)
     951            3 :         pg_fatal("invalid compression specification: %s",
     952              :                  error_detail);
     953              : 
     954          270 :     error_detail = supports_compression(compression_spec);
     955          270 :     if (error_detail != NULL)
     956            0 :         pg_fatal("%s", error_detail);
     957              : 
     958              :     /*
     959              :      * Disable support for zstd workers for now - these are based on
     960              :      * threading, and it's unclear how it interacts with parallel dumps on
     961              :      * platforms where that relies on threads too (e.g. Windows).
     962              :      */
     963          270 :     if (compression_spec.options & PG_COMPRESSION_OPTION_WORKERS)
     964            0 :         pg_log_warning("compression option \"%s\" is not currently supported by pg_dump",
     965              :                        "workers");
     966              : 
     967              :     /*
     968              :      * If emitting an archive format, we always want to emit a DATABASE item,
     969              :      * in case --create is specified at pg_restore time.
     970              :      */
     971          270 :     if (!plainText)
     972          122 :         dopt.outputCreateDB = 1;
     973              : 
     974              :     /* Parallel backup only in the directory archive format so far */
     975          270 :     if (archiveFormat != archDirectory && numWorkers > 1)
     976            1 :         pg_fatal("parallel backup only supported by the directory format");
     977              : 
     978              :     /* Open the output file */
     979          269 :     fout = CreateArchive(filename, archiveFormat, compression_spec,
     980              :                          dosync, archiveMode, setupDumpWorker, sync_method);
     981              : 
     982              :     /* Make dump options accessible right away */
     983          268 :     SetArchiveOptions(fout, &dopt, NULL);
     984              : 
     985              :     /* Register the cleanup hook */
     986          268 :     on_exit_close_archive(fout);
     987              : 
     988              :     /* Let the archiver know how noisy to be */
     989          268 :     fout->verbose = g_verbose;
     990              : 
     991              : 
     992              :     /*
     993              :      * We allow the server to be back to 9.2, and up to any minor release of
     994              :      * our own major version.  (See also version check in pg_dumpall.c.)
     995              :      */
     996          268 :     fout->minRemoteVersion = 90200;
     997          268 :     fout->maxRemoteVersion = (PG_VERSION_NUM / 100) * 100 + 99;
     998              : 
     999          268 :     fout->numWorkers = numWorkers;
    1000              : 
    1001              :     /*
    1002              :      * Open the database using the Archiver, so it knows about it. Errors mean
    1003              :      * death.
    1004              :      */
    1005          268 :     ConnectDatabaseAhx(fout, &dopt.cparams, false);
    1006          266 :     setup_connection(fout, dumpencoding, dumpsnapshot, use_role);
    1007              : 
    1008              :     /*
    1009              :      * On hot standbys, never try to dump unlogged table data, since it will
    1010              :      * just throw an error.
    1011              :      */
    1012          266 :     if (fout->isStandby)
    1013            4 :         dopt.no_unlogged_table_data = true;
    1014              : 
    1015              :     /*
    1016              :      * Find the last built-in OID, if needed (prior to 8.1)
    1017              :      *
    1018              :      * With 8.1 and above, we can just use FirstNormalObjectId - 1.
    1019              :      */
    1020          266 :     g_last_builtin_oid = FirstNormalObjectId - 1;
    1021              : 
    1022          266 :     pg_log_info("last built-in OID is %u", g_last_builtin_oid);
    1023              : 
    1024              :     /* Expand schema selection patterns into OID lists */
    1025          266 :     if (schema_include_patterns.head != NULL)
    1026              :     {
    1027           18 :         expand_schema_name_patterns(fout, &schema_include_patterns,
    1028              :                                     &schema_include_oids,
    1029              :                                     strict_names);
    1030           12 :         if (schema_include_oids.head == NULL)
    1031            1 :             pg_fatal("no matching schemas were found");
    1032              :     }
    1033          259 :     expand_schema_name_patterns(fout, &schema_exclude_patterns,
    1034              :                                 &schema_exclude_oids,
    1035              :                                 false);
    1036              :     /* non-matching exclusion patterns aren't an error */
    1037              : 
    1038              :     /* Expand table selection patterns into OID lists */
    1039          259 :     expand_table_name_patterns(fout, &table_include_patterns,
    1040              :                                &table_include_oids,
    1041              :                                strict_names, false);
    1042          254 :     expand_table_name_patterns(fout, &table_include_patterns_and_children,
    1043              :                                &table_include_oids,
    1044              :                                strict_names, true);
    1045          254 :     if ((table_include_patterns.head != NULL ||
    1046          243 :          table_include_patterns_and_children.head != NULL) &&
    1047           13 :         table_include_oids.head == NULL)
    1048            2 :         pg_fatal("no matching tables were found");
    1049              : 
    1050          252 :     expand_table_name_patterns(fout, &table_exclude_patterns,
    1051              :                                &table_exclude_oids,
    1052              :                                false, false);
    1053          252 :     expand_table_name_patterns(fout, &table_exclude_patterns_and_children,
    1054              :                                &table_exclude_oids,
    1055              :                                false, true);
    1056              : 
    1057          252 :     expand_table_name_patterns(fout, &tabledata_exclude_patterns,
    1058              :                                &tabledata_exclude_oids,
    1059              :                                false, false);
    1060          252 :     expand_table_name_patterns(fout, &tabledata_exclude_patterns_and_children,
    1061              :                                &tabledata_exclude_oids,
    1062              :                                false, true);
    1063              : 
    1064          252 :     expand_foreign_server_name_patterns(fout, &foreign_servers_include_patterns,
    1065              :                                         &foreign_servers_include_oids);
    1066              : 
    1067              :     /* non-matching exclusion patterns aren't an error */
    1068              : 
    1069              :     /* Expand extension selection patterns into OID lists */
    1070          251 :     if (extension_include_patterns.head != NULL)
    1071              :     {
    1072            5 :         expand_extension_name_patterns(fout, &extension_include_patterns,
    1073              :                                        &extension_include_oids,
    1074              :                                        strict_names);
    1075            5 :         if (extension_include_oids.head == NULL)
    1076            1 :             pg_fatal("no matching extensions were found");
    1077              :     }
    1078          250 :     expand_extension_name_patterns(fout, &extension_exclude_patterns,
    1079              :                                    &extension_exclude_oids,
    1080              :                                    false);
    1081              :     /* non-matching exclusion patterns aren't an error */
    1082              : 
    1083              :     /*
    1084              :      * Dumping LOs is the default for dumps where an inclusion switch is not
    1085              :      * used (an "include everything" dump).  -B can be used to exclude LOs
    1086              :      * from those dumps.  -b can be used to include LOs even when an inclusion
    1087              :      * switch is used.
    1088              :      *
    1089              :      * -s means "schema only" and LOs are data, not schema, so we never
    1090              :      * include LOs when -s is used.
    1091              :      */
    1092          250 :     if (dopt.include_everything && dopt.dumpData && !dopt.dontOutputLOs)
    1093          183 :         dopt.outputLOs = true;
    1094              : 
    1095              :     /*
    1096              :      * Collect role names so we can map object owner OIDs to names.
    1097              :      */
    1098          250 :     collectRoleNames(fout);
    1099              : 
    1100              :     /*
    1101              :      * Now scan the database and create DumpableObject structs for all the
    1102              :      * objects we intend to dump.
    1103              :      */
    1104          250 :     tblinfo = getSchemaData(fout, &numTables);
    1105              : 
    1106          249 :     if (dopt.dumpData)
    1107              :     {
    1108          207 :         getTableData(&dopt, tblinfo, numTables, 0);
    1109          207 :         buildMatViewRefreshDependencies(fout);
    1110          207 :         if (!dopt.dumpSchema)
    1111            7 :             getTableDataFKConstraints();
    1112              :     }
    1113              : 
    1114          249 :     if (!dopt.dumpData && dopt.sequence_data)
    1115           34 :         getTableData(&dopt, tblinfo, numTables, RELKIND_SEQUENCE);
    1116              : 
    1117              :     /*
    1118              :      * For binary upgrade mode, dump the pg_shdepend rows for large objects
    1119              :      * and maybe even pg_largeobject_metadata (see comment below for details).
    1120              :      * This is faster to restore than the equivalent set of large object
    1121              :      * commands.
    1122              :      */
    1123          249 :     if (dopt.binary_upgrade)
    1124              :     {
    1125              :         TableInfo  *shdepend;
    1126              : 
    1127           38 :         shdepend = findTableByOid(SharedDependRelationId);
    1128           38 :         makeTableDataInfo(&dopt, shdepend);
    1129              : 
    1130              :         /*
    1131              :          * Only dump large object shdepend rows for this database.
    1132              :          */
    1133           38 :         shdepend->dataObj->filtercond = "WHERE classid = 'pg_largeobject'::regclass "
    1134              :             "AND dbid = (SELECT oid FROM pg_database "
    1135              :             "            WHERE datname = current_database())";
    1136              : 
    1137              :         /*
    1138              :          * For binary upgrades from v16 and newer versions, we can copy
    1139              :          * pg_largeobject_metadata's files from the old cluster, so we don't
    1140              :          * need to dump its contents.  pg_upgrade can't copy/link the files
    1141              :          * from older versions because aclitem (needed by
    1142              :          * pg_largeobject_metadata.lomacl) changed its storage format in v16.
    1143              :          */
    1144           38 :         if (fout->remoteVersion < 160000)
    1145              :         {
    1146              :             TableInfo  *lo_metadata;
    1147              : 
    1148            0 :             lo_metadata = findTableByOid(LargeObjectMetadataRelationId);
    1149            0 :             makeTableDataInfo(&dopt, lo_metadata);
    1150              :         }
    1151              :     }
    1152              : 
    1153              :     /*
    1154              :      * In binary-upgrade mode, we do not have to worry about the actual LO
    1155              :      * data or the associated metadata that resides in the pg_largeobject and
    1156              :      * pg_largeobject_metadata tables, respectively.
    1157              :      *
    1158              :      * However, we do need to collect LO information as there may be comments
    1159              :      * or other information on LOs that we do need to dump out.
    1160              :      */
    1161          249 :     if (dopt.outputLOs || dopt.binary_upgrade)
    1162          221 :         getLOs(fout);
    1163              : 
    1164              :     /*
    1165              :      * Collect dependency data to assist in ordering the objects.
    1166              :      */
    1167          249 :     getDependencies(fout);
    1168              : 
    1169              :     /*
    1170              :      * Collect ACLs, comments, and security labels, if wanted.
    1171              :      */
    1172          249 :     if (!dopt.aclsSkip)
    1173          247 :         getAdditionalACLs(fout);
    1174          249 :     if (!dopt.no_comments)
    1175          249 :         collectComments(fout);
    1176          249 :     if (!dopt.no_security_labels)
    1177          249 :         collectSecLabels(fout);
    1178              : 
    1179              :     /* For binary upgrade mode, collect required pg_class information. */
    1180          249 :     if (dopt.binary_upgrade)
    1181           38 :         collectBinaryUpgradeClassOids(fout);
    1182              : 
    1183              :     /* Collect sequence information. */
    1184          249 :     collectSequences(fout);
    1185              : 
    1186              :     /* Lastly, create dummy objects to represent the section boundaries */
    1187          249 :     boundaryObjs = createBoundaryObjects();
    1188              : 
    1189              :     /* Get pointers to all the known DumpableObjects */
    1190          249 :     getDumpableObjects(&dobjs, &numObjs);
    1191              : 
    1192              :     /*
    1193              :      * Add dummy dependencies to enforce the dump section ordering.
    1194              :      */
    1195          249 :     addBoundaryDependencies(dobjs, numObjs, boundaryObjs);
    1196              : 
    1197              :     /*
    1198              :      * Sort the objects into a safe dump order (no forward references).
    1199              :      *
    1200              :      * We rely on dependency information to help us determine a safe order, so
    1201              :      * the initial sort is mostly for cosmetic purposes: we sort by name to
    1202              :      * ensure that logically identical schemas will dump identically.
    1203              :      */
    1204          249 :     sortDumpableObjectsByTypeName(dobjs, numObjs);
    1205              : 
    1206          249 :     sortDumpableObjects(dobjs, numObjs,
    1207          249 :                         boundaryObjs[0].dumpId, boundaryObjs[1].dumpId);
    1208              : 
    1209              :     /*
    1210              :      * Create archive TOC entries for all the objects to be dumped, in a safe
    1211              :      * order.
    1212              :      */
    1213              : 
    1214              :     /*
    1215              :      * First the special entries for ENCODING, STDSTRINGS, and SEARCHPATH.
    1216              :      */
    1217          249 :     dumpEncoding(fout);
    1218          249 :     dumpStdStrings(fout);
    1219          249 :     dumpSearchPath(fout);
    1220              : 
    1221              :     /* The database items are always next, unless we don't want them at all */
    1222          249 :     if (dopt.outputCreateDB)
    1223          150 :         dumpDatabase(fout);
    1224              : 
    1225              :     /* Now the rearrangeable objects. */
    1226       925955 :     for (i = 0; i < numObjs; i++)
    1227       925706 :         dumpDumpableObject(fout, dobjs[i]);
    1228              : 
    1229              :     /*
    1230              :      * Set up options info to ensure we dump what we want.
    1231              :      */
    1232          249 :     ropt = NewRestoreOptions();
    1233          249 :     ropt->filename = filename;
    1234              : 
    1235              :     /* if you change this list, see dumpOptionsFromRestoreOptions */
    1236          249 :     ropt->cparams.dbname = dopt.cparams.dbname ? pg_strdup(dopt.cparams.dbname) : NULL;
    1237          249 :     ropt->cparams.pgport = dopt.cparams.pgport ? pg_strdup(dopt.cparams.pgport) : NULL;
    1238          249 :     ropt->cparams.pghost = dopt.cparams.pghost ? pg_strdup(dopt.cparams.pghost) : NULL;
    1239          249 :     ropt->cparams.username = dopt.cparams.username ? pg_strdup(dopt.cparams.username) : NULL;
    1240          249 :     ropt->cparams.promptPassword = dopt.cparams.promptPassword;
    1241          249 :     ropt->dropSchema = dopt.outputClean;
    1242          249 :     ropt->dumpData = dopt.dumpData;
    1243          249 :     ropt->dumpSchema = dopt.dumpSchema;
    1244          249 :     ropt->dumpStatistics = dopt.dumpStatistics;
    1245          249 :     ropt->if_exists = dopt.if_exists;
    1246          249 :     ropt->column_inserts = dopt.column_inserts;
    1247          249 :     ropt->dumpSections = dopt.dumpSections;
    1248          249 :     ropt->aclsSkip = dopt.aclsSkip;
    1249          249 :     ropt->superuser = dopt.outputSuperuser;
    1250          249 :     ropt->createDB = dopt.outputCreateDB;
    1251          249 :     ropt->noOwner = dopt.outputNoOwner;
    1252          249 :     ropt->noTableAm = dopt.outputNoTableAm;
    1253          249 :     ropt->noTablespace = dopt.outputNoTablespaces;
    1254          249 :     ropt->disable_triggers = dopt.disable_triggers;
    1255          249 :     ropt->use_setsessauth = dopt.use_setsessauth;
    1256          249 :     ropt->disable_dollar_quoting = dopt.disable_dollar_quoting;
    1257          249 :     ropt->dump_inserts = dopt.dump_inserts;
    1258          249 :     ropt->no_comments = dopt.no_comments;
    1259          249 :     ropt->no_policies = dopt.no_policies;
    1260          249 :     ropt->no_publications = dopt.no_publications;
    1261          249 :     ropt->no_security_labels = dopt.no_security_labels;
    1262          249 :     ropt->no_subscriptions = dopt.no_subscriptions;
    1263          249 :     ropt->lockWaitTimeout = dopt.lockWaitTimeout;
    1264          249 :     ropt->include_everything = dopt.include_everything;
    1265          249 :     ropt->enable_row_security = dopt.enable_row_security;
    1266          249 :     ropt->sequence_data = dopt.sequence_data;
    1267          249 :     ropt->binary_upgrade = dopt.binary_upgrade;
    1268          249 :     ropt->restrict_key = dopt.restrict_key ? pg_strdup(dopt.restrict_key) : NULL;
    1269              : 
    1270          249 :     ropt->compression_spec = compression_spec;
    1271              : 
    1272          249 :     ropt->suppressDumpWarnings = true;   /* We've already shown them */
    1273              : 
    1274          249 :     SetArchiveOptions(fout, &dopt, ropt);
    1275              : 
    1276              :     /* Mark which entries should be output */
    1277          249 :     ProcessArchiveRestoreOptions(fout);
    1278              : 
    1279              :     /*
    1280              :      * The archive's TOC entries are now marked as to which ones will actually
    1281              :      * be output, so we can set up their dependency lists properly. This isn't
    1282              :      * necessary for plain-text output, though.
    1283              :      */
    1284          249 :     if (!plainText)
    1285          121 :         BuildArchiveDependencies(fout);
    1286              : 
    1287              :     /*
    1288              :      * And finally we can do the actual output.
    1289              :      *
    1290              :      * Note: for non-plain-text output formats, the output file is written
    1291              :      * inside CloseArchive().  This is, um, bizarre; but not worth changing
    1292              :      * right now.
    1293              :      */
    1294          249 :     if (plainText)
    1295          128 :         RestoreArchive(fout, false);
    1296              : 
    1297          248 :     CloseArchive(fout);
    1298              : 
    1299          248 :     exit_nicely(0);
    1300              : }
    1301              : 
    1302              : 
    1303              : static void
    1304            1 : help(const char *progname)
    1305              : {
    1306            1 :     printf(_("%s exports a PostgreSQL database as an SQL script or to other formats.\n\n"), progname);
    1307            1 :     printf(_("Usage:\n"));
    1308            1 :     printf(_("  %s [OPTION]... [DBNAME]\n"), progname);
    1309              : 
    1310            1 :     printf(_("\nGeneral options:\n"));
    1311            1 :     printf(_("  -f, --file=FILENAME          output file or directory name\n"));
    1312            1 :     printf(_("  -F, --format=c|d|t|p         output file format (custom, directory, tar,\n"
    1313              :              "                               plain text (default))\n"));
    1314            1 :     printf(_("  -j, --jobs=NUM               use this many parallel jobs to dump\n"));
    1315            1 :     printf(_("  -v, --verbose                verbose mode\n"));
    1316            1 :     printf(_("  -V, --version                output version information, then exit\n"));
    1317            1 :     printf(_("  -Z, --compress=METHOD[:DETAIL]\n"
    1318              :              "                               compress as specified\n"));
    1319            1 :     printf(_("  --lock-wait-timeout=TIMEOUT  fail after waiting TIMEOUT for a table lock\n"));
    1320            1 :     printf(_("  --no-sync                    do not wait for changes to be written safely to disk\n"));
    1321            1 :     printf(_("  --sync-method=METHOD         set method for syncing files to disk\n"));
    1322            1 :     printf(_("  -?, --help                   show this help, then exit\n"));
    1323              : 
    1324            1 :     printf(_("\nOptions controlling the output content:\n"));
    1325            1 :     printf(_("  -a, --data-only              dump only the data, not the schema or statistics\n"));
    1326            1 :     printf(_("  -b, --large-objects          include large objects in dump\n"));
    1327            1 :     printf(_("  --blobs                      (same as --large-objects, deprecated)\n"));
    1328            1 :     printf(_("  -B, --no-large-objects       exclude large objects in dump\n"));
    1329            1 :     printf(_("  --no-blobs                   (same as --no-large-objects, deprecated)\n"));
    1330            1 :     printf(_("  -c, --clean                  clean (drop) database objects before recreating\n"));
    1331            1 :     printf(_("  -C, --create                 include commands to create database in dump\n"));
    1332            1 :     printf(_("  -e, --extension=PATTERN      dump the specified extension(s) only\n"));
    1333            1 :     printf(_("  -E, --encoding=ENCODING      dump the data in encoding ENCODING\n"));
    1334            1 :     printf(_("  -n, --schema=PATTERN         dump the specified schema(s) only\n"));
    1335            1 :     printf(_("  -N, --exclude-schema=PATTERN do NOT dump the specified schema(s)\n"));
    1336            1 :     printf(_("  -O, --no-owner               skip restoration of object ownership in\n"
    1337              :              "                               plain-text format\n"));
    1338            1 :     printf(_("  -s, --schema-only            dump only the schema, no data or statistics\n"));
    1339            1 :     printf(_("  -S, --superuser=NAME         superuser user name to use in plain-text format\n"));
    1340            1 :     printf(_("  -t, --table=PATTERN          dump only the specified table(s)\n"));
    1341            1 :     printf(_("  -T, --exclude-table=PATTERN  do NOT dump the specified table(s)\n"));
    1342            1 :     printf(_("  -x, --no-privileges          do not dump privileges (grant/revoke)\n"));
    1343            1 :     printf(_("  --binary-upgrade             for use by upgrade utilities only\n"));
    1344            1 :     printf(_("  --column-inserts             dump data as INSERT commands with column names\n"));
    1345            1 :     printf(_("  --disable-dollar-quoting     disable dollar quoting, use SQL standard quoting\n"));
    1346            1 :     printf(_("  --disable-triggers           disable triggers during data-only restore\n"));
    1347            1 :     printf(_("  --enable-row-security        enable row security (dump only content user has\n"
    1348              :              "                               access to)\n"));
    1349            1 :     printf(_("  --exclude-extension=PATTERN  do NOT dump the specified extension(s)\n"));
    1350            1 :     printf(_("  --exclude-table-and-children=PATTERN\n"
    1351              :              "                               do NOT dump the specified table(s), including\n"
    1352              :              "                               child and partition tables\n"));
    1353            1 :     printf(_("  --exclude-table-data=PATTERN do NOT dump data for the specified table(s)\n"));
    1354            1 :     printf(_("  --exclude-table-data-and-children=PATTERN\n"
    1355              :              "                               do NOT dump data for the specified table(s),\n"
    1356              :              "                               including child and partition tables\n"));
    1357            1 :     printf(_("  --extra-float-digits=NUM     override default setting for extra_float_digits\n"));
    1358            1 :     printf(_("  --filter=FILENAME            include or exclude objects and data from dump\n"
    1359              :              "                               based on expressions in FILENAME\n"));
    1360            1 :     printf(_("  --if-exists                  use IF EXISTS when dropping objects\n"));
    1361            1 :     printf(_("  --include-foreign-data=PATTERN\n"
    1362              :              "                               include data of foreign tables on foreign\n"
    1363              :              "                               servers matching PATTERN\n"));
    1364            1 :     printf(_("  --inserts                    dump data as INSERT commands, rather than COPY\n"));
    1365            1 :     printf(_("  --load-via-partition-root    load partitions via the root table\n"));
    1366            1 :     printf(_("  --no-comments                do not dump comment commands\n"));
    1367            1 :     printf(_("  --no-data                    do not dump data\n"));
    1368            1 :     printf(_("  --no-policies                do not dump row security policies\n"));
    1369            1 :     printf(_("  --no-publications            do not dump publications\n"));
    1370            1 :     printf(_("  --no-schema                  do not dump schema\n"));
    1371            1 :     printf(_("  --no-security-labels         do not dump security label assignments\n"));
    1372            1 :     printf(_("  --no-statistics              do not dump statistics\n"));
    1373            1 :     printf(_("  --no-subscriptions           do not dump subscriptions\n"));
    1374            1 :     printf(_("  --no-table-access-method     do not dump table access methods\n"));
    1375            1 :     printf(_("  --no-tablespaces             do not dump tablespace assignments\n"));
    1376            1 :     printf(_("  --no-toast-compression       do not dump TOAST compression methods\n"));
    1377            1 :     printf(_("  --no-unlogged-table-data     do not dump unlogged table data\n"));
    1378            1 :     printf(_("  --on-conflict-do-nothing     add ON CONFLICT DO NOTHING to INSERT commands\n"));
    1379            1 :     printf(_("  --quote-all-identifiers      quote all identifiers, even if not key words\n"));
    1380            1 :     printf(_("  --restrict-key=RESTRICT_KEY  use provided string as psql \\restrict key\n"));
    1381            1 :     printf(_("  --rows-per-insert=NROWS      number of rows per INSERT; implies --inserts\n"));
    1382            1 :     printf(_("  --section=SECTION            dump named section (pre-data, data, or post-data)\n"));
    1383            1 :     printf(_("  --sequence-data              include sequence data in dump\n"));
    1384            1 :     printf(_("  --serializable-deferrable    wait until the dump can run without anomalies\n"));
    1385            1 :     printf(_("  --snapshot=SNAPSHOT          use given snapshot for the dump\n"));
    1386            1 :     printf(_("  --statistics                 dump the statistics\n"));
    1387            1 :     printf(_("  --statistics-only            dump only the statistics, not schema or data\n"));
    1388            1 :     printf(_("  --strict-names               require table and/or schema include patterns to\n"
    1389              :              "                               match at least one entity each\n"));
    1390            1 :     printf(_("  --table-and-children=PATTERN dump only the specified table(s), including\n"
    1391              :              "                               child and partition tables\n"));
    1392            1 :     printf(_("  --use-set-session-authorization\n"
    1393              :              "                               use SET SESSION AUTHORIZATION commands instead of\n"
    1394              :              "                               ALTER OWNER commands to set ownership\n"));
    1395              : 
    1396            1 :     printf(_("\nConnection options:\n"));
    1397            1 :     printf(_("  -d, --dbname=DBNAME      database to dump\n"));
    1398            1 :     printf(_("  -h, --host=HOSTNAME      database server host or socket directory\n"));
    1399            1 :     printf(_("  -p, --port=PORT          database server port number\n"));
    1400            1 :     printf(_("  -U, --username=NAME      connect as specified database user\n"));
    1401            1 :     printf(_("  -w, --no-password        never prompt for password\n"));
    1402            1 :     printf(_("  -W, --password           force password prompt (should happen automatically)\n"));
    1403            1 :     printf(_("  --role=ROLENAME          do SET ROLE before dump\n"));
    1404              : 
    1405            1 :     printf(_("\nIf no database name is supplied, then the PGDATABASE environment\n"
    1406              :              "variable value is used.\n\n"));
    1407            1 :     printf(_("Report bugs to <%s>.\n"), PACKAGE_BUGREPORT);
    1408            1 :     printf(_("%s home page: <%s>\n"), PACKAGE_NAME, PACKAGE_URL);
    1409            1 : }
    1410              : 
    1411              : static void
    1412          282 : setup_connection(Archive *AH, const char *dumpencoding,
    1413              :                  const char *dumpsnapshot, char *use_role)
    1414              : {
    1415          282 :     DumpOptions *dopt = AH->dopt;
    1416          282 :     PGconn     *conn = GetConnection(AH);
    1417              : 
    1418          282 :     PQclear(ExecuteSqlQueryForSingleRow(AH, ALWAYS_SECURE_SEARCH_PATH_SQL));
    1419              : 
    1420              :     /*
    1421              :      * Set the client encoding if requested.
    1422              :      */
    1423          282 :     if (dumpencoding)
    1424              :     {
    1425           18 :         if (PQsetClientEncoding(conn, dumpencoding) < 0)
    1426            0 :             pg_fatal("invalid client encoding \"%s\" specified",
    1427              :                      dumpencoding);
    1428              :     }
    1429              : 
    1430              :     /*
    1431              :      * Force standard_conforming_strings on, just in case we are dumping from
    1432              :      * an old server that has it disabled.  Without this, literals in views,
    1433              :      * expressions, etc, would be incorrect for modern servers.
    1434              :      */
    1435          282 :     ExecuteSqlStatement(AH, "SET standard_conforming_strings = on");
    1436              : 
    1437              :     /*
    1438              :      * And reflect that to AH->std_strings.  You might think that we should
    1439              :      * just delete that variable and the code that checks it, but that would
    1440              :      * be problematic for pg_restore, which at least for now should still cope
    1441              :      * with archives containing the other setting (cf. processStdStringsEntry
    1442              :      * in pg_backup_archiver.c).
    1443              :      */
    1444          282 :     AH->std_strings = true;
    1445              : 
    1446              :     /*
    1447              :      * Get the active encoding, so we know how to escape strings.
    1448              :      */
    1449          282 :     AH->encoding = PQclientEncoding(conn);
    1450          282 :     setFmtEncoding(AH->encoding);
    1451              : 
    1452              :     /*
    1453              :      * Set the role if requested.  In a parallel dump worker, we'll be passed
    1454              :      * use_role == NULL, but AH->use_role is already set (if user specified it
    1455              :      * originally) and we should use that.
    1456              :      */
    1457          282 :     if (!use_role && AH->use_role)
    1458            2 :         use_role = AH->use_role;
    1459              : 
    1460              :     /* Set the role if requested */
    1461          282 :     if (use_role)
    1462              :     {
    1463            5 :         PQExpBuffer query = createPQExpBuffer();
    1464              : 
    1465            5 :         appendPQExpBuffer(query, "SET ROLE %s", fmtId(use_role));
    1466            5 :         ExecuteSqlStatement(AH, query->data);
    1467            5 :         destroyPQExpBuffer(query);
    1468              : 
    1469              :         /* save it for possible later use by parallel workers */
    1470            5 :         if (!AH->use_role)
    1471            3 :             AH->use_role = pg_strdup(use_role);
    1472              :     }
    1473              : 
    1474              :     /* Set the datestyle to ISO to ensure the dump's portability */
    1475          282 :     ExecuteSqlStatement(AH, "SET DATESTYLE = ISO");
    1476              : 
    1477              :     /* Likewise, avoid using sql_standard intervalstyle */
    1478          282 :     ExecuteSqlStatement(AH, "SET INTERVALSTYLE = POSTGRES");
    1479              : 
    1480              :     /*
    1481              :      * Use an explicitly specified extra_float_digits if it has been provided.
    1482              :      * Otherwise, set extra_float_digits so that we can dump float data
    1483              :      * exactly (given correctly implemented float I/O code, anyway).
    1484              :      */
    1485          282 :     if (have_extra_float_digits)
    1486              :     {
    1487            0 :         PQExpBuffer q = createPQExpBuffer();
    1488              : 
    1489            0 :         appendPQExpBuffer(q, "SET extra_float_digits TO %d",
    1490              :                           extra_float_digits);
    1491            0 :         ExecuteSqlStatement(AH, q->data);
    1492            0 :         destroyPQExpBuffer(q);
    1493              :     }
    1494              :     else
    1495          282 :         ExecuteSqlStatement(AH, "SET extra_float_digits TO 3");
    1496              : 
    1497              :     /*
    1498              :      * Disable synchronized scanning, to prevent unpredictable changes in row
    1499              :      * ordering across a dump and reload.
    1500              :      */
    1501          282 :     ExecuteSqlStatement(AH, "SET synchronize_seqscans TO off");
    1502              : 
    1503              :     /*
    1504              :      * Disable timeouts if supported.
    1505              :      */
    1506          282 :     ExecuteSqlStatement(AH, "SET statement_timeout = 0");
    1507          282 :     if (AH->remoteVersion >= 90300)
    1508          282 :         ExecuteSqlStatement(AH, "SET lock_timeout = 0");
    1509          282 :     if (AH->remoteVersion >= 90600)
    1510          282 :         ExecuteSqlStatement(AH, "SET idle_in_transaction_session_timeout = 0");
    1511          282 :     if (AH->remoteVersion >= 170000)
    1512          282 :         ExecuteSqlStatement(AH, "SET transaction_timeout = 0");
    1513              : 
    1514              :     /*
    1515              :      * Quote all identifiers, if requested.
    1516              :      */
    1517          282 :     if (quote_all_identifiers)
    1518           36 :         ExecuteSqlStatement(AH, "SET quote_all_identifiers = true");
    1519              : 
    1520              :     /*
    1521              :      * Adjust row-security mode, if supported.
    1522              :      */
    1523          282 :     if (AH->remoteVersion >= 90500)
    1524              :     {
    1525          282 :         if (dopt->enable_row_security)
    1526            0 :             ExecuteSqlStatement(AH, "SET row_security = on");
    1527              :         else
    1528          282 :             ExecuteSqlStatement(AH, "SET row_security = off");
    1529              :     }
    1530              : 
    1531              :     /*
    1532              :      * For security reasons, we restrict the expansion of non-system views and
    1533              :      * access to foreign tables during the pg_dump process. This restriction
    1534              :      * is adjusted when dumping foreign table data.
    1535              :      */
    1536          282 :     set_restrict_relation_kind(AH, "view, foreign-table");
    1537              : 
    1538              :     /*
    1539              :      * Initialize prepared-query state to "nothing prepared".  We do this here
    1540              :      * so that a parallel dump worker will have its own state.
    1541              :      */
    1542          282 :     AH->is_prepared = pg_malloc0_array(bool, NUM_PREP_QUERIES);
    1543              : 
    1544              :     /*
    1545              :      * Start transaction-snapshot mode transaction to dump consistent data.
    1546              :      */
    1547          282 :     ExecuteSqlStatement(AH, "BEGIN");
    1548              : 
    1549              :     /*
    1550              :      * To support the combination of serializable_deferrable with the jobs
    1551              :      * option we use REPEATABLE READ for the worker connections that are
    1552              :      * passed a snapshot.  As long as the snapshot is acquired in a
    1553              :      * SERIALIZABLE, READ ONLY, DEFERRABLE transaction, its use within a
    1554              :      * REPEATABLE READ transaction provides the appropriate integrity
    1555              :      * guarantees.  This is a kluge, but safe for back-patching.
    1556              :      */
    1557          282 :     if (dopt->serializable_deferrable && AH->sync_snapshot_id == NULL)
    1558            0 :         ExecuteSqlStatement(AH,
    1559              :                             "SET TRANSACTION ISOLATION LEVEL "
    1560              :                             "SERIALIZABLE, READ ONLY, DEFERRABLE");
    1561              :     else
    1562          282 :         ExecuteSqlStatement(AH,
    1563              :                             "SET TRANSACTION ISOLATION LEVEL "
    1564              :                             "REPEATABLE READ, READ ONLY");
    1565              : 
    1566              :     /*
    1567              :      * If user specified a snapshot to use, select that.  In a parallel dump
    1568              :      * worker, we'll be passed dumpsnapshot == NULL, but AH->sync_snapshot_id
    1569              :      * is already set (if the server can handle it) and we should use that.
    1570              :      */
    1571          282 :     if (dumpsnapshot)
    1572            0 :         AH->sync_snapshot_id = pg_strdup(dumpsnapshot);
    1573              : 
    1574          282 :     if (AH->sync_snapshot_id)
    1575              :     {
    1576           16 :         PQExpBuffer query = createPQExpBuffer();
    1577              : 
    1578           16 :         appendPQExpBufferStr(query, "SET TRANSACTION SNAPSHOT ");
    1579           16 :         appendStringLiteralConn(query, AH->sync_snapshot_id, conn);
    1580           16 :         ExecuteSqlStatement(AH, query->data);
    1581           16 :         destroyPQExpBuffer(query);
    1582              :     }
    1583          266 :     else if (AH->numWorkers > 1)
    1584              :     {
    1585            8 :         if (AH->isStandby && AH->remoteVersion < 100000)
    1586            0 :             pg_fatal("parallel dumps from standby servers are not supported by this server version");
    1587            8 :         AH->sync_snapshot_id = get_synchronized_snapshot(AH);
    1588              :     }
    1589          282 : }
    1590              : 
    1591              : /* Set up connection for a parallel worker process */
    1592              : static void
    1593           16 : setupDumpWorker(Archive *AH)
    1594              : {
    1595              :     /*
    1596              :      * We want to re-select all the same values the leader connection is
    1597              :      * using.  We'll have inherited directly-usable values in
    1598              :      * AH->sync_snapshot_id and AH->use_role, but we need to translate the
    1599              :      * inherited encoding value back to a string to pass to setup_connection.
    1600              :      */
    1601           16 :     setup_connection(AH,
    1602              :                      pg_encoding_to_char(AH->encoding),
    1603              :                      NULL,
    1604              :                      NULL);
    1605           16 : }
    1606              : 
    1607              : static char *
    1608            8 : get_synchronized_snapshot(Archive *fout)
    1609              : {
    1610            8 :     char       *query = "SELECT pg_catalog.pg_export_snapshot()";
    1611              :     char       *result;
    1612              :     PGresult   *res;
    1613              : 
    1614            8 :     res = ExecuteSqlQueryForSingleRow(fout, query);
    1615            8 :     result = pg_strdup(PQgetvalue(res, 0, 0));
    1616            8 :     PQclear(res);
    1617              : 
    1618            8 :     return result;
    1619              : }
    1620              : 
    1621              : static ArchiveFormat
    1622          275 : parseArchiveFormat(const char *format, ArchiveMode *mode)
    1623              : {
    1624              :     ArchiveFormat archiveFormat;
    1625              : 
    1626          275 :     *mode = archModeWrite;
    1627              : 
    1628          275 :     if (pg_strcasecmp(format, "a") == 0 || pg_strcasecmp(format, "append") == 0)
    1629              :     {
    1630              :         /* This is used by pg_dumpall, and is not documented */
    1631           48 :         archiveFormat = archNull;
    1632           48 :         *mode = archModeAppend;
    1633              :     }
    1634          227 :     else if (pg_strcasecmp(format, "c") == 0)
    1635            0 :         archiveFormat = archCustom;
    1636          227 :     else if (pg_strcasecmp(format, "custom") == 0)
    1637           54 :         archiveFormat = archCustom;
    1638          173 :     else if (pg_strcasecmp(format, "d") == 0)
    1639            0 :         archiveFormat = archDirectory;
    1640          173 :     else if (pg_strcasecmp(format, "directory") == 0)
    1641           57 :         archiveFormat = archDirectory;
    1642          116 :     else if (pg_strcasecmp(format, "p") == 0)
    1643          101 :         archiveFormat = archNull;
    1644           15 :     else if (pg_strcasecmp(format, "plain") == 0)
    1645            3 :         archiveFormat = archNull;
    1646           12 :     else if (pg_strcasecmp(format, "t") == 0)
    1647            0 :         archiveFormat = archTar;
    1648           12 :     else if (pg_strcasecmp(format, "tar") == 0)
    1649           11 :         archiveFormat = archTar;
    1650              :     else
    1651            1 :         pg_fatal("invalid output format \"%s\" specified", format);
    1652          274 :     return archiveFormat;
    1653              : }
    1654              : 
    1655              : /*
    1656              :  * Find the OIDs of all schemas matching the given list of patterns,
    1657              :  * and append them to the given OID list.
    1658              :  */
    1659              : static void
    1660          277 : expand_schema_name_patterns(Archive *fout,
    1661              :                             SimpleStringList *patterns,
    1662              :                             SimpleOidList *oids,
    1663              :                             bool strict_names)
    1664              : {
    1665              :     PQExpBuffer query;
    1666              :     PGresult   *res;
    1667              :     SimpleStringListCell *cell;
    1668              :     int         i;
    1669              : 
    1670          277 :     if (patterns->head == NULL)
    1671          256 :         return;                 /* nothing to do */
    1672              : 
    1673           21 :     query = createPQExpBuffer();
    1674              : 
    1675              :     /*
    1676              :      * The loop below runs multiple SELECTs might sometimes result in
    1677              :      * duplicate entries in the OID list, but we don't care.
    1678              :      */
    1679              : 
    1680           36 :     for (cell = patterns->head; cell; cell = cell->next)
    1681              :     {
    1682              :         PQExpBufferData dbbuf;
    1683              :         int         dotcnt;
    1684              : 
    1685           21 :         appendPQExpBufferStr(query,
    1686              :                              "SELECT oid FROM pg_catalog.pg_namespace n\n");
    1687           21 :         initPQExpBuffer(&dbbuf);
    1688           21 :         processSQLNamePattern(GetConnection(fout), query, cell->val, false,
    1689              :                               false, NULL, "n.nspname", NULL, NULL, &dbbuf,
    1690              :                               &dotcnt);
    1691           21 :         if (dotcnt > 1)
    1692            2 :             pg_fatal("improper qualified name (too many dotted names): %s",
    1693              :                      cell->val);
    1694           19 :         else if (dotcnt == 1)
    1695            3 :             prohibit_crossdb_refs(GetConnection(fout), dbbuf.data, cell->val);
    1696           16 :         termPQExpBuffer(&dbbuf);
    1697              : 
    1698           16 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    1699           16 :         if (strict_names && PQntuples(res) == 0)
    1700            1 :             pg_fatal("no matching schemas were found for pattern \"%s\"", cell->val);
    1701              : 
    1702           29 :         for (i = 0; i < PQntuples(res); i++)
    1703              :         {
    1704           14 :             simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
    1705              :         }
    1706              : 
    1707           15 :         PQclear(res);
    1708           15 :         resetPQExpBuffer(query);
    1709              :     }
    1710              : 
    1711           15 :     destroyPQExpBuffer(query);
    1712              : }
    1713              : 
    1714              : /*
    1715              :  * Find the OIDs of all extensions matching the given list of patterns,
    1716              :  * and append them to the given OID list.
    1717              :  */
    1718              : static void
    1719          255 : expand_extension_name_patterns(Archive *fout,
    1720              :                                SimpleStringList *patterns,
    1721              :                                SimpleOidList *oids,
    1722              :                                bool strict_names)
    1723              : {
    1724              :     PQExpBuffer query;
    1725              :     PGresult   *res;
    1726              :     SimpleStringListCell *cell;
    1727              :     int         i;
    1728              : 
    1729          255 :     if (patterns->head == NULL)
    1730          248 :         return;                 /* nothing to do */
    1731              : 
    1732            7 :     query = createPQExpBuffer();
    1733              : 
    1734              :     /*
    1735              :      * The loop below runs multiple SELECTs might sometimes result in
    1736              :      * duplicate entries in the OID list, but we don't care.
    1737              :      */
    1738           14 :     for (cell = patterns->head; cell; cell = cell->next)
    1739              :     {
    1740              :         int         dotcnt;
    1741              : 
    1742            7 :         appendPQExpBufferStr(query,
    1743              :                              "SELECT oid FROM pg_catalog.pg_extension e\n");
    1744            7 :         processSQLNamePattern(GetConnection(fout), query, cell->val, false,
    1745              :                               false, NULL, "e.extname", NULL, NULL, NULL,
    1746              :                               &dotcnt);
    1747            7 :         if (dotcnt > 0)
    1748            0 :             pg_fatal("improper qualified name (too many dotted names): %s",
    1749              :                      cell->val);
    1750              : 
    1751            7 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    1752            7 :         if (strict_names && PQntuples(res) == 0)
    1753            0 :             pg_fatal("no matching extensions were found for pattern \"%s\"", cell->val);
    1754              : 
    1755           13 :         for (i = 0; i < PQntuples(res); i++)
    1756              :         {
    1757            6 :             simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
    1758              :         }
    1759              : 
    1760            7 :         PQclear(res);
    1761            7 :         resetPQExpBuffer(query);
    1762              :     }
    1763              : 
    1764            7 :     destroyPQExpBuffer(query);
    1765              : }
    1766              : 
    1767              : /*
    1768              :  * Find the OIDs of all foreign servers matching the given list of patterns,
    1769              :  * and append them to the given OID list.
    1770              :  */
    1771              : static void
    1772          252 : expand_foreign_server_name_patterns(Archive *fout,
    1773              :                                     SimpleStringList *patterns,
    1774              :                                     SimpleOidList *oids)
    1775              : {
    1776              :     PQExpBuffer query;
    1777              :     PGresult   *res;
    1778              :     SimpleStringListCell *cell;
    1779              :     int         i;
    1780              : 
    1781          252 :     if (patterns->head == NULL)
    1782          249 :         return;                 /* nothing to do */
    1783              : 
    1784            3 :     query = createPQExpBuffer();
    1785              : 
    1786              :     /*
    1787              :      * The loop below runs multiple SELECTs might sometimes result in
    1788              :      * duplicate entries in the OID list, but we don't care.
    1789              :      */
    1790              : 
    1791            5 :     for (cell = patterns->head; cell; cell = cell->next)
    1792              :     {
    1793              :         int         dotcnt;
    1794              : 
    1795            3 :         appendPQExpBufferStr(query,
    1796              :                              "SELECT oid FROM pg_catalog.pg_foreign_server s\n");
    1797            3 :         processSQLNamePattern(GetConnection(fout), query, cell->val, false,
    1798              :                               false, NULL, "s.srvname", NULL, NULL, NULL,
    1799              :                               &dotcnt);
    1800            3 :         if (dotcnt > 0)
    1801            0 :             pg_fatal("improper qualified name (too many dotted names): %s",
    1802              :                      cell->val);
    1803              : 
    1804            3 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    1805            3 :         if (PQntuples(res) == 0)
    1806            1 :             pg_fatal("no matching foreign servers were found for pattern \"%s\"", cell->val);
    1807              : 
    1808            4 :         for (i = 0; i < PQntuples(res); i++)
    1809            2 :             simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
    1810              : 
    1811            2 :         PQclear(res);
    1812            2 :         resetPQExpBuffer(query);
    1813              :     }
    1814              : 
    1815            2 :     destroyPQExpBuffer(query);
    1816              : }
    1817              : 
    1818              : /*
    1819              :  * Find the OIDs of all tables matching the given list of patterns,
    1820              :  * and append them to the given OID list. See also expand_dbname_patterns()
    1821              :  * in pg_dumpall.c
    1822              :  */
    1823              : static void
    1824         1521 : expand_table_name_patterns(Archive *fout,
    1825              :                            SimpleStringList *patterns, SimpleOidList *oids,
    1826              :                            bool strict_names, bool with_child_tables)
    1827              : {
    1828              :     PQExpBuffer query;
    1829              :     PGresult   *res;
    1830              :     SimpleStringListCell *cell;
    1831              :     int         i;
    1832              : 
    1833         1521 :     if (patterns->head == NULL)
    1834         1492 :         return;                 /* nothing to do */
    1835              : 
    1836           29 :     query = createPQExpBuffer();
    1837              : 
    1838              :     /*
    1839              :      * this might sometimes result in duplicate entries in the OID list, but
    1840              :      * we don't care.
    1841              :      */
    1842              : 
    1843           59 :     for (cell = patterns->head; cell; cell = cell->next)
    1844              :     {
    1845              :         PQExpBufferData dbbuf;
    1846              :         int         dotcnt;
    1847              : 
    1848              :         /*
    1849              :          * Query must remain ABSOLUTELY devoid of unqualified names.  This
    1850              :          * would be unnecessary given a pg_table_is_visible() variant taking a
    1851              :          * search_path argument.
    1852              :          *
    1853              :          * For with_child_tables, we start with the basic query's results and
    1854              :          * recursively search the inheritance tree to add child tables.
    1855              :          */
    1856           35 :         if (with_child_tables)
    1857              :         {
    1858            6 :             appendPQExpBufferStr(query, "WITH RECURSIVE partition_tree (relid) AS (\n");
    1859              :         }
    1860              : 
    1861           35 :         appendPQExpBuffer(query,
    1862              :                           "SELECT c.oid"
    1863              :                           "\nFROM pg_catalog.pg_class c"
    1864              :                           "\n     LEFT JOIN pg_catalog.pg_namespace n"
    1865              :                           "\n     ON n.oid OPERATOR(pg_catalog.=) c.relnamespace"
    1866              :                           "\nWHERE c.relkind OPERATOR(pg_catalog.=) ANY"
    1867              :                           "\n    (array['%c', '%c', '%c', '%c', '%c', '%c'])\n",
    1868              :                           RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_VIEW,
    1869              :                           RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE,
    1870              :                           RELKIND_PARTITIONED_TABLE);
    1871           35 :         initPQExpBuffer(&dbbuf);
    1872           35 :         processSQLNamePattern(GetConnection(fout), query, cell->val, true,
    1873              :                               false, "n.nspname", "c.relname", NULL,
    1874              :                               "pg_catalog.pg_table_is_visible(c.oid)", &dbbuf,
    1875              :                               &dotcnt);
    1876           35 :         if (dotcnt > 2)
    1877            1 :             pg_fatal("improper relation name (too many dotted names): %s",
    1878              :                      cell->val);
    1879           34 :         else if (dotcnt == 2)
    1880            2 :             prohibit_crossdb_refs(GetConnection(fout), dbbuf.data, cell->val);
    1881           32 :         termPQExpBuffer(&dbbuf);
    1882              : 
    1883           32 :         if (with_child_tables)
    1884              :         {
    1885            6 :             appendPQExpBufferStr(query, "UNION"
    1886              :                                  "\nSELECT i.inhrelid"
    1887              :                                  "\nFROM partition_tree p"
    1888              :                                  "\n     JOIN pg_catalog.pg_inherits i"
    1889              :                                  "\n     ON p.relid OPERATOR(pg_catalog.=) i.inhparent"
    1890              :                                  "\n)"
    1891              :                                  "\nSELECT relid FROM partition_tree");
    1892              :         }
    1893              : 
    1894           32 :         ExecuteSqlStatement(fout, "RESET search_path");
    1895           32 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    1896           32 :         PQclear(ExecuteSqlQueryForSingleRow(fout,
    1897              :                                             ALWAYS_SECURE_SEARCH_PATH_SQL));
    1898           32 :         if (strict_names && PQntuples(res) == 0)
    1899            2 :             pg_fatal("no matching tables were found for pattern \"%s\"", cell->val);
    1900              : 
    1901           74 :         for (i = 0; i < PQntuples(res); i++)
    1902              :         {
    1903           44 :             simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
    1904              :         }
    1905              : 
    1906           30 :         PQclear(res);
    1907           30 :         resetPQExpBuffer(query);
    1908              :     }
    1909              : 
    1910           24 :     destroyPQExpBuffer(query);
    1911              : }
    1912              : 
    1913              : /*
    1914              :  * Verifies that the connected database name matches the given database name,
    1915              :  * and if not, dies with an error about the given pattern.
    1916              :  *
    1917              :  * The 'dbname' argument should be a literal name parsed from 'pattern'.
    1918              :  */
    1919              : static void
    1920            5 : prohibit_crossdb_refs(PGconn *conn, const char *dbname, const char *pattern)
    1921              : {
    1922              :     const char *db;
    1923              : 
    1924            5 :     db = PQdb(conn);
    1925            5 :     if (db == NULL)
    1926            0 :         pg_fatal("You are currently not connected to a database.");
    1927              : 
    1928            5 :     if (strcmp(db, dbname) != 0)
    1929            5 :         pg_fatal("cross-database references are not implemented: %s",
    1930              :                  pattern);
    1931            0 : }
    1932              : 
    1933              : /*
    1934              :  * checkExtensionMembership
    1935              :  *      Determine whether object is an extension member, and if so,
    1936              :  *      record an appropriate dependency and set the object's dump flag.
    1937              :  *
    1938              :  * It's important to call this for each object that could be an extension
    1939              :  * member.  Generally, we integrate this with determining the object's
    1940              :  * to-be-dumped-ness, since extension membership overrides other rules for that.
    1941              :  *
    1942              :  * Returns true if object is an extension member, else false.
    1943              :  */
    1944              : static bool
    1945       798649 : checkExtensionMembership(DumpableObject *dobj, Archive *fout)
    1946              : {
    1947       798649 :     ExtensionInfo *ext = findOwningExtension(dobj->catId);
    1948              : 
    1949       798649 :     if (ext == NULL)
    1950       797781 :         return false;
    1951              : 
    1952          868 :     dobj->ext_member = true;
    1953              : 
    1954              :     /* Record dependency so that getDependencies needn't deal with that */
    1955          868 :     addObjectDependency(dobj, ext->dobj.dumpId);
    1956              : 
    1957              :     /*
    1958              :      * In 9.6 and above, mark the member object to have any non-initial ACLs
    1959              :      * dumped.  (Any initial ACLs will be removed later, using data from
    1960              :      * pg_init_privs, so that we'll dump only the delta from the extension's
    1961              :      * initial setup.)
    1962              :      *
    1963              :      * Prior to 9.6, we do not include any extension member components.
    1964              :      *
    1965              :      * In binary upgrades, we still dump all components of the members
    1966              :      * individually, since the idea is to exactly reproduce the database
    1967              :      * contents rather than replace the extension contents with something
    1968              :      * different.
    1969              :      *
    1970              :      * Note: it might be interesting someday to implement storage and delta
    1971              :      * dumping of extension members' RLS policies and/or security labels.
    1972              :      * However there is a pitfall for RLS policies: trying to dump them
    1973              :      * requires getting a lock on their tables, and the calling user might not
    1974              :      * have privileges for that.  We need no lock to examine a table's ACLs,
    1975              :      * so the current feature doesn't have a problem of that sort.
    1976              :      */
    1977          868 :     if (fout->dopt->binary_upgrade)
    1978          177 :         dobj->dump = ext->dobj.dump;
    1979              :     else
    1980              :     {
    1981          691 :         if (fout->remoteVersion < 90600)
    1982            0 :             dobj->dump = DUMP_COMPONENT_NONE;
    1983              :         else
    1984          691 :             dobj->dump = ext->dobj.dump_contains & (DUMP_COMPONENT_ACL);
    1985              :     }
    1986              : 
    1987          868 :     return true;
    1988              : }
    1989              : 
    1990              : /*
    1991              :  * selectDumpableNamespace: policy-setting subroutine
    1992              :  *      Mark a namespace as to be dumped or not
    1993              :  */
    1994              : static void
    1995         1714 : selectDumpableNamespace(NamespaceInfo *nsinfo, Archive *fout)
    1996              : {
    1997              :     /*
    1998              :      * DUMP_COMPONENT_DEFINITION typically implies a CREATE SCHEMA statement
    1999              :      * and (for --clean) a DROP SCHEMA statement.  (In the absence of
    2000              :      * DUMP_COMPONENT_DEFINITION, this value is irrelevant.)
    2001              :      */
    2002         1714 :     nsinfo->create = true;
    2003              : 
    2004              :     /*
    2005              :      * If specific tables are being dumped, do not dump any complete
    2006              :      * namespaces. If specific namespaces are being dumped, dump just those
    2007              :      * namespaces. Otherwise, dump all non-system namespaces.
    2008              :      */
    2009         1714 :     if (table_include_oids.head != NULL)
    2010           50 :         nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
    2011         1664 :     else if (schema_include_oids.head != NULL)
    2012          187 :         nsinfo->dobj.dump_contains = nsinfo->dobj.dump =
    2013          187 :             simple_oid_list_member(&schema_include_oids,
    2014              :                                    nsinfo->dobj.catId.oid) ?
    2015          187 :             DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
    2016         1477 :     else if (fout->remoteVersion >= 90600 &&
    2017         1477 :              strcmp(nsinfo->dobj.name, "pg_catalog") == 0)
    2018              :     {
    2019              :         /*
    2020              :          * In 9.6 and above, we dump out any ACLs defined in pg_catalog, if
    2021              :          * they are interesting (and not the original ACLs which were set at
    2022              :          * initdb time, see pg_init_privs).
    2023              :          */
    2024          228 :         nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_ACL;
    2025              :     }
    2026         1249 :     else if (strncmp(nsinfo->dobj.name, "pg_", 3) == 0 ||
    2027          637 :              strcmp(nsinfo->dobj.name, "information_schema") == 0)
    2028              :     {
    2029              :         /* Other system schemas don't get dumped */
    2030          840 :         nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
    2031              :     }
    2032          409 :     else if (strcmp(nsinfo->dobj.name, "public") == 0)
    2033              :     {
    2034              :         /*
    2035              :          * The public schema is a strange beast that sits in a sort of
    2036              :          * no-mans-land between being a system object and a user object.
    2037              :          * CREATE SCHEMA would fail, so its DUMP_COMPONENT_DEFINITION is just
    2038              :          * a comment and an indication of ownership.  If the owner is the
    2039              :          * default, omit that superfluous DUMP_COMPONENT_DEFINITION.  Before
    2040              :          * v15, the default owner was BOOTSTRAP_SUPERUSERID.
    2041              :          */
    2042          224 :         nsinfo->create = false;
    2043          224 :         nsinfo->dobj.dump = DUMP_COMPONENT_ALL;
    2044          224 :         if (nsinfo->nspowner == ROLE_PG_DATABASE_OWNER)
    2045          182 :             nsinfo->dobj.dump &= ~DUMP_COMPONENT_DEFINITION;
    2046          224 :         nsinfo->dobj.dump_contains = DUMP_COMPONENT_ALL;
    2047              : 
    2048              :         /*
    2049              :          * Also, make like it has a comment even if it doesn't; this is so
    2050              :          * that we'll emit a command to drop the comment, if appropriate.
    2051              :          * (Without this, we'd not call dumpCommentExtended for it.)
    2052              :          */
    2053          224 :         nsinfo->dobj.components |= DUMP_COMPONENT_COMMENT;
    2054              :     }
    2055              :     else
    2056          185 :         nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_ALL;
    2057              : 
    2058              :     /*
    2059              :      * In any case, a namespace can be excluded by an exclusion switch
    2060              :      */
    2061         2362 :     if (nsinfo->dobj.dump_contains &&
    2062          648 :         simple_oid_list_member(&schema_exclude_oids,
    2063              :                                nsinfo->dobj.catId.oid))
    2064            3 :         nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
    2065              : 
    2066              :     /*
    2067              :      * If the schema belongs to an extension, allow extension membership to
    2068              :      * override the dump decision for the schema itself.  However, this does
    2069              :      * not change dump_contains, so this won't change what we do with objects
    2070              :      * within the schema.  (If they belong to the extension, they'll get
    2071              :      * suppressed by it, otherwise not.)
    2072              :      */
    2073         1714 :     (void) checkExtensionMembership(&nsinfo->dobj, fout);
    2074         1714 : }
    2075              : 
    2076              : /*
    2077              :  * selectDumpableTable: policy-setting subroutine
    2078              :  *      Mark a table as to be dumped or not
    2079              :  */
    2080              : static void
    2081        62906 : selectDumpableTable(TableInfo *tbinfo, Archive *fout)
    2082              : {
    2083        62906 :     if (checkExtensionMembership(&tbinfo->dobj, fout))
    2084          225 :         return;                 /* extension membership overrides all else */
    2085              : 
    2086              :     /*
    2087              :      * If specific tables are being dumped, dump just those tables; else, dump
    2088              :      * according to the parent namespace's dump flag.
    2089              :      */
    2090        62681 :     if (table_include_oids.head != NULL)
    2091         5200 :         tbinfo->dobj.dump = simple_oid_list_member(&table_include_oids,
    2092              :                                                    tbinfo->dobj.catId.oid) ?
    2093         2600 :             DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
    2094              :     else
    2095        60081 :         tbinfo->dobj.dump = tbinfo->dobj.namespace->dobj.dump_contains;
    2096              : 
    2097              :     /*
    2098              :      * In any case, a table can be excluded by an exclusion switch
    2099              :      */
    2100       103193 :     if (tbinfo->dobj.dump &&
    2101        40512 :         simple_oid_list_member(&table_exclude_oids,
    2102              :                                tbinfo->dobj.catId.oid))
    2103           12 :         tbinfo->dobj.dump = DUMP_COMPONENT_NONE;
    2104              : }
    2105              : 
    2106              : /*
    2107              :  * selectDumpableType: policy-setting subroutine
    2108              :  *      Mark a type as to be dumped or not
    2109              :  *
    2110              :  * If it's a table's rowtype or an autogenerated array type, we also apply a
    2111              :  * special type code to facilitate sorting into the desired order.  (We don't
    2112              :  * want to consider those to be ordinary types because that would bring tables
    2113              :  * up into the datatype part of the dump order.)  We still set the object's
    2114              :  * dump flag; that's not going to cause the dummy type to be dumped, but we
    2115              :  * need it so that casts involving such types will be dumped correctly -- see
    2116              :  * dumpCast.  This means the flag should be set the same as for the underlying
    2117              :  * object (the table or base type).
    2118              :  */
    2119              : static void
    2120       175325 : selectDumpableType(TypeInfo *tyinfo, Archive *fout)
    2121              : {
    2122              :     /* skip complex types, except for standalone composite types */
    2123       175325 :     if (OidIsValid(tyinfo->typrelid) &&
    2124        62170 :         tyinfo->typrelkind != RELKIND_COMPOSITE_TYPE)
    2125              :     {
    2126        61988 :         TableInfo  *tytable = findTableByOid(tyinfo->typrelid);
    2127              : 
    2128        61988 :         tyinfo->dobj.objType = DO_DUMMY_TYPE;
    2129        61988 :         if (tytable != NULL)
    2130        61988 :             tyinfo->dobj.dump = tytable->dobj.dump;
    2131              :         else
    2132            0 :             tyinfo->dobj.dump = DUMP_COMPONENT_NONE;
    2133        61988 :         return;
    2134              :     }
    2135              : 
    2136              :     /* skip auto-generated array and multirange types */
    2137       113337 :     if (tyinfo->isArray || tyinfo->isMultirange)
    2138              :     {
    2139        85652 :         tyinfo->dobj.objType = DO_DUMMY_TYPE;
    2140              : 
    2141              :         /*
    2142              :          * Fall through to set the dump flag; we assume that the subsequent
    2143              :          * rules will do the same thing as they would for the array's base
    2144              :          * type or multirange's range type.  (We cannot reliably look up the
    2145              :          * base type here, since getTypes may not have processed it yet.)
    2146              :          */
    2147              :     }
    2148              : 
    2149       113337 :     if (checkExtensionMembership(&tyinfo->dobj, fout))
    2150          150 :         return;                 /* extension membership overrides all else */
    2151              : 
    2152              :     /* Dump based on if the contents of the namespace are being dumped */
    2153       113187 :     tyinfo->dobj.dump = tyinfo->dobj.namespace->dobj.dump_contains;
    2154              : }
    2155              : 
    2156              : /*
    2157              :  * selectDumpableDefaultACL: policy-setting subroutine
    2158              :  *      Mark a default ACL as to be dumped or not
    2159              :  *
    2160              :  * For per-schema default ACLs, dump if the schema is to be dumped.
    2161              :  * Otherwise dump if we are dumping "everything".  Note that dumpSchema
    2162              :  * and aclsSkip are checked separately.
    2163              :  */
    2164              : static void
    2165          194 : selectDumpableDefaultACL(DefaultACLInfo *dinfo, DumpOptions *dopt)
    2166              : {
    2167              :     /* Default ACLs can't be extension members */
    2168              : 
    2169          194 :     if (dinfo->dobj.namespace)
    2170              :         /* default ACLs are considered part of the namespace */
    2171           90 :         dinfo->dobj.dump = dinfo->dobj.namespace->dobj.dump_contains;
    2172              :     else
    2173          104 :         dinfo->dobj.dump = dopt->include_everything ?
    2174          104 :             DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
    2175          194 : }
    2176              : 
    2177              : /*
    2178              :  * selectDumpableCast: policy-setting subroutine
    2179              :  *      Mark a cast as to be dumped or not
    2180              :  *
    2181              :  * Casts do not belong to any particular namespace (since they haven't got
    2182              :  * names), nor do they have identifiable owners.  To distinguish user-defined
    2183              :  * casts from built-in ones, we must resort to checking whether the cast's
    2184              :  * OID is in the range reserved for initdb.
    2185              :  */
    2186              : static void
    2187        60096 : selectDumpableCast(CastInfo *cast, Archive *fout)
    2188              : {
    2189        60096 :     if (checkExtensionMembership(&cast->dobj, fout))
    2190            0 :         return;                 /* extension membership overrides all else */
    2191              : 
    2192              :     /*
    2193              :      * This would be DUMP_COMPONENT_ACL for from-initdb casts, but they do not
    2194              :      * support ACLs currently.
    2195              :      */
    2196        60096 :     if (cast->dobj.catId.oid <= g_last_builtin_oid)
    2197        60009 :         cast->dobj.dump = DUMP_COMPONENT_NONE;
    2198              :     else
    2199           87 :         cast->dobj.dump = fout->dopt->include_everything ?
    2200           87 :             DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
    2201              : }
    2202              : 
    2203              : /*
    2204              :  * selectDumpableProcLang: policy-setting subroutine
    2205              :  *      Mark a procedural language as to be dumped or not
    2206              :  *
    2207              :  * Procedural languages do not belong to any particular namespace.  To
    2208              :  * identify built-in languages, we must resort to checking whether the
    2209              :  * language's OID is in the range reserved for initdb.
    2210              :  */
    2211              : static void
    2212          294 : selectDumpableProcLang(ProcLangInfo *plang, Archive *fout)
    2213              : {
    2214          294 :     if (checkExtensionMembership(&plang->dobj, fout))
    2215          249 :         return;                 /* extension membership overrides all else */
    2216              : 
    2217              :     /*
    2218              :      * Only include procedural languages when we are dumping everything.
    2219              :      *
    2220              :      * For from-initdb procedural languages, only include ACLs, as we do for
    2221              :      * the pg_catalog namespace.  We need this because procedural languages do
    2222              :      * not live in any namespace.
    2223              :      */
    2224           45 :     if (!fout->dopt->include_everything)
    2225            8 :         plang->dobj.dump = DUMP_COMPONENT_NONE;
    2226              :     else
    2227              :     {
    2228           37 :         if (plang->dobj.catId.oid <= g_last_builtin_oid)
    2229            0 :             plang->dobj.dump = fout->remoteVersion < 90600 ?
    2230            0 :                 DUMP_COMPONENT_NONE : DUMP_COMPONENT_ACL;
    2231              :         else
    2232           37 :             plang->dobj.dump = DUMP_COMPONENT_ALL;
    2233              :     }
    2234              : }
    2235              : 
    2236              : /*
    2237              :  * selectDumpableAccessMethod: policy-setting subroutine
    2238              :  *      Mark an access method as to be dumped or not
    2239              :  *
    2240              :  * Access methods do not belong to any particular namespace.  To identify
    2241              :  * built-in access methods, we must resort to checking whether the
    2242              :  * method's OID is in the range reserved for initdb.
    2243              :  */
    2244              : static void
    2245         1865 : selectDumpableAccessMethod(AccessMethodInfo *method, Archive *fout)
    2246              : {
    2247              :     /* see getAccessMethods() comment about v9.6. */
    2248         1865 :     if (fout->remoteVersion < 90600)
    2249              :     {
    2250            0 :         method->dobj.dump = DUMP_COMPONENT_NONE;
    2251            0 :         return;
    2252              :     }
    2253              : 
    2254         1865 :     if (checkExtensionMembership(&method->dobj, fout))
    2255           25 :         return;                 /* extension membership overrides all else */
    2256              : 
    2257              :     /*
    2258              :      * This would be DUMP_COMPONENT_ACL for from-initdb access methods, but
    2259              :      * they do not support ACLs currently.
    2260              :      */
    2261         1840 :     if (method->dobj.catId.oid <= g_last_builtin_oid)
    2262         1743 :         method->dobj.dump = DUMP_COMPONENT_NONE;
    2263              :     else
    2264           97 :         method->dobj.dump = fout->dopt->include_everything ?
    2265           97 :             DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
    2266              : }
    2267              : 
    2268              : /*
    2269              :  * selectDumpableExtension: policy-setting subroutine
    2270              :  *      Mark an extension as to be dumped or not
    2271              :  *
    2272              :  * Built-in extensions should be skipped except for checking ACLs, since we
    2273              :  * assume those will already be installed in the target database.  We identify
    2274              :  * such extensions by their having OIDs in the range reserved for initdb.
    2275              :  * We dump all user-added extensions by default.  No extensions are dumped
    2276              :  * if include_everything is false (i.e., a --schema or --table switch was
    2277              :  * given), except if --extension specifies a list of extensions to dump.
    2278              :  */
    2279              : static void
    2280          280 : selectDumpableExtension(ExtensionInfo *extinfo, DumpOptions *dopt)
    2281              : {
    2282              :     /*
    2283              :      * Use DUMP_COMPONENT_ACL for built-in extensions, to allow users to
    2284              :      * change permissions on their member objects, if they wish to, and have
    2285              :      * those changes preserved.
    2286              :      */
    2287          280 :     if (extinfo->dobj.catId.oid <= g_last_builtin_oid)
    2288          250 :         extinfo->dobj.dump = extinfo->dobj.dump_contains = DUMP_COMPONENT_ACL;
    2289              :     else
    2290              :     {
    2291              :         /* check if there is a list of extensions to dump */
    2292           30 :         if (extension_include_oids.head != NULL)
    2293            4 :             extinfo->dobj.dump = extinfo->dobj.dump_contains =
    2294            4 :                 simple_oid_list_member(&extension_include_oids,
    2295              :                                        extinfo->dobj.catId.oid) ?
    2296            4 :                 DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
    2297              :         else
    2298           26 :             extinfo->dobj.dump = extinfo->dobj.dump_contains =
    2299           26 :                 dopt->include_everything ?
    2300           26 :                 DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
    2301              : 
    2302              :         /* check that the extension is not explicitly excluded */
    2303           56 :         if (extinfo->dobj.dump &&
    2304           26 :             simple_oid_list_member(&extension_exclude_oids,
    2305              :                                    extinfo->dobj.catId.oid))
    2306            2 :             extinfo->dobj.dump = extinfo->dobj.dump_contains = DUMP_COMPONENT_NONE;
    2307              :     }
    2308          280 : }
    2309              : 
    2310              : /*
    2311              :  * selectDumpablePublicationObject: policy-setting subroutine
    2312              :  *      Mark a publication object as to be dumped or not
    2313              :  *
    2314              :  * A publication can have schemas and tables which have schemas, but those are
    2315              :  * ignored in decision making, because publications are only dumped when we are
    2316              :  * dumping everything.
    2317              :  */
    2318              : static void
    2319          475 : selectDumpablePublicationObject(DumpableObject *dobj, Archive *fout)
    2320              : {
    2321          475 :     if (checkExtensionMembership(dobj, fout))
    2322            0 :         return;                 /* extension membership overrides all else */
    2323              : 
    2324          475 :     dobj->dump = fout->dopt->include_everything ?
    2325          475 :         DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
    2326              : }
    2327              : 
    2328              : /*
    2329              :  * selectDumpableStatisticsObject: policy-setting subroutine
    2330              :  *      Mark an extended statistics object as to be dumped or not
    2331              :  *
    2332              :  * We dump an extended statistics object if the schema it's in and the table
    2333              :  * it's for are being dumped.  (This'll need more thought if statistics
    2334              :  * objects ever support cross-table stats.)
    2335              :  */
    2336              : static void
    2337          208 : selectDumpableStatisticsObject(StatsExtInfo *sobj, Archive *fout)
    2338              : {
    2339          208 :     if (checkExtensionMembership(&sobj->dobj, fout))
    2340            0 :         return;                 /* extension membership overrides all else */
    2341              : 
    2342          208 :     sobj->dobj.dump = sobj->dobj.namespace->dobj.dump_contains;
    2343          208 :     if (sobj->stattable == NULL ||
    2344          208 :         !(sobj->stattable->dobj.dump & DUMP_COMPONENT_DEFINITION))
    2345           35 :         sobj->dobj.dump = DUMP_COMPONENT_NONE;
    2346              : }
    2347              : 
    2348              : /*
    2349              :  * selectDumpableObject: policy-setting subroutine
    2350              :  *      Mark a generic dumpable object as to be dumped or not
    2351              :  *
    2352              :  * Use this only for object types without a special-case routine above.
    2353              :  */
    2354              : static void
    2355       557754 : selectDumpableObject(DumpableObject *dobj, Archive *fout)
    2356              : {
    2357       557754 :     if (checkExtensionMembership(dobj, fout))
    2358          194 :         return;                 /* extension membership overrides all else */
    2359              : 
    2360              :     /*
    2361              :      * Default policy is to dump if parent namespace is dumpable, or for
    2362              :      * non-namespace-associated items, dump if we're dumping "everything".
    2363              :      */
    2364       557560 :     if (dobj->namespace)
    2365       556831 :         dobj->dump = dobj->namespace->dobj.dump_contains;
    2366              :     else
    2367          729 :         dobj->dump = fout->dopt->include_everything ?
    2368          729 :             DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
    2369              : }
    2370              : 
    2371              : /*
    2372              :  *  Dump a table's contents for loading using the COPY command
    2373              :  *  - this routine is called by the Archiver when it wants the table
    2374              :  *    to be dumped.
    2375              :  */
    2376              : static int
    2377         4234 : dumpTableData_copy(Archive *fout, const void *dcontext)
    2378              : {
    2379         4234 :     const TableDataInfo *tdinfo = dcontext;
    2380         4234 :     const TableInfo *tbinfo = tdinfo->tdtable;
    2381         4234 :     const char *classname = tbinfo->dobj.name;
    2382         4234 :     PQExpBuffer q = createPQExpBuffer();
    2383              : 
    2384              :     /*
    2385              :      * Note: can't use getThreadLocalPQExpBuffer() here, we're calling fmtId
    2386              :      * which uses it already.
    2387              :      */
    2388         4234 :     PQExpBuffer clistBuf = createPQExpBuffer();
    2389         4234 :     PGconn     *conn = GetConnection(fout);
    2390              :     PGresult   *res;
    2391              :     int         ret;
    2392              :     char       *copybuf;
    2393              :     const char *column_list;
    2394              : 
    2395         4234 :     pg_log_info("dumping contents of table \"%s.%s\"",
    2396              :                 tbinfo->dobj.namespace->dobj.name, classname);
    2397              : 
    2398              :     /*
    2399              :      * Specify the column list explicitly so that we have no possibility of
    2400              :      * retrieving data in the wrong column order.  (The default column
    2401              :      * ordering of COPY will not be what we want in certain corner cases
    2402              :      * involving ADD COLUMN and inheritance.)
    2403              :      */
    2404         4234 :     column_list = fmtCopyColumnList(tbinfo, clistBuf);
    2405              : 
    2406              :     /*
    2407              :      * Use COPY (SELECT ...) TO when dumping a foreign table's data, when a
    2408              :      * filter condition was specified, and when in binary upgrade mode and
    2409              :      * dumping an old pg_largeobject_metadata defined WITH OIDS.  For other
    2410              :      * cases a simple COPY suffices.
    2411              :      */
    2412         4234 :     if (tdinfo->filtercond || tbinfo->relkind == RELKIND_FOREIGN_TABLE ||
    2413         4195 :         (fout->dopt->binary_upgrade && fout->remoteVersion < 120000 &&
    2414            0 :          tbinfo->dobj.catId.oid == LargeObjectMetadataRelationId))
    2415              :     {
    2416              :         /* Temporary allows to access to foreign tables to dump data */
    2417           39 :         if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
    2418            1 :             set_restrict_relation_kind(fout, "view");
    2419              : 
    2420           39 :         appendPQExpBufferStr(q, "COPY (SELECT ");
    2421              :         /* klugery to get rid of parens in column list */
    2422           39 :         if (strlen(column_list) > 2)
    2423              :         {
    2424           39 :             appendPQExpBufferStr(q, column_list + 1);
    2425           39 :             q->data[q->len - 1] = ' ';
    2426              :         }
    2427              :         else
    2428            0 :             appendPQExpBufferStr(q, "* ");
    2429              : 
    2430           78 :         appendPQExpBuffer(q, "FROM %s %s) TO stdout;",
    2431           39 :                           fmtQualifiedDumpable(tbinfo),
    2432           39 :                           tdinfo->filtercond ? tdinfo->filtercond : "");
    2433              :     }
    2434              :     else
    2435              :     {
    2436         4195 :         appendPQExpBuffer(q, "COPY %s %s TO stdout;",
    2437         4195 :                           fmtQualifiedDumpable(tbinfo),
    2438              :                           column_list);
    2439              :     }
    2440         4234 :     res = ExecuteSqlQuery(fout, q->data, PGRES_COPY_OUT);
    2441         4233 :     PQclear(res);
    2442         4233 :     destroyPQExpBuffer(clistBuf);
    2443              : 
    2444              :     for (;;)
    2445              :     {
    2446      1814696 :         ret = PQgetCopyData(conn, &copybuf, 0);
    2447              : 
    2448      1814696 :         if (ret < 0)
    2449         4233 :             break;              /* done or error */
    2450              : 
    2451      1810463 :         if (copybuf)
    2452              :         {
    2453      1810463 :             WriteData(fout, copybuf, ret);
    2454      1810463 :             PQfreemem(copybuf);
    2455              :         }
    2456              : 
    2457              :         /* ----------
    2458              :          * THROTTLE:
    2459              :          *
    2460              :          * There was considerable discussion in late July, 2000 regarding
    2461              :          * slowing down pg_dump when backing up large tables. Users with both
    2462              :          * slow & fast (multi-processor) machines experienced performance
    2463              :          * degradation when doing a backup.
    2464              :          *
    2465              :          * Initial attempts based on sleeping for a number of ms for each ms
    2466              :          * of work were deemed too complex, then a simple 'sleep in each loop'
    2467              :          * implementation was suggested. The latter failed because the loop
    2468              :          * was too tight. Finally, the following was implemented:
    2469              :          *
    2470              :          * If throttle is non-zero, then
    2471              :          *      See how long since the last sleep.
    2472              :          *      Work out how long to sleep (based on ratio).
    2473              :          *      If sleep is more than 100ms, then
    2474              :          *          sleep
    2475              :          *          reset timer
    2476              :          *      EndIf
    2477              :          * EndIf
    2478              :          *
    2479              :          * where the throttle value was the number of ms to sleep per ms of
    2480              :          * work. The calculation was done in each loop.
    2481              :          *
    2482              :          * Most of the hard work is done in the backend, and this solution
    2483              :          * still did not work particularly well: on slow machines, the ratio
    2484              :          * was 50:1, and on medium paced machines, 1:1, and on fast
    2485              :          * multi-processor machines, it had little or no effect, for reasons
    2486              :          * that were unclear.
    2487              :          *
    2488              :          * Further discussion ensued, and the proposal was dropped.
    2489              :          *
    2490              :          * For those people who want this feature, it can be implemented using
    2491              :          * gettimeofday in each loop, calculating the time since last sleep,
    2492              :          * multiplying that by the sleep ratio, then if the result is more
    2493              :          * than a preset 'minimum sleep time' (say 100ms), call the 'select'
    2494              :          * function to sleep for a subsecond period ie.
    2495              :          *
    2496              :          * select(0, NULL, NULL, NULL, &tvi);
    2497              :          *
    2498              :          * This will return after the interval specified in the structure tvi.
    2499              :          * Finally, call gettimeofday again to save the 'last sleep time'.
    2500              :          * ----------
    2501              :          */
    2502              :     }
    2503         4233 :     archprintf(fout, "\\.\n\n\n");
    2504              : 
    2505         4233 :     if (ret == -2)
    2506              :     {
    2507              :         /* copy data transfer failed */
    2508            0 :         pg_log_error("Dumping the contents of table \"%s\" failed: PQgetCopyData() failed.", classname);
    2509            0 :         pg_log_error_detail("Error message from server: %s", PQerrorMessage(conn));
    2510            0 :         pg_log_error_detail("Command was: %s", q->data);
    2511            0 :         exit_nicely(1);
    2512              :     }
    2513              : 
    2514              :     /* Check command status and return to normal libpq state */
    2515         4233 :     res = PQgetResult(conn);
    2516         4233 :     if (PQresultStatus(res) != PGRES_COMMAND_OK)
    2517              :     {
    2518            0 :         pg_log_error("Dumping the contents of table \"%s\" failed: PQgetResult() failed.", classname);
    2519            0 :         pg_log_error_detail("Error message from server: %s", PQerrorMessage(conn));
    2520            0 :         pg_log_error_detail("Command was: %s", q->data);
    2521            0 :         exit_nicely(1);
    2522              :     }
    2523         4233 :     PQclear(res);
    2524              : 
    2525              :     /* Do this to ensure we've pumped libpq back to idle state */
    2526         4233 :     if (PQgetResult(conn) != NULL)
    2527            0 :         pg_log_warning("unexpected extra results during COPY of table \"%s\"",
    2528              :                        classname);
    2529              : 
    2530         4233 :     destroyPQExpBuffer(q);
    2531              : 
    2532              :     /* Revert back the setting */
    2533         4233 :     if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
    2534            0 :         set_restrict_relation_kind(fout, "view, foreign-table");
    2535              : 
    2536         4233 :     return 1;
    2537              : }
    2538              : 
    2539              : /*
    2540              :  * Dump table data using INSERT commands.
    2541              :  *
    2542              :  * Caution: when we restore from an archive file direct to database, the
    2543              :  * INSERT commands emitted by this function have to be parsed by
    2544              :  * pg_backup_db.c's ExecuteSimpleCommands(), which will not handle comments,
    2545              :  * E'' strings, or dollar-quoted strings.  So don't emit anything like that.
    2546              :  */
    2547              : static int
    2548           87 : dumpTableData_insert(Archive *fout, const void *dcontext)
    2549              : {
    2550           87 :     const TableDataInfo *tdinfo = dcontext;
    2551           87 :     const TableInfo *tbinfo = tdinfo->tdtable;
    2552           87 :     DumpOptions *dopt = fout->dopt;
    2553           87 :     PQExpBuffer q = createPQExpBuffer();
    2554           87 :     PQExpBuffer insertStmt = NULL;
    2555              :     char       *attgenerated;
    2556              :     PGresult   *res;
    2557              :     int         nfields,
    2558              :                 i;
    2559           87 :     int         rows_per_statement = dopt->dump_inserts;
    2560           87 :     int         rows_this_statement = 0;
    2561              : 
    2562              :     /* Temporary allows to access to foreign tables to dump data */
    2563           87 :     if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
    2564            0 :         set_restrict_relation_kind(fout, "view");
    2565              : 
    2566              :     /*
    2567              :      * If we're going to emit INSERTs with column names, the most efficient
    2568              :      * way to deal with generated columns is to exclude them entirely.  For
    2569              :      * INSERTs without column names, we have to emit DEFAULT rather than the
    2570              :      * actual column value --- but we can save a few cycles by fetching nulls
    2571              :      * rather than the uninteresting-to-us value.
    2572              :      */
    2573           87 :     attgenerated = pg_malloc_array(char, tbinfo->numatts);
    2574           87 :     appendPQExpBufferStr(q, "DECLARE _pg_dump_cursor CURSOR FOR SELECT ");
    2575           87 :     nfields = 0;
    2576          269 :     for (i = 0; i < tbinfo->numatts; i++)
    2577              :     {
    2578          182 :         if (tbinfo->attisdropped[i])
    2579            2 :             continue;
    2580          180 :         if (tbinfo->attgenerated[i] && dopt->column_inserts)
    2581            8 :             continue;
    2582          172 :         if (nfields > 0)
    2583           92 :             appendPQExpBufferStr(q, ", ");
    2584          172 :         if (tbinfo->attgenerated[i])
    2585            8 :             appendPQExpBufferStr(q, "NULL");
    2586              :         else
    2587          164 :             appendPQExpBufferStr(q, fmtId(tbinfo->attnames[i]));
    2588          172 :         attgenerated[nfields] = tbinfo->attgenerated[i];
    2589          172 :         nfields++;
    2590              :     }
    2591              :     /* Servers before 9.4 will complain about zero-column SELECT */
    2592           87 :     if (nfields == 0)
    2593            7 :         appendPQExpBufferStr(q, "NULL");
    2594           87 :     appendPQExpBuffer(q, " FROM ONLY %s",
    2595           87 :                       fmtQualifiedDumpable(tbinfo));
    2596           87 :     if (tdinfo->filtercond)
    2597            0 :         appendPQExpBuffer(q, " %s", tdinfo->filtercond);
    2598              : 
    2599           87 :     ExecuteSqlStatement(fout, q->data);
    2600              : 
    2601              :     while (1)
    2602              :     {
    2603          139 :         res = ExecuteSqlQuery(fout, "FETCH 100 FROM _pg_dump_cursor",
    2604              :                               PGRES_TUPLES_OK);
    2605              : 
    2606              :         /* cross-check field count, allowing for dummy NULL if any */
    2607          139 :         if (nfields != PQnfields(res) &&
    2608           10 :             !(nfields == 0 && PQnfields(res) == 1))
    2609            0 :             pg_fatal("wrong number of fields retrieved from table \"%s\"",
    2610              :                      tbinfo->dobj.name);
    2611              : 
    2612              :         /*
    2613              :          * First time through, we build as much of the INSERT statement as
    2614              :          * possible in "insertStmt", which we can then just print for each
    2615              :          * statement. If the table happens to have zero dumpable columns then
    2616              :          * this will be a complete statement, otherwise it will end in
    2617              :          * "VALUES" and be ready to have the row's column values printed.
    2618              :          */
    2619          139 :         if (insertStmt == NULL)
    2620              :         {
    2621              :             const TableInfo *targettab;
    2622              : 
    2623           87 :             insertStmt = createPQExpBuffer();
    2624              : 
    2625              :             /*
    2626              :              * When load-via-partition-root is set or forced, get the root
    2627              :              * table name for the partition table, so that we can reload data
    2628              :              * through the root table.
    2629              :              */
    2630           87 :             if (tbinfo->ispartition &&
    2631           48 :                 (dopt->load_via_partition_root ||
    2632           24 :                  forcePartitionRootLoad(tbinfo)))
    2633            7 :                 targettab = getRootTableInfo(tbinfo);
    2634              :             else
    2635           80 :                 targettab = tbinfo;
    2636              : 
    2637           87 :             appendPQExpBuffer(insertStmt, "INSERT INTO %s ",
    2638           87 :                               fmtQualifiedDumpable(targettab));
    2639              : 
    2640              :             /* corner case for zero-column table */
    2641           87 :             if (nfields == 0)
    2642              :             {
    2643            7 :                 appendPQExpBufferStr(insertStmt, "DEFAULT VALUES;\n");
    2644              :             }
    2645              :             else
    2646              :             {
    2647              :                 /* append the list of column names if required */
    2648           80 :                 if (dopt->column_inserts)
    2649              :                 {
    2650           36 :                     appendPQExpBufferChar(insertStmt, '(');
    2651          109 :                     for (int field = 0; field < nfields; field++)
    2652              :                     {
    2653           73 :                         if (field > 0)
    2654           37 :                             appendPQExpBufferStr(insertStmt, ", ");
    2655           73 :                         appendPQExpBufferStr(insertStmt,
    2656           73 :                                              fmtId(PQfname(res, field)));
    2657              :                     }
    2658           36 :                     appendPQExpBufferStr(insertStmt, ") ");
    2659              :                 }
    2660              : 
    2661           80 :                 if (tbinfo->needs_override)
    2662            2 :                     appendPQExpBufferStr(insertStmt, "OVERRIDING SYSTEM VALUE ");
    2663              : 
    2664           80 :                 appendPQExpBufferStr(insertStmt, "VALUES");
    2665              :             }
    2666              :         }
    2667              : 
    2668         3608 :         for (int tuple = 0; tuple < PQntuples(res); tuple++)
    2669              :         {
    2670              :             /* Write the INSERT if not in the middle of a multi-row INSERT. */
    2671         3469 :             if (rows_this_statement == 0)
    2672         3463 :                 archputs(insertStmt->data, fout);
    2673              : 
    2674              :             /*
    2675              :              * If it is zero-column table then we've already written the
    2676              :              * complete statement, which will mean we've disobeyed
    2677              :              * --rows-per-insert when it's set greater than 1.  We do support
    2678              :              * a way to make this multi-row with: SELECT UNION ALL SELECT
    2679              :              * UNION ALL ... but that's non-standard so we should avoid it
    2680              :              * given that using INSERTs is mostly only ever needed for
    2681              :              * cross-database exports.
    2682              :              */
    2683         3469 :             if (nfields == 0)
    2684            6 :                 continue;
    2685              : 
    2686              :             /* Emit a row heading */
    2687         3463 :             if (rows_per_statement == 1)
    2688         3454 :                 archputs(" (", fout);
    2689            9 :             else if (rows_this_statement > 0)
    2690            6 :                 archputs(",\n\t(", fout);
    2691              :             else
    2692            3 :                 archputs("\n\t(", fout);
    2693              : 
    2694        10445 :             for (int field = 0; field < nfields; field++)
    2695              :             {
    2696         6982 :                 if (field > 0)
    2697         3519 :                     archputs(", ", fout);
    2698         6982 :                 if (attgenerated[field])
    2699              :                 {
    2700            2 :                     archputs("DEFAULT", fout);
    2701            2 :                     continue;
    2702              :                 }
    2703         6980 :                 if (PQgetisnull(res, tuple, field))
    2704              :                 {
    2705           83 :                     archputs("NULL", fout);
    2706           83 :                     continue;
    2707              :                 }
    2708              : 
    2709              :                 /* XXX This code is partially duplicated in ruleutils.c */
    2710         6897 :                 switch (PQftype(res, field))
    2711              :                 {
    2712         4869 :                     case INT2OID:
    2713              :                     case INT4OID:
    2714              :                     case INT8OID:
    2715              :                     case OIDOID:
    2716              :                     case FLOAT4OID:
    2717              :                     case FLOAT8OID:
    2718              :                     case NUMERICOID:
    2719              :                         {
    2720              :                             /*
    2721              :                              * These types are printed without quotes unless
    2722              :                              * they contain values that aren't accepted by the
    2723              :                              * scanner unquoted (e.g., 'NaN').  Note that
    2724              :                              * strtod() and friends might accept NaN, so we
    2725              :                              * can't use that to test.
    2726              :                              *
    2727              :                              * In reality we only need to defend against
    2728              :                              * infinity and NaN, so we need not get too crazy
    2729              :                              * about pattern matching here.
    2730              :                              */
    2731         4869 :                             const char *s = PQgetvalue(res, tuple, field);
    2732              : 
    2733         4869 :                             if (strspn(s, "0123456789 +-eE.") == strlen(s))
    2734         4867 :                                 archputs(s, fout);
    2735              :                             else
    2736            2 :                                 archprintf(fout, "'%s'", s);
    2737              :                         }
    2738         4869 :                         break;
    2739              : 
    2740            2 :                     case BITOID:
    2741              :                     case VARBITOID:
    2742            2 :                         archprintf(fout, "B'%s'",
    2743              :                                    PQgetvalue(res, tuple, field));
    2744            2 :                         break;
    2745              : 
    2746            4 :                     case BOOLOID:
    2747            4 :                         if (strcmp(PQgetvalue(res, tuple, field), "t") == 0)
    2748            2 :                             archputs("true", fout);
    2749              :                         else
    2750            2 :                             archputs("false", fout);
    2751            4 :                         break;
    2752              : 
    2753         2022 :                     default:
    2754              :                         /* All other types are printed as string literals. */
    2755         2022 :                         resetPQExpBuffer(q);
    2756         2022 :                         appendStringLiteralAH(q,
    2757              :                                               PQgetvalue(res, tuple, field),
    2758              :                                               fout);
    2759         2022 :                         archputs(q->data, fout);
    2760         2022 :                         break;
    2761              :                 }
    2762              :             }
    2763              : 
    2764              :             /* Terminate the row ... */
    2765         3463 :             archputs(")", fout);
    2766              : 
    2767              :             /* ... and the statement, if the target no. of rows is reached */
    2768         3463 :             if (++rows_this_statement >= rows_per_statement)
    2769              :             {
    2770         3456 :                 if (dopt->do_nothing)
    2771            0 :                     archputs(" ON CONFLICT DO NOTHING;\n", fout);
    2772              :                 else
    2773         3456 :                     archputs(";\n", fout);
    2774              :                 /* Reset the row counter */
    2775         3456 :                 rows_this_statement = 0;
    2776              :             }
    2777              :         }
    2778              : 
    2779          139 :         if (PQntuples(res) <= 0)
    2780              :         {
    2781           87 :             PQclear(res);
    2782           87 :             break;
    2783              :         }
    2784           52 :         PQclear(res);
    2785              :     }
    2786              : 
    2787              :     /* Terminate any statements that didn't make the row count. */
    2788           87 :     if (rows_this_statement > 0)
    2789              :     {
    2790            1 :         if (dopt->do_nothing)
    2791            0 :             archputs(" ON CONFLICT DO NOTHING;\n", fout);
    2792              :         else
    2793            1 :             archputs(";\n", fout);
    2794              :     }
    2795              : 
    2796           87 :     archputs("\n\n", fout);
    2797              : 
    2798           87 :     ExecuteSqlStatement(fout, "CLOSE _pg_dump_cursor");
    2799              : 
    2800           87 :     destroyPQExpBuffer(q);
    2801           87 :     if (insertStmt != NULL)
    2802           87 :         destroyPQExpBuffer(insertStmt);
    2803           87 :     free(attgenerated);
    2804              : 
    2805              :     /* Revert back the setting */
    2806           87 :     if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
    2807            0 :         set_restrict_relation_kind(fout, "view, foreign-table");
    2808              : 
    2809           87 :     return 1;
    2810              : }
    2811              : 
    2812              : /*
    2813              :  * getRootTableInfo:
    2814              :  *     get the root TableInfo for the given partition table.
    2815              :  */
    2816              : static TableInfo *
    2817           79 : getRootTableInfo(const TableInfo *tbinfo)
    2818              : {
    2819              :     TableInfo  *parentTbinfo;
    2820              : 
    2821              :     Assert(tbinfo->ispartition);
    2822              :     Assert(tbinfo->numParents == 1);
    2823              : 
    2824           79 :     parentTbinfo = tbinfo->parents[0];
    2825           79 :     while (parentTbinfo->ispartition)
    2826              :     {
    2827              :         Assert(parentTbinfo->numParents == 1);
    2828            0 :         parentTbinfo = parentTbinfo->parents[0];
    2829              :     }
    2830              : 
    2831           79 :     return parentTbinfo;
    2832              : }
    2833              : 
    2834              : /*
    2835              :  * forcePartitionRootLoad
    2836              :  *     Check if we must force load_via_partition_root for this partition.
    2837              :  *
    2838              :  * This is required if any level of ancestral partitioned table has an
    2839              :  * unsafe partitioning scheme.
    2840              :  */
    2841              : static bool
    2842         1052 : forcePartitionRootLoad(const TableInfo *tbinfo)
    2843              : {
    2844              :     TableInfo  *parentTbinfo;
    2845              : 
    2846              :     Assert(tbinfo->ispartition);
    2847              :     Assert(tbinfo->numParents == 1);
    2848              : 
    2849         1052 :     parentTbinfo = tbinfo->parents[0];
    2850         1052 :     if (parentTbinfo->unsafe_partitions)
    2851           79 :         return true;
    2852         1193 :     while (parentTbinfo->ispartition)
    2853              :     {
    2854              :         Assert(parentTbinfo->numParents == 1);
    2855          220 :         parentTbinfo = parentTbinfo->parents[0];
    2856          220 :         if (parentTbinfo->unsafe_partitions)
    2857            0 :             return true;
    2858              :     }
    2859              : 
    2860          973 :     return false;
    2861              : }
    2862              : 
    2863              : /*
    2864              :  * dumpTableData -
    2865              :  *    dump the contents of a single table
    2866              :  *
    2867              :  * Actually, this just makes an ArchiveEntry for the table contents.
    2868              :  */
    2869              : static void
    2870         4407 : dumpTableData(Archive *fout, const TableDataInfo *tdinfo)
    2871              : {
    2872         4407 :     DumpOptions *dopt = fout->dopt;
    2873         4407 :     const TableInfo *tbinfo = tdinfo->tdtable;
    2874         4407 :     PQExpBuffer copyBuf = createPQExpBuffer();
    2875         4407 :     PQExpBuffer clistBuf = createPQExpBuffer();
    2876              :     DataDumperPtr dumpFn;
    2877         4407 :     char       *tdDefn = NULL;
    2878              :     char       *copyStmt;
    2879              :     const char *copyFrom;
    2880              : 
    2881              :     /* We had better have loaded per-column details about this table */
    2882              :     Assert(tbinfo->interesting);
    2883              : 
    2884              :     /*
    2885              :      * When load-via-partition-root is set or forced, get the root table name
    2886              :      * for the partition table, so that we can reload data through the root
    2887              :      * table.  Then construct a comment to be inserted into the TOC entry's
    2888              :      * defn field, so that such cases can be identified reliably.
    2889              :      */
    2890         4407 :     if (tbinfo->ispartition &&
    2891         2056 :         (dopt->load_via_partition_root ||
    2892         1028 :          forcePartitionRootLoad(tbinfo)))
    2893           72 :     {
    2894              :         const TableInfo *parentTbinfo;
    2895              :         char       *sanitized;
    2896              : 
    2897           72 :         parentTbinfo = getRootTableInfo(tbinfo);
    2898           72 :         copyFrom = fmtQualifiedDumpable(parentTbinfo);
    2899           72 :         sanitized = sanitize_line(copyFrom, true);
    2900           72 :         printfPQExpBuffer(copyBuf, "-- load via partition root %s",
    2901              :                           sanitized);
    2902           72 :         free(sanitized);
    2903           72 :         tdDefn = pg_strdup(copyBuf->data);
    2904              :     }
    2905              :     else
    2906         4335 :         copyFrom = fmtQualifiedDumpable(tbinfo);
    2907              : 
    2908         4407 :     if (dopt->dump_inserts == 0)
    2909              :     {
    2910              :         /* Dump/restore using COPY */
    2911         4320 :         dumpFn = dumpTableData_copy;
    2912              :         /* must use 2 steps here 'cause fmtId is nonreentrant */
    2913         4320 :         printfPQExpBuffer(copyBuf, "COPY %s ",
    2914              :                           copyFrom);
    2915         4320 :         appendPQExpBuffer(copyBuf, "%s FROM stdin;\n",
    2916              :                           fmtCopyColumnList(tbinfo, clistBuf));
    2917         4320 :         copyStmt = copyBuf->data;
    2918              :     }
    2919              :     else
    2920              :     {
    2921              :         /* Restore using INSERT */
    2922           87 :         dumpFn = dumpTableData_insert;
    2923           87 :         copyStmt = NULL;
    2924              :     }
    2925              : 
    2926              :     /*
    2927              :      * Note: although the TableDataInfo is a full DumpableObject, we treat its
    2928              :      * dependency on its table as "special" and pass it to ArchiveEntry now.
    2929              :      * See comments for BuildArchiveDependencies.
    2930              :      */
    2931         4407 :     if (tdinfo->dobj.dump & DUMP_COMPONENT_DATA)
    2932              :     {
    2933              :         TocEntry   *te;
    2934              : 
    2935         4407 :         te = ArchiveEntry(fout, tdinfo->dobj.catId, tdinfo->dobj.dumpId,
    2936         4407 :                           ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
    2937              :                                        .namespace = tbinfo->dobj.namespace->dobj.name,
    2938              :                                        .owner = tbinfo->rolname,
    2939              :                                        .description = "TABLE DATA",
    2940              :                                        .section = SECTION_DATA,
    2941              :                                        .createStmt = tdDefn,
    2942              :                                        .copyStmt = copyStmt,
    2943              :                                        .deps = &(tbinfo->dobj.dumpId),
    2944              :                                        .nDeps = 1,
    2945              :                                        .dumpFn = dumpFn,
    2946              :                                        .dumpArg = tdinfo));
    2947              : 
    2948              :         /*
    2949              :          * Set the TocEntry's dataLength in case we are doing a parallel dump
    2950              :          * and want to order dump jobs by table size.  We choose to measure
    2951              :          * dataLength in table pages (including TOAST pages) during dump, so
    2952              :          * no scaling is needed.
    2953              :          *
    2954              :          * However, relpages is declared as "integer" in pg_class, and hence
    2955              :          * also in TableInfo, but it's really BlockNumber a/k/a unsigned int.
    2956              :          * Cast so that we get the right interpretation of table sizes
    2957              :          * exceeding INT_MAX pages.
    2958              :          */
    2959         4407 :         te->dataLength = (BlockNumber) tbinfo->relpages;
    2960         4407 :         te->dataLength += (BlockNumber) tbinfo->toastpages;
    2961              : 
    2962              :         /*
    2963              :          * If pgoff_t is only 32 bits wide, the above refinement is useless,
    2964              :          * and instead we'd better worry about integer overflow.  Clamp to
    2965              :          * INT_MAX if the correct result exceeds that.
    2966              :          */
    2967              :         if (sizeof(te->dataLength) == 4 &&
    2968              :             (tbinfo->relpages < 0 || tbinfo->toastpages < 0 ||
    2969              :              te->dataLength < 0))
    2970              :             te->dataLength = INT_MAX;
    2971              :     }
    2972              : 
    2973         4407 :     destroyPQExpBuffer(copyBuf);
    2974         4407 :     destroyPQExpBuffer(clistBuf);
    2975         4407 : }
    2976              : 
    2977              : /*
    2978              :  * refreshMatViewData -
    2979              :  *    load or refresh the contents of a single materialized view
    2980              :  *
    2981              :  * Actually, this just makes an ArchiveEntry for the REFRESH MATERIALIZED VIEW
    2982              :  * statement.
    2983              :  */
    2984              : static void
    2985          345 : refreshMatViewData(Archive *fout, const TableDataInfo *tdinfo)
    2986              : {
    2987          345 :     TableInfo  *tbinfo = tdinfo->tdtable;
    2988              :     PQExpBuffer q;
    2989              : 
    2990              :     /* If the materialized view is not flagged as populated, skip this. */
    2991          345 :     if (!tbinfo->relispopulated)
    2992           68 :         return;
    2993              : 
    2994          277 :     q = createPQExpBuffer();
    2995              : 
    2996          277 :     appendPQExpBuffer(q, "REFRESH MATERIALIZED VIEW %s;\n",
    2997          277 :                       fmtQualifiedDumpable(tbinfo));
    2998              : 
    2999          277 :     if (tdinfo->dobj.dump & DUMP_COMPONENT_DATA)
    3000          277 :         ArchiveEntry(fout,
    3001              :                      tdinfo->dobj.catId, /* catalog ID */
    3002          277 :                      tdinfo->dobj.dumpId,    /* dump ID */
    3003          277 :                      ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
    3004              :                                   .namespace = tbinfo->dobj.namespace->dobj.name,
    3005              :                                   .owner = tbinfo->rolname,
    3006              :                                   .description = "MATERIALIZED VIEW DATA",
    3007              :                                   .section = SECTION_POST_DATA,
    3008              :                                   .createStmt = q->data,
    3009              :                                   .deps = tdinfo->dobj.dependencies,
    3010              :                                   .nDeps = tdinfo->dobj.nDeps));
    3011              : 
    3012          277 :     destroyPQExpBuffer(q);
    3013              : }
    3014              : 
    3015              : /*
    3016              :  * getTableData -
    3017              :  *    set up dumpable objects representing the contents of tables
    3018              :  */
    3019              : static void
    3020          241 : getTableData(DumpOptions *dopt, TableInfo *tblinfo, int numTables, char relkind)
    3021              : {
    3022              :     int         i;
    3023              : 
    3024        61146 :     for (i = 0; i < numTables; i++)
    3025              :     {
    3026        60905 :         if (tblinfo[i].dobj.dump & DUMP_COMPONENT_DATA &&
    3027          935 :             (!relkind || tblinfo[i].relkind == relkind))
    3028         6119 :             makeTableDataInfo(dopt, &(tblinfo[i]));
    3029              :     }
    3030          241 : }
    3031              : 
    3032              : /*
    3033              :  * Make a dumpable object for the data of this specific table
    3034              :  *
    3035              :  * Note: we make a TableDataInfo if and only if we are going to dump the
    3036              :  * table data; the "dump" field in such objects isn't very interesting.
    3037              :  */
    3038              : static void
    3039         6196 : makeTableDataInfo(DumpOptions *dopt, TableInfo *tbinfo)
    3040              : {
    3041              :     TableDataInfo *tdinfo;
    3042              : 
    3043              :     /*
    3044              :      * Nothing to do if we already decided to dump the table.  This will
    3045              :      * happen for "config" tables.
    3046              :      */
    3047         6196 :     if (tbinfo->dataObj != NULL)
    3048            1 :         return;
    3049              : 
    3050              :     /* Skip VIEWs (no data to dump) */
    3051         6195 :     if (tbinfo->relkind == RELKIND_VIEW)
    3052          484 :         return;
    3053              :     /* Skip FOREIGN TABLEs (no data to dump) unless requested explicitly */
    3054         5711 :     if (tbinfo->relkind == RELKIND_FOREIGN_TABLE &&
    3055           38 :         (foreign_servers_include_oids.head == NULL ||
    3056            4 :          !simple_oid_list_member(&foreign_servers_include_oids,
    3057              :                                  tbinfo->foreign_server)))
    3058           37 :         return;
    3059              :     /* Skip partitioned tables (data in partitions) */
    3060         5674 :     if (tbinfo->relkind == RELKIND_PARTITIONED_TABLE)
    3061          495 :         return;
    3062              : 
    3063              :     /* Don't dump data in unlogged tables, if so requested */
    3064         5179 :     if (tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED &&
    3065           41 :         dopt->no_unlogged_table_data)
    3066           18 :         return;
    3067              : 
    3068              :     /* Check that the data is not explicitly excluded */
    3069         5161 :     if (simple_oid_list_member(&tabledata_exclude_oids,
    3070              :                                tbinfo->dobj.catId.oid))
    3071            8 :         return;
    3072              : 
    3073              :     /* OK, let's dump it */
    3074         5153 :     tdinfo = pg_malloc_object(TableDataInfo);
    3075              : 
    3076         5153 :     if (tbinfo->relkind == RELKIND_MATVIEW)
    3077          345 :         tdinfo->dobj.objType = DO_REFRESH_MATVIEW;
    3078         4808 :     else if (tbinfo->relkind == RELKIND_SEQUENCE)
    3079          401 :         tdinfo->dobj.objType = DO_SEQUENCE_SET;
    3080              :     else
    3081         4407 :         tdinfo->dobj.objType = DO_TABLE_DATA;
    3082              : 
    3083              :     /*
    3084              :      * Note: use tableoid 0 so that this object won't be mistaken for
    3085              :      * something that pg_depend entries apply to.
    3086              :      */
    3087         5153 :     tdinfo->dobj.catId.tableoid = 0;
    3088         5153 :     tdinfo->dobj.catId.oid = tbinfo->dobj.catId.oid;
    3089         5153 :     AssignDumpId(&tdinfo->dobj);
    3090         5153 :     tdinfo->dobj.name = tbinfo->dobj.name;
    3091         5153 :     tdinfo->dobj.namespace = tbinfo->dobj.namespace;
    3092         5153 :     tdinfo->tdtable = tbinfo;
    3093         5153 :     tdinfo->filtercond = NULL;   /* might get set later */
    3094         5153 :     addObjectDependency(&tdinfo->dobj, tbinfo->dobj.dumpId);
    3095              : 
    3096              :     /* A TableDataInfo contains data, of course */
    3097         5153 :     tdinfo->dobj.components |= DUMP_COMPONENT_DATA;
    3098              : 
    3099         5153 :     tbinfo->dataObj = tdinfo;
    3100              : 
    3101              :     /*
    3102              :      * Materialized view statistics must be restored after the data, because
    3103              :      * REFRESH MATERIALIZED VIEW replaces the storage and resets the stats.
    3104              :      *
    3105              :      * The dependency is added here because the statistics objects are created
    3106              :      * first.
    3107              :      */
    3108         5153 :     if (tbinfo->relkind == RELKIND_MATVIEW && tbinfo->stats != NULL)
    3109              :     {
    3110          268 :         tbinfo->stats->section = SECTION_POST_DATA;
    3111          268 :         addObjectDependency(&tbinfo->stats->dobj, tdinfo->dobj.dumpId);
    3112              :     }
    3113              : 
    3114              :     /* Make sure that we'll collect per-column info for this table. */
    3115         5153 :     tbinfo->interesting = true;
    3116              : }
    3117              : 
    3118              : /*
    3119              :  * The refresh for a materialized view must be dependent on the refresh for
    3120              :  * any materialized view that this one is dependent on.
    3121              :  *
    3122              :  * This must be called after all the objects are created, but before they are
    3123              :  * sorted.
    3124              :  */
    3125              : static void
    3126          207 : buildMatViewRefreshDependencies(Archive *fout)
    3127              : {
    3128              :     PQExpBuffer query;
    3129              :     PGresult   *res;
    3130              :     int         ntups,
    3131              :                 i;
    3132              :     int         i_classid,
    3133              :                 i_objid,
    3134              :                 i_refobjid;
    3135              : 
    3136              :     /* No Mat Views before 9.3. */
    3137          207 :     if (fout->remoteVersion < 90300)
    3138            0 :         return;
    3139              : 
    3140          207 :     query = createPQExpBuffer();
    3141              : 
    3142          207 :     appendPQExpBufferStr(query, "WITH RECURSIVE w AS "
    3143              :                          "( "
    3144              :                          "SELECT d1.objid, d2.refobjid, c2.relkind AS refrelkind "
    3145              :                          "FROM pg_depend d1 "
    3146              :                          "JOIN pg_class c1 ON c1.oid = d1.objid "
    3147              :                          "AND c1.relkind = " CppAsString2(RELKIND_MATVIEW)
    3148              :                          " JOIN pg_rewrite r1 ON r1.ev_class = d1.objid "
    3149              :                          "JOIN pg_depend d2 ON d2.classid = 'pg_rewrite'::regclass "
    3150              :                          "AND d2.objid = r1.oid "
    3151              :                          "AND d2.refobjid <> d1.objid "
    3152              :                          "JOIN pg_class c2 ON c2.oid = d2.refobjid "
    3153              :                          "AND c2.relkind IN (" CppAsString2(RELKIND_MATVIEW) ","
    3154              :                          CppAsString2(RELKIND_VIEW) ") "
    3155              :                          "WHERE d1.classid = 'pg_class'::regclass "
    3156              :                          "UNION "
    3157              :                          "SELECT w.objid, d3.refobjid, c3.relkind "
    3158              :                          "FROM w "
    3159              :                          "JOIN pg_rewrite r3 ON r3.ev_class = w.refobjid "
    3160              :                          "JOIN pg_depend d3 ON d3.classid = 'pg_rewrite'::regclass "
    3161              :                          "AND d3.objid = r3.oid "
    3162              :                          "AND d3.refobjid <> w.refobjid "
    3163              :                          "JOIN pg_class c3 ON c3.oid = d3.refobjid "
    3164              :                          "AND c3.relkind IN (" CppAsString2(RELKIND_MATVIEW) ","
    3165              :                          CppAsString2(RELKIND_VIEW) ") "
    3166              :                          ") "
    3167              :                          "SELECT 'pg_class'::regclass::oid AS classid, objid, refobjid "
    3168              :                          "FROM w "
    3169              :                          "WHERE refrelkind = " CppAsString2(RELKIND_MATVIEW));
    3170              : 
    3171          207 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    3172              : 
    3173          207 :     ntups = PQntuples(res);
    3174              : 
    3175          207 :     i_classid = PQfnumber(res, "classid");
    3176          207 :     i_objid = PQfnumber(res, "objid");
    3177          207 :     i_refobjid = PQfnumber(res, "refobjid");
    3178              : 
    3179          471 :     for (i = 0; i < ntups; i++)
    3180              :     {
    3181              :         CatalogId   objId;
    3182              :         CatalogId   refobjId;
    3183              :         DumpableObject *dobj;
    3184              :         DumpableObject *refdobj;
    3185              :         TableInfo  *tbinfo;
    3186              :         TableInfo  *reftbinfo;
    3187              : 
    3188          264 :         objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
    3189          264 :         objId.oid = atooid(PQgetvalue(res, i, i_objid));
    3190          264 :         refobjId.tableoid = objId.tableoid;
    3191          264 :         refobjId.oid = atooid(PQgetvalue(res, i, i_refobjid));
    3192              : 
    3193          264 :         dobj = findObjectByCatalogId(objId);
    3194          264 :         if (dobj == NULL)
    3195           48 :             continue;
    3196              : 
    3197              :         Assert(dobj->objType == DO_TABLE);
    3198          264 :         tbinfo = (TableInfo *) dobj;
    3199              :         Assert(tbinfo->relkind == RELKIND_MATVIEW);
    3200          264 :         dobj = (DumpableObject *) tbinfo->dataObj;
    3201          264 :         if (dobj == NULL)
    3202           48 :             continue;
    3203              :         Assert(dobj->objType == DO_REFRESH_MATVIEW);
    3204              : 
    3205          216 :         refdobj = findObjectByCatalogId(refobjId);
    3206          216 :         if (refdobj == NULL)
    3207            0 :             continue;
    3208              : 
    3209              :         Assert(refdobj->objType == DO_TABLE);
    3210          216 :         reftbinfo = (TableInfo *) refdobj;
    3211              :         Assert(reftbinfo->relkind == RELKIND_MATVIEW);
    3212          216 :         refdobj = (DumpableObject *) reftbinfo->dataObj;
    3213          216 :         if (refdobj == NULL)
    3214            0 :             continue;
    3215              :         Assert(refdobj->objType == DO_REFRESH_MATVIEW);
    3216              : 
    3217          216 :         addObjectDependency(dobj, refdobj->dumpId);
    3218              : 
    3219          216 :         if (!reftbinfo->relispopulated)
    3220           34 :             tbinfo->relispopulated = false;
    3221              :     }
    3222              : 
    3223          207 :     PQclear(res);
    3224              : 
    3225          207 :     destroyPQExpBuffer(query);
    3226              : }
    3227              : 
    3228              : /*
    3229              :  * getTableDataFKConstraints -
    3230              :  *    add dump-order dependencies reflecting foreign key constraints
    3231              :  *
    3232              :  * This code is executed only in a data-only dump --- in schema+data dumps
    3233              :  * we handle foreign key issues by not creating the FK constraints until
    3234              :  * after the data is loaded.  In a data-only dump, however, we want to
    3235              :  * order the table data objects in such a way that a table's referenced
    3236              :  * tables are restored first.  (In the presence of circular references or
    3237              :  * self-references this may be impossible; we'll detect and complain about
    3238              :  * that during the dependency sorting step.)
    3239              :  */
    3240              : static void
    3241            7 : getTableDataFKConstraints(void)
    3242              : {
    3243              :     DumpableObject **dobjs;
    3244              :     int         numObjs;
    3245              :     int         i;
    3246              : 
    3247              :     /* Search through all the dumpable objects for FK constraints */
    3248            7 :     getDumpableObjects(&dobjs, &numObjs);
    3249        26440 :     for (i = 0; i < numObjs; i++)
    3250              :     {
    3251        26433 :         if (dobjs[i]->objType == DO_FK_CONSTRAINT)
    3252              :         {
    3253            8 :             ConstraintInfo *cinfo = (ConstraintInfo *) dobjs[i];
    3254              :             TableInfo  *ftable;
    3255              : 
    3256              :             /* Not interesting unless both tables are to be dumped */
    3257            8 :             if (cinfo->contable == NULL ||
    3258            8 :                 cinfo->contable->dataObj == NULL)
    3259            4 :                 continue;
    3260            4 :             ftable = findTableByOid(cinfo->confrelid);
    3261            4 :             if (ftable == NULL ||
    3262            4 :                 ftable->dataObj == NULL)
    3263            0 :                 continue;
    3264              : 
    3265              :             /*
    3266              :              * Okay, make referencing table's TABLE_DATA object depend on the
    3267              :              * referenced table's TABLE_DATA object.
    3268              :              */
    3269            4 :             addObjectDependency(&cinfo->contable->dataObj->dobj,
    3270            4 :                                 ftable->dataObj->dobj.dumpId);
    3271              :         }
    3272              :     }
    3273            7 :     free(dobjs);
    3274            7 : }
    3275              : 
    3276              : 
    3277              : /*
    3278              :  * dumpDatabase:
    3279              :  *  dump the database definition
    3280              :  */
    3281              : static void
    3282          150 : dumpDatabase(Archive *fout)
    3283              : {
    3284          150 :     DumpOptions *dopt = fout->dopt;
    3285          150 :     PQExpBuffer dbQry = createPQExpBuffer();
    3286          150 :     PQExpBuffer delQry = createPQExpBuffer();
    3287          150 :     PQExpBuffer creaQry = createPQExpBuffer();
    3288          150 :     PQExpBuffer labelq = createPQExpBuffer();
    3289          150 :     PGconn     *conn = GetConnection(fout);
    3290              :     PGresult   *res;
    3291              :     int         i_tableoid,
    3292              :                 i_oid,
    3293              :                 i_datname,
    3294              :                 i_datdba,
    3295              :                 i_encoding,
    3296              :                 i_datlocprovider,
    3297              :                 i_collate,
    3298              :                 i_ctype,
    3299              :                 i_datlocale,
    3300              :                 i_daticurules,
    3301              :                 i_frozenxid,
    3302              :                 i_minmxid,
    3303              :                 i_datacl,
    3304              :                 i_acldefault,
    3305              :                 i_datistemplate,
    3306              :                 i_datconnlimit,
    3307              :                 i_datcollversion,
    3308              :                 i_tablespace;
    3309              :     CatalogId   dbCatId;
    3310              :     DumpId      dbDumpId;
    3311              :     DumpableAcl dbdacl;
    3312              :     const char *datname,
    3313              :                *dba,
    3314              :                *encoding,
    3315              :                *datlocprovider,
    3316              :                *collate,
    3317              :                *ctype,
    3318              :                *locale,
    3319              :                *icurules,
    3320              :                *datistemplate,
    3321              :                *datconnlimit,
    3322              :                *tablespace;
    3323              :     uint32      frozenxid,
    3324              :                 minmxid;
    3325              :     char       *qdatname;
    3326              : 
    3327          150 :     pg_log_info("saving database definition");
    3328              : 
    3329              :     /*
    3330              :      * Fetch the database-level properties for this database.
    3331              :      */
    3332          150 :     appendPQExpBufferStr(dbQry, "SELECT tableoid, oid, datname, "
    3333              :                          "datdba, "
    3334              :                          "pg_encoding_to_char(encoding) AS encoding, "
    3335              :                          "datcollate, datctype, datfrozenxid, "
    3336              :                          "datacl, acldefault('d', datdba) AS acldefault, "
    3337              :                          "datistemplate, datconnlimit, ");
    3338          150 :     if (fout->remoteVersion >= 90300)
    3339          150 :         appendPQExpBufferStr(dbQry, "datminmxid, ");
    3340              :     else
    3341            0 :         appendPQExpBufferStr(dbQry, "0 AS datminmxid, ");
    3342          150 :     if (fout->remoteVersion >= 170000)
    3343          150 :         appendPQExpBufferStr(dbQry, "datlocprovider, datlocale, datcollversion, ");
    3344            0 :     else if (fout->remoteVersion >= 150000)
    3345            0 :         appendPQExpBufferStr(dbQry, "datlocprovider, daticulocale AS datlocale, datcollversion, ");
    3346              :     else
    3347            0 :         appendPQExpBufferStr(dbQry, "'c' AS datlocprovider, NULL AS datlocale, NULL AS datcollversion, ");
    3348          150 :     if (fout->remoteVersion >= 160000)
    3349          150 :         appendPQExpBufferStr(dbQry, "daticurules, ");
    3350              :     else
    3351            0 :         appendPQExpBufferStr(dbQry, "NULL AS daticurules, ");
    3352          150 :     appendPQExpBufferStr(dbQry,
    3353              :                          "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace, "
    3354              :                          "shobj_description(oid, 'pg_database') AS description "
    3355              :                          "FROM pg_database "
    3356              :                          "WHERE datname = current_database()");
    3357              : 
    3358          150 :     res = ExecuteSqlQueryForSingleRow(fout, dbQry->data);
    3359              : 
    3360          150 :     i_tableoid = PQfnumber(res, "tableoid");
    3361          150 :     i_oid = PQfnumber(res, "oid");
    3362          150 :     i_datname = PQfnumber(res, "datname");
    3363          150 :     i_datdba = PQfnumber(res, "datdba");
    3364          150 :     i_encoding = PQfnumber(res, "encoding");
    3365          150 :     i_datlocprovider = PQfnumber(res, "datlocprovider");
    3366          150 :     i_collate = PQfnumber(res, "datcollate");
    3367          150 :     i_ctype = PQfnumber(res, "datctype");
    3368          150 :     i_datlocale = PQfnumber(res, "datlocale");
    3369          150 :     i_daticurules = PQfnumber(res, "daticurules");
    3370          150 :     i_frozenxid = PQfnumber(res, "datfrozenxid");
    3371          150 :     i_minmxid = PQfnumber(res, "datminmxid");
    3372          150 :     i_datacl = PQfnumber(res, "datacl");
    3373          150 :     i_acldefault = PQfnumber(res, "acldefault");
    3374          150 :     i_datistemplate = PQfnumber(res, "datistemplate");
    3375          150 :     i_datconnlimit = PQfnumber(res, "datconnlimit");
    3376          150 :     i_datcollversion = PQfnumber(res, "datcollversion");
    3377          150 :     i_tablespace = PQfnumber(res, "tablespace");
    3378              : 
    3379          150 :     dbCatId.tableoid = atooid(PQgetvalue(res, 0, i_tableoid));
    3380          150 :     dbCatId.oid = atooid(PQgetvalue(res, 0, i_oid));
    3381          150 :     datname = PQgetvalue(res, 0, i_datname);
    3382          150 :     dba = getRoleName(PQgetvalue(res, 0, i_datdba));
    3383          150 :     encoding = PQgetvalue(res, 0, i_encoding);
    3384          150 :     datlocprovider = PQgetvalue(res, 0, i_datlocprovider);
    3385          150 :     collate = PQgetvalue(res, 0, i_collate);
    3386          150 :     ctype = PQgetvalue(res, 0, i_ctype);
    3387          150 :     if (!PQgetisnull(res, 0, i_datlocale))
    3388           14 :         locale = PQgetvalue(res, 0, i_datlocale);
    3389              :     else
    3390          136 :         locale = NULL;
    3391          150 :     if (!PQgetisnull(res, 0, i_daticurules))
    3392            0 :         icurules = PQgetvalue(res, 0, i_daticurules);
    3393              :     else
    3394          150 :         icurules = NULL;
    3395          150 :     frozenxid = atooid(PQgetvalue(res, 0, i_frozenxid));
    3396          150 :     minmxid = atooid(PQgetvalue(res, 0, i_minmxid));
    3397          150 :     dbdacl.acl = PQgetvalue(res, 0, i_datacl);
    3398          150 :     dbdacl.acldefault = PQgetvalue(res, 0, i_acldefault);
    3399          150 :     datistemplate = PQgetvalue(res, 0, i_datistemplate);
    3400          150 :     datconnlimit = PQgetvalue(res, 0, i_datconnlimit);
    3401          150 :     tablespace = PQgetvalue(res, 0, i_tablespace);
    3402              : 
    3403          150 :     qdatname = pg_strdup(fmtId(datname));
    3404              : 
    3405              :     /*
    3406              :      * Prepare the CREATE DATABASE command.  We must specify OID (if we want
    3407              :      * to preserve that), as well as the encoding, locale, and tablespace
    3408              :      * since those can't be altered later.  Other DB properties are left to
    3409              :      * the DATABASE PROPERTIES entry, so that they can be applied after
    3410              :      * reconnecting to the target DB.
    3411              :      *
    3412              :      * For binary upgrade, we use the FILE_COPY strategy because testing has
    3413              :      * shown it to be faster.  When the server is in binary upgrade mode, it
    3414              :      * will also skip the checkpoints this strategy ordinarily performs.
    3415              :      */
    3416          150 :     if (dopt->binary_upgrade)
    3417              :     {
    3418           37 :         appendPQExpBuffer(creaQry,
    3419              :                           "CREATE DATABASE %s WITH TEMPLATE = template0 "
    3420              :                           "OID = %u STRATEGY = FILE_COPY",
    3421              :                           qdatname, dbCatId.oid);
    3422              :     }
    3423              :     else
    3424              :     {
    3425          113 :         appendPQExpBuffer(creaQry, "CREATE DATABASE %s WITH TEMPLATE = template0",
    3426              :                           qdatname);
    3427              :     }
    3428          150 :     if (strlen(encoding) > 0)
    3429              :     {
    3430          150 :         appendPQExpBufferStr(creaQry, " ENCODING = ");
    3431          150 :         appendStringLiteralAH(creaQry, encoding, fout);
    3432              :     }
    3433              : 
    3434          150 :     appendPQExpBufferStr(creaQry, " LOCALE_PROVIDER = ");
    3435          150 :     if (datlocprovider[0] == 'b')
    3436           14 :         appendPQExpBufferStr(creaQry, "builtin");
    3437          136 :     else if (datlocprovider[0] == 'c')
    3438          136 :         appendPQExpBufferStr(creaQry, "libc");
    3439            0 :     else if (datlocprovider[0] == 'i')
    3440            0 :         appendPQExpBufferStr(creaQry, "icu");
    3441              :     else
    3442            0 :         pg_fatal("unrecognized locale provider: %s",
    3443              :                  datlocprovider);
    3444              : 
    3445          150 :     if (strlen(collate) > 0 && strcmp(collate, ctype) == 0)
    3446              :     {
    3447          150 :         appendPQExpBufferStr(creaQry, " LOCALE = ");
    3448          150 :         appendStringLiteralAH(creaQry, collate, fout);
    3449              :     }
    3450              :     else
    3451              :     {
    3452            0 :         if (strlen(collate) > 0)
    3453              :         {
    3454            0 :             appendPQExpBufferStr(creaQry, " LC_COLLATE = ");
    3455            0 :             appendStringLiteralAH(creaQry, collate, fout);
    3456              :         }
    3457            0 :         if (strlen(ctype) > 0)
    3458              :         {
    3459            0 :             appendPQExpBufferStr(creaQry, " LC_CTYPE = ");
    3460            0 :             appendStringLiteralAH(creaQry, ctype, fout);
    3461              :         }
    3462              :     }
    3463          150 :     if (locale)
    3464              :     {
    3465           14 :         if (datlocprovider[0] == 'b')
    3466           14 :             appendPQExpBufferStr(creaQry, " BUILTIN_LOCALE = ");
    3467              :         else
    3468            0 :             appendPQExpBufferStr(creaQry, " ICU_LOCALE = ");
    3469              : 
    3470           14 :         appendStringLiteralAH(creaQry, locale, fout);
    3471              :     }
    3472              : 
    3473          150 :     if (icurules)
    3474              :     {
    3475            0 :         appendPQExpBufferStr(creaQry, " ICU_RULES = ");
    3476            0 :         appendStringLiteralAH(creaQry, icurules, fout);
    3477              :     }
    3478              : 
    3479              :     /*
    3480              :      * For binary upgrade, carry over the collation version.  For normal
    3481              :      * dump/restore, omit the version, so that it is computed upon restore.
    3482              :      */
    3483          150 :     if (dopt->binary_upgrade)
    3484              :     {
    3485           37 :         if (!PQgetisnull(res, 0, i_datcollversion))
    3486              :         {
    3487           37 :             appendPQExpBufferStr(creaQry, " COLLATION_VERSION = ");
    3488           37 :             appendStringLiteralAH(creaQry,
    3489              :                                   PQgetvalue(res, 0, i_datcollversion),
    3490              :                                   fout);
    3491              :         }
    3492              :     }
    3493              : 
    3494              :     /*
    3495              :      * Note: looking at dopt->outputNoTablespaces here is completely the wrong
    3496              :      * thing; the decision whether to specify a tablespace should be left till
    3497              :      * pg_restore, so that pg_restore --no-tablespaces applies.  Ideally we'd
    3498              :      * label the DATABASE entry with the tablespace and let the normal
    3499              :      * tablespace selection logic work ... but CREATE DATABASE doesn't pay
    3500              :      * attention to default_tablespace, so that won't work.
    3501              :      */
    3502          150 :     if (strlen(tablespace) > 0 && strcmp(tablespace, "pg_default") != 0 &&
    3503            5 :         !dopt->outputNoTablespaces)
    3504            5 :         appendPQExpBuffer(creaQry, " TABLESPACE = %s",
    3505              :                           fmtId(tablespace));
    3506          150 :     appendPQExpBufferStr(creaQry, ";\n");
    3507              : 
    3508          150 :     appendPQExpBuffer(delQry, "DROP DATABASE %s;\n",
    3509              :                       qdatname);
    3510              : 
    3511          150 :     dbDumpId = createDumpId();
    3512              : 
    3513          150 :     ArchiveEntry(fout,
    3514              :                  dbCatId,       /* catalog ID */
    3515              :                  dbDumpId,      /* dump ID */
    3516          150 :                  ARCHIVE_OPTS(.tag = datname,
    3517              :                               .owner = dba,
    3518              :                               .description = "DATABASE",
    3519              :                               .section = SECTION_PRE_DATA,
    3520              :                               .createStmt = creaQry->data,
    3521              :                               .dropStmt = delQry->data));
    3522              : 
    3523              :     /* Compute correct tag for archive entry */
    3524          150 :     appendPQExpBuffer(labelq, "DATABASE %s", qdatname);
    3525              : 
    3526              :     /* Dump DB comment if any */
    3527              :     {
    3528              :         /*
    3529              :          * 8.2 and up keep comments on shared objects in a shared table, so we
    3530              :          * cannot use the dumpComment() code used for other database objects.
    3531              :          * Be careful that the ArchiveEntry parameters match that function.
    3532              :          */
    3533          150 :         char       *comment = PQgetvalue(res, 0, PQfnumber(res, "description"));
    3534              : 
    3535          150 :         if (comment && *comment && !dopt->no_comments)
    3536              :         {
    3537           58 :             resetPQExpBuffer(dbQry);
    3538              : 
    3539              :             /*
    3540              :              * Generates warning when loaded into a differently-named
    3541              :              * database.
    3542              :              */
    3543           58 :             appendPQExpBuffer(dbQry, "COMMENT ON DATABASE %s IS ", qdatname);
    3544           58 :             appendStringLiteralAH(dbQry, comment, fout);
    3545           58 :             appendPQExpBufferStr(dbQry, ";\n");
    3546              : 
    3547           58 :             ArchiveEntry(fout, nilCatalogId, createDumpId(),
    3548           58 :                          ARCHIVE_OPTS(.tag = labelq->data,
    3549              :                                       .owner = dba,
    3550              :                                       .description = "COMMENT",
    3551              :                                       .section = SECTION_NONE,
    3552              :                                       .createStmt = dbQry->data,
    3553              :                                       .deps = &dbDumpId,
    3554              :                                       .nDeps = 1));
    3555              :         }
    3556              :     }
    3557              : 
    3558              :     /* Dump DB security label, if enabled */
    3559          150 :     if (!dopt->no_security_labels)
    3560              :     {
    3561              :         PGresult   *shres;
    3562              :         PQExpBuffer seclabelQry;
    3563              : 
    3564          150 :         seclabelQry = createPQExpBuffer();
    3565              : 
    3566          150 :         buildShSecLabelQuery("pg_database", dbCatId.oid, seclabelQry);
    3567          150 :         shres = ExecuteSqlQuery(fout, seclabelQry->data, PGRES_TUPLES_OK);
    3568          150 :         resetPQExpBuffer(seclabelQry);
    3569          150 :         emitShSecLabels(conn, shres, seclabelQry, "DATABASE", datname);
    3570          150 :         if (seclabelQry->len > 0)
    3571            0 :             ArchiveEntry(fout, nilCatalogId, createDumpId(),
    3572            0 :                          ARCHIVE_OPTS(.tag = labelq->data,
    3573              :                                       .owner = dba,
    3574              :                                       .description = "SECURITY LABEL",
    3575              :                                       .section = SECTION_NONE,
    3576              :                                       .createStmt = seclabelQry->data,
    3577              :                                       .deps = &dbDumpId,
    3578              :                                       .nDeps = 1));
    3579          150 :         destroyPQExpBuffer(seclabelQry);
    3580          150 :         PQclear(shres);
    3581              :     }
    3582              : 
    3583              :     /*
    3584              :      * Dump ACL if any.  Note that we do not support initial privileges
    3585              :      * (pg_init_privs) on databases.
    3586              :      */
    3587          150 :     dbdacl.privtype = 0;
    3588          150 :     dbdacl.initprivs = NULL;
    3589              : 
    3590          150 :     dumpACL(fout, dbDumpId, InvalidDumpId, "DATABASE",
    3591              :             qdatname, NULL, NULL,
    3592              :             NULL, dba, &dbdacl);
    3593              : 
    3594              :     /*
    3595              :      * Now construct a DATABASE PROPERTIES archive entry to restore any
    3596              :      * non-default database-level properties.  (The reason this must be
    3597              :      * separate is that we cannot put any additional commands into the TOC
    3598              :      * entry that has CREATE DATABASE.  pg_restore would execute such a group
    3599              :      * in an implicit transaction block, and the backend won't allow CREATE
    3600              :      * DATABASE in that context.)
    3601              :      */
    3602          150 :     resetPQExpBuffer(creaQry);
    3603          150 :     resetPQExpBuffer(delQry);
    3604              : 
    3605          150 :     if (strlen(datconnlimit) > 0 && strcmp(datconnlimit, "-1") != 0)
    3606            0 :         appendPQExpBuffer(creaQry, "ALTER DATABASE %s CONNECTION LIMIT = %s;\n",
    3607              :                           qdatname, datconnlimit);
    3608              : 
    3609          150 :     if (strcmp(datistemplate, "t") == 0)
    3610              :     {
    3611           19 :         appendPQExpBuffer(creaQry, "ALTER DATABASE %s IS_TEMPLATE = true;\n",
    3612              :                           qdatname);
    3613              : 
    3614              :         /*
    3615              :          * The backend won't accept DROP DATABASE on a template database.  We
    3616              :          * can deal with that by removing the template marking before the DROP
    3617              :          * gets issued.  We'd prefer to use ALTER DATABASE IF EXISTS here, but
    3618              :          * since no such command is currently supported, fake it with a direct
    3619              :          * UPDATE on pg_database.
    3620              :          */
    3621           19 :         appendPQExpBufferStr(delQry, "UPDATE pg_catalog.pg_database "
    3622              :                              "SET datistemplate = false WHERE datname = ");
    3623           19 :         appendStringLiteralAH(delQry, datname, fout);
    3624           19 :         appendPQExpBufferStr(delQry, ";\n");
    3625              :     }
    3626              : 
    3627              :     /*
    3628              :      * We do not restore pg_database.dathasloginevt because it is set
    3629              :      * automatically on login event trigger creation.
    3630              :      */
    3631              : 
    3632              :     /* Add database-specific SET options */
    3633          150 :     dumpDatabaseConfig(fout, creaQry, datname, dbCatId.oid);
    3634              : 
    3635              :     /*
    3636              :      * We stick this binary-upgrade query into the DATABASE PROPERTIES archive
    3637              :      * entry, too, for lack of a better place.
    3638              :      */
    3639          150 :     if (dopt->binary_upgrade)
    3640              :     {
    3641           37 :         appendPQExpBufferStr(creaQry, "\n-- For binary upgrade, set datfrozenxid and datminmxid.\n");
    3642           37 :         appendPQExpBuffer(creaQry, "UPDATE pg_catalog.pg_database\n"
    3643              :                           "SET datfrozenxid = '%u', datminmxid = '%u'\n"
    3644              :                           "WHERE datname = ",
    3645              :                           frozenxid, minmxid);
    3646           37 :         appendStringLiteralAH(creaQry, datname, fout);
    3647           37 :         appendPQExpBufferStr(creaQry, ";\n");
    3648              :     }
    3649              : 
    3650          150 :     if (creaQry->len > 0)
    3651           49 :         ArchiveEntry(fout, nilCatalogId, createDumpId(),
    3652           49 :                      ARCHIVE_OPTS(.tag = datname,
    3653              :                                   .owner = dba,
    3654              :                                   .description = "DATABASE PROPERTIES",
    3655              :                                   .section = SECTION_PRE_DATA,
    3656              :                                   .createStmt = creaQry->data,
    3657              :                                   .dropStmt = delQry->data,
    3658              :                                   .deps = &dbDumpId));
    3659              : 
    3660              :     /*
    3661              :      * pg_largeobject comes from the old system intact, so set its
    3662              :      * relfrozenxids, relminmxids and relfilenode.
    3663              :      *
    3664              :      * pg_largeobject_metadata also comes from the old system intact for
    3665              :      * upgrades from v16 and newer, so set its relfrozenxids, relminmxids, and
    3666              :      * relfilenode, too.  pg_upgrade can't copy/link the files from older
    3667              :      * versions because aclitem (needed by pg_largeobject_metadata.lomacl)
    3668              :      * changed its storage format in v16.
    3669              :      */
    3670          150 :     if (dopt->binary_upgrade)
    3671              :     {
    3672              :         PGresult   *lo_res;
    3673           37 :         PQExpBuffer loFrozenQry = createPQExpBuffer();
    3674           37 :         PQExpBuffer loOutQry = createPQExpBuffer();
    3675           37 :         PQExpBuffer lomOutQry = createPQExpBuffer();
    3676           37 :         PQExpBuffer loHorizonQry = createPQExpBuffer();
    3677           37 :         PQExpBuffer lomHorizonQry = createPQExpBuffer();
    3678              :         int         ii_relfrozenxid,
    3679              :                     ii_relfilenode,
    3680              :                     ii_oid,
    3681              :                     ii_relminmxid;
    3682              : 
    3683           37 :         if (fout->remoteVersion >= 90300)
    3684           37 :             appendPQExpBuffer(loFrozenQry, "SELECT relfrozenxid, relminmxid, relfilenode, oid\n"
    3685              :                               "FROM pg_catalog.pg_class\n"
    3686              :                               "WHERE oid IN (%u, %u, %u, %u);\n",
    3687              :                               LargeObjectRelationId, LargeObjectLOidPNIndexId,
    3688              :                               LargeObjectMetadataRelationId, LargeObjectMetadataOidIndexId);
    3689              :         else
    3690            0 :             appendPQExpBuffer(loFrozenQry, "SELECT relfrozenxid, 0 AS relminmxid, relfilenode, oid\n"
    3691              :                               "FROM pg_catalog.pg_class\n"
    3692              :                               "WHERE oid IN (%u, %u);\n",
    3693              :                               LargeObjectRelationId, LargeObjectLOidPNIndexId);
    3694              : 
    3695           37 :         lo_res = ExecuteSqlQuery(fout, loFrozenQry->data, PGRES_TUPLES_OK);
    3696              : 
    3697           37 :         ii_relfrozenxid = PQfnumber(lo_res, "relfrozenxid");
    3698           37 :         ii_relminmxid = PQfnumber(lo_res, "relminmxid");
    3699           37 :         ii_relfilenode = PQfnumber(lo_res, "relfilenode");
    3700           37 :         ii_oid = PQfnumber(lo_res, "oid");
    3701              : 
    3702           37 :         appendPQExpBufferStr(loHorizonQry, "\n-- For binary upgrade, set pg_largeobject relfrozenxid and relminmxid\n");
    3703           37 :         appendPQExpBufferStr(lomHorizonQry, "\n-- For binary upgrade, set pg_largeobject_metadata relfrozenxid and relminmxid\n");
    3704           37 :         appendPQExpBufferStr(loOutQry, "\n-- For binary upgrade, preserve pg_largeobject and index relfilenodes\n");
    3705           37 :         appendPQExpBufferStr(lomOutQry, "\n-- For binary upgrade, preserve pg_largeobject_metadata and index relfilenodes\n");
    3706          185 :         for (int i = 0; i < PQntuples(lo_res); ++i)
    3707              :         {
    3708              :             Oid         oid;
    3709              :             RelFileNumber relfilenumber;
    3710              :             PQExpBuffer horizonQry;
    3711              :             PQExpBuffer outQry;
    3712              : 
    3713          148 :             oid = atooid(PQgetvalue(lo_res, i, ii_oid));
    3714          148 :             relfilenumber = atooid(PQgetvalue(lo_res, i, ii_relfilenode));
    3715              : 
    3716          148 :             if (oid == LargeObjectRelationId ||
    3717              :                 oid == LargeObjectLOidPNIndexId)
    3718              :             {
    3719           74 :                 horizonQry = loHorizonQry;
    3720           74 :                 outQry = loOutQry;
    3721              :             }
    3722              :             else
    3723              :             {
    3724           74 :                 horizonQry = lomHorizonQry;
    3725           74 :                 outQry = lomOutQry;
    3726              :             }
    3727              : 
    3728          148 :             appendPQExpBuffer(horizonQry, "UPDATE pg_catalog.pg_class\n"
    3729              :                               "SET relfrozenxid = '%u', relminmxid = '%u'\n"
    3730              :                               "WHERE oid = %u;\n",
    3731          148 :                               atooid(PQgetvalue(lo_res, i, ii_relfrozenxid)),
    3732          148 :                               atooid(PQgetvalue(lo_res, i, ii_relminmxid)),
    3733          148 :                               atooid(PQgetvalue(lo_res, i, ii_oid)));
    3734              : 
    3735          148 :             if (oid == LargeObjectRelationId ||
    3736              :                 oid == LargeObjectMetadataRelationId)
    3737           74 :                 appendPQExpBuffer(outQry,
    3738              :                                   "SELECT pg_catalog.binary_upgrade_set_next_heap_relfilenode('%u'::pg_catalog.oid);\n",
    3739              :                                   relfilenumber);
    3740           74 :             else if (oid == LargeObjectLOidPNIndexId ||
    3741              :                      oid == LargeObjectMetadataOidIndexId)
    3742           74 :                 appendPQExpBuffer(outQry,
    3743              :                                   "SELECT pg_catalog.binary_upgrade_set_next_index_relfilenode('%u'::pg_catalog.oid);\n",
    3744              :                                   relfilenumber);
    3745              :         }
    3746              : 
    3747           37 :         appendPQExpBufferStr(loOutQry,
    3748              :                              "TRUNCATE pg_catalog.pg_largeobject;\n");
    3749           37 :         appendPQExpBufferStr(lomOutQry,
    3750              :                              "TRUNCATE pg_catalog.pg_largeobject_metadata;\n");
    3751              : 
    3752           37 :         appendPQExpBufferStr(loOutQry, loHorizonQry->data);
    3753           37 :         appendPQExpBufferStr(lomOutQry, lomHorizonQry->data);
    3754              : 
    3755           37 :         ArchiveEntry(fout, nilCatalogId, createDumpId(),
    3756           37 :                      ARCHIVE_OPTS(.tag = "pg_largeobject",
    3757              :                                   .description = "pg_largeobject",
    3758              :                                   .section = SECTION_PRE_DATA,
    3759              :                                   .createStmt = loOutQry->data));
    3760              : 
    3761           37 :         if (fout->remoteVersion >= 160000)
    3762           37 :             ArchiveEntry(fout, nilCatalogId, createDumpId(),
    3763           37 :                          ARCHIVE_OPTS(.tag = "pg_largeobject_metadata",
    3764              :                                       .description = "pg_largeobject_metadata",
    3765              :                                       .section = SECTION_PRE_DATA,
    3766              :                                       .createStmt = lomOutQry->data));
    3767              : 
    3768           37 :         PQclear(lo_res);
    3769              : 
    3770           37 :         destroyPQExpBuffer(loFrozenQry);
    3771           37 :         destroyPQExpBuffer(loHorizonQry);
    3772           37 :         destroyPQExpBuffer(lomHorizonQry);
    3773           37 :         destroyPQExpBuffer(loOutQry);
    3774           37 :         destroyPQExpBuffer(lomOutQry);
    3775              :     }
    3776              : 
    3777          150 :     PQclear(res);
    3778              : 
    3779          150 :     free(qdatname);
    3780          150 :     destroyPQExpBuffer(dbQry);
    3781          150 :     destroyPQExpBuffer(delQry);
    3782          150 :     destroyPQExpBuffer(creaQry);
    3783          150 :     destroyPQExpBuffer(labelq);
    3784          150 : }
    3785              : 
    3786              : /*
    3787              :  * Collect any database-specific or role-and-database-specific SET options
    3788              :  * for this database, and append them to outbuf.
    3789              :  */
    3790              : static void
    3791          150 : dumpDatabaseConfig(Archive *AH, PQExpBuffer outbuf,
    3792              :                    const char *dbname, Oid dboid)
    3793              : {
    3794          150 :     PGconn     *conn = GetConnection(AH);
    3795          150 :     PQExpBuffer buf = createPQExpBuffer();
    3796              :     PGresult   *res;
    3797              : 
    3798              :     /* First collect database-specific options */
    3799          150 :     printfPQExpBuffer(buf, "SELECT unnest(setconfig) FROM pg_db_role_setting "
    3800              :                       "WHERE setrole = 0 AND setdatabase = '%u'::oid",
    3801              :                       dboid);
    3802              : 
    3803          150 :     res = ExecuteSqlQuery(AH, buf->data, PGRES_TUPLES_OK);
    3804              : 
    3805          180 :     for (int i = 0; i < PQntuples(res); i++)
    3806           30 :         makeAlterConfigCommand(conn, PQgetvalue(res, i, 0),
    3807              :                                "DATABASE", dbname, NULL, NULL,
    3808              :                                outbuf);
    3809              : 
    3810          150 :     PQclear(res);
    3811              : 
    3812              :     /* Now look for role-and-database-specific options */
    3813          150 :     printfPQExpBuffer(buf, "SELECT rolname, unnest(setconfig) "
    3814              :                       "FROM pg_db_role_setting s, pg_roles r "
    3815              :                       "WHERE setrole = r.oid AND setdatabase = '%u'::oid",
    3816              :                       dboid);
    3817              : 
    3818          150 :     res = ExecuteSqlQuery(AH, buf->data, PGRES_TUPLES_OK);
    3819              : 
    3820          150 :     for (int i = 0; i < PQntuples(res); i++)
    3821            0 :         makeAlterConfigCommand(conn, PQgetvalue(res, i, 1),
    3822            0 :                                "ROLE", PQgetvalue(res, i, 0),
    3823              :                                "DATABASE", dbname,
    3824              :                                outbuf);
    3825              : 
    3826          150 :     PQclear(res);
    3827              : 
    3828          150 :     destroyPQExpBuffer(buf);
    3829          150 : }
    3830              : 
    3831              : /*
    3832              :  * dumpEncoding: put the correct encoding into the archive
    3833              :  */
    3834              : static void
    3835          249 : dumpEncoding(Archive *AH)
    3836              : {
    3837          249 :     const char *encname = pg_encoding_to_char(AH->encoding);
    3838          249 :     PQExpBuffer qry = createPQExpBuffer();
    3839              : 
    3840          249 :     pg_log_info("saving encoding = %s", encname);
    3841              : 
    3842          249 :     appendPQExpBufferStr(qry, "SET client_encoding = ");
    3843          249 :     appendStringLiteralAH(qry, encname, AH);
    3844          249 :     appendPQExpBufferStr(qry, ";\n");
    3845              : 
    3846          249 :     ArchiveEntry(AH, nilCatalogId, createDumpId(),
    3847          249 :                  ARCHIVE_OPTS(.tag = "ENCODING",
    3848              :                               .description = "ENCODING",
    3849              :                               .section = SECTION_PRE_DATA,
    3850              :                               .createStmt = qry->data));
    3851              : 
    3852          249 :     destroyPQExpBuffer(qry);
    3853          249 : }
    3854              : 
    3855              : 
    3856              : /*
    3857              :  * dumpStdStrings: put the correct escape string behavior into the archive
    3858              :  */
    3859              : static void
    3860          249 : dumpStdStrings(Archive *AH)
    3861              : {
    3862          249 :     const char *stdstrings = AH->std_strings ? "on" : "off";
    3863          249 :     PQExpBuffer qry = createPQExpBuffer();
    3864              : 
    3865          249 :     pg_log_info("saving \"standard_conforming_strings = %s\"",
    3866              :                 stdstrings);
    3867              : 
    3868          249 :     appendPQExpBuffer(qry, "SET standard_conforming_strings = '%s';\n",
    3869              :                       stdstrings);
    3870              : 
    3871          249 :     ArchiveEntry(AH, nilCatalogId, createDumpId(),
    3872          249 :                  ARCHIVE_OPTS(.tag = "STDSTRINGS",
    3873              :                               .description = "STDSTRINGS",
    3874              :                               .section = SECTION_PRE_DATA,
    3875              :                               .createStmt = qry->data));
    3876              : 
    3877          249 :     destroyPQExpBuffer(qry);
    3878          249 : }
    3879              : 
    3880              : /*
    3881              :  * dumpSearchPath: record the active search_path in the archive
    3882              :  */
    3883              : static void
    3884          249 : dumpSearchPath(Archive *AH)
    3885              : {
    3886          249 :     PQExpBuffer qry = createPQExpBuffer();
    3887          249 :     PQExpBuffer path = createPQExpBuffer();
    3888              :     PGresult   *res;
    3889          249 :     char      **schemanames = NULL;
    3890          249 :     int         nschemanames = 0;
    3891              :     int         i;
    3892              : 
    3893              :     /*
    3894              :      * We use the result of current_schemas(), not the search_path GUC,
    3895              :      * because that might contain wildcards such as "$user", which won't
    3896              :      * necessarily have the same value during restore.  Also, this way avoids
    3897              :      * listing schemas that may appear in search_path but not actually exist,
    3898              :      * which seems like a prudent exclusion.
    3899              :      */
    3900          249 :     res = ExecuteSqlQueryForSingleRow(AH,
    3901              :                                       "SELECT pg_catalog.current_schemas(false)");
    3902              : 
    3903          249 :     if (!parsePGArray(PQgetvalue(res, 0, 0), &schemanames, &nschemanames))
    3904            0 :         pg_fatal("could not parse result of current_schemas()");
    3905              : 
    3906              :     /*
    3907              :      * We use set_config(), not a simple "SET search_path" command, because
    3908              :      * the latter has less-clean behavior if the search path is empty.  While
    3909              :      * that's likely to get fixed at some point, it seems like a good idea to
    3910              :      * be as backwards-compatible as possible in what we put into archives.
    3911              :      */
    3912          249 :     for (i = 0; i < nschemanames; i++)
    3913              :     {
    3914            0 :         if (i > 0)
    3915            0 :             appendPQExpBufferStr(path, ", ");
    3916            0 :         appendPQExpBufferStr(path, fmtId(schemanames[i]));
    3917              :     }
    3918              : 
    3919          249 :     appendPQExpBufferStr(qry, "SELECT pg_catalog.set_config('search_path', ");
    3920          249 :     appendStringLiteralAH(qry, path->data, AH);
    3921          249 :     appendPQExpBufferStr(qry, ", false);\n");
    3922              : 
    3923          249 :     pg_log_info("saving \"search_path = %s\"", path->data);
    3924              : 
    3925          249 :     ArchiveEntry(AH, nilCatalogId, createDumpId(),
    3926          249 :                  ARCHIVE_OPTS(.tag = "SEARCHPATH",
    3927              :                               .description = "SEARCHPATH",
    3928              :                               .section = SECTION_PRE_DATA,
    3929              :                               .createStmt = qry->data));
    3930              : 
    3931              :     /* Also save it in AH->searchpath, in case we're doing plain text dump */
    3932          249 :     AH->searchpath = pg_strdup(qry->data);
    3933              : 
    3934          249 :     free(schemanames);
    3935          249 :     PQclear(res);
    3936          249 :     destroyPQExpBuffer(qry);
    3937          249 :     destroyPQExpBuffer(path);
    3938          249 : }
    3939              : 
    3940              : 
    3941              : /*
    3942              :  * getLOs:
    3943              :  *  Collect schema-level data about large objects
    3944              :  */
    3945              : static void
    3946          221 : getLOs(Archive *fout)
    3947              : {
    3948          221 :     DumpOptions *dopt = fout->dopt;
    3949          221 :     PQExpBuffer loQry = createPQExpBuffer();
    3950              :     PGresult   *res;
    3951              :     int         ntups;
    3952              :     int         i;
    3953              :     int         n;
    3954              :     int         i_oid;
    3955              :     int         i_lomowner;
    3956              :     int         i_lomacl;
    3957              :     int         i_acldefault;
    3958              : 
    3959          221 :     pg_log_info("reading large objects");
    3960              : 
    3961              :     /*
    3962              :      * Fetch LO OIDs and owner/ACL data.  Order the data so that all the blobs
    3963              :      * with the same owner/ACL appear together.
    3964              :      */
    3965          221 :     appendPQExpBufferStr(loQry,
    3966              :                          "SELECT oid, lomowner, lomacl, "
    3967              :                          "acldefault('L', lomowner) AS acldefault "
    3968              :                          "FROM pg_largeobject_metadata ");
    3969              : 
    3970              :     /*
    3971              :      * For binary upgrades, we transfer pg_largeobject_metadata via COPY or by
    3972              :      * copying/linking its files from the old cluster.  On such upgrades, we
    3973              :      * only need to consider large objects that have comments or security
    3974              :      * labels, since we still restore those objects via COMMENT/SECURITY LABEL
    3975              :      * commands.
    3976              :      */
    3977          221 :     if (dopt->binary_upgrade)
    3978           38 :         appendPQExpBufferStr(loQry,
    3979              :                              "WHERE oid IN "
    3980              :                              "(SELECT objoid FROM pg_description "
    3981              :                              "WHERE classoid = " CppAsString2(LargeObjectRelationId) " "
    3982              :                              "UNION SELECT objoid FROM pg_seclabel "
    3983              :                              "WHERE classoid = " CppAsString2(LargeObjectRelationId) ") ");
    3984              : 
    3985          221 :     appendPQExpBufferStr(loQry,
    3986              :                          "ORDER BY lomowner, lomacl::pg_catalog.text, oid");
    3987              : 
    3988          221 :     res = ExecuteSqlQuery(fout, loQry->data, PGRES_TUPLES_OK);
    3989              : 
    3990          221 :     i_oid = PQfnumber(res, "oid");
    3991          221 :     i_lomowner = PQfnumber(res, "lomowner");
    3992          221 :     i_lomacl = PQfnumber(res, "lomacl");
    3993          221 :     i_acldefault = PQfnumber(res, "acldefault");
    3994              : 
    3995          221 :     ntups = PQntuples(res);
    3996              : 
    3997              :     /*
    3998              :      * Group the blobs into suitably-sized groups that have the same owner and
    3999              :      * ACL setting, and build a metadata and a data DumpableObject for each
    4000              :      * group.  (If we supported initprivs for blobs, we'd have to insist that
    4001              :      * groups also share initprivs settings, since the DumpableObject only has
    4002              :      * room for one.)  i is the index of the first tuple in the current group,
    4003              :      * and n is the number of tuples we include in the group.
    4004              :      */
    4005          305 :     for (i = 0; i < ntups; i += n)
    4006              :     {
    4007           84 :         Oid         thisoid = atooid(PQgetvalue(res, i, i_oid));
    4008           84 :         char       *thisowner = PQgetvalue(res, i, i_lomowner);
    4009           84 :         char       *thisacl = PQgetvalue(res, i, i_lomacl);
    4010              :         LoInfo     *loinfo;
    4011              :         DumpableObject *lodata;
    4012              :         char        namebuf[64];
    4013              : 
    4014              :         /* Scan to find first tuple not to be included in group */
    4015           84 :         n = 1;
    4016           98 :         while (n < MAX_BLOBS_PER_ARCHIVE_ENTRY && i + n < ntups)
    4017              :         {
    4018           47 :             if (strcmp(thisowner, PQgetvalue(res, i + n, i_lomowner)) != 0 ||
    4019           47 :                 strcmp(thisacl, PQgetvalue(res, i + n, i_lomacl)) != 0)
    4020              :                 break;
    4021           14 :             n++;
    4022              :         }
    4023              : 
    4024              :         /* Build the metadata DumpableObject */
    4025           84 :         loinfo = (LoInfo *) pg_malloc(offsetof(LoInfo, looids) + n * sizeof(Oid));
    4026              : 
    4027           84 :         loinfo->dobj.objType = DO_LARGE_OBJECT;
    4028           84 :         loinfo->dobj.catId.tableoid = LargeObjectRelationId;
    4029           84 :         loinfo->dobj.catId.oid = thisoid;
    4030           84 :         AssignDumpId(&loinfo->dobj);
    4031              : 
    4032           84 :         if (n > 1)
    4033           10 :             snprintf(namebuf, sizeof(namebuf), "%u..%u", thisoid,
    4034           10 :                      atooid(PQgetvalue(res, i + n - 1, i_oid)));
    4035              :         else
    4036           74 :             snprintf(namebuf, sizeof(namebuf), "%u", thisoid);
    4037           84 :         loinfo->dobj.name = pg_strdup(namebuf);
    4038           84 :         loinfo->dacl.acl = pg_strdup(thisacl);
    4039           84 :         loinfo->dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
    4040           84 :         loinfo->dacl.privtype = 0;
    4041           84 :         loinfo->dacl.initprivs = NULL;
    4042           84 :         loinfo->rolname = getRoleName(thisowner);
    4043           84 :         loinfo->numlos = n;
    4044           84 :         loinfo->looids[0] = thisoid;
    4045              :         /* Collect OIDs of the remaining blobs in this group */
    4046           98 :         for (int k = 1; k < n; k++)
    4047              :         {
    4048              :             CatalogId   extraID;
    4049              : 
    4050           14 :             loinfo->looids[k] = atooid(PQgetvalue(res, i + k, i_oid));
    4051              : 
    4052              :             /* Make sure we can look up loinfo by any of the blobs' OIDs */
    4053           14 :             extraID.tableoid = LargeObjectRelationId;
    4054           14 :             extraID.oid = loinfo->looids[k];
    4055           14 :             recordAdditionalCatalogID(extraID, &loinfo->dobj);
    4056              :         }
    4057              : 
    4058              :         /* LOs have data */
    4059           84 :         loinfo->dobj.components |= DUMP_COMPONENT_DATA;
    4060              : 
    4061              :         /* Mark whether LO group has a non-empty ACL */
    4062           84 :         if (!PQgetisnull(res, i, i_lomacl))
    4063           34 :             loinfo->dobj.components |= DUMP_COMPONENT_ACL;
    4064              : 
    4065              :         /*
    4066              :          * In binary upgrade mode, pg_largeobject and pg_largeobject_metadata
    4067              :          * are transferred via COPY or by copying/linking the files from the
    4068              :          * old cluster.  Thus, we do not need to dump LO data, definitions, or
    4069              :          * ACLs.
    4070              :          */
    4071           84 :         if (dopt->binary_upgrade)
    4072            7 :             loinfo->dobj.dump &= ~(DUMP_COMPONENT_DATA | DUMP_COMPONENT_ACL | DUMP_COMPONENT_DEFINITION);
    4073              : 
    4074              :         /*
    4075              :          * Create a "BLOBS" data item for the group, too. This is just a
    4076              :          * placeholder for sorting; it carries no data now.
    4077              :          */
    4078           84 :         lodata = pg_malloc_object(DumpableObject);
    4079           84 :         lodata->objType = DO_LARGE_OBJECT_DATA;
    4080           84 :         lodata->catId = nilCatalogId;
    4081           84 :         AssignDumpId(lodata);
    4082           84 :         lodata->name = pg_strdup(namebuf);
    4083           84 :         lodata->components |= DUMP_COMPONENT_DATA;
    4084              :         /* Set up explicit dependency from data to metadata */
    4085           84 :         lodata->dependencies = pg_malloc_object(DumpId);
    4086           84 :         lodata->dependencies[0] = loinfo->dobj.dumpId;
    4087           84 :         lodata->nDeps = lodata->allocDeps = 1;
    4088              :     }
    4089              : 
    4090          221 :     PQclear(res);
    4091          221 :     destroyPQExpBuffer(loQry);
    4092          221 : }
    4093              : 
    4094              : /*
    4095              :  * dumpLO
    4096              :  *
    4097              :  * dump the definition (metadata) of the given large object group
    4098              :  */
    4099              : static void
    4100           84 : dumpLO(Archive *fout, const LoInfo *loinfo)
    4101              : {
    4102           84 :     PQExpBuffer cquery = createPQExpBuffer();
    4103              : 
    4104              :     /*
    4105              :      * The "definition" is just a newline-separated list of OIDs.  We need to
    4106              :      * put something into the dropStmt too, but it can just be a comment.
    4107              :      */
    4108          182 :     for (int i = 0; i < loinfo->numlos; i++)
    4109           98 :         appendPQExpBuffer(cquery, "%u\n", loinfo->looids[i]);
    4110              : 
    4111           84 :     if (loinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
    4112           77 :         ArchiveEntry(fout, loinfo->dobj.catId, loinfo->dobj.dumpId,
    4113           77 :                      ARCHIVE_OPTS(.tag = loinfo->dobj.name,
    4114              :                                   .owner = loinfo->rolname,
    4115              :                                   .description = "BLOB METADATA",
    4116              :                                   .section = SECTION_DATA,
    4117              :                                   .createStmt = cquery->data,
    4118              :                                   .dropStmt = "-- dummy"));
    4119              : 
    4120              :     /*
    4121              :      * Dump per-blob comments and seclabels if any.  We assume these are rare
    4122              :      * enough that it's okay to generate retail TOC entries for them.
    4123              :      */
    4124           84 :     if (loinfo->dobj.dump & (DUMP_COMPONENT_COMMENT |
    4125              :                              DUMP_COMPONENT_SECLABEL))
    4126              :     {
    4127          102 :         for (int i = 0; i < loinfo->numlos; i++)
    4128              :         {
    4129              :             CatalogId   catId;
    4130              :             char        namebuf[32];
    4131              : 
    4132              :             /* Build identifying info for this blob */
    4133           58 :             catId.tableoid = loinfo->dobj.catId.tableoid;
    4134           58 :             catId.oid = loinfo->looids[i];
    4135           58 :             snprintf(namebuf, sizeof(namebuf), "%u", loinfo->looids[i]);
    4136              : 
    4137           58 :             if (loinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
    4138           58 :                 dumpComment(fout, "LARGE OBJECT", namebuf,
    4139           58 :                             NULL, loinfo->rolname,
    4140           58 :                             catId, 0, loinfo->dobj.dumpId);
    4141              : 
    4142           58 :             if (loinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
    4143           10 :                 dumpSecLabel(fout, "LARGE OBJECT", namebuf,
    4144           10 :                              NULL, loinfo->rolname,
    4145           10 :                              catId, 0, loinfo->dobj.dumpId);
    4146              :         }
    4147              :     }
    4148              : 
    4149              :     /*
    4150              :      * Dump the ACLs if any (remember that all blobs in the group will have
    4151              :      * the same ACL).  If there's just one blob, dump a simple ACL entry; if
    4152              :      * there's more, make a "LARGE OBJECTS" entry that really contains only
    4153              :      * the ACL for the first blob.  _printTocEntry() will be cued by the tag
    4154              :      * string to emit a mutated version for each blob.
    4155              :      */
    4156           84 :     if (loinfo->dobj.dump & DUMP_COMPONENT_ACL)
    4157              :     {
    4158              :         char        namebuf[32];
    4159              : 
    4160              :         /* Build identifying info for the first blob */
    4161           33 :         snprintf(namebuf, sizeof(namebuf), "%u", loinfo->looids[0]);
    4162              : 
    4163           33 :         if (loinfo->numlos > 1)
    4164              :         {
    4165              :             char        tagbuf[64];
    4166              : 
    4167            0 :             snprintf(tagbuf, sizeof(tagbuf), "LARGE OBJECTS %u..%u",
    4168            0 :                      loinfo->looids[0], loinfo->looids[loinfo->numlos - 1]);
    4169              : 
    4170            0 :             dumpACL(fout, loinfo->dobj.dumpId, InvalidDumpId,
    4171              :                     "LARGE OBJECT", namebuf, NULL, NULL,
    4172            0 :                     tagbuf, loinfo->rolname, &loinfo->dacl);
    4173              :         }
    4174              :         else
    4175              :         {
    4176           33 :             dumpACL(fout, loinfo->dobj.dumpId, InvalidDumpId,
    4177              :                     "LARGE OBJECT", namebuf, NULL, NULL,
    4178           33 :                     NULL, loinfo->rolname, &loinfo->dacl);
    4179              :         }
    4180              :     }
    4181              : 
    4182           84 :     destroyPQExpBuffer(cquery);
    4183           84 : }
    4184              : 
    4185              : /*
    4186              :  * dumpLOs:
    4187              :  *  dump the data contents of the large objects in the given group
    4188              :  */
    4189              : static int
    4190           73 : dumpLOs(Archive *fout, const void *arg)
    4191              : {
    4192           73 :     const LoInfo *loinfo = (const LoInfo *) arg;
    4193           73 :     PGconn     *conn = GetConnection(fout);
    4194              :     char        buf[LOBBUFSIZE];
    4195              : 
    4196           73 :     pg_log_info("saving large objects \"%s\"", loinfo->dobj.name);
    4197              : 
    4198          154 :     for (int i = 0; i < loinfo->numlos; i++)
    4199              :     {
    4200           81 :         Oid         loOid = loinfo->looids[i];
    4201              :         int         loFd;
    4202              :         int         cnt;
    4203              : 
    4204              :         /* Open the LO */
    4205           81 :         loFd = lo_open(conn, loOid, INV_READ);
    4206           81 :         if (loFd == -1)
    4207            0 :             pg_fatal("could not open large object %u: %s",
    4208              :                      loOid, PQerrorMessage(conn));
    4209              : 
    4210           81 :         StartLO(fout, loOid);
    4211              : 
    4212              :         /* Now read it in chunks, sending data to archive */
    4213              :         do
    4214              :         {
    4215          127 :             cnt = lo_read(conn, loFd, buf, LOBBUFSIZE);
    4216          127 :             if (cnt < 0)
    4217            0 :                 pg_fatal("error reading large object %u: %s",
    4218              :                          loOid, PQerrorMessage(conn));
    4219              : 
    4220          127 :             WriteData(fout, buf, cnt);
    4221          127 :         } while (cnt > 0);
    4222              : 
    4223           81 :         lo_close(conn, loFd);
    4224              : 
    4225           81 :         EndLO(fout, loOid);
    4226              :     }
    4227              : 
    4228           73 :     return 1;
    4229              : }
    4230              : 
    4231              : /*
    4232              :  * getPolicies
    4233              :  *    get information about all RLS policies on dumpable tables.
    4234              :  */
    4235              : void
    4236          249 : getPolicies(Archive *fout, TableInfo tblinfo[], int numTables)
    4237              : {
    4238          249 :     DumpOptions *dopt = fout->dopt;
    4239              :     PQExpBuffer query;
    4240              :     PQExpBuffer tbloids;
    4241              :     PGresult   *res;
    4242              :     PolicyInfo *polinfo;
    4243              :     int         i_oid;
    4244              :     int         i_tableoid;
    4245              :     int         i_polrelid;
    4246              :     int         i_polname;
    4247              :     int         i_polcmd;
    4248              :     int         i_polpermissive;
    4249              :     int         i_polroles;
    4250              :     int         i_polqual;
    4251              :     int         i_polwithcheck;
    4252              :     int         i,
    4253              :                 j,
    4254              :                 ntups;
    4255              : 
    4256              :     /* No policies before 9.5 */
    4257          249 :     if (fout->remoteVersion < 90500)
    4258            0 :         return;
    4259              : 
    4260              :     /* Skip if --no-policies was specified */
    4261          249 :     if (dopt->no_policies)
    4262            1 :         return;
    4263              : 
    4264          248 :     query = createPQExpBuffer();
    4265          248 :     tbloids = createPQExpBuffer();
    4266              : 
    4267              :     /*
    4268              :      * Identify tables of interest, and check which ones have RLS enabled.
    4269              :      */
    4270          248 :     appendPQExpBufferChar(tbloids, '{');
    4271        62791 :     for (i = 0; i < numTables; i++)
    4272              :     {
    4273        62543 :         TableInfo  *tbinfo = &tblinfo[i];
    4274              : 
    4275              :         /* Ignore row security on tables not to be dumped */
    4276        62543 :         if (!(tbinfo->dobj.dump & DUMP_COMPONENT_POLICY))
    4277        55433 :             continue;
    4278              : 
    4279              :         /* It can't have RLS or policies if it's not a table */
    4280         7110 :         if (tbinfo->relkind != RELKIND_RELATION &&
    4281         1954 :             tbinfo->relkind != RELKIND_PARTITIONED_TABLE)
    4282         1358 :             continue;
    4283              : 
    4284              :         /* Add it to the list of table OIDs to be probed below */
    4285         5752 :         if (tbloids->len > 1) /* do we have more than the '{'? */
    4286         5583 :             appendPQExpBufferChar(tbloids, ',');
    4287         5752 :         appendPQExpBuffer(tbloids, "%u", tbinfo->dobj.catId.oid);
    4288              : 
    4289              :         /* Is RLS enabled?  (That's separate from whether it has policies) */
    4290         5752 :         if (tbinfo->rowsec)
    4291              :         {
    4292           53 :             tbinfo->dobj.components |= DUMP_COMPONENT_POLICY;
    4293              : 
    4294              :             /*
    4295              :              * We represent RLS being enabled on a table by creating a
    4296              :              * PolicyInfo object with null polname.
    4297              :              *
    4298              :              * Note: use tableoid 0 so that this object won't be mistaken for
    4299              :              * something that pg_depend entries apply to.
    4300              :              */
    4301           53 :             polinfo = pg_malloc_object(PolicyInfo);
    4302           53 :             polinfo->dobj.objType = DO_POLICY;
    4303           53 :             polinfo->dobj.catId.tableoid = 0;
    4304           53 :             polinfo->dobj.catId.oid = tbinfo->dobj.catId.oid;
    4305           53 :             AssignDumpId(&polinfo->dobj);
    4306           53 :             polinfo->dobj.namespace = tbinfo->dobj.namespace;
    4307           53 :             polinfo->dobj.name = pg_strdup(tbinfo->dobj.name);
    4308           53 :             polinfo->poltable = tbinfo;
    4309           53 :             polinfo->polname = NULL;
    4310           53 :             polinfo->polcmd = '\0';
    4311           53 :             polinfo->polpermissive = 0;
    4312           53 :             polinfo->polroles = NULL;
    4313           53 :             polinfo->polqual = NULL;
    4314           53 :             polinfo->polwithcheck = NULL;
    4315              :         }
    4316              :     }
    4317          248 :     appendPQExpBufferChar(tbloids, '}');
    4318              : 
    4319              :     /*
    4320              :      * Now, read all RLS policies belonging to the tables of interest, and
    4321              :      * create PolicyInfo objects for them.  (Note that we must filter the
    4322              :      * results server-side not locally, because we dare not apply pg_get_expr
    4323              :      * to tables we don't have lock on.)
    4324              :      */
    4325          248 :     pg_log_info("reading row-level security policies");
    4326              : 
    4327          248 :     printfPQExpBuffer(query,
    4328              :                       "SELECT pol.oid, pol.tableoid, pol.polrelid, pol.polname, pol.polcmd, ");
    4329          248 :     if (fout->remoteVersion >= 100000)
    4330          248 :         appendPQExpBufferStr(query, "pol.polpermissive, ");
    4331              :     else
    4332            0 :         appendPQExpBufferStr(query, "'t' as polpermissive, ");
    4333          248 :     appendPQExpBuffer(query,
    4334              :                       "CASE WHEN pol.polroles = '{0}' THEN NULL ELSE "
    4335              :                       "   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, "
    4336              :                       "pg_catalog.pg_get_expr(pol.polqual, pol.polrelid) AS polqual, "
    4337              :                       "pg_catalog.pg_get_expr(pol.polwithcheck, pol.polrelid) AS polwithcheck "
    4338              :                       "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
    4339              :                       "JOIN pg_catalog.pg_policy pol ON (src.tbloid = pol.polrelid)",
    4340              :                       tbloids->data);
    4341              : 
    4342          248 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    4343              : 
    4344          248 :     ntups = PQntuples(res);
    4345          248 :     if (ntups > 0)
    4346              :     {
    4347           43 :         i_oid = PQfnumber(res, "oid");
    4348           43 :         i_tableoid = PQfnumber(res, "tableoid");
    4349           43 :         i_polrelid = PQfnumber(res, "polrelid");
    4350           43 :         i_polname = PQfnumber(res, "polname");
    4351           43 :         i_polcmd = PQfnumber(res, "polcmd");
    4352           43 :         i_polpermissive = PQfnumber(res, "polpermissive");
    4353           43 :         i_polroles = PQfnumber(res, "polroles");
    4354           43 :         i_polqual = PQfnumber(res, "polqual");
    4355           43 :         i_polwithcheck = PQfnumber(res, "polwithcheck");
    4356              : 
    4357           43 :         polinfo = pg_malloc_array(PolicyInfo, ntups);
    4358              : 
    4359          316 :         for (j = 0; j < ntups; j++)
    4360              :         {
    4361          273 :             Oid         polrelid = atooid(PQgetvalue(res, j, i_polrelid));
    4362          273 :             TableInfo  *tbinfo = findTableByOid(polrelid);
    4363              : 
    4364          273 :             tbinfo->dobj.components |= DUMP_COMPONENT_POLICY;
    4365              : 
    4366          273 :             polinfo[j].dobj.objType = DO_POLICY;
    4367          273 :             polinfo[j].dobj.catId.tableoid =
    4368          273 :                 atooid(PQgetvalue(res, j, i_tableoid));
    4369          273 :             polinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
    4370          273 :             AssignDumpId(&polinfo[j].dobj);
    4371          273 :             polinfo[j].dobj.namespace = tbinfo->dobj.namespace;
    4372          273 :             polinfo[j].poltable = tbinfo;
    4373          273 :             polinfo[j].polname = pg_strdup(PQgetvalue(res, j, i_polname));
    4374          273 :             polinfo[j].dobj.name = pg_strdup(polinfo[j].polname);
    4375              : 
    4376          273 :             polinfo[j].polcmd = *(PQgetvalue(res, j, i_polcmd));
    4377          273 :             polinfo[j].polpermissive = *(PQgetvalue(res, j, i_polpermissive)) == 't';
    4378              : 
    4379          273 :             if (PQgetisnull(res, j, i_polroles))
    4380          121 :                 polinfo[j].polroles = NULL;
    4381              :             else
    4382          152 :                 polinfo[j].polroles = pg_strdup(PQgetvalue(res, j, i_polroles));
    4383              : 
    4384          273 :             if (PQgetisnull(res, j, i_polqual))
    4385           38 :                 polinfo[j].polqual = NULL;
    4386              :             else
    4387          235 :                 polinfo[j].polqual = pg_strdup(PQgetvalue(res, j, i_polqual));
    4388              : 
    4389          273 :             if (PQgetisnull(res, j, i_polwithcheck))
    4390          144 :                 polinfo[j].polwithcheck = NULL;
    4391              :             else
    4392          129 :                 polinfo[j].polwithcheck
    4393          129 :                     = pg_strdup(PQgetvalue(res, j, i_polwithcheck));
    4394              :         }
    4395              :     }
    4396              : 
    4397          248 :     PQclear(res);
    4398              : 
    4399          248 :     destroyPQExpBuffer(query);
    4400          248 :     destroyPQExpBuffer(tbloids);
    4401              : }
    4402              : 
    4403              : /*
    4404              :  * dumpPolicy
    4405              :  *    dump the definition of the given policy
    4406              :  */
    4407              : static void
    4408          326 : dumpPolicy(Archive *fout, const PolicyInfo *polinfo)
    4409              : {
    4410          326 :     DumpOptions *dopt = fout->dopt;
    4411          326 :     TableInfo  *tbinfo = polinfo->poltable;
    4412              :     PQExpBuffer query;
    4413              :     PQExpBuffer delqry;
    4414              :     PQExpBuffer polprefix;
    4415              :     char       *qtabname;
    4416              :     const char *cmd;
    4417              :     char       *tag;
    4418              : 
    4419              :     /* Do nothing if not dumping schema */
    4420          326 :     if (!dopt->dumpSchema)
    4421           49 :         return;
    4422              : 
    4423              :     /*
    4424              :      * If polname is NULL, then this record is just indicating that ROW LEVEL
    4425              :      * SECURITY is enabled for the table. Dump as ALTER TABLE <table> ENABLE
    4426              :      * ROW LEVEL SECURITY.
    4427              :      */
    4428          277 :     if (polinfo->polname == NULL)
    4429              :     {
    4430           46 :         query = createPQExpBuffer();
    4431              : 
    4432           46 :         appendPQExpBuffer(query, "ALTER TABLE %s ENABLE ROW LEVEL SECURITY;",
    4433           46 :                           fmtQualifiedDumpable(tbinfo));
    4434              : 
    4435              :         /*
    4436              :          * We must emit the ROW SECURITY object's dependency on its table
    4437              :          * explicitly, because it will not match anything in pg_depend (unlike
    4438              :          * the case for other PolicyInfo objects).
    4439              :          */
    4440           46 :         if (polinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
    4441           46 :             ArchiveEntry(fout, polinfo->dobj.catId, polinfo->dobj.dumpId,
    4442           46 :                          ARCHIVE_OPTS(.tag = polinfo->dobj.name,
    4443              :                                       .namespace = polinfo->dobj.namespace->dobj.name,
    4444              :                                       .owner = tbinfo->rolname,
    4445              :                                       .description = "ROW SECURITY",
    4446              :                                       .section = SECTION_POST_DATA,
    4447              :                                       .createStmt = query->data,
    4448              :                                       .deps = &(tbinfo->dobj.dumpId),
    4449              :                                       .nDeps = 1));
    4450              : 
    4451           46 :         destroyPQExpBuffer(query);
    4452           46 :         return;
    4453              :     }
    4454              : 
    4455          231 :     if (polinfo->polcmd == '*')
    4456           77 :         cmd = "";
    4457          154 :     else if (polinfo->polcmd == 'r')
    4458           41 :         cmd = " FOR SELECT";
    4459          113 :     else if (polinfo->polcmd == 'a')
    4460           31 :         cmd = " FOR INSERT";
    4461           82 :     else if (polinfo->polcmd == 'w')
    4462           41 :         cmd = " FOR UPDATE";
    4463           41 :     else if (polinfo->polcmd == 'd')
    4464           41 :         cmd = " FOR DELETE";
    4465              :     else
    4466            0 :         pg_fatal("unexpected policy command type: %c",
    4467              :                  polinfo->polcmd);
    4468              : 
    4469          231 :     query = createPQExpBuffer();
    4470          231 :     delqry = createPQExpBuffer();
    4471          231 :     polprefix = createPQExpBuffer();
    4472              : 
    4473          231 :     qtabname = pg_strdup(fmtId(tbinfo->dobj.name));
    4474              : 
    4475          231 :     appendPQExpBuffer(query, "CREATE POLICY %s", fmtId(polinfo->polname));
    4476              : 
    4477          231 :     appendPQExpBuffer(query, " ON %s%s%s", fmtQualifiedDumpable(tbinfo),
    4478          231 :                       !polinfo->polpermissive ? " AS RESTRICTIVE" : "", cmd);
    4479              : 
    4480          231 :     if (polinfo->polroles != NULL)
    4481          124 :         appendPQExpBuffer(query, " TO %s", polinfo->polroles);
    4482              : 
    4483          231 :     if (polinfo->polqual != NULL)
    4484          200 :         appendPQExpBuffer(query, " USING (%s)", polinfo->polqual);
    4485              : 
    4486          231 :     if (polinfo->polwithcheck != NULL)
    4487          108 :         appendPQExpBuffer(query, " WITH CHECK (%s)", polinfo->polwithcheck);
    4488              : 
    4489          231 :     appendPQExpBufferStr(query, ";\n");
    4490              : 
    4491          231 :     appendPQExpBuffer(delqry, "DROP POLICY %s", fmtId(polinfo->polname));
    4492          231 :     appendPQExpBuffer(delqry, " ON %s;\n", fmtQualifiedDumpable(tbinfo));
    4493              : 
    4494          231 :     appendPQExpBuffer(polprefix, "POLICY %s ON",
    4495          231 :                       fmtId(polinfo->polname));
    4496              : 
    4497          231 :     tag = psprintf("%s %s", tbinfo->dobj.name, polinfo->dobj.name);
    4498              : 
    4499          231 :     if (polinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
    4500          231 :         ArchiveEntry(fout, polinfo->dobj.catId, polinfo->dobj.dumpId,
    4501          231 :                      ARCHIVE_OPTS(.tag = tag,
    4502              :                                   .namespace = polinfo->dobj.namespace->dobj.name,
    4503              :                                   .owner = tbinfo->rolname,
    4504              :                                   .description = "POLICY",
    4505              :                                   .section = SECTION_POST_DATA,
    4506              :                                   .createStmt = query->data,
    4507              :                                   .dropStmt = delqry->data));
    4508              : 
    4509          231 :     if (polinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
    4510           31 :         dumpComment(fout, polprefix->data, qtabname,
    4511           31 :                     tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
    4512           31 :                     polinfo->dobj.catId, 0, polinfo->dobj.dumpId);
    4513              : 
    4514          231 :     free(tag);
    4515          231 :     destroyPQExpBuffer(query);
    4516          231 :     destroyPQExpBuffer(delqry);
    4517          231 :     destroyPQExpBuffer(polprefix);
    4518          231 :     free(qtabname);
    4519              : }
    4520              : 
    4521              : /*
    4522              :  * getPublications
    4523              :  *    get information about publications
    4524              :  */
    4525              : void
    4526          249 : getPublications(Archive *fout)
    4527              : {
    4528          249 :     DumpOptions *dopt = fout->dopt;
    4529              :     PQExpBuffer query;
    4530              :     PGresult   *res;
    4531              :     PublicationInfo *pubinfo;
    4532              :     int         i_tableoid;
    4533              :     int         i_oid;
    4534              :     int         i_pubname;
    4535              :     int         i_pubowner;
    4536              :     int         i_puballtables;
    4537              :     int         i_puballsequences;
    4538              :     int         i_pubinsert;
    4539              :     int         i_pubupdate;
    4540              :     int         i_pubdelete;
    4541              :     int         i_pubtruncate;
    4542              :     int         i_pubviaroot;
    4543              :     int         i_pubgencols;
    4544              :     int         i,
    4545              :                 ntups;
    4546              : 
    4547          249 :     if (dopt->no_publications || fout->remoteVersion < 100000)
    4548            0 :         return;
    4549              : 
    4550          249 :     query = createPQExpBuffer();
    4551              : 
    4552              :     /* Get the publications. */
    4553          249 :     appendPQExpBufferStr(query, "SELECT p.tableoid, p.oid, p.pubname, "
    4554              :                          "p.pubowner, p.puballtables, p.pubinsert, "
    4555              :                          "p.pubupdate, p.pubdelete, ");
    4556              : 
    4557          249 :     if (fout->remoteVersion >= 110000)
    4558          249 :         appendPQExpBufferStr(query, "p.pubtruncate, ");
    4559              :     else
    4560            0 :         appendPQExpBufferStr(query, "false AS pubtruncate, ");
    4561              : 
    4562          249 :     if (fout->remoteVersion >= 130000)
    4563          249 :         appendPQExpBufferStr(query, "p.pubviaroot, ");
    4564              :     else
    4565            0 :         appendPQExpBufferStr(query, "false AS pubviaroot, ");
    4566              : 
    4567          249 :     if (fout->remoteVersion >= 180000)
    4568          249 :         appendPQExpBufferStr(query, "p.pubgencols, ");
    4569              :     else
    4570            0 :         appendPQExpBuffer(query, "'%c' AS pubgencols, ", PUBLISH_GENCOLS_NONE);
    4571              : 
    4572          249 :     if (fout->remoteVersion >= 190000)
    4573          249 :         appendPQExpBufferStr(query, "p.puballsequences ");
    4574              :     else
    4575            0 :         appendPQExpBufferStr(query, "false AS puballsequences ");
    4576              : 
    4577          249 :     appendPQExpBufferStr(query, "FROM pg_publication p");
    4578              : 
    4579          249 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    4580              : 
    4581          249 :     ntups = PQntuples(res);
    4582              : 
    4583          249 :     if (ntups == 0)
    4584          196 :         goto cleanup;
    4585              : 
    4586           53 :     i_tableoid = PQfnumber(res, "tableoid");
    4587           53 :     i_oid = PQfnumber(res, "oid");
    4588           53 :     i_pubname = PQfnumber(res, "pubname");
    4589           53 :     i_pubowner = PQfnumber(res, "pubowner");
    4590           53 :     i_puballtables = PQfnumber(res, "puballtables");
    4591           53 :     i_puballsequences = PQfnumber(res, "puballsequences");
    4592           53 :     i_pubinsert = PQfnumber(res, "pubinsert");
    4593           53 :     i_pubupdate = PQfnumber(res, "pubupdate");
    4594           53 :     i_pubdelete = PQfnumber(res, "pubdelete");
    4595           53 :     i_pubtruncate = PQfnumber(res, "pubtruncate");
    4596           53 :     i_pubviaroot = PQfnumber(res, "pubviaroot");
    4597           53 :     i_pubgencols = PQfnumber(res, "pubgencols");
    4598              : 
    4599           53 :     pubinfo = pg_malloc_array(PublicationInfo, ntups);
    4600              : 
    4601          404 :     for (i = 0; i < ntups; i++)
    4602              :     {
    4603          351 :         pubinfo[i].dobj.objType = DO_PUBLICATION;
    4604          351 :         pubinfo[i].dobj.catId.tableoid =
    4605          351 :             atooid(PQgetvalue(res, i, i_tableoid));
    4606          351 :         pubinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    4607          351 :         AssignDumpId(&pubinfo[i].dobj);
    4608          351 :         pubinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_pubname));
    4609          351 :         pubinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_pubowner));
    4610          351 :         pubinfo[i].puballtables =
    4611          351 :             (strcmp(PQgetvalue(res, i, i_puballtables), "t") == 0);
    4612          351 :         pubinfo[i].puballsequences =
    4613          351 :             (strcmp(PQgetvalue(res, i, i_puballsequences), "t") == 0);
    4614          351 :         pubinfo[i].pubinsert =
    4615          351 :             (strcmp(PQgetvalue(res, i, i_pubinsert), "t") == 0);
    4616          351 :         pubinfo[i].pubupdate =
    4617          351 :             (strcmp(PQgetvalue(res, i, i_pubupdate), "t") == 0);
    4618          351 :         pubinfo[i].pubdelete =
    4619          351 :             (strcmp(PQgetvalue(res, i, i_pubdelete), "t") == 0);
    4620          351 :         pubinfo[i].pubtruncate =
    4621          351 :             (strcmp(PQgetvalue(res, i, i_pubtruncate), "t") == 0);
    4622          351 :         pubinfo[i].pubviaroot =
    4623          351 :             (strcmp(PQgetvalue(res, i, i_pubviaroot), "t") == 0);
    4624          351 :         pubinfo[i].pubgencols_type =
    4625          351 :             *(PQgetvalue(res, i, i_pubgencols));
    4626              : 
    4627              :         /* Decide whether we want to dump it */
    4628          351 :         selectDumpableObject(&(pubinfo[i].dobj), fout);
    4629              :     }
    4630              : 
    4631           53 : cleanup:
    4632          249 :     PQclear(res);
    4633              : 
    4634          249 :     destroyPQExpBuffer(query);
    4635              : }
    4636              : 
    4637              : /*
    4638              :  * dumpPublication
    4639              :  *    dump the definition of the given publication
    4640              :  */
    4641              : static void
    4642          285 : dumpPublication(Archive *fout, const PublicationInfo *pubinfo)
    4643              : {
    4644          285 :     DumpOptions *dopt = fout->dopt;
    4645              :     PQExpBuffer delq;
    4646              :     PQExpBuffer query;
    4647              :     char       *qpubname;
    4648          285 :     bool        first = true;
    4649              : 
    4650              :     /* Do nothing if not dumping schema */
    4651          285 :     if (!dopt->dumpSchema)
    4652           42 :         return;
    4653              : 
    4654          243 :     delq = createPQExpBuffer();
    4655          243 :     query = createPQExpBuffer();
    4656              : 
    4657          243 :     qpubname = pg_strdup(fmtId(pubinfo->dobj.name));
    4658              : 
    4659          243 :     appendPQExpBuffer(delq, "DROP PUBLICATION %s;\n",
    4660              :                       qpubname);
    4661              : 
    4662          243 :     appendPQExpBuffer(query, "CREATE PUBLICATION %s",
    4663              :                       qpubname);
    4664              : 
    4665          243 :     if (pubinfo->puballtables && pubinfo->puballsequences)
    4666           31 :         appendPQExpBufferStr(query, " FOR ALL TABLES, ALL SEQUENCES");
    4667          212 :     else if (pubinfo->puballtables)
    4668           32 :         appendPQExpBufferStr(query, " FOR ALL TABLES");
    4669          180 :     else if (pubinfo->puballsequences)
    4670           31 :         appendPQExpBufferStr(query, " FOR ALL SEQUENCES");
    4671              : 
    4672          243 :     appendPQExpBufferStr(query, " WITH (publish = '");
    4673          243 :     if (pubinfo->pubinsert)
    4674              :     {
    4675          181 :         appendPQExpBufferStr(query, "insert");
    4676          181 :         first = false;
    4677              :     }
    4678              : 
    4679          243 :     if (pubinfo->pubupdate)
    4680              :     {
    4681          181 :         if (!first)
    4682          181 :             appendPQExpBufferStr(query, ", ");
    4683              : 
    4684          181 :         appendPQExpBufferStr(query, "update");
    4685          181 :         first = false;
    4686              :     }
    4687              : 
    4688          243 :     if (pubinfo->pubdelete)
    4689              :     {
    4690          181 :         if (!first)
    4691          181 :             appendPQExpBufferStr(query, ", ");
    4692              : 
    4693          181 :         appendPQExpBufferStr(query, "delete");
    4694          181 :         first = false;
    4695              :     }
    4696              : 
    4697          243 :     if (pubinfo->pubtruncate)
    4698              :     {
    4699          181 :         if (!first)
    4700          181 :             appendPQExpBufferStr(query, ", ");
    4701              : 
    4702          181 :         appendPQExpBufferStr(query, "truncate");
    4703          181 :         first = false;
    4704              :     }
    4705              : 
    4706          243 :     appendPQExpBufferChar(query, '\'');
    4707              : 
    4708          243 :     if (pubinfo->pubviaroot)
    4709            5 :         appendPQExpBufferStr(query, ", publish_via_partition_root = true");
    4710              : 
    4711          243 :     if (pubinfo->pubgencols_type == PUBLISH_GENCOLS_STORED)
    4712           31 :         appendPQExpBufferStr(query, ", publish_generated_columns = stored");
    4713              : 
    4714          243 :     appendPQExpBufferStr(query, ");\n");
    4715              : 
    4716          243 :     if (pubinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
    4717          243 :         ArchiveEntry(fout, pubinfo->dobj.catId, pubinfo->dobj.dumpId,
    4718          243 :                      ARCHIVE_OPTS(.tag = pubinfo->dobj.name,
    4719              :                                   .owner = pubinfo->rolname,
    4720              :                                   .description = "PUBLICATION",
    4721              :                                   .section = SECTION_POST_DATA,
    4722              :                                   .createStmt = query->data,
    4723              :                                   .dropStmt = delq->data));
    4724              : 
    4725          243 :     if (pubinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
    4726           31 :         dumpComment(fout, "PUBLICATION", qpubname,
    4727           31 :                     NULL, pubinfo->rolname,
    4728           31 :                     pubinfo->dobj.catId, 0, pubinfo->dobj.dumpId);
    4729              : 
    4730          243 :     if (pubinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
    4731            0 :         dumpSecLabel(fout, "PUBLICATION", qpubname,
    4732            0 :                      NULL, pubinfo->rolname,
    4733            0 :                      pubinfo->dobj.catId, 0, pubinfo->dobj.dumpId);
    4734              : 
    4735          243 :     destroyPQExpBuffer(delq);
    4736          243 :     destroyPQExpBuffer(query);
    4737          243 :     free(qpubname);
    4738              : }
    4739              : 
    4740              : /*
    4741              :  * getPublicationNamespaces
    4742              :  *    get information about publication membership for dumpable schemas.
    4743              :  */
    4744              : void
    4745          249 : getPublicationNamespaces(Archive *fout)
    4746              : {
    4747              :     PQExpBuffer query;
    4748              :     PGresult   *res;
    4749              :     PublicationSchemaInfo *pubsinfo;
    4750          249 :     DumpOptions *dopt = fout->dopt;
    4751              :     int         i_tableoid;
    4752              :     int         i_oid;
    4753              :     int         i_pnpubid;
    4754              :     int         i_pnnspid;
    4755              :     int         i,
    4756              :                 j,
    4757              :                 ntups;
    4758              : 
    4759          249 :     if (dopt->no_publications || fout->remoteVersion < 150000)
    4760            0 :         return;
    4761              : 
    4762          249 :     query = createPQExpBuffer();
    4763              : 
    4764              :     /* Collect all publication membership info. */
    4765          249 :     appendPQExpBufferStr(query,
    4766              :                          "SELECT tableoid, oid, pnpubid, pnnspid "
    4767              :                          "FROM pg_catalog.pg_publication_namespace");
    4768          249 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    4769              : 
    4770          249 :     ntups = PQntuples(res);
    4771              : 
    4772          249 :     i_tableoid = PQfnumber(res, "tableoid");
    4773          249 :     i_oid = PQfnumber(res, "oid");
    4774          249 :     i_pnpubid = PQfnumber(res, "pnpubid");
    4775          249 :     i_pnnspid = PQfnumber(res, "pnnspid");
    4776              : 
    4777              :     /* this allocation may be more than we need */
    4778          249 :     pubsinfo = pg_malloc_array(PublicationSchemaInfo, ntups);
    4779          249 :     j = 0;
    4780              : 
    4781          374 :     for (i = 0; i < ntups; i++)
    4782              :     {
    4783          125 :         Oid         pnpubid = atooid(PQgetvalue(res, i, i_pnpubid));
    4784          125 :         Oid         pnnspid = atooid(PQgetvalue(res, i, i_pnnspid));
    4785              :         PublicationInfo *pubinfo;
    4786              :         NamespaceInfo *nspinfo;
    4787              : 
    4788              :         /*
    4789              :          * Ignore any entries for which we aren't interested in either the
    4790              :          * publication or the rel.
    4791              :          */
    4792          125 :         pubinfo = findPublicationByOid(pnpubid);
    4793          125 :         if (pubinfo == NULL)
    4794            0 :             continue;
    4795          125 :         nspinfo = findNamespaceByOid(pnnspid);
    4796          125 :         if (nspinfo == NULL)
    4797            0 :             continue;
    4798              : 
    4799              :         /* OK, make a DumpableObject for this relationship */
    4800          125 :         pubsinfo[j].dobj.objType = DO_PUBLICATION_TABLE_IN_SCHEMA;
    4801          125 :         pubsinfo[j].dobj.catId.tableoid =
    4802          125 :             atooid(PQgetvalue(res, i, i_tableoid));
    4803          125 :         pubsinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    4804          125 :         AssignDumpId(&pubsinfo[j].dobj);
    4805          125 :         pubsinfo[j].dobj.namespace = nspinfo->dobj.namespace;
    4806          125 :         pubsinfo[j].dobj.name = nspinfo->dobj.name;
    4807          125 :         pubsinfo[j].publication = pubinfo;
    4808          125 :         pubsinfo[j].pubschema = nspinfo;
    4809              : 
    4810              :         /* Decide whether we want to dump it */
    4811          125 :         selectDumpablePublicationObject(&(pubsinfo[j].dobj), fout);
    4812              : 
    4813          125 :         j++;
    4814              :     }
    4815              : 
    4816          249 :     PQclear(res);
    4817          249 :     destroyPQExpBuffer(query);
    4818              : }
    4819              : 
    4820              : /*
    4821              :  * getPublicationTables
    4822              :  *    get information about publication membership for dumpable tables.
    4823              :  */
    4824              : void
    4825          249 : getPublicationTables(Archive *fout, TableInfo tblinfo[], int numTables)
    4826              : {
    4827              :     PQExpBuffer query;
    4828              :     PGresult   *res;
    4829              :     PublicationRelInfo *pubrinfo;
    4830          249 :     DumpOptions *dopt = fout->dopt;
    4831              :     int         i_tableoid;
    4832              :     int         i_oid;
    4833              :     int         i_prpubid;
    4834              :     int         i_prrelid;
    4835              :     int         i_prrelqual;
    4836              :     int         i_prattrs;
    4837              :     int         i,
    4838              :                 j,
    4839              :                 ntups;
    4840              : 
    4841          249 :     if (dopt->no_publications || fout->remoteVersion < 100000)
    4842            0 :         return;
    4843              : 
    4844          249 :     query = createPQExpBuffer();
    4845              : 
    4846              :     /* Collect all publication membership info. */
    4847          249 :     if (fout->remoteVersion >= 150000)
    4848          249 :         appendPQExpBufferStr(query,
    4849              :                              "SELECT tableoid, oid, prpubid, prrelid, "
    4850              :                              "pg_catalog.pg_get_expr(prqual, prrelid) AS prrelqual, "
    4851              :                              "(CASE\n"
    4852              :                              "  WHEN pr.prattrs IS NOT NULL THEN\n"
    4853              :                              "    (SELECT array_agg(attname)\n"
    4854              :                              "       FROM\n"
    4855              :                              "         pg_catalog.generate_series(0, pg_catalog.array_upper(pr.prattrs::pg_catalog.int2[], 1)) s,\n"
    4856              :                              "         pg_catalog.pg_attribute\n"
    4857              :                              "      WHERE attrelid = pr.prrelid AND attnum = prattrs[s])\n"
    4858              :                              "  ELSE NULL END) prattrs "
    4859              :                              "FROM pg_catalog.pg_publication_rel pr");
    4860              :     else
    4861            0 :         appendPQExpBufferStr(query,
    4862              :                              "SELECT tableoid, oid, prpubid, prrelid, "
    4863              :                              "NULL AS prrelqual, NULL AS prattrs "
    4864              :                              "FROM pg_catalog.pg_publication_rel");
    4865          249 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    4866              : 
    4867          249 :     ntups = PQntuples(res);
    4868              : 
    4869          249 :     i_tableoid = PQfnumber(res, "tableoid");
    4870          249 :     i_oid = PQfnumber(res, "oid");
    4871          249 :     i_prpubid = PQfnumber(res, "prpubid");
    4872          249 :     i_prrelid = PQfnumber(res, "prrelid");
    4873          249 :     i_prrelqual = PQfnumber(res, "prrelqual");
    4874          249 :     i_prattrs = PQfnumber(res, "prattrs");
    4875              : 
    4876              :     /* this allocation may be more than we need */
    4877          249 :     pubrinfo = pg_malloc_array(PublicationRelInfo, ntups);
    4878          249 :     j = 0;
    4879              : 
    4880          599 :     for (i = 0; i < ntups; i++)
    4881              :     {
    4882          350 :         Oid         prpubid = atooid(PQgetvalue(res, i, i_prpubid));
    4883          350 :         Oid         prrelid = atooid(PQgetvalue(res, i, i_prrelid));
    4884              :         PublicationInfo *pubinfo;
    4885              :         TableInfo  *tbinfo;
    4886              : 
    4887              :         /*
    4888              :          * Ignore any entries for which we aren't interested in either the
    4889              :          * publication or the rel.
    4890              :          */
    4891          350 :         pubinfo = findPublicationByOid(prpubid);
    4892          350 :         if (pubinfo == NULL)
    4893            0 :             continue;
    4894          350 :         tbinfo = findTableByOid(prrelid);
    4895          350 :         if (tbinfo == NULL)
    4896            0 :             continue;
    4897              : 
    4898              :         /* OK, make a DumpableObject for this relationship */
    4899          350 :         pubrinfo[j].dobj.objType = DO_PUBLICATION_REL;
    4900          350 :         pubrinfo[j].dobj.catId.tableoid =
    4901          350 :             atooid(PQgetvalue(res, i, i_tableoid));
    4902          350 :         pubrinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    4903          350 :         AssignDumpId(&pubrinfo[j].dobj);
    4904          350 :         pubrinfo[j].dobj.namespace = tbinfo->dobj.namespace;
    4905          350 :         pubrinfo[j].dobj.name = tbinfo->dobj.name;
    4906          350 :         pubrinfo[j].publication = pubinfo;
    4907          350 :         pubrinfo[j].pubtable = tbinfo;
    4908          350 :         if (PQgetisnull(res, i, i_prrelqual))
    4909          194 :             pubrinfo[j].pubrelqual = NULL;
    4910              :         else
    4911          156 :             pubrinfo[j].pubrelqual = pg_strdup(PQgetvalue(res, i, i_prrelqual));
    4912              : 
    4913          350 :         if (!PQgetisnull(res, i, i_prattrs))
    4914              :         {
    4915              :             char      **attnames;
    4916              :             int         nattnames;
    4917              :             PQExpBuffer attribs;
    4918              : 
    4919          111 :             if (!parsePGArray(PQgetvalue(res, i, i_prattrs),
    4920              :                               &attnames, &nattnames))
    4921            0 :                 pg_fatal("could not parse %s array", "prattrs");
    4922          111 :             attribs = createPQExpBuffer();
    4923          319 :             for (int k = 0; k < nattnames; k++)
    4924              :             {
    4925          208 :                 if (k > 0)
    4926           97 :                     appendPQExpBufferStr(attribs, ", ");
    4927              : 
    4928          208 :                 appendPQExpBufferStr(attribs, fmtId(attnames[k]));
    4929              :             }
    4930          111 :             pubrinfo[j].pubrattrs = attribs->data;
    4931          111 :             free(attribs);      /* but not attribs->data */
    4932          111 :             free(attnames);
    4933              :         }
    4934              :         else
    4935          239 :             pubrinfo[j].pubrattrs = NULL;
    4936              : 
    4937              :         /* Decide whether we want to dump it */
    4938          350 :         selectDumpablePublicationObject(&(pubrinfo[j].dobj), fout);
    4939              : 
    4940          350 :         j++;
    4941              :     }
    4942              : 
    4943          249 :     PQclear(res);
    4944          249 :     destroyPQExpBuffer(query);
    4945              : }
    4946              : 
    4947              : /*
    4948              :  * dumpPublicationNamespace
    4949              :  *    dump the definition of the given publication schema mapping.
    4950              :  */
    4951              : static void
    4952           99 : dumpPublicationNamespace(Archive *fout, const PublicationSchemaInfo *pubsinfo)
    4953              : {
    4954           99 :     DumpOptions *dopt = fout->dopt;
    4955           99 :     NamespaceInfo *schemainfo = pubsinfo->pubschema;
    4956           99 :     PublicationInfo *pubinfo = pubsinfo->publication;
    4957              :     PQExpBuffer query;
    4958              :     char       *tag;
    4959              : 
    4960              :     /* Do nothing if not dumping schema */
    4961           99 :     if (!dopt->dumpSchema)
    4962           12 :         return;
    4963              : 
    4964           87 :     tag = psprintf("%s %s", pubinfo->dobj.name, schemainfo->dobj.name);
    4965              : 
    4966           87 :     query = createPQExpBuffer();
    4967              : 
    4968           87 :     appendPQExpBuffer(query, "ALTER PUBLICATION %s ", fmtId(pubinfo->dobj.name));
    4969           87 :     appendPQExpBuffer(query, "ADD TABLES IN SCHEMA %s;\n", fmtId(schemainfo->dobj.name));
    4970              : 
    4971              :     /*
    4972              :      * There is no point in creating drop query as the drop is done by schema
    4973              :      * drop.
    4974              :      */
    4975           87 :     if (pubsinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
    4976           87 :         ArchiveEntry(fout, pubsinfo->dobj.catId, pubsinfo->dobj.dumpId,
    4977           87 :                      ARCHIVE_OPTS(.tag = tag,
    4978              :                                   .namespace = schemainfo->dobj.name,
    4979              :                                   .owner = pubinfo->rolname,
    4980              :                                   .description = "PUBLICATION TABLES IN SCHEMA",
    4981              :                                   .section = SECTION_POST_DATA,
    4982              :                                   .createStmt = query->data));
    4983              : 
    4984              :     /* These objects can't currently have comments or seclabels */
    4985              : 
    4986           87 :     free(tag);
    4987           87 :     destroyPQExpBuffer(query);
    4988              : }
    4989              : 
    4990              : /*
    4991              :  * dumpPublicationTable
    4992              :  *    dump the definition of the given publication table mapping
    4993              :  */
    4994              : static void
    4995          284 : dumpPublicationTable(Archive *fout, const PublicationRelInfo *pubrinfo)
    4996              : {
    4997          284 :     DumpOptions *dopt = fout->dopt;
    4998          284 :     PublicationInfo *pubinfo = pubrinfo->publication;
    4999          284 :     TableInfo  *tbinfo = pubrinfo->pubtable;
    5000              :     PQExpBuffer query;
    5001              :     char       *tag;
    5002              : 
    5003              :     /* Do nothing if not dumping schema */
    5004          284 :     if (!dopt->dumpSchema)
    5005           42 :         return;
    5006              : 
    5007          242 :     tag = psprintf("%s %s", pubinfo->dobj.name, tbinfo->dobj.name);
    5008              : 
    5009          242 :     query = createPQExpBuffer();
    5010              : 
    5011          242 :     appendPQExpBuffer(query, "ALTER PUBLICATION %s ADD TABLE ONLY",
    5012          242 :                       fmtId(pubinfo->dobj.name));
    5013          242 :     appendPQExpBuffer(query, " %s",
    5014          242 :                       fmtQualifiedDumpable(tbinfo));
    5015              : 
    5016          242 :     if (pubrinfo->pubrattrs)
    5017           77 :         appendPQExpBuffer(query, " (%s)", pubrinfo->pubrattrs);
    5018              : 
    5019          242 :     if (pubrinfo->pubrelqual)
    5020              :     {
    5021              :         /*
    5022              :          * It's necessary to add parentheses around the expression because
    5023              :          * pg_get_expr won't supply the parentheses for things like WHERE
    5024              :          * TRUE.
    5025              :          */
    5026          108 :         appendPQExpBuffer(query, " WHERE (%s)", pubrinfo->pubrelqual);
    5027              :     }
    5028          242 :     appendPQExpBufferStr(query, ";\n");
    5029              : 
    5030              :     /*
    5031              :      * There is no point in creating a drop query as the drop is done by table
    5032              :      * drop.  (If you think to change this, see also _printTocEntry().)
    5033              :      * Although this object doesn't really have ownership as such, set the
    5034              :      * owner field anyway to ensure that the command is run by the correct
    5035              :      * role at restore time.
    5036              :      */
    5037          242 :     if (pubrinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
    5038          242 :         ArchiveEntry(fout, pubrinfo->dobj.catId, pubrinfo->dobj.dumpId,
    5039          242 :                      ARCHIVE_OPTS(.tag = tag,
    5040              :                                   .namespace = tbinfo->dobj.namespace->dobj.name,
    5041              :                                   .owner = pubinfo->rolname,
    5042              :                                   .description = "PUBLICATION TABLE",
    5043              :                                   .section = SECTION_POST_DATA,
    5044              :                                   .createStmt = query->data));
    5045              : 
    5046              :     /* These objects can't currently have comments or seclabels */
    5047              : 
    5048          242 :     free(tag);
    5049          242 :     destroyPQExpBuffer(query);
    5050              : }
    5051              : 
    5052              : /*
    5053              :  * Is the currently connected user a superuser?
    5054              :  */
    5055              : static bool
    5056          248 : is_superuser(Archive *fout)
    5057              : {
    5058          248 :     ArchiveHandle *AH = (ArchiveHandle *) fout;
    5059              :     const char *val;
    5060              : 
    5061          248 :     val = PQparameterStatus(AH->connection, "is_superuser");
    5062              : 
    5063          248 :     if (val && strcmp(val, "on") == 0)
    5064          245 :         return true;
    5065              : 
    5066            3 :     return false;
    5067              : }
    5068              : 
    5069              : /*
    5070              :  * Set the given value to restrict_nonsystem_relation_kind value. Since
    5071              :  * restrict_nonsystem_relation_kind is introduced in minor version releases,
    5072              :  * the setting query is effective only where available.
    5073              :  */
    5074              : static void
    5075          283 : set_restrict_relation_kind(Archive *AH, const char *value)
    5076              : {
    5077          283 :     PQExpBuffer query = createPQExpBuffer();
    5078              :     PGresult   *res;
    5079              : 
    5080          283 :     appendPQExpBuffer(query,
    5081              :                       "SELECT set_config(name, '%s', false) "
    5082              :                       "FROM pg_settings "
    5083              :                       "WHERE name = 'restrict_nonsystem_relation_kind'",
    5084              :                       value);
    5085          283 :     res = ExecuteSqlQuery(AH, query->data, PGRES_TUPLES_OK);
    5086              : 
    5087          283 :     PQclear(res);
    5088          283 :     destroyPQExpBuffer(query);
    5089          283 : }
    5090              : 
    5091              : /*
    5092              :  * getSubscriptions
    5093              :  *    get information about subscriptions
    5094              :  */
    5095              : void
    5096          249 : getSubscriptions(Archive *fout)
    5097              : {
    5098          249 :     DumpOptions *dopt = fout->dopt;
    5099              :     PQExpBuffer query;
    5100              :     PGresult   *res;
    5101              :     SubscriptionInfo *subinfo;
    5102              :     int         i_tableoid;
    5103              :     int         i_oid;
    5104              :     int         i_subname;
    5105              :     int         i_subowner;
    5106              :     int         i_subbinary;
    5107              :     int         i_substream;
    5108              :     int         i_subtwophasestate;
    5109              :     int         i_subdisableonerr;
    5110              :     int         i_subpasswordrequired;
    5111              :     int         i_subrunasowner;
    5112              :     int         i_subconninfo;
    5113              :     int         i_subslotname;
    5114              :     int         i_subsynccommit;
    5115              :     int         i_subwalrcvtimeout;
    5116              :     int         i_subpublications;
    5117              :     int         i_suborigin;
    5118              :     int         i_suboriginremotelsn;
    5119              :     int         i_subenabled;
    5120              :     int         i_subfailover;
    5121              :     int         i_subretaindeadtuples;
    5122              :     int         i_submaxretention;
    5123              :     int         i,
    5124              :                 ntups;
    5125              : 
    5126          249 :     if (dopt->no_subscriptions || fout->remoteVersion < 100000)
    5127            1 :         return;
    5128              : 
    5129          248 :     if (!is_superuser(fout))
    5130              :     {
    5131              :         int         n;
    5132              : 
    5133            3 :         res = ExecuteSqlQuery(fout,
    5134              :                               "SELECT count(*) FROM pg_subscription "
    5135              :                               "WHERE subdbid = (SELECT oid FROM pg_database"
    5136              :                               "                 WHERE datname = current_database())",
    5137              :                               PGRES_TUPLES_OK);
    5138            3 :         n = atoi(PQgetvalue(res, 0, 0));
    5139            3 :         if (n > 0)
    5140            2 :             pg_log_warning("subscriptions not dumped because current user is not a superuser");
    5141            3 :         PQclear(res);
    5142            3 :         return;
    5143              :     }
    5144              : 
    5145          245 :     query = createPQExpBuffer();
    5146              : 
    5147              :     /* Get the subscriptions in current database. */
    5148          245 :     appendPQExpBufferStr(query,
    5149              :                          "SELECT s.tableoid, s.oid, s.subname,\n"
    5150              :                          " s.subowner,\n"
    5151              :                          " s.subconninfo, s.subslotname, s.subsynccommit,\n"
    5152              :                          " s.subpublications,\n");
    5153              : 
    5154          245 :     if (fout->remoteVersion >= 140000)
    5155          245 :         appendPQExpBufferStr(query, " s.subbinary,\n");
    5156              :     else
    5157            0 :         appendPQExpBufferStr(query, " false AS subbinary,\n");
    5158              : 
    5159          245 :     if (fout->remoteVersion >= 140000)
    5160          245 :         appendPQExpBufferStr(query, " s.substream,\n");
    5161              :     else
    5162            0 :         appendPQExpBufferStr(query, " 'f' AS substream,\n");
    5163              : 
    5164          245 :     if (fout->remoteVersion >= 150000)
    5165          245 :         appendPQExpBufferStr(query,
    5166              :                              " s.subtwophasestate,\n"
    5167              :                              " s.subdisableonerr,\n");
    5168              :     else
    5169            0 :         appendPQExpBuffer(query,
    5170              :                           " '%c' AS subtwophasestate,\n"
    5171              :                           " false AS subdisableonerr,\n",
    5172              :                           LOGICALREP_TWOPHASE_STATE_DISABLED);
    5173              : 
    5174          245 :     if (fout->remoteVersion >= 160000)
    5175          245 :         appendPQExpBufferStr(query,
    5176              :                              " s.subpasswordrequired,\n"
    5177              :                              " s.subrunasowner,\n"
    5178              :                              " s.suborigin,\n");
    5179              :     else
    5180            0 :         appendPQExpBuffer(query,
    5181              :                           " 't' AS subpasswordrequired,\n"
    5182              :                           " 't' AS subrunasowner,\n"
    5183              :                           " '%s' AS suborigin,\n",
    5184              :                           LOGICALREP_ORIGIN_ANY);
    5185              : 
    5186          245 :     if (dopt->binary_upgrade && fout->remoteVersion >= 170000)
    5187           38 :         appendPQExpBufferStr(query, " o.remote_lsn AS suboriginremotelsn,\n"
    5188              :                              " s.subenabled,\n");
    5189              :     else
    5190          207 :         appendPQExpBufferStr(query, " NULL AS suboriginremotelsn,\n"
    5191              :                              " false AS subenabled,\n");
    5192              : 
    5193          245 :     if (fout->remoteVersion >= 170000)
    5194          245 :         appendPQExpBufferStr(query,
    5195              :                              " s.subfailover,\n");
    5196              :     else
    5197            0 :         appendPQExpBufferStr(query,
    5198              :                              " false AS subfailover,\n");
    5199              : 
    5200          245 :     if (fout->remoteVersion >= 190000)
    5201          245 :         appendPQExpBufferStr(query,
    5202              :                              " s.subretaindeadtuples,\n");
    5203              :     else
    5204            0 :         appendPQExpBufferStr(query,
    5205              :                              " false AS subretaindeadtuples,\n");
    5206              : 
    5207          245 :     if (fout->remoteVersion >= 190000)
    5208          245 :         appendPQExpBufferStr(query,
    5209              :                              " s.submaxretention,\n");
    5210              :     else
    5211            0 :         appendPQExpBuffer(query,
    5212              :                           " 0 AS submaxretention,\n");
    5213              : 
    5214          245 :     if (fout->remoteVersion >= 190000)
    5215          245 :         appendPQExpBufferStr(query,
    5216              :                              " s.subwalrcvtimeout\n");
    5217              :     else
    5218            0 :         appendPQExpBufferStr(query,
    5219              :                              " '-1' AS subwalrcvtimeout\n");
    5220              : 
    5221          245 :     appendPQExpBufferStr(query,
    5222              :                          "FROM pg_subscription s\n");
    5223              : 
    5224          245 :     if (dopt->binary_upgrade && fout->remoteVersion >= 170000)
    5225           38 :         appendPQExpBufferStr(query,
    5226              :                              "LEFT JOIN pg_catalog.pg_replication_origin_status o \n"
    5227              :                              "    ON o.external_id = 'pg_' || s.oid::text \n");
    5228              : 
    5229          245 :     appendPQExpBufferStr(query,
    5230              :                          "WHERE s.subdbid = (SELECT oid FROM pg_database\n"
    5231              :                          "                   WHERE datname = current_database())");
    5232              : 
    5233          245 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    5234              : 
    5235          245 :     ntups = PQntuples(res);
    5236              : 
    5237              :     /*
    5238              :      * Get subscription fields. We don't include subskiplsn in the dump as
    5239              :      * after restoring the dump this value may no longer be relevant.
    5240              :      */
    5241          245 :     i_tableoid = PQfnumber(res, "tableoid");
    5242          245 :     i_oid = PQfnumber(res, "oid");
    5243          245 :     i_subname = PQfnumber(res, "subname");
    5244          245 :     i_subowner = PQfnumber(res, "subowner");
    5245          245 :     i_subenabled = PQfnumber(res, "subenabled");
    5246          245 :     i_subbinary = PQfnumber(res, "subbinary");
    5247          245 :     i_substream = PQfnumber(res, "substream");
    5248          245 :     i_subtwophasestate = PQfnumber(res, "subtwophasestate");
    5249          245 :     i_subdisableonerr = PQfnumber(res, "subdisableonerr");
    5250          245 :     i_subpasswordrequired = PQfnumber(res, "subpasswordrequired");
    5251          245 :     i_subrunasowner = PQfnumber(res, "subrunasowner");
    5252          245 :     i_subfailover = PQfnumber(res, "subfailover");
    5253          245 :     i_subretaindeadtuples = PQfnumber(res, "subretaindeadtuples");
    5254          245 :     i_submaxretention = PQfnumber(res, "submaxretention");
    5255          245 :     i_subconninfo = PQfnumber(res, "subconninfo");
    5256          245 :     i_subslotname = PQfnumber(res, "subslotname");
    5257          245 :     i_subsynccommit = PQfnumber(res, "subsynccommit");
    5258          245 :     i_subwalrcvtimeout = PQfnumber(res, "subwalrcvtimeout");
    5259          245 :     i_subpublications = PQfnumber(res, "subpublications");
    5260          245 :     i_suborigin = PQfnumber(res, "suborigin");
    5261          245 :     i_suboriginremotelsn = PQfnumber(res, "suboriginremotelsn");
    5262              : 
    5263          245 :     subinfo = pg_malloc_array(SubscriptionInfo, ntups);
    5264              : 
    5265          373 :     for (i = 0; i < ntups; i++)
    5266              :     {
    5267          128 :         subinfo[i].dobj.objType = DO_SUBSCRIPTION;
    5268          128 :         subinfo[i].dobj.catId.tableoid =
    5269          128 :             atooid(PQgetvalue(res, i, i_tableoid));
    5270          128 :         subinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    5271          128 :         AssignDumpId(&subinfo[i].dobj);
    5272          128 :         subinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_subname));
    5273          128 :         subinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_subowner));
    5274              : 
    5275          128 :         subinfo[i].subenabled =
    5276          128 :             (strcmp(PQgetvalue(res, i, i_subenabled), "t") == 0);
    5277          128 :         subinfo[i].subbinary =
    5278          128 :             (strcmp(PQgetvalue(res, i, i_subbinary), "t") == 0);
    5279          128 :         subinfo[i].substream = *(PQgetvalue(res, i, i_substream));
    5280          128 :         subinfo[i].subtwophasestate = *(PQgetvalue(res, i, i_subtwophasestate));
    5281          128 :         subinfo[i].subdisableonerr =
    5282          128 :             (strcmp(PQgetvalue(res, i, i_subdisableonerr), "t") == 0);
    5283          128 :         subinfo[i].subpasswordrequired =
    5284          128 :             (strcmp(PQgetvalue(res, i, i_subpasswordrequired), "t") == 0);
    5285          128 :         subinfo[i].subrunasowner =
    5286          128 :             (strcmp(PQgetvalue(res, i, i_subrunasowner), "t") == 0);
    5287          128 :         subinfo[i].subfailover =
    5288          128 :             (strcmp(PQgetvalue(res, i, i_subfailover), "t") == 0);
    5289          128 :         subinfo[i].subretaindeadtuples =
    5290          128 :             (strcmp(PQgetvalue(res, i, i_subretaindeadtuples), "t") == 0);
    5291          128 :         subinfo[i].submaxretention =
    5292          128 :             atoi(PQgetvalue(res, i, i_submaxretention));
    5293          256 :         subinfo[i].subconninfo =
    5294          128 :             pg_strdup(PQgetvalue(res, i, i_subconninfo));
    5295          128 :         if (PQgetisnull(res, i, i_subslotname))
    5296            0 :             subinfo[i].subslotname = NULL;
    5297              :         else
    5298          128 :             subinfo[i].subslotname =
    5299          128 :                 pg_strdup(PQgetvalue(res, i, i_subslotname));
    5300          256 :         subinfo[i].subsynccommit =
    5301          128 :             pg_strdup(PQgetvalue(res, i, i_subsynccommit));
    5302          256 :         subinfo[i].subwalrcvtimeout =
    5303          128 :             pg_strdup(PQgetvalue(res, i, i_subwalrcvtimeout));
    5304          256 :         subinfo[i].subpublications =
    5305          128 :             pg_strdup(PQgetvalue(res, i, i_subpublications));
    5306          128 :         subinfo[i].suborigin = pg_strdup(PQgetvalue(res, i, i_suborigin));
    5307          128 :         if (PQgetisnull(res, i, i_suboriginremotelsn))
    5308          127 :             subinfo[i].suboriginremotelsn = NULL;
    5309              :         else
    5310            1 :             subinfo[i].suboriginremotelsn =
    5311            1 :                 pg_strdup(PQgetvalue(res, i, i_suboriginremotelsn));
    5312              : 
    5313              :         /* Decide whether we want to dump it */
    5314          128 :         selectDumpableObject(&(subinfo[i].dobj), fout);
    5315              :     }
    5316          245 :     PQclear(res);
    5317              : 
    5318          245 :     destroyPQExpBuffer(query);
    5319              : }
    5320              : 
    5321              : /*
    5322              :  * getSubscriptionRelations
    5323              :  *    Get information about subscription membership for dumpable relations. This
    5324              :  *    will be used only in binary-upgrade mode for PG17 or later versions.
    5325              :  */
    5326              : void
    5327          249 : getSubscriptionRelations(Archive *fout)
    5328              : {
    5329          249 :     DumpOptions *dopt = fout->dopt;
    5330          249 :     SubscriptionInfo *subinfo = NULL;
    5331              :     SubRelInfo *subrinfo;
    5332              :     PGresult   *res;
    5333              :     int         i_srsubid;
    5334              :     int         i_srrelid;
    5335              :     int         i_srsubstate;
    5336              :     int         i_srsublsn;
    5337              :     int         ntups;
    5338          249 :     Oid         last_srsubid = InvalidOid;
    5339              : 
    5340          249 :     if (dopt->no_subscriptions || !dopt->binary_upgrade ||
    5341           38 :         fout->remoteVersion < 170000)
    5342          211 :         return;
    5343              : 
    5344           38 :     res = ExecuteSqlQuery(fout,
    5345              :                           "SELECT srsubid, srrelid, srsubstate, srsublsn "
    5346              :                           "FROM pg_catalog.pg_subscription_rel "
    5347              :                           "ORDER BY srsubid",
    5348              :                           PGRES_TUPLES_OK);
    5349           38 :     ntups = PQntuples(res);
    5350           38 :     if (ntups == 0)
    5351           37 :         goto cleanup;
    5352              : 
    5353              :     /* Get pg_subscription_rel attributes */
    5354            1 :     i_srsubid = PQfnumber(res, "srsubid");
    5355            1 :     i_srrelid = PQfnumber(res, "srrelid");
    5356            1 :     i_srsubstate = PQfnumber(res, "srsubstate");
    5357            1 :     i_srsublsn = PQfnumber(res, "srsublsn");
    5358              : 
    5359            1 :     subrinfo = pg_malloc_array(SubRelInfo, ntups);
    5360            4 :     for (int i = 0; i < ntups; i++)
    5361              :     {
    5362            3 :         Oid         cur_srsubid = atooid(PQgetvalue(res, i, i_srsubid));
    5363            3 :         Oid         relid = atooid(PQgetvalue(res, i, i_srrelid));
    5364              :         TableInfo  *tblinfo;
    5365              : 
    5366              :         /*
    5367              :          * If we switched to a new subscription, check if the subscription
    5368              :          * exists.
    5369              :          */
    5370            3 :         if (cur_srsubid != last_srsubid)
    5371              :         {
    5372            2 :             subinfo = findSubscriptionByOid(cur_srsubid);
    5373            2 :             if (subinfo == NULL)
    5374            0 :                 pg_fatal("subscription with OID %u does not exist", cur_srsubid);
    5375              : 
    5376            2 :             last_srsubid = cur_srsubid;
    5377              :         }
    5378              : 
    5379            3 :         tblinfo = findTableByOid(relid);
    5380            3 :         if (tblinfo == NULL)
    5381            0 :             pg_fatal("failed sanity check, relation with OID %u not found",
    5382              :                      relid);
    5383              : 
    5384              :         /* OK, make a DumpableObject for this relationship */
    5385            3 :         subrinfo[i].dobj.objType = DO_SUBSCRIPTION_REL;
    5386            3 :         subrinfo[i].dobj.catId.tableoid = relid;
    5387            3 :         subrinfo[i].dobj.catId.oid = cur_srsubid;
    5388            3 :         AssignDumpId(&subrinfo[i].dobj);
    5389            3 :         subrinfo[i].dobj.namespace = tblinfo->dobj.namespace;
    5390            3 :         subrinfo[i].dobj.name = tblinfo->dobj.name;
    5391            3 :         subrinfo[i].subinfo = subinfo;
    5392            3 :         subrinfo[i].tblinfo = tblinfo;
    5393            3 :         subrinfo[i].srsubstate = PQgetvalue(res, i, i_srsubstate)[0];
    5394            3 :         if (PQgetisnull(res, i, i_srsublsn))
    5395            1 :             subrinfo[i].srsublsn = NULL;
    5396              :         else
    5397            2 :             subrinfo[i].srsublsn = pg_strdup(PQgetvalue(res, i, i_srsublsn));
    5398              : 
    5399              :         /* Decide whether we want to dump it */
    5400            3 :         selectDumpableObject(&(subrinfo[i].dobj), fout);
    5401              :     }
    5402              : 
    5403            1 : cleanup:
    5404           38 :     PQclear(res);
    5405              : }
    5406              : 
    5407              : /*
    5408              :  * dumpSubscriptionTable
    5409              :  *    Dump the definition of the given subscription table mapping. This will be
    5410              :  *    used only in binary-upgrade mode for PG17 or later versions.
    5411              :  */
    5412              : static void
    5413            3 : dumpSubscriptionTable(Archive *fout, const SubRelInfo *subrinfo)
    5414              : {
    5415            3 :     DumpOptions *dopt = fout->dopt;
    5416            3 :     SubscriptionInfo *subinfo = subrinfo->subinfo;
    5417              :     PQExpBuffer query;
    5418              :     char       *tag;
    5419              : 
    5420              :     /* Do nothing if not dumping schema */
    5421            3 :     if (!dopt->dumpSchema)
    5422            0 :         return;
    5423              : 
    5424              :     Assert(fout->dopt->binary_upgrade && fout->remoteVersion >= 170000);
    5425              : 
    5426            3 :     tag = psprintf("%s %s", subinfo->dobj.name, subrinfo->tblinfo->dobj.name);
    5427              : 
    5428            3 :     query = createPQExpBuffer();
    5429              : 
    5430            3 :     if (subinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
    5431              :     {
    5432              :         /*
    5433              :          * binary_upgrade_add_sub_rel_state will add the subscription relation
    5434              :          * to pg_subscription_rel table. This will be used only in
    5435              :          * binary-upgrade mode.
    5436              :          */
    5437            3 :         appendPQExpBufferStr(query,
    5438              :                              "\n-- For binary upgrade, must preserve the subscriber table.\n");
    5439            3 :         appendPQExpBufferStr(query,
    5440              :                              "SELECT pg_catalog.binary_upgrade_add_sub_rel_state(");
    5441            3 :         appendStringLiteralAH(query, subinfo->dobj.name, fout);
    5442            3 :         appendPQExpBuffer(query,
    5443              :                           ", %u, '%c'",
    5444            3 :                           subrinfo->tblinfo->dobj.catId.oid,
    5445            3 :                           subrinfo->srsubstate);
    5446              : 
    5447            3 :         if (subrinfo->srsublsn && subrinfo->srsublsn[0] != '\0')
    5448            2 :             appendPQExpBuffer(query, ", '%s'", subrinfo->srsublsn);
    5449              :         else
    5450            1 :             appendPQExpBufferStr(query, ", NULL");
    5451              : 
    5452            3 :         appendPQExpBufferStr(query, ");\n");
    5453              :     }
    5454              : 
    5455              :     /*
    5456              :      * There is no point in creating a drop query as the drop is done by table
    5457              :      * drop.  (If you think to change this, see also _printTocEntry().)
    5458              :      * Although this object doesn't really have ownership as such, set the
    5459              :      * owner field anyway to ensure that the command is run by the correct
    5460              :      * role at restore time.
    5461              :      */
    5462            3 :     if (subrinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
    5463            3 :         ArchiveEntry(fout, subrinfo->dobj.catId, subrinfo->dobj.dumpId,
    5464            3 :                      ARCHIVE_OPTS(.tag = tag,
    5465              :                                   .namespace = subrinfo->tblinfo->dobj.namespace->dobj.name,
    5466              :                                   .owner = subinfo->rolname,
    5467              :                                   .description = "SUBSCRIPTION TABLE",
    5468              :                                   .section = SECTION_POST_DATA,
    5469              :                                   .createStmt = query->data));
    5470              : 
    5471              :     /* These objects can't currently have comments or seclabels */
    5472              : 
    5473            3 :     free(tag);
    5474            3 :     destroyPQExpBuffer(query);
    5475              : }
    5476              : 
    5477              : /*
    5478              :  * dumpSubscription
    5479              :  *    dump the definition of the given subscription
    5480              :  */
    5481              : static void
    5482          110 : dumpSubscription(Archive *fout, const SubscriptionInfo *subinfo)
    5483              : {
    5484          110 :     DumpOptions *dopt = fout->dopt;
    5485              :     PQExpBuffer delq;
    5486              :     PQExpBuffer query;
    5487              :     PQExpBuffer publications;
    5488              :     char       *qsubname;
    5489          110 :     char      **pubnames = NULL;
    5490          110 :     int         npubnames = 0;
    5491              :     int         i;
    5492              : 
    5493              :     /* Do nothing if not dumping schema */
    5494          110 :     if (!dopt->dumpSchema)
    5495           18 :         return;
    5496              : 
    5497           92 :     delq = createPQExpBuffer();
    5498           92 :     query = createPQExpBuffer();
    5499              : 
    5500           92 :     qsubname = pg_strdup(fmtId(subinfo->dobj.name));
    5501              : 
    5502           92 :     appendPQExpBuffer(delq, "DROP SUBSCRIPTION %s;\n",
    5503              :                       qsubname);
    5504              : 
    5505           92 :     appendPQExpBuffer(query, "CREATE SUBSCRIPTION %s CONNECTION ",
    5506              :                       qsubname);
    5507           92 :     appendStringLiteralAH(query, subinfo->subconninfo, fout);
    5508              : 
    5509              :     /* Build list of quoted publications and append them to query. */
    5510           92 :     if (!parsePGArray(subinfo->subpublications, &pubnames, &npubnames))
    5511            0 :         pg_fatal("could not parse %s array", "subpublications");
    5512              : 
    5513           92 :     publications = createPQExpBuffer();
    5514          184 :     for (i = 0; i < npubnames; i++)
    5515              :     {
    5516           92 :         if (i > 0)
    5517            0 :             appendPQExpBufferStr(publications, ", ");
    5518              : 
    5519           92 :         appendPQExpBufferStr(publications, fmtId(pubnames[i]));
    5520              :     }
    5521              : 
    5522           92 :     appendPQExpBuffer(query, " PUBLICATION %s WITH (connect = false, slot_name = ", publications->data);
    5523           92 :     if (subinfo->subslotname)
    5524           92 :         appendStringLiteralAH(query, subinfo->subslotname, fout);
    5525              :     else
    5526            0 :         appendPQExpBufferStr(query, "NONE");
    5527              : 
    5528           92 :     if (subinfo->subbinary)
    5529            0 :         appendPQExpBufferStr(query, ", binary = true");
    5530              : 
    5531           92 :     if (subinfo->substream == LOGICALREP_STREAM_ON)
    5532           30 :         appendPQExpBufferStr(query, ", streaming = on");
    5533           62 :     else if (subinfo->substream == LOGICALREP_STREAM_PARALLEL)
    5534           32 :         appendPQExpBufferStr(query, ", streaming = parallel");
    5535              :     else
    5536           30 :         appendPQExpBufferStr(query, ", streaming = off");
    5537              : 
    5538           92 :     if (subinfo->subtwophasestate != LOGICALREP_TWOPHASE_STATE_DISABLED)
    5539            0 :         appendPQExpBufferStr(query, ", two_phase = on");
    5540              : 
    5541           92 :     if (subinfo->subdisableonerr)
    5542            0 :         appendPQExpBufferStr(query, ", disable_on_error = true");
    5543              : 
    5544           92 :     if (!subinfo->subpasswordrequired)
    5545            0 :         appendPQExpBufferStr(query, ", password_required = false");
    5546              : 
    5547           92 :     if (subinfo->subrunasowner)
    5548            0 :         appendPQExpBufferStr(query, ", run_as_owner = true");
    5549              : 
    5550           92 :     if (subinfo->subfailover)
    5551            1 :         appendPQExpBufferStr(query, ", failover = true");
    5552              : 
    5553           92 :     if (subinfo->subretaindeadtuples)
    5554            1 :         appendPQExpBufferStr(query, ", retain_dead_tuples = true");
    5555              : 
    5556           92 :     if (subinfo->submaxretention)
    5557            0 :         appendPQExpBuffer(query, ", max_retention_duration = %d", subinfo->submaxretention);
    5558              : 
    5559           92 :     if (strcmp(subinfo->subsynccommit, "off") != 0)
    5560            0 :         appendPQExpBuffer(query, ", synchronous_commit = %s", fmtId(subinfo->subsynccommit));
    5561              : 
    5562           92 :     if (strcmp(subinfo->subwalrcvtimeout, "-1") != 0)
    5563            0 :         appendPQExpBuffer(query, ", wal_receiver_timeout = %s", fmtId(subinfo->subwalrcvtimeout));
    5564              : 
    5565           92 :     if (pg_strcasecmp(subinfo->suborigin, LOGICALREP_ORIGIN_ANY) != 0)
    5566           30 :         appendPQExpBuffer(query, ", origin = %s", subinfo->suborigin);
    5567              : 
    5568           92 :     appendPQExpBufferStr(query, ");\n");
    5569              : 
    5570              :     /*
    5571              :      * In binary-upgrade mode, we allow the replication to continue after the
    5572              :      * upgrade.
    5573              :      */
    5574           92 :     if (dopt->binary_upgrade && fout->remoteVersion >= 170000)
    5575              :     {
    5576            5 :         if (subinfo->suboriginremotelsn)
    5577              :         {
    5578              :             /*
    5579              :              * Preserve the remote_lsn for the subscriber's replication
    5580              :              * origin. This value is required to start the replication from
    5581              :              * the position before the upgrade. This value will be stale if
    5582              :              * the publisher gets upgraded before the subscriber node.
    5583              :              * However, this shouldn't be a problem as the upgrade of the
    5584              :              * publisher ensures that all the transactions were replicated
    5585              :              * before upgrading it.
    5586              :              */
    5587            1 :             appendPQExpBufferStr(query,
    5588              :                                  "\n-- For binary upgrade, must preserve the remote_lsn for the subscriber's replication origin.\n");
    5589            1 :             appendPQExpBufferStr(query,
    5590              :                                  "SELECT pg_catalog.binary_upgrade_replorigin_advance(");
    5591            1 :             appendStringLiteralAH(query, subinfo->dobj.name, fout);
    5592            1 :             appendPQExpBuffer(query, ", '%s');\n", subinfo->suboriginremotelsn);
    5593              :         }
    5594              : 
    5595            5 :         if (subinfo->subenabled)
    5596              :         {
    5597              :             /*
    5598              :              * Enable the subscription to allow the replication to continue
    5599              :              * after the upgrade.
    5600              :              */
    5601            1 :             appendPQExpBufferStr(query,
    5602              :                                  "\n-- For binary upgrade, must preserve the subscriber's running state.\n");
    5603            1 :             appendPQExpBuffer(query, "ALTER SUBSCRIPTION %s ENABLE;\n", qsubname);
    5604              :         }
    5605              :     }
    5606              : 
    5607           92 :     if (subinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
    5608           92 :         ArchiveEntry(fout, subinfo->dobj.catId, subinfo->dobj.dumpId,
    5609           92 :                      ARCHIVE_OPTS(.tag = subinfo->dobj.name,
    5610              :                                   .owner = subinfo->rolname,
    5611              :                                   .description = "SUBSCRIPTION",
    5612              :                                   .section = SECTION_POST_DATA,
    5613              :                                   .createStmt = query->data,
    5614              :                                   .dropStmt = delq->data));
    5615              : 
    5616           92 :     if (subinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
    5617           30 :         dumpComment(fout, "SUBSCRIPTION", qsubname,
    5618           30 :                     NULL, subinfo->rolname,
    5619           30 :                     subinfo->dobj.catId, 0, subinfo->dobj.dumpId);
    5620              : 
    5621           92 :     if (subinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
    5622            0 :         dumpSecLabel(fout, "SUBSCRIPTION", qsubname,
    5623            0 :                      NULL, subinfo->rolname,
    5624            0 :                      subinfo->dobj.catId, 0, subinfo->dobj.dumpId);
    5625              : 
    5626           92 :     destroyPQExpBuffer(publications);
    5627           92 :     free(pubnames);
    5628              : 
    5629           92 :     destroyPQExpBuffer(delq);
    5630           92 :     destroyPQExpBuffer(query);
    5631           92 :     free(qsubname);
    5632              : }
    5633              : 
    5634              : /*
    5635              :  * Given a "create query", append as many ALTER ... DEPENDS ON EXTENSION as
    5636              :  * the object needs.
    5637              :  */
    5638              : static void
    5639         5084 : append_depends_on_extension(Archive *fout,
    5640              :                             PQExpBuffer create,
    5641              :                             const DumpableObject *dobj,
    5642              :                             const char *catalog,
    5643              :                             const char *keyword,
    5644              :                             const char *objname)
    5645              : {
    5646         5084 :     if (dobj->depends_on_ext)
    5647              :     {
    5648              :         char       *nm;
    5649              :         PGresult   *res;
    5650              :         PQExpBuffer query;
    5651              :         int         ntups;
    5652              :         int         i_extname;
    5653              :         int         i;
    5654              : 
    5655              :         /* dodge fmtId() non-reentrancy */
    5656           42 :         nm = pg_strdup(objname);
    5657              : 
    5658           42 :         query = createPQExpBuffer();
    5659           42 :         appendPQExpBuffer(query,
    5660              :                           "SELECT e.extname "
    5661              :                           "FROM pg_catalog.pg_depend d, pg_catalog.pg_extension e "
    5662              :                           "WHERE d.refobjid = e.oid AND classid = '%s'::pg_catalog.regclass "
    5663              :                           "AND objid = '%u'::pg_catalog.oid AND deptype = 'x' "
    5664              :                           "AND refclassid = 'pg_catalog.pg_extension'::pg_catalog.regclass",
    5665              :                           catalog,
    5666           42 :                           dobj->catId.oid);
    5667           42 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    5668           42 :         ntups = PQntuples(res);
    5669           42 :         i_extname = PQfnumber(res, "extname");
    5670           84 :         for (i = 0; i < ntups; i++)
    5671              :         {
    5672           42 :             appendPQExpBuffer(create, "\nALTER %s %s DEPENDS ON EXTENSION %s;",
    5673              :                               keyword, nm,
    5674           42 :                               fmtId(PQgetvalue(res, i, i_extname)));
    5675              :         }
    5676              : 
    5677           42 :         PQclear(res);
    5678           42 :         destroyPQExpBuffer(query);
    5679           42 :         pg_free(nm);
    5680              :     }
    5681         5084 : }
    5682              : 
    5683              : static Oid
    5684            0 : get_next_possible_free_pg_type_oid(Archive *fout, PQExpBuffer upgrade_query)
    5685              : {
    5686              :     /*
    5687              :      * If the old version didn't assign an array type, but the new version
    5688              :      * does, we must select an unused type OID to assign.  This currently only
    5689              :      * happens for domains, when upgrading pre-v11 to v11 and up.
    5690              :      *
    5691              :      * Note: local state here is kind of ugly, but we must have some, since we
    5692              :      * mustn't choose the same unused OID more than once.
    5693              :      */
    5694              :     static Oid  next_possible_free_oid = FirstNormalObjectId;
    5695              :     PGresult   *res;
    5696              :     bool        is_dup;
    5697              : 
    5698              :     do
    5699              :     {
    5700            0 :         ++next_possible_free_oid;
    5701            0 :         printfPQExpBuffer(upgrade_query,
    5702              :                           "SELECT EXISTS(SELECT 1 "
    5703              :                           "FROM pg_catalog.pg_type "
    5704              :                           "WHERE oid = '%u'::pg_catalog.oid);",
    5705              :                           next_possible_free_oid);
    5706            0 :         res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data);
    5707            0 :         is_dup = (PQgetvalue(res, 0, 0)[0] == 't');
    5708            0 :         PQclear(res);
    5709            0 :     } while (is_dup);
    5710              : 
    5711            0 :     return next_possible_free_oid;
    5712              : }
    5713              : 
    5714              : static void
    5715          949 : binary_upgrade_set_type_oids_by_type_oid(Archive *fout,
    5716              :                                          PQExpBuffer upgrade_buffer,
    5717              :                                          Oid pg_type_oid,
    5718              :                                          bool force_array_type,
    5719              :                                          bool include_multirange_type)
    5720              : {
    5721          949 :     PQExpBuffer upgrade_query = createPQExpBuffer();
    5722              :     PGresult   *res;
    5723              :     Oid         pg_type_array_oid;
    5724              :     Oid         pg_type_multirange_oid;
    5725              :     Oid         pg_type_multirange_array_oid;
    5726              :     TypeInfo   *tinfo;
    5727              : 
    5728          949 :     appendPQExpBufferStr(upgrade_buffer, "\n-- For binary upgrade, must preserve pg_type oid\n");
    5729          949 :     appendPQExpBuffer(upgrade_buffer,
    5730              :                       "SELECT pg_catalog.binary_upgrade_set_next_pg_type_oid('%u'::pg_catalog.oid);\n\n",
    5731              :                       pg_type_oid);
    5732              : 
    5733          949 :     tinfo = findTypeByOid(pg_type_oid);
    5734          949 :     if (tinfo)
    5735          949 :         pg_type_array_oid = tinfo->typarray;
    5736              :     else
    5737            0 :         pg_type_array_oid = InvalidOid;
    5738              : 
    5739          949 :     if (!OidIsValid(pg_type_array_oid) && force_array_type)
    5740            0 :         pg_type_array_oid = get_next_possible_free_pg_type_oid(fout, upgrade_query);
    5741              : 
    5742          949 :     if (OidIsValid(pg_type_array_oid))
    5743              :     {
    5744          947 :         appendPQExpBufferStr(upgrade_buffer,
    5745              :                              "\n-- For binary upgrade, must preserve pg_type array oid\n");
    5746          947 :         appendPQExpBuffer(upgrade_buffer,
    5747              :                           "SELECT pg_catalog.binary_upgrade_set_next_array_pg_type_oid('%u'::pg_catalog.oid);\n\n",
    5748              :                           pg_type_array_oid);
    5749              :     }
    5750              : 
    5751              :     /*
    5752              :      * Pre-set the multirange type oid and its own array type oid.
    5753              :      */
    5754          949 :     if (include_multirange_type)
    5755              :     {
    5756            8 :         if (fout->remoteVersion >= 140000)
    5757              :         {
    5758            8 :             printfPQExpBuffer(upgrade_query,
    5759              :                               "SELECT t.oid, t.typarray "
    5760              :                               "FROM pg_catalog.pg_type t "
    5761              :                               "JOIN pg_catalog.pg_range r "
    5762              :                               "ON t.oid = r.rngmultitypid "
    5763              :                               "WHERE r.rngtypid = '%u'::pg_catalog.oid;",
    5764              :                               pg_type_oid);
    5765              : 
    5766            8 :             res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data);
    5767              : 
    5768            8 :             pg_type_multirange_oid = atooid(PQgetvalue(res, 0, PQfnumber(res, "oid")));
    5769            8 :             pg_type_multirange_array_oid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typarray")));
    5770              : 
    5771            8 :             PQclear(res);
    5772              :         }
    5773              :         else
    5774              :         {
    5775            0 :             pg_type_multirange_oid = get_next_possible_free_pg_type_oid(fout, upgrade_query);
    5776            0 :             pg_type_multirange_array_oid = get_next_possible_free_pg_type_oid(fout, upgrade_query);
    5777              :         }
    5778              : 
    5779            8 :         appendPQExpBufferStr(upgrade_buffer,
    5780              :                              "\n-- For binary upgrade, must preserve multirange pg_type oid\n");
    5781            8 :         appendPQExpBuffer(upgrade_buffer,
    5782              :                           "SELECT pg_catalog.binary_upgrade_set_next_multirange_pg_type_oid('%u'::pg_catalog.oid);\n\n",
    5783              :                           pg_type_multirange_oid);
    5784            8 :         appendPQExpBufferStr(upgrade_buffer,
    5785              :                              "\n-- For binary upgrade, must preserve multirange pg_type array oid\n");
    5786            8 :         appendPQExpBuffer(upgrade_buffer,
    5787              :                           "SELECT pg_catalog.binary_upgrade_set_next_multirange_array_pg_type_oid('%u'::pg_catalog.oid);\n\n",
    5788              :                           pg_type_multirange_array_oid);
    5789              :     }
    5790              : 
    5791          949 :     destroyPQExpBuffer(upgrade_query);
    5792          949 : }
    5793              : 
    5794              : static void
    5795          874 : binary_upgrade_set_type_oids_by_rel(Archive *fout,
    5796              :                                     PQExpBuffer upgrade_buffer,
    5797              :                                     const TableInfo *tbinfo)
    5798              : {
    5799          874 :     Oid         pg_type_oid = tbinfo->reltype;
    5800              : 
    5801          874 :     if (OidIsValid(pg_type_oid))
    5802          874 :         binary_upgrade_set_type_oids_by_type_oid(fout, upgrade_buffer,
    5803              :                                                  pg_type_oid, false, false);
    5804          874 : }
    5805              : 
    5806              : /*
    5807              :  * bsearch() comparator for BinaryUpgradeClassOidItem
    5808              :  */
    5809              : static int
    5810        12461 : BinaryUpgradeClassOidItemCmp(const void *p1, const void *p2)
    5811              : {
    5812        12461 :     BinaryUpgradeClassOidItem v1 = *((const BinaryUpgradeClassOidItem *) p1);
    5813        12461 :     BinaryUpgradeClassOidItem v2 = *((const BinaryUpgradeClassOidItem *) p2);
    5814              : 
    5815        12461 :     return pg_cmp_u32(v1.oid, v2.oid);
    5816              : }
    5817              : 
    5818              : /*
    5819              :  * collectBinaryUpgradeClassOids
    5820              :  *
    5821              :  * Construct a table of pg_class information required for
    5822              :  * binary_upgrade_set_pg_class_oids().  The table is sorted by OID for speed in
    5823              :  * lookup.
    5824              :  */
    5825              : static void
    5826           38 : collectBinaryUpgradeClassOids(Archive *fout)
    5827              : {
    5828              :     PGresult   *res;
    5829              :     const char *query;
    5830              : 
    5831           38 :     query = "SELECT c.oid, c.relkind, c.relfilenode, c.reltoastrelid, "
    5832              :         "ct.relfilenode, i.indexrelid, cti.relfilenode "
    5833              :         "FROM pg_catalog.pg_class c LEFT JOIN pg_catalog.pg_index i "
    5834              :         "ON (c.reltoastrelid = i.indrelid AND i.indisvalid) "
    5835              :         "LEFT JOIN pg_catalog.pg_class ct ON (c.reltoastrelid = ct.oid) "
    5836              :         "LEFT JOIN pg_catalog.pg_class AS cti ON (i.indexrelid = cti.oid) "
    5837              :         "ORDER BY c.oid;";
    5838              : 
    5839           38 :     res = ExecuteSqlQuery(fout, query, PGRES_TUPLES_OK);
    5840              : 
    5841           38 :     nbinaryUpgradeClassOids = PQntuples(res);
    5842           38 :     binaryUpgradeClassOids =
    5843           38 :         pg_malloc_array(BinaryUpgradeClassOidItem, nbinaryUpgradeClassOids);
    5844              : 
    5845        17704 :     for (int i = 0; i < nbinaryUpgradeClassOids; i++)
    5846              :     {
    5847        17666 :         binaryUpgradeClassOids[i].oid = atooid(PQgetvalue(res, i, 0));
    5848        17666 :         binaryUpgradeClassOids[i].relkind = *PQgetvalue(res, i, 1);
    5849        17666 :         binaryUpgradeClassOids[i].relfilenumber = atooid(PQgetvalue(res, i, 2));
    5850        17666 :         binaryUpgradeClassOids[i].toast_oid = atooid(PQgetvalue(res, i, 3));
    5851        17666 :         binaryUpgradeClassOids[i].toast_relfilenumber = atooid(PQgetvalue(res, i, 4));
    5852        17666 :         binaryUpgradeClassOids[i].toast_index_oid = atooid(PQgetvalue(res, i, 5));
    5853        17666 :         binaryUpgradeClassOids[i].toast_index_relfilenumber = atooid(PQgetvalue(res, i, 6));
    5854              :     }
    5855              : 
    5856           38 :     PQclear(res);
    5857           38 : }
    5858              : 
    5859              : static void
    5860         1266 : binary_upgrade_set_pg_class_oids(Archive *fout,
    5861              :                                  PQExpBuffer upgrade_buffer, Oid pg_class_oid)
    5862              : {
    5863         1266 :     BinaryUpgradeClassOidItem key = {0};
    5864              :     BinaryUpgradeClassOidItem *entry;
    5865              : 
    5866              :     Assert(binaryUpgradeClassOids);
    5867              : 
    5868              :     /*
    5869              :      * Preserve the OID and relfilenumber of the table, table's index, table's
    5870              :      * toast table and toast table's index if any.
    5871              :      *
    5872              :      * One complexity is that the current table definition might not require
    5873              :      * the creation of a TOAST table, but the old database might have a TOAST
    5874              :      * table that was created earlier, before some wide columns were dropped.
    5875              :      * By setting the TOAST oid we force creation of the TOAST heap and index
    5876              :      * by the new backend, so we can copy the files during binary upgrade
    5877              :      * without worrying about this case.
    5878              :      */
    5879         1266 :     key.oid = pg_class_oid;
    5880         1266 :     entry = bsearch(&key, binaryUpgradeClassOids, nbinaryUpgradeClassOids,
    5881              :                     sizeof(BinaryUpgradeClassOidItem),
    5882              :                     BinaryUpgradeClassOidItemCmp);
    5883              : 
    5884         1266 :     appendPQExpBufferStr(upgrade_buffer,
    5885              :                          "\n-- For binary upgrade, must preserve pg_class oids and relfilenodes\n");
    5886              : 
    5887         1266 :     if (entry->relkind != RELKIND_INDEX &&
    5888          986 :         entry->relkind != RELKIND_PARTITIONED_INDEX)
    5889              :     {
    5890          958 :         appendPQExpBuffer(upgrade_buffer,
    5891              :                           "SELECT pg_catalog.binary_upgrade_set_next_heap_pg_class_oid('%u'::pg_catalog.oid);\n",
    5892              :                           pg_class_oid);
    5893              : 
    5894              :         /*
    5895              :          * Not every relation has storage. Also, in a pre-v12 database,
    5896              :          * partitioned tables have a relfilenumber, which should not be
    5897              :          * preserved when upgrading.
    5898              :          */
    5899          958 :         if (RelFileNumberIsValid(entry->relfilenumber) &&
    5900          794 :             entry->relkind != RELKIND_PARTITIONED_TABLE)
    5901          794 :             appendPQExpBuffer(upgrade_buffer,
    5902              :                               "SELECT pg_catalog.binary_upgrade_set_next_heap_relfilenode('%u'::pg_catalog.oid);\n",
    5903              :                               entry->relfilenumber);
    5904              : 
    5905              :         /*
    5906              :          * In a pre-v12 database, partitioned tables might be marked as having
    5907              :          * toast tables, but we should ignore them if so.
    5908              :          */
    5909          958 :         if (OidIsValid(entry->toast_oid) &&
    5910          277 :             entry->relkind != RELKIND_PARTITIONED_TABLE)
    5911              :         {
    5912          277 :             appendPQExpBuffer(upgrade_buffer,
    5913              :                               "SELECT pg_catalog.binary_upgrade_set_next_toast_pg_class_oid('%u'::pg_catalog.oid);\n",
    5914              :                               entry->toast_oid);
    5915          277 :             appendPQExpBuffer(upgrade_buffer,
    5916              :                               "SELECT pg_catalog.binary_upgrade_set_next_toast_relfilenode('%u'::pg_catalog.oid);\n",
    5917              :                               entry->toast_relfilenumber);
    5918              : 
    5919              :             /* every toast table has an index */
    5920          277 :             appendPQExpBuffer(upgrade_buffer,
    5921              :                               "SELECT pg_catalog.binary_upgrade_set_next_index_pg_class_oid('%u'::pg_catalog.oid);\n",
    5922              :                               entry->toast_index_oid);
    5923          277 :             appendPQExpBuffer(upgrade_buffer,
    5924              :                               "SELECT pg_catalog.binary_upgrade_set_next_index_relfilenode('%u'::pg_catalog.oid);\n",
    5925              :                               entry->toast_index_relfilenumber);
    5926              :         }
    5927              :     }
    5928              :     else
    5929              :     {
    5930              :         /* Preserve the OID and relfilenumber of the index */
    5931          308 :         appendPQExpBuffer(upgrade_buffer,
    5932              :                           "SELECT pg_catalog.binary_upgrade_set_next_index_pg_class_oid('%u'::pg_catalog.oid);\n",
    5933              :                           pg_class_oid);
    5934          308 :         appendPQExpBuffer(upgrade_buffer,
    5935              :                           "SELECT pg_catalog.binary_upgrade_set_next_index_relfilenode('%u'::pg_catalog.oid);\n",
    5936              :                           entry->relfilenumber);
    5937              :     }
    5938              : 
    5939         1266 :     appendPQExpBufferChar(upgrade_buffer, '\n');
    5940         1266 : }
    5941              : 
    5942              : /*
    5943              :  * If the DumpableObject is a member of an extension, add a suitable
    5944              :  * ALTER EXTENSION ADD command to the creation commands in upgrade_buffer.
    5945              :  *
    5946              :  * For somewhat historical reasons, objname should already be quoted,
    5947              :  * but not objnamespace (if any).
    5948              :  */
    5949              : static void
    5950         1516 : binary_upgrade_extension_member(PQExpBuffer upgrade_buffer,
    5951              :                                 const DumpableObject *dobj,
    5952              :                                 const char *objtype,
    5953              :                                 const char *objname,
    5954              :                                 const char *objnamespace)
    5955              : {
    5956         1516 :     DumpableObject *extobj = NULL;
    5957              :     int         i;
    5958              : 
    5959         1516 :     if (!dobj->ext_member)
    5960         1495 :         return;
    5961              : 
    5962              :     /*
    5963              :      * Find the parent extension.  We could avoid this search if we wanted to
    5964              :      * add a link field to DumpableObject, but the space costs of that would
    5965              :      * be considerable.  We assume that member objects could only have a
    5966              :      * direct dependency on their own extension, not any others.
    5967              :      */
    5968           21 :     for (i = 0; i < dobj->nDeps; i++)
    5969              :     {
    5970           21 :         extobj = findObjectByDumpId(dobj->dependencies[i]);
    5971           21 :         if (extobj && extobj->objType == DO_EXTENSION)
    5972           21 :             break;
    5973            0 :         extobj = NULL;
    5974              :     }
    5975           21 :     if (extobj == NULL)
    5976            0 :         pg_fatal("could not find parent extension for %s %s",
    5977              :                  objtype, objname);
    5978              : 
    5979           21 :     appendPQExpBufferStr(upgrade_buffer,
    5980              :                          "\n-- For binary upgrade, handle extension membership the hard way\n");
    5981           21 :     appendPQExpBuffer(upgrade_buffer, "ALTER EXTENSION %s ADD %s ",
    5982           21 :                       fmtId(extobj->name),
    5983              :                       objtype);
    5984           21 :     if (objnamespace && *objnamespace)
    5985           18 :         appendPQExpBuffer(upgrade_buffer, "%s.", fmtId(objnamespace));
    5986           21 :     appendPQExpBuffer(upgrade_buffer, "%s;\n", objname);
    5987              : }
    5988              : 
    5989              : /*
    5990              :  * getNamespaces:
    5991              :  *    get information about all namespaces in the system catalogs
    5992              :  */
    5993              : void
    5994          250 : getNamespaces(Archive *fout)
    5995              : {
    5996              :     PGresult   *res;
    5997              :     int         ntups;
    5998              :     int         i;
    5999              :     PQExpBuffer query;
    6000              :     NamespaceInfo *nsinfo;
    6001              :     int         i_tableoid;
    6002              :     int         i_oid;
    6003              :     int         i_nspname;
    6004              :     int         i_nspowner;
    6005              :     int         i_nspacl;
    6006              :     int         i_acldefault;
    6007              : 
    6008          250 :     query = createPQExpBuffer();
    6009              : 
    6010              :     /*
    6011              :      * we fetch all namespaces including system ones, so that every object we
    6012              :      * read in can be linked to a containing namespace.
    6013              :      */
    6014          250 :     appendPQExpBufferStr(query, "SELECT n.tableoid, n.oid, n.nspname, "
    6015              :                          "n.nspowner, "
    6016              :                          "n.nspacl, "
    6017              :                          "acldefault('n', n.nspowner) AS acldefault "
    6018              :                          "FROM pg_namespace n");
    6019              : 
    6020          250 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    6021              : 
    6022          250 :     ntups = PQntuples(res);
    6023              : 
    6024          250 :     nsinfo = pg_malloc_array(NamespaceInfo, ntups);
    6025              : 
    6026          250 :     i_tableoid = PQfnumber(res, "tableoid");
    6027          250 :     i_oid = PQfnumber(res, "oid");
    6028          250 :     i_nspname = PQfnumber(res, "nspname");
    6029          250 :     i_nspowner = PQfnumber(res, "nspowner");
    6030          250 :     i_nspacl = PQfnumber(res, "nspacl");
    6031          250 :     i_acldefault = PQfnumber(res, "acldefault");
    6032              : 
    6033         1964 :     for (i = 0; i < ntups; i++)
    6034              :     {
    6035              :         const char *nspowner;
    6036              : 
    6037         1714 :         nsinfo[i].dobj.objType = DO_NAMESPACE;
    6038         1714 :         nsinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    6039         1714 :         nsinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    6040         1714 :         AssignDumpId(&nsinfo[i].dobj);
    6041         1714 :         nsinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_nspname));
    6042         1714 :         nsinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_nspacl));
    6043         1714 :         nsinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
    6044         1714 :         nsinfo[i].dacl.privtype = 0;
    6045         1714 :         nsinfo[i].dacl.initprivs = NULL;
    6046         1714 :         nspowner = PQgetvalue(res, i, i_nspowner);
    6047         1714 :         nsinfo[i].nspowner = atooid(nspowner);
    6048         1714 :         nsinfo[i].rolname = getRoleName(nspowner);
    6049              : 
    6050              :         /* Decide whether to dump this namespace */
    6051         1714 :         selectDumpableNamespace(&nsinfo[i], fout);
    6052              : 
    6053              :         /* Mark whether namespace has an ACL */
    6054         1714 :         if (!PQgetisnull(res, i, i_nspacl))
    6055          820 :             nsinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
    6056              : 
    6057              :         /*
    6058              :          * We ignore any pg_init_privs.initprivs entry for the public schema
    6059              :          * and assume a predetermined default, for several reasons.  First,
    6060              :          * dropping and recreating the schema removes its pg_init_privs entry,
    6061              :          * but an empty destination database starts with this ACL nonetheless.
    6062              :          * Second, we support dump/reload of public schema ownership changes.
    6063              :          * ALTER SCHEMA OWNER filters nspacl through aclnewowner(), but
    6064              :          * initprivs continues to reflect the initial owner.  Hence,
    6065              :          * synthesize the value that nspacl will have after the restore's
    6066              :          * ALTER SCHEMA OWNER.  Third, this makes the destination database
    6067              :          * match the source's ACL, even if the latter was an initdb-default
    6068              :          * ACL, which changed in v15.  An upgrade pulls in changes to most
    6069              :          * system object ACLs that the DBA had not customized.  We've made the
    6070              :          * public schema depart from that, because changing its ACL so easily
    6071              :          * breaks applications.
    6072              :          */
    6073         1714 :         if (strcmp(nsinfo[i].dobj.name, "public") == 0)
    6074              :         {
    6075          246 :             PQExpBuffer aclarray = createPQExpBuffer();
    6076          246 :             PQExpBuffer aclitem = createPQExpBuffer();
    6077              : 
    6078              :             /* Standard ACL as of v15 is {owner=UC/owner,=U/owner} */
    6079          246 :             appendPQExpBufferChar(aclarray, '{');
    6080          246 :             quoteAclUserName(aclitem, nsinfo[i].rolname);
    6081          246 :             appendPQExpBufferStr(aclitem, "=UC/");
    6082          246 :             quoteAclUserName(aclitem, nsinfo[i].rolname);
    6083          246 :             appendPGArray(aclarray, aclitem->data);
    6084          246 :             resetPQExpBuffer(aclitem);
    6085          246 :             appendPQExpBufferStr(aclitem, "=U/");
    6086          246 :             quoteAclUserName(aclitem, nsinfo[i].rolname);
    6087          246 :             appendPGArray(aclarray, aclitem->data);
    6088          246 :             appendPQExpBufferChar(aclarray, '}');
    6089              : 
    6090          246 :             nsinfo[i].dacl.privtype = 'i';
    6091          246 :             nsinfo[i].dacl.initprivs = pstrdup(aclarray->data);
    6092          246 :             nsinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
    6093              : 
    6094          246 :             destroyPQExpBuffer(aclarray);
    6095          246 :             destroyPQExpBuffer(aclitem);
    6096              :         }
    6097              :     }
    6098              : 
    6099          250 :     PQclear(res);
    6100          250 :     destroyPQExpBuffer(query);
    6101          250 : }
    6102              : 
    6103              : /*
    6104              :  * findNamespace:
    6105              :  *      given a namespace OID, look up the info read by getNamespaces
    6106              :  */
    6107              : static NamespaceInfo *
    6108       795734 : findNamespace(Oid nsoid)
    6109              : {
    6110              :     NamespaceInfo *nsinfo;
    6111              : 
    6112       795734 :     nsinfo = findNamespaceByOid(nsoid);
    6113       795734 :     if (nsinfo == NULL)
    6114            0 :         pg_fatal("schema with OID %u does not exist", nsoid);
    6115       795734 :     return nsinfo;
    6116              : }
    6117              : 
    6118              : /*
    6119              :  * getExtensions:
    6120              :  *    read all extensions in the system catalogs and return them in the
    6121              :  * ExtensionInfo* structure
    6122              :  *
    6123              :  *  numExtensions is set to the number of extensions read in
    6124              :  */
    6125              : ExtensionInfo *
    6126          250 : getExtensions(Archive *fout, int *numExtensions)
    6127              : {
    6128          250 :     DumpOptions *dopt = fout->dopt;
    6129              :     PGresult   *res;
    6130              :     int         ntups;
    6131              :     int         i;
    6132              :     PQExpBuffer query;
    6133          250 :     ExtensionInfo *extinfo = NULL;
    6134              :     int         i_tableoid;
    6135              :     int         i_oid;
    6136              :     int         i_extname;
    6137              :     int         i_nspname;
    6138              :     int         i_extrelocatable;
    6139              :     int         i_extversion;
    6140              :     int         i_extconfig;
    6141              :     int         i_extcondition;
    6142              : 
    6143          250 :     query = createPQExpBuffer();
    6144              : 
    6145          250 :     appendPQExpBufferStr(query, "SELECT x.tableoid, x.oid, "
    6146              :                          "x.extname, n.nspname, x.extrelocatable, x.extversion, x.extconfig, x.extcondition "
    6147              :                          "FROM pg_extension x "
    6148              :                          "JOIN pg_namespace n ON n.oid = x.extnamespace");
    6149              : 
    6150          250 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    6151              : 
    6152          250 :     ntups = PQntuples(res);
    6153          250 :     if (ntups == 0)
    6154            0 :         goto cleanup;
    6155              : 
    6156          250 :     extinfo = pg_malloc_array(ExtensionInfo, ntups);
    6157              : 
    6158          250 :     i_tableoid = PQfnumber(res, "tableoid");
    6159          250 :     i_oid = PQfnumber(res, "oid");
    6160          250 :     i_extname = PQfnumber(res, "extname");
    6161          250 :     i_nspname = PQfnumber(res, "nspname");
    6162          250 :     i_extrelocatable = PQfnumber(res, "extrelocatable");
    6163          250 :     i_extversion = PQfnumber(res, "extversion");
    6164          250 :     i_extconfig = PQfnumber(res, "extconfig");
    6165          250 :     i_extcondition = PQfnumber(res, "extcondition");
    6166              : 
    6167          530 :     for (i = 0; i < ntups; i++)
    6168              :     {
    6169          280 :         extinfo[i].dobj.objType = DO_EXTENSION;
    6170          280 :         extinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    6171          280 :         extinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    6172          280 :         AssignDumpId(&extinfo[i].dobj);
    6173          280 :         extinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_extname));
    6174          280 :         extinfo[i].namespace = pg_strdup(PQgetvalue(res, i, i_nspname));
    6175          280 :         extinfo[i].relocatable = *(PQgetvalue(res, i, i_extrelocatable)) == 't';
    6176          280 :         extinfo[i].extversion = pg_strdup(PQgetvalue(res, i, i_extversion));
    6177          280 :         extinfo[i].extconfig = pg_strdup(PQgetvalue(res, i, i_extconfig));
    6178          280 :         extinfo[i].extcondition = pg_strdup(PQgetvalue(res, i, i_extcondition));
    6179              : 
    6180              :         /* Decide whether we want to dump it */
    6181          280 :         selectDumpableExtension(&(extinfo[i]), dopt);
    6182              :     }
    6183              : 
    6184          250 : cleanup:
    6185          250 :     PQclear(res);
    6186          250 :     destroyPQExpBuffer(query);
    6187              : 
    6188          250 :     *numExtensions = ntups;
    6189              : 
    6190          250 :     return extinfo;
    6191              : }
    6192              : 
    6193              : /*
    6194              :  * getTypes:
    6195              :  *    get information about all types in the system catalogs
    6196              :  *
    6197              :  * NB: this must run after getFuncs() because we assume we can do
    6198              :  * findFuncByOid().
    6199              :  */
    6200              : void
    6201          249 : getTypes(Archive *fout)
    6202              : {
    6203              :     PGresult   *res;
    6204              :     int         ntups;
    6205              :     int         i;
    6206          249 :     PQExpBuffer query = createPQExpBuffer();
    6207              :     TypeInfo   *tyinfo;
    6208              :     ShellTypeInfo *stinfo;
    6209              :     int         i_tableoid;
    6210              :     int         i_oid;
    6211              :     int         i_typname;
    6212              :     int         i_typnamespace;
    6213              :     int         i_typacl;
    6214              :     int         i_acldefault;
    6215              :     int         i_typowner;
    6216              :     int         i_typelem;
    6217              :     int         i_typrelid;
    6218              :     int         i_typrelkind;
    6219              :     int         i_typtype;
    6220              :     int         i_typisdefined;
    6221              :     int         i_isarray;
    6222              :     int         i_typarray;
    6223              : 
    6224              :     /*
    6225              :      * we include even the built-in types because those may be used as array
    6226              :      * elements by user-defined types
    6227              :      *
    6228              :      * we filter out the built-in types when we dump out the types
    6229              :      *
    6230              :      * same approach for undefined (shell) types and array types
    6231              :      *
    6232              :      * Note: as of 8.3 we can reliably detect whether a type is an
    6233              :      * auto-generated array type by checking the element type's typarray.
    6234              :      * (Before that the test is capable of generating false positives.) We
    6235              :      * still check for name beginning with '_', though, so as to avoid the
    6236              :      * cost of the subselect probe for all standard types.  This would have to
    6237              :      * be revisited if the backend ever allows renaming of array types.
    6238              :      */
    6239          249 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, typname, "
    6240              :                          "typnamespace, typacl, "
    6241              :                          "acldefault('T', typowner) AS acldefault, "
    6242              :                          "typowner, "
    6243              :                          "typelem, typrelid, typarray, "
    6244              :                          "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
    6245              :                          "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
    6246              :                          "typtype, typisdefined, "
    6247              :                          "typname[0] = '_' AND typelem != 0 AND "
    6248              :                          "(SELECT typarray FROM pg_type te WHERE oid = pg_type.typelem) = oid AS isarray "
    6249              :                          "FROM pg_type");
    6250              : 
    6251          249 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    6252              : 
    6253          249 :     ntups = PQntuples(res);
    6254              : 
    6255          249 :     tyinfo = pg_malloc_array(TypeInfo, ntups);
    6256              : 
    6257          249 :     i_tableoid = PQfnumber(res, "tableoid");
    6258          249 :     i_oid = PQfnumber(res, "oid");
    6259          249 :     i_typname = PQfnumber(res, "typname");
    6260          249 :     i_typnamespace = PQfnumber(res, "typnamespace");
    6261          249 :     i_typacl = PQfnumber(res, "typacl");
    6262          249 :     i_acldefault = PQfnumber(res, "acldefault");
    6263          249 :     i_typowner = PQfnumber(res, "typowner");
    6264          249 :     i_typelem = PQfnumber(res, "typelem");
    6265          249 :     i_typrelid = PQfnumber(res, "typrelid");
    6266          249 :     i_typrelkind = PQfnumber(res, "typrelkind");
    6267          249 :     i_typtype = PQfnumber(res, "typtype");
    6268          249 :     i_typisdefined = PQfnumber(res, "typisdefined");
    6269          249 :     i_isarray = PQfnumber(res, "isarray");
    6270          249 :     i_typarray = PQfnumber(res, "typarray");
    6271              : 
    6272       175574 :     for (i = 0; i < ntups; i++)
    6273              :     {
    6274       175325 :         tyinfo[i].dobj.objType = DO_TYPE;
    6275       175325 :         tyinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    6276       175325 :         tyinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    6277       175325 :         AssignDumpId(&tyinfo[i].dobj);
    6278       175325 :         tyinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_typname));
    6279       350650 :         tyinfo[i].dobj.namespace =
    6280       175325 :             findNamespace(atooid(PQgetvalue(res, i, i_typnamespace)));
    6281       175325 :         tyinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_typacl));
    6282       175325 :         tyinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
    6283       175325 :         tyinfo[i].dacl.privtype = 0;
    6284       175325 :         tyinfo[i].dacl.initprivs = NULL;
    6285       175325 :         tyinfo[i].ftypname = NULL;  /* may get filled later */
    6286       175325 :         tyinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_typowner));
    6287       175325 :         tyinfo[i].typelem = atooid(PQgetvalue(res, i, i_typelem));
    6288       175325 :         tyinfo[i].typrelid = atooid(PQgetvalue(res, i, i_typrelid));
    6289       175325 :         tyinfo[i].typrelkind = *PQgetvalue(res, i, i_typrelkind);
    6290       175325 :         tyinfo[i].typtype = *PQgetvalue(res, i, i_typtype);
    6291       175325 :         tyinfo[i].shellType = NULL;
    6292              : 
    6293       175325 :         if (strcmp(PQgetvalue(res, i, i_typisdefined), "t") == 0)
    6294       175273 :             tyinfo[i].isDefined = true;
    6295              :         else
    6296           52 :             tyinfo[i].isDefined = false;
    6297              : 
    6298       175325 :         if (strcmp(PQgetvalue(res, i, i_isarray), "t") == 0)
    6299        84026 :             tyinfo[i].isArray = true;
    6300              :         else
    6301        91299 :             tyinfo[i].isArray = false;
    6302              : 
    6303       175325 :         tyinfo[i].typarray = atooid(PQgetvalue(res, i, i_typarray));
    6304              : 
    6305       175325 :         if (tyinfo[i].typtype == TYPTYPE_MULTIRANGE)
    6306         1626 :             tyinfo[i].isMultirange = true;
    6307              :         else
    6308       173699 :             tyinfo[i].isMultirange = false;
    6309              : 
    6310              :         /* Decide whether we want to dump it */
    6311       175325 :         selectDumpableType(&tyinfo[i], fout);
    6312              : 
    6313              :         /* Mark whether type has an ACL */
    6314       175325 :         if (!PQgetisnull(res, i, i_typacl))
    6315          205 :             tyinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
    6316              : 
    6317              :         /*
    6318              :          * If it's a domain, fetch info about its constraints, if any
    6319              :          */
    6320       175325 :         tyinfo[i].nDomChecks = 0;
    6321       175325 :         tyinfo[i].domChecks = NULL;
    6322       175325 :         tyinfo[i].notnull = NULL;
    6323       175325 :         if ((tyinfo[i].dobj.dump & DUMP_COMPONENT_DEFINITION) &&
    6324        15449 :             tyinfo[i].typtype == TYPTYPE_DOMAIN)
    6325          158 :             getDomainConstraints(fout, &(tyinfo[i]));
    6326              : 
    6327              :         /*
    6328              :          * If it's a base type, make a DumpableObject representing a shell
    6329              :          * definition of the type.  We will need to dump that ahead of the I/O
    6330              :          * functions for the type.  Similarly, range types need a shell
    6331              :          * definition in case they have a canonicalize function.
    6332              :          *
    6333              :          * Note: the shell type doesn't have a catId.  You might think it
    6334              :          * should copy the base type's catId, but then it might capture the
    6335              :          * pg_depend entries for the type, which we don't want.
    6336              :          */
    6337       175325 :         if ((tyinfo[i].dobj.dump & DUMP_COMPONENT_DEFINITION) &&
    6338        15449 :             (tyinfo[i].typtype == TYPTYPE_BASE ||
    6339         7508 :              tyinfo[i].typtype == TYPTYPE_RANGE))
    6340              :         {
    6341         8065 :             stinfo = pg_malloc_object(ShellTypeInfo);
    6342         8065 :             stinfo->dobj.objType = DO_SHELL_TYPE;
    6343         8065 :             stinfo->dobj.catId = nilCatalogId;
    6344         8065 :             AssignDumpId(&stinfo->dobj);
    6345         8065 :             stinfo->dobj.name = pg_strdup(tyinfo[i].dobj.name);
    6346         8065 :             stinfo->dobj.namespace = tyinfo[i].dobj.namespace;
    6347         8065 :             stinfo->baseType = &(tyinfo[i]);
    6348         8065 :             tyinfo[i].shellType = stinfo;
    6349              : 
    6350              :             /*
    6351              :              * Initially mark the shell type as not to be dumped.  We'll only
    6352              :              * dump it if the I/O or canonicalize functions need to be dumped;
    6353              :              * this is taken care of while sorting dependencies.
    6354              :              */
    6355         8065 :             stinfo->dobj.dump = DUMP_COMPONENT_NONE;
    6356              :         }
    6357              :     }
    6358              : 
    6359          249 :     PQclear(res);
    6360              : 
    6361          249 :     destroyPQExpBuffer(query);
    6362          249 : }
    6363              : 
    6364              : /*
    6365              :  * getOperators:
    6366              :  *    get information about all operators in the system catalogs
    6367              :  */
    6368              : void
    6369          249 : getOperators(Archive *fout)
    6370              : {
    6371              :     PGresult   *res;
    6372              :     int         ntups;
    6373              :     int         i;
    6374          249 :     PQExpBuffer query = createPQExpBuffer();
    6375              :     OprInfo    *oprinfo;
    6376              :     int         i_tableoid;
    6377              :     int         i_oid;
    6378              :     int         i_oprname;
    6379              :     int         i_oprnamespace;
    6380              :     int         i_oprowner;
    6381              :     int         i_oprkind;
    6382              :     int         i_oprleft;
    6383              :     int         i_oprright;
    6384              :     int         i_oprcode;
    6385              : 
    6386              :     /*
    6387              :      * find all operators, including builtin operators; we filter out
    6388              :      * system-defined operators at dump-out time.
    6389              :      */
    6390              : 
    6391          249 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, oprname, "
    6392              :                          "oprnamespace, "
    6393              :                          "oprowner, "
    6394              :                          "oprkind, "
    6395              :                          "oprleft, "
    6396              :                          "oprright, "
    6397              :                          "oprcode::oid AS oprcode "
    6398              :                          "FROM pg_operator");
    6399              : 
    6400          249 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    6401              : 
    6402          249 :     ntups = PQntuples(res);
    6403              : 
    6404          249 :     oprinfo = pg_malloc_array(OprInfo, ntups);
    6405              : 
    6406          249 :     i_tableoid = PQfnumber(res, "tableoid");
    6407          249 :     i_oid = PQfnumber(res, "oid");
    6408          249 :     i_oprname = PQfnumber(res, "oprname");
    6409          249 :     i_oprnamespace = PQfnumber(res, "oprnamespace");
    6410          249 :     i_oprowner = PQfnumber(res, "oprowner");
    6411          249 :     i_oprkind = PQfnumber(res, "oprkind");
    6412          249 :     i_oprleft = PQfnumber(res, "oprleft");
    6413          249 :     i_oprright = PQfnumber(res, "oprright");
    6414          249 :     i_oprcode = PQfnumber(res, "oprcode");
    6415              : 
    6416       200836 :     for (i = 0; i < ntups; i++)
    6417              :     {
    6418       200587 :         oprinfo[i].dobj.objType = DO_OPERATOR;
    6419       200587 :         oprinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    6420       200587 :         oprinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    6421       200587 :         AssignDumpId(&oprinfo[i].dobj);
    6422       200587 :         oprinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_oprname));
    6423       401174 :         oprinfo[i].dobj.namespace =
    6424       200587 :             findNamespace(atooid(PQgetvalue(res, i, i_oprnamespace)));
    6425       200587 :         oprinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_oprowner));
    6426       200587 :         oprinfo[i].oprkind = (PQgetvalue(res, i, i_oprkind))[0];
    6427       200587 :         oprinfo[i].oprleft = atooid(PQgetvalue(res, i, i_oprleft));
    6428       200587 :         oprinfo[i].oprright = atooid(PQgetvalue(res, i, i_oprright));
    6429       200587 :         oprinfo[i].oprcode = atooid(PQgetvalue(res, i, i_oprcode));
    6430              : 
    6431              :         /* Decide whether we want to dump it */
    6432       200587 :         selectDumpableObject(&(oprinfo[i].dobj), fout);
    6433              :     }
    6434              : 
    6435          249 :     PQclear(res);
    6436              : 
    6437          249 :     destroyPQExpBuffer(query);
    6438          249 : }
    6439              : 
    6440              : /*
    6441              :  * getCollations:
    6442              :  *    get information about all collations in the system catalogs
    6443              :  */
    6444              : void
    6445          249 : getCollations(Archive *fout)
    6446              : {
    6447              :     PGresult   *res;
    6448              :     int         ntups;
    6449              :     int         i;
    6450              :     PQExpBuffer query;
    6451              :     CollInfo   *collinfo;
    6452              :     int         i_tableoid;
    6453              :     int         i_oid;
    6454              :     int         i_collname;
    6455              :     int         i_collnamespace;
    6456              :     int         i_collowner;
    6457              :     int         i_collencoding;
    6458              : 
    6459          249 :     query = createPQExpBuffer();
    6460              : 
    6461              :     /*
    6462              :      * find all collations, including builtin collations; we filter out
    6463              :      * system-defined collations at dump-out time.
    6464              :      */
    6465              : 
    6466          249 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, collname, "
    6467              :                          "collnamespace, "
    6468              :                          "collowner, "
    6469              :                          "collencoding "
    6470              :                          "FROM pg_collation");
    6471              : 
    6472          249 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    6473              : 
    6474          249 :     ntups = PQntuples(res);
    6475              : 
    6476          249 :     collinfo = pg_malloc_array(CollInfo, ntups);
    6477              : 
    6478          249 :     i_tableoid = PQfnumber(res, "tableoid");
    6479          249 :     i_oid = PQfnumber(res, "oid");
    6480          249 :     i_collname = PQfnumber(res, "collname");
    6481          249 :     i_collnamespace = PQfnumber(res, "collnamespace");
    6482          249 :     i_collowner = PQfnumber(res, "collowner");
    6483          249 :     i_collencoding = PQfnumber(res, "collencoding");
    6484              : 
    6485       219480 :     for (i = 0; i < ntups; i++)
    6486              :     {
    6487       219231 :         collinfo[i].dobj.objType = DO_COLLATION;
    6488       219231 :         collinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    6489       219231 :         collinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    6490       219231 :         AssignDumpId(&collinfo[i].dobj);
    6491       219231 :         collinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_collname));
    6492       438462 :         collinfo[i].dobj.namespace =
    6493       219231 :             findNamespace(atooid(PQgetvalue(res, i, i_collnamespace)));
    6494       219231 :         collinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_collowner));
    6495       219231 :         collinfo[i].collencoding = atoi(PQgetvalue(res, i, i_collencoding));
    6496              : 
    6497              :         /* Decide whether we want to dump it */
    6498       219231 :         selectDumpableObject(&(collinfo[i].dobj), fout);
    6499              :     }
    6500              : 
    6501          249 :     PQclear(res);
    6502              : 
    6503          249 :     destroyPQExpBuffer(query);
    6504          249 : }
    6505              : 
    6506              : /*
    6507              :  * getConversions:
    6508              :  *    get information about all conversions in the system catalogs
    6509              :  */
    6510              : void
    6511          249 : getConversions(Archive *fout)
    6512              : {
    6513              :     PGresult   *res;
    6514              :     int         ntups;
    6515              :     int         i;
    6516              :     PQExpBuffer query;
    6517              :     ConvInfo   *convinfo;
    6518              :     int         i_tableoid;
    6519              :     int         i_oid;
    6520              :     int         i_conname;
    6521              :     int         i_connamespace;
    6522              :     int         i_conowner;
    6523              : 
    6524          249 :     query = createPQExpBuffer();
    6525              : 
    6526              :     /*
    6527              :      * find all conversions, including builtin conversions; we filter out
    6528              :      * system-defined conversions at dump-out time.
    6529              :      */
    6530              : 
    6531          249 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, conname, "
    6532              :                          "connamespace, "
    6533              :                          "conowner "
    6534              :                          "FROM pg_conversion");
    6535              : 
    6536          249 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    6537              : 
    6538          249 :     ntups = PQntuples(res);
    6539              : 
    6540          249 :     convinfo = pg_malloc_array(ConvInfo, ntups);
    6541              : 
    6542          249 :     i_tableoid = PQfnumber(res, "tableoid");
    6543          249 :     i_oid = PQfnumber(res, "oid");
    6544          249 :     i_conname = PQfnumber(res, "conname");
    6545          249 :     i_connamespace = PQfnumber(res, "connamespace");
    6546          249 :     i_conowner = PQfnumber(res, "conowner");
    6547              : 
    6548        32166 :     for (i = 0; i < ntups; i++)
    6549              :     {
    6550        31917 :         convinfo[i].dobj.objType = DO_CONVERSION;
    6551        31917 :         convinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    6552        31917 :         convinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    6553        31917 :         AssignDumpId(&convinfo[i].dobj);
    6554        31917 :         convinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_conname));
    6555        63834 :         convinfo[i].dobj.namespace =
    6556        31917 :             findNamespace(atooid(PQgetvalue(res, i, i_connamespace)));
    6557        31917 :         convinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_conowner));
    6558              : 
    6559              :         /* Decide whether we want to dump it */
    6560        31917 :         selectDumpableObject(&(convinfo[i].dobj), fout);
    6561              :     }
    6562              : 
    6563          249 :     PQclear(res);
    6564              : 
    6565          249 :     destroyPQExpBuffer(query);
    6566          249 : }
    6567              : 
    6568              : /*
    6569              :  * getAccessMethods:
    6570              :  *    get information about all user-defined access methods
    6571              :  */
    6572              : void
    6573          249 : getAccessMethods(Archive *fout)
    6574              : {
    6575              :     PGresult   *res;
    6576              :     int         ntups;
    6577              :     int         i;
    6578              :     PQExpBuffer query;
    6579              :     AccessMethodInfo *aminfo;
    6580              :     int         i_tableoid;
    6581              :     int         i_oid;
    6582              :     int         i_amname;
    6583              :     int         i_amhandler;
    6584              :     int         i_amtype;
    6585              : 
    6586          249 :     query = createPQExpBuffer();
    6587              : 
    6588              :     /*
    6589              :      * Select all access methods from pg_am table.  v9.6 introduced CREATE
    6590              :      * ACCESS METHOD, so earlier versions usually have only built-in access
    6591              :      * methods.  v9.6 also changed the access method API, replacing dozens of
    6592              :      * pg_am columns with amhandler.  Even if a user created an access method
    6593              :      * by "INSERT INTO pg_am", we have no way to translate pre-v9.6 pg_am
    6594              :      * columns to a v9.6+ CREATE ACCESS METHOD.  Hence, before v9.6, read
    6595              :      * pg_am just to facilitate findAccessMethodByOid() providing the
    6596              :      * OID-to-name mapping.
    6597              :      */
    6598          249 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, amname, ");
    6599          249 :     if (fout->remoteVersion >= 90600)
    6600          249 :         appendPQExpBufferStr(query,
    6601              :                              "amtype, "
    6602              :                              "amhandler::pg_catalog.regproc AS amhandler ");
    6603              :     else
    6604            0 :         appendPQExpBufferStr(query,
    6605              :                              "'i'::pg_catalog.\"char\" AS amtype, "
    6606              :                              "'-'::pg_catalog.regproc AS amhandler ");
    6607          249 :     appendPQExpBufferStr(query, "FROM pg_am");
    6608              : 
    6609          249 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    6610              : 
    6611          249 :     ntups = PQntuples(res);
    6612              : 
    6613          249 :     aminfo = pg_malloc_array(AccessMethodInfo, ntups);
    6614              : 
    6615          249 :     i_tableoid = PQfnumber(res, "tableoid");
    6616          249 :     i_oid = PQfnumber(res, "oid");
    6617          249 :     i_amname = PQfnumber(res, "amname");
    6618          249 :     i_amhandler = PQfnumber(res, "amhandler");
    6619          249 :     i_amtype = PQfnumber(res, "amtype");
    6620              : 
    6621         2114 :     for (i = 0; i < ntups; i++)
    6622              :     {
    6623         1865 :         aminfo[i].dobj.objType = DO_ACCESS_METHOD;
    6624         1865 :         aminfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    6625         1865 :         aminfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    6626         1865 :         AssignDumpId(&aminfo[i].dobj);
    6627         1865 :         aminfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_amname));
    6628         1865 :         aminfo[i].dobj.namespace = NULL;
    6629         1865 :         aminfo[i].amhandler = pg_strdup(PQgetvalue(res, i, i_amhandler));
    6630         1865 :         aminfo[i].amtype = *(PQgetvalue(res, i, i_amtype));
    6631              : 
    6632              :         /* Decide whether we want to dump it */
    6633         1865 :         selectDumpableAccessMethod(&(aminfo[i]), fout);
    6634              :     }
    6635              : 
    6636          249 :     PQclear(res);
    6637              : 
    6638          249 :     destroyPQExpBuffer(query);
    6639          249 : }
    6640              : 
    6641              : 
    6642              : /*
    6643              :  * getOpclasses:
    6644              :  *    get information about all opclasses in the system catalogs
    6645              :  */
    6646              : void
    6647          249 : getOpclasses(Archive *fout)
    6648              : {
    6649              :     PGresult   *res;
    6650              :     int         ntups;
    6651              :     int         i;
    6652          249 :     PQExpBuffer query = createPQExpBuffer();
    6653              :     OpclassInfo *opcinfo;
    6654              :     int         i_tableoid;
    6655              :     int         i_oid;
    6656              :     int         i_opcmethod;
    6657              :     int         i_opcname;
    6658              :     int         i_opcnamespace;
    6659              :     int         i_opcowner;
    6660              : 
    6661              :     /*
    6662              :      * find all opclasses, including builtin opclasses; we filter out
    6663              :      * system-defined opclasses at dump-out time.
    6664              :      */
    6665              : 
    6666          249 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, opcmethod, opcname, "
    6667              :                          "opcnamespace, "
    6668              :                          "opcowner "
    6669              :                          "FROM pg_opclass");
    6670              : 
    6671          249 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    6672              : 
    6673          249 :     ntups = PQntuples(res);
    6674              : 
    6675          249 :     opcinfo = pg_malloc_array(OpclassInfo, ntups);
    6676              : 
    6677          249 :     i_tableoid = PQfnumber(res, "tableoid");
    6678          249 :     i_oid = PQfnumber(res, "oid");
    6679          249 :     i_opcmethod = PQfnumber(res, "opcmethod");
    6680          249 :     i_opcname = PQfnumber(res, "opcname");
    6681          249 :     i_opcnamespace = PQfnumber(res, "opcnamespace");
    6682          249 :     i_opcowner = PQfnumber(res, "opcowner");
    6683              : 
    6684        44976 :     for (i = 0; i < ntups; i++)
    6685              :     {
    6686        44727 :         opcinfo[i].dobj.objType = DO_OPCLASS;
    6687        44727 :         opcinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    6688        44727 :         opcinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    6689        44727 :         AssignDumpId(&opcinfo[i].dobj);
    6690        44727 :         opcinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_opcname));
    6691        89454 :         opcinfo[i].dobj.namespace =
    6692        44727 :             findNamespace(atooid(PQgetvalue(res, i, i_opcnamespace)));
    6693        44727 :         opcinfo[i].opcmethod = atooid(PQgetvalue(res, i, i_opcmethod));
    6694        44727 :         opcinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_opcowner));
    6695              : 
    6696              :         /* Decide whether we want to dump it */
    6697        44727 :         selectDumpableObject(&(opcinfo[i].dobj), fout);
    6698              :     }
    6699              : 
    6700          249 :     PQclear(res);
    6701              : 
    6702          249 :     destroyPQExpBuffer(query);
    6703          249 : }
    6704              : 
    6705              : /*
    6706              :  * getOpfamilies:
    6707              :  *    get information about all opfamilies in the system catalogs
    6708              :  */
    6709              : void
    6710          249 : getOpfamilies(Archive *fout)
    6711              : {
    6712              :     PGresult   *res;
    6713              :     int         ntups;
    6714              :     int         i;
    6715              :     PQExpBuffer query;
    6716              :     OpfamilyInfo *opfinfo;
    6717              :     int         i_tableoid;
    6718              :     int         i_oid;
    6719              :     int         i_opfmethod;
    6720              :     int         i_opfname;
    6721              :     int         i_opfnamespace;
    6722              :     int         i_opfowner;
    6723              : 
    6724          249 :     query = createPQExpBuffer();
    6725              : 
    6726              :     /*
    6727              :      * find all opfamilies, including builtin opfamilies; we filter out
    6728              :      * system-defined opfamilies at dump-out time.
    6729              :      */
    6730              : 
    6731          249 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, opfmethod, opfname, "
    6732              :                          "opfnamespace, "
    6733              :                          "opfowner "
    6734              :                          "FROM pg_opfamily");
    6735              : 
    6736          249 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    6737              : 
    6738          249 :     ntups = PQntuples(res);
    6739              : 
    6740          249 :     opfinfo = pg_malloc_array(OpfamilyInfo, ntups);
    6741              : 
    6742          249 :     i_tableoid = PQfnumber(res, "tableoid");
    6743          249 :     i_oid = PQfnumber(res, "oid");
    6744          249 :     i_opfname = PQfnumber(res, "opfname");
    6745          249 :     i_opfmethod = PQfnumber(res, "opfmethod");
    6746          249 :     i_opfnamespace = PQfnumber(res, "opfnamespace");
    6747          249 :     i_opfowner = PQfnumber(res, "opfowner");
    6748              : 
    6749        37240 :     for (i = 0; i < ntups; i++)
    6750              :     {
    6751        36991 :         opfinfo[i].dobj.objType = DO_OPFAMILY;
    6752        36991 :         opfinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    6753        36991 :         opfinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    6754        36991 :         AssignDumpId(&opfinfo[i].dobj);
    6755        36991 :         opfinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_opfname));
    6756        73982 :         opfinfo[i].dobj.namespace =
    6757        36991 :             findNamespace(atooid(PQgetvalue(res, i, i_opfnamespace)));
    6758        36991 :         opfinfo[i].opfmethod = atooid(PQgetvalue(res, i, i_opfmethod));
    6759        36991 :         opfinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_opfowner));
    6760              : 
    6761              :         /* Decide whether we want to dump it */
    6762        36991 :         selectDumpableObject(&(opfinfo[i].dobj), fout);
    6763              :     }
    6764              : 
    6765          249 :     PQclear(res);
    6766              : 
    6767          249 :     destroyPQExpBuffer(query);
    6768          249 : }
    6769              : 
    6770              : /*
    6771              :  * getAggregates:
    6772              :  *    get information about all user-defined aggregates in the system catalogs
    6773              :  */
    6774              : void
    6775          249 : getAggregates(Archive *fout)
    6776              : {
    6777          249 :     DumpOptions *dopt = fout->dopt;
    6778              :     PGresult   *res;
    6779              :     int         ntups;
    6780              :     int         i;
    6781          249 :     PQExpBuffer query = createPQExpBuffer();
    6782              :     AggInfo    *agginfo;
    6783              :     int         i_tableoid;
    6784              :     int         i_oid;
    6785              :     int         i_aggname;
    6786              :     int         i_aggnamespace;
    6787              :     int         i_pronargs;
    6788              :     int         i_proargtypes;
    6789              :     int         i_proowner;
    6790              :     int         i_aggacl;
    6791              :     int         i_acldefault;
    6792              : 
    6793              :     /*
    6794              :      * Find all interesting aggregates.  See comment in getFuncs() for the
    6795              :      * rationale behind the filtering logic.
    6796              :      */
    6797          249 :     if (fout->remoteVersion >= 90600)
    6798              :     {
    6799              :         const char *agg_check;
    6800              : 
    6801          498 :         agg_check = (fout->remoteVersion >= 110000 ? "p.prokind = 'a'"
    6802          249 :                      : "p.proisagg");
    6803              : 
    6804          249 :         appendPQExpBuffer(query, "SELECT p.tableoid, p.oid, "
    6805              :                           "p.proname AS aggname, "
    6806              :                           "p.pronamespace AS aggnamespace, "
    6807              :                           "p.pronargs, p.proargtypes, "
    6808              :                           "p.proowner, "
    6809              :                           "p.proacl AS aggacl, "
    6810              :                           "acldefault('f', p.proowner) AS acldefault "
    6811              :                           "FROM pg_proc p "
    6812              :                           "LEFT JOIN pg_init_privs pip ON "
    6813              :                           "(p.oid = pip.objoid "
    6814              :                           "AND pip.classoid = 'pg_proc'::regclass "
    6815              :                           "AND pip.objsubid = 0) "
    6816              :                           "WHERE %s AND ("
    6817              :                           "p.pronamespace != "
    6818              :                           "(SELECT oid FROM pg_namespace "
    6819              :                           "WHERE nspname = 'pg_catalog') OR "
    6820              :                           "p.proacl IS DISTINCT FROM pip.initprivs",
    6821              :                           agg_check);
    6822          249 :         if (dopt->binary_upgrade)
    6823           38 :             appendPQExpBufferStr(query,
    6824              :                                  " OR EXISTS(SELECT 1 FROM pg_depend WHERE "
    6825              :                                  "classid = 'pg_proc'::regclass AND "
    6826              :                                  "objid = p.oid AND "
    6827              :                                  "refclassid = 'pg_extension'::regclass AND "
    6828              :                                  "deptype = 'e')");
    6829          249 :         appendPQExpBufferChar(query, ')');
    6830              :     }
    6831              :     else
    6832              :     {
    6833            0 :         appendPQExpBufferStr(query, "SELECT tableoid, oid, proname AS aggname, "
    6834              :                              "pronamespace AS aggnamespace, "
    6835              :                              "pronargs, proargtypes, "
    6836              :                              "proowner, "
    6837              :                              "proacl AS aggacl, "
    6838              :                              "acldefault('f', proowner) AS acldefault "
    6839              :                              "FROM pg_proc p "
    6840              :                              "WHERE proisagg AND ("
    6841              :                              "pronamespace != "
    6842              :                              "(SELECT oid FROM pg_namespace "
    6843              :                              "WHERE nspname = 'pg_catalog')");
    6844            0 :         if (dopt->binary_upgrade)
    6845            0 :             appendPQExpBufferStr(query,
    6846              :                                  " OR EXISTS(SELECT 1 FROM pg_depend WHERE "
    6847              :                                  "classid = 'pg_proc'::regclass AND "
    6848              :                                  "objid = p.oid AND "
    6849              :                                  "refclassid = 'pg_extension'::regclass AND "
    6850              :                                  "deptype = 'e')");
    6851            0 :         appendPQExpBufferChar(query, ')');
    6852              :     }
    6853              : 
    6854          249 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    6855              : 
    6856          249 :     ntups = PQntuples(res);
    6857              : 
    6858          249 :     agginfo = pg_malloc_array(AggInfo, ntups);
    6859              : 
    6860          249 :     i_tableoid = PQfnumber(res, "tableoid");
    6861          249 :     i_oid = PQfnumber(res, "oid");
    6862          249 :     i_aggname = PQfnumber(res, "aggname");
    6863          249 :     i_aggnamespace = PQfnumber(res, "aggnamespace");
    6864          249 :     i_pronargs = PQfnumber(res, "pronargs");
    6865          249 :     i_proargtypes = PQfnumber(res, "proargtypes");
    6866          249 :     i_proowner = PQfnumber(res, "proowner");
    6867          249 :     i_aggacl = PQfnumber(res, "aggacl");
    6868          249 :     i_acldefault = PQfnumber(res, "acldefault");
    6869              : 
    6870          648 :     for (i = 0; i < ntups; i++)
    6871              :     {
    6872          399 :         agginfo[i].aggfn.dobj.objType = DO_AGG;
    6873          399 :         agginfo[i].aggfn.dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    6874          399 :         agginfo[i].aggfn.dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    6875          399 :         AssignDumpId(&agginfo[i].aggfn.dobj);
    6876          399 :         agginfo[i].aggfn.dobj.name = pg_strdup(PQgetvalue(res, i, i_aggname));
    6877          798 :         agginfo[i].aggfn.dobj.namespace =
    6878          399 :             findNamespace(atooid(PQgetvalue(res, i, i_aggnamespace)));
    6879          399 :         agginfo[i].aggfn.dacl.acl = pg_strdup(PQgetvalue(res, i, i_aggacl));
    6880          399 :         agginfo[i].aggfn.dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
    6881          399 :         agginfo[i].aggfn.dacl.privtype = 0;
    6882          399 :         agginfo[i].aggfn.dacl.initprivs = NULL;
    6883          399 :         agginfo[i].aggfn.rolname = getRoleName(PQgetvalue(res, i, i_proowner));
    6884          399 :         agginfo[i].aggfn.lang = InvalidOid; /* not currently interesting */
    6885          399 :         agginfo[i].aggfn.prorettype = InvalidOid;   /* not saved */
    6886          399 :         agginfo[i].aggfn.nargs = atoi(PQgetvalue(res, i, i_pronargs));
    6887          399 :         if (agginfo[i].aggfn.nargs == 0)
    6888           56 :             agginfo[i].aggfn.argtypes = NULL;
    6889              :         else
    6890              :         {
    6891          343 :             agginfo[i].aggfn.argtypes = pg_malloc_array(Oid, agginfo[i].aggfn.nargs);
    6892          343 :             parseOidArray(PQgetvalue(res, i, i_proargtypes),
    6893          343 :                           agginfo[i].aggfn.argtypes,
    6894          343 :                           agginfo[i].aggfn.nargs);
    6895              :         }
    6896          399 :         agginfo[i].aggfn.postponed_def = false; /* might get set during sort */
    6897              : 
    6898              :         /* Decide whether we want to dump it */
    6899          399 :         selectDumpableObject(&(agginfo[i].aggfn.dobj), fout);
    6900              : 
    6901              :         /* Mark whether aggregate has an ACL */
    6902          399 :         if (!PQgetisnull(res, i, i_aggacl))
    6903           25 :             agginfo[i].aggfn.dobj.components |= DUMP_COMPONENT_ACL;
    6904              :     }
    6905              : 
    6906          249 :     PQclear(res);
    6907              : 
    6908          249 :     destroyPQExpBuffer(query);
    6909          249 : }
    6910              : 
    6911              : /*
    6912              :  * getFuncs:
    6913              :  *    get information about all user-defined functions in the system catalogs
    6914              :  */
    6915              : void
    6916          249 : getFuncs(Archive *fout)
    6917              : {
    6918          249 :     DumpOptions *dopt = fout->dopt;
    6919              :     PGresult   *res;
    6920              :     int         ntups;
    6921              :     int         i;
    6922          249 :     PQExpBuffer query = createPQExpBuffer();
    6923              :     FuncInfo   *finfo;
    6924              :     int         i_tableoid;
    6925              :     int         i_oid;
    6926              :     int         i_proname;
    6927              :     int         i_pronamespace;
    6928              :     int         i_proowner;
    6929              :     int         i_prolang;
    6930              :     int         i_pronargs;
    6931              :     int         i_proargtypes;
    6932              :     int         i_prorettype;
    6933              :     int         i_proacl;
    6934              :     int         i_acldefault;
    6935              : 
    6936              :     /*
    6937              :      * Find all interesting functions.  This is a bit complicated:
    6938              :      *
    6939              :      * 1. Always exclude aggregates; those are handled elsewhere.
    6940              :      *
    6941              :      * 2. Always exclude functions that are internally dependent on something
    6942              :      * else, since presumably those will be created as a result of creating
    6943              :      * the something else.  This currently acts only to suppress constructor
    6944              :      * functions for range types.  Note this is OK only because the
    6945              :      * constructors don't have any dependencies the range type doesn't have;
    6946              :      * otherwise we might not get creation ordering correct.
    6947              :      *
    6948              :      * 3. Otherwise, we normally exclude functions in pg_catalog.  However, if
    6949              :      * they're members of extensions and we are in binary-upgrade mode then
    6950              :      * include them, since we want to dump extension members individually in
    6951              :      * that mode.  Also, if they are used by casts or transforms then we need
    6952              :      * to gather the information about them, though they won't be dumped if
    6953              :      * they are built-in.  Also, in 9.6 and up, include functions in
    6954              :      * pg_catalog if they have an ACL different from what's shown in
    6955              :      * pg_init_privs (so we have to join to pg_init_privs; annoying).
    6956              :      */
    6957          249 :     if (fout->remoteVersion >= 90600)
    6958              :     {
    6959              :         const char *not_agg_check;
    6960              : 
    6961          498 :         not_agg_check = (fout->remoteVersion >= 110000 ? "p.prokind <> 'a'"
    6962          249 :                          : "NOT p.proisagg");
    6963              : 
    6964          249 :         appendPQExpBuffer(query,
    6965              :                           "SELECT p.tableoid, p.oid, p.proname, p.prolang, "
    6966              :                           "p.pronargs, p.proargtypes, p.prorettype, "
    6967              :                           "p.proacl, "
    6968              :                           "acldefault('f', p.proowner) AS acldefault, "
    6969              :                           "p.pronamespace, "
    6970              :                           "p.proowner "
    6971              :                           "FROM pg_proc p "
    6972              :                           "LEFT JOIN pg_init_privs pip ON "
    6973              :                           "(p.oid = pip.objoid "
    6974              :                           "AND pip.classoid = 'pg_proc'::regclass "
    6975              :                           "AND pip.objsubid = 0) "
    6976              :                           "WHERE %s"
    6977              :                           "\n  AND NOT EXISTS (SELECT 1 FROM pg_depend "
    6978              :                           "WHERE classid = 'pg_proc'::regclass AND "
    6979              :                           "objid = p.oid AND deptype = 'i')"
    6980              :                           "\n  AND ("
    6981              :                           "\n  pronamespace != "
    6982              :                           "(SELECT oid FROM pg_namespace "
    6983              :                           "WHERE nspname = 'pg_catalog')"
    6984              :                           "\n  OR EXISTS (SELECT 1 FROM pg_cast"
    6985              :                           "\n  WHERE pg_cast.oid > %u "
    6986              :                           "\n  AND p.oid = pg_cast.castfunc)"
    6987              :                           "\n  OR EXISTS (SELECT 1 FROM pg_transform"
    6988              :                           "\n  WHERE pg_transform.oid > %u AND "
    6989              :                           "\n  (p.oid = pg_transform.trffromsql"
    6990              :                           "\n  OR p.oid = pg_transform.trftosql))",
    6991              :                           not_agg_check,
    6992              :                           g_last_builtin_oid,
    6993              :                           g_last_builtin_oid);
    6994          249 :         if (dopt->binary_upgrade)
    6995           38 :             appendPQExpBufferStr(query,
    6996              :                                  "\n  OR EXISTS(SELECT 1 FROM pg_depend WHERE "
    6997              :                                  "classid = 'pg_proc'::regclass AND "
    6998              :                                  "objid = p.oid AND "
    6999              :                                  "refclassid = 'pg_extension'::regclass AND "
    7000              :                                  "deptype = 'e')");
    7001          249 :         appendPQExpBufferStr(query,
    7002              :                              "\n  OR p.proacl IS DISTINCT FROM pip.initprivs");
    7003          249 :         appendPQExpBufferChar(query, ')');
    7004              :     }
    7005              :     else
    7006              :     {
    7007            0 :         appendPQExpBuffer(query,
    7008              :                           "SELECT tableoid, oid, proname, prolang, "
    7009              :                           "pronargs, proargtypes, prorettype, proacl, "
    7010              :                           "acldefault('f', proowner) AS acldefault, "
    7011              :                           "pronamespace, "
    7012              :                           "proowner "
    7013              :                           "FROM pg_proc p "
    7014              :                           "WHERE NOT proisagg"
    7015              :                           "\n  AND NOT EXISTS (SELECT 1 FROM pg_depend "
    7016              :                           "WHERE classid = 'pg_proc'::regclass AND "
    7017              :                           "objid = p.oid AND deptype = 'i')"
    7018              :                           "\n  AND ("
    7019              :                           "\n  pronamespace != "
    7020              :                           "(SELECT oid FROM pg_namespace "
    7021              :                           "WHERE nspname = 'pg_catalog')"
    7022              :                           "\n  OR EXISTS (SELECT 1 FROM pg_cast"
    7023              :                           "\n  WHERE pg_cast.oid > '%u'::oid"
    7024              :                           "\n  AND p.oid = pg_cast.castfunc)",
    7025              :                           g_last_builtin_oid);
    7026              : 
    7027            0 :         if (fout->remoteVersion >= 90500)
    7028            0 :             appendPQExpBuffer(query,
    7029              :                               "\n  OR EXISTS (SELECT 1 FROM pg_transform"
    7030              :                               "\n  WHERE pg_transform.oid > '%u'::oid"
    7031              :                               "\n  AND (p.oid = pg_transform.trffromsql"
    7032              :                               "\n  OR p.oid = pg_transform.trftosql))",
    7033              :                               g_last_builtin_oid);
    7034              : 
    7035            0 :         if (dopt->binary_upgrade)
    7036            0 :             appendPQExpBufferStr(query,
    7037              :                                  "\n  OR EXISTS(SELECT 1 FROM pg_depend WHERE "
    7038              :                                  "classid = 'pg_proc'::regclass AND "
    7039              :                                  "objid = p.oid AND "
    7040              :                                  "refclassid = 'pg_extension'::regclass AND "
    7041              :                                  "deptype = 'e')");
    7042            0 :         appendPQExpBufferChar(query, ')');
    7043              :     }
    7044              : 
    7045          249 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    7046              : 
    7047          249 :     ntups = PQntuples(res);
    7048              : 
    7049          249 :     finfo = pg_malloc0_array(FuncInfo, ntups);
    7050              : 
    7051          249 :     i_tableoid = PQfnumber(res, "tableoid");
    7052          249 :     i_oid = PQfnumber(res, "oid");
    7053          249 :     i_proname = PQfnumber(res, "proname");
    7054          249 :     i_pronamespace = PQfnumber(res, "pronamespace");
    7055          249 :     i_proowner = PQfnumber(res, "proowner");
    7056          249 :     i_prolang = PQfnumber(res, "prolang");
    7057          249 :     i_pronargs = PQfnumber(res, "pronargs");
    7058          249 :     i_proargtypes = PQfnumber(res, "proargtypes");
    7059          249 :     i_prorettype = PQfnumber(res, "prorettype");
    7060          249 :     i_proacl = PQfnumber(res, "proacl");
    7061          249 :     i_acldefault = PQfnumber(res, "acldefault");
    7062              : 
    7063         5718 :     for (i = 0; i < ntups; i++)
    7064              :     {
    7065         5469 :         finfo[i].dobj.objType = DO_FUNC;
    7066         5469 :         finfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    7067         5469 :         finfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    7068         5469 :         AssignDumpId(&finfo[i].dobj);
    7069         5469 :         finfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_proname));
    7070        10938 :         finfo[i].dobj.namespace =
    7071         5469 :             findNamespace(atooid(PQgetvalue(res, i, i_pronamespace)));
    7072         5469 :         finfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_proacl));
    7073         5469 :         finfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
    7074         5469 :         finfo[i].dacl.privtype = 0;
    7075         5469 :         finfo[i].dacl.initprivs = NULL;
    7076         5469 :         finfo[i].rolname = getRoleName(PQgetvalue(res, i, i_proowner));
    7077         5469 :         finfo[i].lang = atooid(PQgetvalue(res, i, i_prolang));
    7078         5469 :         finfo[i].prorettype = atooid(PQgetvalue(res, i, i_prorettype));
    7079         5469 :         finfo[i].nargs = atoi(PQgetvalue(res, i, i_pronargs));
    7080         5469 :         if (finfo[i].nargs == 0)
    7081         1080 :             finfo[i].argtypes = NULL;
    7082              :         else
    7083              :         {
    7084         4389 :             finfo[i].argtypes = pg_malloc_array(Oid, finfo[i].nargs);
    7085         4389 :             parseOidArray(PQgetvalue(res, i, i_proargtypes),
    7086         4389 :                           finfo[i].argtypes, finfo[i].nargs);
    7087              :         }
    7088         5469 :         finfo[i].postponed_def = false; /* might get set during sort */
    7089              : 
    7090              :         /* Decide whether we want to dump it */
    7091         5469 :         selectDumpableObject(&(finfo[i].dobj), fout);
    7092              : 
    7093              :         /* Mark whether function has an ACL */
    7094         5469 :         if (!PQgetisnull(res, i, i_proacl))
    7095          148 :             finfo[i].dobj.components |= DUMP_COMPONENT_ACL;
    7096              :     }
    7097              : 
    7098          249 :     PQclear(res);
    7099              : 
    7100          249 :     destroyPQExpBuffer(query);
    7101          249 : }
    7102              : 
    7103              : /*
    7104              :  * getRelationStatistics
    7105              :  *    register the statistics object as a dependent of the relation.
    7106              :  *
    7107              :  * reltuples is passed as a string to avoid complexities in converting from/to
    7108              :  * floating point.
    7109              :  */
    7110              : static RelStatsInfo *
    7111         9830 : getRelationStatistics(Archive *fout, DumpableObject *rel, int32 relpages,
    7112              :                       char *reltuples, int32 relallvisible,
    7113              :                       int32 relallfrozen, char relkind,
    7114              :                       char **indAttNames, int nindAttNames)
    7115              : {
    7116         9830 :     if (!fout->dopt->dumpStatistics)
    7117         6200 :         return NULL;
    7118              : 
    7119         3630 :     if ((relkind == RELKIND_RELATION) ||
    7120         1484 :         (relkind == RELKIND_PARTITIONED_TABLE) ||
    7121          886 :         (relkind == RELKIND_INDEX) ||
    7122          572 :         (relkind == RELKIND_PARTITIONED_INDEX) ||
    7123          269 :         (relkind == RELKIND_MATVIEW ||
    7124              :          relkind == RELKIND_FOREIGN_TABLE))
    7125              :     {
    7126         3393 :         RelStatsInfo *info = pg_malloc0_object(RelStatsInfo);
    7127         3393 :         DumpableObject *dobj = &info->dobj;
    7128              : 
    7129         3393 :         dobj->objType = DO_REL_STATS;
    7130         3393 :         dobj->catId.tableoid = 0;
    7131         3393 :         dobj->catId.oid = 0;
    7132         3393 :         AssignDumpId(dobj);
    7133         3393 :         dobj->dependencies = pg_malloc_object(DumpId);
    7134         3393 :         dobj->dependencies[0] = rel->dumpId;
    7135         3393 :         dobj->nDeps = 1;
    7136         3393 :         dobj->allocDeps = 1;
    7137         3393 :         dobj->components |= DUMP_COMPONENT_STATISTICS;
    7138         3393 :         dobj->name = pg_strdup(rel->name);
    7139         3393 :         dobj->namespace = rel->namespace;
    7140         3393 :         info->relpages = relpages;
    7141         3393 :         info->reltuples = pstrdup(reltuples);
    7142         3393 :         info->relallvisible = relallvisible;
    7143         3393 :         info->relallfrozen = relallfrozen;
    7144         3393 :         info->relkind = relkind;
    7145         3393 :         info->indAttNames = indAttNames;
    7146         3393 :         info->nindAttNames = nindAttNames;
    7147              : 
    7148              :         /*
    7149              :          * Ordinarily, stats go in SECTION_DATA for tables and
    7150              :          * SECTION_POST_DATA for indexes.
    7151              :          *
    7152              :          * However, the section may be updated later for materialized view
    7153              :          * stats. REFRESH MATERIALIZED VIEW replaces the storage and resets
    7154              :          * the stats, so the stats must be restored after the data. Also, the
    7155              :          * materialized view definition may be postponed to SECTION_POST_DATA
    7156              :          * (see repairMatViewBoundaryMultiLoop()).
    7157              :          */
    7158         3393 :         switch (info->relkind)
    7159              :         {
    7160         2481 :             case RELKIND_RELATION:
    7161              :             case RELKIND_PARTITIONED_TABLE:
    7162              :             case RELKIND_MATVIEW:
    7163              :             case RELKIND_FOREIGN_TABLE:
    7164         2481 :                 info->section = SECTION_DATA;
    7165         2481 :                 break;
    7166          912 :             case RELKIND_INDEX:
    7167              :             case RELKIND_PARTITIONED_INDEX:
    7168          912 :                 info->section = SECTION_POST_DATA;
    7169          912 :                 break;
    7170            0 :             default:
    7171            0 :                 pg_fatal("cannot dump statistics for relation kind \"%c\"",
    7172              :                          info->relkind);
    7173              :         }
    7174              : 
    7175         3393 :         return info;
    7176              :     }
    7177          237 :     return NULL;
    7178              : }
    7179              : 
    7180              : /*
    7181              :  * getTables
    7182              :  *    read all the tables (no indexes) in the system catalogs,
    7183              :  *    and return them as an array of TableInfo structures
    7184              :  *
    7185              :  * *numTables is set to the number of tables read in
    7186              :  */
    7187              : TableInfo *
    7188          250 : getTables(Archive *fout, int *numTables)
    7189              : {
    7190          250 :     DumpOptions *dopt = fout->dopt;
    7191              :     PGresult   *res;
    7192              :     int         ntups;
    7193              :     int         i;
    7194          250 :     PQExpBuffer query = createPQExpBuffer();
    7195              :     TableInfo  *tblinfo;
    7196              :     int         i_reltableoid;
    7197              :     int         i_reloid;
    7198              :     int         i_relname;
    7199              :     int         i_relnamespace;
    7200              :     int         i_relkind;
    7201              :     int         i_reltype;
    7202              :     int         i_relowner;
    7203              :     int         i_relchecks;
    7204              :     int         i_relhasindex;
    7205              :     int         i_relhasrules;
    7206              :     int         i_relpages;
    7207              :     int         i_reltuples;
    7208              :     int         i_relallvisible;
    7209              :     int         i_relallfrozen;
    7210              :     int         i_toastpages;
    7211              :     int         i_owning_tab;
    7212              :     int         i_owning_col;
    7213              :     int         i_reltablespace;
    7214              :     int         i_relhasoids;
    7215              :     int         i_relhastriggers;
    7216              :     int         i_relpersistence;
    7217              :     int         i_relispopulated;
    7218              :     int         i_relreplident;
    7219              :     int         i_relrowsec;
    7220              :     int         i_relforcerowsec;
    7221              :     int         i_relfrozenxid;
    7222              :     int         i_toastfrozenxid;
    7223              :     int         i_toastoid;
    7224              :     int         i_relminmxid;
    7225              :     int         i_toastminmxid;
    7226              :     int         i_reloptions;
    7227              :     int         i_checkoption;
    7228              :     int         i_toastreloptions;
    7229              :     int         i_reloftype;
    7230              :     int         i_foreignserver;
    7231              :     int         i_amname;
    7232              :     int         i_is_identity_sequence;
    7233              :     int         i_relacl;
    7234              :     int         i_acldefault;
    7235              :     int         i_ispartition;
    7236              : 
    7237              :     /*
    7238              :      * Find all the tables and table-like objects.
    7239              :      *
    7240              :      * We must fetch all tables in this phase because otherwise we cannot
    7241              :      * correctly identify inherited columns, owned sequences, etc.
    7242              :      *
    7243              :      * We include system catalogs, so that we can work if a user table is
    7244              :      * defined to inherit from a system catalog (pretty weird, but...)
    7245              :      *
    7246              :      * Note: in this phase we should collect only a minimal amount of
    7247              :      * information about each table, basically just enough to decide if it is
    7248              :      * interesting.  In particular, since we do not yet have lock on any user
    7249              :      * table, we MUST NOT invoke any server-side data collection functions
    7250              :      * (for instance, pg_get_partkeydef()).  Those are likely to fail or give
    7251              :      * wrong answers if any concurrent DDL is happening.
    7252              :      */
    7253              : 
    7254          250 :     appendPQExpBufferStr(query,
    7255              :                          "SELECT c.tableoid, c.oid, c.relname, "
    7256              :                          "c.relnamespace, c.relkind, c.reltype, "
    7257              :                          "c.relowner, "
    7258              :                          "c.relchecks, "
    7259              :                          "c.relhasindex, c.relhasrules, c.relpages, "
    7260              :                          "c.reltuples, c.relallvisible, ");
    7261              : 
    7262          250 :     if (fout->remoteVersion >= 180000)
    7263          250 :         appendPQExpBufferStr(query, "c.relallfrozen, ");
    7264              :     else
    7265            0 :         appendPQExpBufferStr(query, "0 AS relallfrozen, ");
    7266              : 
    7267          250 :     appendPQExpBufferStr(query,
    7268              :                          "c.relhastriggers, c.relpersistence, "
    7269              :                          "c.reloftype, "
    7270              :                          "c.relacl, "
    7271              :                          "acldefault(CASE WHEN c.relkind = " CppAsString2(RELKIND_SEQUENCE)
    7272              :                          " THEN 's'::\"char\" ELSE 'r'::\"char\" END, c.relowner) AS acldefault, "
    7273              :                          "CASE WHEN c.relkind = " CppAsString2(RELKIND_FOREIGN_TABLE) " THEN "
    7274              :                          "(SELECT ftserver FROM pg_catalog.pg_foreign_table WHERE ftrelid = c.oid) "
    7275              :                          "ELSE 0 END AS foreignserver, "
    7276              :                          "c.relfrozenxid, tc.relfrozenxid AS tfrozenxid, "
    7277              :                          "tc.oid AS toid, "
    7278              :                          "tc.relpages AS toastpages, "
    7279              :                          "tc.reloptions AS toast_reloptions, "
    7280              :                          "d.refobjid AS owning_tab, "
    7281              :                          "d.refobjsubid AS owning_col, "
    7282              :                          "tsp.spcname AS reltablespace, ");
    7283              : 
    7284          250 :     if (fout->remoteVersion >= 120000)
    7285          250 :         appendPQExpBufferStr(query,
    7286              :                              "false AS relhasoids, ");
    7287              :     else
    7288            0 :         appendPQExpBufferStr(query,
    7289              :                              "c.relhasoids, ");
    7290              : 
    7291          250 :     if (fout->remoteVersion >= 90300)
    7292          250 :         appendPQExpBufferStr(query,
    7293              :                              "c.relispopulated, ");
    7294              :     else
    7295            0 :         appendPQExpBufferStr(query,
    7296              :                              "'t' as relispopulated, ");
    7297              : 
    7298          250 :     if (fout->remoteVersion >= 90400)
    7299          250 :         appendPQExpBufferStr(query,
    7300              :                              "c.relreplident, ");
    7301              :     else
    7302            0 :         appendPQExpBufferStr(query,
    7303              :                              "'d' AS relreplident, ");
    7304              : 
    7305          250 :     if (fout->remoteVersion >= 90500)
    7306          250 :         appendPQExpBufferStr(query,
    7307              :                              "c.relrowsecurity, c.relforcerowsecurity, ");
    7308              :     else
    7309            0 :         appendPQExpBufferStr(query,
    7310              :                              "false AS relrowsecurity, "
    7311              :                              "false AS relforcerowsecurity, ");
    7312              : 
    7313          250 :     if (fout->remoteVersion >= 90300)
    7314          250 :         appendPQExpBufferStr(query,
    7315              :                              "c.relminmxid, tc.relminmxid AS tminmxid, ");
    7316              :     else
    7317            0 :         appendPQExpBufferStr(query,
    7318              :                              "0 AS relminmxid, 0 AS tminmxid, ");
    7319              : 
    7320          250 :     if (fout->remoteVersion >= 90300)
    7321          250 :         appendPQExpBufferStr(query,
    7322              :                              "array_remove(array_remove(c.reloptions,'check_option=local'),'check_option=cascaded') AS reloptions, "
    7323              :                              "CASE WHEN 'check_option=local' = ANY (c.reloptions) THEN 'LOCAL'::text "
    7324              :                              "WHEN 'check_option=cascaded' = ANY (c.reloptions) THEN 'CASCADED'::text ELSE NULL END AS checkoption, ");
    7325              :     else
    7326            0 :         appendPQExpBufferStr(query,
    7327              :                              "c.reloptions, NULL AS checkoption, ");
    7328              : 
    7329          250 :     if (fout->remoteVersion >= 90600)
    7330          250 :         appendPQExpBufferStr(query,
    7331              :                              "am.amname, ");
    7332              :     else
    7333            0 :         appendPQExpBufferStr(query,
    7334              :                              "NULL AS amname, ");
    7335              : 
    7336          250 :     if (fout->remoteVersion >= 90600)
    7337          250 :         appendPQExpBufferStr(query,
    7338              :                              "(d.deptype = 'i') IS TRUE AS is_identity_sequence, ");
    7339              :     else
    7340            0 :         appendPQExpBufferStr(query,
    7341              :                              "false AS is_identity_sequence, ");
    7342              : 
    7343          250 :     if (fout->remoteVersion >= 100000)
    7344          250 :         appendPQExpBufferStr(query,
    7345              :                              "c.relispartition AS ispartition ");
    7346              :     else
    7347            0 :         appendPQExpBufferStr(query,
    7348              :                              "false AS ispartition ");
    7349              : 
    7350              :     /*
    7351              :      * Left join to pg_depend to pick up dependency info linking sequences to
    7352              :      * their owning column, if any (note this dependency is AUTO except for
    7353              :      * identity sequences, where it's INTERNAL). Also join to pg_tablespace to
    7354              :      * collect the spcname.
    7355              :      */
    7356          250 :     appendPQExpBufferStr(query,
    7357              :                          "\nFROM pg_class c\n"
    7358              :                          "LEFT JOIN pg_depend d ON "
    7359              :                          "(c.relkind = " CppAsString2(RELKIND_SEQUENCE) " AND "
    7360              :                          "d.classid = 'pg_class'::regclass AND d.objid = c.oid AND "
    7361              :                          "d.objsubid = 0 AND "
    7362              :                          "d.refclassid = 'pg_class'::regclass AND d.deptype IN ('a', 'i'))\n"
    7363              :                          "LEFT JOIN pg_tablespace tsp ON (tsp.oid = c.reltablespace)\n");
    7364              : 
    7365              :     /*
    7366              :      * In 9.6 and up, left join to pg_am to pick up the amname.
    7367              :      */
    7368          250 :     if (fout->remoteVersion >= 90600)
    7369          250 :         appendPQExpBufferStr(query,
    7370              :                              "LEFT JOIN pg_am am ON (c.relam = am.oid)\n");
    7371              : 
    7372              :     /*
    7373              :      * We purposefully ignore toast OIDs for partitioned tables; the reason is
    7374              :      * that versions 10 and 11 have them, but later versions do not, so
    7375              :      * emitting them causes the upgrade to fail.
    7376              :      */
    7377          250 :     appendPQExpBufferStr(query,
    7378              :                          "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid"
    7379              :                          " AND tc.relkind = " CppAsString2(RELKIND_TOASTVALUE)
    7380              :                          " AND c.relkind <> " CppAsString2(RELKIND_PARTITIONED_TABLE) ")\n");
    7381              : 
    7382              :     /*
    7383              :      * Restrict to interesting relkinds (in particular, not indexes).  Not all
    7384              :      * relkinds are possible in older servers, but it's not worth the trouble
    7385              :      * to emit a version-dependent list.
    7386              :      *
    7387              :      * Composite-type table entries won't be dumped as such, but we have to
    7388              :      * make a DumpableObject for them so that we can track dependencies of the
    7389              :      * composite type (pg_depend entries for columns of the composite type
    7390              :      * link to the pg_class entry not the pg_type entry).
    7391              :      */
    7392          250 :     appendPQExpBufferStr(query,
    7393              :                          "WHERE c.relkind IN ("
    7394              :                          CppAsString2(RELKIND_RELATION) ", "
    7395              :                          CppAsString2(RELKIND_SEQUENCE) ", "
    7396              :                          CppAsString2(RELKIND_VIEW) ", "
    7397              :                          CppAsString2(RELKIND_COMPOSITE_TYPE) ", "
    7398              :                          CppAsString2(RELKIND_MATVIEW) ", "
    7399              :                          CppAsString2(RELKIND_FOREIGN_TABLE) ", "
    7400              :                          CppAsString2(RELKIND_PARTITIONED_TABLE) ")\n"
    7401              :                          "ORDER BY c.oid");
    7402              : 
    7403          250 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    7404              : 
    7405          250 :     ntups = PQntuples(res);
    7406              : 
    7407          250 :     *numTables = ntups;
    7408              : 
    7409              :     /*
    7410              :      * Extract data from result and lock dumpable tables.  We do the locking
    7411              :      * before anything else, to minimize the window wherein a table could
    7412              :      * disappear under us.
    7413              :      *
    7414              :      * Note that we have to save info about all tables here, even when dumping
    7415              :      * only one, because we don't yet know which tables might be inheritance
    7416              :      * ancestors of the target table.
    7417              :      */
    7418          250 :     tblinfo = pg_malloc0_array(TableInfo, ntups);
    7419              : 
    7420          250 :     i_reltableoid = PQfnumber(res, "tableoid");
    7421          250 :     i_reloid = PQfnumber(res, "oid");
    7422          250 :     i_relname = PQfnumber(res, "relname");
    7423          250 :     i_relnamespace = PQfnumber(res, "relnamespace");
    7424          250 :     i_relkind = PQfnumber(res, "relkind");
    7425          250 :     i_reltype = PQfnumber(res, "reltype");
    7426          250 :     i_relowner = PQfnumber(res, "relowner");
    7427          250 :     i_relchecks = PQfnumber(res, "relchecks");
    7428          250 :     i_relhasindex = PQfnumber(res, "relhasindex");
    7429          250 :     i_relhasrules = PQfnumber(res, "relhasrules");
    7430          250 :     i_relpages = PQfnumber(res, "relpages");
    7431          250 :     i_reltuples = PQfnumber(res, "reltuples");
    7432          250 :     i_relallvisible = PQfnumber(res, "relallvisible");
    7433          250 :     i_relallfrozen = PQfnumber(res, "relallfrozen");
    7434          250 :     i_toastpages = PQfnumber(res, "toastpages");
    7435          250 :     i_owning_tab = PQfnumber(res, "owning_tab");
    7436          250 :     i_owning_col = PQfnumber(res, "owning_col");
    7437          250 :     i_reltablespace = PQfnumber(res, "reltablespace");
    7438          250 :     i_relhasoids = PQfnumber(res, "relhasoids");
    7439          250 :     i_relhastriggers = PQfnumber(res, "relhastriggers");
    7440          250 :     i_relpersistence = PQfnumber(res, "relpersistence");
    7441          250 :     i_relispopulated = PQfnumber(res, "relispopulated");
    7442          250 :     i_relreplident = PQfnumber(res, "relreplident");
    7443          250 :     i_relrowsec = PQfnumber(res, "relrowsecurity");
    7444          250 :     i_relforcerowsec = PQfnumber(res, "relforcerowsecurity");
    7445          250 :     i_relfrozenxid = PQfnumber(res, "relfrozenxid");
    7446          250 :     i_toastfrozenxid = PQfnumber(res, "tfrozenxid");
    7447          250 :     i_toastoid = PQfnumber(res, "toid");
    7448          250 :     i_relminmxid = PQfnumber(res, "relminmxid");
    7449          250 :     i_toastminmxid = PQfnumber(res, "tminmxid");
    7450          250 :     i_reloptions = PQfnumber(res, "reloptions");
    7451          250 :     i_checkoption = PQfnumber(res, "checkoption");
    7452          250 :     i_toastreloptions = PQfnumber(res, "toast_reloptions");
    7453          250 :     i_reloftype = PQfnumber(res, "reloftype");
    7454          250 :     i_foreignserver = PQfnumber(res, "foreignserver");
    7455          250 :     i_amname = PQfnumber(res, "amname");
    7456          250 :     i_is_identity_sequence = PQfnumber(res, "is_identity_sequence");
    7457          250 :     i_relacl = PQfnumber(res, "relacl");
    7458          250 :     i_acldefault = PQfnumber(res, "acldefault");
    7459          250 :     i_ispartition = PQfnumber(res, "ispartition");
    7460              : 
    7461          250 :     if (dopt->lockWaitTimeout)
    7462              :     {
    7463              :         /*
    7464              :          * Arrange to fail instead of waiting forever for a table lock.
    7465              :          *
    7466              :          * NB: this coding assumes that the only queries issued within the
    7467              :          * following loop are LOCK TABLEs; else the timeout may be undesirably
    7468              :          * applied to other things too.
    7469              :          */
    7470            2 :         resetPQExpBuffer(query);
    7471            2 :         appendPQExpBufferStr(query, "SET statement_timeout = ");
    7472            2 :         appendStringLiteralConn(query, dopt->lockWaitTimeout, GetConnection(fout));
    7473            2 :         ExecuteSqlStatement(fout, query->data);
    7474              :     }
    7475              : 
    7476          250 :     resetPQExpBuffer(query);
    7477              : 
    7478        63339 :     for (i = 0; i < ntups; i++)
    7479              :     {
    7480        63089 :         int32       relallvisible = atoi(PQgetvalue(res, i, i_relallvisible));
    7481        63089 :         int32       relallfrozen = atoi(PQgetvalue(res, i, i_relallfrozen));
    7482              : 
    7483        63089 :         tblinfo[i].dobj.objType = DO_TABLE;
    7484        63089 :         tblinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_reltableoid));
    7485        63089 :         tblinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_reloid));
    7486        63089 :         AssignDumpId(&tblinfo[i].dobj);
    7487        63089 :         tblinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_relname));
    7488       126178 :         tblinfo[i].dobj.namespace =
    7489        63089 :             findNamespace(atooid(PQgetvalue(res, i, i_relnamespace)));
    7490        63089 :         tblinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_relacl));
    7491        63089 :         tblinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
    7492        63089 :         tblinfo[i].dacl.privtype = 0;
    7493        63089 :         tblinfo[i].dacl.initprivs = NULL;
    7494        63089 :         tblinfo[i].relkind = *(PQgetvalue(res, i, i_relkind));
    7495        63089 :         tblinfo[i].reltype = atooid(PQgetvalue(res, i, i_reltype));
    7496        63089 :         tblinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_relowner));
    7497        63089 :         tblinfo[i].ncheck = atoi(PQgetvalue(res, i, i_relchecks));
    7498        63089 :         tblinfo[i].hasindex = (strcmp(PQgetvalue(res, i, i_relhasindex), "t") == 0);
    7499        63089 :         tblinfo[i].hasrules = (strcmp(PQgetvalue(res, i, i_relhasrules), "t") == 0);
    7500        63089 :         tblinfo[i].relpages = atoi(PQgetvalue(res, i, i_relpages));
    7501        63089 :         if (PQgetisnull(res, i, i_toastpages))
    7502        50937 :             tblinfo[i].toastpages = 0;
    7503              :         else
    7504        12152 :             tblinfo[i].toastpages = atoi(PQgetvalue(res, i, i_toastpages));
    7505        63089 :         if (PQgetisnull(res, i, i_owning_tab))
    7506              :         {
    7507        62674 :             tblinfo[i].owning_tab = InvalidOid;
    7508        62674 :             tblinfo[i].owning_col = 0;
    7509              :         }
    7510              :         else
    7511              :         {
    7512          415 :             tblinfo[i].owning_tab = atooid(PQgetvalue(res, i, i_owning_tab));
    7513          415 :             tblinfo[i].owning_col = atoi(PQgetvalue(res, i, i_owning_col));
    7514              :         }
    7515        63089 :         tblinfo[i].reltablespace = pg_strdup(PQgetvalue(res, i, i_reltablespace));
    7516        63089 :         tblinfo[i].hasoids = (strcmp(PQgetvalue(res, i, i_relhasoids), "t") == 0);
    7517        63089 :         tblinfo[i].hastriggers = (strcmp(PQgetvalue(res, i, i_relhastriggers), "t") == 0);
    7518        63089 :         tblinfo[i].relpersistence = *(PQgetvalue(res, i, i_relpersistence));
    7519        63089 :         tblinfo[i].relispopulated = (strcmp(PQgetvalue(res, i, i_relispopulated), "t") == 0);
    7520        63089 :         tblinfo[i].relreplident = *(PQgetvalue(res, i, i_relreplident));
    7521        63089 :         tblinfo[i].rowsec = (strcmp(PQgetvalue(res, i, i_relrowsec), "t") == 0);
    7522        63089 :         tblinfo[i].forcerowsec = (strcmp(PQgetvalue(res, i, i_relforcerowsec), "t") == 0);
    7523        63089 :         tblinfo[i].frozenxid = atooid(PQgetvalue(res, i, i_relfrozenxid));
    7524        63089 :         tblinfo[i].toast_frozenxid = atooid(PQgetvalue(res, i, i_toastfrozenxid));
    7525        63089 :         tblinfo[i].toast_oid = atooid(PQgetvalue(res, i, i_toastoid));
    7526        63089 :         tblinfo[i].minmxid = atooid(PQgetvalue(res, i, i_relminmxid));
    7527        63089 :         tblinfo[i].toast_minmxid = atooid(PQgetvalue(res, i, i_toastminmxid));
    7528        63089 :         tblinfo[i].reloptions = pg_strdup(PQgetvalue(res, i, i_reloptions));
    7529        63089 :         if (PQgetisnull(res, i, i_checkoption))
    7530        63043 :             tblinfo[i].checkoption = NULL;
    7531              :         else
    7532           46 :             tblinfo[i].checkoption = pg_strdup(PQgetvalue(res, i, i_checkoption));
    7533        63089 :         tblinfo[i].toast_reloptions = pg_strdup(PQgetvalue(res, i, i_toastreloptions));
    7534        63089 :         tblinfo[i].reloftype = atooid(PQgetvalue(res, i, i_reloftype));
    7535        63089 :         tblinfo[i].foreign_server = atooid(PQgetvalue(res, i, i_foreignserver));
    7536        63089 :         if (PQgetisnull(res, i, i_amname))
    7537        38800 :             tblinfo[i].amname = NULL;
    7538              :         else
    7539        24289 :             tblinfo[i].amname = pg_strdup(PQgetvalue(res, i, i_amname));
    7540        63089 :         tblinfo[i].is_identity_sequence = (strcmp(PQgetvalue(res, i, i_is_identity_sequence), "t") == 0);
    7541        63089 :         tblinfo[i].ispartition = (strcmp(PQgetvalue(res, i, i_ispartition), "t") == 0);
    7542              : 
    7543              :         /* other fields were zeroed above */
    7544              : 
    7545              :         /*
    7546              :          * Decide whether we want to dump this table.
    7547              :          */
    7548        63089 :         if (tblinfo[i].relkind == RELKIND_COMPOSITE_TYPE)
    7549          183 :             tblinfo[i].dobj.dump = DUMP_COMPONENT_NONE;
    7550              :         else
    7551        62906 :             selectDumpableTable(&tblinfo[i], fout);
    7552              : 
    7553              :         /*
    7554              :          * Now, consider the table "interesting" if we need to dump its
    7555              :          * definition, data or its statistics.  Later on, we'll skip a lot of
    7556              :          * data collection for uninteresting tables.
    7557              :          *
    7558              :          * Note: the "interesting" flag will also be set by flagInhTables for
    7559              :          * parents of interesting tables, so that we collect necessary
    7560              :          * inheritance info even when the parents are not themselves being
    7561              :          * dumped.  This is the main reason why we need an "interesting" flag
    7562              :          * that's separate from the components-to-dump bitmask.
    7563              :          */
    7564        63089 :         tblinfo[i].interesting = (tblinfo[i].dobj.dump &
    7565              :                                   (DUMP_COMPONENT_DEFINITION |
    7566              :                                    DUMP_COMPONENT_DATA |
    7567        63089 :                                    DUMP_COMPONENT_STATISTICS)) != 0;
    7568              : 
    7569        63089 :         tblinfo[i].dummy_view = false;  /* might get set during sort */
    7570        63089 :         tblinfo[i].postponed_def = false;   /* might get set during sort */
    7571              : 
    7572              :         /* Tables have data */
    7573        63089 :         tblinfo[i].dobj.components |= DUMP_COMPONENT_DATA;
    7574              : 
    7575              :         /* Mark whether table has an ACL */
    7576        63089 :         if (!PQgetisnull(res, i, i_relacl))
    7577        52584 :             tblinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
    7578        63089 :         tblinfo[i].hascolumnACLs = false;   /* may get set later */
    7579              : 
    7580              :         /* Add statistics */
    7581        63089 :         if (tblinfo[i].interesting)
    7582              :         {
    7583              :             RelStatsInfo *stats;
    7584              : 
    7585        14442 :             stats = getRelationStatistics(fout, &tblinfo[i].dobj,
    7586         7221 :                                           tblinfo[i].relpages,
    7587              :                                           PQgetvalue(res, i, i_reltuples),
    7588              :                                           relallvisible, relallfrozen,
    7589         7221 :                                           tblinfo[i].relkind, NULL, 0);
    7590         7221 :             if (tblinfo[i].relkind == RELKIND_MATVIEW)
    7591          398 :                 tblinfo[i].stats = stats;
    7592              :         }
    7593              : 
    7594              :         /*
    7595              :          * Read-lock target tables to make sure they aren't DROPPED or altered
    7596              :          * in schema before we get around to dumping them.
    7597              :          *
    7598              :          * Note that we don't explicitly lock parents of the target tables; we
    7599              :          * assume our lock on the child is enough to prevent schema
    7600              :          * alterations to parent tables.
    7601              :          *
    7602              :          * NOTE: it'd be kinda nice to lock other relations too, not only
    7603              :          * plain or partitioned tables, but the backend doesn't presently
    7604              :          * allow that.
    7605              :          *
    7606              :          * We only need to lock the table for certain components; see
    7607              :          * pg_dump.h
    7608              :          */
    7609        63089 :         if ((tblinfo[i].dobj.dump & DUMP_COMPONENTS_REQUIRING_LOCK) &&
    7610         7221 :             (tblinfo[i].relkind == RELKIND_RELATION ||
    7611         1987 :              tblinfo[i].relkind == RELKIND_PARTITIONED_TABLE))
    7612              :         {
    7613              :             /*
    7614              :              * Tables are locked in batches.  When dumping from a remote
    7615              :              * server this can save a significant amount of time by reducing
    7616              :              * the number of round trips.
    7617              :              */
    7618         5838 :             if (query->len == 0)
    7619          171 :                 appendPQExpBuffer(query, "LOCK TABLE %s",
    7620          171 :                                   fmtQualifiedDumpable(&tblinfo[i]));
    7621              :             else
    7622              :             {
    7623         5667 :                 appendPQExpBuffer(query, ", %s",
    7624         5667 :                                   fmtQualifiedDumpable(&tblinfo[i]));
    7625              : 
    7626              :                 /* Arbitrarily end a batch when query length reaches 100K. */
    7627         5667 :                 if (query->len >= 100000)
    7628              :                 {
    7629              :                     /* Lock another batch of tables. */
    7630            0 :                     appendPQExpBufferStr(query, " IN ACCESS SHARE MODE");
    7631            0 :                     ExecuteSqlStatement(fout, query->data);
    7632            0 :                     resetPQExpBuffer(query);
    7633              :                 }
    7634              :             }
    7635              :         }
    7636              :     }
    7637              : 
    7638          250 :     if (query->len != 0)
    7639              :     {
    7640              :         /* Lock the tables in the last batch. */
    7641          171 :         appendPQExpBufferStr(query, " IN ACCESS SHARE MODE");
    7642          171 :         ExecuteSqlStatement(fout, query->data);
    7643              :     }
    7644              : 
    7645          249 :     if (dopt->lockWaitTimeout)
    7646              :     {
    7647            2 :         ExecuteSqlStatement(fout, "SET statement_timeout = 0");
    7648              :     }
    7649              : 
    7650          249 :     PQclear(res);
    7651              : 
    7652          249 :     destroyPQExpBuffer(query);
    7653              : 
    7654          249 :     return tblinfo;
    7655              : }
    7656              : 
    7657              : /*
    7658              :  * getOwnedSeqs
    7659              :  *    identify owned sequences and mark them as dumpable if owning table is
    7660              :  *
    7661              :  * We used to do this in getTables(), but it's better to do it after the
    7662              :  * index used by findTableByOid() has been set up.
    7663              :  */
    7664              : void
    7665          249 : getOwnedSeqs(Archive *fout, TableInfo tblinfo[], int numTables)
    7666              : {
    7667              :     int         i;
    7668              : 
    7669              :     /*
    7670              :      * Force sequences that are "owned" by table columns to be dumped whenever
    7671              :      * their owning table is being dumped.
    7672              :      */
    7673        63065 :     for (i = 0; i < numTables; i++)
    7674              :     {
    7675        62816 :         TableInfo  *seqinfo = &tblinfo[i];
    7676              :         TableInfo  *owning_tab;
    7677              : 
    7678        62816 :         if (!OidIsValid(seqinfo->owning_tab))
    7679        62404 :             continue;           /* not an owned sequence */
    7680              : 
    7681          412 :         owning_tab = findTableByOid(seqinfo->owning_tab);
    7682          412 :         if (owning_tab == NULL)
    7683            0 :             pg_fatal("failed sanity check, parent table with OID %u of sequence with OID %u not found",
    7684              :                      seqinfo->owning_tab, seqinfo->dobj.catId.oid);
    7685              : 
    7686              :         /*
    7687              :          * For an identity sequence, dump exactly the same components for the
    7688              :          * sequence as for the owning table.  This is important because we
    7689              :          * treat the identity sequence as an integral part of the table.  For
    7690              :          * example, there is not any DDL command that allows creation of such
    7691              :          * a sequence independently of the table.
    7692              :          *
    7693              :          * For other owned sequences such as serial sequences, we need to dump
    7694              :          * the components that are being dumped for the table and any
    7695              :          * components that the sequence is explicitly marked with.
    7696              :          *
    7697              :          * We can't simply use the set of components which are being dumped
    7698              :          * for the table as the table might be in an extension (and only the
    7699              :          * non-extension components, eg: ACLs if changed, security labels, and
    7700              :          * policies, are being dumped) while the sequence is not (and
    7701              :          * therefore the definition and other components should also be
    7702              :          * dumped).
    7703              :          *
    7704              :          * If the sequence is part of the extension then it should be properly
    7705              :          * marked by checkExtensionMembership() and this will be a no-op as
    7706              :          * the table will be equivalently marked.
    7707              :          */
    7708          412 :         if (seqinfo->is_identity_sequence)
    7709          199 :             seqinfo->dobj.dump = owning_tab->dobj.dump;
    7710              :         else
    7711          213 :             seqinfo->dobj.dump |= owning_tab->dobj.dump;
    7712              : 
    7713              :         /* Make sure that necessary data is available if we're dumping it */
    7714          412 :         if (seqinfo->dobj.dump != DUMP_COMPONENT_NONE)
    7715              :         {
    7716          316 :             seqinfo->interesting = true;
    7717          316 :             owning_tab->interesting = true;
    7718              :         }
    7719              :     }
    7720          249 : }
    7721              : 
    7722              : /*
    7723              :  * getInherits
    7724              :  *    read all the inheritance information
    7725              :  * from the system catalogs return them in the InhInfo* structure
    7726              :  *
    7727              :  * numInherits is set to the number of pairs read in
    7728              :  */
    7729              : InhInfo *
    7730          249 : getInherits(Archive *fout, int *numInherits)
    7731              : {
    7732              :     PGresult   *res;
    7733              :     int         ntups;
    7734              :     int         i;
    7735          249 :     PQExpBuffer query = createPQExpBuffer();
    7736              :     InhInfo    *inhinfo;
    7737              : 
    7738              :     int         i_inhrelid;
    7739              :     int         i_inhparent;
    7740              : 
    7741              :     /* find all the inheritance information */
    7742          249 :     appendPQExpBufferStr(query, "SELECT inhrelid, inhparent FROM pg_inherits");
    7743              : 
    7744          249 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    7745              : 
    7746          249 :     ntups = PQntuples(res);
    7747              : 
    7748          249 :     *numInherits = ntups;
    7749              : 
    7750          249 :     inhinfo = pg_malloc_array(InhInfo, ntups);
    7751              : 
    7752          249 :     i_inhrelid = PQfnumber(res, "inhrelid");
    7753          249 :     i_inhparent = PQfnumber(res, "inhparent");
    7754              : 
    7755         3690 :     for (i = 0; i < ntups; i++)
    7756              :     {
    7757         3441 :         inhinfo[i].inhrelid = atooid(PQgetvalue(res, i, i_inhrelid));
    7758         3441 :         inhinfo[i].inhparent = atooid(PQgetvalue(res, i, i_inhparent));
    7759              :     }
    7760              : 
    7761          249 :     PQclear(res);
    7762              : 
    7763          249 :     destroyPQExpBuffer(query);
    7764              : 
    7765          249 :     return inhinfo;
    7766              : }
    7767              : 
    7768              : /*
    7769              :  * getPartitioningInfo
    7770              :  *    get information about partitioning
    7771              :  *
    7772              :  * For the most part, we only collect partitioning info about tables we
    7773              :  * intend to dump.  However, this function has to consider all partitioned
    7774              :  * tables in the database, because we need to know about parents of partitions
    7775              :  * we are going to dump even if the parents themselves won't be dumped.
    7776              :  *
    7777              :  * Specifically, what we need to know is whether each partitioned table
    7778              :  * has an "unsafe" partitioning scheme that requires us to force
    7779              :  * load-via-partition-root mode for its children.  Currently the only case
    7780              :  * for which we force that is hash partitioning on enum columns, since the
    7781              :  * hash codes depend on enum value OIDs which won't be replicated across
    7782              :  * dump-and-reload.  There are other cases in which load-via-partition-root
    7783              :  * might be necessary, but we expect users to cope with them.
    7784              :  */
    7785              : void
    7786          249 : getPartitioningInfo(Archive *fout)
    7787              : {
    7788              :     PQExpBuffer query;
    7789              :     PGresult   *res;
    7790              :     int         ntups;
    7791              : 
    7792              :     /* hash partitioning didn't exist before v11 */
    7793          249 :     if (fout->remoteVersion < 110000)
    7794            0 :         return;
    7795              :     /* needn't bother if not dumping data */
    7796          249 :     if (!fout->dopt->dumpData)
    7797           42 :         return;
    7798              : 
    7799          207 :     query = createPQExpBuffer();
    7800              : 
    7801              :     /*
    7802              :      * Unsafe partitioning schemes are exactly those for which hash enum_ops
    7803              :      * appears among the partition opclasses.  We needn't check partstrat.
    7804              :      *
    7805              :      * Note that this query may well retrieve info about tables we aren't
    7806              :      * going to dump and hence have no lock on.  That's okay since we need not
    7807              :      * invoke any unsafe server-side functions.
    7808              :      */
    7809          207 :     appendPQExpBufferStr(query,
    7810              :                          "SELECT partrelid FROM pg_partitioned_table WHERE\n"
    7811              :                          "(SELECT c.oid FROM pg_opclass c JOIN pg_am a "
    7812              :                          "ON c.opcmethod = a.oid\n"
    7813              :                          "WHERE opcname = 'enum_ops' "
    7814              :                          "AND opcnamespace = 'pg_catalog'::regnamespace "
    7815              :                          "AND amname = 'hash') = ANY(partclass)");
    7816              : 
    7817          207 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    7818              : 
    7819          207 :     ntups = PQntuples(res);
    7820              : 
    7821          250 :     for (int i = 0; i < ntups; i++)
    7822              :     {
    7823           43 :         Oid         tabrelid = atooid(PQgetvalue(res, i, 0));
    7824              :         TableInfo  *tbinfo;
    7825              : 
    7826           43 :         tbinfo = findTableByOid(tabrelid);
    7827           43 :         if (tbinfo == NULL)
    7828            0 :             pg_fatal("failed sanity check, table OID %u appearing in pg_partitioned_table not found",
    7829              :                      tabrelid);
    7830           43 :         tbinfo->unsafe_partitions = true;
    7831              :     }
    7832              : 
    7833          207 :     PQclear(res);
    7834              : 
    7835          207 :     destroyPQExpBuffer(query);
    7836              : }
    7837              : 
    7838              : /*
    7839              :  * getIndexes
    7840              :  *    get information about every index on a dumpable table
    7841              :  *
    7842              :  * Note: index data is not returned directly to the caller, but it
    7843              :  * does get entered into the DumpableObject tables.
    7844              :  */
    7845              : void
    7846          249 : getIndexes(Archive *fout, TableInfo tblinfo[], int numTables)
    7847              : {
    7848          249 :     PQExpBuffer query = createPQExpBuffer();
    7849          249 :     PQExpBuffer tbloids = createPQExpBuffer();
    7850              :     PGresult   *res;
    7851              :     int         ntups;
    7852              :     int         curtblindx;
    7853              :     IndxInfo   *indxinfo;
    7854              :     int         i_tableoid,
    7855              :                 i_oid,
    7856              :                 i_indrelid,
    7857              :                 i_indexname,
    7858              :                 i_relpages,
    7859              :                 i_reltuples,
    7860              :                 i_relallvisible,
    7861              :                 i_relallfrozen,
    7862              :                 i_parentidx,
    7863              :                 i_indexdef,
    7864              :                 i_indnkeyatts,
    7865              :                 i_indnatts,
    7866              :                 i_indkey,
    7867              :                 i_indisclustered,
    7868              :                 i_indisreplident,
    7869              :                 i_indnullsnotdistinct,
    7870              :                 i_contype,
    7871              :                 i_conname,
    7872              :                 i_condeferrable,
    7873              :                 i_condeferred,
    7874              :                 i_conperiod,
    7875              :                 i_contableoid,
    7876              :                 i_conoid,
    7877              :                 i_condef,
    7878              :                 i_indattnames,
    7879              :                 i_tablespace,
    7880              :                 i_indreloptions,
    7881              :                 i_indstatcols,
    7882              :                 i_indstatvals;
    7883              : 
    7884              :     /*
    7885              :      * We want to perform just one query against pg_index.  However, we
    7886              :      * mustn't try to select every row of the catalog and then sort it out on
    7887              :      * the client side, because some of the server-side functions we need
    7888              :      * would be unsafe to apply to tables we don't have lock on.  Hence, we
    7889              :      * build an array of the OIDs of tables we care about (and now have lock
    7890              :      * on!), and use a WHERE clause to constrain which rows are selected.
    7891              :      */
    7892          249 :     appendPQExpBufferChar(tbloids, '{');
    7893        63065 :     for (int i = 0; i < numTables; i++)
    7894              :     {
    7895        62816 :         TableInfo  *tbinfo = &tblinfo[i];
    7896              : 
    7897        62816 :         if (!tbinfo->hasindex)
    7898        44490 :             continue;
    7899              : 
    7900              :         /*
    7901              :          * We can ignore indexes of uninteresting tables.
    7902              :          */
    7903        18326 :         if (!tbinfo->interesting)
    7904        16325 :             continue;
    7905              : 
    7906              :         /* OK, we need info for this table */
    7907         2001 :         if (tbloids->len > 1) /* do we have more than the '{'? */
    7908         1922 :             appendPQExpBufferChar(tbloids, ',');
    7909         2001 :         appendPQExpBuffer(tbloids, "%u", tbinfo->dobj.catId.oid);
    7910              :     }
    7911          249 :     appendPQExpBufferChar(tbloids, '}');
    7912              : 
    7913          249 :     appendPQExpBufferStr(query,
    7914              :                          "SELECT t.tableoid, t.oid, i.indrelid, "
    7915              :                          "t.relname AS indexname, "
    7916              :                          "t.relpages, t.reltuples, t.relallvisible, ");
    7917              : 
    7918          249 :     if (fout->remoteVersion >= 180000)
    7919          249 :         appendPQExpBufferStr(query, "t.relallfrozen, ");
    7920              :     else
    7921            0 :         appendPQExpBufferStr(query, "0 AS relallfrozen, ");
    7922              : 
    7923          249 :     appendPQExpBufferStr(query,
    7924              :                          "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
    7925              :                          "i.indkey, i.indisclustered, "
    7926              :                          "c.contype, c.conname, "
    7927              :                          "c.condeferrable, c.condeferred, "
    7928              :                          "c.tableoid AS contableoid, "
    7929              :                          "c.oid AS conoid, "
    7930              :                          "pg_catalog.pg_get_constraintdef(c.oid, false) AS condef, "
    7931              :                          "CASE WHEN i.indexprs IS NOT NULL THEN "
    7932              :                          "(SELECT pg_catalog.array_agg(attname ORDER BY attnum)"
    7933              :                          "  FROM pg_catalog.pg_attribute "
    7934              :                          "  WHERE attrelid = i.indexrelid) "
    7935              :                          "ELSE NULL END AS indattnames, "
    7936              :                          "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
    7937              :                          "t.reloptions AS indreloptions, ");
    7938              : 
    7939              : 
    7940          249 :     if (fout->remoteVersion >= 90400)
    7941          249 :         appendPQExpBufferStr(query,
    7942              :                              "i.indisreplident, ");
    7943              :     else
    7944            0 :         appendPQExpBufferStr(query,
    7945              :                              "false AS indisreplident, ");
    7946              : 
    7947          249 :     if (fout->remoteVersion >= 110000)
    7948          249 :         appendPQExpBufferStr(query,
    7949              :                              "inh.inhparent AS parentidx, "
    7950              :                              "i.indnkeyatts AS indnkeyatts, "
    7951              :                              "i.indnatts AS indnatts, "
    7952              :                              "(SELECT pg_catalog.array_agg(attnum ORDER BY attnum) "
    7953              :                              "  FROM pg_catalog.pg_attribute "
    7954              :                              "  WHERE attrelid = i.indexrelid AND "
    7955              :                              "    attstattarget >= 0) AS indstatcols, "
    7956              :                              "(SELECT pg_catalog.array_agg(attstattarget ORDER BY attnum) "
    7957              :                              "  FROM pg_catalog.pg_attribute "
    7958              :                              "  WHERE attrelid = i.indexrelid AND "
    7959              :                              "    attstattarget >= 0) AS indstatvals, ");
    7960              :     else
    7961            0 :         appendPQExpBufferStr(query,
    7962              :                              "0 AS parentidx, "
    7963              :                              "i.indnatts AS indnkeyatts, "
    7964              :                              "i.indnatts AS indnatts, "
    7965              :                              "'' AS indstatcols, "
    7966              :                              "'' AS indstatvals, ");
    7967              : 
    7968          249 :     if (fout->remoteVersion >= 150000)
    7969          249 :         appendPQExpBufferStr(query,
    7970              :                              "i.indnullsnotdistinct, ");
    7971              :     else
    7972            0 :         appendPQExpBufferStr(query,
    7973              :                              "false AS indnullsnotdistinct, ");
    7974              : 
    7975          249 :     if (fout->remoteVersion >= 180000)
    7976          249 :         appendPQExpBufferStr(query,
    7977              :                              "c.conperiod ");
    7978              :     else
    7979            0 :         appendPQExpBufferStr(query,
    7980              :                              "NULL AS conperiod ");
    7981              : 
    7982              :     /*
    7983              :      * The point of the messy-looking outer join is to find a constraint that
    7984              :      * is related by an internal dependency link to the index. If we find one,
    7985              :      * create a CONSTRAINT entry linked to the INDEX entry.  We assume an
    7986              :      * index won't have more than one internal dependency.
    7987              :      *
    7988              :      * Note: the check on conrelid is redundant, but useful because that
    7989              :      * column is indexed while conindid is not.
    7990              :      */
    7991          249 :     if (fout->remoteVersion >= 110000)
    7992              :     {
    7993          249 :         appendPQExpBuffer(query,
    7994              :                           "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
    7995              :                           "JOIN pg_catalog.pg_index i ON (src.tbloid = i.indrelid) "
    7996              :                           "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
    7997              :                           "JOIN pg_catalog.pg_class t2 ON (t2.oid = i.indrelid) "
    7998              :                           "LEFT JOIN pg_catalog.pg_constraint c "
    7999              :                           "ON (i.indrelid = c.conrelid AND "
    8000              :                           "i.indexrelid = c.conindid AND "
    8001              :                           "c.contype IN ('p','u','x')) "
    8002              :                           "LEFT JOIN pg_catalog.pg_inherits inh "
    8003              :                           "ON (inh.inhrelid = indexrelid) "
    8004              :                           "WHERE (i.indisvalid OR t2.relkind = 'p') "
    8005              :                           "AND i.indisready "
    8006              :                           "ORDER BY i.indrelid, indexname",
    8007              :                           tbloids->data);
    8008              :     }
    8009              :     else
    8010              :     {
    8011              :         /*
    8012              :          * the test on indisready is necessary in 9.2, and harmless in
    8013              :          * earlier/later versions
    8014              :          */
    8015            0 :         appendPQExpBuffer(query,
    8016              :                           "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
    8017              :                           "JOIN pg_catalog.pg_index i ON (src.tbloid = i.indrelid) "
    8018              :                           "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
    8019              :                           "LEFT JOIN pg_catalog.pg_constraint c "
    8020              :                           "ON (i.indrelid = c.conrelid AND "
    8021              :                           "i.indexrelid = c.conindid AND "
    8022              :                           "c.contype IN ('p','u','x')) "
    8023              :                           "WHERE i.indisvalid AND i.indisready "
    8024              :                           "ORDER BY i.indrelid, indexname",
    8025              :                           tbloids->data);
    8026              :     }
    8027              : 
    8028          249 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    8029              : 
    8030          249 :     ntups = PQntuples(res);
    8031              : 
    8032          249 :     i_tableoid = PQfnumber(res, "tableoid");
    8033          249 :     i_oid = PQfnumber(res, "oid");
    8034          249 :     i_indrelid = PQfnumber(res, "indrelid");
    8035          249 :     i_indexname = PQfnumber(res, "indexname");
    8036          249 :     i_relpages = PQfnumber(res, "relpages");
    8037          249 :     i_reltuples = PQfnumber(res, "reltuples");
    8038          249 :     i_relallvisible = PQfnumber(res, "relallvisible");
    8039          249 :     i_relallfrozen = PQfnumber(res, "relallfrozen");
    8040          249 :     i_parentidx = PQfnumber(res, "parentidx");
    8041          249 :     i_indexdef = PQfnumber(res, "indexdef");
    8042          249 :     i_indnkeyatts = PQfnumber(res, "indnkeyatts");
    8043          249 :     i_indnatts = PQfnumber(res, "indnatts");
    8044          249 :     i_indkey = PQfnumber(res, "indkey");
    8045          249 :     i_indisclustered = PQfnumber(res, "indisclustered");
    8046          249 :     i_indisreplident = PQfnumber(res, "indisreplident");
    8047          249 :     i_indnullsnotdistinct = PQfnumber(res, "indnullsnotdistinct");
    8048          249 :     i_contype = PQfnumber(res, "contype");
    8049          249 :     i_conname = PQfnumber(res, "conname");
    8050          249 :     i_condeferrable = PQfnumber(res, "condeferrable");
    8051          249 :     i_condeferred = PQfnumber(res, "condeferred");
    8052          249 :     i_conperiod = PQfnumber(res, "conperiod");
    8053          249 :     i_contableoid = PQfnumber(res, "contableoid");
    8054          249 :     i_conoid = PQfnumber(res, "conoid");
    8055          249 :     i_condef = PQfnumber(res, "condef");
    8056          249 :     i_indattnames = PQfnumber(res, "indattnames");
    8057          249 :     i_tablespace = PQfnumber(res, "tablespace");
    8058          249 :     i_indreloptions = PQfnumber(res, "indreloptions");
    8059          249 :     i_indstatcols = PQfnumber(res, "indstatcols");
    8060          249 :     i_indstatvals = PQfnumber(res, "indstatvals");
    8061              : 
    8062          249 :     indxinfo = pg_malloc_array(IndxInfo, ntups);
    8063              : 
    8064              :     /*
    8065              :      * Outer loop iterates once per table, not once per row.  Incrementing of
    8066              :      * j is handled by the inner loop.
    8067              :      */
    8068          249 :     curtblindx = -1;
    8069         2236 :     for (int j = 0; j < ntups;)
    8070              :     {
    8071         1987 :         Oid         indrelid = atooid(PQgetvalue(res, j, i_indrelid));
    8072         1987 :         TableInfo  *tbinfo = NULL;
    8073         1987 :         char      **indAttNames = NULL;
    8074         1987 :         int         nindAttNames = 0;
    8075              :         int         numinds;
    8076              : 
    8077              :         /* Count rows for this table */
    8078         2609 :         for (numinds = 1; numinds < ntups - j; numinds++)
    8079         2530 :             if (atooid(PQgetvalue(res, j + numinds, i_indrelid)) != indrelid)
    8080         1908 :                 break;
    8081              : 
    8082              :         /*
    8083              :          * Locate the associated TableInfo; we rely on tblinfo[] being in OID
    8084              :          * order.
    8085              :          */
    8086        23143 :         while (++curtblindx < numTables)
    8087              :         {
    8088        23143 :             tbinfo = &tblinfo[curtblindx];
    8089        23143 :             if (tbinfo->dobj.catId.oid == indrelid)
    8090         1987 :                 break;
    8091              :         }
    8092         1987 :         if (curtblindx >= numTables)
    8093            0 :             pg_fatal("unrecognized table OID %u", indrelid);
    8094              :         /* cross-check that we only got requested tables */
    8095         1987 :         if (!tbinfo->hasindex ||
    8096         1987 :             !tbinfo->interesting)
    8097            0 :             pg_fatal("unexpected index data for table \"%s\"",
    8098              :                      tbinfo->dobj.name);
    8099              : 
    8100              :         /* Save data for this table */
    8101         1987 :         tbinfo->indexes = indxinfo + j;
    8102         1987 :         tbinfo->numIndexes = numinds;
    8103              : 
    8104         4596 :         for (int c = 0; c < numinds; c++, j++)
    8105              :         {
    8106              :             char        contype;
    8107              :             char        indexkind;
    8108              :             RelStatsInfo *relstats;
    8109         2609 :             int32       relpages = atoi(PQgetvalue(res, j, i_relpages));
    8110         2609 :             int32       relallvisible = atoi(PQgetvalue(res, j, i_relallvisible));
    8111         2609 :             int32       relallfrozen = atoi(PQgetvalue(res, j, i_relallfrozen));
    8112              : 
    8113         2609 :             indxinfo[j].dobj.objType = DO_INDEX;
    8114         2609 :             indxinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
    8115         2609 :             indxinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
    8116         2609 :             AssignDumpId(&indxinfo[j].dobj);
    8117         2609 :             indxinfo[j].dobj.dump = tbinfo->dobj.dump;
    8118         2609 :             indxinfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_indexname));
    8119         2609 :             indxinfo[j].dobj.namespace = tbinfo->dobj.namespace;
    8120         2609 :             indxinfo[j].indextable = tbinfo;
    8121         2609 :             indxinfo[j].indexdef = pg_strdup(PQgetvalue(res, j, i_indexdef));
    8122         2609 :             indxinfo[j].indnkeyattrs = atoi(PQgetvalue(res, j, i_indnkeyatts));
    8123         2609 :             indxinfo[j].indnattrs = atoi(PQgetvalue(res, j, i_indnatts));
    8124         2609 :             indxinfo[j].tablespace = pg_strdup(PQgetvalue(res, j, i_tablespace));
    8125         2609 :             indxinfo[j].indreloptions = pg_strdup(PQgetvalue(res, j, i_indreloptions));
    8126         2609 :             indxinfo[j].indstatcols = pg_strdup(PQgetvalue(res, j, i_indstatcols));
    8127         2609 :             indxinfo[j].indstatvals = pg_strdup(PQgetvalue(res, j, i_indstatvals));
    8128         2609 :             indxinfo[j].indkeys = pg_malloc_array(Oid, indxinfo[j].indnattrs);
    8129         2609 :             parseOidArray(PQgetvalue(res, j, i_indkey),
    8130         2609 :                           indxinfo[j].indkeys, indxinfo[j].indnattrs);
    8131         2609 :             indxinfo[j].indisclustered = (PQgetvalue(res, j, i_indisclustered)[0] == 't');
    8132         2609 :             indxinfo[j].indisreplident = (PQgetvalue(res, j, i_indisreplident)[0] == 't');
    8133         2609 :             indxinfo[j].indnullsnotdistinct = (PQgetvalue(res, j, i_indnullsnotdistinct)[0] == 't');
    8134         2609 :             indxinfo[j].parentidx = atooid(PQgetvalue(res, j, i_parentidx));
    8135         2609 :             indxinfo[j].partattaches = (SimplePtrList)
    8136              :             {
    8137              :                 NULL, NULL
    8138              :             };
    8139              : 
    8140         2609 :             if (indxinfo[j].parentidx == 0)
    8141         2035 :                 indexkind = RELKIND_INDEX;
    8142              :             else
    8143          574 :                 indexkind = RELKIND_PARTITIONED_INDEX;
    8144              : 
    8145         2609 :             if (!PQgetisnull(res, j, i_indattnames))
    8146              :             {
    8147          146 :                 if (!parsePGArray(PQgetvalue(res, j, i_indattnames),
    8148              :                                   &indAttNames, &nindAttNames))
    8149            0 :                     pg_fatal("could not parse %s array", "indattnames");
    8150              :             }
    8151              : 
    8152         2609 :             relstats = getRelationStatistics(fout, &indxinfo[j].dobj, relpages,
    8153              :                                              PQgetvalue(res, j, i_reltuples),
    8154              :                                              relallvisible, relallfrozen, indexkind,
    8155              :                                              indAttNames, nindAttNames);
    8156              : 
    8157         2609 :             contype = *(PQgetvalue(res, j, i_contype));
    8158         2609 :             if (contype == 'p' || contype == 'u' || contype == 'x')
    8159         1517 :             {
    8160              :                 /*
    8161              :                  * If we found a constraint matching the index, create an
    8162              :                  * entry for it.
    8163              :                  */
    8164              :                 ConstraintInfo *constrinfo;
    8165              : 
    8166         1517 :                 constrinfo = pg_malloc_object(ConstraintInfo);
    8167         1517 :                 constrinfo->dobj.objType = DO_CONSTRAINT;
    8168         1517 :                 constrinfo->dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_contableoid));
    8169         1517 :                 constrinfo->dobj.catId.oid = atooid(PQgetvalue(res, j, i_conoid));
    8170         1517 :                 AssignDumpId(&constrinfo->dobj);
    8171         1517 :                 constrinfo->dobj.dump = tbinfo->dobj.dump;
    8172         1517 :                 constrinfo->dobj.name = pg_strdup(PQgetvalue(res, j, i_conname));
    8173         1517 :                 constrinfo->dobj.namespace = tbinfo->dobj.namespace;
    8174         1517 :                 constrinfo->contable = tbinfo;
    8175         1517 :                 constrinfo->condomain = NULL;
    8176         1517 :                 constrinfo->contype = contype;
    8177         1517 :                 if (contype == 'x')
    8178           10 :                     constrinfo->condef = pg_strdup(PQgetvalue(res, j, i_condef));
    8179              :                 else
    8180         1507 :                     constrinfo->condef = NULL;
    8181         1517 :                 constrinfo->confrelid = InvalidOid;
    8182         1517 :                 constrinfo->conindex = indxinfo[j].dobj.dumpId;
    8183         1517 :                 constrinfo->condeferrable = *(PQgetvalue(res, j, i_condeferrable)) == 't';
    8184         1517 :                 constrinfo->condeferred = *(PQgetvalue(res, j, i_condeferred)) == 't';
    8185         1517 :                 constrinfo->conperiod = *(PQgetvalue(res, j, i_conperiod)) == 't';
    8186         1517 :                 constrinfo->conislocal = true;
    8187         1517 :                 constrinfo->separate = true;
    8188              : 
    8189         1517 :                 indxinfo[j].indexconstraint = constrinfo->dobj.dumpId;
    8190         1517 :                 if (relstats != NULL)
    8191          530 :                     addObjectDependency(&relstats->dobj, constrinfo->dobj.dumpId);
    8192              :             }
    8193              :             else
    8194              :             {
    8195              :                 /* Plain secondary index */
    8196         1092 :                 indxinfo[j].indexconstraint = 0;
    8197              :             }
    8198              :         }
    8199              :     }
    8200              : 
    8201          249 :     PQclear(res);
    8202              : 
    8203          249 :     destroyPQExpBuffer(query);
    8204          249 :     destroyPQExpBuffer(tbloids);
    8205          249 : }
    8206              : 
    8207              : /*
    8208              :  * getExtendedStatistics
    8209              :  *    get information about extended-statistics objects.
    8210              :  *
    8211              :  * Note: extended statistics data is not returned directly to the caller, but
    8212              :  * it does get entered into the DumpableObject tables.
    8213              :  */
    8214              : void
    8215          249 : getExtendedStatistics(Archive *fout)
    8216              : {
    8217              :     PQExpBuffer query;
    8218              :     PGresult   *res;
    8219              :     StatsExtInfo *statsextinfo;
    8220              :     int         ntups;
    8221              :     int         i_tableoid;
    8222              :     int         i_oid;
    8223              :     int         i_stxname;
    8224              :     int         i_stxnamespace;
    8225              :     int         i_stxowner;
    8226              :     int         i_stxrelid;
    8227              :     int         i_stattarget;
    8228              :     int         i;
    8229              : 
    8230              :     /* Extended statistics were new in v10 */
    8231          249 :     if (fout->remoteVersion < 100000)
    8232            0 :         return;
    8233              : 
    8234          249 :     query = createPQExpBuffer();
    8235              : 
    8236          249 :     if (fout->remoteVersion < 130000)
    8237            0 :         appendPQExpBufferStr(query, "SELECT tableoid, oid, stxname, "
    8238              :                              "stxnamespace, stxowner, stxrelid, NULL AS stxstattarget "
    8239              :                              "FROM pg_catalog.pg_statistic_ext");
    8240              :     else
    8241          249 :         appendPQExpBufferStr(query, "SELECT tableoid, oid, stxname, "
    8242              :                              "stxnamespace, stxowner, stxrelid, stxstattarget "
    8243              :                              "FROM pg_catalog.pg_statistic_ext");
    8244              : 
    8245          249 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    8246              : 
    8247          249 :     ntups = PQntuples(res);
    8248              : 
    8249          249 :     i_tableoid = PQfnumber(res, "tableoid");
    8250          249 :     i_oid = PQfnumber(res, "oid");
    8251          249 :     i_stxname = PQfnumber(res, "stxname");
    8252          249 :     i_stxnamespace = PQfnumber(res, "stxnamespace");
    8253          249 :     i_stxowner = PQfnumber(res, "stxowner");
    8254          249 :     i_stxrelid = PQfnumber(res, "stxrelid");
    8255          249 :     i_stattarget = PQfnumber(res, "stxstattarget");
    8256              : 
    8257          249 :     statsextinfo = pg_malloc_array(StatsExtInfo, ntups);
    8258              : 
    8259          457 :     for (i = 0; i < ntups; i++)
    8260              :     {
    8261          208 :         statsextinfo[i].dobj.objType = DO_STATSEXT;
    8262          208 :         statsextinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    8263          208 :         statsextinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    8264          208 :         AssignDumpId(&statsextinfo[i].dobj);
    8265          208 :         statsextinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_stxname));
    8266          416 :         statsextinfo[i].dobj.namespace =
    8267          208 :             findNamespace(atooid(PQgetvalue(res, i, i_stxnamespace)));
    8268          208 :         statsextinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_stxowner));
    8269          416 :         statsextinfo[i].stattable =
    8270          208 :             findTableByOid(atooid(PQgetvalue(res, i, i_stxrelid)));
    8271          208 :         if (PQgetisnull(res, i, i_stattarget))
    8272          163 :             statsextinfo[i].stattarget = -1;
    8273              :         else
    8274           45 :             statsextinfo[i].stattarget = atoi(PQgetvalue(res, i, i_stattarget));
    8275              : 
    8276              :         /* Decide whether we want to dump it */
    8277          208 :         selectDumpableStatisticsObject(&(statsextinfo[i]), fout);
    8278              : 
    8279          208 :         if (fout->dopt->dumpStatistics)
    8280          152 :             statsextinfo[i].dobj.components |= DUMP_COMPONENT_STATISTICS;
    8281              :     }
    8282              : 
    8283          249 :     PQclear(res);
    8284          249 :     destroyPQExpBuffer(query);
    8285              : }
    8286              : 
    8287              : /*
    8288              :  * getConstraints
    8289              :  *
    8290              :  * Get info about constraints on dumpable tables.
    8291              :  *
    8292              :  * Currently handles foreign keys only.
    8293              :  * Unique and primary key constraints are handled with indexes,
    8294              :  * while check constraints are processed in getTableAttrs().
    8295              :  */
    8296              : void
    8297          249 : getConstraints(Archive *fout, TableInfo tblinfo[], int numTables)
    8298              : {
    8299          249 :     PQExpBuffer query = createPQExpBuffer();
    8300          249 :     PQExpBuffer tbloids = createPQExpBuffer();
    8301              :     PGresult   *res;
    8302              :     int         ntups;
    8303              :     int         curtblindx;
    8304          249 :     TableInfo  *tbinfo = NULL;
    8305              :     ConstraintInfo *constrinfo;
    8306              :     int         i_contableoid,
    8307              :                 i_conoid,
    8308              :                 i_conrelid,
    8309              :                 i_conname,
    8310              :                 i_confrelid,
    8311              :                 i_conindid,
    8312              :                 i_condef;
    8313              : 
    8314              :     /*
    8315              :      * We want to perform just one query against pg_constraint.  However, we
    8316              :      * mustn't try to select every row of the catalog and then sort it out on
    8317              :      * the client side, because some of the server-side functions we need
    8318              :      * would be unsafe to apply to tables we don't have lock on.  Hence, we
    8319              :      * build an array of the OIDs of tables we care about (and now have lock
    8320              :      * on!), and use a WHERE clause to constrain which rows are selected.
    8321              :      */
    8322          249 :     appendPQExpBufferChar(tbloids, '{');
    8323        63065 :     for (int i = 0; i < numTables; i++)
    8324              :     {
    8325        62816 :         TableInfo  *tinfo = &tblinfo[i];
    8326              : 
    8327        62816 :         if (!(tinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
    8328        55649 :             continue;
    8329              : 
    8330              :         /* OK, we need info for this table */
    8331         7167 :         if (tbloids->len > 1) /* do we have more than the '{'? */
    8332         6995 :             appendPQExpBufferChar(tbloids, ',');
    8333         7167 :         appendPQExpBuffer(tbloids, "%u", tinfo->dobj.catId.oid);
    8334              :     }
    8335          249 :     appendPQExpBufferChar(tbloids, '}');
    8336              : 
    8337          249 :     appendPQExpBufferStr(query,
    8338              :                          "SELECT c.tableoid, c.oid, "
    8339              :                          "conrelid, conname, confrelid, ");
    8340          249 :     if (fout->remoteVersion >= 110000)
    8341          249 :         appendPQExpBufferStr(query, "conindid, ");
    8342              :     else
    8343            0 :         appendPQExpBufferStr(query, "0 AS conindid, ");
    8344          249 :     appendPQExpBuffer(query,
    8345              :                       "pg_catalog.pg_get_constraintdef(c.oid) AS condef\n"
    8346              :                       "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
    8347              :                       "JOIN pg_catalog.pg_constraint c ON (src.tbloid = c.conrelid)\n"
    8348              :                       "WHERE contype = 'f' ",
    8349              :                       tbloids->data);
    8350          249 :     if (fout->remoteVersion >= 110000)
    8351          249 :         appendPQExpBufferStr(query,
    8352              :                              "AND conparentid = 0 ");
    8353          249 :     appendPQExpBufferStr(query,
    8354              :                          "ORDER BY conrelid, conname");
    8355              : 
    8356          249 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    8357              : 
    8358          249 :     ntups = PQntuples(res);
    8359              : 
    8360          249 :     i_contableoid = PQfnumber(res, "tableoid");
    8361          249 :     i_conoid = PQfnumber(res, "oid");
    8362          249 :     i_conrelid = PQfnumber(res, "conrelid");
    8363          249 :     i_conname = PQfnumber(res, "conname");
    8364          249 :     i_confrelid = PQfnumber(res, "confrelid");
    8365          249 :     i_conindid = PQfnumber(res, "conindid");
    8366          249 :     i_condef = PQfnumber(res, "condef");
    8367              : 
    8368          249 :     constrinfo = pg_malloc_array(ConstraintInfo, ntups);
    8369              : 
    8370          249 :     curtblindx = -1;
    8371          420 :     for (int j = 0; j < ntups; j++)
    8372              :     {
    8373          171 :         Oid         conrelid = atooid(PQgetvalue(res, j, i_conrelid));
    8374              :         TableInfo  *reftable;
    8375              : 
    8376              :         /*
    8377              :          * Locate the associated TableInfo; we rely on tblinfo[] being in OID
    8378              :          * order.
    8379              :          */
    8380          171 :         if (tbinfo == NULL || tbinfo->dobj.catId.oid != conrelid)
    8381              :         {
    8382        13533 :             while (++curtblindx < numTables)
    8383              :             {
    8384        13533 :                 tbinfo = &tblinfo[curtblindx];
    8385        13533 :                 if (tbinfo->dobj.catId.oid == conrelid)
    8386          161 :                     break;
    8387              :             }
    8388          161 :             if (curtblindx >= numTables)
    8389            0 :                 pg_fatal("unrecognized table OID %u", conrelid);
    8390              :         }
    8391              : 
    8392          171 :         constrinfo[j].dobj.objType = DO_FK_CONSTRAINT;
    8393          171 :         constrinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_contableoid));
    8394          171 :         constrinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_conoid));
    8395          171 :         AssignDumpId(&constrinfo[j].dobj);
    8396          171 :         constrinfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_conname));
    8397          171 :         constrinfo[j].dobj.namespace = tbinfo->dobj.namespace;
    8398          171 :         constrinfo[j].contable = tbinfo;
    8399          171 :         constrinfo[j].condomain = NULL;
    8400          171 :         constrinfo[j].contype = 'f';
    8401          171 :         constrinfo[j].condef = pg_strdup(PQgetvalue(res, j, i_condef));
    8402          171 :         constrinfo[j].confrelid = atooid(PQgetvalue(res, j, i_confrelid));
    8403          171 :         constrinfo[j].conindex = 0;
    8404          171 :         constrinfo[j].condeferrable = false;
    8405          171 :         constrinfo[j].condeferred = false;
    8406          171 :         constrinfo[j].conislocal = true;
    8407          171 :         constrinfo[j].separate = true;
    8408              : 
    8409              :         /*
    8410              :          * Restoring an FK that points to a partitioned table requires that
    8411              :          * all partition indexes have been attached beforehand. Ensure that
    8412              :          * happens by making the constraint depend on each index partition
    8413              :          * attach object.
    8414              :          */
    8415          171 :         reftable = findTableByOid(constrinfo[j].confrelid);
    8416          171 :         if (reftable && reftable->relkind == RELKIND_PARTITIONED_TABLE)
    8417              :         {
    8418           20 :             Oid         indexOid = atooid(PQgetvalue(res, j, i_conindid));
    8419              : 
    8420           20 :             if (indexOid != InvalidOid)
    8421              :             {
    8422           20 :                 for (int k = 0; k < reftable->numIndexes; k++)
    8423              :                 {
    8424              :                     IndxInfo   *refidx;
    8425              : 
    8426              :                     /* not our index? */
    8427           20 :                     if (reftable->indexes[k].dobj.catId.oid != indexOid)
    8428            0 :                         continue;
    8429              : 
    8430           20 :                     refidx = &reftable->indexes[k];
    8431           20 :                     addConstrChildIdxDeps(&constrinfo[j].dobj, refidx);
    8432           20 :                     break;
    8433              :                 }
    8434              :             }
    8435              :         }
    8436              :     }
    8437              : 
    8438          249 :     PQclear(res);
    8439              : 
    8440          249 :     destroyPQExpBuffer(query);
    8441          249 :     destroyPQExpBuffer(tbloids);
    8442          249 : }
    8443              : 
    8444              : /*
    8445              :  * addConstrChildIdxDeps
    8446              :  *
    8447              :  * Recursive subroutine for getConstraints
    8448              :  *
    8449              :  * Given an object representing a foreign key constraint and an index on the
    8450              :  * partitioned table it references, mark the constraint object as dependent
    8451              :  * on the DO_INDEX_ATTACH object of each index partition, recursively
    8452              :  * drilling down to their partitions if any.  This ensures that the FK is not
    8453              :  * restored until the index is fully marked valid.
    8454              :  */
    8455              : static void
    8456           45 : addConstrChildIdxDeps(DumpableObject *dobj, const IndxInfo *refidx)
    8457              : {
    8458              :     SimplePtrListCell *cell;
    8459              : 
    8460              :     Assert(dobj->objType == DO_FK_CONSTRAINT);
    8461              : 
    8462          155 :     for (cell = refidx->partattaches.head; cell; cell = cell->next)
    8463              :     {
    8464          110 :         IndexAttachInfo *attach = (IndexAttachInfo *) cell->ptr;
    8465              : 
    8466          110 :         addObjectDependency(dobj, attach->dobj.dumpId);
    8467              : 
    8468          110 :         if (attach->partitionIdx->partattaches.head != NULL)
    8469           25 :             addConstrChildIdxDeps(dobj, attach->partitionIdx);
    8470              :     }
    8471           45 : }
    8472              : 
    8473              : /*
    8474              :  * getDomainConstraints
    8475              :  *
    8476              :  * Get info about constraints on a domain.
    8477              :  */
    8478              : static void
    8479          158 : getDomainConstraints(Archive *fout, TypeInfo *tyinfo)
    8480              : {
    8481              :     ConstraintInfo *constrinfo;
    8482          158 :     PQExpBuffer query = createPQExpBuffer();
    8483              :     PGresult   *res;
    8484              :     int         i_tableoid,
    8485              :                 i_oid,
    8486              :                 i_conname,
    8487              :                 i_consrc,
    8488              :                 i_convalidated,
    8489              :                 i_contype;
    8490              :     int         ntups;
    8491              : 
    8492          158 :     if (!fout->is_prepared[PREPQUERY_GETDOMAINCONSTRAINTS])
    8493              :     {
    8494              :         /*
    8495              :          * Set up query for constraint-specific details.  For servers 17 and
    8496              :          * up, domains have constraints of type 'n' as well as 'c', otherwise
    8497              :          * just the latter.
    8498              :          */
    8499           43 :         appendPQExpBuffer(query,
    8500              :                           "PREPARE getDomainConstraints(pg_catalog.oid) AS\n"
    8501              :                           "SELECT tableoid, oid, conname, "
    8502              :                           "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
    8503              :                           "convalidated, contype "
    8504              :                           "FROM pg_catalog.pg_constraint "
    8505              :                           "WHERE contypid = $1 AND contype IN (%s) "
    8506              :                           "ORDER BY conname",
    8507           43 :                           fout->remoteVersion < 170000 ? "'c'" : "'c', 'n'");
    8508              : 
    8509           43 :         ExecuteSqlStatement(fout, query->data);
    8510              : 
    8511           43 :         fout->is_prepared[PREPQUERY_GETDOMAINCONSTRAINTS] = true;
    8512              :     }
    8513              : 
    8514          158 :     printfPQExpBuffer(query,
    8515              :                       "EXECUTE getDomainConstraints('%u')",
    8516              :                       tyinfo->dobj.catId.oid);
    8517              : 
    8518          158 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    8519              : 
    8520          158 :     ntups = PQntuples(res);
    8521              : 
    8522          158 :     i_tableoid = PQfnumber(res, "tableoid");
    8523          158 :     i_oid = PQfnumber(res, "oid");
    8524          158 :     i_conname = PQfnumber(res, "conname");
    8525          158 :     i_consrc = PQfnumber(res, "consrc");
    8526          158 :     i_convalidated = PQfnumber(res, "convalidated");
    8527          158 :     i_contype = PQfnumber(res, "contype");
    8528              : 
    8529          158 :     constrinfo = pg_malloc_array(ConstraintInfo, ntups);
    8530          158 :     tyinfo->domChecks = constrinfo;
    8531              : 
    8532              :     /* 'i' tracks result rows; 'j' counts CHECK constraints */
    8533          324 :     for (int i = 0, j = 0; i < ntups; i++)
    8534              :     {
    8535          166 :         bool        validated = PQgetvalue(res, i, i_convalidated)[0] == 't';
    8536          166 :         char        contype = (PQgetvalue(res, i, i_contype))[0];
    8537              :         ConstraintInfo *constraint;
    8538              : 
    8539          166 :         if (contype == CONSTRAINT_CHECK)
    8540              :         {
    8541          113 :             constraint = &constrinfo[j++];
    8542          113 :             tyinfo->nDomChecks++;
    8543              :         }
    8544              :         else
    8545              :         {
    8546              :             Assert(contype == CONSTRAINT_NOTNULL);
    8547              :             Assert(tyinfo->notnull == NULL);
    8548              :             /* use last item in array for the not-null constraint */
    8549           53 :             tyinfo->notnull = &(constrinfo[ntups - 1]);
    8550           53 :             constraint = tyinfo->notnull;
    8551              :         }
    8552              : 
    8553          166 :         constraint->dobj.objType = DO_CONSTRAINT;
    8554          166 :         constraint->dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    8555          166 :         constraint->dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    8556          166 :         AssignDumpId(&(constraint->dobj));
    8557          166 :         constraint->dobj.name = pg_strdup(PQgetvalue(res, i, i_conname));
    8558          166 :         constraint->dobj.namespace = tyinfo->dobj.namespace;
    8559          166 :         constraint->contable = NULL;
    8560          166 :         constraint->condomain = tyinfo;
    8561          166 :         constraint->contype = contype;
    8562          166 :         constraint->condef = pg_strdup(PQgetvalue(res, i, i_consrc));
    8563          166 :         constraint->confrelid = InvalidOid;
    8564          166 :         constraint->conindex = 0;
    8565          166 :         constraint->condeferrable = false;
    8566          166 :         constraint->condeferred = false;
    8567          166 :         constraint->conislocal = true;
    8568              : 
    8569          166 :         constraint->separate = !validated;
    8570              : 
    8571              :         /*
    8572              :          * Make the domain depend on the constraint, ensuring it won't be
    8573              :          * output till any constraint dependencies are OK.  If the constraint
    8574              :          * has not been validated, it's going to be dumped after the domain
    8575              :          * anyway, so this doesn't matter.
    8576              :          */
    8577          166 :         if (validated)
    8578          161 :             addObjectDependency(&tyinfo->dobj, constraint->dobj.dumpId);
    8579              :     }
    8580              : 
    8581          158 :     PQclear(res);
    8582              : 
    8583          158 :     destroyPQExpBuffer(query);
    8584          158 : }
    8585              : 
    8586              : /*
    8587              :  * getRules
    8588              :  *    get basic information about every rule in the system
    8589              :  */
    8590              : void
    8591          249 : getRules(Archive *fout)
    8592              : {
    8593              :     PGresult   *res;
    8594              :     int         ntups;
    8595              :     int         i;
    8596          249 :     PQExpBuffer query = createPQExpBuffer();
    8597              :     RuleInfo   *ruleinfo;
    8598              :     int         i_tableoid;
    8599              :     int         i_oid;
    8600              :     int         i_rulename;
    8601              :     int         i_ruletable;
    8602              :     int         i_ev_type;
    8603              :     int         i_is_instead;
    8604              :     int         i_ev_enabled;
    8605              : 
    8606          249 :     appendPQExpBufferStr(query, "SELECT "
    8607              :                          "tableoid, oid, rulename, "
    8608              :                          "ev_class AS ruletable, ev_type, is_instead, "
    8609              :                          "ev_enabled "
    8610              :                          "FROM pg_rewrite "
    8611              :                          "ORDER BY oid");
    8612              : 
    8613          249 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    8614              : 
    8615          249 :     ntups = PQntuples(res);
    8616              : 
    8617          249 :     ruleinfo = pg_malloc_array(RuleInfo, ntups);
    8618              : 
    8619          249 :     i_tableoid = PQfnumber(res, "tableoid");
    8620          249 :     i_oid = PQfnumber(res, "oid");
    8621          249 :     i_rulename = PQfnumber(res, "rulename");
    8622          249 :     i_ruletable = PQfnumber(res, "ruletable");
    8623          249 :     i_ev_type = PQfnumber(res, "ev_type");
    8624          249 :     i_is_instead = PQfnumber(res, "is_instead");
    8625          249 :     i_ev_enabled = PQfnumber(res, "ev_enabled");
    8626              : 
    8627        38493 :     for (i = 0; i < ntups; i++)
    8628              :     {
    8629              :         Oid         ruletableoid;
    8630              : 
    8631        38244 :         ruleinfo[i].dobj.objType = DO_RULE;
    8632        38244 :         ruleinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    8633        38244 :         ruleinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    8634        38244 :         AssignDumpId(&ruleinfo[i].dobj);
    8635        38244 :         ruleinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_rulename));
    8636        38244 :         ruletableoid = atooid(PQgetvalue(res, i, i_ruletable));
    8637        38244 :         ruleinfo[i].ruletable = findTableByOid(ruletableoid);
    8638        38244 :         if (ruleinfo[i].ruletable == NULL)
    8639            0 :             pg_fatal("failed sanity check, parent table with OID %u of pg_rewrite entry with OID %u not found",
    8640              :                      ruletableoid, ruleinfo[i].dobj.catId.oid);
    8641        38244 :         ruleinfo[i].dobj.namespace = ruleinfo[i].ruletable->dobj.namespace;
    8642        38244 :         ruleinfo[i].dobj.dump = ruleinfo[i].ruletable->dobj.dump;
    8643        38244 :         ruleinfo[i].ev_type = *(PQgetvalue(res, i, i_ev_type));
    8644        38244 :         ruleinfo[i].is_instead = *(PQgetvalue(res, i, i_is_instead)) == 't';
    8645        38244 :         ruleinfo[i].ev_enabled = *(PQgetvalue(res, i, i_ev_enabled));
    8646        38244 :         if (ruleinfo[i].ruletable)
    8647              :         {
    8648              :             /*
    8649              :              * If the table is a view or materialized view, force its ON
    8650              :              * SELECT rule to be sorted before the view itself --- this
    8651              :              * ensures that any dependencies for the rule affect the table's
    8652              :              * positioning. Other rules are forced to appear after their
    8653              :              * table.
    8654              :              */
    8655        38244 :             if ((ruleinfo[i].ruletable->relkind == RELKIND_VIEW ||
    8656          699 :                  ruleinfo[i].ruletable->relkind == RELKIND_MATVIEW) &&
    8657        38013 :                 ruleinfo[i].ev_type == '1' && ruleinfo[i].is_instead)
    8658              :             {
    8659        37473 :                 addObjectDependency(&ruleinfo[i].ruletable->dobj,
    8660        37473 :                                     ruleinfo[i].dobj.dumpId);
    8661              :                 /* We'll merge the rule into CREATE VIEW, if possible */
    8662        37473 :                 ruleinfo[i].separate = false;
    8663              :             }
    8664              :             else
    8665              :             {
    8666          771 :                 addObjectDependency(&ruleinfo[i].dobj,
    8667          771 :                                     ruleinfo[i].ruletable->dobj.dumpId);
    8668          771 :                 ruleinfo[i].separate = true;
    8669              :             }
    8670              :         }
    8671              :         else
    8672            0 :             ruleinfo[i].separate = true;
    8673              :     }
    8674              : 
    8675          249 :     PQclear(res);
    8676              : 
    8677          249 :     destroyPQExpBuffer(query);
    8678          249 : }
    8679              : 
    8680              : /*
    8681              :  * getTriggers
    8682              :  *    get information about every trigger on a dumpable table
    8683              :  *
    8684              :  * Note: trigger data is not returned directly to the caller, but it
    8685              :  * does get entered into the DumpableObject tables.
    8686              :  */
    8687              : void
    8688          249 : getTriggers(Archive *fout, TableInfo tblinfo[], int numTables)
    8689              : {
    8690          249 :     PQExpBuffer query = createPQExpBuffer();
    8691          249 :     PQExpBuffer tbloids = createPQExpBuffer();
    8692              :     PGresult   *res;
    8693              :     int         ntups;
    8694              :     int         curtblindx;
    8695              :     TriggerInfo *tginfo;
    8696              :     int         i_tableoid,
    8697              :                 i_oid,
    8698              :                 i_tgrelid,
    8699              :                 i_tgname,
    8700              :                 i_tgenabled,
    8701              :                 i_tgispartition,
    8702              :                 i_tgdef;
    8703              : 
    8704              :     /*
    8705              :      * We want to perform just one query against pg_trigger.  However, we
    8706              :      * mustn't try to select every row of the catalog and then sort it out on
    8707              :      * the client side, because some of the server-side functions we need
    8708              :      * would be unsafe to apply to tables we don't have lock on.  Hence, we
    8709              :      * build an array of the OIDs of tables we care about (and now have lock
    8710              :      * on!), and use a WHERE clause to constrain which rows are selected.
    8711              :      */
    8712          249 :     appendPQExpBufferChar(tbloids, '{');
    8713        63065 :     for (int i = 0; i < numTables; i++)
    8714              :     {
    8715        62816 :         TableInfo  *tbinfo = &tblinfo[i];
    8716              : 
    8717        62816 :         if (!tbinfo->hastriggers ||
    8718         1114 :             !(tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
    8719        61964 :             continue;
    8720              : 
    8721              :         /* OK, we need info for this table */
    8722          852 :         if (tbloids->len > 1) /* do we have more than the '{'? */
    8723          801 :             appendPQExpBufferChar(tbloids, ',');
    8724          852 :         appendPQExpBuffer(tbloids, "%u", tbinfo->dobj.catId.oid);
    8725              :     }
    8726          249 :     appendPQExpBufferChar(tbloids, '}');
    8727              : 
    8728          249 :     if (fout->remoteVersion >= 150000)
    8729              :     {
    8730              :         /*
    8731              :          * NB: think not to use pretty=true in pg_get_triggerdef.  It could
    8732              :          * result in non-forward-compatible dumps of WHEN clauses due to
    8733              :          * under-parenthesization.
    8734              :          *
    8735              :          * NB: We need to see partition triggers in case the tgenabled flag
    8736              :          * has been changed from the parent.
    8737              :          */
    8738          249 :         appendPQExpBuffer(query,
    8739              :                           "SELECT t.tgrelid, t.tgname, "
    8740              :                           "pg_catalog.pg_get_triggerdef(t.oid, false) AS tgdef, "
    8741              :                           "t.tgenabled, t.tableoid, t.oid, "
    8742              :                           "t.tgparentid <> 0 AS tgispartition\n"
    8743              :                           "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
    8744              :                           "JOIN pg_catalog.pg_trigger t ON (src.tbloid = t.tgrelid) "
    8745              :                           "LEFT JOIN pg_catalog.pg_trigger u ON (u.oid = t.tgparentid) "
    8746              :                           "WHERE ((NOT t.tgisinternal AND t.tgparentid = 0) "
    8747              :                           "OR t.tgenabled != u.tgenabled) "
    8748              :                           "ORDER BY t.tgrelid, t.tgname",
    8749              :                           tbloids->data);
    8750              :     }
    8751            0 :     else if (fout->remoteVersion >= 130000)
    8752              :     {
    8753              :         /*
    8754              :          * NB: think not to use pretty=true in pg_get_triggerdef.  It could
    8755              :          * result in non-forward-compatible dumps of WHEN clauses due to
    8756              :          * under-parenthesization.
    8757              :          *
    8758              :          * NB: We need to see tgisinternal triggers in partitions, in case the
    8759              :          * tgenabled flag has been changed from the parent.
    8760              :          */
    8761            0 :         appendPQExpBuffer(query,
    8762              :                           "SELECT t.tgrelid, t.tgname, "
    8763              :                           "pg_catalog.pg_get_triggerdef(t.oid, false) AS tgdef, "
    8764              :                           "t.tgenabled, t.tableoid, t.oid, t.tgisinternal as tgispartition\n"
    8765              :                           "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
    8766              :                           "JOIN pg_catalog.pg_trigger t ON (src.tbloid = t.tgrelid) "
    8767              :                           "LEFT JOIN pg_catalog.pg_trigger u ON (u.oid = t.tgparentid) "
    8768              :                           "WHERE (NOT t.tgisinternal OR t.tgenabled != u.tgenabled) "
    8769              :                           "ORDER BY t.tgrelid, t.tgname",
    8770              :                           tbloids->data);
    8771              :     }
    8772            0 :     else if (fout->remoteVersion >= 110000)
    8773              :     {
    8774              :         /*
    8775              :          * NB: We need to see tgisinternal triggers in partitions, in case the
    8776              :          * tgenabled flag has been changed from the parent. No tgparentid in
    8777              :          * version 11-12, so we have to match them via pg_depend.
    8778              :          *
    8779              :          * See above about pretty=true in pg_get_triggerdef.
    8780              :          */
    8781            0 :         appendPQExpBuffer(query,
    8782              :                           "SELECT t.tgrelid, t.tgname, "
    8783              :                           "pg_catalog.pg_get_triggerdef(t.oid, false) AS tgdef, "
    8784              :                           "t.tgenabled, t.tableoid, t.oid, t.tgisinternal as tgispartition "
    8785              :                           "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
    8786              :                           "JOIN pg_catalog.pg_trigger t ON (src.tbloid = t.tgrelid) "
    8787              :                           "LEFT JOIN pg_catalog.pg_depend AS d ON "
    8788              :                           " d.classid = 'pg_catalog.pg_trigger'::pg_catalog.regclass AND "
    8789              :                           " d.refclassid = 'pg_catalog.pg_trigger'::pg_catalog.regclass AND "
    8790              :                           " d.objid = t.oid "
    8791              :                           "LEFT JOIN pg_catalog.pg_trigger AS pt ON pt.oid = refobjid "
    8792              :                           "WHERE (NOT t.tgisinternal OR t.tgenabled != pt.tgenabled) "
    8793              :                           "ORDER BY t.tgrelid, t.tgname",
    8794              :                           tbloids->data);
    8795              :     }
    8796              :     else
    8797              :     {
    8798              :         /* See above about pretty=true in pg_get_triggerdef */
    8799            0 :         appendPQExpBuffer(query,
    8800              :                           "SELECT t.tgrelid, t.tgname, "
    8801              :                           "pg_catalog.pg_get_triggerdef(t.oid, false) AS tgdef, "
    8802              :                           "t.tgenabled, false as tgispartition, "
    8803              :                           "t.tableoid, t.oid "
    8804              :                           "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
    8805              :                           "JOIN pg_catalog.pg_trigger t ON (src.tbloid = t.tgrelid) "
    8806              :                           "WHERE NOT tgisinternal "
    8807              :                           "ORDER BY t.tgrelid, t.tgname",
    8808              :                           tbloids->data);
    8809              :     }
    8810              : 
    8811          249 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    8812              : 
    8813          249 :     ntups = PQntuples(res);
    8814              : 
    8815          249 :     i_tableoid = PQfnumber(res, "tableoid");
    8816          249 :     i_oid = PQfnumber(res, "oid");
    8817          249 :     i_tgrelid = PQfnumber(res, "tgrelid");
    8818          249 :     i_tgname = PQfnumber(res, "tgname");
    8819          249 :     i_tgenabled = PQfnumber(res, "tgenabled");
    8820          249 :     i_tgispartition = PQfnumber(res, "tgispartition");
    8821          249 :     i_tgdef = PQfnumber(res, "tgdef");
    8822              : 
    8823          249 :     tginfo = pg_malloc_array(TriggerInfo, ntups);
    8824              : 
    8825              :     /*
    8826              :      * Outer loop iterates once per table, not once per row.  Incrementing of
    8827              :      * j is handled by the inner loop.
    8828              :      */
    8829          249 :     curtblindx = -1;
    8830          555 :     for (int j = 0; j < ntups;)
    8831              :     {
    8832          306 :         Oid         tgrelid = atooid(PQgetvalue(res, j, i_tgrelid));
    8833          306 :         TableInfo  *tbinfo = NULL;
    8834              :         int         numtrigs;
    8835              : 
    8836              :         /* Count rows for this table */
    8837          523 :         for (numtrigs = 1; numtrigs < ntups - j; numtrigs++)
    8838          472 :             if (atooid(PQgetvalue(res, j + numtrigs, i_tgrelid)) != tgrelid)
    8839          255 :                 break;
    8840              : 
    8841              :         /*
    8842              :          * Locate the associated TableInfo; we rely on tblinfo[] being in OID
    8843              :          * order.
    8844              :          */
    8845        16043 :         while (++curtblindx < numTables)
    8846              :         {
    8847        16043 :             tbinfo = &tblinfo[curtblindx];
    8848        16043 :             if (tbinfo->dobj.catId.oid == tgrelid)
    8849          306 :                 break;
    8850              :         }
    8851          306 :         if (curtblindx >= numTables)
    8852            0 :             pg_fatal("unrecognized table OID %u", tgrelid);
    8853              : 
    8854              :         /* Save data for this table */
    8855          306 :         tbinfo->triggers = tginfo + j;
    8856          306 :         tbinfo->numTriggers = numtrigs;
    8857              : 
    8858          829 :         for (int c = 0; c < numtrigs; c++, j++)
    8859              :         {
    8860          523 :             tginfo[j].dobj.objType = DO_TRIGGER;
    8861          523 :             tginfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
    8862          523 :             tginfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
    8863          523 :             AssignDumpId(&tginfo[j].dobj);
    8864          523 :             tginfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_tgname));
    8865          523 :             tginfo[j].dobj.namespace = tbinfo->dobj.namespace;
    8866          523 :             tginfo[j].tgtable = tbinfo;
    8867          523 :             tginfo[j].tgenabled = *(PQgetvalue(res, j, i_tgenabled));
    8868          523 :             tginfo[j].tgispartition = *(PQgetvalue(res, j, i_tgispartition)) == 't';
    8869          523 :             tginfo[j].tgdef = pg_strdup(PQgetvalue(res, j, i_tgdef));
    8870              :         }
    8871              :     }
    8872              : 
    8873          249 :     PQclear(res);
    8874              : 
    8875          249 :     destroyPQExpBuffer(query);
    8876          249 :     destroyPQExpBuffer(tbloids);
    8877          249 : }
    8878              : 
    8879              : /*
    8880              :  * getEventTriggers
    8881              :  *    get information about event triggers
    8882              :  */
    8883              : void
    8884          249 : getEventTriggers(Archive *fout)
    8885              : {
    8886              :     int         i;
    8887              :     PQExpBuffer query;
    8888              :     PGresult   *res;
    8889              :     EventTriggerInfo *evtinfo;
    8890              :     int         i_tableoid,
    8891              :                 i_oid,
    8892              :                 i_evtname,
    8893              :                 i_evtevent,
    8894              :                 i_evtowner,
    8895              :                 i_evttags,
    8896              :                 i_evtfname,
    8897              :                 i_evtenabled;
    8898              :     int         ntups;
    8899              : 
    8900              :     /* Before 9.3, there are no event triggers */
    8901          249 :     if (fout->remoteVersion < 90300)
    8902            0 :         return;
    8903              : 
    8904          249 :     query = createPQExpBuffer();
    8905              : 
    8906          249 :     appendPQExpBufferStr(query,
    8907              :                          "SELECT e.tableoid, e.oid, evtname, evtenabled, "
    8908              :                          "evtevent, evtowner, "
    8909              :                          "array_to_string(array("
    8910              :                          "select quote_literal(x) "
    8911              :                          " from unnest(evttags) as t(x)), ', ') as evttags, "
    8912              :                          "e.evtfoid::regproc as evtfname "
    8913              :                          "FROM pg_event_trigger e "
    8914              :                          "ORDER BY e.oid");
    8915              : 
    8916          249 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    8917              : 
    8918          249 :     ntups = PQntuples(res);
    8919              : 
    8920          249 :     evtinfo = pg_malloc_array(EventTriggerInfo, ntups);
    8921              : 
    8922          249 :     i_tableoid = PQfnumber(res, "tableoid");
    8923          249 :     i_oid = PQfnumber(res, "oid");
    8924          249 :     i_evtname = PQfnumber(res, "evtname");
    8925          249 :     i_evtevent = PQfnumber(res, "evtevent");
    8926          249 :     i_evtowner = PQfnumber(res, "evtowner");
    8927          249 :     i_evttags = PQfnumber(res, "evttags");
    8928          249 :     i_evtfname = PQfnumber(res, "evtfname");
    8929          249 :     i_evtenabled = PQfnumber(res, "evtenabled");
    8930              : 
    8931          301 :     for (i = 0; i < ntups; i++)
    8932              :     {
    8933           52 :         evtinfo[i].dobj.objType = DO_EVENT_TRIGGER;
    8934           52 :         evtinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    8935           52 :         evtinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    8936           52 :         AssignDumpId(&evtinfo[i].dobj);
    8937           52 :         evtinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_evtname));
    8938           52 :         evtinfo[i].evtname = pg_strdup(PQgetvalue(res, i, i_evtname));
    8939           52 :         evtinfo[i].evtevent = pg_strdup(PQgetvalue(res, i, i_evtevent));
    8940           52 :         evtinfo[i].evtowner = getRoleName(PQgetvalue(res, i, i_evtowner));
    8941           52 :         evtinfo[i].evttags = pg_strdup(PQgetvalue(res, i, i_evttags));
    8942           52 :         evtinfo[i].evtfname = pg_strdup(PQgetvalue(res, i, i_evtfname));
    8943           52 :         evtinfo[i].evtenabled = *(PQgetvalue(res, i, i_evtenabled));
    8944              : 
    8945              :         /* Decide whether we want to dump it */
    8946           52 :         selectDumpableObject(&(evtinfo[i].dobj), fout);
    8947              :     }
    8948              : 
    8949          249 :     PQclear(res);
    8950              : 
    8951          249 :     destroyPQExpBuffer(query);
    8952              : }
    8953              : 
    8954              : /*
    8955              :  * getProcLangs
    8956              :  *    get basic information about every procedural language in the system
    8957              :  *
    8958              :  * NB: this must run after getFuncs() because we assume we can do
    8959              :  * findFuncByOid().
    8960              :  */
    8961              : void
    8962          249 : getProcLangs(Archive *fout)
    8963              : {
    8964              :     PGresult   *res;
    8965              :     int         ntups;
    8966              :     int         i;
    8967          249 :     PQExpBuffer query = createPQExpBuffer();
    8968              :     ProcLangInfo *planginfo;
    8969              :     int         i_tableoid;
    8970              :     int         i_oid;
    8971              :     int         i_lanname;
    8972              :     int         i_lanpltrusted;
    8973              :     int         i_lanplcallfoid;
    8974              :     int         i_laninline;
    8975              :     int         i_lanvalidator;
    8976              :     int         i_lanacl;
    8977              :     int         i_acldefault;
    8978              :     int         i_lanowner;
    8979              : 
    8980          249 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, "
    8981              :                          "lanname, lanpltrusted, lanplcallfoid, "
    8982              :                          "laninline, lanvalidator, "
    8983              :                          "lanacl, "
    8984              :                          "acldefault('l', lanowner) AS acldefault, "
    8985              :                          "lanowner "
    8986              :                          "FROM pg_language "
    8987              :                          "WHERE lanispl "
    8988              :                          "ORDER BY oid");
    8989              : 
    8990          249 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    8991              : 
    8992          249 :     ntups = PQntuples(res);
    8993              : 
    8994          249 :     planginfo = pg_malloc_array(ProcLangInfo, ntups);
    8995              : 
    8996          249 :     i_tableoid = PQfnumber(res, "tableoid");
    8997          249 :     i_oid = PQfnumber(res, "oid");
    8998          249 :     i_lanname = PQfnumber(res, "lanname");
    8999          249 :     i_lanpltrusted = PQfnumber(res, "lanpltrusted");
    9000          249 :     i_lanplcallfoid = PQfnumber(res, "lanplcallfoid");
    9001          249 :     i_laninline = PQfnumber(res, "laninline");
    9002          249 :     i_lanvalidator = PQfnumber(res, "lanvalidator");
    9003          249 :     i_lanacl = PQfnumber(res, "lanacl");
    9004          249 :     i_acldefault = PQfnumber(res, "acldefault");
    9005          249 :     i_lanowner = PQfnumber(res, "lanowner");
    9006              : 
    9007          543 :     for (i = 0; i < ntups; i++)
    9008              :     {
    9009          294 :         planginfo[i].dobj.objType = DO_PROCLANG;
    9010          294 :         planginfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    9011          294 :         planginfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    9012          294 :         AssignDumpId(&planginfo[i].dobj);
    9013              : 
    9014          294 :         planginfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_lanname));
    9015          294 :         planginfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_lanacl));
    9016          294 :         planginfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
    9017          294 :         planginfo[i].dacl.privtype = 0;
    9018          294 :         planginfo[i].dacl.initprivs = NULL;
    9019          294 :         planginfo[i].lanpltrusted = *(PQgetvalue(res, i, i_lanpltrusted)) == 't';
    9020          294 :         planginfo[i].lanplcallfoid = atooid(PQgetvalue(res, i, i_lanplcallfoid));
    9021          294 :         planginfo[i].laninline = atooid(PQgetvalue(res, i, i_laninline));
    9022          294 :         planginfo[i].lanvalidator = atooid(PQgetvalue(res, i, i_lanvalidator));
    9023          294 :         planginfo[i].lanowner = getRoleName(PQgetvalue(res, i, i_lanowner));
    9024              : 
    9025              :         /* Decide whether we want to dump it */
    9026          294 :         selectDumpableProcLang(&(planginfo[i]), fout);
    9027              : 
    9028              :         /* Mark whether language has an ACL */
    9029          294 :         if (!PQgetisnull(res, i, i_lanacl))
    9030           45 :             planginfo[i].dobj.components |= DUMP_COMPONENT_ACL;
    9031              :     }
    9032              : 
    9033          249 :     PQclear(res);
    9034              : 
    9035          249 :     destroyPQExpBuffer(query);
    9036          249 : }
    9037              : 
    9038              : /*
    9039              :  * getCasts
    9040              :  *    get basic information about most casts in the system
    9041              :  *
    9042              :  * Skip casts from a range to its multirange, since we'll create those
    9043              :  * automatically.
    9044              :  */
    9045              : void
    9046          249 : getCasts(Archive *fout)
    9047              : {
    9048              :     PGresult   *res;
    9049              :     int         ntups;
    9050              :     int         i;
    9051          249 :     PQExpBuffer query = createPQExpBuffer();
    9052              :     CastInfo   *castinfo;
    9053              :     int         i_tableoid;
    9054              :     int         i_oid;
    9055              :     int         i_castsource;
    9056              :     int         i_casttarget;
    9057              :     int         i_castfunc;
    9058              :     int         i_castcontext;
    9059              :     int         i_castmethod;
    9060              : 
    9061          249 :     if (fout->remoteVersion >= 140000)
    9062              :     {
    9063          249 :         appendPQExpBufferStr(query, "SELECT tableoid, oid, "
    9064              :                              "castsource, casttarget, castfunc, castcontext, "
    9065              :                              "castmethod "
    9066              :                              "FROM pg_cast c "
    9067              :                              "WHERE NOT EXISTS ( "
    9068              :                              "SELECT 1 FROM pg_range r "
    9069              :                              "WHERE c.castsource = r.rngtypid "
    9070              :                              "AND c.casttarget = r.rngmultitypid "
    9071              :                              ") "
    9072              :                              "ORDER BY 3,4");
    9073              :     }
    9074              :     else
    9075              :     {
    9076            0 :         appendPQExpBufferStr(query, "SELECT tableoid, oid, "
    9077              :                              "castsource, casttarget, castfunc, castcontext, "
    9078              :                              "castmethod "
    9079              :                              "FROM pg_cast ORDER BY 3,4");
    9080              :     }
    9081              : 
    9082          249 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    9083              : 
    9084          249 :     ntups = PQntuples(res);
    9085              : 
    9086          249 :     castinfo = pg_malloc_array(CastInfo, ntups);
    9087              : 
    9088          249 :     i_tableoid = PQfnumber(res, "tableoid");
    9089          249 :     i_oid = PQfnumber(res, "oid");
    9090          249 :     i_castsource = PQfnumber(res, "castsource");
    9091          249 :     i_casttarget = PQfnumber(res, "casttarget");
    9092          249 :     i_castfunc = PQfnumber(res, "castfunc");
    9093          249 :     i_castcontext = PQfnumber(res, "castcontext");
    9094          249 :     i_castmethod = PQfnumber(res, "castmethod");
    9095              : 
    9096        60345 :     for (i = 0; i < ntups; i++)
    9097              :     {
    9098              :         PQExpBufferData namebuf;
    9099              :         TypeInfo   *sTypeInfo;
    9100              :         TypeInfo   *tTypeInfo;
    9101              : 
    9102        60096 :         castinfo[i].dobj.objType = DO_CAST;
    9103        60096 :         castinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    9104        60096 :         castinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    9105        60096 :         AssignDumpId(&castinfo[i].dobj);
    9106        60096 :         castinfo[i].castsource = atooid(PQgetvalue(res, i, i_castsource));
    9107        60096 :         castinfo[i].casttarget = atooid(PQgetvalue(res, i, i_casttarget));
    9108        60096 :         castinfo[i].castfunc = atooid(PQgetvalue(res, i, i_castfunc));
    9109        60096 :         castinfo[i].castcontext = *(PQgetvalue(res, i, i_castcontext));
    9110        60096 :         castinfo[i].castmethod = *(PQgetvalue(res, i, i_castmethod));
    9111              : 
    9112              :         /*
    9113              :          * Try to name cast as concatenation of typnames.  This is only used
    9114              :          * for purposes of sorting.  If we fail to find either type, the name
    9115              :          * will be an empty string.
    9116              :          */
    9117        60096 :         initPQExpBuffer(&namebuf);
    9118        60096 :         sTypeInfo = findTypeByOid(castinfo[i].castsource);
    9119        60096 :         tTypeInfo = findTypeByOid(castinfo[i].casttarget);
    9120        60096 :         if (sTypeInfo && tTypeInfo)
    9121        60096 :             appendPQExpBuffer(&namebuf, "%s %s",
    9122              :                               sTypeInfo->dobj.name, tTypeInfo->dobj.name);
    9123        60096 :         castinfo[i].dobj.name = namebuf.data;
    9124              : 
    9125              :         /* Decide whether we want to dump it */
    9126        60096 :         selectDumpableCast(&(castinfo[i]), fout);
    9127              :     }
    9128              : 
    9129          249 :     PQclear(res);
    9130              : 
    9131          249 :     destroyPQExpBuffer(query);
    9132          249 : }
    9133              : 
    9134              : static char *
    9135           88 : get_language_name(Archive *fout, Oid langid)
    9136              : {
    9137              :     PQExpBuffer query;
    9138              :     PGresult   *res;
    9139              :     char       *lanname;
    9140              : 
    9141           88 :     query = createPQExpBuffer();
    9142           88 :     appendPQExpBuffer(query, "SELECT lanname FROM pg_language WHERE oid = %u", langid);
    9143           88 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
    9144           88 :     lanname = pg_strdup(fmtId(PQgetvalue(res, 0, 0)));
    9145           88 :     destroyPQExpBuffer(query);
    9146           88 :     PQclear(res);
    9147              : 
    9148           88 :     return lanname;
    9149              : }
    9150              : 
    9151              : /*
    9152              :  * getTransforms
    9153              :  *    get basic information about every transform in the system
    9154              :  */
    9155              : void
    9156          249 : getTransforms(Archive *fout)
    9157              : {
    9158              :     PGresult   *res;
    9159              :     int         ntups;
    9160              :     int         i;
    9161              :     PQExpBuffer query;
    9162              :     TransformInfo *transforminfo;
    9163              :     int         i_tableoid;
    9164              :     int         i_oid;
    9165              :     int         i_trftype;
    9166              :     int         i_trflang;
    9167              :     int         i_trffromsql;
    9168              :     int         i_trftosql;
    9169              : 
    9170              :     /* Transforms didn't exist pre-9.5 */
    9171          249 :     if (fout->remoteVersion < 90500)
    9172            0 :         return;
    9173              : 
    9174          249 :     query = createPQExpBuffer();
    9175              : 
    9176          249 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, "
    9177              :                          "trftype, trflang, trffromsql::oid, trftosql::oid "
    9178              :                          "FROM pg_transform "
    9179              :                          "ORDER BY 3,4");
    9180              : 
    9181          249 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    9182              : 
    9183          249 :     ntups = PQntuples(res);
    9184              : 
    9185          249 :     transforminfo = pg_malloc_array(TransformInfo, ntups);
    9186              : 
    9187          249 :     i_tableoid = PQfnumber(res, "tableoid");
    9188          249 :     i_oid = PQfnumber(res, "oid");
    9189          249 :     i_trftype = PQfnumber(res, "trftype");
    9190          249 :     i_trflang = PQfnumber(res, "trflang");
    9191          249 :     i_trffromsql = PQfnumber(res, "trffromsql");
    9192          249 :     i_trftosql = PQfnumber(res, "trftosql");
    9193              : 
    9194          301 :     for (i = 0; i < ntups; i++)
    9195              :     {
    9196              :         PQExpBufferData namebuf;
    9197              :         TypeInfo   *typeInfo;
    9198              :         char       *lanname;
    9199              : 
    9200           52 :         transforminfo[i].dobj.objType = DO_TRANSFORM;
    9201           52 :         transforminfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    9202           52 :         transforminfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    9203           52 :         AssignDumpId(&transforminfo[i].dobj);
    9204           52 :         transforminfo[i].trftype = atooid(PQgetvalue(res, i, i_trftype));
    9205           52 :         transforminfo[i].trflang = atooid(PQgetvalue(res, i, i_trflang));
    9206           52 :         transforminfo[i].trffromsql = atooid(PQgetvalue(res, i, i_trffromsql));
    9207           52 :         transforminfo[i].trftosql = atooid(PQgetvalue(res, i, i_trftosql));
    9208              : 
    9209              :         /*
    9210              :          * Try to name transform as concatenation of type and language name.
    9211              :          * This is only used for purposes of sorting.  If we fail to find
    9212              :          * either, the name will be an empty string.
    9213              :          */
    9214           52 :         initPQExpBuffer(&namebuf);
    9215           52 :         typeInfo = findTypeByOid(transforminfo[i].trftype);
    9216           52 :         lanname = get_language_name(fout, transforminfo[i].trflang);
    9217           52 :         if (typeInfo && lanname)
    9218           52 :             appendPQExpBuffer(&namebuf, "%s %s",
    9219              :                               typeInfo->dobj.name, lanname);
    9220           52 :         transforminfo[i].dobj.name = namebuf.data;
    9221           52 :         free(lanname);
    9222              : 
    9223              :         /* Decide whether we want to dump it */
    9224           52 :         selectDumpableObject(&(transforminfo[i].dobj), fout);
    9225              :     }
    9226              : 
    9227          249 :     PQclear(res);
    9228              : 
    9229          249 :     destroyPQExpBuffer(query);
    9230              : }
    9231              : 
    9232              : /*
    9233              :  * getTableAttrs -
    9234              :  *    for each interesting table, read info about its attributes
    9235              :  *    (names, types, default values, CHECK constraints, etc)
    9236              :  *
    9237              :  *  modifies tblinfo
    9238              :  */
    9239              : void
    9240          249 : getTableAttrs(Archive *fout, TableInfo *tblinfo, int numTables)
    9241              : {
    9242          249 :     DumpOptions *dopt = fout->dopt;
    9243          249 :     PQExpBuffer q = createPQExpBuffer();
    9244          249 :     PQExpBuffer tbloids = createPQExpBuffer();
    9245          249 :     PQExpBuffer checkoids = createPQExpBuffer();
    9246          249 :     PQExpBuffer invalidnotnulloids = NULL;
    9247              :     PGresult   *res;
    9248              :     int         ntups;
    9249              :     int         curtblindx;
    9250              :     int         i_attrelid;
    9251              :     int         i_attnum;
    9252              :     int         i_attname;
    9253              :     int         i_atttypname;
    9254              :     int         i_attstattarget;
    9255              :     int         i_attstorage;
    9256              :     int         i_typstorage;
    9257              :     int         i_attidentity;
    9258              :     int         i_attgenerated;
    9259              :     int         i_attisdropped;
    9260              :     int         i_attlen;
    9261              :     int         i_attalign;
    9262              :     int         i_attislocal;
    9263              :     int         i_notnull_name;
    9264              :     int         i_notnull_comment;
    9265              :     int         i_notnull_noinherit;
    9266              :     int         i_notnull_islocal;
    9267              :     int         i_notnull_invalidoid;
    9268              :     int         i_attoptions;
    9269              :     int         i_attcollation;
    9270              :     int         i_attcompression;
    9271              :     int         i_attfdwoptions;
    9272              :     int         i_attmissingval;
    9273              :     int         i_atthasdef;
    9274              : 
    9275              :     /*
    9276              :      * We want to perform just one query against pg_attribute, and then just
    9277              :      * one against pg_attrdef (for DEFAULTs) and two against pg_constraint
    9278              :      * (for CHECK constraints and for NOT NULL constraints).  However, we
    9279              :      * mustn't try to select every row of those catalogs and then sort it out
    9280              :      * on the client side, because some of the server-side functions we need
    9281              :      * would be unsafe to apply to tables we don't have lock on.  Hence, we
    9282              :      * build an array of the OIDs of tables we care about (and now have lock
    9283              :      * on!), and use a WHERE clause to constrain which rows are selected.
    9284              :      */
    9285          249 :     appendPQExpBufferChar(tbloids, '{');
    9286          249 :     appendPQExpBufferChar(checkoids, '{');
    9287        63065 :     for (int i = 0; i < numTables; i++)
    9288              :     {
    9289        62816 :         TableInfo  *tbinfo = &tblinfo[i];
    9290              : 
    9291              :         /* Don't bother to collect info for sequences */
    9292        62816 :         if (tbinfo->relkind == RELKIND_SEQUENCE)
    9293          646 :             continue;
    9294              : 
    9295              :         /*
    9296              :          * Don't bother with uninteresting tables, either.  For binary
    9297              :          * upgrades, this is bypassed for pg_largeobject_metadata and
    9298              :          * pg_shdepend so that the columns names are collected for the
    9299              :          * corresponding COPY commands.  Restoring the data for those catalogs
    9300              :          * is faster than restoring the equivalent set of large object
    9301              :          * commands.
    9302              :          */
    9303        62170 :         if (!tbinfo->interesting &&
    9304        55364 :             !(fout->dopt->binary_upgrade &&
    9305         8188 :               (tbinfo->dobj.catId.oid == LargeObjectMetadataRelationId ||
    9306         8150 :                tbinfo->dobj.catId.oid == SharedDependRelationId)))
    9307        55288 :             continue;
    9308              : 
    9309              :         /* OK, we need info for this table */
    9310         6882 :         if (tbloids->len > 1) /* do we have more than the '{'? */
    9311         6691 :             appendPQExpBufferChar(tbloids, ',');
    9312         6882 :         appendPQExpBuffer(tbloids, "%u", tbinfo->dobj.catId.oid);
    9313              : 
    9314         6882 :         if (tbinfo->ncheck > 0)
    9315              :         {
    9316              :             /* Also make a list of the ones with check constraints */
    9317          528 :             if (checkoids->len > 1) /* do we have more than the '{'? */
    9318          459 :                 appendPQExpBufferChar(checkoids, ',');
    9319          528 :             appendPQExpBuffer(checkoids, "%u", tbinfo->dobj.catId.oid);
    9320              :         }
    9321              :     }
    9322          249 :     appendPQExpBufferChar(tbloids, '}');
    9323          249 :     appendPQExpBufferChar(checkoids, '}');
    9324              : 
    9325              :     /*
    9326              :      * Find all the user attributes and their types.
    9327              :      *
    9328              :      * Since we only want to dump COLLATE clauses for attributes whose
    9329              :      * collation is different from their type's default, we use a CASE here to
    9330              :      * suppress uninteresting attcollations cheaply.
    9331              :      */
    9332          249 :     appendPQExpBufferStr(q,
    9333              :                          "SELECT\n"
    9334              :                          "a.attrelid,\n"
    9335              :                          "a.attnum,\n"
    9336              :                          "a.attname,\n"
    9337              :                          "a.attstattarget,\n"
    9338              :                          "a.attstorage,\n"
    9339              :                          "t.typstorage,\n"
    9340              :                          "a.atthasdef,\n"
    9341              :                          "a.attisdropped,\n"
    9342              :                          "a.attlen,\n"
    9343              :                          "a.attalign,\n"
    9344              :                          "a.attislocal,\n"
    9345              :                          "pg_catalog.format_type(t.oid, a.atttypmod) AS atttypname,\n"
    9346              :                          "array_to_string(a.attoptions, ', ') AS attoptions,\n"
    9347              :                          "CASE WHEN a.attcollation <> t.typcollation "
    9348              :                          "THEN a.attcollation ELSE 0 END AS attcollation,\n"
    9349              :                          "pg_catalog.array_to_string(ARRAY("
    9350              :                          "SELECT pg_catalog.quote_ident(option_name) || "
    9351              :                          "' ' || pg_catalog.quote_literal(option_value) "
    9352              :                          "FROM pg_catalog.pg_options_to_table(attfdwoptions) "
    9353              :                          "ORDER BY option_name"
    9354              :                          "), E',\n    ') AS attfdwoptions,\n");
    9355              : 
    9356              :     /*
    9357              :      * Find out any NOT NULL markings for each column.  In 18 and up we read
    9358              :      * pg_constraint to obtain the constraint name, and for valid constraints
    9359              :      * also pg_description to obtain its comment.  notnull_noinherit is set
    9360              :      * according to the NO INHERIT property.  For versions prior to 18, we
    9361              :      * store an empty string as the name when a constraint is marked as
    9362              :      * attnotnull (this cues dumpTableSchema to print the NOT NULL clause
    9363              :      * without a name); also, such cases are never NO INHERIT.
    9364              :      *
    9365              :      * For invalid constraints, we need to store their OIDs for processing
    9366              :      * elsewhere, so we bring the pg_constraint.oid value when the constraint
    9367              :      * is invalid, and NULL otherwise.  Their comments are handled not here
    9368              :      * but by collectComments, because they're their own dumpable object.
    9369              :      *
    9370              :      * We track in notnull_islocal whether the constraint was defined directly
    9371              :      * in this table or via an ancestor, for binary upgrade.  flagInhAttrs
    9372              :      * might modify this later.
    9373              :      */
    9374          249 :     if (fout->remoteVersion >= 180000)
    9375          249 :         appendPQExpBufferStr(q,
    9376              :                              "co.conname AS notnull_name,\n"
    9377              :                              "CASE WHEN co.convalidated THEN pt.description"
    9378              :                              " ELSE NULL END AS notnull_comment,\n"
    9379              :                              "CASE WHEN NOT co.convalidated THEN co.oid "
    9380              :                              "ELSE NULL END AS notnull_invalidoid,\n"
    9381              :                              "co.connoinherit AS notnull_noinherit,\n"
    9382              :                              "co.conislocal AS notnull_islocal,\n");
    9383              :     else
    9384            0 :         appendPQExpBufferStr(q,
    9385              :                              "CASE WHEN a.attnotnull THEN '' ELSE NULL END AS notnull_name,\n"
    9386              :                              "NULL AS notnull_comment,\n"
    9387              :                              "NULL AS notnull_invalidoid,\n"
    9388              :                              "false AS notnull_noinherit,\n"
    9389              :                              "CASE WHEN a.attislocal THEN true\n"
    9390              :                              "     WHEN a.attnotnull AND NOT a.attislocal THEN true\n"
    9391              :                              "     ELSE false\n"
    9392              :                              "END AS notnull_islocal,\n");
    9393              : 
    9394          249 :     if (fout->remoteVersion >= 140000)
    9395          249 :         appendPQExpBufferStr(q,
    9396              :                              "a.attcompression AS attcompression,\n");
    9397              :     else
    9398            0 :         appendPQExpBufferStr(q,
    9399              :                              "'' AS attcompression,\n");
    9400              : 
    9401          249 :     if (fout->remoteVersion >= 100000)
    9402          249 :         appendPQExpBufferStr(q,
    9403              :                              "a.attidentity,\n");
    9404              :     else
    9405            0 :         appendPQExpBufferStr(q,
    9406              :                              "'' AS attidentity,\n");
    9407              : 
    9408          249 :     if (fout->remoteVersion >= 110000)
    9409          249 :         appendPQExpBufferStr(q,
    9410              :                              "CASE WHEN a.atthasmissing AND NOT a.attisdropped "
    9411              :                              "THEN a.attmissingval ELSE null END AS attmissingval,\n");
    9412              :     else
    9413            0 :         appendPQExpBufferStr(q,
    9414              :                              "NULL AS attmissingval,\n");
    9415              : 
    9416          249 :     if (fout->remoteVersion >= 120000)
    9417          249 :         appendPQExpBufferStr(q,
    9418              :                              "a.attgenerated\n");
    9419              :     else
    9420            0 :         appendPQExpBufferStr(q,
    9421              :                              "'' AS attgenerated\n");
    9422              : 
    9423              :     /* need left join to pg_type to not fail on dropped columns ... */
    9424          249 :     appendPQExpBuffer(q,
    9425              :                       "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
    9426              :                       "JOIN pg_catalog.pg_attribute a ON (src.tbloid = a.attrelid) "
    9427              :                       "LEFT JOIN pg_catalog.pg_type t "
    9428              :                       "ON (a.atttypid = t.oid)\n",
    9429              :                       tbloids->data);
    9430              : 
    9431              :     /*
    9432              :      * In versions 18 and up, we need pg_constraint for explicit NOT NULL
    9433              :      * entries and pg_description to get their comments.
    9434              :      */
    9435          249 :     if (fout->remoteVersion >= 180000)
    9436          249 :         appendPQExpBufferStr(q,
    9437              :                              " LEFT JOIN pg_catalog.pg_constraint co ON "
    9438              :                              "(a.attrelid = co.conrelid\n"
    9439              :                              "   AND co.contype = 'n' AND "
    9440              :                              "co.conkey = array[a.attnum])\n"
    9441              :                              " LEFT JOIN pg_catalog.pg_description pt ON "
    9442              :                              "(pt.classoid = co.tableoid AND pt.objoid = co.oid)\n");
    9443              : 
    9444          249 :     appendPQExpBufferStr(q,
    9445              :                          "WHERE a.attnum > 0::pg_catalog.int2\n");
    9446              : 
    9447              :     /*
    9448              :      * For binary upgrades from <v12, be sure to pick up
    9449              :      * pg_largeobject_metadata's oid column.
    9450              :      */
    9451          249 :     if (fout->dopt->binary_upgrade && fout->remoteVersion < 120000)
    9452            0 :         appendPQExpBufferStr(q,
    9453              :                              "OR (a.attnum = -2::pg_catalog.int2 AND src.tbloid = "
    9454              :                              CppAsString2(LargeObjectMetadataRelationId) ")\n");
    9455              : 
    9456          249 :     appendPQExpBufferStr(q,
    9457              :                          "ORDER BY a.attrelid, a.attnum");
    9458              : 
    9459          249 :     res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
    9460              : 
    9461          249 :     ntups = PQntuples(res);
    9462              : 
    9463          249 :     i_attrelid = PQfnumber(res, "attrelid");
    9464          249 :     i_attnum = PQfnumber(res, "attnum");
    9465          249 :     i_attname = PQfnumber(res, "attname");
    9466          249 :     i_atttypname = PQfnumber(res, "atttypname");
    9467          249 :     i_attstattarget = PQfnumber(res, "attstattarget");
    9468          249 :     i_attstorage = PQfnumber(res, "attstorage");
    9469          249 :     i_typstorage = PQfnumber(res, "typstorage");
    9470          249 :     i_attidentity = PQfnumber(res, "attidentity");
    9471          249 :     i_attgenerated = PQfnumber(res, "attgenerated");
    9472          249 :     i_attisdropped = PQfnumber(res, "attisdropped");
    9473          249 :     i_attlen = PQfnumber(res, "attlen");
    9474          249 :     i_attalign = PQfnumber(res, "attalign");
    9475          249 :     i_attislocal = PQfnumber(res, "attislocal");
    9476          249 :     i_notnull_name = PQfnumber(res, "notnull_name");
    9477          249 :     i_notnull_comment = PQfnumber(res, "notnull_comment");
    9478          249 :     i_notnull_invalidoid = PQfnumber(res, "notnull_invalidoid");
    9479          249 :     i_notnull_noinherit = PQfnumber(res, "notnull_noinherit");
    9480          249 :     i_notnull_islocal = PQfnumber(res, "notnull_islocal");
    9481          249 :     i_attoptions = PQfnumber(res, "attoptions");
    9482          249 :     i_attcollation = PQfnumber(res, "attcollation");
    9483          249 :     i_attcompression = PQfnumber(res, "attcompression");
    9484          249 :     i_attfdwoptions = PQfnumber(res, "attfdwoptions");
    9485          249 :     i_attmissingval = PQfnumber(res, "attmissingval");
    9486          249 :     i_atthasdef = PQfnumber(res, "atthasdef");
    9487              : 
    9488              :     /* Within the next loop, we'll accumulate OIDs of tables with defaults */
    9489          249 :     resetPQExpBuffer(tbloids);
    9490          249 :     appendPQExpBufferChar(tbloids, '{');
    9491              : 
    9492              :     /*
    9493              :      * Outer loop iterates once per table, not once per row.  Incrementing of
    9494              :      * r is handled by the inner loop.
    9495              :      */
    9496          249 :     curtblindx = -1;
    9497         6993 :     for (int r = 0; r < ntups;)
    9498              :     {
    9499         6744 :         Oid         attrelid = atooid(PQgetvalue(res, r, i_attrelid));
    9500         6744 :         TableInfo  *tbinfo = NULL;
    9501              :         int         numatts;
    9502              :         bool        hasdefaults;
    9503              : 
    9504              :         /* Count rows for this table */
    9505        25127 :         for (numatts = 1; numatts < ntups - r; numatts++)
    9506        24939 :             if (atooid(PQgetvalue(res, r + numatts, i_attrelid)) != attrelid)
    9507         6556 :                 break;
    9508              : 
    9509              :         /*
    9510              :          * Locate the associated TableInfo; we rely on tblinfo[] being in OID
    9511              :          * order.
    9512              :          */
    9513        44470 :         while (++curtblindx < numTables)
    9514              :         {
    9515        44470 :             tbinfo = &tblinfo[curtblindx];
    9516        44470 :             if (tbinfo->dobj.catId.oid == attrelid)
    9517         6744 :                 break;
    9518              :         }
    9519         6744 :         if (curtblindx >= numTables)
    9520            0 :             pg_fatal("unrecognized table OID %u", attrelid);
    9521              :         /* cross-check that we only got requested tables */
    9522         6744 :         if (tbinfo->relkind == RELKIND_SEQUENCE ||
    9523         6744 :             (!tbinfo->interesting &&
    9524           76 :              !(fout->dopt->binary_upgrade &&
    9525           76 :                (tbinfo->dobj.catId.oid == LargeObjectMetadataRelationId ||
    9526           38 :                 tbinfo->dobj.catId.oid == SharedDependRelationId))))
    9527            0 :             pg_fatal("unexpected column data for table \"%s\"",
    9528              :                      tbinfo->dobj.name);
    9529              : 
    9530              :         /* Save data for this table */
    9531         6744 :         tbinfo->numatts = numatts;
    9532         6744 :         tbinfo->attnames = pg_malloc_array(char *, numatts);
    9533         6744 :         tbinfo->atttypnames = pg_malloc_array(char *, numatts);
    9534         6744 :         tbinfo->attstattarget = pg_malloc_array(int, numatts);
    9535         6744 :         tbinfo->attstorage = pg_malloc_array(char, numatts);
    9536         6744 :         tbinfo->typstorage = pg_malloc_array(char, numatts);
    9537         6744 :         tbinfo->attidentity = pg_malloc_array(char, numatts);
    9538         6744 :         tbinfo->attgenerated = pg_malloc_array(char, numatts);
    9539         6744 :         tbinfo->attisdropped = pg_malloc_array(bool, numatts);
    9540         6744 :         tbinfo->attlen = pg_malloc_array(int, numatts);
    9541         6744 :         tbinfo->attalign = pg_malloc_array(char, numatts);
    9542         6744 :         tbinfo->attislocal = pg_malloc_array(bool, numatts);
    9543         6744 :         tbinfo->attoptions = pg_malloc_array(char *, numatts);
    9544         6744 :         tbinfo->attcollation = pg_malloc_array(Oid, numatts);
    9545         6744 :         tbinfo->attcompression = pg_malloc_array(char, numatts);
    9546         6744 :         tbinfo->attfdwoptions = pg_malloc_array(char *, numatts);
    9547         6744 :         tbinfo->attmissingval = pg_malloc_array(char *, numatts);
    9548         6744 :         tbinfo->notnull_constrs = pg_malloc_array(char *, numatts);
    9549         6744 :         tbinfo->notnull_comment = pg_malloc_array(char *, numatts);
    9550         6744 :         tbinfo->notnull_invalid = pg_malloc_array(bool, numatts);
    9551         6744 :         tbinfo->notnull_noinh = pg_malloc_array(bool, numatts);
    9552         6744 :         tbinfo->notnull_islocal = pg_malloc_array(bool, numatts);
    9553         6744 :         tbinfo->attrdefs = pg_malloc_array(AttrDefInfo *, numatts);
    9554         6744 :         hasdefaults = false;
    9555              : 
    9556        31871 :         for (int j = 0; j < numatts; j++, r++)
    9557              :         {
    9558        25127 :             if (j + 1 != atoi(PQgetvalue(res, r, i_attnum)) &&
    9559            0 :                 !(fout->dopt->binary_upgrade && fout->remoteVersion < 120000 &&
    9560            0 :                   tbinfo->dobj.catId.oid == LargeObjectMetadataRelationId))
    9561            0 :                 pg_fatal("invalid column numbering in table \"%s\"",
    9562              :                          tbinfo->dobj.name);
    9563        25127 :             tbinfo->attnames[j] = pg_strdup(PQgetvalue(res, r, i_attname));
    9564        25127 :             tbinfo->atttypnames[j] = pg_strdup(PQgetvalue(res, r, i_atttypname));
    9565        25127 :             if (PQgetisnull(res, r, i_attstattarget))
    9566        25087 :                 tbinfo->attstattarget[j] = -1;
    9567              :             else
    9568           40 :                 tbinfo->attstattarget[j] = atoi(PQgetvalue(res, r, i_attstattarget));
    9569        25127 :             tbinfo->attstorage[j] = *(PQgetvalue(res, r, i_attstorage));
    9570        25127 :             tbinfo->typstorage[j] = *(PQgetvalue(res, r, i_typstorage));
    9571        25127 :             tbinfo->attidentity[j] = *(PQgetvalue(res, r, i_attidentity));
    9572        25127 :             tbinfo->attgenerated[j] = *(PQgetvalue(res, r, i_attgenerated));
    9573        25127 :             tbinfo->needs_override = tbinfo->needs_override || (tbinfo->attidentity[j] == ATTRIBUTE_IDENTITY_ALWAYS);
    9574        25127 :             tbinfo->attisdropped[j] = (PQgetvalue(res, r, i_attisdropped)[0] == 't');
    9575        25127 :             tbinfo->attlen[j] = atoi(PQgetvalue(res, r, i_attlen));
    9576        25127 :             tbinfo->attalign[j] = *(PQgetvalue(res, r, i_attalign));
    9577        25127 :             tbinfo->attislocal[j] = (PQgetvalue(res, r, i_attislocal)[0] == 't');
    9578              : 
    9579              :             /* Handle not-null constraint name and flags */
    9580        25127 :             determineNotNullFlags(fout, res, r,
    9581              :                                   tbinfo, j,
    9582              :                                   i_notnull_name,
    9583              :                                   i_notnull_comment,
    9584              :                                   i_notnull_invalidoid,
    9585              :                                   i_notnull_noinherit,
    9586              :                                   i_notnull_islocal,
    9587              :                                   &invalidnotnulloids);
    9588              : 
    9589        25127 :             tbinfo->notnull_comment[j] = PQgetisnull(res, r, i_notnull_comment) ?
    9590        25127 :                 NULL : pg_strdup(PQgetvalue(res, r, i_notnull_comment));
    9591        25127 :             tbinfo->attoptions[j] = pg_strdup(PQgetvalue(res, r, i_attoptions));
    9592        25127 :             tbinfo->attcollation[j] = atooid(PQgetvalue(res, r, i_attcollation));
    9593        25127 :             tbinfo->attcompression[j] = *(PQgetvalue(res, r, i_attcompression));
    9594        25127 :             tbinfo->attfdwoptions[j] = pg_strdup(PQgetvalue(res, r, i_attfdwoptions));
    9595        25127 :             tbinfo->attmissingval[j] = pg_strdup(PQgetvalue(res, r, i_attmissingval));
    9596        25127 :             tbinfo->attrdefs[j] = NULL; /* fix below */
    9597        25127 :             if (PQgetvalue(res, r, i_atthasdef)[0] == 't')
    9598         1273 :                 hasdefaults = true;
    9599              :         }
    9600              : 
    9601         6744 :         if (hasdefaults)
    9602              :         {
    9603              :             /* Collect OIDs of interesting tables that have defaults */
    9604          952 :             if (tbloids->len > 1) /* do we have more than the '{'? */
    9605          884 :                 appendPQExpBufferChar(tbloids, ',');
    9606          952 :             appendPQExpBuffer(tbloids, "%u", tbinfo->dobj.catId.oid);
    9607              :         }
    9608              :     }
    9609              : 
    9610              :     /* If invalidnotnulloids has any data, finalize it */
    9611          249 :     if (invalidnotnulloids != NULL)
    9612           43 :         appendPQExpBufferChar(invalidnotnulloids, '}');
    9613              : 
    9614          249 :     PQclear(res);
    9615              : 
    9616              :     /*
    9617              :      * Now get info about column defaults.  This is skipped for a data-only
    9618              :      * dump, as it is only needed for table schemas.
    9619              :      */
    9620          249 :     if (dopt->dumpSchema && tbloids->len > 1)
    9621              :     {
    9622              :         AttrDefInfo *attrdefs;
    9623              :         int         numDefaults;
    9624           60 :         TableInfo  *tbinfo = NULL;
    9625              : 
    9626           60 :         pg_log_info("finding table default expressions");
    9627              : 
    9628           60 :         appendPQExpBufferChar(tbloids, '}');
    9629              : 
    9630           60 :         printfPQExpBuffer(q, "SELECT a.tableoid, a.oid, adrelid, adnum, "
    9631              :                           "pg_catalog.pg_get_expr(adbin, adrelid) AS adsrc\n"
    9632              :                           "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
    9633              :                           "JOIN pg_catalog.pg_attrdef a ON (src.tbloid = a.adrelid)\n"
    9634              :                           "ORDER BY a.adrelid, a.adnum",
    9635              :                           tbloids->data);
    9636              : 
    9637           60 :         res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
    9638              : 
    9639           60 :         numDefaults = PQntuples(res);
    9640           60 :         attrdefs = pg_malloc_array(AttrDefInfo, numDefaults);
    9641              : 
    9642           60 :         curtblindx = -1;
    9643         1235 :         for (int j = 0; j < numDefaults; j++)
    9644              :         {
    9645         1175 :             Oid         adtableoid = atooid(PQgetvalue(res, j, 0));
    9646         1175 :             Oid         adoid = atooid(PQgetvalue(res, j, 1));
    9647         1175 :             Oid         adrelid = atooid(PQgetvalue(res, j, 2));
    9648         1175 :             int         adnum = atoi(PQgetvalue(res, j, 3));
    9649         1175 :             char       *adsrc = PQgetvalue(res, j, 4);
    9650              : 
    9651              :             /*
    9652              :              * Locate the associated TableInfo; we rely on tblinfo[] being in
    9653              :              * OID order.
    9654              :              */
    9655         1175 :             if (tbinfo == NULL || tbinfo->dobj.catId.oid != adrelid)
    9656              :             {
    9657        18725 :                 while (++curtblindx < numTables)
    9658              :                 {
    9659        18725 :                     tbinfo = &tblinfo[curtblindx];
    9660        18725 :                     if (tbinfo->dobj.catId.oid == adrelid)
    9661          884 :                         break;
    9662              :                 }
    9663          884 :                 if (curtblindx >= numTables)
    9664            0 :                     pg_fatal("unrecognized table OID %u", adrelid);
    9665              :             }
    9666              : 
    9667         1175 :             if (adnum <= 0 || adnum > tbinfo->numatts)
    9668            0 :                 pg_fatal("invalid adnum value %d for table \"%s\"",
    9669              :                          adnum, tbinfo->dobj.name);
    9670              : 
    9671              :             /*
    9672              :              * dropped columns shouldn't have defaults, but just in case,
    9673              :              * ignore 'em
    9674              :              */
    9675         1175 :             if (tbinfo->attisdropped[adnum - 1])
    9676            0 :                 continue;
    9677              : 
    9678         1175 :             attrdefs[j].dobj.objType = DO_ATTRDEF;
    9679         1175 :             attrdefs[j].dobj.catId.tableoid = adtableoid;
    9680         1175 :             attrdefs[j].dobj.catId.oid = adoid;
    9681         1175 :             AssignDumpId(&attrdefs[j].dobj);
    9682         1175 :             attrdefs[j].adtable = tbinfo;
    9683         1175 :             attrdefs[j].adnum = adnum;
    9684         1175 :             attrdefs[j].adef_expr = pg_strdup(adsrc);
    9685              : 
    9686         1175 :             attrdefs[j].dobj.name = pg_strdup(tbinfo->dobj.name);
    9687         1175 :             attrdefs[j].dobj.namespace = tbinfo->dobj.namespace;
    9688              : 
    9689         1175 :             attrdefs[j].dobj.dump = tbinfo->dobj.dump;
    9690              : 
    9691              :             /*
    9692              :              * Figure out whether the default/generation expression should be
    9693              :              * dumped as part of the main CREATE TABLE (or similar) command or
    9694              :              * as a separate ALTER TABLE (or similar) command. The preference
    9695              :              * is to put it into the CREATE command, but in some cases that's
    9696              :              * not possible.
    9697              :              */
    9698         1175 :             if (tbinfo->attgenerated[adnum - 1])
    9699              :             {
    9700              :                 /*
    9701              :                  * Column generation expressions cannot be dumped separately,
    9702              :                  * because there is no syntax for it.  By setting separate to
    9703              :                  * false here we prevent the "default" from being processed as
    9704              :                  * its own dumpable object.  Later, flagInhAttrs() will mark
    9705              :                  * it as not to be dumped at all, if possible (that is, if it
    9706              :                  * can be inherited from a parent).
    9707              :                  */
    9708          656 :                 attrdefs[j].separate = false;
    9709              :             }
    9710          519 :             else if (tbinfo->relkind == RELKIND_VIEW)
    9711              :             {
    9712              :                 /*
    9713              :                  * Defaults on a VIEW must always be dumped as separate ALTER
    9714              :                  * TABLE commands.
    9715              :                  */
    9716           32 :                 attrdefs[j].separate = true;
    9717              :             }
    9718          487 :             else if (!shouldPrintColumn(dopt, tbinfo, adnum - 1))
    9719              :             {
    9720              :                 /* column will be suppressed, print default separately */
    9721            4 :                 attrdefs[j].separate = true;
    9722              :             }
    9723              :             else
    9724              :             {
    9725          483 :                 attrdefs[j].separate = false;
    9726              :             }
    9727              : 
    9728         1175 :             if (!attrdefs[j].separate)
    9729              :             {
    9730              :                 /*
    9731              :                  * Mark the default as needing to appear before the table, so
    9732              :                  * that any dependencies it has must be emitted before the
    9733              :                  * CREATE TABLE.  If this is not possible, we'll change to
    9734              :                  * "separate" mode while sorting dependencies.
    9735              :                  */
    9736         1139 :                 addObjectDependency(&tbinfo->dobj,
    9737         1139 :                                     attrdefs[j].dobj.dumpId);
    9738              :             }
    9739              : 
    9740         1175 :             tbinfo->attrdefs[adnum - 1] = &attrdefs[j];
    9741              :         }
    9742              : 
    9743           60 :         PQclear(res);
    9744              :     }
    9745              : 
    9746              :     /*
    9747              :      * Get info about NOT NULL NOT VALID constraints.  This is skipped for a
    9748              :      * data-only dump, as it is only needed for table schemas.
    9749              :      */
    9750          249 :     if (dopt->dumpSchema && invalidnotnulloids)
    9751              :     {
    9752              :         ConstraintInfo *constrs;
    9753              :         int         numConstrs;
    9754              :         int         i_tableoid;
    9755              :         int         i_oid;
    9756              :         int         i_conrelid;
    9757              :         int         i_conname;
    9758              :         int         i_consrc;
    9759              :         int         i_conislocal;
    9760              : 
    9761           37 :         pg_log_info("finding invalid not-null constraints");
    9762              : 
    9763           37 :         resetPQExpBuffer(q);
    9764           37 :         appendPQExpBuffer(q,
    9765              :                           "SELECT c.tableoid, c.oid, conrelid, conname, "
    9766              :                           "pg_catalog.pg_get_constraintdef(c.oid) AS consrc, "
    9767              :                           "conislocal, convalidated "
    9768              :                           "FROM unnest('%s'::pg_catalog.oid[]) AS src(conoid)\n"
    9769              :                           "JOIN pg_catalog.pg_constraint c ON (src.conoid = c.oid)\n"
    9770              :                           "ORDER BY c.conrelid, c.conname",
    9771           37 :                           invalidnotnulloids->data);
    9772              : 
    9773           37 :         res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
    9774              : 
    9775           37 :         numConstrs = PQntuples(res);
    9776           37 :         constrs = pg_malloc_array(ConstraintInfo, numConstrs);
    9777              : 
    9778           37 :         i_tableoid = PQfnumber(res, "tableoid");
    9779           37 :         i_oid = PQfnumber(res, "oid");
    9780           37 :         i_conrelid = PQfnumber(res, "conrelid");
    9781           37 :         i_conname = PQfnumber(res, "conname");
    9782           37 :         i_consrc = PQfnumber(res, "consrc");
    9783           37 :         i_conislocal = PQfnumber(res, "conislocal");
    9784              : 
    9785              :         /* As above, this loop iterates once per table, not once per row */
    9786           37 :         curtblindx = -1;
    9787          104 :         for (int j = 0; j < numConstrs;)
    9788              :         {
    9789           67 :             Oid         conrelid = atooid(PQgetvalue(res, j, i_conrelid));
    9790           67 :             TableInfo  *tbinfo = NULL;
    9791              :             int         numcons;
    9792              : 
    9793              :             /* Count rows for this table */
    9794           67 :             for (numcons = 1; numcons < numConstrs - j; numcons++)
    9795           30 :                 if (atooid(PQgetvalue(res, j + numcons, i_conrelid)) != conrelid)
    9796           30 :                     break;
    9797              : 
    9798              :             /*
    9799              :              * Locate the associated TableInfo; we rely on tblinfo[] being in
    9800              :              * OID order.
    9801              :              */
    9802        12788 :             while (++curtblindx < numTables)
    9803              :             {
    9804        12788 :                 tbinfo = &tblinfo[curtblindx];
    9805        12788 :                 if (tbinfo->dobj.catId.oid == conrelid)
    9806           67 :                     break;
    9807              :             }
    9808           67 :             if (curtblindx >= numTables)
    9809            0 :                 pg_fatal("unrecognized table OID %u", conrelid);
    9810              : 
    9811          134 :             for (int c = 0; c < numcons; c++, j++)
    9812              :             {
    9813           67 :                 constrs[j].dobj.objType = DO_CONSTRAINT;
    9814           67 :                 constrs[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
    9815           67 :                 constrs[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
    9816           67 :                 AssignDumpId(&constrs[j].dobj);
    9817           67 :                 constrs[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_conname));
    9818           67 :                 constrs[j].dobj.namespace = tbinfo->dobj.namespace;
    9819           67 :                 constrs[j].contable = tbinfo;
    9820           67 :                 constrs[j].condomain = NULL;
    9821           67 :                 constrs[j].contype = 'n';
    9822           67 :                 constrs[j].condef = pg_strdup(PQgetvalue(res, j, i_consrc));
    9823           67 :                 constrs[j].confrelid = InvalidOid;
    9824           67 :                 constrs[j].conindex = 0;
    9825           67 :                 constrs[j].condeferrable = false;
    9826           67 :                 constrs[j].condeferred = false;
    9827           67 :                 constrs[j].conislocal = (PQgetvalue(res, j, i_conislocal)[0] == 't');
    9828              : 
    9829              :                 /*
    9830              :                  * All invalid not-null constraints must be dumped separately,
    9831              :                  * because CREATE TABLE would not create them as invalid, and
    9832              :                  * also because they must be created after potentially
    9833              :                  * violating data has been loaded.
    9834              :                  */
    9835           67 :                 constrs[j].separate = true;
    9836              : 
    9837           67 :                 constrs[j].dobj.dump = tbinfo->dobj.dump;
    9838              :             }
    9839              :         }
    9840           37 :         PQclear(res);
    9841              :     }
    9842              : 
    9843              :     /*
    9844              :      * Get info about table CHECK constraints.  This is skipped for a
    9845              :      * data-only dump, as it is only needed for table schemas.
    9846              :      */
    9847          249 :     if (dopt->dumpSchema && checkoids->len > 2)
    9848              :     {
    9849              :         ConstraintInfo *constrs;
    9850              :         int         numConstrs;
    9851              :         int         i_tableoid;
    9852              :         int         i_oid;
    9853              :         int         i_conrelid;
    9854              :         int         i_conname;
    9855              :         int         i_consrc;
    9856              :         int         i_conislocal;
    9857              :         int         i_convalidated;
    9858              : 
    9859           61 :         pg_log_info("finding table check constraints");
    9860              : 
    9861           61 :         resetPQExpBuffer(q);
    9862           61 :         appendPQExpBuffer(q,
    9863              :                           "SELECT c.tableoid, c.oid, conrelid, conname, "
    9864              :                           "pg_catalog.pg_get_constraintdef(c.oid) AS consrc, "
    9865              :                           "conislocal, convalidated "
    9866              :                           "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
    9867              :                           "JOIN pg_catalog.pg_constraint c ON (src.tbloid = c.conrelid)\n"
    9868              :                           "WHERE contype = 'c' "
    9869              :                           "ORDER BY c.conrelid, c.conname",
    9870              :                           checkoids->data);
    9871              : 
    9872           61 :         res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
    9873              : 
    9874           61 :         numConstrs = PQntuples(res);
    9875           61 :         constrs = pg_malloc_array(ConstraintInfo, numConstrs);
    9876              : 
    9877           61 :         i_tableoid = PQfnumber(res, "tableoid");
    9878           61 :         i_oid = PQfnumber(res, "oid");
    9879           61 :         i_conrelid = PQfnumber(res, "conrelid");
    9880           61 :         i_conname = PQfnumber(res, "conname");
    9881           61 :         i_consrc = PQfnumber(res, "consrc");
    9882           61 :         i_conislocal = PQfnumber(res, "conislocal");
    9883           61 :         i_convalidated = PQfnumber(res, "convalidated");
    9884              : 
    9885              :         /* As above, this loop iterates once per table, not once per row */
    9886           61 :         curtblindx = -1;
    9887          538 :         for (int j = 0; j < numConstrs;)
    9888              :         {
    9889          477 :             Oid         conrelid = atooid(PQgetvalue(res, j, i_conrelid));
    9890          477 :             TableInfo  *tbinfo = NULL;
    9891              :             int         numcons;
    9892              : 
    9893              :             /* Count rows for this table */
    9894          612 :             for (numcons = 1; numcons < numConstrs - j; numcons++)
    9895          551 :                 if (atooid(PQgetvalue(res, j + numcons, i_conrelid)) != conrelid)
    9896          416 :                     break;
    9897              : 
    9898              :             /*
    9899              :              * Locate the associated TableInfo; we rely on tblinfo[] being in
    9900              :              * OID order.
    9901              :              */
    9902        18034 :             while (++curtblindx < numTables)
    9903              :             {
    9904        18034 :                 tbinfo = &tblinfo[curtblindx];
    9905        18034 :                 if (tbinfo->dobj.catId.oid == conrelid)
    9906          477 :                     break;
    9907              :             }
    9908          477 :             if (curtblindx >= numTables)
    9909            0 :                 pg_fatal("unrecognized table OID %u", conrelid);
    9910              : 
    9911          477 :             if (numcons != tbinfo->ncheck)
    9912              :             {
    9913            0 :                 pg_log_error(ngettext("expected %d check constraint on table \"%s\" but found %d",
    9914              :                                       "expected %d check constraints on table \"%s\" but found %d",
    9915              :                                       tbinfo->ncheck),
    9916              :                              tbinfo->ncheck, tbinfo->dobj.name, numcons);
    9917            0 :                 pg_log_error_hint("The system catalogs might be corrupted.");
    9918            0 :                 exit_nicely(1);
    9919              :             }
    9920              : 
    9921          477 :             tbinfo->checkexprs = constrs + j;
    9922              : 
    9923         1089 :             for (int c = 0; c < numcons; c++, j++)
    9924              :             {
    9925          612 :                 bool        validated = PQgetvalue(res, j, i_convalidated)[0] == 't';
    9926              : 
    9927          612 :                 constrs[j].dobj.objType = DO_CONSTRAINT;
    9928          612 :                 constrs[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
    9929          612 :                 constrs[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
    9930          612 :                 AssignDumpId(&constrs[j].dobj);
    9931          612 :                 constrs[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_conname));
    9932          612 :                 constrs[j].dobj.namespace = tbinfo->dobj.namespace;
    9933          612 :                 constrs[j].contable = tbinfo;
    9934          612 :                 constrs[j].condomain = NULL;
    9935          612 :                 constrs[j].contype = 'c';
    9936          612 :                 constrs[j].condef = pg_strdup(PQgetvalue(res, j, i_consrc));
    9937          612 :                 constrs[j].confrelid = InvalidOid;
    9938          612 :                 constrs[j].conindex = 0;
    9939          612 :                 constrs[j].condeferrable = false;
    9940          612 :                 constrs[j].condeferred = false;
    9941          612 :                 constrs[j].conislocal = (PQgetvalue(res, j, i_conislocal)[0] == 't');
    9942              : 
    9943              :                 /*
    9944              :                  * An unvalidated constraint needs to be dumped separately, so
    9945              :                  * that potentially-violating existing data is loaded before
    9946              :                  * the constraint.
    9947              :                  */
    9948          612 :                 constrs[j].separate = !validated;
    9949              : 
    9950          612 :                 constrs[j].dobj.dump = tbinfo->dobj.dump;
    9951              : 
    9952              :                 /*
    9953              :                  * Mark the constraint as needing to appear before the table
    9954              :                  * --- this is so that any other dependencies of the
    9955              :                  * constraint will be emitted before we try to create the
    9956              :                  * table.  If the constraint is to be dumped separately, it
    9957              :                  * will be dumped after data is loaded anyway, so don't do it.
    9958              :                  * (There's an automatic dependency in the opposite direction
    9959              :                  * anyway, so don't need to add one manually here.)
    9960              :                  */
    9961          612 :                 if (!constrs[j].separate)
    9962          547 :                     addObjectDependency(&tbinfo->dobj,
    9963          547 :                                         constrs[j].dobj.dumpId);
    9964              : 
    9965              :                 /*
    9966              :                  * We will detect later whether the constraint must be split
    9967              :                  * out from the table definition.
    9968              :                  */
    9969              :             }
    9970              :         }
    9971              : 
    9972           61 :         PQclear(res);
    9973              :     }
    9974              : 
    9975          249 :     destroyPQExpBuffer(q);
    9976          249 :     destroyPQExpBuffer(tbloids);
    9977          249 :     destroyPQExpBuffer(checkoids);
    9978          249 : }
    9979              : 
    9980              : /*
    9981              :  * Based on the getTableAttrs query's row corresponding to one column, set
    9982              :  * the name and flags to handle a not-null constraint for that column in
    9983              :  * the tbinfo struct.
    9984              :  *
    9985              :  * Result row 'r' is for tbinfo's attribute 'j'.
    9986              :  *
    9987              :  * There are four possibilities:
    9988              :  * 1) the column has no not-null constraints. In that case, ->notnull_constrs
    9989              :  *    (the constraint name) remains NULL.
    9990              :  * 2) The column has a constraint with no name (this is the case when
    9991              :  *    constraints come from pre-18 servers).  In this case, ->notnull_constrs
    9992              :  *    is set to the empty string; dumpTableSchema will print just "NOT NULL".
    9993              :  * 3) The column has an invalid not-null constraint.  This must be treated
    9994              :  *    as a separate object (because it must be created after the table data
    9995              :  *    is loaded).  So we add its OID to invalidnotnulloids for processing
    9996              :  *    elsewhere and do nothing further with it here.  We distinguish this
    9997              :  *    case because the "notnull_invalidoid" column has been set to a non-NULL
    9998              :  *    value, which is the constraint OID.  Valid constraints have a null OID.
    9999              :  * 4) The column has a constraint with a known name; in that case
   10000              :  *    notnull_constrs carries that name and dumpTableSchema will print
   10001              :  *    "CONSTRAINT the_name NOT NULL".  However, if the name is the default
   10002              :  *    (table_column_not_null) and there's no comment on the constraint,
   10003              :  *    there's no need to print that name in the dump, so notnull_constrs
   10004              :  *    is set to the empty string and it behaves as case 2.
   10005              :  *
   10006              :  * In a child table that inherits from a parent already containing NOT NULL
   10007              :  * constraints and the columns in the child don't have their own NOT NULL
   10008              :  * declarations, we suppress printing constraints in the child: the
   10009              :  * constraints are acquired at the point where the child is attached to the
   10010              :  * parent.  This is tracked in ->notnull_islocal; for servers pre-18 this is
   10011              :  * set not here but in flagInhAttrs.  That flag is also used when the
   10012              :  * constraint was validated in a child but all its parent have it as NOT
   10013              :  * VALID.
   10014              :  *
   10015              :  * Any of these constraints might have the NO INHERIT bit.  If so we set
   10016              :  * ->notnull_noinh and NO INHERIT will be printed by dumpTableSchema.
   10017              :  *
   10018              :  * In case 4 above, the name comparison is a bit of a hack; it actually fails
   10019              :  * to do the right thing in all but the trivial case.  However, the downside
   10020              :  * of getting it wrong is simply that the name is printed rather than
   10021              :  * suppressed, so it's not a big deal.
   10022              :  *
   10023              :  * invalidnotnulloids is expected to be given as NULL; if any invalid not-null
   10024              :  * constraints are found, it is initialized and filled with the array of
   10025              :  * OIDs of such constraints, for later processing.
   10026              :  */
   10027              : static void
   10028        25127 : determineNotNullFlags(Archive *fout, PGresult *res, int r,
   10029              :                       TableInfo *tbinfo, int j,
   10030              :                       int i_notnull_name,
   10031              :                       int i_notnull_comment,
   10032              :                       int i_notnull_invalidoid,
   10033              :                       int i_notnull_noinherit,
   10034              :                       int i_notnull_islocal,
   10035              :                       PQExpBuffer *invalidnotnulloids)
   10036              : {
   10037        25127 :     DumpOptions *dopt = fout->dopt;
   10038              : 
   10039              :     /*
   10040              :      * If this not-null constraint is not valid, list its OID in
   10041              :      * invalidnotnulloids and do nothing further.  It'll be processed
   10042              :      * elsewhere later.
   10043              :      *
   10044              :      * Because invalid not-null constraints are rare, we don't want to malloc
   10045              :      * invalidnotnulloids until we're sure we're going it need it, which
   10046              :      * happens here.
   10047              :      */
   10048        25127 :     if (!PQgetisnull(res, r, i_notnull_invalidoid))
   10049              :     {
   10050           73 :         char       *constroid = PQgetvalue(res, r, i_notnull_invalidoid);
   10051              : 
   10052           73 :         if (*invalidnotnulloids == NULL)
   10053              :         {
   10054           43 :             *invalidnotnulloids = createPQExpBuffer();
   10055           43 :             appendPQExpBufferChar(*invalidnotnulloids, '{');
   10056           43 :             appendPQExpBufferStr(*invalidnotnulloids, constroid);
   10057              :         }
   10058              :         else
   10059           30 :             appendPQExpBuffer(*invalidnotnulloids, ",%s", constroid);
   10060              : 
   10061              :         /*
   10062              :          * Track when a parent constraint is invalid for the cases where a
   10063              :          * child constraint has been validated independenly.
   10064              :          */
   10065           73 :         tbinfo->notnull_invalid[j] = true;
   10066              : 
   10067              :         /* nothing else to do */
   10068           73 :         tbinfo->notnull_constrs[j] = NULL;
   10069           73 :         return;
   10070              :     }
   10071              : 
   10072              :     /*
   10073              :      * notnull_noinh is straight from the query result. notnull_islocal also,
   10074              :      * though flagInhAttrs may change that one later.
   10075              :      */
   10076        25054 :     tbinfo->notnull_noinh[j] = PQgetvalue(res, r, i_notnull_noinherit)[0] == 't';
   10077        25054 :     tbinfo->notnull_islocal[j] = PQgetvalue(res, r, i_notnull_islocal)[0] == 't';
   10078        25054 :     tbinfo->notnull_invalid[j] = false;
   10079              : 
   10080              :     /*
   10081              :      * Determine a constraint name to use.  If the column is not marked not-
   10082              :      * null, we set NULL which cues ... to do nothing.  An empty string says
   10083              :      * to print an unnamed NOT NULL, and anything else is a constraint name to
   10084              :      * use.
   10085              :      */
   10086        25054 :     if (fout->remoteVersion < 180000)
   10087              :     {
   10088              :         /*
   10089              :          * < 18 doesn't have not-null names, so an unnamed constraint is
   10090              :          * sufficient.
   10091              :          */
   10092            0 :         if (PQgetisnull(res, r, i_notnull_name))
   10093            0 :             tbinfo->notnull_constrs[j] = NULL;
   10094              :         else
   10095            0 :             tbinfo->notnull_constrs[j] = "";
   10096              :     }
   10097              :     else
   10098              :     {
   10099        25054 :         if (PQgetisnull(res, r, i_notnull_name))
   10100        22353 :             tbinfo->notnull_constrs[j] = NULL;
   10101              :         else
   10102              :         {
   10103              :             /*
   10104              :              * In binary upgrade of inheritance child tables, must have a
   10105              :              * constraint name that we can UPDATE later; same if there's a
   10106              :              * comment on the constraint.
   10107              :              */
   10108         2701 :             if ((dopt->binary_upgrade &&
   10109          335 :                  !tbinfo->ispartition &&
   10110         2956 :                  !tbinfo->notnull_islocal) ||
   10111         2701 :                 !PQgetisnull(res, r, i_notnull_comment))
   10112              :             {
   10113           48 :                 tbinfo->notnull_constrs[j] =
   10114           48 :                     pstrdup(PQgetvalue(res, r, i_notnull_name));
   10115              :             }
   10116              :             else
   10117              :             {
   10118              :                 char       *default_name;
   10119              : 
   10120              :                 /* XXX should match ChooseConstraintName better */
   10121         2653 :                 default_name = psprintf("%s_%s_not_null", tbinfo->dobj.name,
   10122         2653 :                                         tbinfo->attnames[j]);
   10123         2653 :                 if (strcmp(default_name,
   10124         2653 :                            PQgetvalue(res, r, i_notnull_name)) == 0)
   10125         1741 :                     tbinfo->notnull_constrs[j] = "";
   10126              :                 else
   10127              :                 {
   10128          912 :                     tbinfo->notnull_constrs[j] =
   10129          912 :                         pstrdup(PQgetvalue(res, r, i_notnull_name));
   10130              :                 }
   10131         2653 :                 free(default_name);
   10132              :             }
   10133              :         }
   10134              :     }
   10135              : }
   10136              : 
   10137              : /*
   10138              :  * Test whether a column should be printed as part of table's CREATE TABLE.
   10139              :  * Column number is zero-based.
   10140              :  *
   10141              :  * Normally this is always true, but it's false for dropped columns, as well
   10142              :  * as those that were inherited without any local definition.  (If we print
   10143              :  * such a column it will mistakenly get pg_attribute.attislocal set to true.)
   10144              :  * For partitions, it's always true, because we want the partitions to be
   10145              :  * created independently and ATTACH PARTITION used afterwards.
   10146              :  *
   10147              :  * In binary_upgrade mode, we must print all columns and fix the attislocal/
   10148              :  * attisdropped state later, so as to keep control of the physical column
   10149              :  * order.
   10150              :  *
   10151              :  * This function exists because there are scattered nonobvious places that
   10152              :  * must be kept in sync with this decision.
   10153              :  */
   10154              : bool
   10155        40829 : shouldPrintColumn(const DumpOptions *dopt, const TableInfo *tbinfo, int colno)
   10156              : {
   10157        40829 :     if (dopt->binary_upgrade)
   10158         6243 :         return true;
   10159        34586 :     if (tbinfo->attisdropped[colno])
   10160          726 :         return false;
   10161        33860 :     return (tbinfo->attislocal[colno] || tbinfo->ispartition);
   10162              : }
   10163              : 
   10164              : 
   10165              : /*
   10166              :  * getTSParsers:
   10167              :  *    get information about all text search parsers in the system catalogs
   10168              :  */
   10169              : void
   10170          249 : getTSParsers(Archive *fout)
   10171              : {
   10172              :     PGresult   *res;
   10173              :     int         ntups;
   10174              :     int         i;
   10175              :     PQExpBuffer query;
   10176              :     TSParserInfo *prsinfo;
   10177              :     int         i_tableoid;
   10178              :     int         i_oid;
   10179              :     int         i_prsname;
   10180              :     int         i_prsnamespace;
   10181              :     int         i_prsstart;
   10182              :     int         i_prstoken;
   10183              :     int         i_prsend;
   10184              :     int         i_prsheadline;
   10185              :     int         i_prslextype;
   10186              : 
   10187          249 :     query = createPQExpBuffer();
   10188              : 
   10189              :     /*
   10190              :      * find all text search objects, including builtin ones; we filter out
   10191              :      * system-defined objects at dump-out time.
   10192              :      */
   10193              : 
   10194          249 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, prsname, prsnamespace, "
   10195              :                          "prsstart::oid, prstoken::oid, "
   10196              :                          "prsend::oid, prsheadline::oid, prslextype::oid "
   10197              :                          "FROM pg_ts_parser");
   10198              : 
   10199          249 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   10200              : 
   10201          249 :     ntups = PQntuples(res);
   10202              : 
   10203          249 :     prsinfo = pg_malloc_array(TSParserInfo, ntups);
   10204              : 
   10205          249 :     i_tableoid = PQfnumber(res, "tableoid");
   10206          249 :     i_oid = PQfnumber(res, "oid");
   10207          249 :     i_prsname = PQfnumber(res, "prsname");
   10208          249 :     i_prsnamespace = PQfnumber(res, "prsnamespace");
   10209          249 :     i_prsstart = PQfnumber(res, "prsstart");
   10210          249 :     i_prstoken = PQfnumber(res, "prstoken");
   10211          249 :     i_prsend = PQfnumber(res, "prsend");
   10212          249 :     i_prsheadline = PQfnumber(res, "prsheadline");
   10213          249 :     i_prslextype = PQfnumber(res, "prslextype");
   10214              : 
   10215          543 :     for (i = 0; i < ntups; i++)
   10216              :     {
   10217          294 :         prsinfo[i].dobj.objType = DO_TSPARSER;
   10218          294 :         prsinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
   10219          294 :         prsinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
   10220          294 :         AssignDumpId(&prsinfo[i].dobj);
   10221          294 :         prsinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_prsname));
   10222          588 :         prsinfo[i].dobj.namespace =
   10223          294 :             findNamespace(atooid(PQgetvalue(res, i, i_prsnamespace)));
   10224          294 :         prsinfo[i].prsstart = atooid(PQgetvalue(res, i, i_prsstart));
   10225          294 :         prsinfo[i].prstoken = atooid(PQgetvalue(res, i, i_prstoken));
   10226          294 :         prsinfo[i].prsend = atooid(PQgetvalue(res, i, i_prsend));
   10227          294 :         prsinfo[i].prsheadline = atooid(PQgetvalue(res, i, i_prsheadline));
   10228          294 :         prsinfo[i].prslextype = atooid(PQgetvalue(res, i, i_prslextype));
   10229              : 
   10230              :         /* Decide whether we want to dump it */
   10231          294 :         selectDumpableObject(&(prsinfo[i].dobj), fout);
   10232              :     }
   10233              : 
   10234          249 :     PQclear(res);
   10235              : 
   10236          249 :     destroyPQExpBuffer(query);
   10237          249 : }
   10238              : 
   10239              : /*
   10240              :  * getTSDictionaries:
   10241              :  *    get information about all text search dictionaries in the system catalogs
   10242              :  */
   10243              : void
   10244          249 : getTSDictionaries(Archive *fout)
   10245              : {
   10246              :     PGresult   *res;
   10247              :     int         ntups;
   10248              :     int         i;
   10249              :     PQExpBuffer query;
   10250              :     TSDictInfo *dictinfo;
   10251              :     int         i_tableoid;
   10252              :     int         i_oid;
   10253              :     int         i_dictname;
   10254              :     int         i_dictnamespace;
   10255              :     int         i_dictowner;
   10256              :     int         i_dicttemplate;
   10257              :     int         i_dictinitoption;
   10258              : 
   10259          249 :     query = createPQExpBuffer();
   10260              : 
   10261          249 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, dictname, "
   10262              :                          "dictnamespace, dictowner, "
   10263              :                          "dicttemplate, dictinitoption "
   10264              :                          "FROM pg_ts_dict");
   10265              : 
   10266          249 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   10267              : 
   10268          249 :     ntups = PQntuples(res);
   10269              : 
   10270          249 :     dictinfo = pg_malloc_array(TSDictInfo, ntups);
   10271              : 
   10272          249 :     i_tableoid = PQfnumber(res, "tableoid");
   10273          249 :     i_oid = PQfnumber(res, "oid");
   10274          249 :     i_dictname = PQfnumber(res, "dictname");
   10275          249 :     i_dictnamespace = PQfnumber(res, "dictnamespace");
   10276          249 :     i_dictowner = PQfnumber(res, "dictowner");
   10277          249 :     i_dictinitoption = PQfnumber(res, "dictinitoption");
   10278          249 :     i_dicttemplate = PQfnumber(res, "dicttemplate");
   10279              : 
   10280         8325 :     for (i = 0; i < ntups; i++)
   10281              :     {
   10282         8076 :         dictinfo[i].dobj.objType = DO_TSDICT;
   10283         8076 :         dictinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
   10284         8076 :         dictinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
   10285         8076 :         AssignDumpId(&dictinfo[i].dobj);
   10286         8076 :         dictinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_dictname));
   10287        16152 :         dictinfo[i].dobj.namespace =
   10288         8076 :             findNamespace(atooid(PQgetvalue(res, i, i_dictnamespace)));
   10289         8076 :         dictinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_dictowner));
   10290         8076 :         dictinfo[i].dicttemplate = atooid(PQgetvalue(res, i, i_dicttemplate));
   10291         8076 :         if (PQgetisnull(res, i, i_dictinitoption))
   10292          294 :             dictinfo[i].dictinitoption = NULL;
   10293              :         else
   10294         7782 :             dictinfo[i].dictinitoption = pg_strdup(PQgetvalue(res, i, i_dictinitoption));
   10295              : 
   10296              :         /* Decide whether we want to dump it */
   10297         8076 :         selectDumpableObject(&(dictinfo[i].dobj), fout);
   10298              :     }
   10299              : 
   10300          249 :     PQclear(res);
   10301              : 
   10302          249 :     destroyPQExpBuffer(query);
   10303          249 : }
   10304              : 
   10305              : /*
   10306              :  * getTSTemplates:
   10307              :  *    get information about all text search templates in the system catalogs
   10308              :  */
   10309              : void
   10310          249 : getTSTemplates(Archive *fout)
   10311              : {
   10312              :     PGresult   *res;
   10313              :     int         ntups;
   10314              :     int         i;
   10315              :     PQExpBuffer query;
   10316              :     TSTemplateInfo *tmplinfo;
   10317              :     int         i_tableoid;
   10318              :     int         i_oid;
   10319              :     int         i_tmplname;
   10320              :     int         i_tmplnamespace;
   10321              :     int         i_tmplinit;
   10322              :     int         i_tmpllexize;
   10323              : 
   10324          249 :     query = createPQExpBuffer();
   10325              : 
   10326          249 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, tmplname, "
   10327              :                          "tmplnamespace, tmplinit::oid, tmpllexize::oid "
   10328              :                          "FROM pg_ts_template");
   10329              : 
   10330          249 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   10331              : 
   10332          249 :     ntups = PQntuples(res);
   10333              : 
   10334          249 :     tmplinfo = pg_malloc_array(TSTemplateInfo, ntups);
   10335              : 
   10336          249 :     i_tableoid = PQfnumber(res, "tableoid");
   10337          249 :     i_oid = PQfnumber(res, "oid");
   10338          249 :     i_tmplname = PQfnumber(res, "tmplname");
   10339          249 :     i_tmplnamespace = PQfnumber(res, "tmplnamespace");
   10340          249 :     i_tmplinit = PQfnumber(res, "tmplinit");
   10341          249 :     i_tmpllexize = PQfnumber(res, "tmpllexize");
   10342              : 
   10343         1539 :     for (i = 0; i < ntups; i++)
   10344              :     {
   10345         1290 :         tmplinfo[i].dobj.objType = DO_TSTEMPLATE;
   10346         1290 :         tmplinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
   10347         1290 :         tmplinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
   10348         1290 :         AssignDumpId(&tmplinfo[i].dobj);
   10349         1290 :         tmplinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_tmplname));
   10350         2580 :         tmplinfo[i].dobj.namespace =
   10351         1290 :             findNamespace(atooid(PQgetvalue(res, i, i_tmplnamespace)));
   10352         1290 :         tmplinfo[i].tmplinit = atooid(PQgetvalue(res, i, i_tmplinit));
   10353         1290 :         tmplinfo[i].tmpllexize = atooid(PQgetvalue(res, i, i_tmpllexize));
   10354              : 
   10355              :         /* Decide whether we want to dump it */
   10356         1290 :         selectDumpableObject(&(tmplinfo[i].dobj), fout);
   10357              :     }
   10358              : 
   10359          249 :     PQclear(res);
   10360              : 
   10361          249 :     destroyPQExpBuffer(query);
   10362          249 : }
   10363              : 
   10364              : /*
   10365              :  * getTSConfigurations:
   10366              :  *    get information about all text search configurations
   10367              :  */
   10368              : void
   10369          249 : getTSConfigurations(Archive *fout)
   10370              : {
   10371              :     PGresult   *res;
   10372              :     int         ntups;
   10373              :     int         i;
   10374              :     PQExpBuffer query;
   10375              :     TSConfigInfo *cfginfo;
   10376              :     int         i_tableoid;
   10377              :     int         i_oid;
   10378              :     int         i_cfgname;
   10379              :     int         i_cfgnamespace;
   10380              :     int         i_cfgowner;
   10381              :     int         i_cfgparser;
   10382              : 
   10383          249 :     query = createPQExpBuffer();
   10384              : 
   10385          249 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, cfgname, "
   10386              :                          "cfgnamespace, cfgowner, cfgparser "
   10387              :                          "FROM pg_ts_config");
   10388              : 
   10389          249 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   10390              : 
   10391          249 :     ntups = PQntuples(res);
   10392              : 
   10393          249 :     cfginfo = pg_malloc_array(TSConfigInfo, ntups);
   10394              : 
   10395          249 :     i_tableoid = PQfnumber(res, "tableoid");
   10396          249 :     i_oid = PQfnumber(res, "oid");
   10397          249 :     i_cfgname = PQfnumber(res, "cfgname");
   10398          249 :     i_cfgnamespace = PQfnumber(res, "cfgnamespace");
   10399          249 :     i_cfgowner = PQfnumber(res, "cfgowner");
   10400          249 :     i_cfgparser = PQfnumber(res, "cfgparser");
   10401              : 
   10402         8290 :     for (i = 0; i < ntups; i++)
   10403              :     {
   10404         8041 :         cfginfo[i].dobj.objType = DO_TSCONFIG;
   10405         8041 :         cfginfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
   10406         8041 :         cfginfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
   10407         8041 :         AssignDumpId(&cfginfo[i].dobj);
   10408         8041 :         cfginfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_cfgname));
   10409        16082 :         cfginfo[i].dobj.namespace =
   10410         8041 :             findNamespace(atooid(PQgetvalue(res, i, i_cfgnamespace)));
   10411         8041 :         cfginfo[i].rolname = getRoleName(PQgetvalue(res, i, i_cfgowner));
   10412         8041 :         cfginfo[i].cfgparser = atooid(PQgetvalue(res, i, i_cfgparser));
   10413              : 
   10414              :         /* Decide whether we want to dump it */
   10415         8041 :         selectDumpableObject(&(cfginfo[i].dobj), fout);
   10416              :     }
   10417              : 
   10418          249 :     PQclear(res);
   10419              : 
   10420          249 :     destroyPQExpBuffer(query);
   10421          249 : }
   10422              : 
   10423              : /*
   10424              :  * getForeignDataWrappers:
   10425              :  *    get information about all foreign-data wrappers in the system catalogs
   10426              :  */
   10427              : void
   10428          249 : getForeignDataWrappers(Archive *fout)
   10429              : {
   10430              :     PGresult   *res;
   10431              :     int         ntups;
   10432              :     int         i;
   10433              :     PQExpBuffer query;
   10434              :     FdwInfo    *fdwinfo;
   10435              :     int         i_tableoid;
   10436              :     int         i_oid;
   10437              :     int         i_fdwname;
   10438              :     int         i_fdwowner;
   10439              :     int         i_fdwhandler;
   10440              :     int         i_fdwvalidator;
   10441              :     int         i_fdwacl;
   10442              :     int         i_acldefault;
   10443              :     int         i_fdwoptions;
   10444              : 
   10445          249 :     query = createPQExpBuffer();
   10446              : 
   10447          249 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, fdwname, "
   10448              :                          "fdwowner, "
   10449              :                          "fdwhandler::pg_catalog.regproc, "
   10450              :                          "fdwvalidator::pg_catalog.regproc, "
   10451              :                          "fdwacl, "
   10452              :                          "acldefault('F', fdwowner) AS acldefault, "
   10453              :                          "array_to_string(ARRAY("
   10454              :                          "SELECT quote_ident(option_name) || ' ' || "
   10455              :                          "quote_literal(option_value) "
   10456              :                          "FROM pg_options_to_table(fdwoptions) "
   10457              :                          "ORDER BY option_name"
   10458              :                          "), E',\n    ') AS fdwoptions "
   10459              :                          "FROM pg_foreign_data_wrapper");
   10460              : 
   10461          249 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   10462              : 
   10463          249 :     ntups = PQntuples(res);
   10464              : 
   10465          249 :     fdwinfo = pg_malloc_array(FdwInfo, ntups);
   10466              : 
   10467          249 :     i_tableoid = PQfnumber(res, "tableoid");
   10468          249 :     i_oid = PQfnumber(res, "oid");
   10469          249 :     i_fdwname = PQfnumber(res, "fdwname");
   10470          249 :     i_fdwowner = PQfnumber(res, "fdwowner");
   10471          249 :     i_fdwhandler = PQfnumber(res, "fdwhandler");
   10472          249 :     i_fdwvalidator = PQfnumber(res, "fdwvalidator");
   10473          249 :     i_fdwacl = PQfnumber(res, "fdwacl");
   10474          249 :     i_acldefault = PQfnumber(res, "acldefault");
   10475          249 :     i_fdwoptions = PQfnumber(res, "fdwoptions");
   10476              : 
   10477          320 :     for (i = 0; i < ntups; i++)
   10478              :     {
   10479           71 :         fdwinfo[i].dobj.objType = DO_FDW;
   10480           71 :         fdwinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
   10481           71 :         fdwinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
   10482           71 :         AssignDumpId(&fdwinfo[i].dobj);
   10483           71 :         fdwinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_fdwname));
   10484           71 :         fdwinfo[i].dobj.namespace = NULL;
   10485           71 :         fdwinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_fdwacl));
   10486           71 :         fdwinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
   10487           71 :         fdwinfo[i].dacl.privtype = 0;
   10488           71 :         fdwinfo[i].dacl.initprivs = NULL;
   10489           71 :         fdwinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_fdwowner));
   10490           71 :         fdwinfo[i].fdwhandler = pg_strdup(PQgetvalue(res, i, i_fdwhandler));
   10491           71 :         fdwinfo[i].fdwvalidator = pg_strdup(PQgetvalue(res, i, i_fdwvalidator));
   10492           71 :         fdwinfo[i].fdwoptions = pg_strdup(PQgetvalue(res, i, i_fdwoptions));
   10493              : 
   10494              :         /* Decide whether we want to dump it */
   10495           71 :         selectDumpableObject(&(fdwinfo[i].dobj), fout);
   10496              : 
   10497              :         /* Mark whether FDW has an ACL */
   10498           71 :         if (!PQgetisnull(res, i, i_fdwacl))
   10499           45 :             fdwinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
   10500              :     }
   10501              : 
   10502          249 :     PQclear(res);
   10503              : 
   10504          249 :     destroyPQExpBuffer(query);
   10505          249 : }
   10506              : 
   10507              : /*
   10508              :  * getForeignServers:
   10509              :  *    get information about all foreign servers in the system catalogs
   10510              :  */
   10511              : void
   10512          249 : getForeignServers(Archive *fout)
   10513              : {
   10514              :     PGresult   *res;
   10515              :     int         ntups;
   10516              :     int         i;
   10517              :     PQExpBuffer query;
   10518              :     ForeignServerInfo *srvinfo;
   10519              :     int         i_tableoid;
   10520              :     int         i_oid;
   10521              :     int         i_srvname;
   10522              :     int         i_srvowner;
   10523              :     int         i_srvfdw;
   10524              :     int         i_srvtype;
   10525              :     int         i_srvversion;
   10526              :     int         i_srvacl;
   10527              :     int         i_acldefault;
   10528              :     int         i_srvoptions;
   10529              : 
   10530          249 :     query = createPQExpBuffer();
   10531              : 
   10532          249 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, srvname, "
   10533              :                          "srvowner, "
   10534              :                          "srvfdw, srvtype, srvversion, srvacl, "
   10535              :                          "acldefault('S', srvowner) AS acldefault, "
   10536              :                          "array_to_string(ARRAY("
   10537              :                          "SELECT quote_ident(option_name) || ' ' || "
   10538              :                          "quote_literal(option_value) "
   10539              :                          "FROM pg_options_to_table(srvoptions) "
   10540              :                          "ORDER BY option_name"
   10541              :                          "), E',\n    ') AS srvoptions "
   10542              :                          "FROM pg_foreign_server");
   10543              : 
   10544          249 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   10545              : 
   10546          249 :     ntups = PQntuples(res);
   10547              : 
   10548          249 :     srvinfo = pg_malloc_array(ForeignServerInfo, ntups);
   10549              : 
   10550          249 :     i_tableoid = PQfnumber(res, "tableoid");
   10551          249 :     i_oid = PQfnumber(res, "oid");
   10552          249 :     i_srvname = PQfnumber(res, "srvname");
   10553          249 :     i_srvowner = PQfnumber(res, "srvowner");
   10554          249 :     i_srvfdw = PQfnumber(res, "srvfdw");
   10555          249 :     i_srvtype = PQfnumber(res, "srvtype");
   10556          249 :     i_srvversion = PQfnumber(res, "srvversion");
   10557          249 :     i_srvacl = PQfnumber(res, "srvacl");
   10558          249 :     i_acldefault = PQfnumber(res, "acldefault");
   10559          249 :     i_srvoptions = PQfnumber(res, "srvoptions");
   10560              : 
   10561          324 :     for (i = 0; i < ntups; i++)
   10562              :     {
   10563           75 :         srvinfo[i].dobj.objType = DO_FOREIGN_SERVER;
   10564           75 :         srvinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
   10565           75 :         srvinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
   10566           75 :         AssignDumpId(&srvinfo[i].dobj);
   10567           75 :         srvinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_srvname));
   10568           75 :         srvinfo[i].dobj.namespace = NULL;
   10569           75 :         srvinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_srvacl));
   10570           75 :         srvinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
   10571           75 :         srvinfo[i].dacl.privtype = 0;
   10572           75 :         srvinfo[i].dacl.initprivs = NULL;
   10573           75 :         srvinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_srvowner));
   10574           75 :         srvinfo[i].srvfdw = atooid(PQgetvalue(res, i, i_srvfdw));
   10575           75 :         srvinfo[i].srvtype = pg_strdup(PQgetvalue(res, i, i_srvtype));
   10576           75 :         srvinfo[i].srvversion = pg_strdup(PQgetvalue(res, i, i_srvversion));
   10577           75 :         srvinfo[i].srvoptions = pg_strdup(PQgetvalue(res, i, i_srvoptions));
   10578              : 
   10579              :         /* Decide whether we want to dump it */
   10580           75 :         selectDumpableObject(&(srvinfo[i].dobj), fout);
   10581              : 
   10582              :         /* Servers have user mappings */
   10583           75 :         srvinfo[i].dobj.components |= DUMP_COMPONENT_USERMAP;
   10584              : 
   10585              :         /* Mark whether server has an ACL */
   10586           75 :         if (!PQgetisnull(res, i, i_srvacl))
   10587           45 :             srvinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
   10588              :     }
   10589              : 
   10590          249 :     PQclear(res);
   10591              : 
   10592          249 :     destroyPQExpBuffer(query);
   10593          249 : }
   10594              : 
   10595              : /*
   10596              :  * getDefaultACLs:
   10597              :  *    get information about all default ACL information in the system catalogs
   10598              :  */
   10599              : void
   10600          249 : getDefaultACLs(Archive *fout)
   10601              : {
   10602          249 :     DumpOptions *dopt = fout->dopt;
   10603              :     DefaultACLInfo *daclinfo;
   10604              :     PQExpBuffer query;
   10605              :     PGresult   *res;
   10606              :     int         i_oid;
   10607              :     int         i_tableoid;
   10608              :     int         i_defaclrole;
   10609              :     int         i_defaclnamespace;
   10610              :     int         i_defaclobjtype;
   10611              :     int         i_defaclacl;
   10612              :     int         i_acldefault;
   10613              :     int         i,
   10614              :                 ntups;
   10615              : 
   10616          249 :     query = createPQExpBuffer();
   10617              : 
   10618              :     /*
   10619              :      * Global entries (with defaclnamespace=0) replace the hard-wired default
   10620              :      * ACL for their object type.  We should dump them as deltas from the
   10621              :      * default ACL, since that will be used as a starting point for
   10622              :      * interpreting the ALTER DEFAULT PRIVILEGES commands.  On the other hand,
   10623              :      * non-global entries can only add privileges not revoke them.  We must
   10624              :      * dump those as-is (i.e., as deltas from an empty ACL).
   10625              :      *
   10626              :      * We can use defaclobjtype as the object type for acldefault(), except
   10627              :      * for the case of 'S' (DEFACLOBJ_SEQUENCE) which must be converted to
   10628              :      * 's'.
   10629              :      */
   10630          249 :     appendPQExpBufferStr(query,
   10631              :                          "SELECT oid, tableoid, "
   10632              :                          "defaclrole, "
   10633              :                          "defaclnamespace, "
   10634              :                          "defaclobjtype, "
   10635              :                          "defaclacl, "
   10636              :                          "CASE WHEN defaclnamespace = 0 THEN "
   10637              :                          "acldefault(CASE WHEN defaclobjtype = 'S' "
   10638              :                          "THEN 's'::\"char\" ELSE defaclobjtype END, "
   10639              :                          "defaclrole) ELSE '{}' END AS acldefault "
   10640              :                          "FROM pg_default_acl");
   10641              : 
   10642          249 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   10643              : 
   10644          249 :     ntups = PQntuples(res);
   10645              : 
   10646          249 :     daclinfo = pg_malloc_array(DefaultACLInfo, ntups);
   10647              : 
   10648          249 :     i_oid = PQfnumber(res, "oid");
   10649          249 :     i_tableoid = PQfnumber(res, "tableoid");
   10650          249 :     i_defaclrole = PQfnumber(res, "defaclrole");
   10651          249 :     i_defaclnamespace = PQfnumber(res, "defaclnamespace");
   10652          249 :     i_defaclobjtype = PQfnumber(res, "defaclobjtype");
   10653          249 :     i_defaclacl = PQfnumber(res, "defaclacl");
   10654          249 :     i_acldefault = PQfnumber(res, "acldefault");
   10655              : 
   10656          443 :     for (i = 0; i < ntups; i++)
   10657              :     {
   10658          194 :         Oid         nspid = atooid(PQgetvalue(res, i, i_defaclnamespace));
   10659              : 
   10660          194 :         daclinfo[i].dobj.objType = DO_DEFAULT_ACL;
   10661          194 :         daclinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
   10662          194 :         daclinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
   10663          194 :         AssignDumpId(&daclinfo[i].dobj);
   10664              :         /* cheesy ... is it worth coming up with a better object name? */
   10665          194 :         daclinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_defaclobjtype));
   10666              : 
   10667          194 :         if (nspid != InvalidOid)
   10668           90 :             daclinfo[i].dobj.namespace = findNamespace(nspid);
   10669              :         else
   10670          104 :             daclinfo[i].dobj.namespace = NULL;
   10671              : 
   10672          194 :         daclinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_defaclacl));
   10673          194 :         daclinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
   10674          194 :         daclinfo[i].dacl.privtype = 0;
   10675          194 :         daclinfo[i].dacl.initprivs = NULL;
   10676          194 :         daclinfo[i].defaclrole = getRoleName(PQgetvalue(res, i, i_defaclrole));
   10677          194 :         daclinfo[i].defaclobjtype = *(PQgetvalue(res, i, i_defaclobjtype));
   10678              : 
   10679              :         /* Default ACLs are ACLs, of course */
   10680          194 :         daclinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
   10681              : 
   10682              :         /* Decide whether we want to dump it */
   10683          194 :         selectDumpableDefaultACL(&(daclinfo[i]), dopt);
   10684              :     }
   10685              : 
   10686          249 :     PQclear(res);
   10687              : 
   10688          249 :     destroyPQExpBuffer(query);
   10689          249 : }
   10690              : 
   10691              : /*
   10692              :  * getRoleName -- look up the name of a role, given its OID
   10693              :  *
   10694              :  * In current usage, we don't expect failures, so error out for a bad OID.
   10695              :  */
   10696              : static const char *
   10697       797173 : getRoleName(const char *roleoid_str)
   10698              : {
   10699       797173 :     Oid         roleoid = atooid(roleoid_str);
   10700              : 
   10701              :     /*
   10702              :      * Do binary search to find the appropriate item.
   10703              :      */
   10704       797173 :     if (nrolenames > 0)
   10705              :     {
   10706       797173 :         RoleNameItem *low = &rolenames[0];
   10707       797173 :         RoleNameItem *high = &rolenames[nrolenames - 1];
   10708              : 
   10709      3188746 :         while (low <= high)
   10710              :         {
   10711      3188746 :             RoleNameItem *middle = low + (high - low) / 2;
   10712              : 
   10713      3188746 :             if (roleoid < middle->roleoid)
   10714      2390309 :                 high = middle - 1;
   10715       798437 :             else if (roleoid > middle->roleoid)
   10716         1264 :                 low = middle + 1;
   10717              :             else
   10718       797173 :                 return middle->rolename; /* found a match */
   10719              :         }
   10720              :     }
   10721              : 
   10722            0 :     pg_fatal("role with OID %u does not exist", roleoid);
   10723              :     return NULL;                /* keep compiler quiet */
   10724              : }
   10725              : 
   10726              : /*
   10727              :  * collectRoleNames --
   10728              :  *
   10729              :  * Construct a table of all known roles.
   10730              :  * The table is sorted by OID for speed in lookup.
   10731              :  */
   10732              : static void
   10733          250 : collectRoleNames(Archive *fout)
   10734              : {
   10735              :     PGresult   *res;
   10736              :     const char *query;
   10737              :     int         i;
   10738              : 
   10739          250 :     query = "SELECT oid, rolname FROM pg_catalog.pg_roles ORDER BY 1";
   10740              : 
   10741          250 :     res = ExecuteSqlQuery(fout, query, PGRES_TUPLES_OK);
   10742              : 
   10743          250 :     nrolenames = PQntuples(res);
   10744              : 
   10745          250 :     rolenames = pg_malloc_array(RoleNameItem, nrolenames);
   10746              : 
   10747         5496 :     for (i = 0; i < nrolenames; i++)
   10748              :     {
   10749         5246 :         rolenames[i].roleoid = atooid(PQgetvalue(res, i, 0));
   10750         5246 :         rolenames[i].rolename = pg_strdup(PQgetvalue(res, i, 1));
   10751              :     }
   10752              : 
   10753          250 :     PQclear(res);
   10754          250 : }
   10755              : 
   10756              : /*
   10757              :  * getAdditionalACLs
   10758              :  *
   10759              :  * We have now created all the DumpableObjects, and collected the ACL data
   10760              :  * that appears in the directly-associated catalog entries.  However, there's
   10761              :  * more ACL-related info to collect.  If any of a table's columns have ACLs,
   10762              :  * we must set the TableInfo's DUMP_COMPONENT_ACL components flag, as well as
   10763              :  * its hascolumnACLs flag (we won't store the ACLs themselves here, though).
   10764              :  * Also, in versions having the pg_init_privs catalog, read that and load the
   10765              :  * information into the relevant DumpableObjects.
   10766              :  */
   10767              : static void
   10768          247 : getAdditionalACLs(Archive *fout)
   10769              : {
   10770          247 :     PQExpBuffer query = createPQExpBuffer();
   10771              :     PGresult   *res;
   10772              :     int         ntups,
   10773              :                 i;
   10774              : 
   10775              :     /* Check for per-column ACLs */
   10776          247 :     appendPQExpBufferStr(query,
   10777              :                          "SELECT DISTINCT attrelid FROM pg_attribute "
   10778              :                          "WHERE attacl IS NOT NULL");
   10779              : 
   10780          247 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   10781              : 
   10782          247 :     ntups = PQntuples(res);
   10783          664 :     for (i = 0; i < ntups; i++)
   10784              :     {
   10785          417 :         Oid         relid = atooid(PQgetvalue(res, i, 0));
   10786              :         TableInfo  *tblinfo;
   10787              : 
   10788          417 :         tblinfo = findTableByOid(relid);
   10789              :         /* OK to ignore tables we haven't got a DumpableObject for */
   10790          417 :         if (tblinfo)
   10791              :         {
   10792          417 :             tblinfo->dobj.components |= DUMP_COMPONENT_ACL;
   10793          417 :             tblinfo->hascolumnACLs = true;
   10794              :         }
   10795              :     }
   10796          247 :     PQclear(res);
   10797              : 
   10798              :     /* Fetch initial-privileges data */
   10799          247 :     if (fout->remoteVersion >= 90600)
   10800              :     {
   10801          247 :         printfPQExpBuffer(query,
   10802              :                           "SELECT objoid, classoid, objsubid, privtype, initprivs "
   10803              :                           "FROM pg_init_privs");
   10804              : 
   10805          247 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   10806              : 
   10807          247 :         ntups = PQntuples(res);
   10808        58600 :         for (i = 0; i < ntups; i++)
   10809              :         {
   10810        58353 :             Oid         objoid = atooid(PQgetvalue(res, i, 0));
   10811        58353 :             Oid         classoid = atooid(PQgetvalue(res, i, 1));
   10812        58353 :             int         objsubid = atoi(PQgetvalue(res, i, 2));
   10813        58353 :             char        privtype = *(PQgetvalue(res, i, 3));
   10814        58353 :             char       *initprivs = PQgetvalue(res, i, 4);
   10815              :             CatalogId   objId;
   10816              :             DumpableObject *dobj;
   10817              : 
   10818        58353 :             objId.tableoid = classoid;
   10819        58353 :             objId.oid = objoid;
   10820        58353 :             dobj = findObjectByCatalogId(objId);
   10821              :             /* OK to ignore entries we haven't got a DumpableObject for */
   10822        58353 :             if (dobj)
   10823              :             {
   10824              :                 /* Cope with sub-object initprivs */
   10825        41848 :                 if (objsubid != 0)
   10826              :                 {
   10827         4964 :                     if (dobj->objType == DO_TABLE)
   10828              :                     {
   10829              :                         /* For a column initprivs, set the table's ACL flags */
   10830         4964 :                         dobj->components |= DUMP_COMPONENT_ACL;
   10831         4964 :                         ((TableInfo *) dobj)->hascolumnACLs = true;
   10832              :                     }
   10833              :                     else
   10834            0 :                         pg_log_warning("unsupported pg_init_privs entry: %u %u %d",
   10835              :                                        classoid, objoid, objsubid);
   10836         5207 :                     continue;
   10837              :                 }
   10838              : 
   10839              :                 /*
   10840              :                  * We ignore any pg_init_privs.initprivs entry for the public
   10841              :                  * schema, as explained in getNamespaces().
   10842              :                  */
   10843        36884 :                 if (dobj->objType == DO_NAMESPACE &&
   10844          490 :                     strcmp(dobj->name, "public") == 0)
   10845          243 :                     continue;
   10846              : 
   10847              :                 /* Else it had better be of a type we think has ACLs */
   10848        36641 :                 if (dobj->objType == DO_NAMESPACE ||
   10849        36394 :                     dobj->objType == DO_TYPE ||
   10850        36370 :                     dobj->objType == DO_FUNC ||
   10851        36278 :                     dobj->objType == DO_AGG ||
   10852        36254 :                     dobj->objType == DO_TABLE ||
   10853            0 :                     dobj->objType == DO_PROCLANG ||
   10854            0 :                     dobj->objType == DO_FDW ||
   10855            0 :                     dobj->objType == DO_FOREIGN_SERVER)
   10856        36641 :                 {
   10857        36641 :                     DumpableObjectWithAcl *daobj = (DumpableObjectWithAcl *) dobj;
   10858              : 
   10859        36641 :                     daobj->dacl.privtype = privtype;
   10860        36641 :                     daobj->dacl.initprivs = pstrdup(initprivs);
   10861              :                 }
   10862              :                 else
   10863            0 :                     pg_log_warning("unsupported pg_init_privs entry: %u %u %d",
   10864              :                                    classoid, objoid, objsubid);
   10865              :             }
   10866              :         }
   10867          247 :         PQclear(res);
   10868              :     }
   10869              : 
   10870          247 :     destroyPQExpBuffer(query);
   10871          247 : }
   10872              : 
   10873              : /*
   10874              :  * dumpCommentExtended --
   10875              :  *
   10876              :  * This routine is used to dump any comments associated with the
   10877              :  * object handed to this routine. The routine takes the object type
   10878              :  * and object name (ready to print, except for schema decoration), plus
   10879              :  * the namespace and owner of the object (for labeling the ArchiveEntry),
   10880              :  * plus catalog ID and subid which are the lookup key for pg_description,
   10881              :  * plus the dump ID for the object (for setting a dependency).
   10882              :  * If a matching pg_description entry is found, it is dumped.
   10883              :  *
   10884              :  * Note: in some cases, such as comments for triggers and rules, the "type"
   10885              :  * string really looks like, e.g., "TRIGGER name ON".  This is a bit of a hack
   10886              :  * but it doesn't seem worth complicating the API for all callers to make
   10887              :  * it cleaner.
   10888              :  *
   10889              :  * Note: although this routine takes a dumpId for dependency purposes,
   10890              :  * that purpose is just to mark the dependency in the emitted dump file
   10891              :  * for possible future use by pg_restore.  We do NOT use it for determining
   10892              :  * ordering of the comment in the dump file, because this routine is called
   10893              :  * after dependency sorting occurs.  This routine should be called just after
   10894              :  * calling ArchiveEntry() for the specified object.
   10895              :  */
   10896              : static void
   10897         6753 : dumpCommentExtended(Archive *fout, const char *type,
   10898              :                     const char *name, const char *namespace,
   10899              :                     const char *owner, CatalogId catalogId,
   10900              :                     int subid, DumpId dumpId,
   10901              :                     const char *initdb_comment)
   10902              : {
   10903         6753 :     DumpOptions *dopt = fout->dopt;
   10904              :     CommentItem *comments;
   10905              :     int         ncomments;
   10906              : 
   10907              :     /* do nothing, if --no-comments is supplied */
   10908         6753 :     if (dopt->no_comments)
   10909            0 :         return;
   10910              : 
   10911              :     /* Comments are schema not data ... except LO comments are data */
   10912         6753 :     if (strcmp(type, "LARGE OBJECT") != 0)
   10913              :     {
   10914         6695 :         if (!dopt->dumpSchema)
   10915            0 :             return;
   10916              :     }
   10917              :     else
   10918              :     {
   10919              :         /* We do dump LO comments in binary-upgrade mode */
   10920           58 :         if (!dopt->dumpData && !dopt->binary_upgrade)
   10921            0 :             return;
   10922              :     }
   10923              : 
   10924              :     /* Search for comments associated with catalogId, using table */
   10925         6753 :     ncomments = findComments(catalogId.tableoid, catalogId.oid,
   10926              :                              &comments);
   10927              : 
   10928              :     /* Is there one matching the subid? */
   10929         6753 :     while (ncomments > 0)
   10930              :     {
   10931         6708 :         if (comments->objsubid == subid)
   10932         6708 :             break;
   10933            0 :         comments++;
   10934            0 :         ncomments--;
   10935              :     }
   10936              : 
   10937         6753 :     if (initdb_comment != NULL)
   10938              :     {
   10939              :         static CommentItem empty_comment = {.descr = ""};
   10940              : 
   10941              :         /*
   10942              :          * initdb creates this object with a comment.  Skip dumping the
   10943              :          * initdb-provided comment, which would complicate matters for
   10944              :          * non-superuser use of pg_dump.  When the DBA has removed initdb's
   10945              :          * comment, replicate that.
   10946              :          */
   10947          178 :         if (ncomments == 0)
   10948              :         {
   10949            4 :             comments = &empty_comment;
   10950            4 :             ncomments = 1;
   10951              :         }
   10952          174 :         else if (strcmp(comments->descr, initdb_comment) == 0)
   10953          174 :             ncomments = 0;
   10954              :     }
   10955              : 
   10956              :     /* If a comment exists, build COMMENT ON statement */
   10957         6753 :     if (ncomments > 0)
   10958              :     {
   10959         6538 :         PQExpBuffer query = createPQExpBuffer();
   10960         6538 :         PQExpBuffer tag = createPQExpBuffer();
   10961              : 
   10962         6538 :         appendPQExpBuffer(query, "COMMENT ON %s ", type);
   10963         6538 :         if (namespace && *namespace)
   10964         6360 :             appendPQExpBuffer(query, "%s.", fmtId(namespace));
   10965         6538 :         appendPQExpBuffer(query, "%s IS ", name);
   10966         6538 :         appendStringLiteralAH(query, comments->descr, fout);
   10967         6538 :         appendPQExpBufferStr(query, ";\n");
   10968              : 
   10969         6538 :         appendPQExpBuffer(tag, "%s %s", type, name);
   10970              : 
   10971              :         /*
   10972              :          * We mark comments as SECTION_NONE because they really belong in the
   10973              :          * same section as their parent, whether that is pre-data or
   10974              :          * post-data.
   10975              :          */
   10976         6538 :         ArchiveEntry(fout, nilCatalogId, createDumpId(),
   10977         6538 :                      ARCHIVE_OPTS(.tag = tag->data,
   10978              :                                   .namespace = namespace,
   10979              :                                   .owner = owner,
   10980              :                                   .description = "COMMENT",
   10981              :                                   .section = SECTION_NONE,
   10982              :                                   .createStmt = query->data,
   10983              :                                   .deps = &dumpId,
   10984              :                                   .nDeps = 1));
   10985              : 
   10986         6538 :         destroyPQExpBuffer(query);
   10987         6538 :         destroyPQExpBuffer(tag);
   10988              :     }
   10989              : }
   10990              : 
   10991              : /*
   10992              :  * dumpComment --
   10993              :  *
   10994              :  * Typical simplification of the above function.
   10995              :  */
   10996              : static inline void
   10997         6534 : dumpComment(Archive *fout, const char *type,
   10998              :             const char *name, const char *namespace,
   10999              :             const char *owner, CatalogId catalogId,
   11000              :             int subid, DumpId dumpId)
   11001              : {
   11002         6534 :     dumpCommentExtended(fout, type, name, namespace, owner,
   11003              :                         catalogId, subid, dumpId, NULL);
   11004         6534 : }
   11005              : 
   11006              : /*
   11007              :  * appendNamedArgument --
   11008              :  *
   11009              :  * Convenience routine for constructing parameters of the form:
   11010              :  * 'paraname', 'value'::type
   11011              :  */
   11012              : static void
   11013         6246 : appendNamedArgument(PQExpBuffer out, Archive *fout, const char *argname,
   11014              :                     const char *argtype, const char *argval)
   11015              : {
   11016         6246 :     appendPQExpBufferStr(out, ",\n\t");
   11017              : 
   11018         6246 :     appendStringLiteralAH(out, argname, fout);
   11019         6246 :     appendPQExpBufferStr(out, ", ");
   11020              : 
   11021         6246 :     appendStringLiteralAH(out, argval, fout);
   11022         6246 :     appendPQExpBuffer(out, "::%s", argtype);
   11023         6246 : }
   11024              : 
   11025              : /*
   11026              :  * fetchAttributeStats --
   11027              :  *
   11028              :  * Fetch next batch of attribute statistics for dumpRelationStats_dumper().
   11029              :  */
   11030              : static PGresult *
   11031         1037 : fetchAttributeStats(Archive *fout)
   11032              : {
   11033         1037 :     ArchiveHandle *AH = (ArchiveHandle *) fout;
   11034         1037 :     PQExpBuffer nspnames = createPQExpBuffer();
   11035         1037 :     PQExpBuffer relnames = createPQExpBuffer();
   11036         1037 :     int         count = 0;
   11037         1037 :     PGresult   *res = NULL;
   11038              :     static TocEntry *te;
   11039              :     static bool restarted;
   11040         1037 :     int         max_rels = MAX_ATTR_STATS_RELS;
   11041              : 
   11042              :     /*
   11043              :      * Our query for retrieving statistics for multiple relations uses WITH
   11044              :      * ORDINALITY and multi-argument UNNEST(), both of which were introduced
   11045              :      * in v9.4.  For older versions, we resort to gathering statistics for a
   11046              :      * single relation at a time.
   11047              :      */
   11048         1037 :     if (fout->remoteVersion < 90400)
   11049            0 :         max_rels = 1;
   11050              : 
   11051              :     /* If we're just starting, set our TOC pointer. */
   11052         1037 :     if (!te)
   11053           62 :         te = AH->toc->next;
   11054              : 
   11055              :     /*
   11056              :      * We can't easily avoid a second TOC scan for the tar format because it
   11057              :      * writes restore.sql separately, which means we must execute the queries
   11058              :      * twice.  This feels risky, but there is no known reason it should
   11059              :      * generate different output than the first pass.  Even if it does, the
   11060              :      * worst-case scenario is that restore.sql might have different statistics
   11061              :      * data than the archive.
   11062              :      */
   11063         1037 :     if (!restarted && te == AH->toc && AH->format == archTar)
   11064              :     {
   11065            1 :         te = AH->toc->next;
   11066            1 :         restarted = true;
   11067              :     }
   11068              : 
   11069         1037 :     appendPQExpBufferChar(nspnames, '{');
   11070         1037 :     appendPQExpBufferChar(relnames, '{');
   11071              : 
   11072              :     /*
   11073              :      * Scan the TOC for the next set of relevant stats entries.  We assume
   11074              :      * that statistics are dumped in the order they are listed in the TOC.
   11075              :      * This is perhaps not the sturdiest assumption, so we verify it matches
   11076              :      * reality in dumpRelationStats_dumper().
   11077              :      */
   11078        15971 :     for (; te != AH->toc && count < max_rels; te = te->next)
   11079              :     {
   11080        14934 :         if ((te->reqs & REQ_STATS) != 0 &&
   11081         3356 :             strcmp(te->desc, "STATISTICS DATA") == 0)
   11082              :         {
   11083         3321 :             appendPGArray(nspnames, te->namespace);
   11084         3321 :             appendPGArray(relnames, te->tag);
   11085         3321 :             count++;
   11086              :         }
   11087              :     }
   11088              : 
   11089         1037 :     appendPQExpBufferChar(nspnames, '}');
   11090         1037 :     appendPQExpBufferChar(relnames, '}');
   11091              : 
   11092              :     /* Execute the query for the next batch of relations. */
   11093         1037 :     if (count > 0)
   11094              :     {
   11095          105 :         PQExpBuffer query = createPQExpBuffer();
   11096              : 
   11097          105 :         appendPQExpBufferStr(query, "EXECUTE getAttributeStats(");
   11098          105 :         appendStringLiteralAH(query, nspnames->data, fout);
   11099          105 :         appendPQExpBufferStr(query, "::pg_catalog.name[],");
   11100          105 :         appendStringLiteralAH(query, relnames->data, fout);
   11101          105 :         appendPQExpBufferStr(query, "::pg_catalog.name[])");
   11102          105 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   11103          105 :         destroyPQExpBuffer(query);
   11104              :     }
   11105              : 
   11106         1037 :     destroyPQExpBuffer(nspnames);
   11107         1037 :     destroyPQExpBuffer(relnames);
   11108         1037 :     return res;
   11109              : }
   11110              : 
   11111              : /*
   11112              :  * dumpRelationStats_dumper --
   11113              :  *
   11114              :  * Generate command to import stats into the relation on the new database.
   11115              :  * This routine is called by the Archiver when it wants the statistics to be
   11116              :  * dumped.
   11117              :  */
   11118              : static char *
   11119         3321 : dumpRelationStats_dumper(Archive *fout, const void *userArg, const TocEntry *te)
   11120              : {
   11121         3321 :     const RelStatsInfo *rsinfo = userArg;
   11122              :     static PGresult *res;
   11123              :     static int  rownum;
   11124              :     PQExpBuffer query;
   11125              :     PQExpBufferData out_data;
   11126         3321 :     PQExpBuffer out = &out_data;
   11127              :     int         i_schemaname;
   11128              :     int         i_tablename;
   11129              :     int         i_attname;
   11130              :     int         i_inherited;
   11131              :     int         i_null_frac;
   11132              :     int         i_avg_width;
   11133              :     int         i_n_distinct;
   11134              :     int         i_most_common_vals;
   11135              :     int         i_most_common_freqs;
   11136              :     int         i_histogram_bounds;
   11137              :     int         i_correlation;
   11138              :     int         i_most_common_elems;
   11139              :     int         i_most_common_elem_freqs;
   11140              :     int         i_elem_count_histogram;
   11141              :     int         i_range_length_histogram;
   11142              :     int         i_range_empty_frac;
   11143              :     int         i_range_bounds_histogram;
   11144              :     static TocEntry *expected_te;
   11145              : 
   11146              :     /*
   11147              :      * fetchAttributeStats() assumes that the statistics are dumped in the
   11148              :      * order they are listed in the TOC.  We verify that here for safety.
   11149              :      */
   11150         3321 :     if (!expected_te)
   11151           62 :         expected_te = ((ArchiveHandle *) fout)->toc;
   11152              : 
   11153         3321 :     expected_te = expected_te->next;
   11154        13100 :     while ((expected_te->reqs & REQ_STATS) == 0 ||
   11155         3322 :            strcmp(expected_te->desc, "STATISTICS DATA") != 0)
   11156         9779 :         expected_te = expected_te->next;
   11157              : 
   11158         3321 :     if (te != expected_te)
   11159            0 :         pg_fatal("statistics dumped out of order (current: %d %s %s, expected: %d %s %s)",
   11160              :                  te->dumpId, te->desc, te->tag,
   11161              :                  expected_te->dumpId, expected_te->desc, expected_te->tag);
   11162              : 
   11163         3321 :     query = createPQExpBuffer();
   11164         3321 :     if (!fout->is_prepared[PREPQUERY_GETATTRIBUTESTATS])
   11165              :     {
   11166           62 :         appendPQExpBufferStr(query,
   11167              :                              "PREPARE getAttributeStats(pg_catalog.name[], pg_catalog.name[]) AS\n"
   11168              :                              "SELECT s.schemaname, s.tablename, s.attname, s.inherited, "
   11169              :                              "s.null_frac, s.avg_width, s.n_distinct, "
   11170              :                              "s.most_common_vals, s.most_common_freqs, "
   11171              :                              "s.histogram_bounds, s.correlation, "
   11172              :                              "s.most_common_elems, s.most_common_elem_freqs, "
   11173              :                              "s.elem_count_histogram, ");
   11174              : 
   11175           62 :         if (fout->remoteVersion >= 170000)
   11176           62 :             appendPQExpBufferStr(query,
   11177              :                                  "s.range_length_histogram, "
   11178              :                                  "s.range_empty_frac, "
   11179              :                                  "s.range_bounds_histogram ");
   11180              :         else
   11181            0 :             appendPQExpBufferStr(query,
   11182              :                                  "NULL AS range_length_histogram,"
   11183              :                                  "NULL AS range_empty_frac,"
   11184              :                                  "NULL AS range_bounds_histogram ");
   11185              : 
   11186              :         /*
   11187              :          * The results must be in the order of the relations supplied in the
   11188              :          * parameters to ensure we remain in sync as we walk through the TOC.
   11189              :          * The redundant filter clause on s.tablename = ANY(...) seems
   11190              :          * sufficient to convince the planner to use
   11191              :          * pg_class_relname_nsp_index, which avoids a full scan of pg_stats.
   11192              :          * This may not work for all versions.
   11193              :          *
   11194              :          * Our query for retrieving statistics for multiple relations uses
   11195              :          * WITH ORDINALITY and multi-argument UNNEST(), both of which were
   11196              :          * introduced in v9.4.  For older versions, we resort to gathering
   11197              :          * statistics for a single relation at a time.
   11198              :          */
   11199           62 :         if (fout->remoteVersion >= 90400)
   11200           62 :             appendPQExpBufferStr(query,
   11201              :                                  "FROM pg_catalog.pg_stats s "
   11202              :                                  "JOIN unnest($1, $2) WITH ORDINALITY AS u (schemaname, tablename, ord) "
   11203              :                                  "ON s.schemaname = u.schemaname "
   11204              :                                  "AND s.tablename = u.tablename "
   11205              :                                  "WHERE s.tablename = ANY($2) "
   11206              :                                  "ORDER BY u.ord, s.attname, s.inherited");
   11207              :         else
   11208            0 :             appendPQExpBufferStr(query,
   11209              :                                  "FROM pg_catalog.pg_stats s "
   11210              :                                  "WHERE s.schemaname = $1[1] "
   11211              :                                  "AND s.tablename = $2[1] "
   11212              :                                  "ORDER BY s.attname, s.inherited");
   11213              : 
   11214           62 :         ExecuteSqlStatement(fout, query->data);
   11215              : 
   11216           62 :         fout->is_prepared[PREPQUERY_GETATTRIBUTESTATS] = true;
   11217           62 :         resetPQExpBuffer(query);
   11218              :     }
   11219              : 
   11220         3321 :     initPQExpBuffer(out);
   11221              : 
   11222              :     /* restore relation stats */
   11223         3321 :     appendPQExpBufferStr(out, "SELECT * FROM pg_catalog.pg_restore_relation_stats(\n");
   11224         3321 :     appendPQExpBuffer(out, "\t'version', '%d'::integer,\n",
   11225              :                       fout->remoteVersion);
   11226         3321 :     appendPQExpBufferStr(out, "\t'schemaname', ");
   11227         3321 :     appendStringLiteralAH(out, rsinfo->dobj.namespace->dobj.name, fout);
   11228         3321 :     appendPQExpBufferStr(out, ",\n");
   11229         3321 :     appendPQExpBufferStr(out, "\t'relname', ");
   11230         3321 :     appendStringLiteralAH(out, rsinfo->dobj.name, fout);
   11231         3321 :     appendPQExpBufferStr(out, ",\n");
   11232         3321 :     appendPQExpBuffer(out, "\t'relpages', '%d'::integer,\n", rsinfo->relpages);
   11233              : 
   11234              :     /*
   11235              :      * Before v14, a reltuples value of 0 was ambiguous: it could either mean
   11236              :      * the relation is empty, or it could mean that it hadn't yet been
   11237              :      * vacuumed or analyzed.  (Newer versions use -1 for the latter case.)
   11238              :      * This ambiguity allegedly can cause the planner to choose inefficient
   11239              :      * plans after restoring to v18 or newer.  To deal with this, let's just
   11240              :      * set reltuples to -1 in that case.
   11241              :      */
   11242         3321 :     if (fout->remoteVersion < 140000 && strcmp("0", rsinfo->reltuples) == 0)
   11243            0 :         appendPQExpBufferStr(out, "\t'reltuples', '-1'::real,\n");
   11244              :     else
   11245         3321 :         appendPQExpBuffer(out, "\t'reltuples', '%s'::real,\n", rsinfo->reltuples);
   11246              : 
   11247         3321 :     appendPQExpBuffer(out, "\t'relallvisible', '%d'::integer",
   11248         3321 :                       rsinfo->relallvisible);
   11249              : 
   11250         3321 :     if (fout->remoteVersion >= 180000)
   11251         3321 :         appendPQExpBuffer(out, ",\n\t'relallfrozen', '%d'::integer", rsinfo->relallfrozen);
   11252              : 
   11253         3321 :     appendPQExpBufferStr(out, "\n);\n");
   11254              : 
   11255              :     /* Fetch the next batch of attribute statistics if needed. */
   11256         3321 :     if (rownum >= PQntuples(res))
   11257              :     {
   11258         1037 :         PQclear(res);
   11259         1037 :         res = fetchAttributeStats(fout);
   11260         1037 :         rownum = 0;
   11261              :     }
   11262              : 
   11263         3321 :     i_schemaname = PQfnumber(res, "schemaname");
   11264         3321 :     i_tablename = PQfnumber(res, "tablename");
   11265         3321 :     i_attname = PQfnumber(res, "attname");
   11266         3321 :     i_inherited = PQfnumber(res, "inherited");
   11267         3321 :     i_null_frac = PQfnumber(res, "null_frac");
   11268         3321 :     i_avg_width = PQfnumber(res, "avg_width");
   11269         3321 :     i_n_distinct = PQfnumber(res, "n_distinct");
   11270         3321 :     i_most_common_vals = PQfnumber(res, "most_common_vals");
   11271         3321 :     i_most_common_freqs = PQfnumber(res, "most_common_freqs");
   11272         3321 :     i_histogram_bounds = PQfnumber(res, "histogram_bounds");
   11273         3321 :     i_correlation = PQfnumber(res, "correlation");
   11274         3321 :     i_most_common_elems = PQfnumber(res, "most_common_elems");
   11275         3321 :     i_most_common_elem_freqs = PQfnumber(res, "most_common_elem_freqs");
   11276         3321 :     i_elem_count_histogram = PQfnumber(res, "elem_count_histogram");
   11277         3321 :     i_range_length_histogram = PQfnumber(res, "range_length_histogram");
   11278         3321 :     i_range_empty_frac = PQfnumber(res, "range_empty_frac");
   11279         3321 :     i_range_bounds_histogram = PQfnumber(res, "range_bounds_histogram");
   11280              : 
   11281              :     /* restore attribute stats */
   11282         4221 :     for (; rownum < PQntuples(res); rownum++)
   11283              :     {
   11284              :         const char *attname;
   11285              : 
   11286              :         /* Stop if the next stat row in our cache isn't for this relation. */
   11287         3184 :         if (strcmp(te->tag, PQgetvalue(res, rownum, i_tablename)) != 0 ||
   11288          900 :             strcmp(te->namespace, PQgetvalue(res, rownum, i_schemaname)) != 0)
   11289              :             break;
   11290              : 
   11291          900 :         appendPQExpBufferStr(out, "SELECT * FROM pg_catalog.pg_restore_attribute_stats(\n");
   11292          900 :         appendPQExpBuffer(out, "\t'version', '%d'::integer,\n",
   11293              :                           fout->remoteVersion);
   11294          900 :         appendPQExpBufferStr(out, "\t'schemaname', ");
   11295          900 :         appendStringLiteralAH(out, rsinfo->dobj.namespace->dobj.name, fout);
   11296          900 :         appendPQExpBufferStr(out, ",\n\t'relname', ");
   11297          900 :         appendStringLiteralAH(out, rsinfo->dobj.name, fout);
   11298              : 
   11299          900 :         if (PQgetisnull(res, rownum, i_attname))
   11300            0 :             pg_fatal("unexpected null attname");
   11301          900 :         attname = PQgetvalue(res, rownum, i_attname);
   11302              : 
   11303              :         /*
   11304              :          * Indexes look up attname in indAttNames to derive attnum, all others
   11305              :          * use attname directly.  We must specify attnum for indexes, since
   11306              :          * their attnames are not necessarily stable across dump/reload.
   11307              :          */
   11308          900 :         if (rsinfo->nindAttNames == 0)
   11309              :         {
   11310          863 :             appendPQExpBufferStr(out, ",\n\t'attname', ");
   11311          863 :             appendStringLiteralAH(out, attname, fout);
   11312              :         }
   11313              :         else
   11314              :         {
   11315           37 :             bool        found = false;
   11316              : 
   11317           68 :             for (int i = 0; i < rsinfo->nindAttNames; i++)
   11318              :             {
   11319           68 :                 if (strcmp(attname, rsinfo->indAttNames[i]) == 0)
   11320              :                 {
   11321           37 :                     appendPQExpBuffer(out, ",\n\t'attnum', '%d'::smallint",
   11322              :                                       i + 1);
   11323           37 :                     found = true;
   11324           37 :                     break;
   11325              :                 }
   11326              :             }
   11327              : 
   11328           37 :             if (!found)
   11329            0 :                 pg_fatal("could not find index attname \"%s\"", attname);
   11330              :         }
   11331              : 
   11332          900 :         if (!PQgetisnull(res, rownum, i_inherited))
   11333          900 :             appendNamedArgument(out, fout, "inherited", "boolean",
   11334          900 :                                 PQgetvalue(res, rownum, i_inherited));
   11335          900 :         if (!PQgetisnull(res, rownum, i_null_frac))
   11336          900 :             appendNamedArgument(out, fout, "null_frac", "real",
   11337          900 :                                 PQgetvalue(res, rownum, i_null_frac));
   11338          900 :         if (!PQgetisnull(res, rownum, i_avg_width))
   11339          900 :             appendNamedArgument(out, fout, "avg_width", "integer",
   11340          900 :                                 PQgetvalue(res, rownum, i_avg_width));
   11341          900 :         if (!PQgetisnull(res, rownum, i_n_distinct))
   11342          900 :             appendNamedArgument(out, fout, "n_distinct", "real",
   11343          900 :                                 PQgetvalue(res, rownum, i_n_distinct));
   11344          900 :         if (!PQgetisnull(res, rownum, i_most_common_vals))
   11345          466 :             appendNamedArgument(out, fout, "most_common_vals", "text",
   11346          466 :                                 PQgetvalue(res, rownum, i_most_common_vals));
   11347          900 :         if (!PQgetisnull(res, rownum, i_most_common_freqs))
   11348          466 :             appendNamedArgument(out, fout, "most_common_freqs", "real[]",
   11349          466 :                                 PQgetvalue(res, rownum, i_most_common_freqs));
   11350          900 :         if (!PQgetisnull(res, rownum, i_histogram_bounds))
   11351          580 :             appendNamedArgument(out, fout, "histogram_bounds", "text",
   11352          580 :                                 PQgetvalue(res, rownum, i_histogram_bounds));
   11353          900 :         if (!PQgetisnull(res, rownum, i_correlation))
   11354          860 :             appendNamedArgument(out, fout, "correlation", "real",
   11355          860 :                                 PQgetvalue(res, rownum, i_correlation));
   11356          900 :         if (!PQgetisnull(res, rownum, i_most_common_elems))
   11357            8 :             appendNamedArgument(out, fout, "most_common_elems", "text",
   11358            8 :                                 PQgetvalue(res, rownum, i_most_common_elems));
   11359          900 :         if (!PQgetisnull(res, rownum, i_most_common_elem_freqs))
   11360            8 :             appendNamedArgument(out, fout, "most_common_elem_freqs", "real[]",
   11361            8 :                                 PQgetvalue(res, rownum, i_most_common_elem_freqs));
   11362          900 :         if (!PQgetisnull(res, rownum, i_elem_count_histogram))
   11363            7 :             appendNamedArgument(out, fout, "elem_count_histogram", "real[]",
   11364            7 :                                 PQgetvalue(res, rownum, i_elem_count_histogram));
   11365          900 :         if (fout->remoteVersion >= 170000)
   11366              :         {
   11367          900 :             if (!PQgetisnull(res, rownum, i_range_length_histogram))
   11368            4 :                 appendNamedArgument(out, fout, "range_length_histogram", "text",
   11369            4 :                                     PQgetvalue(res, rownum, i_range_length_histogram));
   11370          900 :             if (!PQgetisnull(res, rownum, i_range_empty_frac))
   11371            4 :                 appendNamedArgument(out, fout, "range_empty_frac", "real",
   11372            4 :                                     PQgetvalue(res, rownum, i_range_empty_frac));
   11373          900 :             if (!PQgetisnull(res, rownum, i_range_bounds_histogram))
   11374            4 :                 appendNamedArgument(out, fout, "range_bounds_histogram", "text",
   11375            4 :                                     PQgetvalue(res, rownum, i_range_bounds_histogram));
   11376              :         }
   11377          900 :         appendPQExpBufferStr(out, "\n);\n");
   11378              :     }
   11379              : 
   11380         3321 :     destroyPQExpBuffer(query);
   11381         3321 :     return out->data;
   11382              : }
   11383              : 
   11384              : /*
   11385              :  * dumpRelationStats --
   11386              :  *
   11387              :  * Make an ArchiveEntry for the relation statistics.  The Archiver will take
   11388              :  * care of gathering the statistics and generating the restore commands when
   11389              :  * they are needed.
   11390              :  */
   11391              : static void
   11392         3393 : dumpRelationStats(Archive *fout, const RelStatsInfo *rsinfo)
   11393              : {
   11394         3393 :     const DumpableObject *dobj = &rsinfo->dobj;
   11395              : 
   11396              :     /* nothing to do if we are not dumping statistics */
   11397         3393 :     if (!fout->dopt->dumpStatistics)
   11398            0 :         return;
   11399              : 
   11400         3393 :     ArchiveEntry(fout, nilCatalogId, createDumpId(),
   11401         3393 :                  ARCHIVE_OPTS(.tag = dobj->name,
   11402              :                               .namespace = dobj->namespace->dobj.name,
   11403              :                               .description = "STATISTICS DATA",
   11404              :                               .section = rsinfo->section,
   11405              :                               .defnFn = dumpRelationStats_dumper,
   11406              :                               .defnArg = rsinfo,
   11407              :                               .deps = dobj->dependencies,
   11408              :                               .nDeps = dobj->nDeps));
   11409              : }
   11410              : 
   11411              : /*
   11412              :  * dumpTableComment --
   11413              :  *
   11414              :  * As above, but dump comments for both the specified table (or view)
   11415              :  * and its columns.
   11416              :  */
   11417              : static void
   11418           74 : dumpTableComment(Archive *fout, const TableInfo *tbinfo,
   11419              :                  const char *reltypename)
   11420              : {
   11421           74 :     DumpOptions *dopt = fout->dopt;
   11422              :     CommentItem *comments;
   11423              :     int         ncomments;
   11424              :     PQExpBuffer query;
   11425              :     PQExpBuffer tag;
   11426              : 
   11427              :     /* do nothing, if --no-comments is supplied */
   11428           74 :     if (dopt->no_comments)
   11429            0 :         return;
   11430              : 
   11431              :     /* Comments are SCHEMA not data */
   11432           74 :     if (!dopt->dumpSchema)
   11433            0 :         return;
   11434              : 
   11435              :     /* Search for comments associated with relation, using table */
   11436           74 :     ncomments = findComments(tbinfo->dobj.catId.tableoid,
   11437           74 :                              tbinfo->dobj.catId.oid,
   11438              :                              &comments);
   11439              : 
   11440              :     /* If comments exist, build COMMENT ON statements */
   11441           74 :     if (ncomments <= 0)
   11442            0 :         return;
   11443              : 
   11444           74 :     query = createPQExpBuffer();
   11445           74 :     tag = createPQExpBuffer();
   11446              : 
   11447          212 :     while (ncomments > 0)
   11448              :     {
   11449          138 :         const char *descr = comments->descr;
   11450          138 :         int         objsubid = comments->objsubid;
   11451              : 
   11452          138 :         if (objsubid == 0)
   11453              :         {
   11454           32 :             resetPQExpBuffer(tag);
   11455           32 :             appendPQExpBuffer(tag, "%s %s", reltypename,
   11456           32 :                               fmtId(tbinfo->dobj.name));
   11457              : 
   11458           32 :             resetPQExpBuffer(query);
   11459           32 :             appendPQExpBuffer(query, "COMMENT ON %s %s IS ", reltypename,
   11460           32 :                               fmtQualifiedDumpable(tbinfo));
   11461           32 :             appendStringLiteralAH(query, descr, fout);
   11462           32 :             appendPQExpBufferStr(query, ";\n");
   11463              : 
   11464           32 :             ArchiveEntry(fout, nilCatalogId, createDumpId(),
   11465           32 :                          ARCHIVE_OPTS(.tag = tag->data,
   11466              :                                       .namespace = tbinfo->dobj.namespace->dobj.name,
   11467              :                                       .owner = tbinfo->rolname,
   11468              :                                       .description = "COMMENT",
   11469              :                                       .section = SECTION_NONE,
   11470              :                                       .createStmt = query->data,
   11471              :                                       .deps = &(tbinfo->dobj.dumpId),
   11472              :                                       .nDeps = 1));
   11473              :         }
   11474          106 :         else if (objsubid > 0 && objsubid <= tbinfo->numatts)
   11475              :         {
   11476          106 :             resetPQExpBuffer(tag);
   11477          106 :             appendPQExpBuffer(tag, "COLUMN %s.",
   11478          106 :                               fmtId(tbinfo->dobj.name));
   11479          106 :             appendPQExpBufferStr(tag, fmtId(tbinfo->attnames[objsubid - 1]));
   11480              : 
   11481          106 :             resetPQExpBuffer(query);
   11482          106 :             appendPQExpBuffer(query, "COMMENT ON COLUMN %s.",
   11483          106 :                               fmtQualifiedDumpable(tbinfo));
   11484          106 :             appendPQExpBuffer(query, "%s IS ",
   11485          106 :                               fmtId(tbinfo->attnames[objsubid - 1]));
   11486          106 :             appendStringLiteralAH(query, descr, fout);
   11487          106 :             appendPQExpBufferStr(query, ";\n");
   11488              : 
   11489          106 :             ArchiveEntry(fout, nilCatalogId, createDumpId(),
   11490          106 :                          ARCHIVE_OPTS(.tag = tag->data,
   11491              :                                       .namespace = tbinfo->dobj.namespace->dobj.name,
   11492              :                                       .owner = tbinfo->rolname,
   11493              :                                       .description = "COMMENT",
   11494              :                                       .section = SECTION_NONE,
   11495              :                                       .createStmt = query->data,
   11496              :                                       .deps = &(tbinfo->dobj.dumpId),
   11497              :                                       .nDeps = 1));
   11498              :         }
   11499              : 
   11500          138 :         comments++;
   11501          138 :         ncomments--;
   11502              :     }
   11503              : 
   11504           74 :     destroyPQExpBuffer(query);
   11505           74 :     destroyPQExpBuffer(tag);
   11506              : }
   11507              : 
   11508              : /*
   11509              :  * findComments --
   11510              :  *
   11511              :  * Find the comment(s), if any, associated with the given object.  All the
   11512              :  * objsubid values associated with the given classoid/objoid are found with
   11513              :  * one search.
   11514              :  */
   11515              : static int
   11516         6859 : findComments(Oid classoid, Oid objoid, CommentItem **items)
   11517              : {
   11518         6859 :     CommentItem *middle = NULL;
   11519              :     CommentItem *low;
   11520              :     CommentItem *high;
   11521              :     int         nmatch;
   11522              : 
   11523              :     /*
   11524              :      * Do binary search to find some item matching the object.
   11525              :      */
   11526         6859 :     low = &comments[0];
   11527         6859 :     high = &comments[ncomments - 1];
   11528        67374 :     while (low <= high)
   11529              :     {
   11530        67329 :         middle = low + (high - low) / 2;
   11531              : 
   11532        67329 :         if (classoid < middle->classoid)
   11533         6830 :             high = middle - 1;
   11534        60499 :         else if (classoid > middle->classoid)
   11535         7215 :             low = middle + 1;
   11536        53284 :         else if (objoid < middle->objoid)
   11537        23236 :             high = middle - 1;
   11538        30048 :         else if (objoid > middle->objoid)
   11539        23234 :             low = middle + 1;
   11540              :         else
   11541         6814 :             break;              /* found a match */
   11542              :     }
   11543              : 
   11544         6859 :     if (low > high)              /* no matches */
   11545              :     {
   11546           45 :         *items = NULL;
   11547           45 :         return 0;
   11548              :     }
   11549              : 
   11550              :     /*
   11551              :      * Now determine how many items match the object.  The search loop
   11552              :      * invariant still holds: only items between low and high inclusive could
   11553              :      * match.
   11554              :      */
   11555         6814 :     nmatch = 1;
   11556         6814 :     while (middle > low)
   11557              :     {
   11558         3466 :         if (classoid != middle[-1].classoid ||
   11559         3362 :             objoid != middle[-1].objoid)
   11560              :             break;
   11561            0 :         middle--;
   11562            0 :         nmatch++;
   11563              :     }
   11564              : 
   11565         6814 :     *items = middle;
   11566              : 
   11567         6814 :     middle += nmatch;
   11568         6878 :     while (middle <= high)
   11569              :     {
   11570         3662 :         if (classoid != middle->classoid ||
   11571         3159 :             objoid != middle->objoid)
   11572              :             break;
   11573           64 :         middle++;
   11574           64 :         nmatch++;
   11575              :     }
   11576              : 
   11577         6814 :     return nmatch;
   11578              : }
   11579              : 
   11580              : /*
   11581              :  * collectComments --
   11582              :  *
   11583              :  * Construct a table of all comments available for database objects;
   11584              :  * also set the has-comment component flag for each relevant object.
   11585              :  *
   11586              :  * We used to do per-object queries for the comments, but it's much faster
   11587              :  * to pull them all over at once, and on most databases the memory cost
   11588              :  * isn't high.
   11589              :  *
   11590              :  * The table is sorted by classoid/objid/objsubid for speed in lookup.
   11591              :  */
   11592              : static void
   11593          249 : collectComments(Archive *fout)
   11594              : {
   11595              :     PGresult   *res;
   11596              :     PQExpBuffer query;
   11597              :     int         i_description;
   11598              :     int         i_classoid;
   11599              :     int         i_objoid;
   11600              :     int         i_objsubid;
   11601              :     int         ntups;
   11602              :     int         i;
   11603              :     DumpableObject *dobj;
   11604              : 
   11605          249 :     query = createPQExpBuffer();
   11606              : 
   11607          249 :     appendPQExpBufferStr(query, "SELECT description, classoid, objoid, objsubid "
   11608              :                          "FROM pg_catalog.pg_description "
   11609              :                          "ORDER BY classoid, objoid, objsubid");
   11610              : 
   11611          249 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   11612              : 
   11613              :     /* Construct lookup table containing OIDs in numeric form */
   11614              : 
   11615          249 :     i_description = PQfnumber(res, "description");
   11616          249 :     i_classoid = PQfnumber(res, "classoid");
   11617          249 :     i_objoid = PQfnumber(res, "objoid");
   11618          249 :     i_objsubid = PQfnumber(res, "objsubid");
   11619              : 
   11620          249 :     ntups = PQntuples(res);
   11621              : 
   11622          249 :     comments = pg_malloc_array(CommentItem, ntups);
   11623          249 :     ncomments = 0;
   11624          249 :     dobj = NULL;
   11625              : 
   11626      1351801 :     for (i = 0; i < ntups; i++)
   11627              :     {
   11628              :         CatalogId   objId;
   11629              :         int         subid;
   11630              : 
   11631      1351552 :         objId.tableoid = atooid(PQgetvalue(res, i, i_classoid));
   11632      1351552 :         objId.oid = atooid(PQgetvalue(res, i, i_objoid));
   11633      1351552 :         subid = atoi(PQgetvalue(res, i, i_objsubid));
   11634              : 
   11635              :         /* We needn't remember comments that don't match any dumpable object */
   11636      1351552 :         if (dobj == NULL ||
   11637       495092 :             dobj->catId.tableoid != objId.tableoid ||
   11638       492116 :             dobj->catId.oid != objId.oid)
   11639      1351462 :             dobj = findObjectByCatalogId(objId);
   11640      1351552 :         if (dobj == NULL)
   11641       856217 :             continue;
   11642              : 
   11643              :         /*
   11644              :          * Comments on columns of composite types are linked to the type's
   11645              :          * pg_class entry, but we need to set the DUMP_COMPONENT_COMMENT flag
   11646              :          * in the type's own DumpableObject.
   11647              :          */
   11648       495335 :         if (subid != 0 && dobj->objType == DO_TABLE &&
   11649          194 :             ((TableInfo *) dobj)->relkind == RELKIND_COMPOSITE_TYPE)
   11650           45 :         {
   11651              :             TypeInfo   *cTypeInfo;
   11652              : 
   11653           45 :             cTypeInfo = findTypeByOid(((TableInfo *) dobj)->reltype);
   11654           45 :             if (cTypeInfo)
   11655           45 :                 cTypeInfo->dobj.components |= DUMP_COMPONENT_COMMENT;
   11656              :         }
   11657              :         else
   11658       495290 :             dobj->components |= DUMP_COMPONENT_COMMENT;
   11659              : 
   11660       495335 :         comments[ncomments].descr = pg_strdup(PQgetvalue(res, i, i_description));
   11661       495335 :         comments[ncomments].classoid = objId.tableoid;
   11662       495335 :         comments[ncomments].objoid = objId.oid;
   11663       495335 :         comments[ncomments].objsubid = subid;
   11664       495335 :         ncomments++;
   11665              :     }
   11666              : 
   11667          249 :     PQclear(res);
   11668          249 :     destroyPQExpBuffer(query);
   11669          249 : }
   11670              : 
   11671              : /*
   11672              :  * dumpDumpableObject
   11673              :  *
   11674              :  * This routine and its subsidiaries are responsible for creating
   11675              :  * ArchiveEntries (TOC objects) for each object to be dumped.
   11676              :  */
   11677              : static void
   11678       925706 : dumpDumpableObject(Archive *fout, DumpableObject *dobj)
   11679              : {
   11680              :     /*
   11681              :      * Clear any dump-request bits for components that don't exist for this
   11682              :      * object.  (This makes it safe to initially use DUMP_COMPONENT_ALL as the
   11683              :      * request for every kind of object.)
   11684              :      */
   11685       925706 :     dobj->dump &= dobj->components;
   11686              : 
   11687              :     /* Now, short-circuit if there's nothing to be done here. */
   11688       925706 :     if (dobj->dump == 0)
   11689       838789 :         return;
   11690              : 
   11691        86917 :     switch (dobj->objType)
   11692              :     {
   11693          619 :         case DO_NAMESPACE:
   11694          619 :             dumpNamespace(fout, (const NamespaceInfo *) dobj);
   11695          619 :             break;
   11696           24 :         case DO_EXTENSION:
   11697           24 :             dumpExtension(fout, (const ExtensionInfo *) dobj);
   11698           24 :             break;
   11699          923 :         case DO_TYPE:
   11700          923 :             dumpType(fout, (const TypeInfo *) dobj);
   11701          923 :             break;
   11702           73 :         case DO_SHELL_TYPE:
   11703           73 :             dumpShellType(fout, (const ShellTypeInfo *) dobj);
   11704           73 :             break;
   11705         1836 :         case DO_FUNC:
   11706         1836 :             dumpFunc(fout, (const FuncInfo *) dobj);
   11707         1836 :             break;
   11708          292 :         case DO_AGG:
   11709          292 :             dumpAgg(fout, (const AggInfo *) dobj);
   11710          292 :             break;
   11711         2522 :         case DO_OPERATOR:
   11712         2522 :             dumpOpr(fout, (const OprInfo *) dobj);
   11713         2522 :             break;
   11714           80 :         case DO_ACCESS_METHOD:
   11715           80 :             dumpAccessMethod(fout, (const AccessMethodInfo *) dobj);
   11716           80 :             break;
   11717          666 :         case DO_OPCLASS:
   11718          666 :             dumpOpclass(fout, (const OpclassInfo *) dobj);
   11719          666 :             break;
   11720          555 :         case DO_OPFAMILY:
   11721          555 :             dumpOpfamily(fout, (const OpfamilyInfo *) dobj);
   11722          555 :             break;
   11723         2729 :         case DO_COLLATION:
   11724         2729 :             dumpCollation(fout, (const CollInfo *) dobj);
   11725         2729 :             break;
   11726          422 :         case DO_CONVERSION:
   11727          422 :             dumpConversion(fout, (const ConvInfo *) dobj);
   11728          422 :             break;
   11729        40471 :         case DO_TABLE:
   11730        40471 :             dumpTable(fout, (const TableInfo *) dobj);
   11731        40471 :             break;
   11732         1391 :         case DO_TABLE_ATTACH:
   11733         1391 :             dumpTableAttach(fout, (const TableAttachInfo *) dobj);
   11734         1391 :             break;
   11735         1037 :         case DO_ATTRDEF:
   11736         1037 :             dumpAttrDef(fout, (const AttrDefInfo *) dobj);
   11737         1037 :             break;
   11738         2600 :         case DO_INDEX:
   11739         2600 :             dumpIndex(fout, (const IndxInfo *) dobj);
   11740         2600 :             break;
   11741          574 :         case DO_INDEX_ATTACH:
   11742          574 :             dumpIndexAttach(fout, (const IndexAttachInfo *) dobj);
   11743          574 :             break;
   11744          171 :         case DO_STATSEXT:
   11745          171 :             dumpStatisticsExt(fout, (const StatsExtInfo *) dobj);
   11746          171 :             dumpStatisticsExtStats(fout, (const StatsExtInfo *) dobj);
   11747          171 :             break;
   11748          345 :         case DO_REFRESH_MATVIEW:
   11749          345 :             refreshMatViewData(fout, (const TableDataInfo *) dobj);
   11750          345 :             break;
   11751         1129 :         case DO_RULE:
   11752         1129 :             dumpRule(fout, (const RuleInfo *) dobj);
   11753         1129 :             break;
   11754          523 :         case DO_TRIGGER:
   11755          523 :             dumpTrigger(fout, (const TriggerInfo *) dobj);
   11756          523 :             break;
   11757           42 :         case DO_EVENT_TRIGGER:
   11758           42 :             dumpEventTrigger(fout, (const EventTriggerInfo *) dobj);
   11759           42 :             break;
   11760         2318 :         case DO_CONSTRAINT:
   11761         2318 :             dumpConstraint(fout, (const ConstraintInfo *) dobj);
   11762         2318 :             break;
   11763          171 :         case DO_FK_CONSTRAINT:
   11764          171 :             dumpConstraint(fout, (const ConstraintInfo *) dobj);
   11765          171 :             break;
   11766           82 :         case DO_PROCLANG:
   11767           82 :             dumpProcLang(fout, (const ProcLangInfo *) dobj);
   11768           82 :             break;
   11769           67 :         case DO_CAST:
   11770           67 :             dumpCast(fout, (const CastInfo *) dobj);
   11771           67 :             break;
   11772           42 :         case DO_TRANSFORM:
   11773           42 :             dumpTransform(fout, (const TransformInfo *) dobj);
   11774           42 :             break;
   11775          401 :         case DO_SEQUENCE_SET:
   11776          401 :             dumpSequenceData(fout, (const TableDataInfo *) dobj);
   11777          401 :             break;
   11778         4407 :         case DO_TABLE_DATA:
   11779         4407 :             dumpTableData(fout, (const TableDataInfo *) dobj);
   11780         4407 :             break;
   11781        14544 :         case DO_DUMMY_TYPE:
   11782              :             /* table rowtypes and array types are never dumped separately */
   11783        14544 :             break;
   11784           41 :         case DO_TSPARSER:
   11785           41 :             dumpTSParser(fout, (const TSParserInfo *) dobj);
   11786           41 :             break;
   11787          179 :         case DO_TSDICT:
   11788          179 :             dumpTSDictionary(fout, (const TSDictInfo *) dobj);
   11789          179 :             break;
   11790           53 :         case DO_TSTEMPLATE:
   11791           53 :             dumpTSTemplate(fout, (const TSTemplateInfo *) dobj);
   11792           53 :             break;
   11793          154 :         case DO_TSCONFIG:
   11794          154 :             dumpTSConfig(fout, (const TSConfigInfo *) dobj);
   11795          154 :             break;
   11796           52 :         case DO_FDW:
   11797           52 :             dumpForeignDataWrapper(fout, (const FdwInfo *) dobj);
   11798           52 :             break;
   11799           56 :         case DO_FOREIGN_SERVER:
   11800           56 :             dumpForeignServer(fout, (const ForeignServerInfo *) dobj);
   11801           56 :             break;
   11802          160 :         case DO_DEFAULT_ACL:
   11803          160 :             dumpDefaultACL(fout, (const DefaultACLInfo *) dobj);
   11804          160 :             break;
   11805           84 :         case DO_LARGE_OBJECT:
   11806           84 :             dumpLO(fout, (const LoInfo *) dobj);
   11807           84 :             break;
   11808           84 :         case DO_LARGE_OBJECT_DATA:
   11809           84 :             if (dobj->dump & DUMP_COMPONENT_DATA)
   11810              :             {
   11811              :                 LoInfo     *loinfo;
   11812              :                 TocEntry   *te;
   11813              : 
   11814           84 :                 loinfo = (LoInfo *) findObjectByDumpId(dobj->dependencies[0]);
   11815           84 :                 if (loinfo == NULL)
   11816            0 :                     pg_fatal("missing metadata for large objects \"%s\"",
   11817              :                              dobj->name);
   11818              : 
   11819           84 :                 te = ArchiveEntry(fout, dobj->catId, dobj->dumpId,
   11820           84 :                                   ARCHIVE_OPTS(.tag = dobj->name,
   11821              :                                                .owner = loinfo->rolname,
   11822              :                                                .description = "BLOBS",
   11823              :                                                .section = SECTION_DATA,
   11824              :                                                .deps = dobj->dependencies,
   11825              :                                                .nDeps = dobj->nDeps,
   11826              :                                                .dumpFn = dumpLOs,
   11827              :                                                .dumpArg = loinfo));
   11828              : 
   11829              :                 /*
   11830              :                  * Set the TocEntry's dataLength in case we are doing a
   11831              :                  * parallel dump and want to order dump jobs by table size.
   11832              :                  * (We need some size estimate for every TocEntry with a
   11833              :                  * DataDumper function.)  We don't currently have any cheap
   11834              :                  * way to estimate the size of LOs, but fortunately it doesn't
   11835              :                  * matter too much as long as we get large batches of LOs
   11836              :                  * processed reasonably early.  Assume 8K per blob.
   11837              :                  */
   11838           84 :                 te->dataLength = loinfo->numlos * (pgoff_t) 8192;
   11839              :             }
   11840           84 :             break;
   11841          326 :         case DO_POLICY:
   11842          326 :             dumpPolicy(fout, (const PolicyInfo *) dobj);
   11843          326 :             break;
   11844          285 :         case DO_PUBLICATION:
   11845          285 :             dumpPublication(fout, (const PublicationInfo *) dobj);
   11846          285 :             break;
   11847          284 :         case DO_PUBLICATION_REL:
   11848          284 :             dumpPublicationTable(fout, (const PublicationRelInfo *) dobj);
   11849          284 :             break;
   11850           99 :         case DO_PUBLICATION_TABLE_IN_SCHEMA:
   11851           99 :             dumpPublicationNamespace(fout,
   11852              :                                      (const PublicationSchemaInfo *) dobj);
   11853           99 :             break;
   11854          110 :         case DO_SUBSCRIPTION:
   11855          110 :             dumpSubscription(fout, (const SubscriptionInfo *) dobj);
   11856          110 :             break;
   11857            3 :         case DO_SUBSCRIPTION_REL:
   11858            3 :             dumpSubscriptionTable(fout, (const SubRelInfo *) dobj);
   11859            3 :             break;
   11860         3393 :         case DO_REL_STATS:
   11861         3393 :             dumpRelationStats(fout, (const RelStatsInfo *) dobj);
   11862         3393 :             break;
   11863          498 :         case DO_PRE_DATA_BOUNDARY:
   11864              :         case DO_POST_DATA_BOUNDARY:
   11865              :             /* never dumped, nothing to do */
   11866          498 :             break;
   11867              :     }
   11868              : }
   11869              : 
   11870              : /*
   11871              :  * dumpNamespace
   11872              :  *    writes out to fout the queries to recreate a user-defined namespace
   11873              :  */
   11874              : static void
   11875          619 : dumpNamespace(Archive *fout, const NamespaceInfo *nspinfo)
   11876              : {
   11877          619 :     DumpOptions *dopt = fout->dopt;
   11878              :     PQExpBuffer q;
   11879              :     PQExpBuffer delq;
   11880              :     char       *qnspname;
   11881              : 
   11882              :     /* Do nothing if not dumping schema */
   11883          619 :     if (!dopt->dumpSchema)
   11884           28 :         return;
   11885              : 
   11886          591 :     q = createPQExpBuffer();
   11887          591 :     delq = createPQExpBuffer();
   11888              : 
   11889          591 :     qnspname = pg_strdup(fmtId(nspinfo->dobj.name));
   11890              : 
   11891          591 :     if (nspinfo->create)
   11892              :     {
   11893          377 :         appendPQExpBuffer(delq, "DROP SCHEMA %s;\n", qnspname);
   11894          377 :         appendPQExpBuffer(q, "CREATE SCHEMA %s;\n", qnspname);
   11895              :     }
   11896              :     else
   11897              :     {
   11898              :         /* see selectDumpableNamespace() */
   11899          214 :         appendPQExpBufferStr(delq,
   11900              :                              "-- *not* dropping schema, since initdb creates it\n");
   11901          214 :         appendPQExpBufferStr(q,
   11902              :                              "-- *not* creating schema, since initdb creates it\n");
   11903              :     }
   11904              : 
   11905          591 :     if (dopt->binary_upgrade)
   11906           94 :         binary_upgrade_extension_member(q, &nspinfo->dobj,
   11907              :                                         "SCHEMA", qnspname, NULL);
   11908              : 
   11909          591 :     if (nspinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   11910          193 :         ArchiveEntry(fout, nspinfo->dobj.catId, nspinfo->dobj.dumpId,
   11911          193 :                      ARCHIVE_OPTS(.tag = nspinfo->dobj.name,
   11912              :                                   .owner = nspinfo->rolname,
   11913              :                                   .description = "SCHEMA",
   11914              :                                   .section = SECTION_PRE_DATA,
   11915              :                                   .createStmt = q->data,
   11916              :                                   .dropStmt = delq->data));
   11917              : 
   11918              :     /* Dump Schema Comments and Security Labels */
   11919          591 :     if (nspinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   11920              :     {
   11921          219 :         const char *initdb_comment = NULL;
   11922              : 
   11923          219 :         if (!nspinfo->create && strcmp(qnspname, "public") == 0)
   11924          178 :             initdb_comment = "standard public schema";
   11925          219 :         dumpCommentExtended(fout, "SCHEMA", qnspname,
   11926          219 :                             NULL, nspinfo->rolname,
   11927          219 :                             nspinfo->dobj.catId, 0, nspinfo->dobj.dumpId,
   11928              :                             initdb_comment);
   11929              :     }
   11930              : 
   11931          591 :     if (nspinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
   11932            0 :         dumpSecLabel(fout, "SCHEMA", qnspname,
   11933            0 :                      NULL, nspinfo->rolname,
   11934            0 :                      nspinfo->dobj.catId, 0, nspinfo->dobj.dumpId);
   11935              : 
   11936          591 :     if (nspinfo->dobj.dump & DUMP_COMPONENT_ACL)
   11937          489 :         dumpACL(fout, nspinfo->dobj.dumpId, InvalidDumpId, "SCHEMA",
   11938              :                 qnspname, NULL, NULL,
   11939          489 :                 NULL, nspinfo->rolname, &nspinfo->dacl);
   11940              : 
   11941          591 :     free(qnspname);
   11942              : 
   11943          591 :     destroyPQExpBuffer(q);
   11944          591 :     destroyPQExpBuffer(delq);
   11945              : }
   11946              : 
   11947              : /*
   11948              :  * dumpExtension
   11949              :  *    writes out to fout the queries to recreate an extension
   11950              :  */
   11951              : static void
   11952           24 : dumpExtension(Archive *fout, const ExtensionInfo *extinfo)
   11953              : {
   11954           24 :     DumpOptions *dopt = fout->dopt;
   11955              :     PQExpBuffer q;
   11956              :     PQExpBuffer delq;
   11957              :     char       *qextname;
   11958              : 
   11959              :     /* Do nothing if not dumping schema */
   11960           24 :     if (!dopt->dumpSchema)
   11961            1 :         return;
   11962              : 
   11963           23 :     q = createPQExpBuffer();
   11964           23 :     delq = createPQExpBuffer();
   11965              : 
   11966           23 :     qextname = pg_strdup(fmtId(extinfo->dobj.name));
   11967              : 
   11968           23 :     appendPQExpBuffer(delq, "DROP EXTENSION %s;\n", qextname);
   11969              : 
   11970           23 :     if (!dopt->binary_upgrade)
   11971              :     {
   11972              :         /*
   11973              :          * In a regular dump, we simply create the extension, intentionally
   11974              :          * not specifying a version, so that the destination installation's
   11975              :          * default version is used.
   11976              :          *
   11977              :          * Use of IF NOT EXISTS here is unlike our behavior for other object
   11978              :          * types; but there are various scenarios in which it's convenient to
   11979              :          * manually create the desired extension before restoring, so we
   11980              :          * prefer to allow it to exist already.
   11981              :          */
   11982           17 :         appendPQExpBuffer(q, "CREATE EXTENSION IF NOT EXISTS %s WITH SCHEMA %s;\n",
   11983           17 :                           qextname, fmtId(extinfo->namespace));
   11984              :     }
   11985              :     else
   11986              :     {
   11987              :         /*
   11988              :          * In binary-upgrade mode, it's critical to reproduce the state of the
   11989              :          * database exactly, so our procedure is to create an empty extension,
   11990              :          * restore all the contained objects normally, and add them to the
   11991              :          * extension one by one.  This function performs just the first of
   11992              :          * those steps.  binary_upgrade_extension_member() takes care of
   11993              :          * adding member objects as they're created.
   11994              :          */
   11995              :         int         i;
   11996              :         int         n;
   11997              : 
   11998            6 :         appendPQExpBufferStr(q, "-- For binary upgrade, create an empty extension and insert objects into it\n");
   11999              : 
   12000              :         /*
   12001              :          * We unconditionally create the extension, so we must drop it if it
   12002              :          * exists.  This could happen if the user deleted 'plpgsql' and then
   12003              :          * readded it, causing its oid to be greater than g_last_builtin_oid.
   12004              :          */
   12005            6 :         appendPQExpBuffer(q, "DROP EXTENSION IF EXISTS %s;\n", qextname);
   12006              : 
   12007            6 :         appendPQExpBufferStr(q,
   12008              :                              "SELECT pg_catalog.binary_upgrade_create_empty_extension(");
   12009            6 :         appendStringLiteralAH(q, extinfo->dobj.name, fout);
   12010            6 :         appendPQExpBufferStr(q, ", ");
   12011            6 :         appendStringLiteralAH(q, extinfo->namespace, fout);
   12012            6 :         appendPQExpBufferStr(q, ", ");
   12013            6 :         appendPQExpBuffer(q, "%s, ", extinfo->relocatable ? "true" : "false");
   12014            6 :         appendStringLiteralAH(q, extinfo->extversion, fout);
   12015            6 :         appendPQExpBufferStr(q, ", ");
   12016              : 
   12017              :         /*
   12018              :          * Note that we're pushing extconfig (an OID array) back into
   12019              :          * pg_extension exactly as-is.  This is OK because pg_class OIDs are
   12020              :          * preserved in binary upgrade.
   12021              :          */
   12022            6 :         if (strlen(extinfo->extconfig) > 2)
   12023            1 :             appendStringLiteralAH(q, extinfo->extconfig, fout);
   12024              :         else
   12025            5 :             appendPQExpBufferStr(q, "NULL");
   12026            6 :         appendPQExpBufferStr(q, ", ");
   12027            6 :         if (strlen(extinfo->extcondition) > 2)
   12028            1 :             appendStringLiteralAH(q, extinfo->extcondition, fout);
   12029              :         else
   12030            5 :             appendPQExpBufferStr(q, "NULL");
   12031            6 :         appendPQExpBufferStr(q, ", ");
   12032            6 :         appendPQExpBufferStr(q, "ARRAY[");
   12033            6 :         n = 0;
   12034           12 :         for (i = 0; i < extinfo->dobj.nDeps; i++)
   12035              :         {
   12036              :             DumpableObject *extobj;
   12037              : 
   12038            6 :             extobj = findObjectByDumpId(extinfo->dobj.dependencies[i]);
   12039            6 :             if (extobj && extobj->objType == DO_EXTENSION)
   12040              :             {
   12041            0 :                 if (n++ > 0)
   12042            0 :                     appendPQExpBufferChar(q, ',');
   12043            0 :                 appendStringLiteralAH(q, extobj->name, fout);
   12044              :             }
   12045              :         }
   12046            6 :         appendPQExpBufferStr(q, "]::pg_catalog.text[]");
   12047            6 :         appendPQExpBufferStr(q, ");\n");
   12048              :     }
   12049              : 
   12050           23 :     if (extinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   12051           23 :         ArchiveEntry(fout, extinfo->dobj.catId, extinfo->dobj.dumpId,
   12052           23 :                      ARCHIVE_OPTS(.tag = extinfo->dobj.name,
   12053              :                                   .description = "EXTENSION",
   12054              :                                   .section = SECTION_PRE_DATA,
   12055              :                                   .createStmt = q->data,
   12056              :                                   .dropStmt = delq->data));
   12057              : 
   12058              :     /* Dump Extension Comments */
   12059           23 :     if (extinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   12060           23 :         dumpComment(fout, "EXTENSION", qextname,
   12061              :                     NULL, "",
   12062           23 :                     extinfo->dobj.catId, 0, extinfo->dobj.dumpId);
   12063              : 
   12064           23 :     free(qextname);
   12065              : 
   12066           23 :     destroyPQExpBuffer(q);
   12067           23 :     destroyPQExpBuffer(delq);
   12068              : }
   12069              : 
   12070              : /*
   12071              :  * dumpType
   12072              :  *    writes out to fout the queries to recreate a user-defined type
   12073              :  */
   12074              : static void
   12075          923 : dumpType(Archive *fout, const TypeInfo *tyinfo)
   12076              : {
   12077          923 :     DumpOptions *dopt = fout->dopt;
   12078              : 
   12079              :     /* Do nothing if not dumping schema */
   12080          923 :     if (!dopt->dumpSchema)
   12081           49 :         return;
   12082              : 
   12083              :     /* Dump out in proper style */
   12084          874 :     if (tyinfo->typtype == TYPTYPE_BASE)
   12085          283 :         dumpBaseType(fout, tyinfo);
   12086          591 :     else if (tyinfo->typtype == TYPTYPE_DOMAIN)
   12087          152 :         dumpDomain(fout, tyinfo);
   12088          439 :     else if (tyinfo->typtype == TYPTYPE_COMPOSITE)
   12089          130 :         dumpCompositeType(fout, tyinfo);
   12090          309 :     else if (tyinfo->typtype == TYPTYPE_ENUM)
   12091           85 :         dumpEnumType(fout, tyinfo);
   12092          224 :     else if (tyinfo->typtype == TYPTYPE_RANGE)
   12093          112 :         dumpRangeType(fout, tyinfo);
   12094          112 :     else if (tyinfo->typtype == TYPTYPE_PSEUDO && !tyinfo->isDefined)
   12095           37 :         dumpUndefinedType(fout, tyinfo);
   12096              :     else
   12097           75 :         pg_log_warning("typtype of data type \"%s\" appears to be invalid",
   12098              :                        tyinfo->dobj.name);
   12099              : }
   12100              : 
   12101              : /*
   12102              :  * dumpEnumType
   12103              :  *    writes out to fout the queries to recreate a user-defined enum type
   12104              :  */
   12105              : static void
   12106           85 : dumpEnumType(Archive *fout, const TypeInfo *tyinfo)
   12107              : {
   12108           85 :     DumpOptions *dopt = fout->dopt;
   12109           85 :     PQExpBuffer q = createPQExpBuffer();
   12110           85 :     PQExpBuffer delq = createPQExpBuffer();
   12111           85 :     PQExpBuffer query = createPQExpBuffer();
   12112              :     PGresult   *res;
   12113              :     int         num,
   12114              :                 i;
   12115              :     Oid         enum_oid;
   12116              :     char       *qtypname;
   12117              :     char       *qualtypname;
   12118              :     char       *label;
   12119              :     int         i_enumlabel;
   12120              :     int         i_oid;
   12121              : 
   12122           85 :     if (!fout->is_prepared[PREPQUERY_DUMPENUMTYPE])
   12123              :     {
   12124              :         /* Set up query for enum-specific details */
   12125           40 :         appendPQExpBufferStr(query,
   12126              :                              "PREPARE dumpEnumType(pg_catalog.oid) AS\n"
   12127              :                              "SELECT oid, enumlabel "
   12128              :                              "FROM pg_catalog.pg_enum "
   12129              :                              "WHERE enumtypid = $1 "
   12130              :                              "ORDER BY enumsortorder");
   12131              : 
   12132           40 :         ExecuteSqlStatement(fout, query->data);
   12133              : 
   12134           40 :         fout->is_prepared[PREPQUERY_DUMPENUMTYPE] = true;
   12135              :     }
   12136              : 
   12137           85 :     printfPQExpBuffer(query,
   12138              :                       "EXECUTE dumpEnumType('%u')",
   12139           85 :                       tyinfo->dobj.catId.oid);
   12140              : 
   12141           85 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   12142              : 
   12143           85 :     num = PQntuples(res);
   12144              : 
   12145           85 :     qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
   12146           85 :     qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
   12147              : 
   12148              :     /*
   12149              :      * CASCADE shouldn't be required here as for normal types since the I/O
   12150              :      * functions are generic and do not get dropped.
   12151              :      */
   12152           85 :     appendPQExpBuffer(delq, "DROP TYPE %s;\n", qualtypname);
   12153              : 
   12154           85 :     if (dopt->binary_upgrade)
   12155            6 :         binary_upgrade_set_type_oids_by_type_oid(fout, q,
   12156            6 :                                                  tyinfo->dobj.catId.oid,
   12157              :                                                  false, false);
   12158              : 
   12159           85 :     appendPQExpBuffer(q, "CREATE TYPE %s AS ENUM (",
   12160              :                       qualtypname);
   12161              : 
   12162           85 :     if (!dopt->binary_upgrade)
   12163              :     {
   12164           79 :         i_enumlabel = PQfnumber(res, "enumlabel");
   12165              : 
   12166              :         /* Labels with server-assigned oids */
   12167          482 :         for (i = 0; i < num; i++)
   12168              :         {
   12169          403 :             label = PQgetvalue(res, i, i_enumlabel);
   12170          403 :             if (i > 0)
   12171          324 :                 appendPQExpBufferChar(q, ',');
   12172          403 :             appendPQExpBufferStr(q, "\n    ");
   12173          403 :             appendStringLiteralAH(q, label, fout);
   12174              :         }
   12175              :     }
   12176              : 
   12177           85 :     appendPQExpBufferStr(q, "\n);\n");
   12178              : 
   12179           85 :     if (dopt->binary_upgrade)
   12180              :     {
   12181            6 :         i_oid = PQfnumber(res, "oid");
   12182            6 :         i_enumlabel = PQfnumber(res, "enumlabel");
   12183              : 
   12184              :         /* Labels with dump-assigned (preserved) oids */
   12185           62 :         for (i = 0; i < num; i++)
   12186              :         {
   12187           56 :             enum_oid = atooid(PQgetvalue(res, i, i_oid));
   12188           56 :             label = PQgetvalue(res, i, i_enumlabel);
   12189              : 
   12190           56 :             if (i == 0)
   12191            6 :                 appendPQExpBufferStr(q, "\n-- For binary upgrade, must preserve pg_enum oids\n");
   12192           56 :             appendPQExpBuffer(q,
   12193              :                               "SELECT pg_catalog.binary_upgrade_set_next_pg_enum_oid('%u'::pg_catalog.oid);\n",
   12194              :                               enum_oid);
   12195           56 :             appendPQExpBuffer(q, "ALTER TYPE %s ADD VALUE ", qualtypname);
   12196           56 :             appendStringLiteralAH(q, label, fout);
   12197           56 :             appendPQExpBufferStr(q, ";\n\n");
   12198              :         }
   12199              :     }
   12200              : 
   12201           85 :     if (dopt->binary_upgrade)
   12202            6 :         binary_upgrade_extension_member(q, &tyinfo->dobj,
   12203              :                                         "TYPE", qtypname,
   12204            6 :                                         tyinfo->dobj.namespace->dobj.name);
   12205              : 
   12206           85 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   12207           85 :         ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
   12208           85 :                      ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
   12209              :                                   .namespace = tyinfo->dobj.namespace->dobj.name,
   12210              :                                   .owner = tyinfo->rolname,
   12211              :                                   .description = "TYPE",
   12212              :                                   .section = SECTION_PRE_DATA,
   12213              :                                   .createStmt = q->data,
   12214              :                                   .dropStmt = delq->data));
   12215              : 
   12216              :     /* Dump Type Comments and Security Labels */
   12217           85 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   12218           32 :         dumpComment(fout, "TYPE", qtypname,
   12219           32 :                     tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
   12220           32 :                     tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
   12221              : 
   12222           85 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
   12223            0 :         dumpSecLabel(fout, "TYPE", qtypname,
   12224            0 :                      tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
   12225            0 :                      tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
   12226              : 
   12227           85 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
   12228           32 :         dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
   12229              :                 qtypname, NULL,
   12230           32 :                 tyinfo->dobj.namespace->dobj.name,
   12231           32 :                 NULL, tyinfo->rolname, &tyinfo->dacl);
   12232              : 
   12233           85 :     PQclear(res);
   12234           85 :     destroyPQExpBuffer(q);
   12235           85 :     destroyPQExpBuffer(delq);
   12236           85 :     destroyPQExpBuffer(query);
   12237           85 :     free(qtypname);
   12238           85 :     free(qualtypname);
   12239           85 : }
   12240              : 
   12241              : /*
   12242              :  * dumpRangeType
   12243              :  *    writes out to fout the queries to recreate a user-defined range type
   12244              :  */
   12245              : static void
   12246          112 : dumpRangeType(Archive *fout, const TypeInfo *tyinfo)
   12247              : {
   12248          112 :     DumpOptions *dopt = fout->dopt;
   12249          112 :     PQExpBuffer q = createPQExpBuffer();
   12250          112 :     PQExpBuffer delq = createPQExpBuffer();
   12251          112 :     PQExpBuffer query = createPQExpBuffer();
   12252              :     PGresult   *res;
   12253              :     Oid         collationOid;
   12254              :     char       *qtypname;
   12255              :     char       *qualtypname;
   12256              :     char       *procname;
   12257              : 
   12258          112 :     if (!fout->is_prepared[PREPQUERY_DUMPRANGETYPE])
   12259              :     {
   12260              :         /* Set up query for range-specific details */
   12261           40 :         appendPQExpBufferStr(query,
   12262              :                              "PREPARE dumpRangeType(pg_catalog.oid) AS\n");
   12263              : 
   12264           40 :         appendPQExpBufferStr(query,
   12265              :                              "SELECT ");
   12266              : 
   12267           40 :         if (fout->remoteVersion >= 140000)
   12268           40 :             appendPQExpBufferStr(query,
   12269              :                                  "pg_catalog.format_type(rngmultitypid, NULL) AS rngmultitype, ");
   12270              :         else
   12271            0 :             appendPQExpBufferStr(query,
   12272              :                                  "NULL AS rngmultitype, ");
   12273              : 
   12274           40 :         appendPQExpBufferStr(query,
   12275              :                              "pg_catalog.format_type(rngsubtype, NULL) AS rngsubtype, "
   12276              :                              "opc.opcname AS opcname, "
   12277              :                              "(SELECT nspname FROM pg_catalog.pg_namespace nsp "
   12278              :                              "  WHERE nsp.oid = opc.opcnamespace) AS opcnsp, "
   12279              :                              "opc.opcdefault, "
   12280              :                              "CASE WHEN rngcollation = st.typcollation THEN 0 "
   12281              :                              "     ELSE rngcollation END AS collation, "
   12282              :                              "rngcanonical, rngsubdiff "
   12283              :                              "FROM pg_catalog.pg_range r, pg_catalog.pg_type st, "
   12284              :                              "     pg_catalog.pg_opclass opc "
   12285              :                              "WHERE st.oid = rngsubtype AND opc.oid = rngsubopc AND "
   12286              :                              "rngtypid = $1");
   12287              : 
   12288           40 :         ExecuteSqlStatement(fout, query->data);
   12289              : 
   12290           40 :         fout->is_prepared[PREPQUERY_DUMPRANGETYPE] = true;
   12291              :     }
   12292              : 
   12293          112 :     printfPQExpBuffer(query,
   12294              :                       "EXECUTE dumpRangeType('%u')",
   12295          112 :                       tyinfo->dobj.catId.oid);
   12296              : 
   12297          112 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   12298              : 
   12299          112 :     qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
   12300          112 :     qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
   12301              : 
   12302              :     /*
   12303              :      * CASCADE shouldn't be required here as for normal types since the I/O
   12304              :      * functions are generic and do not get dropped.
   12305              :      */
   12306          112 :     appendPQExpBuffer(delq, "DROP TYPE %s;\n", qualtypname);
   12307              : 
   12308          112 :     if (dopt->binary_upgrade)
   12309            8 :         binary_upgrade_set_type_oids_by_type_oid(fout, q,
   12310            8 :                                                  tyinfo->dobj.catId.oid,
   12311              :                                                  false, true);
   12312              : 
   12313          112 :     appendPQExpBuffer(q, "CREATE TYPE %s AS RANGE (",
   12314              :                       qualtypname);
   12315              : 
   12316          112 :     appendPQExpBuffer(q, "\n    subtype = %s",
   12317              :                       PQgetvalue(res, 0, PQfnumber(res, "rngsubtype")));
   12318              : 
   12319          112 :     if (!PQgetisnull(res, 0, PQfnumber(res, "rngmultitype")))
   12320          112 :         appendPQExpBuffer(q, ",\n    multirange_type_name = %s",
   12321              :                           PQgetvalue(res, 0, PQfnumber(res, "rngmultitype")));
   12322              : 
   12323              :     /* print subtype_opclass only if not default for subtype */
   12324          112 :     if (PQgetvalue(res, 0, PQfnumber(res, "opcdefault"))[0] != 't')
   12325              :     {
   12326           32 :         char       *opcname = PQgetvalue(res, 0, PQfnumber(res, "opcname"));
   12327           32 :         char       *nspname = PQgetvalue(res, 0, PQfnumber(res, "opcnsp"));
   12328              : 
   12329           32 :         appendPQExpBuffer(q, ",\n    subtype_opclass = %s.",
   12330              :                           fmtId(nspname));
   12331           32 :         appendPQExpBufferStr(q, fmtId(opcname));
   12332              :     }
   12333              : 
   12334          112 :     collationOid = atooid(PQgetvalue(res, 0, PQfnumber(res, "collation")));
   12335          112 :     if (OidIsValid(collationOid))
   12336              :     {
   12337           37 :         CollInfo   *coll = findCollationByOid(collationOid);
   12338              : 
   12339           37 :         if (coll)
   12340           37 :             appendPQExpBuffer(q, ",\n    collation = %s",
   12341           37 :                               fmtQualifiedDumpable(coll));
   12342              :     }
   12343              : 
   12344          112 :     procname = PQgetvalue(res, 0, PQfnumber(res, "rngcanonical"));
   12345          112 :     if (strcmp(procname, "-") != 0)
   12346            9 :         appendPQExpBuffer(q, ",\n    canonical = %s", procname);
   12347              : 
   12348          112 :     procname = PQgetvalue(res, 0, PQfnumber(res, "rngsubdiff"));
   12349          112 :     if (strcmp(procname, "-") != 0)
   12350           23 :         appendPQExpBuffer(q, ",\n    subtype_diff = %s", procname);
   12351              : 
   12352          112 :     appendPQExpBufferStr(q, "\n);\n");
   12353              : 
   12354          112 :     if (dopt->binary_upgrade)
   12355            8 :         binary_upgrade_extension_member(q, &tyinfo->dobj,
   12356              :                                         "TYPE", qtypname,
   12357            8 :                                         tyinfo->dobj.namespace->dobj.name);
   12358              : 
   12359          112 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   12360          112 :         ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
   12361          112 :                      ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
   12362              :                                   .namespace = tyinfo->dobj.namespace->dobj.name,
   12363              :                                   .owner = tyinfo->rolname,
   12364              :                                   .description = "TYPE",
   12365              :                                   .section = SECTION_PRE_DATA,
   12366              :                                   .createStmt = q->data,
   12367              :                                   .dropStmt = delq->data));
   12368              : 
   12369              :     /* Dump Type Comments and Security Labels */
   12370          112 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   12371           50 :         dumpComment(fout, "TYPE", qtypname,
   12372           50 :                     tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
   12373           50 :                     tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
   12374              : 
   12375          112 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
   12376            0 :         dumpSecLabel(fout, "TYPE", qtypname,
   12377            0 :                      tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
   12378            0 :                      tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
   12379              : 
   12380          112 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
   12381           32 :         dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
   12382              :                 qtypname, NULL,
   12383           32 :                 tyinfo->dobj.namespace->dobj.name,
   12384           32 :                 NULL, tyinfo->rolname, &tyinfo->dacl);
   12385              : 
   12386          112 :     PQclear(res);
   12387          112 :     destroyPQExpBuffer(q);
   12388          112 :     destroyPQExpBuffer(delq);
   12389          112 :     destroyPQExpBuffer(query);
   12390          112 :     free(qtypname);
   12391          112 :     free(qualtypname);
   12392          112 : }
   12393              : 
   12394              : /*
   12395              :  * dumpUndefinedType
   12396              :  *    writes out to fout the queries to recreate a !typisdefined type
   12397              :  *
   12398              :  * This is a shell type, but we use different terminology to distinguish
   12399              :  * this case from where we have to emit a shell type definition to break
   12400              :  * circular dependencies.  An undefined type shouldn't ever have anything
   12401              :  * depending on it.
   12402              :  */
   12403              : static void
   12404           37 : dumpUndefinedType(Archive *fout, const TypeInfo *tyinfo)
   12405              : {
   12406           37 :     DumpOptions *dopt = fout->dopt;
   12407           37 :     PQExpBuffer q = createPQExpBuffer();
   12408           37 :     PQExpBuffer delq = createPQExpBuffer();
   12409              :     char       *qtypname;
   12410              :     char       *qualtypname;
   12411              : 
   12412           37 :     qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
   12413           37 :     qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
   12414              : 
   12415           37 :     appendPQExpBuffer(delq, "DROP TYPE %s;\n", qualtypname);
   12416              : 
   12417           37 :     if (dopt->binary_upgrade)
   12418            2 :         binary_upgrade_set_type_oids_by_type_oid(fout, q,
   12419            2 :                                                  tyinfo->dobj.catId.oid,
   12420              :                                                  false, false);
   12421              : 
   12422           37 :     appendPQExpBuffer(q, "CREATE TYPE %s;\n",
   12423              :                       qualtypname);
   12424              : 
   12425           37 :     if (dopt->binary_upgrade)
   12426            2 :         binary_upgrade_extension_member(q, &tyinfo->dobj,
   12427              :                                         "TYPE", qtypname,
   12428            2 :                                         tyinfo->dobj.namespace->dobj.name);
   12429              : 
   12430           37 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   12431           37 :         ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
   12432           37 :                      ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
   12433              :                                   .namespace = tyinfo->dobj.namespace->dobj.name,
   12434              :                                   .owner = tyinfo->rolname,
   12435              :                                   .description = "TYPE",
   12436              :                                   .section = SECTION_PRE_DATA,
   12437              :                                   .createStmt = q->data,
   12438              :                                   .dropStmt = delq->data));
   12439              : 
   12440              :     /* Dump Type Comments and Security Labels */
   12441           37 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   12442           32 :         dumpComment(fout, "TYPE", qtypname,
   12443           32 :                     tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
   12444           32 :                     tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
   12445              : 
   12446           37 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
   12447            0 :         dumpSecLabel(fout, "TYPE", qtypname,
   12448            0 :                      tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
   12449            0 :                      tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
   12450              : 
   12451           37 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
   12452            0 :         dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
   12453              :                 qtypname, NULL,
   12454            0 :                 tyinfo->dobj.namespace->dobj.name,
   12455            0 :                 NULL, tyinfo->rolname, &tyinfo->dacl);
   12456              : 
   12457           37 :     destroyPQExpBuffer(q);
   12458           37 :     destroyPQExpBuffer(delq);
   12459           37 :     free(qtypname);
   12460           37 :     free(qualtypname);
   12461           37 : }
   12462              : 
   12463              : /*
   12464              :  * dumpBaseType
   12465              :  *    writes out to fout the queries to recreate a user-defined base type
   12466              :  */
   12467              : static void
   12468          283 : dumpBaseType(Archive *fout, const TypeInfo *tyinfo)
   12469              : {
   12470          283 :     DumpOptions *dopt = fout->dopt;
   12471          283 :     PQExpBuffer q = createPQExpBuffer();
   12472          283 :     PQExpBuffer delq = createPQExpBuffer();
   12473          283 :     PQExpBuffer query = createPQExpBuffer();
   12474              :     PGresult   *res;
   12475              :     char       *qtypname;
   12476              :     char       *qualtypname;
   12477              :     char       *typlen;
   12478              :     char       *typinput;
   12479              :     char       *typoutput;
   12480              :     char       *typreceive;
   12481              :     char       *typsend;
   12482              :     char       *typmodin;
   12483              :     char       *typmodout;
   12484              :     char       *typanalyze;
   12485              :     char       *typsubscript;
   12486              :     Oid         typreceiveoid;
   12487              :     Oid         typsendoid;
   12488              :     Oid         typmodinoid;
   12489              :     Oid         typmodoutoid;
   12490              :     Oid         typanalyzeoid;
   12491              :     Oid         typsubscriptoid;
   12492              :     char       *typcategory;
   12493              :     char       *typispreferred;
   12494              :     char       *typdelim;
   12495              :     char       *typbyval;
   12496              :     char       *typalign;
   12497              :     char       *typstorage;
   12498              :     char       *typcollatable;
   12499              :     char       *typdefault;
   12500          283 :     bool        typdefault_is_literal = false;
   12501              : 
   12502          283 :     if (!fout->is_prepared[PREPQUERY_DUMPBASETYPE])
   12503              :     {
   12504              :         /* Set up query for type-specific details */
   12505           40 :         appendPQExpBufferStr(query,
   12506              :                              "PREPARE dumpBaseType(pg_catalog.oid) AS\n"
   12507              :                              "SELECT typlen, "
   12508              :                              "typinput, typoutput, typreceive, typsend, "
   12509              :                              "typreceive::pg_catalog.oid AS typreceiveoid, "
   12510              :                              "typsend::pg_catalog.oid AS typsendoid, "
   12511              :                              "typanalyze, "
   12512              :                              "typanalyze::pg_catalog.oid AS typanalyzeoid, "
   12513              :                              "typdelim, typbyval, typalign, typstorage, "
   12514              :                              "typmodin, typmodout, "
   12515              :                              "typmodin::pg_catalog.oid AS typmodinoid, "
   12516              :                              "typmodout::pg_catalog.oid AS typmodoutoid, "
   12517              :                              "typcategory, typispreferred, "
   12518              :                              "(typcollation <> 0) AS typcollatable, "
   12519              :                              "pg_catalog.pg_get_expr(typdefaultbin, 0) AS typdefaultbin, typdefault, ");
   12520              : 
   12521           40 :         if (fout->remoteVersion >= 140000)
   12522           40 :             appendPQExpBufferStr(query,
   12523              :                                  "typsubscript, "
   12524              :                                  "typsubscript::pg_catalog.oid AS typsubscriptoid ");
   12525              :         else
   12526            0 :             appendPQExpBufferStr(query,
   12527              :                                  "'-' AS typsubscript, 0 AS typsubscriptoid ");
   12528              : 
   12529           40 :         appendPQExpBufferStr(query, "FROM pg_catalog.pg_type "
   12530              :                              "WHERE oid = $1");
   12531              : 
   12532           40 :         ExecuteSqlStatement(fout, query->data);
   12533              : 
   12534           40 :         fout->is_prepared[PREPQUERY_DUMPBASETYPE] = true;
   12535              :     }
   12536              : 
   12537          283 :     printfPQExpBuffer(query,
   12538              :                       "EXECUTE dumpBaseType('%u')",
   12539          283 :                       tyinfo->dobj.catId.oid);
   12540              : 
   12541          283 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   12542              : 
   12543          283 :     typlen = PQgetvalue(res, 0, PQfnumber(res, "typlen"));
   12544          283 :     typinput = PQgetvalue(res, 0, PQfnumber(res, "typinput"));
   12545          283 :     typoutput = PQgetvalue(res, 0, PQfnumber(res, "typoutput"));
   12546          283 :     typreceive = PQgetvalue(res, 0, PQfnumber(res, "typreceive"));
   12547          283 :     typsend = PQgetvalue(res, 0, PQfnumber(res, "typsend"));
   12548          283 :     typmodin = PQgetvalue(res, 0, PQfnumber(res, "typmodin"));
   12549          283 :     typmodout = PQgetvalue(res, 0, PQfnumber(res, "typmodout"));
   12550          283 :     typanalyze = PQgetvalue(res, 0, PQfnumber(res, "typanalyze"));
   12551          283 :     typsubscript = PQgetvalue(res, 0, PQfnumber(res, "typsubscript"));
   12552          283 :     typreceiveoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typreceiveoid")));
   12553          283 :     typsendoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typsendoid")));
   12554          283 :     typmodinoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typmodinoid")));
   12555          283 :     typmodoutoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typmodoutoid")));
   12556          283 :     typanalyzeoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typanalyzeoid")));
   12557          283 :     typsubscriptoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typsubscriptoid")));
   12558          283 :     typcategory = PQgetvalue(res, 0, PQfnumber(res, "typcategory"));
   12559          283 :     typispreferred = PQgetvalue(res, 0, PQfnumber(res, "typispreferred"));
   12560          283 :     typdelim = PQgetvalue(res, 0, PQfnumber(res, "typdelim"));
   12561          283 :     typbyval = PQgetvalue(res, 0, PQfnumber(res, "typbyval"));
   12562          283 :     typalign = PQgetvalue(res, 0, PQfnumber(res, "typalign"));
   12563          283 :     typstorage = PQgetvalue(res, 0, PQfnumber(res, "typstorage"));
   12564          283 :     typcollatable = PQgetvalue(res, 0, PQfnumber(res, "typcollatable"));
   12565          283 :     if (!PQgetisnull(res, 0, PQfnumber(res, "typdefaultbin")))
   12566            0 :         typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefaultbin"));
   12567          283 :     else if (!PQgetisnull(res, 0, PQfnumber(res, "typdefault")))
   12568              :     {
   12569           42 :         typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefault"));
   12570           42 :         typdefault_is_literal = true;   /* it needs quotes */
   12571              :     }
   12572              :     else
   12573          241 :         typdefault = NULL;
   12574              : 
   12575          283 :     qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
   12576          283 :     qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
   12577              : 
   12578              :     /*
   12579              :      * The reason we include CASCADE is that the circular dependency between
   12580              :      * the type and its I/O functions makes it impossible to drop the type any
   12581              :      * other way.
   12582              :      */
   12583          283 :     appendPQExpBuffer(delq, "DROP TYPE %s CASCADE;\n", qualtypname);
   12584              : 
   12585              :     /*
   12586              :      * We might already have a shell type, but setting pg_type_oid is
   12587              :      * harmless, and in any case we'd better set the array type OID.
   12588              :      */
   12589          283 :     if (dopt->binary_upgrade)
   12590            8 :         binary_upgrade_set_type_oids_by_type_oid(fout, q,
   12591            8 :                                                  tyinfo->dobj.catId.oid,
   12592              :                                                  false, false);
   12593              : 
   12594          283 :     appendPQExpBuffer(q,
   12595              :                       "CREATE TYPE %s (\n"
   12596              :                       "    INTERNALLENGTH = %s",
   12597              :                       qualtypname,
   12598          283 :                       (strcmp(typlen, "-1") == 0) ? "variable" : typlen);
   12599              : 
   12600              :     /* regproc result is sufficiently quoted already */
   12601          283 :     appendPQExpBuffer(q, ",\n    INPUT = %s", typinput);
   12602          283 :     appendPQExpBuffer(q, ",\n    OUTPUT = %s", typoutput);
   12603          283 :     if (OidIsValid(typreceiveoid))
   12604          210 :         appendPQExpBuffer(q, ",\n    RECEIVE = %s", typreceive);
   12605          283 :     if (OidIsValid(typsendoid))
   12606          210 :         appendPQExpBuffer(q, ",\n    SEND = %s", typsend);
   12607          283 :     if (OidIsValid(typmodinoid))
   12608           35 :         appendPQExpBuffer(q, ",\n    TYPMOD_IN = %s", typmodin);
   12609          283 :     if (OidIsValid(typmodoutoid))
   12610           35 :         appendPQExpBuffer(q, ",\n    TYPMOD_OUT = %s", typmodout);
   12611          283 :     if (OidIsValid(typanalyzeoid))
   12612            3 :         appendPQExpBuffer(q, ",\n    ANALYZE = %s", typanalyze);
   12613              : 
   12614          283 :     if (strcmp(typcollatable, "t") == 0)
   12615           30 :         appendPQExpBufferStr(q, ",\n    COLLATABLE = true");
   12616              : 
   12617          283 :     if (typdefault != NULL)
   12618              :     {
   12619           42 :         appendPQExpBufferStr(q, ",\n    DEFAULT = ");
   12620           42 :         if (typdefault_is_literal)
   12621           42 :             appendStringLiteralAH(q, typdefault, fout);
   12622              :         else
   12623            0 :             appendPQExpBufferStr(q, typdefault);
   12624              :     }
   12625              : 
   12626          283 :     if (OidIsValid(typsubscriptoid))
   12627           29 :         appendPQExpBuffer(q, ",\n    SUBSCRIPT = %s", typsubscript);
   12628              : 
   12629          283 :     if (OidIsValid(tyinfo->typelem))
   12630           26 :         appendPQExpBuffer(q, ",\n    ELEMENT = %s",
   12631           26 :                           getFormattedTypeName(fout, tyinfo->typelem,
   12632              :                                                zeroIsError));
   12633              : 
   12634          283 :     if (strcmp(typcategory, "U") != 0)
   12635              :     {
   12636          161 :         appendPQExpBufferStr(q, ",\n    CATEGORY = ");
   12637          161 :         appendStringLiteralAH(q, typcategory, fout);
   12638              :     }
   12639              : 
   12640          283 :     if (strcmp(typispreferred, "t") == 0)
   12641           29 :         appendPQExpBufferStr(q, ",\n    PREFERRED = true");
   12642              : 
   12643          283 :     if (typdelim && strcmp(typdelim, ",") != 0)
   12644              :     {
   12645            3 :         appendPQExpBufferStr(q, ",\n    DELIMITER = ");
   12646            3 :         appendStringLiteralAH(q, typdelim, fout);
   12647              :     }
   12648              : 
   12649          283 :     if (*typalign == TYPALIGN_CHAR)
   12650           12 :         appendPQExpBufferStr(q, ",\n    ALIGNMENT = char");
   12651          271 :     else if (*typalign == TYPALIGN_SHORT)
   12652            6 :         appendPQExpBufferStr(q, ",\n    ALIGNMENT = int2");
   12653          265 :     else if (*typalign == TYPALIGN_INT)
   12654          187 :         appendPQExpBufferStr(q, ",\n    ALIGNMENT = int4");
   12655           78 :     else if (*typalign == TYPALIGN_DOUBLE)
   12656           78 :         appendPQExpBufferStr(q, ",\n    ALIGNMENT = double");
   12657              : 
   12658          283 :     if (*typstorage == TYPSTORAGE_PLAIN)
   12659          208 :         appendPQExpBufferStr(q, ",\n    STORAGE = plain");
   12660           75 :     else if (*typstorage == TYPSTORAGE_EXTERNAL)
   12661            0 :         appendPQExpBufferStr(q, ",\n    STORAGE = external");
   12662           75 :     else if (*typstorage == TYPSTORAGE_EXTENDED)
   12663           66 :         appendPQExpBufferStr(q, ",\n    STORAGE = extended");
   12664            9 :     else if (*typstorage == TYPSTORAGE_MAIN)
   12665            9 :         appendPQExpBufferStr(q, ",\n    STORAGE = main");
   12666              : 
   12667          283 :     if (strcmp(typbyval, "t") == 0)
   12668          137 :         appendPQExpBufferStr(q, ",\n    PASSEDBYVALUE");
   12669              : 
   12670          283 :     appendPQExpBufferStr(q, "\n);\n");
   12671              : 
   12672          283 :     if (dopt->binary_upgrade)
   12673            8 :         binary_upgrade_extension_member(q, &tyinfo->dobj,
   12674              :                                         "TYPE", qtypname,
   12675            8 :                                         tyinfo->dobj.namespace->dobj.name);
   12676              : 
   12677          283 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   12678          283 :         ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
   12679          283 :                      ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
   12680              :                                   .namespace = tyinfo->dobj.namespace->dobj.name,
   12681              :                                   .owner = tyinfo->rolname,
   12682              :                                   .description = "TYPE",
   12683              :                                   .section = SECTION_PRE_DATA,
   12684              :                                   .createStmt = q->data,
   12685              :                                   .dropStmt = delq->data));
   12686              : 
   12687              :     /* Dump Type Comments and Security Labels */
   12688          283 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   12689          248 :         dumpComment(fout, "TYPE", qtypname,
   12690          248 :                     tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
   12691          248 :                     tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
   12692              : 
   12693          283 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
   12694            0 :         dumpSecLabel(fout, "TYPE", qtypname,
   12695            0 :                      tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
   12696            0 :                      tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
   12697              : 
   12698          283 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
   12699           32 :         dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
   12700              :                 qtypname, NULL,
   12701           32 :                 tyinfo->dobj.namespace->dobj.name,
   12702           32 :                 NULL, tyinfo->rolname, &tyinfo->dacl);
   12703              : 
   12704          283 :     PQclear(res);
   12705          283 :     destroyPQExpBuffer(q);
   12706          283 :     destroyPQExpBuffer(delq);
   12707          283 :     destroyPQExpBuffer(query);
   12708          283 :     free(qtypname);
   12709          283 :     free(qualtypname);
   12710          283 : }
   12711              : 
   12712              : /*
   12713              :  * dumpDomain
   12714              :  *    writes out to fout the queries to recreate a user-defined domain
   12715              :  */
   12716              : static void
   12717          152 : dumpDomain(Archive *fout, const TypeInfo *tyinfo)
   12718              : {
   12719          152 :     DumpOptions *dopt = fout->dopt;
   12720          152 :     PQExpBuffer q = createPQExpBuffer();
   12721          152 :     PQExpBuffer delq = createPQExpBuffer();
   12722          152 :     PQExpBuffer query = createPQExpBuffer();
   12723              :     PGresult   *res;
   12724              :     int         i;
   12725              :     char       *qtypname;
   12726              :     char       *qualtypname;
   12727              :     char       *typnotnull;
   12728              :     char       *typdefn;
   12729              :     char       *typdefault;
   12730              :     Oid         typcollation;
   12731          152 :     bool        typdefault_is_literal = false;
   12732              : 
   12733          152 :     if (!fout->is_prepared[PREPQUERY_DUMPDOMAIN])
   12734              :     {
   12735              :         /* Set up query for domain-specific details */
   12736           37 :         appendPQExpBufferStr(query,
   12737              :                              "PREPARE dumpDomain(pg_catalog.oid) AS\n");
   12738              : 
   12739           37 :         appendPQExpBufferStr(query, "SELECT t.typnotnull, "
   12740              :                              "pg_catalog.format_type(t.typbasetype, t.typtypmod) AS typdefn, "
   12741              :                              "pg_catalog.pg_get_expr(t.typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, "
   12742              :                              "t.typdefault, "
   12743              :                              "CASE WHEN t.typcollation <> u.typcollation "
   12744              :                              "THEN t.typcollation ELSE 0 END AS typcollation "
   12745              :                              "FROM pg_catalog.pg_type t "
   12746              :                              "LEFT JOIN pg_catalog.pg_type u ON (t.typbasetype = u.oid) "
   12747              :                              "WHERE t.oid = $1");
   12748              : 
   12749           37 :         ExecuteSqlStatement(fout, query->data);
   12750              : 
   12751           37 :         fout->is_prepared[PREPQUERY_DUMPDOMAIN] = true;
   12752              :     }
   12753              : 
   12754          152 :     printfPQExpBuffer(query,
   12755              :                       "EXECUTE dumpDomain('%u')",
   12756          152 :                       tyinfo->dobj.catId.oid);
   12757              : 
   12758          152 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   12759              : 
   12760          152 :     typnotnull = PQgetvalue(res, 0, PQfnumber(res, "typnotnull"));
   12761          152 :     typdefn = PQgetvalue(res, 0, PQfnumber(res, "typdefn"));
   12762          152 :     if (!PQgetisnull(res, 0, PQfnumber(res, "typdefaultbin")))
   12763           37 :         typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefaultbin"));
   12764          115 :     else if (!PQgetisnull(res, 0, PQfnumber(res, "typdefault")))
   12765              :     {
   12766            0 :         typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefault"));
   12767            0 :         typdefault_is_literal = true;   /* it needs quotes */
   12768              :     }
   12769              :     else
   12770          115 :         typdefault = NULL;
   12771          152 :     typcollation = atooid(PQgetvalue(res, 0, PQfnumber(res, "typcollation")));
   12772              : 
   12773          152 :     if (dopt->binary_upgrade)
   12774           25 :         binary_upgrade_set_type_oids_by_type_oid(fout, q,
   12775           25 :                                                  tyinfo->dobj.catId.oid,
   12776              :                                                  true,  /* force array type */
   12777              :                                                  false);    /* force multirange type */
   12778              : 
   12779          152 :     qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
   12780          152 :     qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
   12781              : 
   12782          152 :     appendPQExpBuffer(q,
   12783              :                       "CREATE DOMAIN %s AS %s",
   12784              :                       qualtypname,
   12785              :                       typdefn);
   12786              : 
   12787              :     /* Print collation only if different from base type's collation */
   12788          152 :     if (OidIsValid(typcollation))
   12789              :     {
   12790              :         CollInfo   *coll;
   12791              : 
   12792           32 :         coll = findCollationByOid(typcollation);
   12793           32 :         if (coll)
   12794           32 :             appendPQExpBuffer(q, " COLLATE %s", fmtQualifiedDumpable(coll));
   12795              :     }
   12796              : 
   12797              :     /*
   12798              :      * Print a not-null constraint if there's one.  In servers older than 17
   12799              :      * these don't have names, so just print it unadorned; in newer ones they
   12800              :      * do, but most of the time it's going to be the standard generated one,
   12801              :      * so omit the name in that case also.
   12802              :      */
   12803          152 :     if (typnotnull[0] == 't')
   12804              :     {
   12805           47 :         if (fout->remoteVersion < 170000 || tyinfo->notnull == NULL)
   12806            0 :             appendPQExpBufferStr(q, " NOT NULL");
   12807              :         else
   12808              :         {
   12809           47 :             ConstraintInfo *notnull = tyinfo->notnull;
   12810              : 
   12811           47 :             if (!notnull->separate)
   12812              :             {
   12813              :                 char       *default_name;
   12814              : 
   12815              :                 /* XXX should match ChooseConstraintName better */
   12816           47 :                 default_name = psprintf("%s_not_null", tyinfo->dobj.name);
   12817              : 
   12818           47 :                 if (strcmp(default_name, notnull->dobj.name) == 0)
   12819           15 :                     appendPQExpBufferStr(q, " NOT NULL");
   12820              :                 else
   12821           32 :                     appendPQExpBuffer(q, " CONSTRAINT %s %s",
   12822           32 :                                       fmtId(notnull->dobj.name), notnull->condef);
   12823           47 :                 free(default_name);
   12824              :             }
   12825              :         }
   12826              :     }
   12827              : 
   12828          152 :     if (typdefault != NULL)
   12829              :     {
   12830           37 :         appendPQExpBufferStr(q, " DEFAULT ");
   12831           37 :         if (typdefault_is_literal)
   12832            0 :             appendStringLiteralAH(q, typdefault, fout);
   12833              :         else
   12834           37 :             appendPQExpBufferStr(q, typdefault);
   12835              :     }
   12836              : 
   12837          152 :     PQclear(res);
   12838              : 
   12839              :     /*
   12840              :      * Add any CHECK constraints for the domain
   12841              :      */
   12842          259 :     for (i = 0; i < tyinfo->nDomChecks; i++)
   12843              :     {
   12844          107 :         ConstraintInfo *domcheck = &(tyinfo->domChecks[i]);
   12845              : 
   12846          107 :         if (!domcheck->separate && domcheck->contype == 'c')
   12847          102 :             appendPQExpBuffer(q, "\n\tCONSTRAINT %s %s",
   12848          102 :                               fmtId(domcheck->dobj.name), domcheck->condef);
   12849              :     }
   12850              : 
   12851          152 :     appendPQExpBufferStr(q, ";\n");
   12852              : 
   12853          152 :     appendPQExpBuffer(delq, "DROP DOMAIN %s;\n", qualtypname);
   12854              : 
   12855          152 :     if (dopt->binary_upgrade)
   12856           25 :         binary_upgrade_extension_member(q, &tyinfo->dobj,
   12857              :                                         "DOMAIN", qtypname,
   12858           25 :                                         tyinfo->dobj.namespace->dobj.name);
   12859              : 
   12860          152 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   12861          152 :         ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
   12862          152 :                      ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
   12863              :                                   .namespace = tyinfo->dobj.namespace->dobj.name,
   12864              :                                   .owner = tyinfo->rolname,
   12865              :                                   .description = "DOMAIN",
   12866              :                                   .section = SECTION_PRE_DATA,
   12867              :                                   .createStmt = q->data,
   12868              :                                   .dropStmt = delq->data));
   12869              : 
   12870              :     /* Dump Domain Comments and Security Labels */
   12871          152 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   12872            0 :         dumpComment(fout, "DOMAIN", qtypname,
   12873            0 :                     tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
   12874            0 :                     tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
   12875              : 
   12876          152 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
   12877            0 :         dumpSecLabel(fout, "DOMAIN", qtypname,
   12878            0 :                      tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
   12879            0 :                      tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
   12880              : 
   12881          152 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
   12882           32 :         dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
   12883              :                 qtypname, NULL,
   12884           32 :                 tyinfo->dobj.namespace->dobj.name,
   12885           32 :                 NULL, tyinfo->rolname, &tyinfo->dacl);
   12886              : 
   12887              :     /* Dump any per-constraint comments */
   12888          259 :     for (i = 0; i < tyinfo->nDomChecks; i++)
   12889              :     {
   12890          107 :         ConstraintInfo *domcheck = &(tyinfo->domChecks[i]);
   12891              :         PQExpBuffer conprefix;
   12892              : 
   12893              :         /* but only if the constraint itself was dumped here */
   12894          107 :         if (domcheck->separate)
   12895            5 :             continue;
   12896              : 
   12897          102 :         conprefix = createPQExpBuffer();
   12898          102 :         appendPQExpBuffer(conprefix, "CONSTRAINT %s ON DOMAIN",
   12899          102 :                           fmtId(domcheck->dobj.name));
   12900              : 
   12901          102 :         if (domcheck->dobj.dump & DUMP_COMPONENT_COMMENT)
   12902           32 :             dumpComment(fout, conprefix->data, qtypname,
   12903           32 :                         tyinfo->dobj.namespace->dobj.name,
   12904           32 :                         tyinfo->rolname,
   12905           32 :                         domcheck->dobj.catId, 0, tyinfo->dobj.dumpId);
   12906              : 
   12907          102 :         destroyPQExpBuffer(conprefix);
   12908              :     }
   12909              : 
   12910              :     /*
   12911              :      * And a comment on the not-null constraint, if there's one -- but only if
   12912              :      * the constraint itself was dumped here
   12913              :      */
   12914          152 :     if (tyinfo->notnull != NULL && !tyinfo->notnull->separate)
   12915              :     {
   12916           47 :         PQExpBuffer conprefix = createPQExpBuffer();
   12917              : 
   12918           47 :         appendPQExpBuffer(conprefix, "CONSTRAINT %s ON DOMAIN",
   12919           47 :                           fmtId(tyinfo->notnull->dobj.name));
   12920              : 
   12921           47 :         if (tyinfo->notnull->dobj.dump & DUMP_COMPONENT_COMMENT)
   12922           32 :             dumpComment(fout, conprefix->data, qtypname,
   12923           32 :                         tyinfo->dobj.namespace->dobj.name,
   12924           32 :                         tyinfo->rolname,
   12925           32 :                         tyinfo->notnull->dobj.catId, 0, tyinfo->dobj.dumpId);
   12926           47 :         destroyPQExpBuffer(conprefix);
   12927              :     }
   12928              : 
   12929          152 :     destroyPQExpBuffer(q);
   12930          152 :     destroyPQExpBuffer(delq);
   12931          152 :     destroyPQExpBuffer(query);
   12932          152 :     free(qtypname);
   12933          152 :     free(qualtypname);
   12934          152 : }
   12935              : 
   12936              : /*
   12937              :  * dumpCompositeType
   12938              :  *    writes out to fout the queries to recreate a user-defined stand-alone
   12939              :  *    composite type
   12940              :  */
   12941              : static void
   12942          130 : dumpCompositeType(Archive *fout, const TypeInfo *tyinfo)
   12943              : {
   12944          130 :     DumpOptions *dopt = fout->dopt;
   12945          130 :     PQExpBuffer q = createPQExpBuffer();
   12946          130 :     PQExpBuffer dropped = createPQExpBuffer();
   12947          130 :     PQExpBuffer delq = createPQExpBuffer();
   12948          130 :     PQExpBuffer query = createPQExpBuffer();
   12949              :     PGresult   *res;
   12950              :     char       *qtypname;
   12951              :     char       *qualtypname;
   12952              :     int         ntups;
   12953              :     int         i_attname;
   12954              :     int         i_atttypdefn;
   12955              :     int         i_attlen;
   12956              :     int         i_attalign;
   12957              :     int         i_attisdropped;
   12958              :     int         i_attcollation;
   12959              :     int         i;
   12960              :     int         actual_atts;
   12961              : 
   12962          130 :     if (!fout->is_prepared[PREPQUERY_DUMPCOMPOSITETYPE])
   12963              :     {
   12964              :         /*
   12965              :          * Set up query for type-specific details.
   12966              :          *
   12967              :          * Since we only want to dump COLLATE clauses for attributes whose
   12968              :          * collation is different from their type's default, we use a CASE
   12969              :          * here to suppress uninteresting attcollations cheaply.  atttypid
   12970              :          * will be 0 for dropped columns; collation does not matter for those.
   12971              :          */
   12972           55 :         appendPQExpBufferStr(query,
   12973              :                              "PREPARE dumpCompositeType(pg_catalog.oid) AS\n"
   12974              :                              "SELECT a.attname, a.attnum, "
   12975              :                              "pg_catalog.format_type(a.atttypid, a.atttypmod) AS atttypdefn, "
   12976              :                              "a.attlen, a.attalign, a.attisdropped, "
   12977              :                              "CASE WHEN a.attcollation <> at.typcollation "
   12978              :                              "THEN a.attcollation ELSE 0 END AS attcollation "
   12979              :                              "FROM pg_catalog.pg_type ct "
   12980              :                              "JOIN pg_catalog.pg_attribute a ON a.attrelid = ct.typrelid "
   12981              :                              "LEFT JOIN pg_catalog.pg_type at ON at.oid = a.atttypid "
   12982              :                              "WHERE ct.oid = $1 "
   12983              :                              "ORDER BY a.attnum");
   12984              : 
   12985           55 :         ExecuteSqlStatement(fout, query->data);
   12986              : 
   12987           55 :         fout->is_prepared[PREPQUERY_DUMPCOMPOSITETYPE] = true;
   12988              :     }
   12989              : 
   12990          130 :     printfPQExpBuffer(query,
   12991              :                       "EXECUTE dumpCompositeType('%u')",
   12992          130 :                       tyinfo->dobj.catId.oid);
   12993              : 
   12994          130 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   12995              : 
   12996          130 :     ntups = PQntuples(res);
   12997              : 
   12998          130 :     i_attname = PQfnumber(res, "attname");
   12999          130 :     i_atttypdefn = PQfnumber(res, "atttypdefn");
   13000          130 :     i_attlen = PQfnumber(res, "attlen");
   13001          130 :     i_attalign = PQfnumber(res, "attalign");
   13002          130 :     i_attisdropped = PQfnumber(res, "attisdropped");
   13003          130 :     i_attcollation = PQfnumber(res, "attcollation");
   13004              : 
   13005          130 :     if (dopt->binary_upgrade)
   13006              :     {
   13007           18 :         binary_upgrade_set_type_oids_by_type_oid(fout, q,
   13008           18 :                                                  tyinfo->dobj.catId.oid,
   13009              :                                                  false, false);
   13010           18 :         binary_upgrade_set_pg_class_oids(fout, q, tyinfo->typrelid);
   13011              :     }
   13012              : 
   13013          130 :     qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
   13014          130 :     qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
   13015              : 
   13016          130 :     appendPQExpBuffer(q, "CREATE TYPE %s AS (",
   13017              :                       qualtypname);
   13018              : 
   13019          130 :     actual_atts = 0;
   13020          412 :     for (i = 0; i < ntups; i++)
   13021              :     {
   13022              :         char       *attname;
   13023              :         char       *atttypdefn;
   13024              :         char       *attlen;
   13025              :         char       *attalign;
   13026              :         bool        attisdropped;
   13027              :         Oid         attcollation;
   13028              : 
   13029          282 :         attname = PQgetvalue(res, i, i_attname);
   13030          282 :         atttypdefn = PQgetvalue(res, i, i_atttypdefn);
   13031          282 :         attlen = PQgetvalue(res, i, i_attlen);
   13032          282 :         attalign = PQgetvalue(res, i, i_attalign);
   13033          282 :         attisdropped = (PQgetvalue(res, i, i_attisdropped)[0] == 't');
   13034          282 :         attcollation = atooid(PQgetvalue(res, i, i_attcollation));
   13035              : 
   13036          282 :         if (attisdropped && !dopt->binary_upgrade)
   13037            8 :             continue;
   13038              : 
   13039              :         /* Format properly if not first attr */
   13040          274 :         if (actual_atts++ > 0)
   13041          144 :             appendPQExpBufferChar(q, ',');
   13042          274 :         appendPQExpBufferStr(q, "\n\t");
   13043              : 
   13044          274 :         if (!attisdropped)
   13045              :         {
   13046          272 :             appendPQExpBuffer(q, "%s %s", fmtId(attname), atttypdefn);
   13047              : 
   13048              :             /* Add collation if not default for the column type */
   13049          272 :             if (OidIsValid(attcollation))
   13050              :             {
   13051              :                 CollInfo   *coll;
   13052              : 
   13053            0 :                 coll = findCollationByOid(attcollation);
   13054            0 :                 if (coll)
   13055            0 :                     appendPQExpBuffer(q, " COLLATE %s",
   13056            0 :                                       fmtQualifiedDumpable(coll));
   13057              :             }
   13058              :         }
   13059              :         else
   13060              :         {
   13061              :             /*
   13062              :              * This is a dropped attribute and we're in binary_upgrade mode.
   13063              :              * Insert a placeholder for it in the CREATE TYPE command, and set
   13064              :              * length and alignment with direct UPDATE to the catalogs
   13065              :              * afterwards. See similar code in dumpTableSchema().
   13066              :              */
   13067            2 :             appendPQExpBuffer(q, "%s INTEGER /* dummy */", fmtId(attname));
   13068              : 
   13069              :             /* stash separately for insertion after the CREATE TYPE */
   13070            2 :             appendPQExpBufferStr(dropped,
   13071              :                                  "\n-- For binary upgrade, recreate dropped column.\n");
   13072            2 :             appendPQExpBuffer(dropped, "UPDATE pg_catalog.pg_attribute\n"
   13073              :                               "SET attlen = %s, "
   13074              :                               "attalign = '%s', attbyval = false\n"
   13075              :                               "WHERE attname = ", attlen, attalign);
   13076            2 :             appendStringLiteralAH(dropped, attname, fout);
   13077            2 :             appendPQExpBufferStr(dropped, "\n  AND attrelid = ");
   13078            2 :             appendStringLiteralAH(dropped, qualtypname, fout);
   13079            2 :             appendPQExpBufferStr(dropped, "::pg_catalog.regclass;\n");
   13080              : 
   13081            2 :             appendPQExpBuffer(dropped, "ALTER TYPE %s ",
   13082              :                               qualtypname);
   13083            2 :             appendPQExpBuffer(dropped, "DROP ATTRIBUTE %s;\n",
   13084              :                               fmtId(attname));
   13085              :         }
   13086              :     }
   13087          130 :     appendPQExpBufferStr(q, "\n);\n");
   13088          130 :     appendPQExpBufferStr(q, dropped->data);
   13089              : 
   13090          130 :     appendPQExpBuffer(delq, "DROP TYPE %s;\n", qualtypname);
   13091              : 
   13092          130 :     if (dopt->binary_upgrade)
   13093           18 :         binary_upgrade_extension_member(q, &tyinfo->dobj,
   13094              :                                         "TYPE", qtypname,
   13095           18 :                                         tyinfo->dobj.namespace->dobj.name);
   13096              : 
   13097          130 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   13098          113 :         ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
   13099          113 :                      ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
   13100              :                                   .namespace = tyinfo->dobj.namespace->dobj.name,
   13101              :                                   .owner = tyinfo->rolname,
   13102              :                                   .description = "TYPE",
   13103              :                                   .section = SECTION_PRE_DATA,
   13104              :                                   .createStmt = q->data,
   13105              :                                   .dropStmt = delq->data));
   13106              : 
   13107              : 
   13108              :     /* Dump Type Comments and Security Labels */
   13109          130 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   13110           32 :         dumpComment(fout, "TYPE", qtypname,
   13111           32 :                     tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
   13112           32 :                     tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
   13113              : 
   13114          130 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
   13115            0 :         dumpSecLabel(fout, "TYPE", qtypname,
   13116            0 :                      tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
   13117            0 :                      tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
   13118              : 
   13119          130 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
   13120           18 :         dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
   13121              :                 qtypname, NULL,
   13122           18 :                 tyinfo->dobj.namespace->dobj.name,
   13123           18 :                 NULL, tyinfo->rolname, &tyinfo->dacl);
   13124              : 
   13125              :     /* Dump any per-column comments */
   13126          130 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   13127           32 :         dumpCompositeTypeColComments(fout, tyinfo, res);
   13128              : 
   13129          130 :     PQclear(res);
   13130          130 :     destroyPQExpBuffer(q);
   13131          130 :     destroyPQExpBuffer(dropped);
   13132          130 :     destroyPQExpBuffer(delq);
   13133          130 :     destroyPQExpBuffer(query);
   13134          130 :     free(qtypname);
   13135          130 :     free(qualtypname);
   13136          130 : }
   13137              : 
   13138              : /*
   13139              :  * dumpCompositeTypeColComments
   13140              :  *    writes out to fout the queries to recreate comments on the columns of
   13141              :  *    a user-defined stand-alone composite type.
   13142              :  *
   13143              :  * The caller has already made a query to collect the names and attnums
   13144              :  * of the type's columns, so we just pass that result into here rather
   13145              :  * than reading them again.
   13146              :  */
   13147              : static void
   13148           32 : dumpCompositeTypeColComments(Archive *fout, const TypeInfo *tyinfo,
   13149              :                              PGresult *res)
   13150              : {
   13151              :     CommentItem *comments;
   13152              :     int         ncomments;
   13153              :     PQExpBuffer query;
   13154              :     PQExpBuffer target;
   13155              :     int         i;
   13156              :     int         ntups;
   13157              :     int         i_attname;
   13158              :     int         i_attnum;
   13159              :     int         i_attisdropped;
   13160              : 
   13161              :     /* do nothing, if --no-comments is supplied */
   13162           32 :     if (fout->dopt->no_comments)
   13163            0 :         return;
   13164              : 
   13165              :     /* Search for comments associated with type's pg_class OID */
   13166           32 :     ncomments = findComments(RelationRelationId, tyinfo->typrelid,
   13167              :                              &comments);
   13168              : 
   13169              :     /* If no comments exist, we're done */
   13170           32 :     if (ncomments <= 0)
   13171            0 :         return;
   13172              : 
   13173              :     /* Build COMMENT ON statements */
   13174           32 :     query = createPQExpBuffer();
   13175           32 :     target = createPQExpBuffer();
   13176              : 
   13177           32 :     ntups = PQntuples(res);
   13178           32 :     i_attnum = PQfnumber(res, "attnum");
   13179           32 :     i_attname = PQfnumber(res, "attname");
   13180           32 :     i_attisdropped = PQfnumber(res, "attisdropped");
   13181           64 :     while (ncomments > 0)
   13182              :     {
   13183              :         const char *attname;
   13184              : 
   13185           32 :         attname = NULL;
   13186           32 :         for (i = 0; i < ntups; i++)
   13187              :         {
   13188           32 :             if (atoi(PQgetvalue(res, i, i_attnum)) == comments->objsubid &&
   13189           32 :                 PQgetvalue(res, i, i_attisdropped)[0] != 't')
   13190              :             {
   13191           32 :                 attname = PQgetvalue(res, i, i_attname);
   13192           32 :                 break;
   13193              :             }
   13194              :         }
   13195           32 :         if (attname)            /* just in case we don't find it */
   13196              :         {
   13197           32 :             const char *descr = comments->descr;
   13198              : 
   13199           32 :             resetPQExpBuffer(target);
   13200           32 :             appendPQExpBuffer(target, "COLUMN %s.",
   13201           32 :                               fmtId(tyinfo->dobj.name));
   13202           32 :             appendPQExpBufferStr(target, fmtId(attname));
   13203              : 
   13204           32 :             resetPQExpBuffer(query);
   13205           32 :             appendPQExpBuffer(query, "COMMENT ON COLUMN %s.",
   13206           32 :                               fmtQualifiedDumpable(tyinfo));
   13207           32 :             appendPQExpBuffer(query, "%s IS ", fmtId(attname));
   13208           32 :             appendStringLiteralAH(query, descr, fout);
   13209           32 :             appendPQExpBufferStr(query, ";\n");
   13210              : 
   13211           32 :             ArchiveEntry(fout, nilCatalogId, createDumpId(),
   13212           32 :                          ARCHIVE_OPTS(.tag = target->data,
   13213              :                                       .namespace = tyinfo->dobj.namespace->dobj.name,
   13214              :                                       .owner = tyinfo->rolname,
   13215              :                                       .description = "COMMENT",
   13216              :                                       .section = SECTION_NONE,
   13217              :                                       .createStmt = query->data,
   13218              :                                       .deps = &(tyinfo->dobj.dumpId),
   13219              :                                       .nDeps = 1));
   13220              :         }
   13221              : 
   13222           32 :         comments++;
   13223           32 :         ncomments--;
   13224              :     }
   13225              : 
   13226           32 :     destroyPQExpBuffer(query);
   13227           32 :     destroyPQExpBuffer(target);
   13228              : }
   13229              : 
   13230              : /*
   13231              :  * dumpShellType
   13232              :  *    writes out to fout the queries to create a shell type
   13233              :  *
   13234              :  * We dump a shell definition in advance of the I/O functions for the type.
   13235              :  */
   13236              : static void
   13237           73 : dumpShellType(Archive *fout, const ShellTypeInfo *stinfo)
   13238              : {
   13239           73 :     DumpOptions *dopt = fout->dopt;
   13240              :     PQExpBuffer q;
   13241              : 
   13242              :     /* Do nothing if not dumping schema */
   13243           73 :     if (!dopt->dumpSchema)
   13244            6 :         return;
   13245              : 
   13246           67 :     q = createPQExpBuffer();
   13247              : 
   13248              :     /*
   13249              :      * Note the lack of a DROP command for the shell type; any required DROP
   13250              :      * is driven off the base type entry, instead.  This interacts with
   13251              :      * _printTocEntry()'s use of the presence of a DROP command to decide
   13252              :      * whether an entry needs an ALTER OWNER command.  We don't want to alter
   13253              :      * the shell type's owner immediately on creation; that should happen only
   13254              :      * after it's filled in, otherwise the backend complains.
   13255              :      */
   13256              : 
   13257           67 :     if (dopt->binary_upgrade)
   13258            8 :         binary_upgrade_set_type_oids_by_type_oid(fout, q,
   13259            8 :                                                  stinfo->baseType->dobj.catId.oid,
   13260              :                                                  false, false);
   13261              : 
   13262           67 :     appendPQExpBuffer(q, "CREATE TYPE %s;\n",
   13263           67 :                       fmtQualifiedDumpable(stinfo));
   13264              : 
   13265           67 :     if (stinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   13266           67 :         ArchiveEntry(fout, stinfo->dobj.catId, stinfo->dobj.dumpId,
   13267           67 :                      ARCHIVE_OPTS(.tag = stinfo->dobj.name,
   13268              :                                   .namespace = stinfo->dobj.namespace->dobj.name,
   13269              :                                   .owner = stinfo->baseType->rolname,
   13270              :                                   .description = "SHELL TYPE",
   13271              :                                   .section = SECTION_PRE_DATA,
   13272              :                                   .createStmt = q->data));
   13273              : 
   13274           67 :     destroyPQExpBuffer(q);
   13275              : }
   13276              : 
   13277              : /*
   13278              :  * dumpProcLang
   13279              :  *        writes out to fout the queries to recreate a user-defined
   13280              :  *        procedural language
   13281              :  */
   13282              : static void
   13283           82 : dumpProcLang(Archive *fout, const ProcLangInfo *plang)
   13284              : {
   13285           82 :     DumpOptions *dopt = fout->dopt;
   13286              :     PQExpBuffer defqry;
   13287              :     PQExpBuffer delqry;
   13288              :     bool        useParams;
   13289              :     char       *qlanname;
   13290              :     FuncInfo   *funcInfo;
   13291           82 :     FuncInfo   *inlineInfo = NULL;
   13292           82 :     FuncInfo   *validatorInfo = NULL;
   13293              : 
   13294              :     /* Do nothing if not dumping schema */
   13295           82 :     if (!dopt->dumpSchema)
   13296           13 :         return;
   13297              : 
   13298              :     /*
   13299              :      * Try to find the support function(s).  It is not an error if we don't
   13300              :      * find them --- if the functions are in the pg_catalog schema, as is
   13301              :      * standard in 8.1 and up, then we won't have loaded them. (In this case
   13302              :      * we will emit a parameterless CREATE LANGUAGE command, which will
   13303              :      * require PL template knowledge in the backend to reload.)
   13304              :      */
   13305              : 
   13306           69 :     funcInfo = findFuncByOid(plang->lanplcallfoid);
   13307           69 :     if (funcInfo != NULL && !funcInfo->dobj.dump)
   13308            2 :         funcInfo = NULL;        /* treat not-dumped same as not-found */
   13309              : 
   13310           69 :     if (OidIsValid(plang->laninline))
   13311              :     {
   13312           38 :         inlineInfo = findFuncByOid(plang->laninline);
   13313           38 :         if (inlineInfo != NULL && !inlineInfo->dobj.dump)
   13314            1 :             inlineInfo = NULL;
   13315              :     }
   13316              : 
   13317           69 :     if (OidIsValid(plang->lanvalidator))
   13318              :     {
   13319           38 :         validatorInfo = findFuncByOid(plang->lanvalidator);
   13320           38 :         if (validatorInfo != NULL && !validatorInfo->dobj.dump)
   13321            1 :             validatorInfo = NULL;
   13322              :     }
   13323              : 
   13324              :     /*
   13325              :      * If the functions are dumpable then emit a complete CREATE LANGUAGE with
   13326              :      * parameters.  Otherwise, we'll write a parameterless command, which will
   13327              :      * be interpreted as CREATE EXTENSION.
   13328              :      */
   13329           30 :     useParams = (funcInfo != NULL &&
   13330          129 :                  (inlineInfo != NULL || !OidIsValid(plang->laninline)) &&
   13331           30 :                  (validatorInfo != NULL || !OidIsValid(plang->lanvalidator)));
   13332              : 
   13333           69 :     defqry = createPQExpBuffer();
   13334           69 :     delqry = createPQExpBuffer();
   13335              : 
   13336           69 :     qlanname = pg_strdup(fmtId(plang->dobj.name));
   13337              : 
   13338           69 :     appendPQExpBuffer(delqry, "DROP PROCEDURAL LANGUAGE %s;\n",
   13339              :                       qlanname);
   13340              : 
   13341           69 :     if (useParams)
   13342              :     {
   13343           30 :         appendPQExpBuffer(defqry, "CREATE %sPROCEDURAL LANGUAGE %s",
   13344           30 :                           plang->lanpltrusted ? "TRUSTED " : "",
   13345              :                           qlanname);
   13346           30 :         appendPQExpBuffer(defqry, " HANDLER %s",
   13347           30 :                           fmtQualifiedDumpable(funcInfo));
   13348           30 :         if (OidIsValid(plang->laninline))
   13349            0 :             appendPQExpBuffer(defqry, " INLINE %s",
   13350            0 :                               fmtQualifiedDumpable(inlineInfo));
   13351           30 :         if (OidIsValid(plang->lanvalidator))
   13352            0 :             appendPQExpBuffer(defqry, " VALIDATOR %s",
   13353            0 :                               fmtQualifiedDumpable(validatorInfo));
   13354              :     }
   13355              :     else
   13356              :     {
   13357              :         /*
   13358              :          * If not dumping parameters, then use CREATE OR REPLACE so that the
   13359              :          * command will not fail if the language is preinstalled in the target
   13360              :          * database.
   13361              :          *
   13362              :          * Modern servers will interpret this as CREATE EXTENSION IF NOT
   13363              :          * EXISTS; perhaps we should emit that instead?  But it might just add
   13364              :          * confusion.
   13365              :          */
   13366           39 :         appendPQExpBuffer(defqry, "CREATE OR REPLACE PROCEDURAL LANGUAGE %s",
   13367              :                           qlanname);
   13368              :     }
   13369           69 :     appendPQExpBufferStr(defqry, ";\n");
   13370              : 
   13371           69 :     if (dopt->binary_upgrade)
   13372            2 :         binary_upgrade_extension_member(defqry, &plang->dobj,
   13373              :                                         "LANGUAGE", qlanname, NULL);
   13374              : 
   13375           69 :     if (plang->dobj.dump & DUMP_COMPONENT_DEFINITION)
   13376           31 :         ArchiveEntry(fout, plang->dobj.catId, plang->dobj.dumpId,
   13377           31 :                      ARCHIVE_OPTS(.tag = plang->dobj.name,
   13378              :                                   .owner = plang->lanowner,
   13379              :                                   .description = "PROCEDURAL LANGUAGE",
   13380              :                                   .section = SECTION_PRE_DATA,
   13381              :                                   .createStmt = defqry->data,
   13382              :                                   .dropStmt = delqry->data,
   13383              :                                   ));
   13384              : 
   13385              :     /* Dump Proc Lang Comments and Security Labels */
   13386           69 :     if (plang->dobj.dump & DUMP_COMPONENT_COMMENT)
   13387            0 :         dumpComment(fout, "LANGUAGE", qlanname,
   13388            0 :                     NULL, plang->lanowner,
   13389            0 :                     plang->dobj.catId, 0, plang->dobj.dumpId);
   13390              : 
   13391           69 :     if (plang->dobj.dump & DUMP_COMPONENT_SECLABEL)
   13392            0 :         dumpSecLabel(fout, "LANGUAGE", qlanname,
   13393            0 :                      NULL, plang->lanowner,
   13394            0 :                      plang->dobj.catId, 0, plang->dobj.dumpId);
   13395              : 
   13396           69 :     if (plang->lanpltrusted && plang->dobj.dump & DUMP_COMPONENT_ACL)
   13397           38 :         dumpACL(fout, plang->dobj.dumpId, InvalidDumpId, "LANGUAGE",
   13398              :                 qlanname, NULL, NULL,
   13399           38 :                 NULL, plang->lanowner, &plang->dacl);
   13400              : 
   13401           69 :     free(qlanname);
   13402              : 
   13403           69 :     destroyPQExpBuffer(defqry);
   13404           69 :     destroyPQExpBuffer(delqry);
   13405              : }
   13406              : 
   13407              : /*
   13408              :  * format_function_arguments: generate function name and argument list
   13409              :  *
   13410              :  * This is used when we can rely on pg_get_function_arguments to format
   13411              :  * the argument list.  Note, however, that pg_get_function_arguments
   13412              :  * does not special-case zero-argument aggregates.
   13413              :  */
   13414              : static char *
   13415         4118 : format_function_arguments(const FuncInfo *finfo, const char *funcargs, bool is_agg)
   13416              : {
   13417              :     PQExpBufferData fn;
   13418              : 
   13419         4118 :     initPQExpBuffer(&fn);
   13420         4118 :     appendPQExpBufferStr(&fn, fmtId(finfo->dobj.name));
   13421         4118 :     if (is_agg && finfo->nargs == 0)
   13422           80 :         appendPQExpBufferStr(&fn, "(*)");
   13423              :     else
   13424         4038 :         appendPQExpBuffer(&fn, "(%s)", funcargs);
   13425         4118 :     return fn.data;
   13426              : }
   13427              : 
   13428              : /*
   13429              :  * format_function_signature: generate function name and argument list
   13430              :  *
   13431              :  * Only a minimal list of input argument types is generated; this is
   13432              :  * sufficient to reference the function, but not to define it.
   13433              :  *
   13434              :  * If honor_quotes is false then the function name is never quoted.
   13435              :  * This is appropriate for use in TOC tags, but not in SQL commands.
   13436              :  */
   13437              : static char *
   13438         2167 : format_function_signature(Archive *fout, const FuncInfo *finfo, bool honor_quotes)
   13439              : {
   13440              :     PQExpBufferData fn;
   13441              :     int         j;
   13442              : 
   13443         2167 :     initPQExpBuffer(&fn);
   13444         2167 :     if (honor_quotes)
   13445          393 :         appendPQExpBuffer(&fn, "%s(", fmtId(finfo->dobj.name));
   13446              :     else
   13447         1774 :         appendPQExpBuffer(&fn, "%s(", finfo->dobj.name);
   13448         3968 :     for (j = 0; j < finfo->nargs; j++)
   13449              :     {
   13450         1801 :         if (j > 0)
   13451          422 :             appendPQExpBufferStr(&fn, ", ");
   13452              : 
   13453         1801 :         appendPQExpBufferStr(&fn,
   13454         1801 :                              getFormattedTypeName(fout, finfo->argtypes[j],
   13455              :                                                   zeroIsError));
   13456              :     }
   13457         2167 :     appendPQExpBufferChar(&fn, ')');
   13458         2167 :     return fn.data;
   13459              : }
   13460              : 
   13461              : 
   13462              : /*
   13463              :  * dumpFunc:
   13464              :  *    dump out one function
   13465              :  */
   13466              : static void
   13467         1836 : dumpFunc(Archive *fout, const FuncInfo *finfo)
   13468              : {
   13469         1836 :     DumpOptions *dopt = fout->dopt;
   13470              :     PQExpBuffer query;
   13471              :     PQExpBuffer q;
   13472              :     PQExpBuffer delqry;
   13473              :     PQExpBuffer asPart;
   13474              :     PGresult   *res;
   13475              :     char       *funcsig;        /* identity signature */
   13476         1836 :     char       *funcfullsig = NULL; /* full signature */
   13477              :     char       *funcsig_tag;
   13478              :     char       *qual_funcsig;
   13479              :     char       *proretset;
   13480              :     char       *prosrc;
   13481              :     char       *probin;
   13482              :     char       *prosqlbody;
   13483              :     char       *funcargs;
   13484              :     char       *funciargs;
   13485              :     char       *funcresult;
   13486              :     char       *protrftypes;
   13487              :     char       *prokind;
   13488              :     char       *provolatile;
   13489              :     char       *proisstrict;
   13490              :     char       *prosecdef;
   13491              :     char       *proleakproof;
   13492              :     char       *proconfig;
   13493              :     char       *procost;
   13494              :     char       *prorows;
   13495              :     char       *prosupport;
   13496              :     char       *proparallel;
   13497              :     char       *lanname;
   13498         1836 :     char      **configitems = NULL;
   13499         1836 :     int         nconfigitems = 0;
   13500              :     const char *keyword;
   13501              : 
   13502              :     /* Do nothing if not dumping schema */
   13503         1836 :     if (!dopt->dumpSchema)
   13504           62 :         return;
   13505              : 
   13506         1774 :     query = createPQExpBuffer();
   13507         1774 :     q = createPQExpBuffer();
   13508         1774 :     delqry = createPQExpBuffer();
   13509         1774 :     asPart = createPQExpBuffer();
   13510              : 
   13511         1774 :     if (!fout->is_prepared[PREPQUERY_DUMPFUNC])
   13512              :     {
   13513              :         /* Set up query for function-specific details */
   13514           74 :         appendPQExpBufferStr(query,
   13515              :                              "PREPARE dumpFunc(pg_catalog.oid) AS\n");
   13516              : 
   13517           74 :         appendPQExpBufferStr(query,
   13518              :                              "SELECT\n"
   13519              :                              "proretset,\n"
   13520              :                              "prosrc,\n"
   13521              :                              "probin,\n"
   13522              :                              "provolatile,\n"
   13523              :                              "proisstrict,\n"
   13524              :                              "prosecdef,\n"
   13525              :                              "lanname,\n"
   13526              :                              "proconfig,\n"
   13527              :                              "procost,\n"
   13528              :                              "prorows,\n"
   13529              :                              "pg_catalog.pg_get_function_arguments(p.oid) AS funcargs,\n"
   13530              :                              "pg_catalog.pg_get_function_identity_arguments(p.oid) AS funciargs,\n"
   13531              :                              "pg_catalog.pg_get_function_result(p.oid) AS funcresult,\n"
   13532              :                              "proleakproof,\n");
   13533              : 
   13534           74 :         if (fout->remoteVersion >= 90500)
   13535           74 :             appendPQExpBufferStr(query,
   13536              :                                  "array_to_string(protrftypes, ' ') AS protrftypes,\n");
   13537              :         else
   13538            0 :             appendPQExpBufferStr(query,
   13539              :                                  "NULL AS protrftypes,\n");
   13540              : 
   13541           74 :         if (fout->remoteVersion >= 90600)
   13542           74 :             appendPQExpBufferStr(query,
   13543              :                                  "proparallel,\n");
   13544              :         else
   13545            0 :             appendPQExpBufferStr(query,
   13546              :                                  "'u' AS proparallel,\n");
   13547              : 
   13548           74 :         if (fout->remoteVersion >= 110000)
   13549           74 :             appendPQExpBufferStr(query,
   13550              :                                  "prokind,\n");
   13551              :         else
   13552            0 :             appendPQExpBufferStr(query,
   13553              :                                  "CASE WHEN proiswindow THEN 'w' ELSE 'f' END AS prokind,\n");
   13554              : 
   13555           74 :         if (fout->remoteVersion >= 120000)
   13556           74 :             appendPQExpBufferStr(query,
   13557              :                                  "prosupport,\n");
   13558              :         else
   13559            0 :             appendPQExpBufferStr(query,
   13560              :                                  "'-' AS prosupport,\n");
   13561              : 
   13562           74 :         if (fout->remoteVersion >= 140000)
   13563           74 :             appendPQExpBufferStr(query,
   13564              :                                  "pg_get_function_sqlbody(p.oid) AS prosqlbody\n");
   13565              :         else
   13566            0 :             appendPQExpBufferStr(query,
   13567              :                                  "NULL AS prosqlbody\n");
   13568              : 
   13569           74 :         appendPQExpBufferStr(query,
   13570              :                              "FROM pg_catalog.pg_proc p, pg_catalog.pg_language l\n"
   13571              :                              "WHERE p.oid = $1 "
   13572              :                              "AND l.oid = p.prolang");
   13573              : 
   13574           74 :         ExecuteSqlStatement(fout, query->data);
   13575              : 
   13576           74 :         fout->is_prepared[PREPQUERY_DUMPFUNC] = true;
   13577              :     }
   13578              : 
   13579         1774 :     printfPQExpBuffer(query,
   13580              :                       "EXECUTE dumpFunc('%u')",
   13581         1774 :                       finfo->dobj.catId.oid);
   13582              : 
   13583         1774 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   13584              : 
   13585         1774 :     proretset = PQgetvalue(res, 0, PQfnumber(res, "proretset"));
   13586         1774 :     if (PQgetisnull(res, 0, PQfnumber(res, "prosqlbody")))
   13587              :     {
   13588         1726 :         prosrc = PQgetvalue(res, 0, PQfnumber(res, "prosrc"));
   13589         1726 :         probin = PQgetvalue(res, 0, PQfnumber(res, "probin"));
   13590         1726 :         prosqlbody = NULL;
   13591              :     }
   13592              :     else
   13593              :     {
   13594           48 :         prosrc = NULL;
   13595           48 :         probin = NULL;
   13596           48 :         prosqlbody = PQgetvalue(res, 0, PQfnumber(res, "prosqlbody"));
   13597              :     }
   13598         1774 :     funcargs = PQgetvalue(res, 0, PQfnumber(res, "funcargs"));
   13599         1774 :     funciargs = PQgetvalue(res, 0, PQfnumber(res, "funciargs"));
   13600         1774 :     funcresult = PQgetvalue(res, 0, PQfnumber(res, "funcresult"));
   13601         1774 :     protrftypes = PQgetvalue(res, 0, PQfnumber(res, "protrftypes"));
   13602         1774 :     prokind = PQgetvalue(res, 0, PQfnumber(res, "prokind"));
   13603         1774 :     provolatile = PQgetvalue(res, 0, PQfnumber(res, "provolatile"));
   13604         1774 :     proisstrict = PQgetvalue(res, 0, PQfnumber(res, "proisstrict"));
   13605         1774 :     prosecdef = PQgetvalue(res, 0, PQfnumber(res, "prosecdef"));
   13606         1774 :     proleakproof = PQgetvalue(res, 0, PQfnumber(res, "proleakproof"));
   13607         1774 :     proconfig = PQgetvalue(res, 0, PQfnumber(res, "proconfig"));
   13608         1774 :     procost = PQgetvalue(res, 0, PQfnumber(res, "procost"));
   13609         1774 :     prorows = PQgetvalue(res, 0, PQfnumber(res, "prorows"));
   13610         1774 :     prosupport = PQgetvalue(res, 0, PQfnumber(res, "prosupport"));
   13611         1774 :     proparallel = PQgetvalue(res, 0, PQfnumber(res, "proparallel"));
   13612         1774 :     lanname = PQgetvalue(res, 0, PQfnumber(res, "lanname"));
   13613              : 
   13614              :     /*
   13615              :      * See backend/commands/functioncmds.c for details of how the 'AS' clause
   13616              :      * is used.
   13617              :      */
   13618         1774 :     if (prosqlbody)
   13619              :     {
   13620           48 :         appendPQExpBufferStr(asPart, prosqlbody);
   13621              :     }
   13622         1726 :     else if (probin[0] != '\0')
   13623              :     {
   13624          147 :         appendPQExpBufferStr(asPart, "AS ");
   13625          147 :         appendStringLiteralAH(asPart, probin, fout);
   13626          147 :         if (prosrc[0] != '\0')
   13627              :         {
   13628          147 :             appendPQExpBufferStr(asPart, ", ");
   13629              : 
   13630              :             /*
   13631              :              * where we have bin, use dollar quoting if allowed and src
   13632              :              * contains quote or backslash; else use regular quoting.
   13633              :              */
   13634          147 :             if (dopt->disable_dollar_quoting ||
   13635          147 :                 (strchr(prosrc, '\'') == NULL && strchr(prosrc, '\\') == NULL))
   13636          147 :                 appendStringLiteralAH(asPart, prosrc, fout);
   13637              :             else
   13638            0 :                 appendStringLiteralDQ(asPart, prosrc, NULL);
   13639              :         }
   13640              :     }
   13641              :     else
   13642              :     {
   13643         1579 :         appendPQExpBufferStr(asPart, "AS ");
   13644              :         /* with no bin, dollar quote src unconditionally if allowed */
   13645         1579 :         if (dopt->disable_dollar_quoting)
   13646            0 :             appendStringLiteralAH(asPart, prosrc, fout);
   13647              :         else
   13648         1579 :             appendStringLiteralDQ(asPart, prosrc, NULL);
   13649              :     }
   13650              : 
   13651         1774 :     if (*proconfig)
   13652              :     {
   13653           15 :         if (!parsePGArray(proconfig, &configitems, &nconfigitems))
   13654            0 :             pg_fatal("could not parse %s array", "proconfig");
   13655              :     }
   13656              :     else
   13657              :     {
   13658         1759 :         configitems = NULL;
   13659         1759 :         nconfigitems = 0;
   13660              :     }
   13661              : 
   13662         1774 :     funcfullsig = format_function_arguments(finfo, funcargs, false);
   13663         1774 :     funcsig = format_function_arguments(finfo, funciargs, false);
   13664              : 
   13665         1774 :     funcsig_tag = format_function_signature(fout, finfo, false);
   13666              : 
   13667         1774 :     qual_funcsig = psprintf("%s.%s",
   13668         1774 :                             fmtId(finfo->dobj.namespace->dobj.name),
   13669              :                             funcsig);
   13670              : 
   13671         1774 :     if (prokind[0] == PROKIND_PROCEDURE)
   13672           92 :         keyword = "PROCEDURE";
   13673              :     else
   13674         1682 :         keyword = "FUNCTION"; /* works for window functions too */
   13675              : 
   13676         1774 :     appendPQExpBuffer(delqry, "DROP %s %s;\n",
   13677              :                       keyword, qual_funcsig);
   13678              : 
   13679         3548 :     appendPQExpBuffer(q, "CREATE %s %s.%s",
   13680              :                       keyword,
   13681         1774 :                       fmtId(finfo->dobj.namespace->dobj.name),
   13682              :                       funcfullsig ? funcfullsig :
   13683              :                       funcsig);
   13684              : 
   13685         1774 :     if (prokind[0] == PROKIND_PROCEDURE)
   13686              :          /* no result type to output */ ;
   13687         1682 :     else if (funcresult)
   13688         1682 :         appendPQExpBuffer(q, " RETURNS %s", funcresult);
   13689              :     else
   13690            0 :         appendPQExpBuffer(q, " RETURNS %s%s",
   13691            0 :                           (proretset[0] == 't') ? "SETOF " : "",
   13692            0 :                           getFormattedTypeName(fout, finfo->prorettype,
   13693              :                                                zeroIsError));
   13694              : 
   13695         1774 :     appendPQExpBuffer(q, "\n    LANGUAGE %s", fmtId(lanname));
   13696              : 
   13697         1774 :     if (*protrftypes)
   13698              :     {
   13699            0 :         Oid        *typeids = pg_malloc_array(Oid, FUNC_MAX_ARGS);
   13700              :         int         i;
   13701              : 
   13702            0 :         appendPQExpBufferStr(q, " TRANSFORM ");
   13703            0 :         parseOidArray(protrftypes, typeids, FUNC_MAX_ARGS);
   13704            0 :         for (i = 0; typeids[i]; i++)
   13705              :         {
   13706            0 :             if (i != 0)
   13707            0 :                 appendPQExpBufferStr(q, ", ");
   13708            0 :             appendPQExpBuffer(q, "FOR TYPE %s",
   13709            0 :                               getFormattedTypeName(fout, typeids[i], zeroAsNone));
   13710              :         }
   13711              : 
   13712            0 :         free(typeids);
   13713              :     }
   13714              : 
   13715         1774 :     if (prokind[0] == PROKIND_WINDOW)
   13716            5 :         appendPQExpBufferStr(q, " WINDOW");
   13717              : 
   13718         1774 :     if (provolatile[0] != PROVOLATILE_VOLATILE)
   13719              :     {
   13720          351 :         if (provolatile[0] == PROVOLATILE_IMMUTABLE)
   13721          330 :             appendPQExpBufferStr(q, " IMMUTABLE");
   13722           21 :         else if (provolatile[0] == PROVOLATILE_STABLE)
   13723           21 :             appendPQExpBufferStr(q, " STABLE");
   13724            0 :         else if (provolatile[0] != PROVOLATILE_VOLATILE)
   13725            0 :             pg_fatal("unrecognized provolatile value for function \"%s\"",
   13726              :                      finfo->dobj.name);
   13727              :     }
   13728              : 
   13729         1774 :     if (proisstrict[0] == 't')
   13730          358 :         appendPQExpBufferStr(q, " STRICT");
   13731              : 
   13732         1774 :     if (prosecdef[0] == 't')
   13733            0 :         appendPQExpBufferStr(q, " SECURITY DEFINER");
   13734              : 
   13735         1774 :     if (proleakproof[0] == 't')
   13736           10 :         appendPQExpBufferStr(q, " LEAKPROOF");
   13737              : 
   13738              :     /*
   13739              :      * COST and ROWS are emitted only if present and not default, so as not to
   13740              :      * break backwards-compatibility of the dump without need.  Keep this code
   13741              :      * in sync with the defaults in functioncmds.c.
   13742              :      */
   13743         1774 :     if (strcmp(procost, "0") != 0)
   13744              :     {
   13745         1774 :         if (strcmp(lanname, "internal") == 0 || strcmp(lanname, "c") == 0)
   13746              :         {
   13747              :             /* default cost is 1 */
   13748          376 :             if (strcmp(procost, "1") != 0)
   13749            0 :                 appendPQExpBuffer(q, " COST %s", procost);
   13750              :         }
   13751              :         else
   13752              :         {
   13753              :             /* default cost is 100 */
   13754         1398 :             if (strcmp(procost, "100") != 0)
   13755            6 :                 appendPQExpBuffer(q, " COST %s", procost);
   13756              :         }
   13757              :     }
   13758         1774 :     if (proretset[0] == 't' &&
   13759          187 :         strcmp(prorows, "0") != 0 && strcmp(prorows, "1000") != 0)
   13760            0 :         appendPQExpBuffer(q, " ROWS %s", prorows);
   13761              : 
   13762         1774 :     if (strcmp(prosupport, "-") != 0)
   13763              :     {
   13764              :         /* We rely on regprocout to provide quoting and qualification */
   13765           42 :         appendPQExpBuffer(q, " SUPPORT %s", prosupport);
   13766              :     }
   13767              : 
   13768         1774 :     if (proparallel[0] != PROPARALLEL_UNSAFE)
   13769              :     {
   13770          116 :         if (proparallel[0] == PROPARALLEL_SAFE)
   13771          111 :             appendPQExpBufferStr(q, " PARALLEL SAFE");
   13772            5 :         else if (proparallel[0] == PROPARALLEL_RESTRICTED)
   13773            5 :             appendPQExpBufferStr(q, " PARALLEL RESTRICTED");
   13774            0 :         else if (proparallel[0] != PROPARALLEL_UNSAFE)
   13775            0 :             pg_fatal("unrecognized proparallel value for function \"%s\"",
   13776              :                      finfo->dobj.name);
   13777              :     }
   13778              : 
   13779         1814 :     for (int i = 0; i < nconfigitems; i++)
   13780              :     {
   13781              :         /* we feel free to scribble on configitems[] here */
   13782           40 :         char       *configitem = configitems[i];
   13783              :         char       *pos;
   13784              : 
   13785           40 :         pos = strchr(configitem, '=');
   13786           40 :         if (pos == NULL)
   13787            0 :             continue;
   13788           40 :         *pos++ = '\0';
   13789           40 :         appendPQExpBuffer(q, "\n    SET %s TO ", fmtId(configitem));
   13790              : 
   13791              :         /*
   13792              :          * Variables that are marked GUC_LIST_QUOTE were already fully quoted
   13793              :          * by flatten_set_variable_args() before they were put into the
   13794              :          * proconfig array.  However, because the quoting rules used there
   13795              :          * aren't exactly like SQL's, we have to break the list value apart
   13796              :          * and then quote the elements as string literals.  (The elements may
   13797              :          * be double-quoted as-is, but we can't just feed them to the SQL
   13798              :          * parser; it would do the wrong thing with elements that are
   13799              :          * zero-length or longer than NAMEDATALEN.)  Also, we need a special
   13800              :          * case for empty lists.
   13801              :          *
   13802              :          * Variables that are not so marked should just be emitted as simple
   13803              :          * string literals.  If the variable is not known to
   13804              :          * variable_is_guc_list_quote(), we'll do that; this makes it unsafe
   13805              :          * to use GUC_LIST_QUOTE for extension variables.
   13806              :          */
   13807           40 :         if (variable_is_guc_list_quote(configitem))
   13808              :         {
   13809              :             char      **namelist;
   13810              :             char      **nameptr;
   13811              : 
   13812              :             /* Parse string into list of identifiers */
   13813              :             /* this shouldn't fail really */
   13814           15 :             if (SplitGUCList(pos, ',', &namelist))
   13815              :             {
   13816              :                 /* Special case: represent an empty list as NULL */
   13817           15 :                 if (*namelist == NULL)
   13818            5 :                     appendPQExpBufferStr(q, "NULL");
   13819           40 :                 for (nameptr = namelist; *nameptr; nameptr++)
   13820              :                 {
   13821           25 :                     if (nameptr != namelist)
   13822           15 :                         appendPQExpBufferStr(q, ", ");
   13823           25 :                     appendStringLiteralAH(q, *nameptr, fout);
   13824              :                 }
   13825              :             }
   13826           15 :             pg_free(namelist);
   13827              :         }
   13828              :         else
   13829           25 :             appendStringLiteralAH(q, pos, fout);
   13830              :     }
   13831              : 
   13832         1774 :     appendPQExpBuffer(q, "\n    %s;\n", asPart->data);
   13833              : 
   13834         1774 :     append_depends_on_extension(fout, q, &finfo->dobj,
   13835              :                                 "pg_catalog.pg_proc", keyword,
   13836              :                                 qual_funcsig);
   13837              : 
   13838         1774 :     if (dopt->binary_upgrade)
   13839          295 :         binary_upgrade_extension_member(q, &finfo->dobj,
   13840              :                                         keyword, funcsig,
   13841          295 :                                         finfo->dobj.namespace->dobj.name);
   13842              : 
   13843         1774 :     if (finfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   13844         1678 :         ArchiveEntry(fout, finfo->dobj.catId, finfo->dobj.dumpId,
   13845         1678 :                      ARCHIVE_OPTS(.tag = funcsig_tag,
   13846              :                                   .namespace = finfo->dobj.namespace->dobj.name,
   13847              :                                   .owner = finfo->rolname,
   13848              :                                   .description = keyword,
   13849              :                                   .section = finfo->postponed_def ?
   13850              :                                   SECTION_POST_DATA : SECTION_PRE_DATA,
   13851              :                                   .createStmt = q->data,
   13852              :                                   .dropStmt = delqry->data));
   13853              : 
   13854              :     /* Dump Function Comments and Security Labels */
   13855         1774 :     if (finfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   13856            9 :         dumpComment(fout, keyword, funcsig,
   13857            9 :                     finfo->dobj.namespace->dobj.name, finfo->rolname,
   13858            9 :                     finfo->dobj.catId, 0, finfo->dobj.dumpId);
   13859              : 
   13860         1774 :     if (finfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
   13861            0 :         dumpSecLabel(fout, keyword, funcsig,
   13862            0 :                      finfo->dobj.namespace->dobj.name, finfo->rolname,
   13863            0 :                      finfo->dobj.catId, 0, finfo->dobj.dumpId);
   13864              : 
   13865         1774 :     if (finfo->dobj.dump & DUMP_COMPONENT_ACL)
   13866          108 :         dumpACL(fout, finfo->dobj.dumpId, InvalidDumpId, keyword,
   13867              :                 funcsig, NULL,
   13868          108 :                 finfo->dobj.namespace->dobj.name,
   13869          108 :                 NULL, finfo->rolname, &finfo->dacl);
   13870              : 
   13871         1774 :     PQclear(res);
   13872              : 
   13873         1774 :     destroyPQExpBuffer(query);
   13874         1774 :     destroyPQExpBuffer(q);
   13875         1774 :     destroyPQExpBuffer(delqry);
   13876         1774 :     destroyPQExpBuffer(asPart);
   13877         1774 :     free(funcsig);
   13878         1774 :     free(funcfullsig);
   13879         1774 :     free(funcsig_tag);
   13880         1774 :     free(qual_funcsig);
   13881         1774 :     free(configitems);
   13882              : }
   13883              : 
   13884              : 
   13885              : /*
   13886              :  * Dump a user-defined cast
   13887              :  */
   13888              : static void
   13889           67 : dumpCast(Archive *fout, const CastInfo *cast)
   13890              : {
   13891           67 :     DumpOptions *dopt = fout->dopt;
   13892              :     PQExpBuffer defqry;
   13893              :     PQExpBuffer delqry;
   13894              :     PQExpBuffer labelq;
   13895              :     PQExpBuffer castargs;
   13896           67 :     FuncInfo   *funcInfo = NULL;
   13897              :     const char *sourceType;
   13898              :     const char *targetType;
   13899              : 
   13900              :     /* Do nothing if not dumping schema */
   13901           67 :     if (!dopt->dumpSchema)
   13902            6 :         return;
   13903              : 
   13904              :     /* Cannot dump if we don't have the cast function's info */
   13905           61 :     if (OidIsValid(cast->castfunc))
   13906              :     {
   13907           36 :         funcInfo = findFuncByOid(cast->castfunc);
   13908           36 :         if (funcInfo == NULL)
   13909            0 :             pg_fatal("could not find function definition for function with OID %u",
   13910              :                      cast->castfunc);
   13911              :     }
   13912              : 
   13913           61 :     defqry = createPQExpBuffer();
   13914           61 :     delqry = createPQExpBuffer();
   13915           61 :     labelq = createPQExpBuffer();
   13916           61 :     castargs = createPQExpBuffer();
   13917              : 
   13918           61 :     sourceType = getFormattedTypeName(fout, cast->castsource, zeroAsNone);
   13919           61 :     targetType = getFormattedTypeName(fout, cast->casttarget, zeroAsNone);
   13920           61 :     appendPQExpBuffer(delqry, "DROP CAST (%s AS %s);\n",
   13921              :                       sourceType, targetType);
   13922              : 
   13923           61 :     appendPQExpBuffer(defqry, "CREATE CAST (%s AS %s) ",
   13924              :                       sourceType, targetType);
   13925              : 
   13926           61 :     switch (cast->castmethod)
   13927              :     {
   13928           25 :         case COERCION_METHOD_BINARY:
   13929           25 :             appendPQExpBufferStr(defqry, "WITHOUT FUNCTION");
   13930           25 :             break;
   13931            0 :         case COERCION_METHOD_INOUT:
   13932            0 :             appendPQExpBufferStr(defqry, "WITH INOUT");
   13933            0 :             break;
   13934           36 :         case COERCION_METHOD_FUNCTION:
   13935           36 :             if (funcInfo)
   13936              :             {
   13937           36 :                 char       *fsig = format_function_signature(fout, funcInfo, true);
   13938              : 
   13939              :                 /*
   13940              :                  * Always qualify the function name (format_function_signature
   13941              :                  * won't qualify it).
   13942              :                  */
   13943           36 :                 appendPQExpBuffer(defqry, "WITH FUNCTION %s.%s",
   13944           36 :                                   fmtId(funcInfo->dobj.namespace->dobj.name), fsig);
   13945           36 :                 free(fsig);
   13946              :             }
   13947              :             else
   13948            0 :                 pg_log_warning("bogus value in pg_cast.castfunc or pg_cast.castmethod field");
   13949           36 :             break;
   13950            0 :         default:
   13951            0 :             pg_log_warning("bogus value in pg_cast.castmethod field");
   13952              :     }
   13953              : 
   13954           61 :     if (cast->castcontext == 'a')
   13955           31 :         appendPQExpBufferStr(defqry, " AS ASSIGNMENT");
   13956           30 :     else if (cast->castcontext == 'i')
   13957           10 :         appendPQExpBufferStr(defqry, " AS IMPLICIT");
   13958           61 :     appendPQExpBufferStr(defqry, ";\n");
   13959              : 
   13960           61 :     appendPQExpBuffer(labelq, "CAST (%s AS %s)",
   13961              :                       sourceType, targetType);
   13962              : 
   13963           61 :     appendPQExpBuffer(castargs, "(%s AS %s)",
   13964              :                       sourceType, targetType);
   13965              : 
   13966           61 :     if (dopt->binary_upgrade)
   13967            7 :         binary_upgrade_extension_member(defqry, &cast->dobj,
   13968            7 :                                         "CAST", castargs->data, NULL);
   13969              : 
   13970           61 :     if (cast->dobj.dump & DUMP_COMPONENT_DEFINITION)
   13971           61 :         ArchiveEntry(fout, cast->dobj.catId, cast->dobj.dumpId,
   13972           61 :                      ARCHIVE_OPTS(.tag = labelq->data,
   13973              :                                   .description = "CAST",
   13974              :                                   .section = SECTION_PRE_DATA,
   13975              :                                   .createStmt = defqry->data,
   13976              :                                   .dropStmt = delqry->data));
   13977              : 
   13978              :     /* Dump Cast Comments */
   13979           61 :     if (cast->dobj.dump & DUMP_COMPONENT_COMMENT)
   13980            0 :         dumpComment(fout, "CAST", castargs->data,
   13981              :                     NULL, "",
   13982            0 :                     cast->dobj.catId, 0, cast->dobj.dumpId);
   13983              : 
   13984           61 :     destroyPQExpBuffer(defqry);
   13985           61 :     destroyPQExpBuffer(delqry);
   13986           61 :     destroyPQExpBuffer(labelq);
   13987           61 :     destroyPQExpBuffer(castargs);
   13988              : }
   13989              : 
   13990              : /*
   13991              :  * Dump a transform
   13992              :  */
   13993              : static void
   13994           42 : dumpTransform(Archive *fout, const TransformInfo *transform)
   13995              : {
   13996           42 :     DumpOptions *dopt = fout->dopt;
   13997              :     PQExpBuffer defqry;
   13998              :     PQExpBuffer delqry;
   13999              :     PQExpBuffer labelq;
   14000              :     PQExpBuffer transformargs;
   14001           42 :     FuncInfo   *fromsqlFuncInfo = NULL;
   14002           42 :     FuncInfo   *tosqlFuncInfo = NULL;
   14003              :     char       *lanname;
   14004              :     const char *transformType;
   14005              : 
   14006              :     /* Do nothing if not dumping schema */
   14007           42 :     if (!dopt->dumpSchema)
   14008            6 :         return;
   14009              : 
   14010              :     /* Cannot dump if we don't have the transform functions' info */
   14011           36 :     if (OidIsValid(transform->trffromsql))
   14012              :     {
   14013           36 :         fromsqlFuncInfo = findFuncByOid(transform->trffromsql);
   14014           36 :         if (fromsqlFuncInfo == NULL)
   14015            0 :             pg_fatal("could not find function definition for function with OID %u",
   14016              :                      transform->trffromsql);
   14017              :     }
   14018           36 :     if (OidIsValid(transform->trftosql))
   14019              :     {
   14020           36 :         tosqlFuncInfo = findFuncByOid(transform->trftosql);
   14021           36 :         if (tosqlFuncInfo == NULL)
   14022            0 :             pg_fatal("could not find function definition for function with OID %u",
   14023              :                      transform->trftosql);
   14024              :     }
   14025              : 
   14026           36 :     defqry = createPQExpBuffer();
   14027           36 :     delqry = createPQExpBuffer();
   14028           36 :     labelq = createPQExpBuffer();
   14029           36 :     transformargs = createPQExpBuffer();
   14030              : 
   14031           36 :     lanname = get_language_name(fout, transform->trflang);
   14032           36 :     transformType = getFormattedTypeName(fout, transform->trftype, zeroAsNone);
   14033              : 
   14034           36 :     appendPQExpBuffer(delqry, "DROP TRANSFORM FOR %s LANGUAGE %s;\n",
   14035              :                       transformType, lanname);
   14036              : 
   14037           36 :     appendPQExpBuffer(defqry, "CREATE TRANSFORM FOR %s LANGUAGE %s (",
   14038              :                       transformType, lanname);
   14039              : 
   14040           36 :     if (!transform->trffromsql && !transform->trftosql)
   14041            0 :         pg_log_warning("bogus transform definition, at least one of trffromsql and trftosql should be nonzero");
   14042              : 
   14043           36 :     if (transform->trffromsql)
   14044              :     {
   14045           36 :         if (fromsqlFuncInfo)
   14046              :         {
   14047           36 :             char       *fsig = format_function_signature(fout, fromsqlFuncInfo, true);
   14048              : 
   14049              :             /*
   14050              :              * Always qualify the function name (format_function_signature
   14051              :              * won't qualify it).
   14052              :              */
   14053           36 :             appendPQExpBuffer(defqry, "FROM SQL WITH FUNCTION %s.%s",
   14054           36 :                               fmtId(fromsqlFuncInfo->dobj.namespace->dobj.name), fsig);
   14055           36 :             free(fsig);
   14056              :         }
   14057              :         else
   14058            0 :             pg_log_warning("bogus value in pg_transform.trffromsql field");
   14059              :     }
   14060              : 
   14061           36 :     if (transform->trftosql)
   14062              :     {
   14063           36 :         if (transform->trffromsql)
   14064           36 :             appendPQExpBufferStr(defqry, ", ");
   14065              : 
   14066           36 :         if (tosqlFuncInfo)
   14067              :         {
   14068           36 :             char       *fsig = format_function_signature(fout, tosqlFuncInfo, true);
   14069              : 
   14070              :             /*
   14071              :              * Always qualify the function name (format_function_signature
   14072              :              * won't qualify it).
   14073              :              */
   14074           36 :             appendPQExpBuffer(defqry, "TO SQL WITH FUNCTION %s.%s",
   14075           36 :                               fmtId(tosqlFuncInfo->dobj.namespace->dobj.name), fsig);
   14076           36 :             free(fsig);
   14077              :         }
   14078              :         else
   14079            0 :             pg_log_warning("bogus value in pg_transform.trftosql field");
   14080              :     }
   14081              : 
   14082           36 :     appendPQExpBufferStr(defqry, ");\n");
   14083              : 
   14084           36 :     appendPQExpBuffer(labelq, "TRANSFORM FOR %s LANGUAGE %s",
   14085              :                       transformType, lanname);
   14086              : 
   14087           36 :     appendPQExpBuffer(transformargs, "FOR %s LANGUAGE %s",
   14088              :                       transformType, lanname);
   14089              : 
   14090           36 :     if (dopt->binary_upgrade)
   14091            2 :         binary_upgrade_extension_member(defqry, &transform->dobj,
   14092            2 :                                         "TRANSFORM", transformargs->data, NULL);
   14093              : 
   14094           36 :     if (transform->dobj.dump & DUMP_COMPONENT_DEFINITION)
   14095           36 :         ArchiveEntry(fout, transform->dobj.catId, transform->dobj.dumpId,
   14096           36 :                      ARCHIVE_OPTS(.tag = labelq->data,
   14097              :                                   .description = "TRANSFORM",
   14098              :                                   .section = SECTION_PRE_DATA,
   14099              :                                   .createStmt = defqry->data,
   14100              :                                   .dropStmt = delqry->data,
   14101              :                                   .deps = transform->dobj.dependencies,
   14102              :                                   .nDeps = transform->dobj.nDeps));
   14103              : 
   14104              :     /* Dump Transform Comments */
   14105           36 :     if (transform->dobj.dump & DUMP_COMPONENT_COMMENT)
   14106            0 :         dumpComment(fout, "TRANSFORM", transformargs->data,
   14107              :                     NULL, "",
   14108            0 :                     transform->dobj.catId, 0, transform->dobj.dumpId);
   14109              : 
   14110           36 :     free(lanname);
   14111           36 :     destroyPQExpBuffer(defqry);
   14112           36 :     destroyPQExpBuffer(delqry);
   14113           36 :     destroyPQExpBuffer(labelq);
   14114           36 :     destroyPQExpBuffer(transformargs);
   14115              : }
   14116              : 
   14117              : 
   14118              : /*
   14119              :  * dumpOpr
   14120              :  *    write out a single operator definition
   14121              :  */
   14122              : static void
   14123         2522 : dumpOpr(Archive *fout, const OprInfo *oprinfo)
   14124              : {
   14125         2522 :     DumpOptions *dopt = fout->dopt;
   14126              :     PQExpBuffer query;
   14127              :     PQExpBuffer q;
   14128              :     PQExpBuffer delq;
   14129              :     PQExpBuffer oprid;
   14130              :     PQExpBuffer details;
   14131              :     PGresult   *res;
   14132              :     int         i_oprkind;
   14133              :     int         i_oprcode;
   14134              :     int         i_oprleft;
   14135              :     int         i_oprright;
   14136              :     int         i_oprcom;
   14137              :     int         i_oprnegate;
   14138              :     int         i_oprrest;
   14139              :     int         i_oprjoin;
   14140              :     int         i_oprcanmerge;
   14141              :     int         i_oprcanhash;
   14142              :     char       *oprkind;
   14143              :     char       *oprcode;
   14144              :     char       *oprleft;
   14145              :     char       *oprright;
   14146              :     char       *oprcom;
   14147              :     char       *oprnegate;
   14148              :     char       *oprrest;
   14149              :     char       *oprjoin;
   14150              :     char       *oprcanmerge;
   14151              :     char       *oprcanhash;
   14152              :     char       *oprregproc;
   14153              :     char       *oprref;
   14154              : 
   14155              :     /* Do nothing if not dumping schema */
   14156         2522 :     if (!dopt->dumpSchema)
   14157            6 :         return;
   14158              : 
   14159              :     /*
   14160              :      * some operators are invalid because they were the result of user
   14161              :      * defining operators before commutators exist
   14162              :      */
   14163         2516 :     if (!OidIsValid(oprinfo->oprcode))
   14164           14 :         return;
   14165              : 
   14166         2502 :     query = createPQExpBuffer();
   14167         2502 :     q = createPQExpBuffer();
   14168         2502 :     delq = createPQExpBuffer();
   14169         2502 :     oprid = createPQExpBuffer();
   14170         2502 :     details = createPQExpBuffer();
   14171              : 
   14172         2502 :     if (!fout->is_prepared[PREPQUERY_DUMPOPR])
   14173              :     {
   14174              :         /* Set up query for operator-specific details */
   14175           40 :         appendPQExpBufferStr(query,
   14176              :                              "PREPARE dumpOpr(pg_catalog.oid) AS\n"
   14177              :                              "SELECT oprkind, "
   14178              :                              "oprcode::pg_catalog.regprocedure, "
   14179              :                              "oprleft::pg_catalog.regtype, "
   14180              :                              "oprright::pg_catalog.regtype, "
   14181              :                              "oprcom, "
   14182              :                              "oprnegate, "
   14183              :                              "oprrest::pg_catalog.regprocedure, "
   14184              :                              "oprjoin::pg_catalog.regprocedure, "
   14185              :                              "oprcanmerge, oprcanhash "
   14186              :                              "FROM pg_catalog.pg_operator "
   14187              :                              "WHERE oid = $1");
   14188              : 
   14189           40 :         ExecuteSqlStatement(fout, query->data);
   14190              : 
   14191           40 :         fout->is_prepared[PREPQUERY_DUMPOPR] = true;
   14192              :     }
   14193              : 
   14194         2502 :     printfPQExpBuffer(query,
   14195              :                       "EXECUTE dumpOpr('%u')",
   14196         2502 :                       oprinfo->dobj.catId.oid);
   14197              : 
   14198         2502 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   14199              : 
   14200         2502 :     i_oprkind = PQfnumber(res, "oprkind");
   14201         2502 :     i_oprcode = PQfnumber(res, "oprcode");
   14202         2502 :     i_oprleft = PQfnumber(res, "oprleft");
   14203         2502 :     i_oprright = PQfnumber(res, "oprright");
   14204         2502 :     i_oprcom = PQfnumber(res, "oprcom");
   14205         2502 :     i_oprnegate = PQfnumber(res, "oprnegate");
   14206         2502 :     i_oprrest = PQfnumber(res, "oprrest");
   14207         2502 :     i_oprjoin = PQfnumber(res, "oprjoin");
   14208         2502 :     i_oprcanmerge = PQfnumber(res, "oprcanmerge");
   14209         2502 :     i_oprcanhash = PQfnumber(res, "oprcanhash");
   14210              : 
   14211         2502 :     oprkind = PQgetvalue(res, 0, i_oprkind);
   14212         2502 :     oprcode = PQgetvalue(res, 0, i_oprcode);
   14213         2502 :     oprleft = PQgetvalue(res, 0, i_oprleft);
   14214         2502 :     oprright = PQgetvalue(res, 0, i_oprright);
   14215         2502 :     oprcom = PQgetvalue(res, 0, i_oprcom);
   14216         2502 :     oprnegate = PQgetvalue(res, 0, i_oprnegate);
   14217         2502 :     oprrest = PQgetvalue(res, 0, i_oprrest);
   14218         2502 :     oprjoin = PQgetvalue(res, 0, i_oprjoin);
   14219         2502 :     oprcanmerge = PQgetvalue(res, 0, i_oprcanmerge);
   14220         2502 :     oprcanhash = PQgetvalue(res, 0, i_oprcanhash);
   14221              : 
   14222              :     /* In PG14 upwards postfix operator support does not exist anymore. */
   14223         2502 :     if (strcmp(oprkind, "r") == 0)
   14224            0 :         pg_log_warning("postfix operators are not supported anymore (operator \"%s\")",
   14225              :                        oprcode);
   14226              : 
   14227         2502 :     oprregproc = convertRegProcReference(oprcode);
   14228         2502 :     if (oprregproc)
   14229              :     {
   14230         2502 :         appendPQExpBuffer(details, "    FUNCTION = %s", oprregproc);
   14231         2502 :         free(oprregproc);
   14232              :     }
   14233              : 
   14234         2502 :     appendPQExpBuffer(oprid, "%s (",
   14235         2502 :                       oprinfo->dobj.name);
   14236              : 
   14237              :     /*
   14238              :      * right unary means there's a left arg and left unary means there's a
   14239              :      * right arg.  (Although the "r" case is dead code for PG14 and later,
   14240              :      * continue to support it in case we're dumping from an old server.)
   14241              :      */
   14242         2502 :     if (strcmp(oprkind, "r") == 0 ||
   14243         2502 :         strcmp(oprkind, "b") == 0)
   14244              :     {
   14245         2359 :         appendPQExpBuffer(details, ",\n    LEFTARG = %s", oprleft);
   14246         2359 :         appendPQExpBufferStr(oprid, oprleft);
   14247              :     }
   14248              :     else
   14249          143 :         appendPQExpBufferStr(oprid, "NONE");
   14250              : 
   14251         2502 :     if (strcmp(oprkind, "l") == 0 ||
   14252         2359 :         strcmp(oprkind, "b") == 0)
   14253              :     {
   14254         2502 :         appendPQExpBuffer(details, ",\n    RIGHTARG = %s", oprright);
   14255         2502 :         appendPQExpBuffer(oprid, ", %s)", oprright);
   14256              :     }
   14257              :     else
   14258            0 :         appendPQExpBufferStr(oprid, ", NONE)");
   14259              : 
   14260         2502 :     oprref = getFormattedOperatorName(oprcom);
   14261         2502 :     if (oprref)
   14262              :     {
   14263         1679 :         appendPQExpBuffer(details, ",\n    COMMUTATOR = %s", oprref);
   14264         1679 :         free(oprref);
   14265              :     }
   14266              : 
   14267         2502 :     oprref = getFormattedOperatorName(oprnegate);
   14268         2502 :     if (oprref)
   14269              :     {
   14270         1181 :         appendPQExpBuffer(details, ",\n    NEGATOR = %s", oprref);
   14271         1181 :         free(oprref);
   14272              :     }
   14273              : 
   14274         2502 :     if (strcmp(oprcanmerge, "t") == 0)
   14275          188 :         appendPQExpBufferStr(details, ",\n    MERGES");
   14276              : 
   14277         2502 :     if (strcmp(oprcanhash, "t") == 0)
   14278          141 :         appendPQExpBufferStr(details, ",\n    HASHES");
   14279              : 
   14280         2502 :     oprregproc = convertRegProcReference(oprrest);
   14281         2502 :     if (oprregproc)
   14282              :     {
   14283         1532 :         appendPQExpBuffer(details, ",\n    RESTRICT = %s", oprregproc);
   14284         1532 :         free(oprregproc);
   14285              :     }
   14286              : 
   14287         2502 :     oprregproc = convertRegProcReference(oprjoin);
   14288         2502 :     if (oprregproc)
   14289              :     {
   14290         1532 :         appendPQExpBuffer(details, ",\n    JOIN = %s", oprregproc);
   14291         1532 :         free(oprregproc);
   14292              :     }
   14293              : 
   14294         2502 :     appendPQExpBuffer(delq, "DROP OPERATOR %s.%s;\n",
   14295         2502 :                       fmtId(oprinfo->dobj.namespace->dobj.name),
   14296              :                       oprid->data);
   14297              : 
   14298         2502 :     appendPQExpBuffer(q, "CREATE OPERATOR %s.%s (\n%s\n);\n",
   14299         2502 :                       fmtId(oprinfo->dobj.namespace->dobj.name),
   14300         2502 :                       oprinfo->dobj.name, details->data);
   14301              : 
   14302         2502 :     if (dopt->binary_upgrade)
   14303           12 :         binary_upgrade_extension_member(q, &oprinfo->dobj,
   14304           12 :                                         "OPERATOR", oprid->data,
   14305           12 :                                         oprinfo->dobj.namespace->dobj.name);
   14306              : 
   14307         2502 :     if (oprinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   14308         2502 :         ArchiveEntry(fout, oprinfo->dobj.catId, oprinfo->dobj.dumpId,
   14309         2502 :                      ARCHIVE_OPTS(.tag = oprinfo->dobj.name,
   14310              :                                   .namespace = oprinfo->dobj.namespace->dobj.name,
   14311              :                                   .owner = oprinfo->rolname,
   14312              :                                   .description = "OPERATOR",
   14313              :                                   .section = SECTION_PRE_DATA,
   14314              :                                   .createStmt = q->data,
   14315              :                                   .dropStmt = delq->data));
   14316              : 
   14317              :     /* Dump Operator Comments */
   14318         2502 :     if (oprinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   14319         2415 :         dumpComment(fout, "OPERATOR", oprid->data,
   14320         2415 :                     oprinfo->dobj.namespace->dobj.name, oprinfo->rolname,
   14321         2415 :                     oprinfo->dobj.catId, 0, oprinfo->dobj.dumpId);
   14322              : 
   14323         2502 :     PQclear(res);
   14324              : 
   14325         2502 :     destroyPQExpBuffer(query);
   14326         2502 :     destroyPQExpBuffer(q);
   14327         2502 :     destroyPQExpBuffer(delq);
   14328         2502 :     destroyPQExpBuffer(oprid);
   14329         2502 :     destroyPQExpBuffer(details);
   14330              : }
   14331              : 
   14332              : /*
   14333              :  * Convert a function reference obtained from pg_operator
   14334              :  *
   14335              :  * Returns allocated string of what to print, or NULL if function references
   14336              :  * is InvalidOid. Returned string is expected to be free'd by the caller.
   14337              :  *
   14338              :  * The input is a REGPROCEDURE display; we have to strip the argument-types
   14339              :  * part.
   14340              :  */
   14341              : static char *
   14342         7506 : convertRegProcReference(const char *proc)
   14343              : {
   14344              :     char       *name;
   14345              :     char       *paren;
   14346              :     bool        inquote;
   14347              : 
   14348              :     /* In all cases "-" means a null reference */
   14349         7506 :     if (strcmp(proc, "-") == 0)
   14350         1940 :         return NULL;
   14351              : 
   14352         5566 :     name = pg_strdup(proc);
   14353              :     /* find non-double-quoted left paren */
   14354         5566 :     inquote = false;
   14355        66996 :     for (paren = name; *paren; paren++)
   14356              :     {
   14357        66996 :         if (*paren == '(' && !inquote)
   14358              :         {
   14359         5566 :             *paren = '\0';
   14360         5566 :             break;
   14361              :         }
   14362        61430 :         if (*paren == '"')
   14363           50 :             inquote = !inquote;
   14364              :     }
   14365         5566 :     return name;
   14366              : }
   14367              : 
   14368              : /*
   14369              :  * getFormattedOperatorName - retrieve the operator name for the
   14370              :  * given operator OID (presented in string form).
   14371              :  *
   14372              :  * Returns an allocated string, or NULL if the given OID is invalid.
   14373              :  * Caller is responsible for free'ing result string.
   14374              :  *
   14375              :  * What we produce has the format "OPERATOR(schema.oprname)".  This is only
   14376              :  * useful in commands where the operator's argument types can be inferred from
   14377              :  * context.  We always schema-qualify the name, though.  The predecessor to
   14378              :  * this code tried to skip the schema qualification if possible, but that led
   14379              :  * to wrong results in corner cases, such as if an operator and its negator
   14380              :  * are in different schemas.
   14381              :  */
   14382              : static char *
   14383         5289 : getFormattedOperatorName(const char *oproid)
   14384              : {
   14385              :     OprInfo    *oprInfo;
   14386              : 
   14387              :     /* In all cases "0" means a null reference */
   14388         5289 :     if (strcmp(oproid, "0") == 0)
   14389         2429 :         return NULL;
   14390              : 
   14391         2860 :     oprInfo = findOprByOid(atooid(oproid));
   14392         2860 :     if (oprInfo == NULL)
   14393              :     {
   14394            0 :         pg_log_warning("could not find operator with OID %s",
   14395              :                        oproid);
   14396            0 :         return NULL;
   14397              :     }
   14398              : 
   14399         2860 :     return psprintf("OPERATOR(%s.%s)",
   14400         2860 :                     fmtId(oprInfo->dobj.namespace->dobj.name),
   14401              :                     oprInfo->dobj.name);
   14402              : }
   14403              : 
   14404              : /*
   14405              :  * Convert a function OID obtained from pg_ts_parser or pg_ts_template
   14406              :  *
   14407              :  * It is sufficient to use REGPROC rather than REGPROCEDURE, since the
   14408              :  * argument lists of these functions are predetermined.  Note that the
   14409              :  * caller should ensure we are in the proper schema, because the results
   14410              :  * are search path dependent!
   14411              :  */
   14412              : static char *
   14413          205 : convertTSFunction(Archive *fout, Oid funcOid)
   14414              : {
   14415              :     char       *result;
   14416              :     char        query[128];
   14417              :     PGresult   *res;
   14418              : 
   14419          205 :     snprintf(query, sizeof(query),
   14420              :              "SELECT '%u'::pg_catalog.regproc", funcOid);
   14421          205 :     res = ExecuteSqlQueryForSingleRow(fout, query);
   14422              : 
   14423          205 :     result = pg_strdup(PQgetvalue(res, 0, 0));
   14424              : 
   14425          205 :     PQclear(res);
   14426              : 
   14427          205 :     return result;
   14428              : }
   14429              : 
   14430              : /*
   14431              :  * dumpAccessMethod
   14432              :  *    write out a single access method definition
   14433              :  */
   14434              : static void
   14435           80 : dumpAccessMethod(Archive *fout, const AccessMethodInfo *aminfo)
   14436              : {
   14437           80 :     DumpOptions *dopt = fout->dopt;
   14438              :     PQExpBuffer q;
   14439              :     PQExpBuffer delq;
   14440              :     char       *qamname;
   14441              : 
   14442              :     /* Do nothing if not dumping schema */
   14443           80 :     if (!dopt->dumpSchema)
   14444           12 :         return;
   14445              : 
   14446           68 :     q = createPQExpBuffer();
   14447           68 :     delq = createPQExpBuffer();
   14448              : 
   14449           68 :     qamname = pg_strdup(fmtId(aminfo->dobj.name));
   14450              : 
   14451           68 :     appendPQExpBuffer(q, "CREATE ACCESS METHOD %s ", qamname);
   14452              : 
   14453           68 :     switch (aminfo->amtype)
   14454              :     {
   14455           32 :         case AMTYPE_INDEX:
   14456           32 :             appendPQExpBufferStr(q, "TYPE INDEX ");
   14457           32 :             break;
   14458           36 :         case AMTYPE_TABLE:
   14459           36 :             appendPQExpBufferStr(q, "TYPE TABLE ");
   14460           36 :             break;
   14461            0 :         default:
   14462            0 :             pg_log_warning("invalid type \"%c\" of access method \"%s\"",
   14463              :                            aminfo->amtype, qamname);
   14464            0 :             destroyPQExpBuffer(q);
   14465            0 :             destroyPQExpBuffer(delq);
   14466            0 :             free(qamname);
   14467            0 :             return;
   14468              :     }
   14469              : 
   14470           68 :     appendPQExpBuffer(q, "HANDLER %s;\n", aminfo->amhandler);
   14471              : 
   14472           68 :     appendPQExpBuffer(delq, "DROP ACCESS METHOD %s;\n",
   14473              :                       qamname);
   14474              : 
   14475           68 :     if (dopt->binary_upgrade)
   14476            4 :         binary_upgrade_extension_member(q, &aminfo->dobj,
   14477              :                                         "ACCESS METHOD", qamname, NULL);
   14478              : 
   14479           68 :     if (aminfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   14480           68 :         ArchiveEntry(fout, aminfo->dobj.catId, aminfo->dobj.dumpId,
   14481           68 :                      ARCHIVE_OPTS(.tag = aminfo->dobj.name,
   14482              :                                   .description = "ACCESS METHOD",
   14483              :                                   .section = SECTION_PRE_DATA,
   14484              :                                   .createStmt = q->data,
   14485              :                                   .dropStmt = delq->data));
   14486              : 
   14487              :     /* Dump Access Method Comments */
   14488           68 :     if (aminfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   14489            0 :         dumpComment(fout, "ACCESS METHOD", qamname,
   14490              :                     NULL, "",
   14491            0 :                     aminfo->dobj.catId, 0, aminfo->dobj.dumpId);
   14492              : 
   14493           68 :     destroyPQExpBuffer(q);
   14494           68 :     destroyPQExpBuffer(delq);
   14495           68 :     free(qamname);
   14496              : }
   14497              : 
   14498              : /*
   14499              :  * dumpOpclass
   14500              :  *    write out a single operator class definition
   14501              :  */
   14502              : static void
   14503          666 : dumpOpclass(Archive *fout, const OpclassInfo *opcinfo)
   14504              : {
   14505          666 :     DumpOptions *dopt = fout->dopt;
   14506              :     PQExpBuffer query;
   14507              :     PQExpBuffer q;
   14508              :     PQExpBuffer delq;
   14509              :     PQExpBuffer nameusing;
   14510              :     PGresult   *res;
   14511              :     int         ntups;
   14512              :     int         i_opcintype;
   14513              :     int         i_opckeytype;
   14514              :     int         i_opcdefault;
   14515              :     int         i_opcfamily;
   14516              :     int         i_opcfamilyname;
   14517              :     int         i_opcfamilynsp;
   14518              :     int         i_amname;
   14519              :     int         i_amopstrategy;
   14520              :     int         i_amopopr;
   14521              :     int         i_sortfamily;
   14522              :     int         i_sortfamilynsp;
   14523              :     int         i_amprocnum;
   14524              :     int         i_amproc;
   14525              :     int         i_amproclefttype;
   14526              :     int         i_amprocrighttype;
   14527              :     char       *opcintype;
   14528              :     char       *opckeytype;
   14529              :     char       *opcdefault;
   14530              :     char       *opcfamily;
   14531              :     char       *opcfamilyname;
   14532              :     char       *opcfamilynsp;
   14533              :     char       *amname;
   14534              :     char       *amopstrategy;
   14535              :     char       *amopopr;
   14536              :     char       *sortfamily;
   14537              :     char       *sortfamilynsp;
   14538              :     char       *amprocnum;
   14539              :     char       *amproc;
   14540              :     char       *amproclefttype;
   14541              :     char       *amprocrighttype;
   14542              :     bool        needComma;
   14543              :     int         i;
   14544              : 
   14545              :     /* Do nothing if not dumping schema */
   14546          666 :     if (!dopt->dumpSchema)
   14547           18 :         return;
   14548              : 
   14549          648 :     query = createPQExpBuffer();
   14550          648 :     q = createPQExpBuffer();
   14551          648 :     delq = createPQExpBuffer();
   14552          648 :     nameusing = createPQExpBuffer();
   14553              : 
   14554              :     /* Get additional fields from the pg_opclass row */
   14555          648 :     appendPQExpBuffer(query, "SELECT opcintype::pg_catalog.regtype, "
   14556              :                       "opckeytype::pg_catalog.regtype, "
   14557              :                       "opcdefault, opcfamily, "
   14558              :                       "opfname AS opcfamilyname, "
   14559              :                       "nspname AS opcfamilynsp, "
   14560              :                       "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opcmethod) AS amname "
   14561              :                       "FROM pg_catalog.pg_opclass c "
   14562              :                       "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = opcfamily "
   14563              :                       "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
   14564              :                       "WHERE c.oid = '%u'::pg_catalog.oid",
   14565          648 :                       opcinfo->dobj.catId.oid);
   14566              : 
   14567          648 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   14568              : 
   14569          648 :     i_opcintype = PQfnumber(res, "opcintype");
   14570          648 :     i_opckeytype = PQfnumber(res, "opckeytype");
   14571          648 :     i_opcdefault = PQfnumber(res, "opcdefault");
   14572          648 :     i_opcfamily = PQfnumber(res, "opcfamily");
   14573          648 :     i_opcfamilyname = PQfnumber(res, "opcfamilyname");
   14574          648 :     i_opcfamilynsp = PQfnumber(res, "opcfamilynsp");
   14575          648 :     i_amname = PQfnumber(res, "amname");
   14576              : 
   14577              :     /* opcintype may still be needed after we PQclear res */
   14578          648 :     opcintype = pg_strdup(PQgetvalue(res, 0, i_opcintype));
   14579          648 :     opckeytype = PQgetvalue(res, 0, i_opckeytype);
   14580          648 :     opcdefault = PQgetvalue(res, 0, i_opcdefault);
   14581              :     /* opcfamily will still be needed after we PQclear res */
   14582          648 :     opcfamily = pg_strdup(PQgetvalue(res, 0, i_opcfamily));
   14583          648 :     opcfamilyname = PQgetvalue(res, 0, i_opcfamilyname);
   14584          648 :     opcfamilynsp = PQgetvalue(res, 0, i_opcfamilynsp);
   14585              :     /* amname will still be needed after we PQclear res */
   14586          648 :     amname = pg_strdup(PQgetvalue(res, 0, i_amname));
   14587              : 
   14588          648 :     appendPQExpBuffer(delq, "DROP OPERATOR CLASS %s",
   14589          648 :                       fmtQualifiedDumpable(opcinfo));
   14590          648 :     appendPQExpBuffer(delq, " USING %s;\n",
   14591              :                       fmtId(amname));
   14592              : 
   14593              :     /* Build the fixed portion of the CREATE command */
   14594          648 :     appendPQExpBuffer(q, "CREATE OPERATOR CLASS %s\n    ",
   14595          648 :                       fmtQualifiedDumpable(opcinfo));
   14596          648 :     if (strcmp(opcdefault, "t") == 0)
   14597          366 :         appendPQExpBufferStr(q, "DEFAULT ");
   14598          648 :     appendPQExpBuffer(q, "FOR TYPE %s USING %s",
   14599              :                       opcintype,
   14600              :                       fmtId(amname));
   14601          648 :     if (strlen(opcfamilyname) > 0)
   14602              :     {
   14603          648 :         appendPQExpBufferStr(q, " FAMILY ");
   14604          648 :         appendPQExpBuffer(q, "%s.", fmtId(opcfamilynsp));
   14605          648 :         appendPQExpBufferStr(q, fmtId(opcfamilyname));
   14606              :     }
   14607          648 :     appendPQExpBufferStr(q, " AS\n    ");
   14608              : 
   14609          648 :     needComma = false;
   14610              : 
   14611          648 :     if (strcmp(opckeytype, "-") != 0)
   14612              :     {
   14613          252 :         appendPQExpBuffer(q, "STORAGE %s",
   14614              :                           opckeytype);
   14615          252 :         needComma = true;
   14616              :     }
   14617              : 
   14618          648 :     PQclear(res);
   14619              : 
   14620              :     /*
   14621              :      * Now fetch and print the OPERATOR entries (pg_amop rows).
   14622              :      *
   14623              :      * Print only those opfamily members that are tied to the opclass by
   14624              :      * pg_depend entries.
   14625              :      */
   14626          648 :     resetPQExpBuffer(query);
   14627          648 :     appendPQExpBuffer(query, "SELECT amopstrategy, "
   14628              :                       "amopopr::pg_catalog.regoperator, "
   14629              :                       "opfname AS sortfamily, "
   14630              :                       "nspname AS sortfamilynsp "
   14631              :                       "FROM pg_catalog.pg_amop ao JOIN pg_catalog.pg_depend ON "
   14632              :                       "(classid = 'pg_catalog.pg_amop'::pg_catalog.regclass AND objid = ao.oid) "
   14633              :                       "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = amopsortfamily "
   14634              :                       "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
   14635              :                       "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
   14636              :                       "AND refobjid = '%u'::pg_catalog.oid "
   14637              :                       "AND amopfamily = '%s'::pg_catalog.oid "
   14638              :                       "ORDER BY amopstrategy",
   14639          648 :                       opcinfo->dobj.catId.oid,
   14640              :                       opcfamily);
   14641              : 
   14642          648 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   14643              : 
   14644          648 :     ntups = PQntuples(res);
   14645              : 
   14646          648 :     i_amopstrategy = PQfnumber(res, "amopstrategy");
   14647          648 :     i_amopopr = PQfnumber(res, "amopopr");
   14648          648 :     i_sortfamily = PQfnumber(res, "sortfamily");
   14649          648 :     i_sortfamilynsp = PQfnumber(res, "sortfamilynsp");
   14650              : 
   14651          850 :     for (i = 0; i < ntups; i++)
   14652              :     {
   14653          202 :         amopstrategy = PQgetvalue(res, i, i_amopstrategy);
   14654          202 :         amopopr = PQgetvalue(res, i, i_amopopr);
   14655          202 :         sortfamily = PQgetvalue(res, i, i_sortfamily);
   14656          202 :         sortfamilynsp = PQgetvalue(res, i, i_sortfamilynsp);
   14657              : 
   14658          202 :         if (needComma)
   14659          128 :             appendPQExpBufferStr(q, " ,\n    ");
   14660              : 
   14661          202 :         appendPQExpBuffer(q, "OPERATOR %s %s",
   14662              :                           amopstrategy, amopopr);
   14663              : 
   14664          202 :         if (strlen(sortfamily) > 0)
   14665              :         {
   14666            0 :             appendPQExpBufferStr(q, " FOR ORDER BY ");
   14667            0 :             appendPQExpBuffer(q, "%s.", fmtId(sortfamilynsp));
   14668            0 :             appendPQExpBufferStr(q, fmtId(sortfamily));
   14669              :         }
   14670              : 
   14671          202 :         needComma = true;
   14672              :     }
   14673              : 
   14674          648 :     PQclear(res);
   14675              : 
   14676              :     /*
   14677              :      * Now fetch and print the FUNCTION entries (pg_amproc rows).
   14678              :      *
   14679              :      * Print only those opfamily members that are tied to the opclass by
   14680              :      * pg_depend entries.
   14681              :      *
   14682              :      * We print the amproclefttype/amprocrighttype even though in most cases
   14683              :      * the backend could deduce the right values, because of the corner case
   14684              :      * of a btree sort support function for a cross-type comparison.
   14685              :      */
   14686          648 :     resetPQExpBuffer(query);
   14687              : 
   14688          648 :     appendPQExpBuffer(query, "SELECT amprocnum, "
   14689              :                       "amproc::pg_catalog.regprocedure, "
   14690              :                       "amproclefttype::pg_catalog.regtype, "
   14691              :                       "amprocrighttype::pg_catalog.regtype "
   14692              :                       "FROM pg_catalog.pg_amproc ap, pg_catalog.pg_depend "
   14693              :                       "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
   14694              :                       "AND refobjid = '%u'::pg_catalog.oid "
   14695              :                       "AND classid = 'pg_catalog.pg_amproc'::pg_catalog.regclass "
   14696              :                       "AND objid = ap.oid "
   14697              :                       "ORDER BY amprocnum",
   14698          648 :                       opcinfo->dobj.catId.oid);
   14699              : 
   14700          648 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   14701              : 
   14702          648 :     ntups = PQntuples(res);
   14703              : 
   14704          648 :     i_amprocnum = PQfnumber(res, "amprocnum");
   14705          648 :     i_amproc = PQfnumber(res, "amproc");
   14706          648 :     i_amproclefttype = PQfnumber(res, "amproclefttype");
   14707          648 :     i_amprocrighttype = PQfnumber(res, "amprocrighttype");
   14708              : 
   14709          680 :     for (i = 0; i < ntups; i++)
   14710              :     {
   14711           32 :         amprocnum = PQgetvalue(res, i, i_amprocnum);
   14712           32 :         amproc = PQgetvalue(res, i, i_amproc);
   14713           32 :         amproclefttype = PQgetvalue(res, i, i_amproclefttype);
   14714           32 :         amprocrighttype = PQgetvalue(res, i, i_amprocrighttype);
   14715              : 
   14716           32 :         if (needComma)
   14717           32 :             appendPQExpBufferStr(q, " ,\n    ");
   14718              : 
   14719           32 :         appendPQExpBuffer(q, "FUNCTION %s", amprocnum);
   14720              : 
   14721           32 :         if (*amproclefttype && *amprocrighttype)
   14722           32 :             appendPQExpBuffer(q, " (%s, %s)", amproclefttype, amprocrighttype);
   14723              : 
   14724           32 :         appendPQExpBuffer(q, " %s", amproc);
   14725              : 
   14726           32 :         needComma = true;
   14727              :     }
   14728              : 
   14729          648 :     PQclear(res);
   14730              : 
   14731              :     /*
   14732              :      * If needComma is still false it means we haven't added anything after
   14733              :      * the AS keyword.  To avoid printing broken SQL, append a dummy STORAGE
   14734              :      * clause with the same datatype.  This isn't sanctioned by the
   14735              :      * documentation, but actually DefineOpClass will treat it as a no-op.
   14736              :      */
   14737          648 :     if (!needComma)
   14738          322 :         appendPQExpBuffer(q, "STORAGE %s", opcintype);
   14739              : 
   14740          648 :     appendPQExpBufferStr(q, ";\n");
   14741              : 
   14742          648 :     appendPQExpBufferStr(nameusing, fmtId(opcinfo->dobj.name));
   14743          648 :     appendPQExpBuffer(nameusing, " USING %s",
   14744              :                       fmtId(amname));
   14745              : 
   14746          648 :     if (dopt->binary_upgrade)
   14747            6 :         binary_upgrade_extension_member(q, &opcinfo->dobj,
   14748            6 :                                         "OPERATOR CLASS", nameusing->data,
   14749            6 :                                         opcinfo->dobj.namespace->dobj.name);
   14750              : 
   14751          648 :     if (opcinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   14752          648 :         ArchiveEntry(fout, opcinfo->dobj.catId, opcinfo->dobj.dumpId,
   14753          648 :                      ARCHIVE_OPTS(.tag = opcinfo->dobj.name,
   14754              :                                   .namespace = opcinfo->dobj.namespace->dobj.name,
   14755              :                                   .owner = opcinfo->rolname,
   14756              :                                   .description = "OPERATOR CLASS",
   14757              :                                   .section = SECTION_PRE_DATA,
   14758              :                                   .createStmt = q->data,
   14759              :                                   .dropStmt = delq->data));
   14760              : 
   14761              :     /* Dump Operator Class Comments */
   14762          648 :     if (opcinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   14763            0 :         dumpComment(fout, "OPERATOR CLASS", nameusing->data,
   14764            0 :                     opcinfo->dobj.namespace->dobj.name, opcinfo->rolname,
   14765            0 :                     opcinfo->dobj.catId, 0, opcinfo->dobj.dumpId);
   14766              : 
   14767          648 :     free(opcintype);
   14768          648 :     free(opcfamily);
   14769          648 :     free(amname);
   14770          648 :     destroyPQExpBuffer(query);
   14771          648 :     destroyPQExpBuffer(q);
   14772          648 :     destroyPQExpBuffer(delq);
   14773          648 :     destroyPQExpBuffer(nameusing);
   14774              : }
   14775              : 
   14776              : /*
   14777              :  * dumpOpfamily
   14778              :  *    write out a single operator family definition
   14779              :  *
   14780              :  * Note: this also dumps any "loose" operator members that aren't bound to a
   14781              :  * specific opclass within the opfamily.
   14782              :  */
   14783              : static void
   14784          555 : dumpOpfamily(Archive *fout, const OpfamilyInfo *opfinfo)
   14785              : {
   14786          555 :     DumpOptions *dopt = fout->dopt;
   14787              :     PQExpBuffer query;
   14788              :     PQExpBuffer q;
   14789              :     PQExpBuffer delq;
   14790              :     PQExpBuffer nameusing;
   14791              :     PGresult   *res;
   14792              :     PGresult   *res_ops;
   14793              :     PGresult   *res_procs;
   14794              :     int         ntups;
   14795              :     int         i_amname;
   14796              :     int         i_amopstrategy;
   14797              :     int         i_amopopr;
   14798              :     int         i_sortfamily;
   14799              :     int         i_sortfamilynsp;
   14800              :     int         i_amprocnum;
   14801              :     int         i_amproc;
   14802              :     int         i_amproclefttype;
   14803              :     int         i_amprocrighttype;
   14804              :     char       *amname;
   14805              :     char       *amopstrategy;
   14806              :     char       *amopopr;
   14807              :     char       *sortfamily;
   14808              :     char       *sortfamilynsp;
   14809              :     char       *amprocnum;
   14810              :     char       *amproc;
   14811              :     char       *amproclefttype;
   14812              :     char       *amprocrighttype;
   14813              :     bool        needComma;
   14814              :     int         i;
   14815              : 
   14816              :     /* Do nothing if not dumping schema */
   14817          555 :     if (!dopt->dumpSchema)
   14818           12 :         return;
   14819              : 
   14820          543 :     query = createPQExpBuffer();
   14821          543 :     q = createPQExpBuffer();
   14822          543 :     delq = createPQExpBuffer();
   14823          543 :     nameusing = createPQExpBuffer();
   14824              : 
   14825              :     /*
   14826              :      * Fetch only those opfamily members that are tied directly to the
   14827              :      * opfamily by pg_depend entries.
   14828              :      */
   14829          543 :     appendPQExpBuffer(query, "SELECT amopstrategy, "
   14830              :                       "amopopr::pg_catalog.regoperator, "
   14831              :                       "opfname AS sortfamily, "
   14832              :                       "nspname AS sortfamilynsp "
   14833              :                       "FROM pg_catalog.pg_amop ao JOIN pg_catalog.pg_depend ON "
   14834              :                       "(classid = 'pg_catalog.pg_amop'::pg_catalog.regclass AND objid = ao.oid) "
   14835              :                       "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = amopsortfamily "
   14836              :                       "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
   14837              :                       "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
   14838              :                       "AND refobjid = '%u'::pg_catalog.oid "
   14839              :                       "AND amopfamily = '%u'::pg_catalog.oid "
   14840              :                       "ORDER BY amopstrategy",
   14841          543 :                       opfinfo->dobj.catId.oid,
   14842          543 :                       opfinfo->dobj.catId.oid);
   14843              : 
   14844          543 :     res_ops = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   14845              : 
   14846          543 :     resetPQExpBuffer(query);
   14847              : 
   14848          543 :     appendPQExpBuffer(query, "SELECT amprocnum, "
   14849              :                       "amproc::pg_catalog.regprocedure, "
   14850              :                       "amproclefttype::pg_catalog.regtype, "
   14851              :                       "amprocrighttype::pg_catalog.regtype "
   14852              :                       "FROM pg_catalog.pg_amproc ap, pg_catalog.pg_depend "
   14853              :                       "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
   14854              :                       "AND refobjid = '%u'::pg_catalog.oid "
   14855              :                       "AND classid = 'pg_catalog.pg_amproc'::pg_catalog.regclass "
   14856              :                       "AND objid = ap.oid "
   14857              :                       "ORDER BY amprocnum",
   14858          543 :                       opfinfo->dobj.catId.oid);
   14859              : 
   14860          543 :     res_procs = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   14861              : 
   14862              :     /* Get additional fields from the pg_opfamily row */
   14863          543 :     resetPQExpBuffer(query);
   14864              : 
   14865          543 :     appendPQExpBuffer(query, "SELECT "
   14866              :                       "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opfmethod) AS amname "
   14867              :                       "FROM pg_catalog.pg_opfamily "
   14868              :                       "WHERE oid = '%u'::pg_catalog.oid",
   14869          543 :                       opfinfo->dobj.catId.oid);
   14870              : 
   14871          543 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   14872              : 
   14873          543 :     i_amname = PQfnumber(res, "amname");
   14874              : 
   14875              :     /* amname will still be needed after we PQclear res */
   14876          543 :     amname = pg_strdup(PQgetvalue(res, 0, i_amname));
   14877              : 
   14878          543 :     appendPQExpBuffer(delq, "DROP OPERATOR FAMILY %s",
   14879          543 :                       fmtQualifiedDumpable(opfinfo));
   14880          543 :     appendPQExpBuffer(delq, " USING %s;\n",
   14881              :                       fmtId(amname));
   14882              : 
   14883              :     /* Build the fixed portion of the CREATE command */
   14884          543 :     appendPQExpBuffer(q, "CREATE OPERATOR FAMILY %s",
   14885          543 :                       fmtQualifiedDumpable(opfinfo));
   14886          543 :     appendPQExpBuffer(q, " USING %s;\n",
   14887              :                       fmtId(amname));
   14888              : 
   14889          543 :     PQclear(res);
   14890              : 
   14891              :     /* Do we need an ALTER to add loose members? */
   14892          543 :     if (PQntuples(res_ops) > 0 || PQntuples(res_procs) > 0)
   14893              :     {
   14894           47 :         appendPQExpBuffer(q, "ALTER OPERATOR FAMILY %s",
   14895           47 :                           fmtQualifiedDumpable(opfinfo));
   14896           47 :         appendPQExpBuffer(q, " USING %s ADD\n    ",
   14897              :                           fmtId(amname));
   14898              : 
   14899           47 :         needComma = false;
   14900              : 
   14901              :         /*
   14902              :          * Now fetch and print the OPERATOR entries (pg_amop rows).
   14903              :          */
   14904           47 :         ntups = PQntuples(res_ops);
   14905              : 
   14906           47 :         i_amopstrategy = PQfnumber(res_ops, "amopstrategy");
   14907           47 :         i_amopopr = PQfnumber(res_ops, "amopopr");
   14908           47 :         i_sortfamily = PQfnumber(res_ops, "sortfamily");
   14909           47 :         i_sortfamilynsp = PQfnumber(res_ops, "sortfamilynsp");
   14910              : 
   14911          207 :         for (i = 0; i < ntups; i++)
   14912              :         {
   14913          160 :             amopstrategy = PQgetvalue(res_ops, i, i_amopstrategy);
   14914          160 :             amopopr = PQgetvalue(res_ops, i, i_amopopr);
   14915          160 :             sortfamily = PQgetvalue(res_ops, i, i_sortfamily);
   14916          160 :             sortfamilynsp = PQgetvalue(res_ops, i, i_sortfamilynsp);
   14917              : 
   14918          160 :             if (needComma)
   14919          128 :                 appendPQExpBufferStr(q, " ,\n    ");
   14920              : 
   14921          160 :             appendPQExpBuffer(q, "OPERATOR %s %s",
   14922              :                               amopstrategy, amopopr);
   14923              : 
   14924          160 :             if (strlen(sortfamily) > 0)
   14925              :             {
   14926            0 :                 appendPQExpBufferStr(q, " FOR ORDER BY ");
   14927            0 :                 appendPQExpBuffer(q, "%s.", fmtId(sortfamilynsp));
   14928            0 :                 appendPQExpBufferStr(q, fmtId(sortfamily));
   14929              :             }
   14930              : 
   14931          160 :             needComma = true;
   14932              :         }
   14933              : 
   14934              :         /*
   14935              :          * Now fetch and print the FUNCTION entries (pg_amproc rows).
   14936              :          */
   14937           47 :         ntups = PQntuples(res_procs);
   14938              : 
   14939           47 :         i_amprocnum = PQfnumber(res_procs, "amprocnum");
   14940           47 :         i_amproc = PQfnumber(res_procs, "amproc");
   14941           47 :         i_amproclefttype = PQfnumber(res_procs, "amproclefttype");
   14942           47 :         i_amprocrighttype = PQfnumber(res_procs, "amprocrighttype");
   14943              : 
   14944          222 :         for (i = 0; i < ntups; i++)
   14945              :         {
   14946          175 :             amprocnum = PQgetvalue(res_procs, i, i_amprocnum);
   14947          175 :             amproc = PQgetvalue(res_procs, i, i_amproc);
   14948          175 :             amproclefttype = PQgetvalue(res_procs, i, i_amproclefttype);
   14949          175 :             amprocrighttype = PQgetvalue(res_procs, i, i_amprocrighttype);
   14950              : 
   14951          175 :             if (needComma)
   14952          160 :                 appendPQExpBufferStr(q, " ,\n    ");
   14953              : 
   14954          175 :             appendPQExpBuffer(q, "FUNCTION %s (%s, %s) %s",
   14955              :                               amprocnum, amproclefttype, amprocrighttype,
   14956              :                               amproc);
   14957              : 
   14958          175 :             needComma = true;
   14959              :         }
   14960              : 
   14961           47 :         appendPQExpBufferStr(q, ";\n");
   14962              :     }
   14963              : 
   14964          543 :     appendPQExpBufferStr(nameusing, fmtId(opfinfo->dobj.name));
   14965          543 :     appendPQExpBuffer(nameusing, " USING %s",
   14966              :                       fmtId(amname));
   14967              : 
   14968          543 :     if (dopt->binary_upgrade)
   14969            9 :         binary_upgrade_extension_member(q, &opfinfo->dobj,
   14970            9 :                                         "OPERATOR FAMILY", nameusing->data,
   14971            9 :                                         opfinfo->dobj.namespace->dobj.name);
   14972              : 
   14973          543 :     if (opfinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   14974          543 :         ArchiveEntry(fout, opfinfo->dobj.catId, opfinfo->dobj.dumpId,
   14975          543 :                      ARCHIVE_OPTS(.tag = opfinfo->dobj.name,
   14976              :                                   .namespace = opfinfo->dobj.namespace->dobj.name,
   14977              :                                   .owner = opfinfo->rolname,
   14978              :                                   .description = "OPERATOR FAMILY",
   14979              :                                   .section = SECTION_PRE_DATA,
   14980              :                                   .createStmt = q->data,
   14981              :                                   .dropStmt = delq->data));
   14982              : 
   14983              :     /* Dump Operator Family Comments */
   14984          543 :     if (opfinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   14985            0 :         dumpComment(fout, "OPERATOR FAMILY", nameusing->data,
   14986            0 :                     opfinfo->dobj.namespace->dobj.name, opfinfo->rolname,
   14987            0 :                     opfinfo->dobj.catId, 0, opfinfo->dobj.dumpId);
   14988              : 
   14989          543 :     free(amname);
   14990          543 :     PQclear(res_ops);
   14991          543 :     PQclear(res_procs);
   14992          543 :     destroyPQExpBuffer(query);
   14993          543 :     destroyPQExpBuffer(q);
   14994          543 :     destroyPQExpBuffer(delq);
   14995          543 :     destroyPQExpBuffer(nameusing);
   14996              : }
   14997              : 
   14998              : /*
   14999              :  * dumpCollation
   15000              :  *    write out a single collation definition
   15001              :  */
   15002              : static void
   15003         2729 : dumpCollation(Archive *fout, const CollInfo *collinfo)
   15004              : {
   15005         2729 :     DumpOptions *dopt = fout->dopt;
   15006              :     PQExpBuffer query;
   15007              :     PQExpBuffer q;
   15008              :     PQExpBuffer delq;
   15009              :     char       *qcollname;
   15010              :     PGresult   *res;
   15011              :     int         i_collprovider;
   15012              :     int         i_collisdeterministic;
   15013              :     int         i_collcollate;
   15014              :     int         i_collctype;
   15015              :     int         i_colllocale;
   15016              :     int         i_collicurules;
   15017              :     const char *collprovider;
   15018              :     const char *collcollate;
   15019              :     const char *collctype;
   15020              :     const char *colllocale;
   15021              :     const char *collicurules;
   15022              : 
   15023              :     /* Do nothing if not dumping schema */
   15024         2729 :     if (!dopt->dumpSchema)
   15025           12 :         return;
   15026              : 
   15027         2717 :     query = createPQExpBuffer();
   15028         2717 :     q = createPQExpBuffer();
   15029         2717 :     delq = createPQExpBuffer();
   15030              : 
   15031         2717 :     qcollname = pg_strdup(fmtId(collinfo->dobj.name));
   15032              : 
   15033              :     /* Get collation-specific details */
   15034         2717 :     appendPQExpBufferStr(query, "SELECT ");
   15035              : 
   15036         2717 :     if (fout->remoteVersion >= 100000)
   15037         2717 :         appendPQExpBufferStr(query,
   15038              :                              "collprovider, "
   15039              :                              "collversion, ");
   15040              :     else
   15041            0 :         appendPQExpBufferStr(query,
   15042              :                              "'c' AS collprovider, "
   15043              :                              "NULL AS collversion, ");
   15044              : 
   15045         2717 :     if (fout->remoteVersion >= 120000)
   15046         2717 :         appendPQExpBufferStr(query,
   15047              :                              "collisdeterministic, ");
   15048              :     else
   15049            0 :         appendPQExpBufferStr(query,
   15050              :                              "true AS collisdeterministic, ");
   15051              : 
   15052         2717 :     if (fout->remoteVersion >= 170000)
   15053         2717 :         appendPQExpBufferStr(query,
   15054              :                              "colllocale, ");
   15055            0 :     else if (fout->remoteVersion >= 150000)
   15056            0 :         appendPQExpBufferStr(query,
   15057              :                              "colliculocale AS colllocale, ");
   15058              :     else
   15059            0 :         appendPQExpBufferStr(query,
   15060              :                              "NULL AS colllocale, ");
   15061              : 
   15062         2717 :     if (fout->remoteVersion >= 160000)
   15063         2717 :         appendPQExpBufferStr(query,
   15064              :                              "collicurules, ");
   15065              :     else
   15066            0 :         appendPQExpBufferStr(query,
   15067              :                              "NULL AS collicurules, ");
   15068              : 
   15069         2717 :     appendPQExpBuffer(query,
   15070              :                       "collcollate, "
   15071              :                       "collctype "
   15072              :                       "FROM pg_catalog.pg_collation c "
   15073              :                       "WHERE c.oid = '%u'::pg_catalog.oid",
   15074         2717 :                       collinfo->dobj.catId.oid);
   15075              : 
   15076         2717 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   15077              : 
   15078         2717 :     i_collprovider = PQfnumber(res, "collprovider");
   15079         2717 :     i_collisdeterministic = PQfnumber(res, "collisdeterministic");
   15080         2717 :     i_collcollate = PQfnumber(res, "collcollate");
   15081         2717 :     i_collctype = PQfnumber(res, "collctype");
   15082         2717 :     i_colllocale = PQfnumber(res, "colllocale");
   15083         2717 :     i_collicurules = PQfnumber(res, "collicurules");
   15084              : 
   15085         2717 :     collprovider = PQgetvalue(res, 0, i_collprovider);
   15086              : 
   15087         2717 :     if (!PQgetisnull(res, 0, i_collcollate))
   15088           46 :         collcollate = PQgetvalue(res, 0, i_collcollate);
   15089              :     else
   15090         2671 :         collcollate = NULL;
   15091              : 
   15092         2717 :     if (!PQgetisnull(res, 0, i_collctype))
   15093           46 :         collctype = PQgetvalue(res, 0, i_collctype);
   15094              :     else
   15095         2671 :         collctype = NULL;
   15096              : 
   15097              :     /*
   15098              :      * Before version 15, collcollate and collctype were of type NAME and
   15099              :      * non-nullable. Treat empty strings as NULL for consistency.
   15100              :      */
   15101         2717 :     if (fout->remoteVersion < 150000)
   15102              :     {
   15103            0 :         if (collcollate[0] == '\0')
   15104            0 :             collcollate = NULL;
   15105            0 :         if (collctype[0] == '\0')
   15106            0 :             collctype = NULL;
   15107              :     }
   15108              : 
   15109         2717 :     if (!PQgetisnull(res, 0, i_colllocale))
   15110         2668 :         colllocale = PQgetvalue(res, 0, i_colllocale);
   15111              :     else
   15112           49 :         colllocale = NULL;
   15113              : 
   15114         2717 :     if (!PQgetisnull(res, 0, i_collicurules))
   15115            0 :         collicurules = PQgetvalue(res, 0, i_collicurules);
   15116              :     else
   15117         2717 :         collicurules = NULL;
   15118              : 
   15119         2717 :     appendPQExpBuffer(delq, "DROP COLLATION %s;\n",
   15120         2717 :                       fmtQualifiedDumpable(collinfo));
   15121              : 
   15122         2717 :     appendPQExpBuffer(q, "CREATE COLLATION %s (",
   15123         2717 :                       fmtQualifiedDumpable(collinfo));
   15124              : 
   15125         2717 :     appendPQExpBufferStr(q, "provider = ");
   15126         2717 :     if (collprovider[0] == 'b')
   15127           19 :         appendPQExpBufferStr(q, "builtin");
   15128         2698 :     else if (collprovider[0] == 'c')
   15129           46 :         appendPQExpBufferStr(q, "libc");
   15130         2652 :     else if (collprovider[0] == 'i')
   15131         2649 :         appendPQExpBufferStr(q, "icu");
   15132            3 :     else if (collprovider[0] == 'd')
   15133              :         /* to allow dumping pg_catalog; not accepted on input */
   15134            3 :         appendPQExpBufferStr(q, "default");
   15135              :     else
   15136            0 :         pg_fatal("unrecognized collation provider: %s",
   15137              :                  collprovider);
   15138              : 
   15139         2717 :     if (strcmp(PQgetvalue(res, 0, i_collisdeterministic), "f") == 0)
   15140            0 :         appendPQExpBufferStr(q, ", deterministic = false");
   15141              : 
   15142         2717 :     if (collprovider[0] == 'd')
   15143              :     {
   15144            3 :         if (collcollate || collctype || colllocale || collicurules)
   15145            0 :             pg_log_warning("invalid collation \"%s\"", qcollname);
   15146              : 
   15147              :         /* no locale -- the default collation cannot be reloaded anyway */
   15148              :     }
   15149         2714 :     else if (collprovider[0] == 'b')
   15150              :     {
   15151           19 :         if (collcollate || collctype || !colllocale || collicurules)
   15152            0 :             pg_log_warning("invalid collation \"%s\"", qcollname);
   15153              : 
   15154           19 :         appendPQExpBufferStr(q, ", locale = ");
   15155           19 :         appendStringLiteralAH(q, colllocale ? colllocale : "",
   15156              :                               fout);
   15157              :     }
   15158         2695 :     else if (collprovider[0] == 'i')
   15159              :     {
   15160         2649 :         if (fout->remoteVersion >= 150000)
   15161              :         {
   15162         2649 :             if (collcollate || collctype || !colllocale)
   15163            0 :                 pg_log_warning("invalid collation \"%s\"", qcollname);
   15164              : 
   15165         2649 :             appendPQExpBufferStr(q, ", locale = ");
   15166         2649 :             appendStringLiteralAH(q, colllocale ? colllocale : "",
   15167              :                                   fout);
   15168              :         }
   15169              :         else
   15170              :         {
   15171            0 :             if (!collcollate || !collctype || colllocale ||
   15172            0 :                 strcmp(collcollate, collctype) != 0)
   15173            0 :                 pg_log_warning("invalid collation \"%s\"", qcollname);
   15174              : 
   15175            0 :             appendPQExpBufferStr(q, ", locale = ");
   15176            0 :             appendStringLiteralAH(q, collcollate ? collcollate : "", fout);
   15177              :         }
   15178              : 
   15179         2649 :         if (collicurules)
   15180              :         {
   15181            0 :             appendPQExpBufferStr(q, ", rules = ");
   15182            0 :             appendStringLiteralAH(q, collicurules ? collicurules : "", fout);
   15183              :         }
   15184              :     }
   15185           46 :     else if (collprovider[0] == 'c')
   15186              :     {
   15187           46 :         if (colllocale || collicurules || !collcollate || !collctype)
   15188            0 :             pg_log_warning("invalid collation \"%s\"", qcollname);
   15189              : 
   15190           46 :         if (collcollate && collctype && strcmp(collcollate, collctype) == 0)
   15191              :         {
   15192           46 :             appendPQExpBufferStr(q, ", locale = ");
   15193           46 :             appendStringLiteralAH(q, collcollate ? collcollate : "", fout);
   15194              :         }
   15195              :         else
   15196              :         {
   15197            0 :             appendPQExpBufferStr(q, ", lc_collate = ");
   15198            0 :             appendStringLiteralAH(q, collcollate ? collcollate : "", fout);
   15199            0 :             appendPQExpBufferStr(q, ", lc_ctype = ");
   15200            0 :             appendStringLiteralAH(q, collctype ? collctype : "", fout);
   15201              :         }
   15202              :     }
   15203              :     else
   15204            0 :         pg_fatal("unrecognized collation provider: %s", collprovider);
   15205              : 
   15206              :     /*
   15207              :      * For binary upgrade, carry over the collation version.  For normal
   15208              :      * dump/restore, omit the version, so that it is computed upon restore.
   15209              :      */
   15210         2717 :     if (dopt->binary_upgrade)
   15211              :     {
   15212              :         int         i_collversion;
   15213              : 
   15214            5 :         i_collversion = PQfnumber(res, "collversion");
   15215            5 :         if (!PQgetisnull(res, 0, i_collversion))
   15216              :         {
   15217            4 :             appendPQExpBufferStr(q, ", version = ");
   15218            4 :             appendStringLiteralAH(q,
   15219              :                                   PQgetvalue(res, 0, i_collversion),
   15220              :                                   fout);
   15221              :         }
   15222              :     }
   15223              : 
   15224         2717 :     appendPQExpBufferStr(q, ");\n");
   15225              : 
   15226         2717 :     if (dopt->binary_upgrade)
   15227            5 :         binary_upgrade_extension_member(q, &collinfo->dobj,
   15228              :                                         "COLLATION", qcollname,
   15229            5 :                                         collinfo->dobj.namespace->dobj.name);
   15230              : 
   15231         2717 :     if (collinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   15232         2717 :         ArchiveEntry(fout, collinfo->dobj.catId, collinfo->dobj.dumpId,
   15233         2717 :                      ARCHIVE_OPTS(.tag = collinfo->dobj.name,
   15234              :                                   .namespace = collinfo->dobj.namespace->dobj.name,
   15235              :                                   .owner = collinfo->rolname,
   15236              :                                   .description = "COLLATION",
   15237              :                                   .section = SECTION_PRE_DATA,
   15238              :                                   .createStmt = q->data,
   15239              :                                   .dropStmt = delq->data));
   15240              : 
   15241              :     /* Dump Collation Comments */
   15242         2717 :     if (collinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   15243         2611 :         dumpComment(fout, "COLLATION", qcollname,
   15244         2611 :                     collinfo->dobj.namespace->dobj.name, collinfo->rolname,
   15245         2611 :                     collinfo->dobj.catId, 0, collinfo->dobj.dumpId);
   15246              : 
   15247         2717 :     PQclear(res);
   15248              : 
   15249         2717 :     destroyPQExpBuffer(query);
   15250         2717 :     destroyPQExpBuffer(q);
   15251         2717 :     destroyPQExpBuffer(delq);
   15252         2717 :     free(qcollname);
   15253              : }
   15254              : 
   15255              : /*
   15256              :  * dumpConversion
   15257              :  *    write out a single conversion definition
   15258              :  */
   15259              : static void
   15260          422 : dumpConversion(Archive *fout, const ConvInfo *convinfo)
   15261              : {
   15262          422 :     DumpOptions *dopt = fout->dopt;
   15263              :     PQExpBuffer query;
   15264              :     PQExpBuffer q;
   15265              :     PQExpBuffer delq;
   15266              :     char       *qconvname;
   15267              :     PGresult   *res;
   15268              :     int         i_conforencoding;
   15269              :     int         i_contoencoding;
   15270              :     int         i_conproc;
   15271              :     int         i_condefault;
   15272              :     const char *conforencoding;
   15273              :     const char *contoencoding;
   15274              :     const char *conproc;
   15275              :     bool        condefault;
   15276              : 
   15277              :     /* Do nothing if not dumping schema */
   15278          422 :     if (!dopt->dumpSchema)
   15279            6 :         return;
   15280              : 
   15281          416 :     query = createPQExpBuffer();
   15282          416 :     q = createPQExpBuffer();
   15283          416 :     delq = createPQExpBuffer();
   15284              : 
   15285          416 :     qconvname = pg_strdup(fmtId(convinfo->dobj.name));
   15286              : 
   15287              :     /* Get conversion-specific details */
   15288          416 :     appendPQExpBuffer(query, "SELECT "
   15289              :                       "pg_catalog.pg_encoding_to_char(conforencoding) AS conforencoding, "
   15290              :                       "pg_catalog.pg_encoding_to_char(contoencoding) AS contoencoding, "
   15291              :                       "conproc, condefault "
   15292              :                       "FROM pg_catalog.pg_conversion c "
   15293              :                       "WHERE c.oid = '%u'::pg_catalog.oid",
   15294          416 :                       convinfo->dobj.catId.oid);
   15295              : 
   15296          416 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   15297              : 
   15298          416 :     i_conforencoding = PQfnumber(res, "conforencoding");
   15299          416 :     i_contoencoding = PQfnumber(res, "contoencoding");
   15300          416 :     i_conproc = PQfnumber(res, "conproc");
   15301          416 :     i_condefault = PQfnumber(res, "condefault");
   15302              : 
   15303          416 :     conforencoding = PQgetvalue(res, 0, i_conforencoding);
   15304          416 :     contoencoding = PQgetvalue(res, 0, i_contoencoding);
   15305          416 :     conproc = PQgetvalue(res, 0, i_conproc);
   15306          416 :     condefault = (PQgetvalue(res, 0, i_condefault)[0] == 't');
   15307              : 
   15308          416 :     appendPQExpBuffer(delq, "DROP CONVERSION %s;\n",
   15309          416 :                       fmtQualifiedDumpable(convinfo));
   15310              : 
   15311          416 :     appendPQExpBuffer(q, "CREATE %sCONVERSION %s FOR ",
   15312              :                       (condefault) ? "DEFAULT " : "",
   15313          416 :                       fmtQualifiedDumpable(convinfo));
   15314          416 :     appendStringLiteralAH(q, conforencoding, fout);
   15315          416 :     appendPQExpBufferStr(q, " TO ");
   15316          416 :     appendStringLiteralAH(q, contoencoding, fout);
   15317              :     /* regproc output is already sufficiently quoted */
   15318          416 :     appendPQExpBuffer(q, " FROM %s;\n", conproc);
   15319              : 
   15320          416 :     if (dopt->binary_upgrade)
   15321            1 :         binary_upgrade_extension_member(q, &convinfo->dobj,
   15322              :                                         "CONVERSION", qconvname,
   15323            1 :                                         convinfo->dobj.namespace->dobj.name);
   15324              : 
   15325          416 :     if (convinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   15326          416 :         ArchiveEntry(fout, convinfo->dobj.catId, convinfo->dobj.dumpId,
   15327          416 :                      ARCHIVE_OPTS(.tag = convinfo->dobj.name,
   15328              :                                   .namespace = convinfo->dobj.namespace->dobj.name,
   15329              :                                   .owner = convinfo->rolname,
   15330              :                                   .description = "CONVERSION",
   15331              :                                   .section = SECTION_PRE_DATA,
   15332              :                                   .createStmt = q->data,
   15333              :                                   .dropStmt = delq->data));
   15334              : 
   15335              :     /* Dump Conversion Comments */
   15336          416 :     if (convinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   15337          416 :         dumpComment(fout, "CONVERSION", qconvname,
   15338          416 :                     convinfo->dobj.namespace->dobj.name, convinfo->rolname,
   15339          416 :                     convinfo->dobj.catId, 0, convinfo->dobj.dumpId);
   15340              : 
   15341          416 :     PQclear(res);
   15342              : 
   15343          416 :     destroyPQExpBuffer(query);
   15344          416 :     destroyPQExpBuffer(q);
   15345          416 :     destroyPQExpBuffer(delq);
   15346          416 :     free(qconvname);
   15347              : }
   15348              : 
   15349              : /*
   15350              :  * format_aggregate_signature: generate aggregate name and argument list
   15351              :  *
   15352              :  * The argument type names are qualified if needed.  The aggregate name
   15353              :  * is never qualified.
   15354              :  */
   15355              : static char *
   15356          285 : format_aggregate_signature(const AggInfo *agginfo, Archive *fout, bool honor_quotes)
   15357              : {
   15358              :     PQExpBufferData buf;
   15359              :     int         j;
   15360              : 
   15361          285 :     initPQExpBuffer(&buf);
   15362          285 :     if (honor_quotes)
   15363            0 :         appendPQExpBufferStr(&buf, fmtId(agginfo->aggfn.dobj.name));
   15364              :     else
   15365          285 :         appendPQExpBufferStr(&buf, agginfo->aggfn.dobj.name);
   15366              : 
   15367          285 :     if (agginfo->aggfn.nargs == 0)
   15368           40 :         appendPQExpBufferStr(&buf, "(*)");
   15369              :     else
   15370              :     {
   15371          245 :         appendPQExpBufferChar(&buf, '(');
   15372          535 :         for (j = 0; j < agginfo->aggfn.nargs; j++)
   15373          290 :             appendPQExpBuffer(&buf, "%s%s",
   15374              :                               (j > 0) ? ", " : "",
   15375              :                               getFormattedTypeName(fout,
   15376          290 :                                                    agginfo->aggfn.argtypes[j],
   15377              :                                                    zeroIsError));
   15378          245 :         appendPQExpBufferChar(&buf, ')');
   15379              :     }
   15380          285 :     return buf.data;
   15381              : }
   15382              : 
   15383              : /*
   15384              :  * dumpAgg
   15385              :  *    write out a single aggregate definition
   15386              :  */
   15387              : static void
   15388          292 : dumpAgg(Archive *fout, const AggInfo *agginfo)
   15389              : {
   15390          292 :     DumpOptions *dopt = fout->dopt;
   15391              :     PQExpBuffer query;
   15392              :     PQExpBuffer q;
   15393              :     PQExpBuffer delq;
   15394              :     PQExpBuffer details;
   15395              :     char       *aggsig;         /* identity signature */
   15396          292 :     char       *aggfullsig = NULL;  /* full signature */
   15397              :     char       *aggsig_tag;
   15398              :     PGresult   *res;
   15399              :     int         i_agginitval;
   15400              :     int         i_aggminitval;
   15401              :     const char *aggtransfn;
   15402              :     const char *aggfinalfn;
   15403              :     const char *aggcombinefn;
   15404              :     const char *aggserialfn;
   15405              :     const char *aggdeserialfn;
   15406              :     const char *aggmtransfn;
   15407              :     const char *aggminvtransfn;
   15408              :     const char *aggmfinalfn;
   15409              :     bool        aggfinalextra;
   15410              :     bool        aggmfinalextra;
   15411              :     char        aggfinalmodify;
   15412              :     char        aggmfinalmodify;
   15413              :     const char *aggsortop;
   15414              :     char       *aggsortconvop;
   15415              :     char        aggkind;
   15416              :     const char *aggtranstype;
   15417              :     const char *aggtransspace;
   15418              :     const char *aggmtranstype;
   15419              :     const char *aggmtransspace;
   15420              :     const char *agginitval;
   15421              :     const char *aggminitval;
   15422              :     const char *proparallel;
   15423              :     char        defaultfinalmodify;
   15424              : 
   15425              :     /* Do nothing if not dumping schema */
   15426          292 :     if (!dopt->dumpSchema)
   15427            7 :         return;
   15428              : 
   15429          285 :     query = createPQExpBuffer();
   15430          285 :     q = createPQExpBuffer();
   15431          285 :     delq = createPQExpBuffer();
   15432          285 :     details = createPQExpBuffer();
   15433              : 
   15434          285 :     if (!fout->is_prepared[PREPQUERY_DUMPAGG])
   15435              :     {
   15436              :         /* Set up query for aggregate-specific details */
   15437           55 :         appendPQExpBufferStr(query,
   15438              :                              "PREPARE dumpAgg(pg_catalog.oid) AS\n");
   15439              : 
   15440           55 :         appendPQExpBufferStr(query,
   15441              :                              "SELECT "
   15442              :                              "aggtransfn,\n"
   15443              :                              "aggfinalfn,\n"
   15444              :                              "aggtranstype::pg_catalog.regtype,\n"
   15445              :                              "agginitval,\n"
   15446              :                              "aggsortop,\n"
   15447              :                              "pg_catalog.pg_get_function_arguments(p.oid) AS funcargs,\n"
   15448              :                              "pg_catalog.pg_get_function_identity_arguments(p.oid) AS funciargs,\n");
   15449              : 
   15450           55 :         if (fout->remoteVersion >= 90400)
   15451           55 :             appendPQExpBufferStr(query,
   15452              :                                  "aggkind,\n"
   15453              :                                  "aggmtransfn,\n"
   15454              :                                  "aggminvtransfn,\n"
   15455              :                                  "aggmfinalfn,\n"
   15456              :                                  "aggmtranstype::pg_catalog.regtype,\n"
   15457              :                                  "aggfinalextra,\n"
   15458              :                                  "aggmfinalextra,\n"
   15459              :                                  "aggtransspace,\n"
   15460              :                                  "aggmtransspace,\n"
   15461              :                                  "aggminitval,\n");
   15462              :         else
   15463            0 :             appendPQExpBufferStr(query,
   15464              :                                  "'n' AS aggkind,\n"
   15465              :                                  "'-' AS aggmtransfn,\n"
   15466              :                                  "'-' AS aggminvtransfn,\n"
   15467              :                                  "'-' AS aggmfinalfn,\n"
   15468              :                                  "0 AS aggmtranstype,\n"
   15469              :                                  "false AS aggfinalextra,\n"
   15470              :                                  "false AS aggmfinalextra,\n"
   15471              :                                  "0 AS aggtransspace,\n"
   15472              :                                  "0 AS aggmtransspace,\n"
   15473              :                                  "NULL AS aggminitval,\n");
   15474              : 
   15475           55 :         if (fout->remoteVersion >= 90600)
   15476           55 :             appendPQExpBufferStr(query,
   15477              :                                  "aggcombinefn,\n"
   15478              :                                  "aggserialfn,\n"
   15479              :                                  "aggdeserialfn,\n"
   15480              :                                  "proparallel,\n");
   15481              :         else
   15482            0 :             appendPQExpBufferStr(query,
   15483              :                                  "'-' AS aggcombinefn,\n"
   15484              :                                  "'-' AS aggserialfn,\n"
   15485              :                                  "'-' AS aggdeserialfn,\n"
   15486              :                                  "'u' AS proparallel,\n");
   15487              : 
   15488           55 :         if (fout->remoteVersion >= 110000)
   15489           55 :             appendPQExpBufferStr(query,
   15490              :                                  "aggfinalmodify,\n"
   15491              :                                  "aggmfinalmodify\n");
   15492              :         else
   15493            0 :             appendPQExpBufferStr(query,
   15494              :                                  "'0' AS aggfinalmodify,\n"
   15495              :                                  "'0' AS aggmfinalmodify\n");
   15496              : 
   15497           55 :         appendPQExpBufferStr(query,
   15498              :                              "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
   15499              :                              "WHERE a.aggfnoid = p.oid "
   15500              :                              "AND p.oid = $1");
   15501              : 
   15502           55 :         ExecuteSqlStatement(fout, query->data);
   15503              : 
   15504           55 :         fout->is_prepared[PREPQUERY_DUMPAGG] = true;
   15505              :     }
   15506              : 
   15507          285 :     printfPQExpBuffer(query,
   15508              :                       "EXECUTE dumpAgg('%u')",
   15509          285 :                       agginfo->aggfn.dobj.catId.oid);
   15510              : 
   15511          285 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   15512              : 
   15513          285 :     i_agginitval = PQfnumber(res, "agginitval");
   15514          285 :     i_aggminitval = PQfnumber(res, "aggminitval");
   15515              : 
   15516          285 :     aggtransfn = PQgetvalue(res, 0, PQfnumber(res, "aggtransfn"));
   15517          285 :     aggfinalfn = PQgetvalue(res, 0, PQfnumber(res, "aggfinalfn"));
   15518          285 :     aggcombinefn = PQgetvalue(res, 0, PQfnumber(res, "aggcombinefn"));
   15519          285 :     aggserialfn = PQgetvalue(res, 0, PQfnumber(res, "aggserialfn"));
   15520          285 :     aggdeserialfn = PQgetvalue(res, 0, PQfnumber(res, "aggdeserialfn"));
   15521          285 :     aggmtransfn = PQgetvalue(res, 0, PQfnumber(res, "aggmtransfn"));
   15522          285 :     aggminvtransfn = PQgetvalue(res, 0, PQfnumber(res, "aggminvtransfn"));
   15523          285 :     aggmfinalfn = PQgetvalue(res, 0, PQfnumber(res, "aggmfinalfn"));
   15524          285 :     aggfinalextra = (PQgetvalue(res, 0, PQfnumber(res, "aggfinalextra"))[0] == 't');
   15525          285 :     aggmfinalextra = (PQgetvalue(res, 0, PQfnumber(res, "aggmfinalextra"))[0] == 't');
   15526          285 :     aggfinalmodify = PQgetvalue(res, 0, PQfnumber(res, "aggfinalmodify"))[0];
   15527          285 :     aggmfinalmodify = PQgetvalue(res, 0, PQfnumber(res, "aggmfinalmodify"))[0];
   15528          285 :     aggsortop = PQgetvalue(res, 0, PQfnumber(res, "aggsortop"));
   15529          285 :     aggkind = PQgetvalue(res, 0, PQfnumber(res, "aggkind"))[0];
   15530          285 :     aggtranstype = PQgetvalue(res, 0, PQfnumber(res, "aggtranstype"));
   15531          285 :     aggtransspace = PQgetvalue(res, 0, PQfnumber(res, "aggtransspace"));
   15532          285 :     aggmtranstype = PQgetvalue(res, 0, PQfnumber(res, "aggmtranstype"));
   15533          285 :     aggmtransspace = PQgetvalue(res, 0, PQfnumber(res, "aggmtransspace"));
   15534          285 :     agginitval = PQgetvalue(res, 0, i_agginitval);
   15535          285 :     aggminitval = PQgetvalue(res, 0, i_aggminitval);
   15536          285 :     proparallel = PQgetvalue(res, 0, PQfnumber(res, "proparallel"));
   15537              : 
   15538              :     {
   15539              :         char       *funcargs;
   15540              :         char       *funciargs;
   15541              : 
   15542          285 :         funcargs = PQgetvalue(res, 0, PQfnumber(res, "funcargs"));
   15543          285 :         funciargs = PQgetvalue(res, 0, PQfnumber(res, "funciargs"));
   15544          285 :         aggfullsig = format_function_arguments(&agginfo->aggfn, funcargs, true);
   15545          285 :         aggsig = format_function_arguments(&agginfo->aggfn, funciargs, true);
   15546              :     }
   15547              : 
   15548          285 :     aggsig_tag = format_aggregate_signature(agginfo, fout, false);
   15549              : 
   15550              :     /* identify default modify flag for aggkind (must match DefineAggregate) */
   15551          285 :     defaultfinalmodify = (aggkind == AGGKIND_NORMAL) ? AGGMODIFY_READ_ONLY : AGGMODIFY_READ_WRITE;
   15552              :     /* replace omitted flags for old versions */
   15553          285 :     if (aggfinalmodify == '0')
   15554            0 :         aggfinalmodify = defaultfinalmodify;
   15555          285 :     if (aggmfinalmodify == '0')
   15556            0 :         aggmfinalmodify = defaultfinalmodify;
   15557              : 
   15558              :     /* regproc and regtype output is already sufficiently quoted */
   15559          285 :     appendPQExpBuffer(details, "    SFUNC = %s,\n    STYPE = %s",
   15560              :                       aggtransfn, aggtranstype);
   15561              : 
   15562          285 :     if (strcmp(aggtransspace, "0") != 0)
   15563              :     {
   15564            5 :         appendPQExpBuffer(details, ",\n    SSPACE = %s",
   15565              :                           aggtransspace);
   15566              :     }
   15567              : 
   15568          285 :     if (!PQgetisnull(res, 0, i_agginitval))
   15569              :     {
   15570          207 :         appendPQExpBufferStr(details, ",\n    INITCOND = ");
   15571          207 :         appendStringLiteralAH(details, agginitval, fout);
   15572              :     }
   15573              : 
   15574          285 :     if (strcmp(aggfinalfn, "-") != 0)
   15575              :     {
   15576          132 :         appendPQExpBuffer(details, ",\n    FINALFUNC = %s",
   15577              :                           aggfinalfn);
   15578          132 :         if (aggfinalextra)
   15579           10 :             appendPQExpBufferStr(details, ",\n    FINALFUNC_EXTRA");
   15580          132 :         if (aggfinalmodify != defaultfinalmodify)
   15581              :         {
   15582           32 :             switch (aggfinalmodify)
   15583              :             {
   15584            0 :                 case AGGMODIFY_READ_ONLY:
   15585            0 :                     appendPQExpBufferStr(details, ",\n    FINALFUNC_MODIFY = READ_ONLY");
   15586            0 :                     break;
   15587           32 :                 case AGGMODIFY_SHAREABLE:
   15588           32 :                     appendPQExpBufferStr(details, ",\n    FINALFUNC_MODIFY = SHAREABLE");
   15589           32 :                     break;
   15590            0 :                 case AGGMODIFY_READ_WRITE:
   15591            0 :                     appendPQExpBufferStr(details, ",\n    FINALFUNC_MODIFY = READ_WRITE");
   15592            0 :                     break;
   15593            0 :                 default:
   15594            0 :                     pg_fatal("unrecognized aggfinalmodify value for aggregate \"%s\"",
   15595              :                              agginfo->aggfn.dobj.name);
   15596              :                     break;
   15597              :             }
   15598              :         }
   15599              :     }
   15600              : 
   15601          285 :     if (strcmp(aggcombinefn, "-") != 0)
   15602            0 :         appendPQExpBuffer(details, ",\n    COMBINEFUNC = %s", aggcombinefn);
   15603              : 
   15604          285 :     if (strcmp(aggserialfn, "-") != 0)
   15605            0 :         appendPQExpBuffer(details, ",\n    SERIALFUNC = %s", aggserialfn);
   15606              : 
   15607          285 :     if (strcmp(aggdeserialfn, "-") != 0)
   15608            0 :         appendPQExpBuffer(details, ",\n    DESERIALFUNC = %s", aggdeserialfn);
   15609              : 
   15610          285 :     if (strcmp(aggmtransfn, "-") != 0)
   15611              :     {
   15612           30 :         appendPQExpBuffer(details, ",\n    MSFUNC = %s,\n    MINVFUNC = %s,\n    MSTYPE = %s",
   15613              :                           aggmtransfn,
   15614              :                           aggminvtransfn,
   15615              :                           aggmtranstype);
   15616              :     }
   15617              : 
   15618          285 :     if (strcmp(aggmtransspace, "0") != 0)
   15619              :     {
   15620            0 :         appendPQExpBuffer(details, ",\n    MSSPACE = %s",
   15621              :                           aggmtransspace);
   15622              :     }
   15623              : 
   15624          285 :     if (!PQgetisnull(res, 0, i_aggminitval))
   15625              :     {
   15626           10 :         appendPQExpBufferStr(details, ",\n    MINITCOND = ");
   15627           10 :         appendStringLiteralAH(details, aggminitval, fout);
   15628              :     }
   15629              : 
   15630          285 :     if (strcmp(aggmfinalfn, "-") != 0)
   15631              :     {
   15632            0 :         appendPQExpBuffer(details, ",\n    MFINALFUNC = %s",
   15633              :                           aggmfinalfn);
   15634            0 :         if (aggmfinalextra)
   15635            0 :             appendPQExpBufferStr(details, ",\n    MFINALFUNC_EXTRA");
   15636            0 :         if (aggmfinalmodify != defaultfinalmodify)
   15637              :         {
   15638            0 :             switch (aggmfinalmodify)
   15639              :             {
   15640            0 :                 case AGGMODIFY_READ_ONLY:
   15641            0 :                     appendPQExpBufferStr(details, ",\n    MFINALFUNC_MODIFY = READ_ONLY");
   15642            0 :                     break;
   15643            0 :                 case AGGMODIFY_SHAREABLE:
   15644            0 :                     appendPQExpBufferStr(details, ",\n    MFINALFUNC_MODIFY = SHAREABLE");
   15645            0 :                     break;
   15646            0 :                 case AGGMODIFY_READ_WRITE:
   15647            0 :                     appendPQExpBufferStr(details, ",\n    MFINALFUNC_MODIFY = READ_WRITE");
   15648            0 :                     break;
   15649            0 :                 default:
   15650            0 :                     pg_fatal("unrecognized aggmfinalmodify value for aggregate \"%s\"",
   15651              :                              agginfo->aggfn.dobj.name);
   15652              :                     break;
   15653              :             }
   15654              :         }
   15655              :     }
   15656              : 
   15657          285 :     aggsortconvop = getFormattedOperatorName(aggsortop);
   15658          285 :     if (aggsortconvop)
   15659              :     {
   15660            0 :         appendPQExpBuffer(details, ",\n    SORTOP = %s",
   15661              :                           aggsortconvop);
   15662            0 :         free(aggsortconvop);
   15663              :     }
   15664              : 
   15665          285 :     if (aggkind == AGGKIND_HYPOTHETICAL)
   15666            5 :         appendPQExpBufferStr(details, ",\n    HYPOTHETICAL");
   15667              : 
   15668          285 :     if (proparallel[0] != PROPARALLEL_UNSAFE)
   15669              :     {
   15670            5 :         if (proparallel[0] == PROPARALLEL_SAFE)
   15671            5 :             appendPQExpBufferStr(details, ",\n    PARALLEL = safe");
   15672            0 :         else if (proparallel[0] == PROPARALLEL_RESTRICTED)
   15673            0 :             appendPQExpBufferStr(details, ",\n    PARALLEL = restricted");
   15674            0 :         else if (proparallel[0] != PROPARALLEL_UNSAFE)
   15675            0 :             pg_fatal("unrecognized proparallel value for function \"%s\"",
   15676              :                      agginfo->aggfn.dobj.name);
   15677              :     }
   15678              : 
   15679          285 :     appendPQExpBuffer(delq, "DROP AGGREGATE %s.%s;\n",
   15680          285 :                       fmtId(agginfo->aggfn.dobj.namespace->dobj.name),
   15681              :                       aggsig);
   15682              : 
   15683          570 :     appendPQExpBuffer(q, "CREATE AGGREGATE %s.%s (\n%s\n);\n",
   15684          285 :                       fmtId(agginfo->aggfn.dobj.namespace->dobj.name),
   15685              :                       aggfullsig ? aggfullsig : aggsig, details->data);
   15686              : 
   15687          285 :     if (dopt->binary_upgrade)
   15688           49 :         binary_upgrade_extension_member(q, &agginfo->aggfn.dobj,
   15689              :                                         "AGGREGATE", aggsig,
   15690           49 :                                         agginfo->aggfn.dobj.namespace->dobj.name);
   15691              : 
   15692          285 :     if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_DEFINITION)
   15693          268 :         ArchiveEntry(fout, agginfo->aggfn.dobj.catId,
   15694          268 :                      agginfo->aggfn.dobj.dumpId,
   15695          268 :                      ARCHIVE_OPTS(.tag = aggsig_tag,
   15696              :                                   .namespace = agginfo->aggfn.dobj.namespace->dobj.name,
   15697              :                                   .owner = agginfo->aggfn.rolname,
   15698              :                                   .description = "AGGREGATE",
   15699              :                                   .section = SECTION_PRE_DATA,
   15700              :                                   .createStmt = q->data,
   15701              :                                   .dropStmt = delq->data));
   15702              : 
   15703              :     /* Dump Aggregate Comments */
   15704          285 :     if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_COMMENT)
   15705           10 :         dumpComment(fout, "AGGREGATE", aggsig,
   15706           10 :                     agginfo->aggfn.dobj.namespace->dobj.name,
   15707           10 :                     agginfo->aggfn.rolname,
   15708           10 :                     agginfo->aggfn.dobj.catId, 0, agginfo->aggfn.dobj.dumpId);
   15709              : 
   15710          285 :     if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_SECLABEL)
   15711            0 :         dumpSecLabel(fout, "AGGREGATE", aggsig,
   15712            0 :                      agginfo->aggfn.dobj.namespace->dobj.name,
   15713            0 :                      agginfo->aggfn.rolname,
   15714            0 :                      agginfo->aggfn.dobj.catId, 0, agginfo->aggfn.dobj.dumpId);
   15715              : 
   15716              :     /*
   15717              :      * Since there is no GRANT ON AGGREGATE syntax, we have to make the ACL
   15718              :      * command look like a function's GRANT; in particular this affects the
   15719              :      * syntax for zero-argument aggregates and ordered-set aggregates.
   15720              :      */
   15721          285 :     free(aggsig);
   15722              : 
   15723          285 :     aggsig = format_function_signature(fout, &agginfo->aggfn, true);
   15724              : 
   15725          285 :     if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_ACL)
   15726           18 :         dumpACL(fout, agginfo->aggfn.dobj.dumpId, InvalidDumpId,
   15727              :                 "FUNCTION", aggsig, NULL,
   15728           18 :                 agginfo->aggfn.dobj.namespace->dobj.name,
   15729           18 :                 NULL, agginfo->aggfn.rolname, &agginfo->aggfn.dacl);
   15730              : 
   15731          285 :     free(aggsig);
   15732          285 :     free(aggfullsig);
   15733          285 :     free(aggsig_tag);
   15734              : 
   15735          285 :     PQclear(res);
   15736              : 
   15737          285 :     destroyPQExpBuffer(query);
   15738          285 :     destroyPQExpBuffer(q);
   15739          285 :     destroyPQExpBuffer(delq);
   15740          285 :     destroyPQExpBuffer(details);
   15741              : }
   15742              : 
   15743              : /*
   15744              :  * dumpTSParser
   15745              :  *    write out a single text search parser
   15746              :  */
   15747              : static void
   15748           41 : dumpTSParser(Archive *fout, const TSParserInfo *prsinfo)
   15749              : {
   15750           41 :     DumpOptions *dopt = fout->dopt;
   15751              :     PQExpBuffer q;
   15752              :     PQExpBuffer delq;
   15753              :     char       *qprsname;
   15754              : 
   15755              :     /* Do nothing if not dumping schema */
   15756           41 :     if (!dopt->dumpSchema)
   15757            6 :         return;
   15758              : 
   15759           35 :     q = createPQExpBuffer();
   15760           35 :     delq = createPQExpBuffer();
   15761              : 
   15762           35 :     qprsname = pg_strdup(fmtId(prsinfo->dobj.name));
   15763              : 
   15764           35 :     appendPQExpBuffer(q, "CREATE TEXT SEARCH PARSER %s (\n",
   15765           35 :                       fmtQualifiedDumpable(prsinfo));
   15766              : 
   15767           35 :     appendPQExpBuffer(q, "    START = %s,\n",
   15768           35 :                       convertTSFunction(fout, prsinfo->prsstart));
   15769           35 :     appendPQExpBuffer(q, "    GETTOKEN = %s,\n",
   15770           35 :                       convertTSFunction(fout, prsinfo->prstoken));
   15771           35 :     appendPQExpBuffer(q, "    END = %s,\n",
   15772           35 :                       convertTSFunction(fout, prsinfo->prsend));
   15773           35 :     if (prsinfo->prsheadline != InvalidOid)
   15774            3 :         appendPQExpBuffer(q, "    HEADLINE = %s,\n",
   15775            3 :                           convertTSFunction(fout, prsinfo->prsheadline));
   15776           35 :     appendPQExpBuffer(q, "    LEXTYPES = %s );\n",
   15777           35 :                       convertTSFunction(fout, prsinfo->prslextype));
   15778              : 
   15779           35 :     appendPQExpBuffer(delq, "DROP TEXT SEARCH PARSER %s;\n",
   15780           35 :                       fmtQualifiedDumpable(prsinfo));
   15781              : 
   15782           35 :     if (dopt->binary_upgrade)
   15783            1 :         binary_upgrade_extension_member(q, &prsinfo->dobj,
   15784              :                                         "TEXT SEARCH PARSER", qprsname,
   15785            1 :                                         prsinfo->dobj.namespace->dobj.name);
   15786              : 
   15787           35 :     if (prsinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   15788           35 :         ArchiveEntry(fout, prsinfo->dobj.catId, prsinfo->dobj.dumpId,
   15789           35 :                      ARCHIVE_OPTS(.tag = prsinfo->dobj.name,
   15790              :                                   .namespace = prsinfo->dobj.namespace->dobj.name,
   15791              :                                   .description = "TEXT SEARCH PARSER",
   15792              :                                   .section = SECTION_PRE_DATA,
   15793              :                                   .createStmt = q->data,
   15794              :                                   .dropStmt = delq->data));
   15795              : 
   15796              :     /* Dump Parser Comments */
   15797           35 :     if (prsinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   15798           35 :         dumpComment(fout, "TEXT SEARCH PARSER", qprsname,
   15799           35 :                     prsinfo->dobj.namespace->dobj.name, "",
   15800           35 :                     prsinfo->dobj.catId, 0, prsinfo->dobj.dumpId);
   15801              : 
   15802           35 :     destroyPQExpBuffer(q);
   15803           35 :     destroyPQExpBuffer(delq);
   15804           35 :     free(qprsname);
   15805              : }
   15806              : 
   15807              : /*
   15808              :  * dumpTSDictionary
   15809              :  *    write out a single text search dictionary
   15810              :  */
   15811              : static void
   15812          179 : dumpTSDictionary(Archive *fout, const TSDictInfo *dictinfo)
   15813              : {
   15814          179 :     DumpOptions *dopt = fout->dopt;
   15815              :     PQExpBuffer q;
   15816              :     PQExpBuffer delq;
   15817              :     PQExpBuffer query;
   15818              :     char       *qdictname;
   15819              :     PGresult   *res;
   15820              :     char       *nspname;
   15821              :     char       *tmplname;
   15822              : 
   15823              :     /* Do nothing if not dumping schema */
   15824          179 :     if (!dopt->dumpSchema)
   15825            6 :         return;
   15826              : 
   15827          173 :     q = createPQExpBuffer();
   15828          173 :     delq = createPQExpBuffer();
   15829          173 :     query = createPQExpBuffer();
   15830              : 
   15831          173 :     qdictname = pg_strdup(fmtId(dictinfo->dobj.name));
   15832              : 
   15833              :     /* Fetch name and namespace of the dictionary's template */
   15834          173 :     appendPQExpBuffer(query, "SELECT nspname, tmplname "
   15835              :                       "FROM pg_ts_template p, pg_namespace n "
   15836              :                       "WHERE p.oid = '%u' AND n.oid = tmplnamespace",
   15837          173 :                       dictinfo->dicttemplate);
   15838          173 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   15839          173 :     nspname = PQgetvalue(res, 0, 0);
   15840          173 :     tmplname = PQgetvalue(res, 0, 1);
   15841              : 
   15842          173 :     appendPQExpBuffer(q, "CREATE TEXT SEARCH DICTIONARY %s (\n",
   15843          173 :                       fmtQualifiedDumpable(dictinfo));
   15844              : 
   15845          173 :     appendPQExpBufferStr(q, "    TEMPLATE = ");
   15846          173 :     appendPQExpBuffer(q, "%s.", fmtId(nspname));
   15847          173 :     appendPQExpBufferStr(q, fmtId(tmplname));
   15848              : 
   15849          173 :     PQclear(res);
   15850              : 
   15851              :     /* the dictinitoption can be dumped straight into the command */
   15852          173 :     if (dictinfo->dictinitoption)
   15853          138 :         appendPQExpBuffer(q, ",\n    %s", dictinfo->dictinitoption);
   15854              : 
   15855          173 :     appendPQExpBufferStr(q, " );\n");
   15856              : 
   15857          173 :     appendPQExpBuffer(delq, "DROP TEXT SEARCH DICTIONARY %s;\n",
   15858          173 :                       fmtQualifiedDumpable(dictinfo));
   15859              : 
   15860          173 :     if (dopt->binary_upgrade)
   15861           10 :         binary_upgrade_extension_member(q, &dictinfo->dobj,
   15862              :                                         "TEXT SEARCH DICTIONARY", qdictname,
   15863           10 :                                         dictinfo->dobj.namespace->dobj.name);
   15864              : 
   15865          173 :     if (dictinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   15866          173 :         ArchiveEntry(fout, dictinfo->dobj.catId, dictinfo->dobj.dumpId,
   15867          173 :                      ARCHIVE_OPTS(.tag = dictinfo->dobj.name,
   15868              :                                   .namespace = dictinfo->dobj.namespace->dobj.name,
   15869              :                                   .owner = dictinfo->rolname,
   15870              :                                   .description = "TEXT SEARCH DICTIONARY",
   15871              :                                   .section = SECTION_PRE_DATA,
   15872              :                                   .createStmt = q->data,
   15873              :                                   .dropStmt = delq->data));
   15874              : 
   15875              :     /* Dump Dictionary Comments */
   15876          173 :     if (dictinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   15877          128 :         dumpComment(fout, "TEXT SEARCH DICTIONARY", qdictname,
   15878          128 :                     dictinfo->dobj.namespace->dobj.name, dictinfo->rolname,
   15879          128 :                     dictinfo->dobj.catId, 0, dictinfo->dobj.dumpId);
   15880              : 
   15881          173 :     destroyPQExpBuffer(q);
   15882          173 :     destroyPQExpBuffer(delq);
   15883          173 :     destroyPQExpBuffer(query);
   15884          173 :     free(qdictname);
   15885              : }
   15886              : 
   15887              : /*
   15888              :  * dumpTSTemplate
   15889              :  *    write out a single text search template
   15890              :  */
   15891              : static void
   15892           53 : dumpTSTemplate(Archive *fout, const TSTemplateInfo *tmplinfo)
   15893              : {
   15894           53 :     DumpOptions *dopt = fout->dopt;
   15895              :     PQExpBuffer q;
   15896              :     PQExpBuffer delq;
   15897              :     char       *qtmplname;
   15898              : 
   15899              :     /* Do nothing if not dumping schema */
   15900           53 :     if (!dopt->dumpSchema)
   15901            6 :         return;
   15902              : 
   15903           47 :     q = createPQExpBuffer();
   15904           47 :     delq = createPQExpBuffer();
   15905              : 
   15906           47 :     qtmplname = pg_strdup(fmtId(tmplinfo->dobj.name));
   15907              : 
   15908           47 :     appendPQExpBuffer(q, "CREATE TEXT SEARCH TEMPLATE %s (\n",
   15909           47 :                       fmtQualifiedDumpable(tmplinfo));
   15910              : 
   15911           47 :     if (tmplinfo->tmplinit != InvalidOid)
   15912           15 :         appendPQExpBuffer(q, "    INIT = %s,\n",
   15913           15 :                           convertTSFunction(fout, tmplinfo->tmplinit));
   15914           47 :     appendPQExpBuffer(q, "    LEXIZE = %s );\n",
   15915           47 :                       convertTSFunction(fout, tmplinfo->tmpllexize));
   15916              : 
   15917           47 :     appendPQExpBuffer(delq, "DROP TEXT SEARCH TEMPLATE %s;\n",
   15918           47 :                       fmtQualifiedDumpable(tmplinfo));
   15919              : 
   15920           47 :     if (dopt->binary_upgrade)
   15921            1 :         binary_upgrade_extension_member(q, &tmplinfo->dobj,
   15922              :                                         "TEXT SEARCH TEMPLATE", qtmplname,
   15923            1 :                                         tmplinfo->dobj.namespace->dobj.name);
   15924              : 
   15925           47 :     if (tmplinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   15926           47 :         ArchiveEntry(fout, tmplinfo->dobj.catId, tmplinfo->dobj.dumpId,
   15927           47 :                      ARCHIVE_OPTS(.tag = tmplinfo->dobj.name,
   15928              :                                   .namespace = tmplinfo->dobj.namespace->dobj.name,
   15929              :                                   .description = "TEXT SEARCH TEMPLATE",
   15930              :                                   .section = SECTION_PRE_DATA,
   15931              :                                   .createStmt = q->data,
   15932              :                                   .dropStmt = delq->data));
   15933              : 
   15934              :     /* Dump Template Comments */
   15935           47 :     if (tmplinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   15936           47 :         dumpComment(fout, "TEXT SEARCH TEMPLATE", qtmplname,
   15937           47 :                     tmplinfo->dobj.namespace->dobj.name, "",
   15938           47 :                     tmplinfo->dobj.catId, 0, tmplinfo->dobj.dumpId);
   15939              : 
   15940           47 :     destroyPQExpBuffer(q);
   15941           47 :     destroyPQExpBuffer(delq);
   15942           47 :     free(qtmplname);
   15943              : }
   15944              : 
   15945              : /*
   15946              :  * dumpTSConfig
   15947              :  *    write out a single text search configuration
   15948              :  */
   15949              : static void
   15950          154 : dumpTSConfig(Archive *fout, const TSConfigInfo *cfginfo)
   15951              : {
   15952          154 :     DumpOptions *dopt = fout->dopt;
   15953              :     PQExpBuffer q;
   15954              :     PQExpBuffer delq;
   15955              :     PQExpBuffer query;
   15956              :     char       *qcfgname;
   15957              :     PGresult   *res;
   15958              :     char       *nspname;
   15959              :     char       *prsname;
   15960              :     int         ntups,
   15961              :                 i;
   15962              :     int         i_tokenname;
   15963              :     int         i_dictname;
   15964              : 
   15965              :     /* Do nothing if not dumping schema */
   15966          154 :     if (!dopt->dumpSchema)
   15967            6 :         return;
   15968              : 
   15969          148 :     q = createPQExpBuffer();
   15970          148 :     delq = createPQExpBuffer();
   15971          148 :     query = createPQExpBuffer();
   15972              : 
   15973          148 :     qcfgname = pg_strdup(fmtId(cfginfo->dobj.name));
   15974              : 
   15975              :     /* Fetch name and namespace of the config's parser */
   15976          148 :     appendPQExpBuffer(query, "SELECT nspname, prsname "
   15977              :                       "FROM pg_ts_parser p, pg_namespace n "
   15978              :                       "WHERE p.oid = '%u' AND n.oid = prsnamespace",
   15979          148 :                       cfginfo->cfgparser);
   15980          148 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   15981          148 :     nspname = PQgetvalue(res, 0, 0);
   15982          148 :     prsname = PQgetvalue(res, 0, 1);
   15983              : 
   15984          148 :     appendPQExpBuffer(q, "CREATE TEXT SEARCH CONFIGURATION %s (\n",
   15985          148 :                       fmtQualifiedDumpable(cfginfo));
   15986              : 
   15987          148 :     appendPQExpBuffer(q, "    PARSER = %s.", fmtId(nspname));
   15988          148 :     appendPQExpBuffer(q, "%s );\n", fmtId(prsname));
   15989              : 
   15990          148 :     PQclear(res);
   15991              : 
   15992          148 :     resetPQExpBuffer(query);
   15993          148 :     appendPQExpBuffer(query,
   15994              :                       "SELECT\n"
   15995              :                       "  ( SELECT alias FROM pg_catalog.ts_token_type('%u'::pg_catalog.oid) AS t\n"
   15996              :                       "    WHERE t.tokid = m.maptokentype ) AS tokenname,\n"
   15997              :                       "  m.mapdict::pg_catalog.regdictionary AS dictname\n"
   15998              :                       "FROM pg_catalog.pg_ts_config_map AS m\n"
   15999              :                       "WHERE m.mapcfg = '%u'\n"
   16000              :                       "ORDER BY m.mapcfg, m.maptokentype, m.mapseqno",
   16001          148 :                       cfginfo->cfgparser, cfginfo->dobj.catId.oid);
   16002              : 
   16003          148 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   16004          148 :     ntups = PQntuples(res);
   16005              : 
   16006          148 :     i_tokenname = PQfnumber(res, "tokenname");
   16007          148 :     i_dictname = PQfnumber(res, "dictname");
   16008              : 
   16009         3095 :     for (i = 0; i < ntups; i++)
   16010              :     {
   16011         2947 :         char       *tokenname = PQgetvalue(res, i, i_tokenname);
   16012         2947 :         char       *dictname = PQgetvalue(res, i, i_dictname);
   16013              : 
   16014         2947 :         if (i == 0 ||
   16015         2799 :             strcmp(tokenname, PQgetvalue(res, i - 1, i_tokenname)) != 0)
   16016              :         {
   16017              :             /* starting a new token type, so start a new command */
   16018         2812 :             if (i > 0)
   16019         2664 :                 appendPQExpBufferStr(q, ";\n");
   16020         2812 :             appendPQExpBuffer(q, "\nALTER TEXT SEARCH CONFIGURATION %s\n",
   16021         2812 :                               fmtQualifiedDumpable(cfginfo));
   16022              :             /* tokenname needs quoting, dictname does NOT */
   16023         2812 :             appendPQExpBuffer(q, "    ADD MAPPING FOR %s WITH %s",
   16024              :                               fmtId(tokenname), dictname);
   16025              :         }
   16026              :         else
   16027          135 :             appendPQExpBuffer(q, ", %s", dictname);
   16028              :     }
   16029              : 
   16030          148 :     if (ntups > 0)
   16031          148 :         appendPQExpBufferStr(q, ";\n");
   16032              : 
   16033          148 :     PQclear(res);
   16034              : 
   16035          148 :     appendPQExpBuffer(delq, "DROP TEXT SEARCH CONFIGURATION %s;\n",
   16036          148 :                       fmtQualifiedDumpable(cfginfo));
   16037              : 
   16038          148 :     if (dopt->binary_upgrade)
   16039            5 :         binary_upgrade_extension_member(q, &cfginfo->dobj,
   16040              :                                         "TEXT SEARCH CONFIGURATION", qcfgname,
   16041            5 :                                         cfginfo->dobj.namespace->dobj.name);
   16042              : 
   16043          148 :     if (cfginfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   16044          148 :         ArchiveEntry(fout, cfginfo->dobj.catId, cfginfo->dobj.dumpId,
   16045          148 :                      ARCHIVE_OPTS(.tag = cfginfo->dobj.name,
   16046              :                                   .namespace = cfginfo->dobj.namespace->dobj.name,
   16047              :                                   .owner = cfginfo->rolname,
   16048              :                                   .description = "TEXT SEARCH CONFIGURATION",
   16049              :                                   .section = SECTION_PRE_DATA,
   16050              :                                   .createStmt = q->data,
   16051              :                                   .dropStmt = delq->data));
   16052              : 
   16053              :     /* Dump Configuration Comments */
   16054          148 :     if (cfginfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   16055          128 :         dumpComment(fout, "TEXT SEARCH CONFIGURATION", qcfgname,
   16056          128 :                     cfginfo->dobj.namespace->dobj.name, cfginfo->rolname,
   16057          128 :                     cfginfo->dobj.catId, 0, cfginfo->dobj.dumpId);
   16058              : 
   16059          148 :     destroyPQExpBuffer(q);
   16060          148 :     destroyPQExpBuffer(delq);
   16061          148 :     destroyPQExpBuffer(query);
   16062          148 :     free(qcfgname);
   16063              : }
   16064              : 
   16065              : /*
   16066              :  * dumpForeignDataWrapper
   16067              :  *    write out a single foreign-data wrapper definition
   16068              :  */
   16069              : static void
   16070           52 : dumpForeignDataWrapper(Archive *fout, const FdwInfo *fdwinfo)
   16071              : {
   16072           52 :     DumpOptions *dopt = fout->dopt;
   16073              :     PQExpBuffer q;
   16074              :     PQExpBuffer delq;
   16075              :     char       *qfdwname;
   16076              : 
   16077              :     /* Do nothing if not dumping schema */
   16078           52 :     if (!dopt->dumpSchema)
   16079            7 :         return;
   16080              : 
   16081           45 :     q = createPQExpBuffer();
   16082           45 :     delq = createPQExpBuffer();
   16083              : 
   16084           45 :     qfdwname = pg_strdup(fmtId(fdwinfo->dobj.name));
   16085              : 
   16086           45 :     appendPQExpBuffer(q, "CREATE FOREIGN DATA WRAPPER %s",
   16087              :                       qfdwname);
   16088              : 
   16089           45 :     if (strcmp(fdwinfo->fdwhandler, "-") != 0)
   16090            0 :         appendPQExpBuffer(q, " HANDLER %s", fdwinfo->fdwhandler);
   16091              : 
   16092           45 :     if (strcmp(fdwinfo->fdwvalidator, "-") != 0)
   16093            0 :         appendPQExpBuffer(q, " VALIDATOR %s", fdwinfo->fdwvalidator);
   16094              : 
   16095           45 :     if (strlen(fdwinfo->fdwoptions) > 0)
   16096            0 :         appendPQExpBuffer(q, " OPTIONS (\n    %s\n)", fdwinfo->fdwoptions);
   16097              : 
   16098           45 :     appendPQExpBufferStr(q, ";\n");
   16099              : 
   16100           45 :     appendPQExpBuffer(delq, "DROP FOREIGN DATA WRAPPER %s;\n",
   16101              :                       qfdwname);
   16102              : 
   16103           45 :     if (dopt->binary_upgrade)
   16104            2 :         binary_upgrade_extension_member(q, &fdwinfo->dobj,
   16105              :                                         "FOREIGN DATA WRAPPER", qfdwname,
   16106              :                                         NULL);
   16107              : 
   16108           45 :     if (fdwinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   16109           45 :         ArchiveEntry(fout, fdwinfo->dobj.catId, fdwinfo->dobj.dumpId,
   16110           45 :                      ARCHIVE_OPTS(.tag = fdwinfo->dobj.name,
   16111              :                                   .owner = fdwinfo->rolname,
   16112              :                                   .description = "FOREIGN DATA WRAPPER",
   16113              :                                   .section = SECTION_PRE_DATA,
   16114              :                                   .createStmt = q->data,
   16115              :                                   .dropStmt = delq->data));
   16116              : 
   16117              :     /* Dump Foreign Data Wrapper Comments */
   16118           45 :     if (fdwinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   16119            0 :         dumpComment(fout, "FOREIGN DATA WRAPPER", qfdwname,
   16120            0 :                     NULL, fdwinfo->rolname,
   16121            0 :                     fdwinfo->dobj.catId, 0, fdwinfo->dobj.dumpId);
   16122              : 
   16123              :     /* Handle the ACL */
   16124           45 :     if (fdwinfo->dobj.dump & DUMP_COMPONENT_ACL)
   16125           31 :         dumpACL(fout, fdwinfo->dobj.dumpId, InvalidDumpId,
   16126              :                 "FOREIGN DATA WRAPPER", qfdwname, NULL, NULL,
   16127           31 :                 NULL, fdwinfo->rolname, &fdwinfo->dacl);
   16128              : 
   16129           45 :     free(qfdwname);
   16130              : 
   16131           45 :     destroyPQExpBuffer(q);
   16132           45 :     destroyPQExpBuffer(delq);
   16133              : }
   16134              : 
   16135              : /*
   16136              :  * dumpForeignServer
   16137              :  *    write out a foreign server definition
   16138              :  */
   16139              : static void
   16140           56 : dumpForeignServer(Archive *fout, const ForeignServerInfo *srvinfo)
   16141              : {
   16142           56 :     DumpOptions *dopt = fout->dopt;
   16143              :     PQExpBuffer q;
   16144              :     PQExpBuffer delq;
   16145              :     PQExpBuffer query;
   16146              :     PGresult   *res;
   16147              :     char       *qsrvname;
   16148              :     char       *fdwname;
   16149              : 
   16150              :     /* Do nothing if not dumping schema */
   16151           56 :     if (!dopt->dumpSchema)
   16152            9 :         return;
   16153              : 
   16154           47 :     q = createPQExpBuffer();
   16155           47 :     delq = createPQExpBuffer();
   16156           47 :     query = createPQExpBuffer();
   16157              : 
   16158           47 :     qsrvname = pg_strdup(fmtId(srvinfo->dobj.name));
   16159              : 
   16160              :     /* look up the foreign-data wrapper */
   16161           47 :     appendPQExpBuffer(query, "SELECT fdwname "
   16162              :                       "FROM pg_foreign_data_wrapper w "
   16163              :                       "WHERE w.oid = '%u'",
   16164           47 :                       srvinfo->srvfdw);
   16165           47 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   16166           47 :     fdwname = PQgetvalue(res, 0, 0);
   16167              : 
   16168           47 :     appendPQExpBuffer(q, "CREATE SERVER %s", qsrvname);
   16169           47 :     if (srvinfo->srvtype && strlen(srvinfo->srvtype) > 0)
   16170              :     {
   16171            0 :         appendPQExpBufferStr(q, " TYPE ");
   16172            0 :         appendStringLiteralAH(q, srvinfo->srvtype, fout);
   16173              :     }
   16174           47 :     if (srvinfo->srvversion && strlen(srvinfo->srvversion) > 0)
   16175              :     {
   16176            0 :         appendPQExpBufferStr(q, " VERSION ");
   16177            0 :         appendStringLiteralAH(q, srvinfo->srvversion, fout);
   16178              :     }
   16179              : 
   16180           47 :     appendPQExpBufferStr(q, " FOREIGN DATA WRAPPER ");
   16181           47 :     appendPQExpBufferStr(q, fmtId(fdwname));
   16182              : 
   16183           47 :     if (srvinfo->srvoptions && strlen(srvinfo->srvoptions) > 0)
   16184            0 :         appendPQExpBuffer(q, " OPTIONS (\n    %s\n)", srvinfo->srvoptions);
   16185              : 
   16186           47 :     appendPQExpBufferStr(q, ";\n");
   16187              : 
   16188           47 :     appendPQExpBuffer(delq, "DROP SERVER %s;\n",
   16189              :                       qsrvname);
   16190              : 
   16191           47 :     if (dopt->binary_upgrade)
   16192            2 :         binary_upgrade_extension_member(q, &srvinfo->dobj,
   16193              :                                         "SERVER", qsrvname, NULL);
   16194              : 
   16195           47 :     if (srvinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   16196           47 :         ArchiveEntry(fout, srvinfo->dobj.catId, srvinfo->dobj.dumpId,
   16197           47 :                      ARCHIVE_OPTS(.tag = srvinfo->dobj.name,
   16198              :                                   .owner = srvinfo->rolname,
   16199              :                                   .description = "SERVER",
   16200              :                                   .section = SECTION_PRE_DATA,
   16201              :                                   .createStmt = q->data,
   16202              :                                   .dropStmt = delq->data));
   16203              : 
   16204              :     /* Dump Foreign Server Comments */
   16205           47 :     if (srvinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   16206            0 :         dumpComment(fout, "SERVER", qsrvname,
   16207            0 :                     NULL, srvinfo->rolname,
   16208            0 :                     srvinfo->dobj.catId, 0, srvinfo->dobj.dumpId);
   16209              : 
   16210              :     /* Handle the ACL */
   16211           47 :     if (srvinfo->dobj.dump & DUMP_COMPONENT_ACL)
   16212           31 :         dumpACL(fout, srvinfo->dobj.dumpId, InvalidDumpId,
   16213              :                 "FOREIGN SERVER", qsrvname, NULL, NULL,
   16214           31 :                 NULL, srvinfo->rolname, &srvinfo->dacl);
   16215              : 
   16216              :     /* Dump user mappings */
   16217           47 :     if (srvinfo->dobj.dump & DUMP_COMPONENT_USERMAP)
   16218           47 :         dumpUserMappings(fout,
   16219           47 :                          srvinfo->dobj.name, NULL,
   16220           47 :                          srvinfo->rolname,
   16221           47 :                          srvinfo->dobj.catId, srvinfo->dobj.dumpId);
   16222              : 
   16223           47 :     PQclear(res);
   16224              : 
   16225           47 :     free(qsrvname);
   16226              : 
   16227           47 :     destroyPQExpBuffer(q);
   16228           47 :     destroyPQExpBuffer(delq);
   16229           47 :     destroyPQExpBuffer(query);
   16230              : }
   16231              : 
   16232              : /*
   16233              :  * dumpUserMappings
   16234              :  *
   16235              :  * This routine is used to dump any user mappings associated with the
   16236              :  * server handed to this routine. Should be called after ArchiveEntry()
   16237              :  * for the server.
   16238              :  */
   16239              : static void
   16240           47 : dumpUserMappings(Archive *fout,
   16241              :                  const char *servername, const char *namespace,
   16242              :                  const char *owner,
   16243              :                  CatalogId catalogId, DumpId dumpId)
   16244              : {
   16245              :     PQExpBuffer q;
   16246              :     PQExpBuffer delq;
   16247              :     PQExpBuffer query;
   16248              :     PQExpBuffer tag;
   16249              :     PGresult   *res;
   16250              :     int         ntups;
   16251              :     int         i_usename;
   16252              :     int         i_umoptions;
   16253              :     int         i;
   16254              : 
   16255           47 :     q = createPQExpBuffer();
   16256           47 :     tag = createPQExpBuffer();
   16257           47 :     delq = createPQExpBuffer();
   16258           47 :     query = createPQExpBuffer();
   16259              : 
   16260              :     /*
   16261              :      * We read from the publicly accessible view pg_user_mappings, so as not
   16262              :      * to fail if run by a non-superuser.  Note that the view will show
   16263              :      * umoptions as null if the user hasn't got privileges for the associated
   16264              :      * server; this means that pg_dump will dump such a mapping, but with no
   16265              :      * OPTIONS clause.  A possible alternative is to skip such mappings
   16266              :      * altogether, but it's not clear that that's an improvement.
   16267              :      */
   16268           47 :     appendPQExpBuffer(query,
   16269              :                       "SELECT usename, "
   16270              :                       "array_to_string(ARRAY("
   16271              :                       "SELECT quote_ident(option_name) || ' ' || "
   16272              :                       "quote_literal(option_value) "
   16273              :                       "FROM pg_options_to_table(umoptions) "
   16274              :                       "ORDER BY option_name"
   16275              :                       "), E',\n    ') AS umoptions "
   16276              :                       "FROM pg_user_mappings "
   16277              :                       "WHERE srvid = '%u' "
   16278              :                       "ORDER BY usename",
   16279              :                       catalogId.oid);
   16280              : 
   16281           47 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   16282              : 
   16283           47 :     ntups = PQntuples(res);
   16284           47 :     i_usename = PQfnumber(res, "usename");
   16285           47 :     i_umoptions = PQfnumber(res, "umoptions");
   16286              : 
   16287           78 :     for (i = 0; i < ntups; i++)
   16288              :     {
   16289              :         char       *usename;
   16290              :         char       *umoptions;
   16291              : 
   16292           31 :         usename = PQgetvalue(res, i, i_usename);
   16293           31 :         umoptions = PQgetvalue(res, i, i_umoptions);
   16294              : 
   16295           31 :         resetPQExpBuffer(q);
   16296           31 :         appendPQExpBuffer(q, "CREATE USER MAPPING FOR %s", fmtId(usename));
   16297           31 :         appendPQExpBuffer(q, " SERVER %s", fmtId(servername));
   16298              : 
   16299           31 :         if (umoptions && strlen(umoptions) > 0)
   16300            0 :             appendPQExpBuffer(q, " OPTIONS (\n    %s\n)", umoptions);
   16301              : 
   16302           31 :         appendPQExpBufferStr(q, ";\n");
   16303              : 
   16304           31 :         resetPQExpBuffer(delq);
   16305           31 :         appendPQExpBuffer(delq, "DROP USER MAPPING FOR %s", fmtId(usename));
   16306           31 :         appendPQExpBuffer(delq, " SERVER %s;\n", fmtId(servername));
   16307              : 
   16308           31 :         resetPQExpBuffer(tag);
   16309           31 :         appendPQExpBuffer(tag, "USER MAPPING %s SERVER %s",
   16310              :                           usename, servername);
   16311              : 
   16312           31 :         ArchiveEntry(fout, nilCatalogId, createDumpId(),
   16313           31 :                      ARCHIVE_OPTS(.tag = tag->data,
   16314              :                                   .namespace = namespace,
   16315              :                                   .owner = owner,
   16316              :                                   .description = "USER MAPPING",
   16317              :                                   .section = SECTION_PRE_DATA,
   16318              :                                   .createStmt = q->data,
   16319              :                                   .dropStmt = delq->data));
   16320              :     }
   16321              : 
   16322           47 :     PQclear(res);
   16323              : 
   16324           47 :     destroyPQExpBuffer(query);
   16325           47 :     destroyPQExpBuffer(delq);
   16326           47 :     destroyPQExpBuffer(tag);
   16327           47 :     destroyPQExpBuffer(q);
   16328           47 : }
   16329              : 
   16330              : /*
   16331              :  * Write out default privileges information
   16332              :  */
   16333              : static void
   16334          160 : dumpDefaultACL(Archive *fout, const DefaultACLInfo *daclinfo)
   16335              : {
   16336          160 :     DumpOptions *dopt = fout->dopt;
   16337              :     PQExpBuffer q;
   16338              :     PQExpBuffer tag;
   16339              :     const char *type;
   16340              : 
   16341              :     /* Do nothing if not dumping schema, or if we're skipping ACLs */
   16342          160 :     if (!dopt->dumpSchema || dopt->aclsSkip)
   16343           28 :         return;
   16344              : 
   16345          132 :     q = createPQExpBuffer();
   16346          132 :     tag = createPQExpBuffer();
   16347              : 
   16348          132 :     switch (daclinfo->defaclobjtype)
   16349              :     {
   16350           61 :         case DEFACLOBJ_RELATION:
   16351           61 :             type = "TABLES";
   16352           61 :             break;
   16353            0 :         case DEFACLOBJ_SEQUENCE:
   16354            0 :             type = "SEQUENCES";
   16355            0 :             break;
   16356           61 :         case DEFACLOBJ_FUNCTION:
   16357           61 :             type = "FUNCTIONS";
   16358           61 :             break;
   16359           10 :         case DEFACLOBJ_TYPE:
   16360           10 :             type = "TYPES";
   16361           10 :             break;
   16362            0 :         case DEFACLOBJ_NAMESPACE:
   16363            0 :             type = "SCHEMAS";
   16364            0 :             break;
   16365            0 :         case DEFACLOBJ_LARGEOBJECT:
   16366            0 :             type = "LARGE OBJECTS";
   16367            0 :             break;
   16368            0 :         default:
   16369              :             /* shouldn't get here */
   16370            0 :             pg_fatal("unrecognized object type in default privileges: %d",
   16371              :                      (int) daclinfo->defaclobjtype);
   16372              :             type = "";            /* keep compiler quiet */
   16373              :     }
   16374              : 
   16375          132 :     appendPQExpBuffer(tag, "DEFAULT PRIVILEGES FOR %s", type);
   16376              : 
   16377              :     /* build the actual command(s) for this tuple */
   16378          132 :     if (!buildDefaultACLCommands(type,
   16379          132 :                                  daclinfo->dobj.namespace != NULL ?
   16380           62 :                                  daclinfo->dobj.namespace->dobj.name : NULL,
   16381          132 :                                  daclinfo->dacl.acl,
   16382          132 :                                  daclinfo->dacl.acldefault,
   16383          132 :                                  daclinfo->defaclrole,
   16384              :                                  fout->remoteVersion,
   16385              :                                  q))
   16386            0 :         pg_fatal("could not parse default ACL list (%s)",
   16387              :                  daclinfo->dacl.acl);
   16388              : 
   16389          132 :     if (daclinfo->dobj.dump & DUMP_COMPONENT_ACL)
   16390          132 :         ArchiveEntry(fout, daclinfo->dobj.catId, daclinfo->dobj.dumpId,
   16391          132 :                      ARCHIVE_OPTS(.tag = tag->data,
   16392              :                                   .namespace = daclinfo->dobj.namespace ?
   16393              :                                   daclinfo->dobj.namespace->dobj.name : NULL,
   16394              :                                   .owner = daclinfo->defaclrole,
   16395              :                                   .description = "DEFAULT ACL",
   16396              :                                   .section = SECTION_POST_DATA,
   16397              :                                   .createStmt = q->data));
   16398              : 
   16399          132 :     destroyPQExpBuffer(tag);
   16400          132 :     destroyPQExpBuffer(q);
   16401              : }
   16402              : 
   16403              : /*----------
   16404              :  * Write out grant/revoke information
   16405              :  *
   16406              :  * 'objDumpId' is the dump ID of the underlying object.
   16407              :  * 'altDumpId' can be a second dumpId that the ACL entry must also depend on,
   16408              :  *      or InvalidDumpId if there is no need for a second dependency.
   16409              :  * 'type' must be one of
   16410              :  *      TABLE, SEQUENCE, FUNCTION, LANGUAGE, SCHEMA, DATABASE, TABLESPACE,
   16411              :  *      FOREIGN DATA WRAPPER, SERVER, or LARGE OBJECT.
   16412              :  * 'name' is the formatted name of the object.  Must be quoted etc. already.
   16413              :  * 'subname' is the formatted name of the sub-object, if any.  Must be quoted.
   16414              :  *      (Currently we assume that subname is only provided for table columns.)
   16415              :  * 'nspname' is the namespace the object is in (NULL if none).
   16416              :  * 'tag' is the tag to use for the ACL TOC entry; typically, this is NULL
   16417              :  *      to use the default for the object type.
   16418              :  * 'owner' is the owner, NULL if there is no owner (for languages).
   16419              :  * 'dacl' is the DumpableAcl struct for the object.
   16420              :  *
   16421              :  * Returns the dump ID assigned to the ACL TocEntry, or InvalidDumpId if
   16422              :  * no ACL entry was created.
   16423              :  *----------
   16424              :  */
   16425              : static DumpId
   16426        39355 : dumpACL(Archive *fout, DumpId objDumpId, DumpId altDumpId,
   16427              :         const char *type, const char *name, const char *subname,
   16428              :         const char *nspname, const char *tag, const char *owner,
   16429              :         const DumpableAcl *dacl)
   16430              : {
   16431        39355 :     DumpId      aclDumpId = InvalidDumpId;
   16432        39355 :     DumpOptions *dopt = fout->dopt;
   16433        39355 :     const char *acls = dacl->acl;
   16434        39355 :     const char *acldefault = dacl->acldefault;
   16435        39355 :     char        privtype = dacl->privtype;
   16436        39355 :     const char *initprivs = dacl->initprivs;
   16437              :     const char *baseacls;
   16438              :     PQExpBuffer sql;
   16439              : 
   16440              :     /* Do nothing if ACL dump is not enabled */
   16441        39355 :     if (dopt->aclsSkip)
   16442          326 :         return InvalidDumpId;
   16443              : 
   16444              :     /* --data-only skips ACLs *except* large object ACLs */
   16445        39029 :     if (!dopt->dumpSchema && strcmp(type, "LARGE OBJECT") != 0)
   16446            0 :         return InvalidDumpId;
   16447              : 
   16448        39029 :     sql = createPQExpBuffer();
   16449              : 
   16450              :     /*
   16451              :      * In binary upgrade mode, we don't run an extension's script but instead
   16452              :      * dump out the objects independently and then recreate them.  To preserve
   16453              :      * any initial privileges which were set on extension objects, we need to
   16454              :      * compute the set of GRANT and REVOKE commands necessary to get from the
   16455              :      * default privileges of an object to its initial privileges as recorded
   16456              :      * in pg_init_privs.
   16457              :      *
   16458              :      * At restore time, we apply these commands after having called
   16459              :      * binary_upgrade_set_record_init_privs(true).  That tells the backend to
   16460              :      * copy the results into pg_init_privs.  This is how we preserve the
   16461              :      * contents of that catalog across binary upgrades.
   16462              :      */
   16463        39029 :     if (dopt->binary_upgrade && privtype == 'e' &&
   16464           13 :         initprivs && *initprivs != '\0')
   16465              :     {
   16466           13 :         appendPQExpBufferStr(sql, "SELECT pg_catalog.binary_upgrade_set_record_init_privs(true);\n");
   16467           13 :         if (!buildACLCommands(name, subname, nspname, type,
   16468              :                               initprivs, acldefault, owner,
   16469              :                               "", fout->remoteVersion, sql))
   16470            0 :             pg_fatal("could not parse initial ACL list (%s) or default (%s) for object \"%s\" (%s)",
   16471              :                      initprivs, acldefault, name, type);
   16472           13 :         appendPQExpBufferStr(sql, "SELECT pg_catalog.binary_upgrade_set_record_init_privs(false);\n");
   16473              :     }
   16474              : 
   16475              :     /*
   16476              :      * Now figure the GRANT and REVOKE commands needed to get to the object's
   16477              :      * actual current ACL, starting from the initprivs if given, else from the
   16478              :      * object-type-specific default.  Also, while buildACLCommands will assume
   16479              :      * that a NULL/empty acls string means it needn't do anything, what that
   16480              :      * actually represents is the object-type-specific default; so we need to
   16481              :      * substitute the acldefault string to get the right results in that case.
   16482              :      */
   16483        39029 :     if (initprivs && *initprivs != '\0')
   16484              :     {
   16485        37206 :         baseacls = initprivs;
   16486        37206 :         if (acls == NULL || *acls == '\0')
   16487           17 :             acls = acldefault;
   16488              :     }
   16489              :     else
   16490         1823 :         baseacls = acldefault;
   16491              : 
   16492        39029 :     if (!buildACLCommands(name, subname, nspname, type,
   16493              :                           acls, baseacls, owner,
   16494              :                           "", fout->remoteVersion, sql))
   16495            0 :         pg_fatal("could not parse ACL list (%s) or default (%s) for object \"%s\" (%s)",
   16496              :                  acls, baseacls, name, type);
   16497              : 
   16498        39029 :     if (sql->len > 0)
   16499              :     {
   16500         1833 :         PQExpBuffer tagbuf = createPQExpBuffer();
   16501              :         DumpId      aclDeps[2];
   16502         1833 :         int         nDeps = 0;
   16503              : 
   16504         1833 :         if (tag)
   16505            0 :             appendPQExpBufferStr(tagbuf, tag);
   16506         1833 :         else if (subname)
   16507         1047 :             appendPQExpBuffer(tagbuf, "COLUMN %s.%s", name, subname);
   16508              :         else
   16509          786 :             appendPQExpBuffer(tagbuf, "%s %s", type, name);
   16510              : 
   16511         1833 :         aclDeps[nDeps++] = objDumpId;
   16512         1833 :         if (altDumpId != InvalidDumpId)
   16513          963 :             aclDeps[nDeps++] = altDumpId;
   16514              : 
   16515         1833 :         aclDumpId = createDumpId();
   16516              : 
   16517         1833 :         ArchiveEntry(fout, nilCatalogId, aclDumpId,
   16518         1833 :                      ARCHIVE_OPTS(.tag = tagbuf->data,
   16519              :                                   .namespace = nspname,
   16520              :                                   .owner = owner,
   16521              :                                   .description = "ACL",
   16522              :                                   .section = SECTION_NONE,
   16523              :                                   .createStmt = sql->data,
   16524              :                                   .deps = aclDeps,
   16525              :                                   .nDeps = nDeps));
   16526              : 
   16527         1833 :         destroyPQExpBuffer(tagbuf);
   16528              :     }
   16529              : 
   16530        39029 :     destroyPQExpBuffer(sql);
   16531              : 
   16532        39029 :     return aclDumpId;
   16533              : }
   16534              : 
   16535              : /*
   16536              :  * dumpSecLabel
   16537              :  *
   16538              :  * This routine is used to dump any security labels associated with the
   16539              :  * object handed to this routine. The routine takes the object type
   16540              :  * and object name (ready to print, except for schema decoration), plus
   16541              :  * the namespace and owner of the object (for labeling the ArchiveEntry),
   16542              :  * plus catalog ID and subid which are the lookup key for pg_seclabel,
   16543              :  * plus the dump ID for the object (for setting a dependency).
   16544              :  * If a matching pg_seclabel entry is found, it is dumped.
   16545              :  *
   16546              :  * Note: although this routine takes a dumpId for dependency purposes,
   16547              :  * that purpose is just to mark the dependency in the emitted dump file
   16548              :  * for possible future use by pg_restore.  We do NOT use it for determining
   16549              :  * ordering of the label in the dump file, because this routine is called
   16550              :  * after dependency sorting occurs.  This routine should be called just after
   16551              :  * calling ArchiveEntry() for the specified object.
   16552              :  */
   16553              : static void
   16554           10 : dumpSecLabel(Archive *fout, const char *type, const char *name,
   16555              :              const char *namespace, const char *owner,
   16556              :              CatalogId catalogId, int subid, DumpId dumpId)
   16557              : {
   16558           10 :     DumpOptions *dopt = fout->dopt;
   16559              :     SecLabelItem *labels;
   16560              :     int         nlabels;
   16561              :     int         i;
   16562              :     PQExpBuffer query;
   16563              : 
   16564              :     /* do nothing, if --no-security-labels is supplied */
   16565           10 :     if (dopt->no_security_labels)
   16566            0 :         return;
   16567              : 
   16568              :     /*
   16569              :      * Security labels are schema not data ... except large object labels are
   16570              :      * data
   16571              :      */
   16572           10 :     if (strcmp(type, "LARGE OBJECT") != 0)
   16573              :     {
   16574            0 :         if (!dopt->dumpSchema)
   16575            0 :             return;
   16576              :     }
   16577              :     else
   16578              :     {
   16579              :         /* We do dump large object security labels in binary-upgrade mode */
   16580           10 :         if (!dopt->dumpData && !dopt->binary_upgrade)
   16581            0 :             return;
   16582              :     }
   16583              : 
   16584              :     /* Search for security labels associated with catalogId, using table */
   16585           10 :     nlabels = findSecLabels(catalogId.tableoid, catalogId.oid, &labels);
   16586              : 
   16587           10 :     query = createPQExpBuffer();
   16588              : 
   16589           15 :     for (i = 0; i < nlabels; i++)
   16590              :     {
   16591              :         /*
   16592              :          * Ignore label entries for which the subid doesn't match.
   16593              :          */
   16594            5 :         if (labels[i].objsubid != subid)
   16595            0 :             continue;
   16596              : 
   16597            5 :         appendPQExpBuffer(query,
   16598              :                           "SECURITY LABEL FOR %s ON %s ",
   16599            5 :                           fmtId(labels[i].provider), type);
   16600            5 :         if (namespace && *namespace)
   16601            0 :             appendPQExpBuffer(query, "%s.", fmtId(namespace));
   16602            5 :         appendPQExpBuffer(query, "%s IS ", name);
   16603            5 :         appendStringLiteralAH(query, labels[i].label, fout);
   16604            5 :         appendPQExpBufferStr(query, ";\n");
   16605              :     }
   16606              : 
   16607           10 :     if (query->len > 0)
   16608              :     {
   16609            5 :         PQExpBuffer tag = createPQExpBuffer();
   16610              : 
   16611            5 :         appendPQExpBuffer(tag, "%s %s", type, name);
   16612            5 :         ArchiveEntry(fout, nilCatalogId, createDumpId(),
   16613            5 :                      ARCHIVE_OPTS(.tag = tag->data,
   16614              :                                   .namespace = namespace,
   16615              :                                   .owner = owner,
   16616              :                                   .description = "SECURITY LABEL",
   16617              :                                   .section = SECTION_NONE,
   16618              :                                   .createStmt = query->data,
   16619              :                                   .deps = &dumpId,
   16620              :                                   .nDeps = 1));
   16621            5 :         destroyPQExpBuffer(tag);
   16622              :     }
   16623              : 
   16624           10 :     destroyPQExpBuffer(query);
   16625              : }
   16626              : 
   16627              : /*
   16628              :  * dumpTableSecLabel
   16629              :  *
   16630              :  * As above, but dump security label for both the specified table (or view)
   16631              :  * and its columns.
   16632              :  */
   16633              : static void
   16634            0 : dumpTableSecLabel(Archive *fout, const TableInfo *tbinfo, const char *reltypename)
   16635              : {
   16636            0 :     DumpOptions *dopt = fout->dopt;
   16637              :     SecLabelItem *labels;
   16638              :     int         nlabels;
   16639              :     int         i;
   16640              :     PQExpBuffer query;
   16641              :     PQExpBuffer target;
   16642              : 
   16643              :     /* do nothing, if --no-security-labels is supplied */
   16644            0 :     if (dopt->no_security_labels)
   16645            0 :         return;
   16646              : 
   16647              :     /* SecLabel are SCHEMA not data */
   16648            0 :     if (!dopt->dumpSchema)
   16649            0 :         return;
   16650              : 
   16651              :     /* Search for comments associated with relation, using table */
   16652            0 :     nlabels = findSecLabels(tbinfo->dobj.catId.tableoid,
   16653            0 :                             tbinfo->dobj.catId.oid,
   16654              :                             &labels);
   16655              : 
   16656              :     /* If security labels exist, build SECURITY LABEL statements */
   16657            0 :     if (nlabels <= 0)
   16658            0 :         return;
   16659              : 
   16660            0 :     query = createPQExpBuffer();
   16661            0 :     target = createPQExpBuffer();
   16662              : 
   16663            0 :     for (i = 0; i < nlabels; i++)
   16664              :     {
   16665              :         const char *colname;
   16666            0 :         const char *provider = labels[i].provider;
   16667            0 :         const char *label = labels[i].label;
   16668            0 :         int         objsubid = labels[i].objsubid;
   16669              : 
   16670            0 :         resetPQExpBuffer(target);
   16671            0 :         if (objsubid == 0)
   16672              :         {
   16673            0 :             appendPQExpBuffer(target, "%s %s", reltypename,
   16674            0 :                               fmtQualifiedDumpable(tbinfo));
   16675              :         }
   16676              :         else
   16677              :         {
   16678            0 :             colname = getAttrName(objsubid, tbinfo);
   16679              :             /* first fmtXXX result must be consumed before calling again */
   16680            0 :             appendPQExpBuffer(target, "COLUMN %s",
   16681            0 :                               fmtQualifiedDumpable(tbinfo));
   16682            0 :             appendPQExpBuffer(target, ".%s", fmtId(colname));
   16683              :         }
   16684            0 :         appendPQExpBuffer(query, "SECURITY LABEL FOR %s ON %s IS ",
   16685              :                           fmtId(provider), target->data);
   16686            0 :         appendStringLiteralAH(query, label, fout);
   16687            0 :         appendPQExpBufferStr(query, ";\n");
   16688              :     }
   16689            0 :     if (query->len > 0)
   16690              :     {
   16691            0 :         resetPQExpBuffer(target);
   16692            0 :         appendPQExpBuffer(target, "%s %s", reltypename,
   16693            0 :                           fmtId(tbinfo->dobj.name));
   16694            0 :         ArchiveEntry(fout, nilCatalogId, createDumpId(),
   16695            0 :                      ARCHIVE_OPTS(.tag = target->data,
   16696              :                                   .namespace = tbinfo->dobj.namespace->dobj.name,
   16697              :                                   .owner = tbinfo->rolname,
   16698              :                                   .description = "SECURITY LABEL",
   16699              :                                   .section = SECTION_NONE,
   16700              :                                   .createStmt = query->data,
   16701              :                                   .deps = &(tbinfo->dobj.dumpId),
   16702              :                                   .nDeps = 1));
   16703              :     }
   16704            0 :     destroyPQExpBuffer(query);
   16705            0 :     destroyPQExpBuffer(target);
   16706              : }
   16707              : 
   16708              : /*
   16709              :  * findSecLabels
   16710              :  *
   16711              :  * Find the security label(s), if any, associated with the given object.
   16712              :  * All the objsubid values associated with the given classoid/objoid are
   16713              :  * found with one search.
   16714              :  */
   16715              : static int
   16716           10 : findSecLabels(Oid classoid, Oid objoid, SecLabelItem **items)
   16717              : {
   16718           10 :     SecLabelItem *middle = NULL;
   16719              :     SecLabelItem *low;
   16720              :     SecLabelItem *high;
   16721              :     int         nmatch;
   16722              : 
   16723           10 :     if (nseclabels <= 0)     /* no labels, so no match is possible */
   16724              :     {
   16725            0 :         *items = NULL;
   16726            0 :         return 0;
   16727              :     }
   16728              : 
   16729              :     /*
   16730              :      * Do binary search to find some item matching the object.
   16731              :      */
   16732           10 :     low = &seclabels[0];
   16733           10 :     high = &seclabels[nseclabels - 1];
   16734           15 :     while (low <= high)
   16735              :     {
   16736           10 :         middle = low + (high - low) / 2;
   16737              : 
   16738           10 :         if (classoid < middle->classoid)
   16739            0 :             high = middle - 1;
   16740           10 :         else if (classoid > middle->classoid)
   16741            0 :             low = middle + 1;
   16742           10 :         else if (objoid < middle->objoid)
   16743            5 :             high = middle - 1;
   16744            5 :         else if (objoid > middle->objoid)
   16745            0 :             low = middle + 1;
   16746              :         else
   16747            5 :             break;              /* found a match */
   16748              :     }
   16749              : 
   16750           10 :     if (low > high)              /* no matches */
   16751              :     {
   16752            5 :         *items = NULL;
   16753            5 :         return 0;
   16754              :     }
   16755              : 
   16756              :     /*
   16757              :      * Now determine how many items match the object.  The search loop
   16758              :      * invariant still holds: only items between low and high inclusive could
   16759              :      * match.
   16760              :      */
   16761            5 :     nmatch = 1;
   16762            5 :     while (middle > low)
   16763              :     {
   16764            0 :         if (classoid != middle[-1].classoid ||
   16765            0 :             objoid != middle[-1].objoid)
   16766              :             break;
   16767            0 :         middle--;
   16768            0 :         nmatch++;
   16769              :     }
   16770              : 
   16771            5 :     *items = middle;
   16772              : 
   16773            5 :     middle += nmatch;
   16774            5 :     while (middle <= high)
   16775              :     {
   16776            0 :         if (classoid != middle->classoid ||
   16777            0 :             objoid != middle->objoid)
   16778              :             break;
   16779            0 :         middle++;
   16780            0 :         nmatch++;
   16781              :     }
   16782              : 
   16783            5 :     return nmatch;
   16784              : }
   16785              : 
   16786              : /*
   16787              :  * collectSecLabels
   16788              :  *
   16789              :  * Construct a table of all security labels available for database objects;
   16790              :  * also set the has-seclabel component flag for each relevant object.
   16791              :  *
   16792              :  * The table is sorted by classoid/objid/objsubid for speed in lookup.
   16793              :  */
   16794              : static void
   16795          249 : collectSecLabels(Archive *fout)
   16796              : {
   16797              :     PGresult   *res;
   16798              :     PQExpBuffer query;
   16799              :     int         i_label;
   16800              :     int         i_provider;
   16801              :     int         i_classoid;
   16802              :     int         i_objoid;
   16803              :     int         i_objsubid;
   16804              :     int         ntups;
   16805              :     int         i;
   16806              :     DumpableObject *dobj;
   16807              : 
   16808          249 :     query = createPQExpBuffer();
   16809              : 
   16810          249 :     appendPQExpBufferStr(query,
   16811              :                          "SELECT label, provider, classoid, objoid, objsubid "
   16812              :                          "FROM pg_catalog.pg_seclabels "
   16813              :                          "ORDER BY classoid, objoid, objsubid");
   16814              : 
   16815          249 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   16816              : 
   16817              :     /* Construct lookup table containing OIDs in numeric form */
   16818          249 :     i_label = PQfnumber(res, "label");
   16819          249 :     i_provider = PQfnumber(res, "provider");
   16820          249 :     i_classoid = PQfnumber(res, "classoid");
   16821          249 :     i_objoid = PQfnumber(res, "objoid");
   16822          249 :     i_objsubid = PQfnumber(res, "objsubid");
   16823              : 
   16824          249 :     ntups = PQntuples(res);
   16825              : 
   16826          249 :     seclabels = pg_malloc_array(SecLabelItem, ntups);
   16827          249 :     nseclabels = 0;
   16828          249 :     dobj = NULL;
   16829              : 
   16830          254 :     for (i = 0; i < ntups; i++)
   16831              :     {
   16832              :         CatalogId   objId;
   16833              :         int         subid;
   16834              : 
   16835            5 :         objId.tableoid = atooid(PQgetvalue(res, i, i_classoid));
   16836            5 :         objId.oid = atooid(PQgetvalue(res, i, i_objoid));
   16837            5 :         subid = atoi(PQgetvalue(res, i, i_objsubid));
   16838              : 
   16839              :         /* We needn't remember labels that don't match any dumpable object */
   16840            5 :         if (dobj == NULL ||
   16841            0 :             dobj->catId.tableoid != objId.tableoid ||
   16842            0 :             dobj->catId.oid != objId.oid)
   16843            5 :             dobj = findObjectByCatalogId(objId);
   16844            5 :         if (dobj == NULL)
   16845            0 :             continue;
   16846              : 
   16847              :         /*
   16848              :          * Labels on columns of composite types are linked to the type's
   16849              :          * pg_class entry, but we need to set the DUMP_COMPONENT_SECLABEL flag
   16850              :          * in the type's own DumpableObject.
   16851              :          */
   16852            5 :         if (subid != 0 && dobj->objType == DO_TABLE &&
   16853            0 :             ((TableInfo *) dobj)->relkind == RELKIND_COMPOSITE_TYPE)
   16854            0 :         {
   16855              :             TypeInfo   *cTypeInfo;
   16856              : 
   16857            0 :             cTypeInfo = findTypeByOid(((TableInfo *) dobj)->reltype);
   16858            0 :             if (cTypeInfo)
   16859            0 :                 cTypeInfo->dobj.components |= DUMP_COMPONENT_SECLABEL;
   16860              :         }
   16861              :         else
   16862            5 :             dobj->components |= DUMP_COMPONENT_SECLABEL;
   16863              : 
   16864            5 :         seclabels[nseclabels].label = pg_strdup(PQgetvalue(res, i, i_label));
   16865            5 :         seclabels[nseclabels].provider = pg_strdup(PQgetvalue(res, i, i_provider));
   16866            5 :         seclabels[nseclabels].classoid = objId.tableoid;
   16867            5 :         seclabels[nseclabels].objoid = objId.oid;
   16868            5 :         seclabels[nseclabels].objsubid = subid;
   16869            5 :         nseclabels++;
   16870              :     }
   16871              : 
   16872          249 :     PQclear(res);
   16873          249 :     destroyPQExpBuffer(query);
   16874          249 : }
   16875              : 
   16876              : /*
   16877              :  * dumpTable
   16878              :  *    write out to fout the declarations (not data) of a user-defined table
   16879              :  */
   16880              : static void
   16881        40471 : dumpTable(Archive *fout, const TableInfo *tbinfo)
   16882              : {
   16883        40471 :     DumpOptions *dopt = fout->dopt;
   16884        40471 :     DumpId      tableAclDumpId = InvalidDumpId;
   16885              :     char       *namecopy;
   16886              : 
   16887              :     /* Do nothing if not dumping schema */
   16888        40471 :     if (!dopt->dumpSchema)
   16889         1526 :         return;
   16890              : 
   16891        38945 :     if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   16892              :     {
   16893         6818 :         if (tbinfo->relkind == RELKIND_SEQUENCE)
   16894          383 :             dumpSequence(fout, tbinfo);
   16895              :         else
   16896         6435 :             dumpTableSchema(fout, tbinfo);
   16897              :     }
   16898              : 
   16899              :     /* Handle the ACL here */
   16900        38945 :     namecopy = pg_strdup(fmtId(tbinfo->dobj.name));
   16901        38945 :     if (tbinfo->dobj.dump & DUMP_COMPONENT_ACL)
   16902              :     {
   16903        32864 :         const char *objtype =
   16904        32864 :             (tbinfo->relkind == RELKIND_SEQUENCE) ? "SEQUENCE" : "TABLE";
   16905              : 
   16906              :         tableAclDumpId =
   16907        32864 :             dumpACL(fout, tbinfo->dobj.dumpId, InvalidDumpId,
   16908              :                     objtype, namecopy, NULL,
   16909        32864 :                     tbinfo->dobj.namespace->dobj.name,
   16910        32864 :                     NULL, tbinfo->rolname, &tbinfo->dacl);
   16911              :     }
   16912              : 
   16913              :     /*
   16914              :      * Handle column ACLs, if any.  Note: we pull these with a separate query
   16915              :      * rather than trying to fetch them during getTableAttrs, so that we won't
   16916              :      * miss ACLs on system columns.  Doing it this way also allows us to dump
   16917              :      * ACLs for catalogs that we didn't mark "interesting" back in getTables.
   16918              :      */
   16919        38945 :     if ((tbinfo->dobj.dump & DUMP_COMPONENT_ACL) && tbinfo->hascolumnACLs)
   16920              :     {
   16921          344 :         PQExpBuffer query = createPQExpBuffer();
   16922              :         PGresult   *res;
   16923              :         int         i;
   16924              : 
   16925          344 :         if (!fout->is_prepared[PREPQUERY_GETCOLUMNACLS])
   16926              :         {
   16927              :             /* Set up query for column ACLs */
   16928          223 :             appendPQExpBufferStr(query,
   16929              :                                  "PREPARE getColumnACLs(pg_catalog.oid) AS\n");
   16930              : 
   16931          223 :             if (fout->remoteVersion >= 90600)
   16932              :             {
   16933              :                 /*
   16934              :                  * In principle we should call acldefault('c', relowner) to
   16935              :                  * get the default ACL for a column.  However, we don't
   16936              :                  * currently store the numeric OID of the relowner in
   16937              :                  * TableInfo.  We could convert the owner name using regrole,
   16938              :                  * but that creates a risk of failure due to concurrent role
   16939              :                  * renames.  Given that the default ACL for columns is empty
   16940              :                  * and is likely to stay that way, it's not worth extra cycles
   16941              :                  * and risk to avoid hard-wiring that knowledge here.
   16942              :                  */
   16943          223 :                 appendPQExpBufferStr(query,
   16944              :                                      "SELECT at.attname, "
   16945              :                                      "at.attacl, "
   16946              :                                      "'{}' AS acldefault, "
   16947              :                                      "pip.privtype, pip.initprivs "
   16948              :                                      "FROM pg_catalog.pg_attribute at "
   16949              :                                      "LEFT JOIN pg_catalog.pg_init_privs pip ON "
   16950              :                                      "(at.attrelid = pip.objoid "
   16951              :                                      "AND pip.classoid = 'pg_catalog.pg_class'::pg_catalog.regclass "
   16952              :                                      "AND at.attnum = pip.objsubid) "
   16953              :                                      "WHERE at.attrelid = $1 AND "
   16954              :                                      "NOT at.attisdropped "
   16955              :                                      "AND (at.attacl IS NOT NULL OR pip.initprivs IS NOT NULL) "
   16956              :                                      "ORDER BY at.attnum");
   16957              :             }
   16958              :             else
   16959              :             {
   16960            0 :                 appendPQExpBufferStr(query,
   16961              :                                      "SELECT attname, attacl, '{}' AS acldefault, "
   16962              :                                      "NULL AS privtype, NULL AS initprivs "
   16963              :                                      "FROM pg_catalog.pg_attribute "
   16964              :                                      "WHERE attrelid = $1 AND NOT attisdropped "
   16965              :                                      "AND attacl IS NOT NULL "
   16966              :                                      "ORDER BY attnum");
   16967              :             }
   16968              : 
   16969          223 :             ExecuteSqlStatement(fout, query->data);
   16970              : 
   16971          223 :             fout->is_prepared[PREPQUERY_GETCOLUMNACLS] = true;
   16972              :         }
   16973              : 
   16974          344 :         printfPQExpBuffer(query,
   16975              :                           "EXECUTE getColumnACLs('%u')",
   16976          344 :                           tbinfo->dobj.catId.oid);
   16977              : 
   16978          344 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   16979              : 
   16980         5791 :         for (i = 0; i < PQntuples(res); i++)
   16981              :         {
   16982         5447 :             char       *attname = PQgetvalue(res, i, 0);
   16983         5447 :             char       *attacl = PQgetvalue(res, i, 1);
   16984         5447 :             char       *acldefault = PQgetvalue(res, i, 2);
   16985         5447 :             char        privtype = *(PQgetvalue(res, i, 3));
   16986         5447 :             char       *initprivs = PQgetvalue(res, i, 4);
   16987              :             DumpableAcl coldacl;
   16988              :             char       *attnamecopy;
   16989              : 
   16990         5447 :             coldacl.acl = attacl;
   16991         5447 :             coldacl.acldefault = acldefault;
   16992         5447 :             coldacl.privtype = privtype;
   16993         5447 :             coldacl.initprivs = initprivs;
   16994         5447 :             attnamecopy = pg_strdup(fmtId(attname));
   16995              : 
   16996              :             /*
   16997              :              * Column's GRANT type is always TABLE.  Each column ACL depends
   16998              :              * on the table-level ACL, since we can restore column ACLs in
   16999              :              * parallel but the table-level ACL has to be done first.
   17000              :              */
   17001         5447 :             dumpACL(fout, tbinfo->dobj.dumpId, tableAclDumpId,
   17002              :                     "TABLE", namecopy, attnamecopy,
   17003         5447 :                     tbinfo->dobj.namespace->dobj.name,
   17004         5447 :                     NULL, tbinfo->rolname, &coldacl);
   17005         5447 :             free(attnamecopy);
   17006              :         }
   17007          344 :         PQclear(res);
   17008          344 :         destroyPQExpBuffer(query);
   17009              :     }
   17010              : 
   17011        38945 :     free(namecopy);
   17012              : }
   17013              : 
   17014              : /*
   17015              :  * Create the AS clause for a view or materialized view. The semicolon is
   17016              :  * stripped because a materialized view must add a WITH NO DATA clause.
   17017              :  *
   17018              :  * This returns a new buffer which must be freed by the caller.
   17019              :  */
   17020              : static PQExpBuffer
   17021          868 : createViewAsClause(Archive *fout, const TableInfo *tbinfo)
   17022              : {
   17023          868 :     PQExpBuffer query = createPQExpBuffer();
   17024          868 :     PQExpBuffer result = createPQExpBuffer();
   17025              :     PGresult   *res;
   17026              :     int         len;
   17027              : 
   17028              :     /* Fetch the view definition */
   17029          868 :     appendPQExpBuffer(query,
   17030              :                       "SELECT pg_catalog.pg_get_viewdef('%u'::pg_catalog.oid) AS viewdef",
   17031          868 :                       tbinfo->dobj.catId.oid);
   17032              : 
   17033          868 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   17034              : 
   17035          868 :     if (PQntuples(res) != 1)
   17036              :     {
   17037            0 :         if (PQntuples(res) < 1)
   17038            0 :             pg_fatal("query to obtain definition of view \"%s\" returned no data",
   17039              :                      tbinfo->dobj.name);
   17040              :         else
   17041            0 :             pg_fatal("query to obtain definition of view \"%s\" returned more than one definition",
   17042              :                      tbinfo->dobj.name);
   17043              :     }
   17044              : 
   17045          868 :     len = PQgetlength(res, 0, 0);
   17046              : 
   17047          868 :     if (len == 0)
   17048            0 :         pg_fatal("definition of view \"%s\" appears to be empty (length zero)",
   17049              :                  tbinfo->dobj.name);
   17050              : 
   17051              :     /* Strip off the trailing semicolon so that other things may follow. */
   17052              :     Assert(PQgetvalue(res, 0, 0)[len - 1] == ';');
   17053          868 :     appendBinaryPQExpBuffer(result, PQgetvalue(res, 0, 0), len - 1);
   17054              : 
   17055          868 :     PQclear(res);
   17056          868 :     destroyPQExpBuffer(query);
   17057              : 
   17058          868 :     return result;
   17059              : }
   17060              : 
   17061              : /*
   17062              :  * Create a dummy AS clause for a view.  This is used when the real view
   17063              :  * definition has to be postponed because of circular dependencies.
   17064              :  * We must duplicate the view's external properties -- column names and types
   17065              :  * (including collation) -- so that it works for subsequent references.
   17066              :  *
   17067              :  * This returns a new buffer which must be freed by the caller.
   17068              :  */
   17069              : static PQExpBuffer
   17070           20 : createDummyViewAsClause(Archive *fout, const TableInfo *tbinfo)
   17071              : {
   17072           20 :     PQExpBuffer result = createPQExpBuffer();
   17073              :     int         j;
   17074              : 
   17075           20 :     appendPQExpBufferStr(result, "SELECT");
   17076              : 
   17077           40 :     for (j = 0; j < tbinfo->numatts; j++)
   17078              :     {
   17079           20 :         if (j > 0)
   17080           10 :             appendPQExpBufferChar(result, ',');
   17081           20 :         appendPQExpBufferStr(result, "\n    ");
   17082              : 
   17083           20 :         appendPQExpBuffer(result, "NULL::%s", tbinfo->atttypnames[j]);
   17084              : 
   17085              :         /*
   17086              :          * Must add collation if not default for the type, because CREATE OR
   17087              :          * REPLACE VIEW won't change it
   17088              :          */
   17089           20 :         if (OidIsValid(tbinfo->attcollation[j]))
   17090              :         {
   17091              :             CollInfo   *coll;
   17092              : 
   17093            0 :             coll = findCollationByOid(tbinfo->attcollation[j]);
   17094            0 :             if (coll)
   17095            0 :                 appendPQExpBuffer(result, " COLLATE %s",
   17096            0 :                                   fmtQualifiedDumpable(coll));
   17097              :         }
   17098              : 
   17099           20 :         appendPQExpBuffer(result, " AS %s", fmtId(tbinfo->attnames[j]));
   17100              :     }
   17101              : 
   17102           20 :     return result;
   17103              : }
   17104              : 
   17105              : /*
   17106              :  * dumpTableSchema
   17107              :  *    write the declaration (not data) of one user-defined table or view
   17108              :  */
   17109              : static void
   17110         6435 : dumpTableSchema(Archive *fout, const TableInfo *tbinfo)
   17111              : {
   17112         6435 :     DumpOptions *dopt = fout->dopt;
   17113         6435 :     PQExpBuffer q = createPQExpBuffer();
   17114         6435 :     PQExpBuffer delq = createPQExpBuffer();
   17115         6435 :     PQExpBuffer extra = createPQExpBuffer();
   17116              :     char       *qrelname;
   17117              :     char       *qualrelname;
   17118              :     int         numParents;
   17119              :     TableInfo **parents;
   17120              :     int         actual_atts;    /* number of attrs in this CREATE statement */
   17121              :     const char *reltypename;
   17122              :     char       *storage;
   17123              :     int         j,
   17124              :                 k;
   17125              : 
   17126              :     /* We had better have loaded per-column details about this table */
   17127              :     Assert(tbinfo->interesting);
   17128              : 
   17129         6435 :     qrelname = pg_strdup(fmtId(tbinfo->dobj.name));
   17130         6435 :     qualrelname = pg_strdup(fmtQualifiedDumpable(tbinfo));
   17131              : 
   17132         6435 :     if (tbinfo->hasoids)
   17133            0 :         pg_log_warning("WITH OIDS is not supported anymore (table \"%s\")",
   17134              :                        qrelname);
   17135              : 
   17136         6435 :     if (dopt->binary_upgrade)
   17137          874 :         binary_upgrade_set_type_oids_by_rel(fout, q, tbinfo);
   17138              : 
   17139              :     /* Is it a table or a view? */
   17140         6435 :     if (tbinfo->relkind == RELKIND_VIEW)
   17141              :     {
   17142              :         PQExpBuffer result;
   17143              : 
   17144              :         /*
   17145              :          * Note: keep this code in sync with the is_view case in dumpRule()
   17146              :          */
   17147              : 
   17148          533 :         reltypename = "VIEW";
   17149              : 
   17150          533 :         appendPQExpBuffer(delq, "DROP VIEW %s;\n", qualrelname);
   17151              : 
   17152          533 :         if (dopt->binary_upgrade)
   17153           52 :             binary_upgrade_set_pg_class_oids(fout, q,
   17154           52 :                                              tbinfo->dobj.catId.oid);
   17155              : 
   17156          533 :         appendPQExpBuffer(q, "CREATE VIEW %s", qualrelname);
   17157              : 
   17158          533 :         if (tbinfo->dummy_view)
   17159           10 :             result = createDummyViewAsClause(fout, tbinfo);
   17160              :         else
   17161              :         {
   17162          523 :             if (nonemptyReloptions(tbinfo->reloptions))
   17163              :             {
   17164           61 :                 appendPQExpBufferStr(q, " WITH (");
   17165           61 :                 appendReloptionsArrayAH(q, tbinfo->reloptions, "", fout);
   17166           61 :                 appendPQExpBufferChar(q, ')');
   17167              :             }
   17168          523 :             result = createViewAsClause(fout, tbinfo);
   17169              :         }
   17170          533 :         appendPQExpBuffer(q, " AS\n%s", result->data);
   17171          533 :         destroyPQExpBuffer(result);
   17172              : 
   17173          533 :         if (tbinfo->checkoption != NULL && !tbinfo->dummy_view)
   17174           32 :             appendPQExpBuffer(q, "\n  WITH %s CHECK OPTION", tbinfo->checkoption);
   17175          533 :         appendPQExpBufferStr(q, ";\n");
   17176              :     }
   17177              :     else
   17178              :     {
   17179         5902 :         char       *partkeydef = NULL;
   17180         5902 :         char       *ftoptions = NULL;
   17181         5902 :         char       *srvname = NULL;
   17182         5902 :         const char *foreign = "";
   17183              : 
   17184              :         /*
   17185              :          * Set reltypename, and collect any relkind-specific data that we
   17186              :          * didn't fetch during getTables().
   17187              :          */
   17188         5902 :         switch (tbinfo->relkind)
   17189              :         {
   17190          576 :             case RELKIND_PARTITIONED_TABLE:
   17191              :                 {
   17192          576 :                     PQExpBuffer query = createPQExpBuffer();
   17193              :                     PGresult   *res;
   17194              : 
   17195          576 :                     reltypename = "TABLE";
   17196              : 
   17197              :                     /* retrieve partition key definition */
   17198          576 :                     appendPQExpBuffer(query,
   17199              :                                       "SELECT pg_get_partkeydef('%u')",
   17200          576 :                                       tbinfo->dobj.catId.oid);
   17201          576 :                     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   17202          576 :                     partkeydef = pg_strdup(PQgetvalue(res, 0, 0));
   17203          576 :                     PQclear(res);
   17204          576 :                     destroyPQExpBuffer(query);
   17205          576 :                     break;
   17206              :                 }
   17207           34 :             case RELKIND_FOREIGN_TABLE:
   17208              :                 {
   17209           34 :                     PQExpBuffer query = createPQExpBuffer();
   17210              :                     PGresult   *res;
   17211              :                     int         i_srvname;
   17212              :                     int         i_ftoptions;
   17213              : 
   17214           34 :                     reltypename = "FOREIGN TABLE";
   17215              : 
   17216              :                     /* retrieve name of foreign server and generic options */
   17217           34 :                     appendPQExpBuffer(query,
   17218              :                                       "SELECT fs.srvname, "
   17219              :                                       "pg_catalog.array_to_string(ARRAY("
   17220              :                                       "SELECT pg_catalog.quote_ident(option_name) || "
   17221              :                                       "' ' || pg_catalog.quote_literal(option_value) "
   17222              :                                       "FROM pg_catalog.pg_options_to_table(ftoptions) "
   17223              :                                       "ORDER BY option_name"
   17224              :                                       "), E',\n    ') AS ftoptions "
   17225              :                                       "FROM pg_catalog.pg_foreign_table ft "
   17226              :                                       "JOIN pg_catalog.pg_foreign_server fs "
   17227              :                                       "ON (fs.oid = ft.ftserver) "
   17228              :                                       "WHERE ft.ftrelid = '%u'",
   17229           34 :                                       tbinfo->dobj.catId.oid);
   17230           34 :                     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   17231           34 :                     i_srvname = PQfnumber(res, "srvname");
   17232           34 :                     i_ftoptions = PQfnumber(res, "ftoptions");
   17233           34 :                     srvname = pg_strdup(PQgetvalue(res, 0, i_srvname));
   17234           34 :                     ftoptions = pg_strdup(PQgetvalue(res, 0, i_ftoptions));
   17235           34 :                     PQclear(res);
   17236           34 :                     destroyPQExpBuffer(query);
   17237              : 
   17238           34 :                     foreign = "FOREIGN ";
   17239           34 :                     break;
   17240              :                 }
   17241          335 :             case RELKIND_MATVIEW:
   17242          335 :                 reltypename = "MATERIALIZED VIEW";
   17243          335 :                 break;
   17244         4957 :             default:
   17245         4957 :                 reltypename = "TABLE";
   17246         4957 :                 break;
   17247              :         }
   17248              : 
   17249         5902 :         numParents = tbinfo->numParents;
   17250         5902 :         parents = tbinfo->parents;
   17251              : 
   17252         5902 :         appendPQExpBuffer(delq, "DROP %s %s;\n", reltypename, qualrelname);
   17253              : 
   17254         5902 :         if (dopt->binary_upgrade)
   17255          822 :             binary_upgrade_set_pg_class_oids(fout, q,
   17256          822 :                                              tbinfo->dobj.catId.oid);
   17257              : 
   17258              :         /*
   17259              :          * PostgreSQL 18 has disabled UNLOGGED for partitioned tables, so
   17260              :          * ignore it when dumping if it was set in this case.
   17261              :          */
   17262         5902 :         appendPQExpBuffer(q, "CREATE %s%s %s",
   17263         5902 :                           (tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED &&
   17264           20 :                            tbinfo->relkind != RELKIND_PARTITIONED_TABLE) ?
   17265              :                           "UNLOGGED " : "",
   17266              :                           reltypename,
   17267              :                           qualrelname);
   17268              : 
   17269              :         /*
   17270              :          * Attach to type, if reloftype; except in case of a binary upgrade,
   17271              :          * we dump the table normally and attach it to the type afterward.
   17272              :          */
   17273         5902 :         if (OidIsValid(tbinfo->reloftype) && !dopt->binary_upgrade)
   17274           24 :             appendPQExpBuffer(q, " OF %s",
   17275           24 :                               getFormattedTypeName(fout, tbinfo->reloftype,
   17276              :                                                    zeroIsError));
   17277              : 
   17278         5902 :         if (tbinfo->relkind != RELKIND_MATVIEW)
   17279              :         {
   17280              :             /* Dump the attributes */
   17281         5567 :             actual_atts = 0;
   17282        25772 :             for (j = 0; j < tbinfo->numatts; j++)
   17283              :             {
   17284              :                 /*
   17285              :                  * Normally, dump if it's locally defined in this table, and
   17286              :                  * not dropped.  But for binary upgrade, we'll dump all the
   17287              :                  * columns, and then fix up the dropped and nonlocal cases
   17288              :                  * below.
   17289              :                  */
   17290        20205 :                 if (shouldPrintColumn(dopt, tbinfo, j))
   17291              :                 {
   17292              :                     bool        print_default;
   17293              :                     bool        print_notnull;
   17294              : 
   17295              :                     /*
   17296              :                      * Default value --- suppress if to be printed separately
   17297              :                      * or not at all.
   17298              :                      */
   17299        39368 :                     print_default = (tbinfo->attrdefs[j] != NULL &&
   17300        20161 :                                      tbinfo->attrdefs[j]->dobj.dump &&
   17301         1001 :                                      !tbinfo->attrdefs[j]->separate);
   17302              : 
   17303              :                     /*
   17304              :                      * Not Null constraint --- print it if it is locally
   17305              :                      * defined, or if binary upgrade.  (In the latter case, we
   17306              :                      * reset conislocal below.)
   17307              :                      */
   17308        21424 :                     print_notnull = (tbinfo->notnull_constrs[j] != NULL &&
   17309         2264 :                                      (tbinfo->notnull_islocal[j] ||
   17310          617 :                                       dopt->binary_upgrade ||
   17311          531 :                                       tbinfo->ispartition));
   17312              : 
   17313              :                     /*
   17314              :                      * Skip column if fully defined by reloftype, except in
   17315              :                      * binary upgrade
   17316              :                      */
   17317        19160 :                     if (OidIsValid(tbinfo->reloftype) &&
   17318           50 :                         !print_default && !print_notnull &&
   17319           30 :                         !dopt->binary_upgrade)
   17320           24 :                         continue;
   17321              : 
   17322              :                     /* Format properly if not first attr */
   17323        19136 :                     if (actual_atts == 0)
   17324         5210 :                         appendPQExpBufferStr(q, " (");
   17325              :                     else
   17326        13926 :                         appendPQExpBufferChar(q, ',');
   17327        19136 :                     appendPQExpBufferStr(q, "\n    ");
   17328        19136 :                     actual_atts++;
   17329              : 
   17330              :                     /* Attribute name */
   17331        19136 :                     appendPQExpBufferStr(q, fmtId(tbinfo->attnames[j]));
   17332              : 
   17333        19136 :                     if (tbinfo->attisdropped[j])
   17334              :                     {
   17335              :                         /*
   17336              :                          * ALTER TABLE DROP COLUMN clears
   17337              :                          * pg_attribute.atttypid, so we will not have gotten a
   17338              :                          * valid type name; insert INTEGER as a stopgap. We'll
   17339              :                          * clean things up later.
   17340              :                          */
   17341           84 :                         appendPQExpBufferStr(q, " INTEGER /* dummy */");
   17342              :                         /* and skip to the next column */
   17343           84 :                         continue;
   17344              :                     }
   17345              : 
   17346              :                     /*
   17347              :                      * Attribute type; print it except when creating a typed
   17348              :                      * table ('OF type_name'), but in binary-upgrade mode,
   17349              :                      * print it in that case too.
   17350              :                      */
   17351        19052 :                     if (dopt->binary_upgrade || !OidIsValid(tbinfo->reloftype))
   17352              :                     {
   17353        19036 :                         appendPQExpBuffer(q, " %s",
   17354        19036 :                                           tbinfo->atttypnames[j]);
   17355              :                     }
   17356              : 
   17357        19052 :                     if (print_default)
   17358              :                     {
   17359          871 :                         if (tbinfo->attgenerated[j] == ATTRIBUTE_GENERATED_STORED)
   17360          277 :                             appendPQExpBuffer(q, " GENERATED ALWAYS AS (%s) STORED",
   17361          277 :                                               tbinfo->attrdefs[j]->adef_expr);
   17362          594 :                         else if (tbinfo->attgenerated[j] == ATTRIBUTE_GENERATED_VIRTUAL)
   17363          223 :                             appendPQExpBuffer(q, " GENERATED ALWAYS AS (%s)",
   17364          223 :                                               tbinfo->attrdefs[j]->adef_expr);
   17365              :                         else
   17366          371 :                             appendPQExpBuffer(q, " DEFAULT %s",
   17367          371 :                                               tbinfo->attrdefs[j]->adef_expr);
   17368              :                     }
   17369              : 
   17370        19052 :                     if (print_notnull)
   17371              :                     {
   17372         2233 :                         if (tbinfo->notnull_constrs[j][0] == '\0')
   17373         1588 :                             appendPQExpBufferStr(q, " NOT NULL");
   17374              :                         else
   17375          645 :                             appendPQExpBuffer(q, " CONSTRAINT %s NOT NULL",
   17376          645 :                                               fmtId(tbinfo->notnull_constrs[j]));
   17377              : 
   17378         2233 :                         if (tbinfo->notnull_noinh[j])
   17379           33 :                             appendPQExpBufferStr(q, " NO INHERIT");
   17380              :                     }
   17381              : 
   17382              :                     /* Add collation if not default for the type */
   17383        19052 :                     if (OidIsValid(tbinfo->attcollation[j]))
   17384              :                     {
   17385              :                         CollInfo   *coll;
   17386              : 
   17387          200 :                         coll = findCollationByOid(tbinfo->attcollation[j]);
   17388          200 :                         if (coll)
   17389          200 :                             appendPQExpBuffer(q, " COLLATE %s",
   17390          200 :                                               fmtQualifiedDumpable(coll));
   17391              :                     }
   17392              :                 }
   17393              : 
   17394              :                 /*
   17395              :                  * On the other hand, if we choose not to print a column
   17396              :                  * (likely because it is created by inheritance), but the
   17397              :                  * column has a locally-defined not-null constraint, we need
   17398              :                  * to dump the constraint as a standalone object.
   17399              :                  *
   17400              :                  * This syntax isn't SQL-conforming, but if you wanted
   17401              :                  * standard output you wouldn't be creating non-standard
   17402              :                  * objects to begin with.
   17403              :                  */
   17404        20097 :                 if (!shouldPrintColumn(dopt, tbinfo, j) &&
   17405         1045 :                     !tbinfo->attisdropped[j] &&
   17406          682 :                     tbinfo->notnull_constrs[j] != NULL &&
   17407          208 :                     tbinfo->notnull_islocal[j])
   17408              :                 {
   17409              :                     /* Format properly if not first attr */
   17410           90 :                     if (actual_atts == 0)
   17411           86 :                         appendPQExpBufferStr(q, " (");
   17412              :                     else
   17413            4 :                         appendPQExpBufferChar(q, ',');
   17414           90 :                     appendPQExpBufferStr(q, "\n    ");
   17415           90 :                     actual_atts++;
   17416              : 
   17417           90 :                     if (tbinfo->notnull_constrs[j][0] == '\0')
   17418            8 :                         appendPQExpBuffer(q, "NOT NULL %s",
   17419            8 :                                           fmtId(tbinfo->attnames[j]));
   17420              :                     else
   17421          164 :                         appendPQExpBuffer(q, "CONSTRAINT %s NOT NULL %s",
   17422           82 :                                           tbinfo->notnull_constrs[j],
   17423           82 :                                           fmtId(tbinfo->attnames[j]));
   17424              : 
   17425           90 :                     if (tbinfo->notnull_noinh[j])
   17426           31 :                         appendPQExpBufferStr(q, " NO INHERIT");
   17427              :                 }
   17428              :             }
   17429              : 
   17430              :             /*
   17431              :              * Add non-inherited CHECK constraints, if any.
   17432              :              *
   17433              :              * For partitions, we need to include check constraints even if
   17434              :              * they're not defined locally, because the ALTER TABLE ATTACH
   17435              :              * PARTITION that we'll emit later expects the constraint to be
   17436              :              * there.  (No need to fix conislocal: ATTACH PARTITION does that)
   17437              :              */
   17438         6140 :             for (j = 0; j < tbinfo->ncheck; j++)
   17439              :             {
   17440          573 :                 ConstraintInfo *constr = &(tbinfo->checkexprs[j]);
   17441              : 
   17442          573 :                 if (constr->separate ||
   17443          503 :                     (!constr->conislocal && !tbinfo->ispartition))
   17444          107 :                     continue;
   17445              : 
   17446          466 :                 if (actual_atts == 0)
   17447           16 :                     appendPQExpBufferStr(q, " (\n    ");
   17448              :                 else
   17449          450 :                     appendPQExpBufferStr(q, ",\n    ");
   17450              : 
   17451          466 :                 appendPQExpBuffer(q, "CONSTRAINT %s ",
   17452          466 :                                   fmtId(constr->dobj.name));
   17453          466 :                 appendPQExpBufferStr(q, constr->condef);
   17454              : 
   17455          466 :                 actual_atts++;
   17456              :             }
   17457              : 
   17458         5567 :             if (actual_atts)
   17459         5312 :                 appendPQExpBufferStr(q, "\n)");
   17460          255 :             else if (!(OidIsValid(tbinfo->reloftype) && !dopt->binary_upgrade))
   17461              :             {
   17462              :                 /*
   17463              :                  * No attributes? we must have a parenthesized attribute list,
   17464              :                  * even though empty, when not using the OF TYPE syntax.
   17465              :                  */
   17466          243 :                 appendPQExpBufferStr(q, " (\n)");
   17467              :             }
   17468              : 
   17469              :             /*
   17470              :              * Emit the INHERITS clause (not for partitions), except in
   17471              :              * binary-upgrade mode.
   17472              :              */
   17473         5567 :             if (numParents > 0 && !tbinfo->ispartition &&
   17474          521 :                 !dopt->binary_upgrade)
   17475              :             {
   17476          456 :                 appendPQExpBufferStr(q, "\nINHERITS (");
   17477          983 :                 for (k = 0; k < numParents; k++)
   17478              :                 {
   17479          527 :                     TableInfo  *parentRel = parents[k];
   17480              : 
   17481          527 :                     if (k > 0)
   17482           71 :                         appendPQExpBufferStr(q, ", ");
   17483          527 :                     appendPQExpBufferStr(q, fmtQualifiedDumpable(parentRel));
   17484              :                 }
   17485          456 :                 appendPQExpBufferChar(q, ')');
   17486              :             }
   17487              : 
   17488         5567 :             if (tbinfo->relkind == RELKIND_PARTITIONED_TABLE)
   17489          576 :                 appendPQExpBuffer(q, "\nPARTITION BY %s", partkeydef);
   17490              : 
   17491         5567 :             if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
   17492           34 :                 appendPQExpBuffer(q, "\nSERVER %s", fmtId(srvname));
   17493              :         }
   17494              : 
   17495        11651 :         if (nonemptyReloptions(tbinfo->reloptions) ||
   17496         5749 :             nonemptyReloptions(tbinfo->toast_reloptions))
   17497              :         {
   17498          153 :             bool        addcomma = false;
   17499              : 
   17500          153 :             appendPQExpBufferStr(q, "\nWITH (");
   17501          153 :             if (nonemptyReloptions(tbinfo->reloptions))
   17502              :             {
   17503          153 :                 addcomma = true;
   17504          153 :                 appendReloptionsArrayAH(q, tbinfo->reloptions, "", fout);
   17505              :             }
   17506          153 :             if (nonemptyReloptions(tbinfo->toast_reloptions))
   17507              :             {
   17508            5 :                 if (addcomma)
   17509            5 :                     appendPQExpBufferStr(q, ", ");
   17510            5 :                 appendReloptionsArrayAH(q, tbinfo->toast_reloptions, "toast.",
   17511              :                                         fout);
   17512              :             }
   17513          153 :             appendPQExpBufferChar(q, ')');
   17514              :         }
   17515              : 
   17516              :         /* Dump generic options if any */
   17517         5902 :         if (ftoptions && ftoptions[0])
   17518           32 :             appendPQExpBuffer(q, "\nOPTIONS (\n    %s\n)", ftoptions);
   17519              : 
   17520              :         /*
   17521              :          * For materialized views, create the AS clause just like a view. At
   17522              :          * this point, we always mark the view as not populated.
   17523              :          */
   17524         5902 :         if (tbinfo->relkind == RELKIND_MATVIEW)
   17525              :         {
   17526              :             PQExpBuffer result;
   17527              : 
   17528          335 :             result = createViewAsClause(fout, tbinfo);
   17529          335 :             appendPQExpBuffer(q, " AS\n%s\n  WITH NO DATA;\n",
   17530              :                               result->data);
   17531          335 :             destroyPQExpBuffer(result);
   17532              :         }
   17533              :         else
   17534         5567 :             appendPQExpBufferStr(q, ";\n");
   17535              : 
   17536              :         /* Materialized views can depend on extensions */
   17537         5902 :         if (tbinfo->relkind == RELKIND_MATVIEW)
   17538          335 :             append_depends_on_extension(fout, q, &tbinfo->dobj,
   17539              :                                         "pg_catalog.pg_class",
   17540              :                                         "MATERIALIZED VIEW",
   17541              :                                         qualrelname);
   17542              : 
   17543              :         /*
   17544              :          * in binary upgrade mode, update the catalog with any missing values
   17545              :          * that might be present.
   17546              :          */
   17547         5902 :         if (dopt->binary_upgrade)
   17548              :         {
   17549         3975 :             for (j = 0; j < tbinfo->numatts; j++)
   17550              :             {
   17551         3153 :                 if (tbinfo->attmissingval[j][0] != '\0')
   17552              :                 {
   17553            3 :                     appendPQExpBufferStr(q, "\n-- set missing value.\n");
   17554            3 :                     appendPQExpBufferStr(q,
   17555              :                                          "SELECT pg_catalog.binary_upgrade_set_missing_value(");
   17556            3 :                     appendStringLiteralAH(q, qualrelname, fout);
   17557            3 :                     appendPQExpBufferStr(q, "::pg_catalog.regclass,");
   17558            3 :                     appendStringLiteralAH(q, tbinfo->attnames[j], fout);
   17559            3 :                     appendPQExpBufferChar(q, ',');
   17560            3 :                     appendStringLiteralAH(q, tbinfo->attmissingval[j], fout);
   17561            3 :                     appendPQExpBufferStr(q, ");\n\n");
   17562              :                 }
   17563              :             }
   17564              :         }
   17565              : 
   17566              :         /*
   17567              :          * To create binary-compatible heap files, we have to ensure the same
   17568              :          * physical column order, including dropped columns, as in the
   17569              :          * original.  Therefore, we create dropped columns above and drop them
   17570              :          * here, also updating their attlen/attalign values so that the
   17571              :          * dropped column can be skipped properly.  (We do not bother with
   17572              :          * restoring the original attbyval setting.)  Also, inheritance
   17573              :          * relationships are set up by doing ALTER TABLE INHERIT rather than
   17574              :          * using an INHERITS clause --- the latter would possibly mess up the
   17575              :          * column order.  That also means we have to take care about setting
   17576              :          * attislocal correctly, plus fix up any inherited CHECK constraints.
   17577              :          * Analogously, we set up typed tables using ALTER TABLE / OF here.
   17578              :          *
   17579              :          * We process foreign and partitioned tables here, even though they
   17580              :          * lack heap storage, because they can participate in inheritance
   17581              :          * relationships and we want this stuff to be consistent across the
   17582              :          * inheritance tree.  We can exclude indexes, toast tables, sequences
   17583              :          * and matviews, even though they have storage, because we don't
   17584              :          * support altering or dropping columns in them, nor can they be part
   17585              :          * of inheritance trees.
   17586              :          */
   17587         5902 :         if (dopt->binary_upgrade &&
   17588          822 :             (tbinfo->relkind == RELKIND_RELATION ||
   17589          111 :              tbinfo->relkind == RELKIND_FOREIGN_TABLE ||
   17590          110 :              tbinfo->relkind == RELKIND_PARTITIONED_TABLE))
   17591              :         {
   17592              :             bool        firstitem;
   17593              :             bool        firstitem_extra;
   17594              : 
   17595              :             /*
   17596              :              * Drop any dropped columns.  Merge the pg_attribute manipulations
   17597              :              * into a single SQL command, so that we don't cause repeated
   17598              :              * relcache flushes on the target table.  Otherwise we risk O(N^2)
   17599              :              * relcache bloat while dropping N columns.
   17600              :              */
   17601          805 :             resetPQExpBuffer(extra);
   17602          805 :             firstitem = true;
   17603         3937 :             for (j = 0; j < tbinfo->numatts; j++)
   17604              :             {
   17605         3132 :                 if (tbinfo->attisdropped[j])
   17606              :                 {
   17607           84 :                     if (firstitem)
   17608              :                     {
   17609           38 :                         appendPQExpBufferStr(q, "\n-- For binary upgrade, recreate dropped columns.\n"
   17610              :                                              "UPDATE pg_catalog.pg_attribute\n"
   17611              :                                              "SET attlen = v.dlen, "
   17612              :                                              "attalign = v.dalign, "
   17613              :                                              "attbyval = false\n"
   17614              :                                              "FROM (VALUES ");
   17615           38 :                         firstitem = false;
   17616              :                     }
   17617              :                     else
   17618           46 :                         appendPQExpBufferStr(q, ",\n             ");
   17619           84 :                     appendPQExpBufferChar(q, '(');
   17620           84 :                     appendStringLiteralAH(q, tbinfo->attnames[j], fout);
   17621           84 :                     appendPQExpBuffer(q, ", %d, '%c')",
   17622           84 :                                       tbinfo->attlen[j],
   17623           84 :                                       tbinfo->attalign[j]);
   17624              :                     /* The ALTER ... DROP COLUMN commands must come after */
   17625           84 :                     appendPQExpBuffer(extra, "ALTER %sTABLE ONLY %s ",
   17626              :                                       foreign, qualrelname);
   17627           84 :                     appendPQExpBuffer(extra, "DROP COLUMN %s;\n",
   17628           84 :                                       fmtId(tbinfo->attnames[j]));
   17629              :                 }
   17630              :             }
   17631          805 :             if (!firstitem)
   17632              :             {
   17633           38 :                 appendPQExpBufferStr(q, ") v(dname, dlen, dalign)\n"
   17634              :                                      "WHERE attrelid = ");
   17635           38 :                 appendStringLiteralAH(q, qualrelname, fout);
   17636           38 :                 appendPQExpBufferStr(q, "::pg_catalog.regclass\n"
   17637              :                                      "  AND attname = v.dname;\n");
   17638              :                 /* Now we can issue the actual DROP COLUMN commands */
   17639           38 :                 appendBinaryPQExpBuffer(q, extra->data, extra->len);
   17640              :             }
   17641              : 
   17642              :             /*
   17643              :              * Fix up inherited columns.  As above, do the pg_attribute
   17644              :              * manipulations in a single SQL command.
   17645              :              */
   17646          805 :             firstitem = true;
   17647         3937 :             for (j = 0; j < tbinfo->numatts; j++)
   17648              :             {
   17649         3132 :                 if (!tbinfo->attisdropped[j] &&
   17650         3048 :                     !tbinfo->attislocal[j])
   17651              :                 {
   17652          608 :                     if (firstitem)
   17653              :                     {
   17654          270 :                         appendPQExpBufferStr(q, "\n-- For binary upgrade, recreate inherited columns.\n");
   17655          270 :                         appendPQExpBufferStr(q, "UPDATE pg_catalog.pg_attribute\n"
   17656              :                                              "SET attislocal = false\n"
   17657              :                                              "WHERE attrelid = ");
   17658          270 :                         appendStringLiteralAH(q, qualrelname, fout);
   17659          270 :                         appendPQExpBufferStr(q, "::pg_catalog.regclass\n"
   17660              :                                              "  AND attname IN (");
   17661          270 :                         firstitem = false;
   17662              :                     }
   17663              :                     else
   17664          338 :                         appendPQExpBufferStr(q, ", ");
   17665          608 :                     appendStringLiteralAH(q, tbinfo->attnames[j], fout);
   17666              :                 }
   17667              :             }
   17668          805 :             if (!firstitem)
   17669          270 :                 appendPQExpBufferStr(q, ");\n");
   17670              : 
   17671              :             /*
   17672              :              * Fix up not-null constraints that come from inheritance.  As
   17673              :              * above, do the pg_constraint manipulations in a single SQL
   17674              :              * command.  (Actually, two in special cases, if we're doing an
   17675              :              * upgrade from < 18).
   17676              :              */
   17677          805 :             firstitem = true;
   17678          805 :             firstitem_extra = true;
   17679          805 :             resetPQExpBuffer(extra);
   17680         3937 :             for (j = 0; j < tbinfo->numatts; j++)
   17681              :             {
   17682              :                 /*
   17683              :                  * If a not-null constraint comes from inheritance, reset
   17684              :                  * conislocal.  The inhcount is fixed by ALTER TABLE INHERIT,
   17685              :                  * below.  Special hack: in versions < 18, columns with no
   17686              :                  * local definition need their constraint to be matched by
   17687              :                  * column number in conkeys instead of by constraint name,
   17688              :                  * because the latter is not available.  (We distinguish the
   17689              :                  * case because the constraint name is the empty string.)
   17690              :                  */
   17691         3132 :                 if (tbinfo->notnull_constrs[j] != NULL &&
   17692          297 :                     !tbinfo->notnull_islocal[j])
   17693              :                 {
   17694           86 :                     if (tbinfo->notnull_constrs[j][0] != '\0')
   17695              :                     {
   17696           73 :                         if (firstitem)
   17697              :                         {
   17698           63 :                             appendPQExpBufferStr(q, "UPDATE pg_catalog.pg_constraint\n"
   17699              :                                                  "SET conislocal = false\n"
   17700              :                                                  "WHERE contype = 'n' AND conrelid = ");
   17701           63 :                             appendStringLiteralAH(q, qualrelname, fout);
   17702           63 :                             appendPQExpBufferStr(q, "::pg_catalog.regclass AND\n"
   17703              :                                                  "conname IN (");
   17704           63 :                             firstitem = false;
   17705              :                         }
   17706              :                         else
   17707           10 :                             appendPQExpBufferStr(q, ", ");
   17708           73 :                         appendStringLiteralAH(q, tbinfo->notnull_constrs[j], fout);
   17709              :                     }
   17710              :                     else
   17711              :                     {
   17712           13 :                         if (firstitem_extra)
   17713              :                         {
   17714           13 :                             appendPQExpBufferStr(extra, "UPDATE pg_catalog.pg_constraint\n"
   17715              :                                                  "SET conislocal = false\n"
   17716              :                                                  "WHERE contype = 'n' AND conrelid = ");
   17717           13 :                             appendStringLiteralAH(extra, qualrelname, fout);
   17718           13 :                             appendPQExpBufferStr(extra, "::pg_catalog.regclass AND\n"
   17719              :                                                  "conkey IN (");
   17720           13 :                             firstitem_extra = false;
   17721              :                         }
   17722              :                         else
   17723            0 :                             appendPQExpBufferStr(extra, ", ");
   17724           13 :                         appendPQExpBuffer(extra, "'{%d}'", j + 1);
   17725              :                     }
   17726              :                 }
   17727              :             }
   17728          805 :             if (!firstitem)
   17729           63 :                 appendPQExpBufferStr(q, ");\n");
   17730          805 :             if (!firstitem_extra)
   17731           13 :                 appendPQExpBufferStr(extra, ");\n");
   17732              : 
   17733          805 :             if (extra->len > 0)
   17734           13 :                 appendBinaryPQExpBuffer(q, extra->data, extra->len);
   17735              : 
   17736              :             /*
   17737              :              * Add inherited CHECK constraints, if any.
   17738              :              *
   17739              :              * For partitions, they were already dumped, and conislocal
   17740              :              * doesn't need fixing.
   17741              :              *
   17742              :              * As above, issue only one direct manipulation of pg_constraint.
   17743              :              * Although it is tempting to merge the ALTER ADD CONSTRAINT
   17744              :              * commands into one as well, refrain for now due to concern about
   17745              :              * possible backend memory bloat if there are many such
   17746              :              * constraints.
   17747              :              */
   17748          805 :             resetPQExpBuffer(extra);
   17749          805 :             firstitem = true;
   17750          867 :             for (k = 0; k < tbinfo->ncheck; k++)
   17751              :             {
   17752           62 :                 ConstraintInfo *constr = &(tbinfo->checkexprs[k]);
   17753              : 
   17754           62 :                 if (constr->separate || constr->conislocal || tbinfo->ispartition)
   17755           60 :                     continue;
   17756              : 
   17757            2 :                 if (firstitem)
   17758            2 :                     appendPQExpBufferStr(q, "\n-- For binary upgrade, set up inherited constraints.\n");
   17759            2 :                 appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s ADD CONSTRAINT %s %s;\n",
   17760              :                                   foreign, qualrelname,
   17761            2 :                                   fmtId(constr->dobj.name),
   17762              :                                   constr->condef);
   17763              :                 /* Update pg_constraint after all the ALTER TABLEs */
   17764            2 :                 if (firstitem)
   17765              :                 {
   17766            2 :                     appendPQExpBufferStr(extra, "UPDATE pg_catalog.pg_constraint\n"
   17767              :                                          "SET conislocal = false\n"
   17768              :                                          "WHERE contype = 'c' AND conrelid = ");
   17769            2 :                     appendStringLiteralAH(extra, qualrelname, fout);
   17770            2 :                     appendPQExpBufferStr(extra, "::pg_catalog.regclass\n");
   17771            2 :                     appendPQExpBufferStr(extra, "  AND conname IN (");
   17772            2 :                     firstitem = false;
   17773              :                 }
   17774              :                 else
   17775            0 :                     appendPQExpBufferStr(extra, ", ");
   17776            2 :                 appendStringLiteralAH(extra, constr->dobj.name, fout);
   17777              :             }
   17778          805 :             if (!firstitem)
   17779              :             {
   17780            2 :                 appendPQExpBufferStr(extra, ");\n");
   17781            2 :                 appendBinaryPQExpBuffer(q, extra->data, extra->len);
   17782              :             }
   17783              : 
   17784          805 :             if (numParents > 0 && !tbinfo->ispartition)
   17785              :             {
   17786           65 :                 appendPQExpBufferStr(q, "\n-- For binary upgrade, set up inheritance this way.\n");
   17787          141 :                 for (k = 0; k < numParents; k++)
   17788              :                 {
   17789           76 :                     TableInfo  *parentRel = parents[k];
   17790              : 
   17791           76 :                     appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s INHERIT %s;\n", foreign,
   17792              :                                       qualrelname,
   17793           76 :                                       fmtQualifiedDumpable(parentRel));
   17794              :                 }
   17795              :             }
   17796              : 
   17797          805 :             if (OidIsValid(tbinfo->reloftype))
   17798              :             {
   17799            6 :                 appendPQExpBufferStr(q, "\n-- For binary upgrade, set up typed tables this way.\n");
   17800            6 :                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s OF %s;\n",
   17801              :                                   qualrelname,
   17802            6 :                                   getFormattedTypeName(fout, tbinfo->reloftype,
   17803              :                                                        zeroIsError));
   17804              :             }
   17805              :         }
   17806              : 
   17807              :         /*
   17808              :          * In binary_upgrade mode, arrange to restore the old relfrozenxid and
   17809              :          * relminmxid of all vacuumable relations.  (While vacuum.c processes
   17810              :          * TOAST tables semi-independently, here we see them only as children
   17811              :          * of other relations; so this "if" lacks RELKIND_TOASTVALUE, and the
   17812              :          * child toast table is handled below.)
   17813              :          */
   17814         5902 :         if (dopt->binary_upgrade &&
   17815          822 :             (tbinfo->relkind == RELKIND_RELATION ||
   17816          111 :              tbinfo->relkind == RELKIND_MATVIEW))
   17817              :         {
   17818          728 :             appendPQExpBufferStr(q, "\n-- For binary upgrade, set heap's relfrozenxid and relminmxid\n");
   17819          728 :             appendPQExpBuffer(q, "UPDATE pg_catalog.pg_class\n"
   17820              :                               "SET relfrozenxid = '%u', relminmxid = '%u'\n"
   17821              :                               "WHERE oid = ",
   17822          728 :                               tbinfo->frozenxid, tbinfo->minmxid);
   17823          728 :             appendStringLiteralAH(q, qualrelname, fout);
   17824          728 :             appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
   17825              : 
   17826          728 :             if (tbinfo->toast_oid)
   17827              :             {
   17828              :                 /*
   17829              :                  * The toast table will have the same OID at restore, so we
   17830              :                  * can safely target it by OID.
   17831              :                  */
   17832          277 :                 appendPQExpBufferStr(q, "\n-- For binary upgrade, set toast's relfrozenxid and relminmxid\n");
   17833          277 :                 appendPQExpBuffer(q, "UPDATE pg_catalog.pg_class\n"
   17834              :                                   "SET relfrozenxid = '%u', relminmxid = '%u'\n"
   17835              :                                   "WHERE oid = '%u';\n",
   17836          277 :                                   tbinfo->toast_frozenxid,
   17837          277 :                                   tbinfo->toast_minmxid, tbinfo->toast_oid);
   17838              :             }
   17839              :         }
   17840              : 
   17841              :         /*
   17842              :          * In binary_upgrade mode, restore matviews' populated status by
   17843              :          * poking pg_class directly.  This is pretty ugly, but we can't use
   17844              :          * REFRESH MATERIALIZED VIEW since it's possible that some underlying
   17845              :          * matview is not populated even though this matview is; in any case,
   17846              :          * we want to transfer the matview's heap storage, not run REFRESH.
   17847              :          */
   17848         5902 :         if (dopt->binary_upgrade && tbinfo->relkind == RELKIND_MATVIEW &&
   17849           17 :             tbinfo->relispopulated)
   17850              :         {
   17851           15 :             appendPQExpBufferStr(q, "\n-- For binary upgrade, mark materialized view as populated\n");
   17852           15 :             appendPQExpBufferStr(q, "UPDATE pg_catalog.pg_class\n"
   17853              :                                  "SET relispopulated = 't'\n"
   17854              :                                  "WHERE oid = ");
   17855           15 :             appendStringLiteralAH(q, qualrelname, fout);
   17856           15 :             appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
   17857              :         }
   17858              : 
   17859              :         /*
   17860              :          * Dump additional per-column properties that we can't handle in the
   17861              :          * main CREATE TABLE command.
   17862              :          */
   17863        26516 :         for (j = 0; j < tbinfo->numatts; j++)
   17864              :         {
   17865              :             /* None of this applies to dropped columns */
   17866        20614 :             if (tbinfo->attisdropped[j])
   17867          447 :                 continue;
   17868              : 
   17869              :             /*
   17870              :              * Dump per-column statistics information. We only issue an ALTER
   17871              :              * TABLE statement if the attstattarget entry for this column is
   17872              :              * not the default value.
   17873              :              */
   17874        20167 :             if (tbinfo->attstattarget[j] >= 0)
   17875           32 :                 appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s ALTER COLUMN %s SET STATISTICS %d;\n",
   17876              :                                   foreign, qualrelname,
   17877           32 :                                   fmtId(tbinfo->attnames[j]),
   17878           32 :                                   tbinfo->attstattarget[j]);
   17879              : 
   17880              :             /*
   17881              :              * Dump per-column storage information.  The statement is only
   17882              :              * dumped if the storage has been changed from the type's default.
   17883              :              */
   17884        20167 :             if (tbinfo->attstorage[j] != tbinfo->typstorage[j])
   17885              :             {
   17886           79 :                 switch (tbinfo->attstorage[j])
   17887              :                 {
   17888           10 :                     case TYPSTORAGE_PLAIN:
   17889           10 :                         storage = "PLAIN";
   17890           10 :                         break;
   17891           37 :                     case TYPSTORAGE_EXTERNAL:
   17892           37 :                         storage = "EXTERNAL";
   17893           37 :                         break;
   17894            0 :                     case TYPSTORAGE_EXTENDED:
   17895            0 :                         storage = "EXTENDED";
   17896            0 :                         break;
   17897           32 :                     case TYPSTORAGE_MAIN:
   17898           32 :                         storage = "MAIN";
   17899           32 :                         break;
   17900            0 :                     default:
   17901            0 :                         storage = NULL;
   17902              :                 }
   17903              : 
   17904              :                 /*
   17905              :                  * Only dump the statement if it's a storage type we recognize
   17906              :                  */
   17907           79 :                 if (storage != NULL)
   17908           79 :                     appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s ALTER COLUMN %s SET STORAGE %s;\n",
   17909              :                                       foreign, qualrelname,
   17910           79 :                                       fmtId(tbinfo->attnames[j]),
   17911              :                                       storage);
   17912              :             }
   17913              : 
   17914              :             /*
   17915              :              * Dump per-column compression, if it's been set.
   17916              :              */
   17917        20167 :             if (!dopt->no_toast_compression)
   17918              :             {
   17919              :                 const char *cmname;
   17920              : 
   17921        20067 :                 switch (tbinfo->attcompression[j])
   17922              :                 {
   17923           71 :                     case 'p':
   17924           71 :                         cmname = "pglz";
   17925           71 :                         break;
   17926           39 :                     case 'l':
   17927           39 :                         cmname = "lz4";
   17928           39 :                         break;
   17929        19957 :                     default:
   17930        19957 :                         cmname = NULL;
   17931        19957 :                         break;
   17932              :                 }
   17933              : 
   17934        20067 :                 if (cmname != NULL)
   17935          110 :                     appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s ALTER COLUMN %s SET COMPRESSION %s;\n",
   17936              :                                       foreign, qualrelname,
   17937          110 :                                       fmtId(tbinfo->attnames[j]),
   17938              :                                       cmname);
   17939              :             }
   17940              : 
   17941              :             /*
   17942              :              * Dump per-column attributes.
   17943              :              */
   17944        20167 :             if (tbinfo->attoptions[j][0] != '\0')
   17945           32 :                 appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s ALTER COLUMN %s SET (%s);\n",
   17946              :                                   foreign, qualrelname,
   17947           32 :                                   fmtId(tbinfo->attnames[j]),
   17948           32 :                                   tbinfo->attoptions[j]);
   17949              : 
   17950              :             /*
   17951              :              * Dump per-column fdw options.
   17952              :              */
   17953        20167 :             if (tbinfo->relkind == RELKIND_FOREIGN_TABLE &&
   17954           34 :                 tbinfo->attfdwoptions[j][0] != '\0')
   17955           32 :                 appendPQExpBuffer(q,
   17956              :                                   "ALTER FOREIGN TABLE ONLY %s ALTER COLUMN %s OPTIONS (\n"
   17957              :                                   "    %s\n"
   17958              :                                   ");\n",
   17959              :                                   qualrelname,
   17960           32 :                                   fmtId(tbinfo->attnames[j]),
   17961           32 :                                   tbinfo->attfdwoptions[j]);
   17962              :         }                       /* end loop over columns */
   17963              : 
   17964         5902 :         free(partkeydef);
   17965         5902 :         free(ftoptions);
   17966         5902 :         free(srvname);
   17967              :     }
   17968              : 
   17969              :     /*
   17970              :      * dump properties we only have ALTER TABLE syntax for
   17971              :      */
   17972         6435 :     if ((tbinfo->relkind == RELKIND_RELATION ||
   17973         1478 :          tbinfo->relkind == RELKIND_PARTITIONED_TABLE ||
   17974          902 :          tbinfo->relkind == RELKIND_MATVIEW) &&
   17975         5868 :         tbinfo->relreplident != REPLICA_IDENTITY_DEFAULT)
   17976              :     {
   17977          192 :         if (tbinfo->relreplident == REPLICA_IDENTITY_INDEX)
   17978              :         {
   17979              :             /* nothing to do, will be set when the index is dumped */
   17980              :         }
   17981          192 :         else if (tbinfo->relreplident == REPLICA_IDENTITY_NOTHING)
   17982              :         {
   17983          192 :             appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY NOTHING;\n",
   17984              :                               qualrelname);
   17985              :         }
   17986            0 :         else if (tbinfo->relreplident == REPLICA_IDENTITY_FULL)
   17987              :         {
   17988            0 :             appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY FULL;\n",
   17989              :                               qualrelname);
   17990              :         }
   17991              :     }
   17992              : 
   17993         6435 :     if (tbinfo->forcerowsec)
   17994            5 :         appendPQExpBuffer(q, "\nALTER TABLE ONLY %s FORCE ROW LEVEL SECURITY;\n",
   17995              :                           qualrelname);
   17996              : 
   17997         6435 :     if (dopt->binary_upgrade)
   17998          874 :         binary_upgrade_extension_member(q, &tbinfo->dobj,
   17999              :                                         reltypename, qrelname,
   18000          874 :                                         tbinfo->dobj.namespace->dobj.name);
   18001              : 
   18002         6435 :     if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   18003              :     {
   18004         6435 :         char       *tablespace = NULL;
   18005         6435 :         char       *tableam = NULL;
   18006              : 
   18007              :         /*
   18008              :          * _selectTablespace() relies on tablespace-enabled objects in the
   18009              :          * default tablespace to have a tablespace of "" (empty string) versus
   18010              :          * non-tablespace-enabled objects to have a tablespace of NULL.
   18011              :          * getTables() sets tbinfo->reltablespace to "" for the default
   18012              :          * tablespace (not NULL).
   18013              :          */
   18014         6435 :         if (RELKIND_HAS_TABLESPACE(tbinfo->relkind))
   18015         5868 :             tablespace = tbinfo->reltablespace;
   18016              : 
   18017         6435 :         if (RELKIND_HAS_TABLE_AM(tbinfo->relkind) ||
   18018         1143 :             tbinfo->relkind == RELKIND_PARTITIONED_TABLE)
   18019         5868 :             tableam = tbinfo->amname;
   18020              : 
   18021         6435 :         ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
   18022         6435 :                      ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
   18023              :                                   .namespace = tbinfo->dobj.namespace->dobj.name,
   18024              :                                   .tablespace = tablespace,
   18025              :                                   .tableam = tableam,
   18026              :                                   .relkind = tbinfo->relkind,
   18027              :                                   .owner = tbinfo->rolname,
   18028              :                                   .description = reltypename,
   18029              :                                   .section = tbinfo->postponed_def ?
   18030              :                                   SECTION_POST_DATA : SECTION_PRE_DATA,
   18031              :                                   .createStmt = q->data,
   18032              :                                   .dropStmt = delq->data));
   18033              :     }
   18034              : 
   18035              :     /* Dump Table Comments */
   18036         6435 :     if (tbinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   18037           74 :         dumpTableComment(fout, tbinfo, reltypename);
   18038              : 
   18039              :     /* Dump Table Security Labels */
   18040         6435 :     if (tbinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
   18041            0 :         dumpTableSecLabel(fout, tbinfo, reltypename);
   18042              : 
   18043              :     /*
   18044              :      * Dump comments for not-null constraints that aren't to be dumped
   18045              :      * separately (those are processed by collectComments/dumpComment).
   18046              :      */
   18047         6435 :     if (!fout->dopt->no_comments && dopt->dumpSchema &&
   18048         6435 :         fout->remoteVersion >= 180000)
   18049              :     {
   18050         6435 :         PQExpBuffer comment = NULL;
   18051         6435 :         PQExpBuffer tag = NULL;
   18052              : 
   18053        30487 :         for (j = 0; j < tbinfo->numatts; j++)
   18054              :         {
   18055        24052 :             if (tbinfo->notnull_constrs[j] != NULL &&
   18056         2472 :                 tbinfo->notnull_comment[j] != NULL)
   18057              :             {
   18058           42 :                 if (comment == NULL)
   18059              :                 {
   18060           42 :                     comment = createPQExpBuffer();
   18061           42 :                     tag = createPQExpBuffer();
   18062              :                 }
   18063              :                 else
   18064              :                 {
   18065            0 :                     resetPQExpBuffer(comment);
   18066            0 :                     resetPQExpBuffer(tag);
   18067              :                 }
   18068              : 
   18069           42 :                 appendPQExpBuffer(comment, "COMMENT ON CONSTRAINT %s ON %s IS ",
   18070           42 :                                   fmtId(tbinfo->notnull_constrs[j]), qualrelname);
   18071           42 :                 appendStringLiteralAH(comment, tbinfo->notnull_comment[j], fout);
   18072           42 :                 appendPQExpBufferStr(comment, ";\n");
   18073              : 
   18074           42 :                 appendPQExpBuffer(tag, "CONSTRAINT %s ON %s",
   18075           42 :                                   fmtId(tbinfo->notnull_constrs[j]), qrelname);
   18076              : 
   18077           42 :                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
   18078           42 :                              ARCHIVE_OPTS(.tag = tag->data,
   18079              :                                           .namespace = tbinfo->dobj.namespace->dobj.name,
   18080              :                                           .owner = tbinfo->rolname,
   18081              :                                           .description = "COMMENT",
   18082              :                                           .section = SECTION_NONE,
   18083              :                                           .createStmt = comment->data,
   18084              :                                           .deps = &(tbinfo->dobj.dumpId),
   18085              :                                           .nDeps = 1));
   18086              :             }
   18087              :         }
   18088              : 
   18089         6435 :         destroyPQExpBuffer(comment);
   18090         6435 :         destroyPQExpBuffer(tag);
   18091              :     }
   18092              : 
   18093              :     /* Dump comments on inlined table constraints */
   18094         7008 :     for (j = 0; j < tbinfo->ncheck; j++)
   18095              :     {
   18096          573 :         ConstraintInfo *constr = &(tbinfo->checkexprs[j]);
   18097              : 
   18098          573 :         if (constr->separate || !constr->conislocal)
   18099          244 :             continue;
   18100              : 
   18101          329 :         if (constr->dobj.dump & DUMP_COMPONENT_COMMENT)
   18102           37 :             dumpTableConstraintComment(fout, constr);
   18103              :     }
   18104              : 
   18105         6435 :     destroyPQExpBuffer(q);
   18106         6435 :     destroyPQExpBuffer(delq);
   18107         6435 :     destroyPQExpBuffer(extra);
   18108         6435 :     free(qrelname);
   18109         6435 :     free(qualrelname);
   18110         6435 : }
   18111              : 
   18112              : /*
   18113              :  * dumpTableAttach
   18114              :  *    write to fout the commands to attach a child partition
   18115              :  *
   18116              :  * Child partitions are always made by creating them separately
   18117              :  * and then using ATTACH PARTITION, rather than using
   18118              :  * CREATE TABLE ... PARTITION OF.  This is important for preserving
   18119              :  * any possible discrepancy in column layout, to allow assigning the
   18120              :  * correct tablespace if different, and so that it's possible to restore
   18121              :  * a partition without restoring its parent.  (You'll get an error from
   18122              :  * the ATTACH PARTITION command, but that can be ignored, or skipped
   18123              :  * using "pg_restore -L" if you prefer.)  The last point motivates
   18124              :  * treating ATTACH PARTITION as a completely separate ArchiveEntry
   18125              :  * rather than emitting it within the child partition's ArchiveEntry.
   18126              :  */
   18127              : static void
   18128         1391 : dumpTableAttach(Archive *fout, const TableAttachInfo *attachinfo)
   18129              : {
   18130         1391 :     DumpOptions *dopt = fout->dopt;
   18131              :     PQExpBuffer q;
   18132              :     PGresult   *res;
   18133              :     char       *partbound;
   18134              : 
   18135              :     /* Do nothing if not dumping schema */
   18136         1391 :     if (!dopt->dumpSchema)
   18137           54 :         return;
   18138              : 
   18139         1337 :     q = createPQExpBuffer();
   18140              : 
   18141         1337 :     if (!fout->is_prepared[PREPQUERY_DUMPTABLEATTACH])
   18142              :     {
   18143              :         /* Set up query for partbound details */
   18144           43 :         appendPQExpBufferStr(q,
   18145              :                              "PREPARE dumpTableAttach(pg_catalog.oid) AS\n");
   18146              : 
   18147           43 :         appendPQExpBufferStr(q,
   18148              :                              "SELECT pg_get_expr(c.relpartbound, c.oid) "
   18149              :                              "FROM pg_class c "
   18150              :                              "WHERE c.oid = $1");
   18151              : 
   18152           43 :         ExecuteSqlStatement(fout, q->data);
   18153              : 
   18154           43 :         fout->is_prepared[PREPQUERY_DUMPTABLEATTACH] = true;
   18155              :     }
   18156              : 
   18157         1337 :     printfPQExpBuffer(q,
   18158              :                       "EXECUTE dumpTableAttach('%u')",
   18159         1337 :                       attachinfo->partitionTbl->dobj.catId.oid);
   18160              : 
   18161         1337 :     res = ExecuteSqlQueryForSingleRow(fout, q->data);
   18162         1337 :     partbound = PQgetvalue(res, 0, 0);
   18163              : 
   18164              :     /* Perform ALTER TABLE on the parent */
   18165         1337 :     printfPQExpBuffer(q,
   18166              :                       "ALTER TABLE ONLY %s ",
   18167         1337 :                       fmtQualifiedDumpable(attachinfo->parentTbl));
   18168         1337 :     appendPQExpBuffer(q,
   18169              :                       "ATTACH PARTITION %s %s;\n",
   18170         1337 :                       fmtQualifiedDumpable(attachinfo->partitionTbl),
   18171              :                       partbound);
   18172              : 
   18173              :     /*
   18174              :      * There is no point in creating a drop query as the drop is done by table
   18175              :      * drop.  (If you think to change this, see also _printTocEntry().)
   18176              :      * Although this object doesn't really have ownership as such, set the
   18177              :      * owner field anyway to ensure that the command is run by the correct
   18178              :      * role at restore time.
   18179              :      */
   18180         1337 :     ArchiveEntry(fout, attachinfo->dobj.catId, attachinfo->dobj.dumpId,
   18181         1337 :                  ARCHIVE_OPTS(.tag = attachinfo->dobj.name,
   18182              :                               .namespace = attachinfo->dobj.namespace->dobj.name,
   18183              :                               .owner = attachinfo->partitionTbl->rolname,
   18184              :                               .description = "TABLE ATTACH",
   18185              :                               .section = SECTION_PRE_DATA,
   18186              :                               .createStmt = q->data));
   18187              : 
   18188         1337 :     PQclear(res);
   18189         1337 :     destroyPQExpBuffer(q);
   18190              : }
   18191              : 
   18192              : /*
   18193              :  * dumpAttrDef --- dump an attribute's default-value declaration
   18194              :  */
   18195              : static void
   18196         1037 : dumpAttrDef(Archive *fout, const AttrDefInfo *adinfo)
   18197              : {
   18198         1037 :     DumpOptions *dopt = fout->dopt;
   18199         1037 :     TableInfo  *tbinfo = adinfo->adtable;
   18200         1037 :     int         adnum = adinfo->adnum;
   18201              :     PQExpBuffer q;
   18202              :     PQExpBuffer delq;
   18203              :     char       *qualrelname;
   18204              :     char       *tag;
   18205              :     char       *foreign;
   18206              : 
   18207              :     /* Do nothing if not dumping schema */
   18208         1037 :     if (!dopt->dumpSchema)
   18209            0 :         return;
   18210              : 
   18211              :     /* Skip if not "separate"; it was dumped in the table's definition */
   18212         1037 :     if (!adinfo->separate)
   18213          871 :         return;
   18214              : 
   18215          166 :     q = createPQExpBuffer();
   18216          166 :     delq = createPQExpBuffer();
   18217              : 
   18218          166 :     qualrelname = pg_strdup(fmtQualifiedDumpable(tbinfo));
   18219              : 
   18220          166 :     foreign = tbinfo->relkind == RELKIND_FOREIGN_TABLE ? "FOREIGN " : "";
   18221              : 
   18222          166 :     appendPQExpBuffer(q,
   18223              :                       "ALTER %sTABLE ONLY %s ALTER COLUMN %s SET DEFAULT %s;\n",
   18224          166 :                       foreign, qualrelname, fmtId(tbinfo->attnames[adnum - 1]),
   18225          166 :                       adinfo->adef_expr);
   18226              : 
   18227          166 :     appendPQExpBuffer(delq, "ALTER %sTABLE %s ALTER COLUMN %s DROP DEFAULT;\n",
   18228              :                       foreign, qualrelname,
   18229          166 :                       fmtId(tbinfo->attnames[adnum - 1]));
   18230              : 
   18231          166 :     tag = psprintf("%s %s", tbinfo->dobj.name, tbinfo->attnames[adnum - 1]);
   18232              : 
   18233          166 :     if (adinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   18234          166 :         ArchiveEntry(fout, adinfo->dobj.catId, adinfo->dobj.dumpId,
   18235          166 :                      ARCHIVE_OPTS(.tag = tag,
   18236              :                                   .namespace = tbinfo->dobj.namespace->dobj.name,
   18237              :                                   .owner = tbinfo->rolname,
   18238              :                                   .description = "DEFAULT",
   18239              :                                   .section = SECTION_PRE_DATA,
   18240              :                                   .createStmt = q->data,
   18241              :                                   .dropStmt = delq->data));
   18242              : 
   18243          166 :     free(tag);
   18244          166 :     destroyPQExpBuffer(q);
   18245          166 :     destroyPQExpBuffer(delq);
   18246          166 :     free(qualrelname);
   18247              : }
   18248              : 
   18249              : /*
   18250              :  * getAttrName: extract the correct name for an attribute
   18251              :  *
   18252              :  * The array tblInfo->attnames[] only provides names of user attributes;
   18253              :  * if a system attribute number is supplied, we have to fake it.
   18254              :  * We also do a little bit of bounds checking for safety's sake.
   18255              :  */
   18256              : static const char *
   18257         2055 : getAttrName(int attrnum, const TableInfo *tblInfo)
   18258              : {
   18259         2055 :     if (attrnum > 0 && attrnum <= tblInfo->numatts)
   18260         2055 :         return tblInfo->attnames[attrnum - 1];
   18261            0 :     switch (attrnum)
   18262              :     {
   18263            0 :         case SelfItemPointerAttributeNumber:
   18264            0 :             return "ctid";
   18265            0 :         case MinTransactionIdAttributeNumber:
   18266            0 :             return "xmin";
   18267            0 :         case MinCommandIdAttributeNumber:
   18268            0 :             return "cmin";
   18269            0 :         case MaxTransactionIdAttributeNumber:
   18270            0 :             return "xmax";
   18271            0 :         case MaxCommandIdAttributeNumber:
   18272            0 :             return "cmax";
   18273            0 :         case TableOidAttributeNumber:
   18274            0 :             return "tableoid";
   18275              :     }
   18276            0 :     pg_fatal("invalid column number %d for table \"%s\"",
   18277              :              attrnum, tblInfo->dobj.name);
   18278              :     return NULL;                /* keep compiler quiet */
   18279              : }
   18280              : 
   18281              : /*
   18282              :  * dumpIndex
   18283              :  *    write out to fout a user-defined index
   18284              :  */
   18285              : static void
   18286         2600 : dumpIndex(Archive *fout, const IndxInfo *indxinfo)
   18287              : {
   18288         2600 :     DumpOptions *dopt = fout->dopt;
   18289         2600 :     TableInfo  *tbinfo = indxinfo->indextable;
   18290         2600 :     bool        is_constraint = (indxinfo->indexconstraint != 0);
   18291              :     PQExpBuffer q;
   18292              :     PQExpBuffer delq;
   18293              :     char       *qindxname;
   18294              :     char       *qqindxname;
   18295              : 
   18296              :     /* Do nothing if not dumping schema */
   18297         2600 :     if (!dopt->dumpSchema)
   18298          117 :         return;
   18299              : 
   18300         2483 :     q = createPQExpBuffer();
   18301         2483 :     delq = createPQExpBuffer();
   18302              : 
   18303         2483 :     qindxname = pg_strdup(fmtId(indxinfo->dobj.name));
   18304         2483 :     qqindxname = pg_strdup(fmtQualifiedDumpable(indxinfo));
   18305              : 
   18306              :     /*
   18307              :      * If there's an associated constraint, don't dump the index per se, but
   18308              :      * do dump any comment for it.  (This is safe because dependency ordering
   18309              :      * will have ensured the constraint is emitted first.)  Note that the
   18310              :      * emitted comment has to be shown as depending on the constraint, not the
   18311              :      * index, in such cases.
   18312              :      */
   18313         2483 :     if (!is_constraint)
   18314              :     {
   18315         1045 :         char       *indstatcols = indxinfo->indstatcols;
   18316         1045 :         char       *indstatvals = indxinfo->indstatvals;
   18317         1045 :         char      **indstatcolsarray = NULL;
   18318         1045 :         char      **indstatvalsarray = NULL;
   18319         1045 :         int         nstatcols = 0;
   18320         1045 :         int         nstatvals = 0;
   18321              : 
   18322         1045 :         if (dopt->binary_upgrade)
   18323          158 :             binary_upgrade_set_pg_class_oids(fout, q,
   18324          158 :                                              indxinfo->dobj.catId.oid);
   18325              : 
   18326              :         /* Plain secondary index */
   18327         1045 :         appendPQExpBuffer(q, "%s;\n", indxinfo->indexdef);
   18328              : 
   18329              :         /*
   18330              :          * Append ALTER TABLE commands as needed to set properties that we
   18331              :          * only have ALTER TABLE syntax for.  Keep this in sync with the
   18332              :          * similar code in dumpConstraint!
   18333              :          */
   18334              : 
   18335              :         /* If the index is clustered, we need to record that. */
   18336         1045 :         if (indxinfo->indisclustered)
   18337              :         {
   18338            0 :             appendPQExpBuffer(q, "\nALTER TABLE %s CLUSTER",
   18339            0 :                               fmtQualifiedDumpable(tbinfo));
   18340              :             /* index name is not qualified in this syntax */
   18341            0 :             appendPQExpBuffer(q, " ON %s;\n",
   18342              :                               qindxname);
   18343              :         }
   18344              : 
   18345              :         /*
   18346              :          * If the index has any statistics on some of its columns, generate
   18347              :          * the associated ALTER INDEX queries.
   18348              :          */
   18349         1045 :         if (strlen(indstatcols) != 0 || strlen(indstatvals) != 0)
   18350              :         {
   18351              :             int         j;
   18352              : 
   18353           32 :             if (!parsePGArray(indstatcols, &indstatcolsarray, &nstatcols))
   18354            0 :                 pg_fatal("could not parse index statistic columns");
   18355           32 :             if (!parsePGArray(indstatvals, &indstatvalsarray, &nstatvals))
   18356            0 :                 pg_fatal("could not parse index statistic values");
   18357           32 :             if (nstatcols != nstatvals)
   18358            0 :                 pg_fatal("mismatched number of columns and values for index statistics");
   18359              : 
   18360           96 :             for (j = 0; j < nstatcols; j++)
   18361              :             {
   18362           64 :                 appendPQExpBuffer(q, "ALTER INDEX %s ", qqindxname);
   18363              : 
   18364              :                 /*
   18365              :                  * Note that this is a column number, so no quotes should be
   18366              :                  * used.
   18367              :                  */
   18368           64 :                 appendPQExpBuffer(q, "ALTER COLUMN %s ",
   18369           64 :                                   indstatcolsarray[j]);
   18370           64 :                 appendPQExpBuffer(q, "SET STATISTICS %s;\n",
   18371           64 :                                   indstatvalsarray[j]);
   18372              :             }
   18373              :         }
   18374              : 
   18375              :         /* Indexes can depend on extensions */
   18376         1045 :         append_depends_on_extension(fout, q, &indxinfo->dobj,
   18377              :                                     "pg_catalog.pg_class",
   18378              :                                     "INDEX", qqindxname);
   18379              : 
   18380              :         /* If the index defines identity, we need to record that. */
   18381         1045 :         if (indxinfo->indisreplident)
   18382              :         {
   18383            0 :             appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY USING",
   18384            0 :                               fmtQualifiedDumpable(tbinfo));
   18385              :             /* index name is not qualified in this syntax */
   18386            0 :             appendPQExpBuffer(q, " INDEX %s;\n",
   18387              :                               qindxname);
   18388              :         }
   18389              : 
   18390              :         /*
   18391              :          * If this index is a member of a partitioned index, the backend will
   18392              :          * not allow us to drop it separately, so don't try.  It will go away
   18393              :          * automatically when we drop either the index's table or the
   18394              :          * partitioned index.  (If, in a selective restore with --clean, we
   18395              :          * drop neither of those, then this index will not be dropped either.
   18396              :          * But that's fine, and even if you think it's not, the backend won't
   18397              :          * let us do differently.)
   18398              :          */
   18399         1045 :         if (indxinfo->parentidx == 0)
   18400          863 :             appendPQExpBuffer(delq, "DROP INDEX %s;\n", qqindxname);
   18401              : 
   18402         1045 :         if (indxinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   18403         1045 :             ArchiveEntry(fout, indxinfo->dobj.catId, indxinfo->dobj.dumpId,
   18404         1045 :                          ARCHIVE_OPTS(.tag = indxinfo->dobj.name,
   18405              :                                       .namespace = tbinfo->dobj.namespace->dobj.name,
   18406              :                                       .tablespace = indxinfo->tablespace,
   18407              :                                       .owner = tbinfo->rolname,
   18408              :                                       .description = "INDEX",
   18409              :                                       .section = SECTION_POST_DATA,
   18410              :                                       .createStmt = q->data,
   18411              :                                       .dropStmt = delq->data));
   18412              : 
   18413         1045 :         free(indstatcolsarray);
   18414         1045 :         free(indstatvalsarray);
   18415              :     }
   18416              : 
   18417              :     /* Dump Index Comments */
   18418         2483 :     if (indxinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   18419           15 :         dumpComment(fout, "INDEX", qindxname,
   18420           15 :                     tbinfo->dobj.namespace->dobj.name,
   18421              :                     tbinfo->rolname,
   18422              :                     indxinfo->dobj.catId, 0,
   18423              :                     is_constraint ? indxinfo->indexconstraint :
   18424              :                     indxinfo->dobj.dumpId);
   18425              : 
   18426         2483 :     destroyPQExpBuffer(q);
   18427         2483 :     destroyPQExpBuffer(delq);
   18428         2483 :     free(qindxname);
   18429         2483 :     free(qqindxname);
   18430              : }
   18431              : 
   18432              : /*
   18433              :  * dumpIndexAttach
   18434              :  *    write out to fout a partitioned-index attachment clause
   18435              :  */
   18436              : static void
   18437          574 : dumpIndexAttach(Archive *fout, const IndexAttachInfo *attachinfo)
   18438              : {
   18439              :     /* Do nothing if not dumping schema */
   18440          574 :     if (!fout->dopt->dumpSchema)
   18441           48 :         return;
   18442              : 
   18443          526 :     if (attachinfo->partitionIdx->dobj.dump & DUMP_COMPONENT_DEFINITION)
   18444              :     {
   18445          526 :         PQExpBuffer q = createPQExpBuffer();
   18446              : 
   18447          526 :         appendPQExpBuffer(q, "ALTER INDEX %s ",
   18448          526 :                           fmtQualifiedDumpable(attachinfo->parentIdx));
   18449          526 :         appendPQExpBuffer(q, "ATTACH PARTITION %s;\n",
   18450          526 :                           fmtQualifiedDumpable(attachinfo->partitionIdx));
   18451              : 
   18452              :         /*
   18453              :          * There is no need for a dropStmt since the drop is done implicitly
   18454              :          * when we drop either the index's table or the partitioned index.
   18455              :          * Moreover, since there's no ALTER INDEX DETACH PARTITION command,
   18456              :          * there's no way to do it anyway.  (If you think to change this,
   18457              :          * consider also what to do with --if-exists.)
   18458              :          *
   18459              :          * Although this object doesn't really have ownership as such, set the
   18460              :          * owner field anyway to ensure that the command is run by the correct
   18461              :          * role at restore time.
   18462              :          */
   18463          526 :         ArchiveEntry(fout, attachinfo->dobj.catId, attachinfo->dobj.dumpId,
   18464          526 :                      ARCHIVE_OPTS(.tag = attachinfo->dobj.name,
   18465              :                                   .namespace = attachinfo->dobj.namespace->dobj.name,
   18466              :                                   .owner = attachinfo->parentIdx->indextable->rolname,
   18467              :                                   .description = "INDEX ATTACH",
   18468              :                                   .section = SECTION_POST_DATA,
   18469              :                                   .createStmt = q->data));
   18470              : 
   18471          526 :         destroyPQExpBuffer(q);
   18472              :     }
   18473              : }
   18474              : 
   18475              : /*
   18476              :  * dumpStatisticsExt
   18477              :  *    write out to fout an extended statistics object
   18478              :  */
   18479              : static void
   18480          171 : dumpStatisticsExt(Archive *fout, const StatsExtInfo *statsextinfo)
   18481              : {
   18482          171 :     DumpOptions *dopt = fout->dopt;
   18483              :     PQExpBuffer q;
   18484              :     PQExpBuffer delq;
   18485              :     PQExpBuffer query;
   18486              :     char       *qstatsextname;
   18487              :     PGresult   *res;
   18488              :     char       *stxdef;
   18489              : 
   18490              :     /* Do nothing if not dumping schema */
   18491          171 :     if (!dopt->dumpSchema)
   18492           24 :         return;
   18493              : 
   18494          147 :     q = createPQExpBuffer();
   18495          147 :     delq = createPQExpBuffer();
   18496          147 :     query = createPQExpBuffer();
   18497              : 
   18498          147 :     qstatsextname = pg_strdup(fmtId(statsextinfo->dobj.name));
   18499              : 
   18500          147 :     appendPQExpBuffer(query, "SELECT "
   18501              :                       "pg_catalog.pg_get_statisticsobjdef('%u'::pg_catalog.oid)",
   18502          147 :                       statsextinfo->dobj.catId.oid);
   18503              : 
   18504          147 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   18505              : 
   18506          147 :     stxdef = PQgetvalue(res, 0, 0);
   18507              : 
   18508              :     /* Result of pg_get_statisticsobjdef is complete except for semicolon */
   18509          147 :     appendPQExpBuffer(q, "%s;\n", stxdef);
   18510              : 
   18511              :     /*
   18512              :      * We only issue an ALTER STATISTICS statement if the stxstattarget entry
   18513              :      * for this statistics object is not the default value.
   18514              :      */
   18515          147 :     if (statsextinfo->stattarget >= 0)
   18516              :     {
   18517           32 :         appendPQExpBuffer(q, "ALTER STATISTICS %s ",
   18518           32 :                           fmtQualifiedDumpable(statsextinfo));
   18519           32 :         appendPQExpBuffer(q, "SET STATISTICS %d;\n",
   18520           32 :                           statsextinfo->stattarget);
   18521              :     }
   18522              : 
   18523          147 :     appendPQExpBuffer(delq, "DROP STATISTICS %s;\n",
   18524          147 :                       fmtQualifiedDumpable(statsextinfo));
   18525              : 
   18526          147 :     if (statsextinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   18527          147 :         ArchiveEntry(fout, statsextinfo->dobj.catId,
   18528          147 :                      statsextinfo->dobj.dumpId,
   18529          147 :                      ARCHIVE_OPTS(.tag = statsextinfo->dobj.name,
   18530              :                                   .namespace = statsextinfo->dobj.namespace->dobj.name,
   18531              :                                   .owner = statsextinfo->rolname,
   18532              :                                   .description = "STATISTICS",
   18533              :                                   .section = SECTION_POST_DATA,
   18534              :                                   .createStmt = q->data,
   18535              :                                   .dropStmt = delq->data));
   18536              : 
   18537              :     /* Dump Statistics Comments */
   18538          147 :     if (statsextinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   18539            0 :         dumpComment(fout, "STATISTICS", qstatsextname,
   18540            0 :                     statsextinfo->dobj.namespace->dobj.name,
   18541            0 :                     statsextinfo->rolname,
   18542              :                     statsextinfo->dobj.catId, 0,
   18543            0 :                     statsextinfo->dobj.dumpId);
   18544              : 
   18545          147 :     PQclear(res);
   18546          147 :     destroyPQExpBuffer(q);
   18547          147 :     destroyPQExpBuffer(delq);
   18548          147 :     destroyPQExpBuffer(query);
   18549          147 :     free(qstatsextname);
   18550              : }
   18551              : 
   18552              : /*
   18553              :  * dumpStatisticsExtStats
   18554              :  *    write out to fout the stats for an extended statistics object
   18555              :  */
   18556              : static void
   18557          171 : dumpStatisticsExtStats(Archive *fout, const StatsExtInfo *statsextinfo)
   18558              : {
   18559          171 :     DumpOptions *dopt = fout->dopt;
   18560              :     PQExpBuffer query;
   18561              :     PGresult   *res;
   18562              :     int         nstats;
   18563              : 
   18564              :     /* Do nothing if not dumping statistics */
   18565          171 :     if (!dopt->dumpStatistics)
   18566           40 :         return;
   18567              : 
   18568          131 :     if (!fout->is_prepared[PREPQUERY_DUMPEXTSTATSOBJSTATS])
   18569              :     {
   18570           33 :         PQExpBuffer pq = createPQExpBuffer();
   18571              : 
   18572              :         /*---------
   18573              :          * Set up query for details about extended statistics objects.
   18574              :          *
   18575              :          * The query depends on the backend version:
   18576              :          * - In v19 and newer versions, query directly the pg_stats_ext*
   18577              :          *   catalogs.
   18578              :          * - In v18 and older versions, ndistinct and dependencies have a
   18579              :          *   different format that needs translation.
   18580              :          * - In v14 and older versions, inherited does not exist.
   18581              :          * - In v11 and older versions, there is no pg_stats_ext, hence
   18582              :          *   the logic joins pg_statistic_ext and pg_namespace.
   18583              :          *---------
   18584              :          */
   18585              : 
   18586           33 :         appendPQExpBufferStr(pq,
   18587              :                              "PREPARE getExtStatsStats(pg_catalog.name, pg_catalog.name) AS\n"
   18588              :                              "SELECT ");
   18589              : 
   18590              :         /*
   18591              :          * Versions 15 and newer have inherited stats.
   18592              :          *
   18593              :          * Create this column in all versions because we need to order by it
   18594              :          * later.
   18595              :          */
   18596           33 :         if (fout->remoteVersion >= 150000)
   18597           33 :             appendPQExpBufferStr(pq, "e.inherited, ");
   18598              :         else
   18599            0 :             appendPQExpBufferStr(pq, "false AS inherited, ");
   18600              : 
   18601              :         /*--------
   18602              :          * The ndistinct and dependencies formats changed in v19, so
   18603              :          * everything before that needs to be translated.
   18604              :          *
   18605              :          * The ndistinct translation converts this kind of data:
   18606              :          * {"3, 4": 11, "3, 6": 11, "4, 6": 11, "3, 4, 6": 11}
   18607              :          *
   18608              :          * to this:
   18609              :          * [ {"attributes": [3,4], "ndistinct": 11},
   18610              :          *   {"attributes": [3,6], "ndistinct": 11},
   18611              :          *   {"attributes": [4,6], "ndistinct": 11},
   18612              :          *   {"attributes": [3,4,6], "ndistinct": 11} ]
   18613              :          *
   18614              :          * The dependencies translation converts this kind of data:
   18615              :          * {"3 => 4": 1.000000, "3 => 6": 1.000000,
   18616              :          *  "4 => 6": 1.000000, "3, 4 => 6": 1.000000,
   18617              :          *  "3, 6 => 4": 1.000000}
   18618              :          *
   18619              :          * to this:
   18620              :          * [ {"attributes": [3], "dependency": 4, "degree": 1.000000},
   18621              :          *   {"attributes": [3], "dependency": 6, "degree": 1.000000},
   18622              :          *   {"attributes": [4], "dependency": 6, "degree": 1.000000},
   18623              :          *   {"attributes": [3,4], "dependency": 6, "degree": 1.000000},
   18624              :          *   {"attributes": [3,6], "dependency": 4, "degree": 1.000000} ]
   18625              :          *--------
   18626              :          */
   18627           33 :         if (fout->remoteVersion >= 190000)
   18628           33 :             appendPQExpBufferStr(pq, "e.n_distinct, e.dependencies, ");
   18629              :         else
   18630            0 :             appendPQExpBufferStr(pq,
   18631              :                                  "( "
   18632              :                                  "SELECT json_agg( "
   18633              :                                  "  json_build_object( "
   18634              :                                  "    '" PG_NDISTINCT_KEY_ATTRIBUTES "', "
   18635              :                                  "    string_to_array(kv.key, ', ')::integer[], "
   18636              :                                  "    '" PG_NDISTINCT_KEY_NDISTINCT "', "
   18637              :                                  "    kv.value::bigint )) "
   18638              :                                  "FROM json_each_text(e.n_distinct::text::json) AS kv"
   18639              :                                  ") AS n_distinct, "
   18640              :                                  "( "
   18641              :                                  "SELECT json_agg( "
   18642              :                                  "  json_build_object( "
   18643              :                                  "    '" PG_DEPENDENCIES_KEY_ATTRIBUTES "', "
   18644              :                                  "    string_to_array( "
   18645              :                                  "      split_part(kv.key, ' => ', 1), "
   18646              :                                  "      ', ')::integer[], "
   18647              :                                  "    '" PG_DEPENDENCIES_KEY_DEPENDENCY "', "
   18648              :                                  "    split_part(kv.key, ' => ', 2)::integer, "
   18649              :                                  "    '" PG_DEPENDENCIES_KEY_DEGREE "', "
   18650              :                                  "    kv.value::double precision )) "
   18651              :                                  "FROM json_each_text(e.dependencies::text::json) AS kv "
   18652              :                                  ") AS dependencies, ");
   18653              : 
   18654              :         /* MCV was introduced v13 */
   18655           33 :         if (fout->remoteVersion >= 130000)
   18656           33 :             appendPQExpBufferStr(pq,
   18657              :                                  "e.most_common_vals, e.most_common_freqs, "
   18658              :                                  "e.most_common_base_freqs, ");
   18659              :         else
   18660            0 :             appendPQExpBufferStr(pq,
   18661              :                                  "NULL AS most_common_vals, NULL AS most_common_freqs, "
   18662              :                                  "NULL AS most_common_base_freqs, ");
   18663              : 
   18664              :         /* Expressions were introduced in v14 */
   18665           33 :         if (fout->remoteVersion >= 140000)
   18666              :         {
   18667              :             /*
   18668              :              * There is no ordering column in pg_stats_ext_exprs.  However, we
   18669              :              * can rely on the unnesting of pg_statistic.ext_data.stxdexpr to
   18670              :              * maintain the desired order of expression elements.
   18671              :              */
   18672           33 :             appendPQExpBufferStr(pq,
   18673              :                                  "( "
   18674              :                                  "SELECT jsonb_pretty(jsonb_agg("
   18675              :                                  "nullif(j.obj, '{}'::jsonb))) "
   18676              :                                  "FROM pg_stats_ext_exprs AS ee "
   18677              :                                  "CROSS JOIN LATERAL jsonb_strip_nulls("
   18678              :                                  "    jsonb_build_object( "
   18679              :                                  "       'null_frac', ee.null_frac::text, "
   18680              :                                  "       'avg_width', ee.avg_width::text, "
   18681              :                                  "       'n_distinct', ee.n_distinct::text, "
   18682              :                                  "       'most_common_vals', ee.most_common_vals::text, "
   18683              :                                  "       'most_common_freqs', ee.most_common_freqs::text, "
   18684              :                                  "       'histogram_bounds', ee.histogram_bounds::text, "
   18685              :                                  "       'correlation', ee.correlation::text, "
   18686              :                                  "       'most_common_elems', ee.most_common_elems::text, "
   18687              :                                  "       'most_common_elem_freqs', ee.most_common_elem_freqs::text, "
   18688              :                                  "       'elem_count_histogram', ee.elem_count_histogram::text");
   18689              : 
   18690              :             /* These three have been added to pg_stats_ext_exprs in v19. */
   18691           33 :             if (fout->remoteVersion >= 190000)
   18692           33 :                 appendPQExpBufferStr(pq,
   18693              :                                      ", "
   18694              :                                      "       'range_length_histogram', ee.range_length_histogram::text, "
   18695              :                                      "       'range_empty_frac', ee.range_empty_frac::text, "
   18696              :                                      "       'range_bounds_histogram', ee.range_bounds_histogram::text");
   18697              : 
   18698           33 :             appendPQExpBufferStr(pq,
   18699              :                                  "    )) AS j(obj)"
   18700              :                                  "WHERE ee.statistics_schemaname = $1 "
   18701              :                                  "AND ee.statistics_name = $2 ");
   18702              :             /* Inherited expressions introduced in v15 */
   18703           33 :             if (fout->remoteVersion >= 150000)
   18704           33 :                 appendPQExpBufferStr(pq, "AND ee.inherited = e.inherited");
   18705              : 
   18706           33 :             appendPQExpBufferStr(pq, ") AS exprs ");
   18707              :         }
   18708              :         else
   18709            0 :             appendPQExpBufferStr(pq, "NULL AS exprs ");
   18710              : 
   18711              :         /* pg_stats_ext introduced in v12 */
   18712           33 :         if (fout->remoteVersion >= 120000)
   18713           33 :             appendPQExpBufferStr(pq,
   18714              :                                  "FROM pg_catalog.pg_stats_ext AS e "
   18715              :                                  "WHERE e.statistics_schemaname = $1 "
   18716              :                                  "AND e.statistics_name = $2 ");
   18717              :         else
   18718            0 :             appendPQExpBufferStr(pq,
   18719              :                                  "FROM ( "
   18720              :                                  "SELECT s.stxndistinct AS n_distinct, "
   18721              :                                  "    s.stxdependencies AS dependencies "
   18722              :                                  "FROM pg_catalog.pg_statistic_ext AS s "
   18723              :                                  "JOIN pg_catalog.pg_namespace AS n "
   18724              :                                  "ON n.oid = s.stxnamespace "
   18725              :                                  "WHERE n.nspname = $1 "
   18726              :                                  "AND s.stxname = $2 "
   18727              :                                  ") AS e ");
   18728              : 
   18729              :         /* we always have an inherited column, but it may be a constant */
   18730           33 :         appendPQExpBufferStr(pq, "ORDER BY inherited");
   18731              : 
   18732           33 :         ExecuteSqlStatement(fout, pq->data);
   18733              : 
   18734           33 :         fout->is_prepared[PREPQUERY_DUMPEXTSTATSOBJSTATS] = true;
   18735              : 
   18736           33 :         destroyPQExpBuffer(pq);
   18737              :     }
   18738              : 
   18739          131 :     query = createPQExpBuffer();
   18740              : 
   18741          131 :     appendPQExpBufferStr(query, "EXECUTE getExtStatsStats(");
   18742          131 :     appendStringLiteralAH(query, statsextinfo->dobj.namespace->dobj.name, fout);
   18743          131 :     appendPQExpBufferStr(query, "::pg_catalog.name, ");
   18744          131 :     appendStringLiteralAH(query, statsextinfo->dobj.name, fout);
   18745          131 :     appendPQExpBufferStr(query, "::pg_catalog.name)");
   18746              : 
   18747          131 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   18748              : 
   18749          131 :     destroyPQExpBuffer(query);
   18750              : 
   18751          131 :     nstats = PQntuples(res);
   18752              : 
   18753          131 :     if (nstats > 0)
   18754              :     {
   18755           36 :         PQExpBuffer out = createPQExpBuffer();
   18756              : 
   18757           36 :         int         i_inherited = PQfnumber(res, "inherited");
   18758           36 :         int         i_ndistinct = PQfnumber(res, "n_distinct");
   18759           36 :         int         i_dependencies = PQfnumber(res, "dependencies");
   18760           36 :         int         i_mcv = PQfnumber(res, "most_common_vals");
   18761           36 :         int         i_mcf = PQfnumber(res, "most_common_freqs");
   18762           36 :         int         i_mcbf = PQfnumber(res, "most_common_base_freqs");
   18763           36 :         int         i_exprs = PQfnumber(res, "exprs");
   18764              : 
   18765           72 :         for (int i = 0; i < nstats; i++)
   18766              :         {
   18767           36 :             TableInfo  *tbinfo = statsextinfo->stattable;
   18768              : 
   18769           36 :             if (PQgetisnull(res, i, i_inherited))
   18770            0 :                 pg_fatal("inherited cannot be NULL");
   18771              : 
   18772           36 :             appendPQExpBufferStr(out,
   18773              :                                  "SELECT * FROM pg_catalog.pg_restore_extended_stats(\n");
   18774           36 :             appendPQExpBuffer(out, "\t'version', '%d'::integer,\n",
   18775              :                               fout->remoteVersion);
   18776              : 
   18777              :             /* Relation information */
   18778           36 :             appendPQExpBufferStr(out, "\t'schemaname', ");
   18779           36 :             appendStringLiteralAH(out, tbinfo->dobj.namespace->dobj.name, fout);
   18780           36 :             appendPQExpBufferStr(out, ",\n\t'relname', ");
   18781           36 :             appendStringLiteralAH(out, tbinfo->dobj.name, fout);
   18782              : 
   18783              :             /* Extended statistics information */
   18784           36 :             appendPQExpBufferStr(out, ",\n\t'statistics_schemaname', ");
   18785           36 :             appendStringLiteralAH(out, statsextinfo->dobj.namespace->dobj.name, fout);
   18786           36 :             appendPQExpBufferStr(out, ",\n\t'statistics_name', ");
   18787           36 :             appendStringLiteralAH(out, statsextinfo->dobj.name, fout);
   18788           36 :             appendNamedArgument(out, fout, "inherited", "boolean",
   18789           36 :                                 PQgetvalue(res, i, i_inherited));
   18790              : 
   18791           36 :             if (!PQgetisnull(res, i, i_ndistinct))
   18792           32 :                 appendNamedArgument(out, fout, "n_distinct", "pg_ndistinct",
   18793           32 :                                     PQgetvalue(res, i, i_ndistinct));
   18794              : 
   18795           36 :             if (!PQgetisnull(res, i, i_dependencies))
   18796           33 :                 appendNamedArgument(out, fout, "dependencies", "pg_dependencies",
   18797           33 :                                     PQgetvalue(res, i, i_dependencies));
   18798              : 
   18799           36 :             if (!PQgetisnull(res, i, i_mcv))
   18800           35 :                 appendNamedArgument(out, fout, "most_common_vals", "text[]",
   18801           35 :                                     PQgetvalue(res, i, i_mcv));
   18802              : 
   18803           36 :             if (!PQgetisnull(res, i, i_mcf))
   18804           35 :                 appendNamedArgument(out, fout, "most_common_freqs", "double precision[]",
   18805           35 :                                     PQgetvalue(res, i, i_mcf));
   18806              : 
   18807           36 :             if (!PQgetisnull(res, i, i_mcbf))
   18808           35 :                 appendNamedArgument(out, fout, "most_common_base_freqs", "double precision[]",
   18809           35 :                                     PQgetvalue(res, i, i_mcbf));
   18810              : 
   18811           36 :             if (!PQgetisnull(res, i, i_exprs))
   18812           33 :                 appendNamedArgument(out, fout, "exprs", "jsonb",
   18813           33 :                                     PQgetvalue(res, i, i_exprs));
   18814              : 
   18815           36 :             appendPQExpBufferStr(out, "\n);\n");
   18816              :         }
   18817              : 
   18818           36 :         ArchiveEntry(fout, nilCatalogId, createDumpId(),
   18819           36 :                      ARCHIVE_OPTS(.tag = statsextinfo->dobj.name,
   18820              :                                   .namespace = statsextinfo->dobj.namespace->dobj.name,
   18821              :                                   .owner = statsextinfo->rolname,
   18822              :                                   .description = "EXTENDED STATISTICS DATA",
   18823              :                                   .section = SECTION_POST_DATA,
   18824              :                                   .createStmt = out->data,
   18825              :                                   .deps = &statsextinfo->dobj.dumpId,
   18826              :                                   .nDeps = 1));
   18827           36 :         destroyPQExpBuffer(out);
   18828              :     }
   18829          131 :     PQclear(res);
   18830              : }
   18831              : 
   18832              : /*
   18833              :  * dumpConstraint
   18834              :  *    write out to fout a user-defined constraint
   18835              :  */
   18836              : static void
   18837         2489 : dumpConstraint(Archive *fout, const ConstraintInfo *coninfo)
   18838              : {
   18839         2489 :     DumpOptions *dopt = fout->dopt;
   18840         2489 :     TableInfo  *tbinfo = coninfo->contable;
   18841              :     PQExpBuffer q;
   18842              :     PQExpBuffer delq;
   18843         2489 :     char       *tag = NULL;
   18844              :     char       *foreign;
   18845              : 
   18846              :     /* Do nothing if not dumping schema */
   18847         2489 :     if (!dopt->dumpSchema)
   18848           98 :         return;
   18849              : 
   18850         2391 :     q = createPQExpBuffer();
   18851         2391 :     delq = createPQExpBuffer();
   18852              : 
   18853         4628 :     foreign = tbinfo &&
   18854         2391 :         tbinfo->relkind == RELKIND_FOREIGN_TABLE ? "FOREIGN " : "";
   18855              : 
   18856         2391 :     if (coninfo->contype == 'p' ||
   18857         1192 :         coninfo->contype == 'u' ||
   18858          963 :         coninfo->contype == 'x')
   18859         1438 :     {
   18860              :         /* Index-related constraint */
   18861              :         IndxInfo   *indxinfo;
   18862              :         int         k;
   18863              : 
   18864         1438 :         indxinfo = (IndxInfo *) findObjectByDumpId(coninfo->conindex);
   18865              : 
   18866         1438 :         if (indxinfo == NULL)
   18867            0 :             pg_fatal("missing index for constraint \"%s\"",
   18868              :                      coninfo->dobj.name);
   18869              : 
   18870         1438 :         if (dopt->binary_upgrade)
   18871          150 :             binary_upgrade_set_pg_class_oids(fout, q,
   18872              :                                              indxinfo->dobj.catId.oid);
   18873              : 
   18874         1438 :         appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s\n", foreign,
   18875         1438 :                           fmtQualifiedDumpable(tbinfo));
   18876         1438 :         appendPQExpBuffer(q, "    ADD CONSTRAINT %s ",
   18877         1438 :                           fmtId(coninfo->dobj.name));
   18878              : 
   18879         1438 :         if (coninfo->condef)
   18880              :         {
   18881              :             /* pg_get_constraintdef should have provided everything */
   18882           10 :             appendPQExpBuffer(q, "%s;\n", coninfo->condef);
   18883              :         }
   18884              :         else
   18885              :         {
   18886         1428 :             appendPQExpBufferStr(q,
   18887         1428 :                                  coninfo->contype == 'p' ? "PRIMARY KEY" : "UNIQUE");
   18888              : 
   18889              :             /*
   18890              :              * PRIMARY KEY constraints should not be using NULLS NOT DISTINCT
   18891              :              * indexes. Being able to create this was fixed, but we need to
   18892              :              * make the index distinct in order to be able to restore the
   18893              :              * dump.
   18894              :              */
   18895         1428 :             if (indxinfo->indnullsnotdistinct && coninfo->contype != 'p')
   18896            0 :                 appendPQExpBufferStr(q, " NULLS NOT DISTINCT");
   18897         1428 :             appendPQExpBufferStr(q, " (");
   18898         3443 :             for (k = 0; k < indxinfo->indnkeyattrs; k++)
   18899              :             {
   18900         2015 :                 int         indkey = (int) indxinfo->indkeys[k];
   18901              :                 const char *attname;
   18902              : 
   18903         2015 :                 if (indkey == InvalidAttrNumber)
   18904            0 :                     break;
   18905         2015 :                 attname = getAttrName(indkey, tbinfo);
   18906              : 
   18907         2015 :                 appendPQExpBuffer(q, "%s%s",
   18908              :                                   (k == 0) ? "" : ", ",
   18909              :                                   fmtId(attname));
   18910              :             }
   18911         1428 :             if (coninfo->conperiod)
   18912          104 :                 appendPQExpBufferStr(q, " WITHOUT OVERLAPS");
   18913              : 
   18914         1428 :             if (indxinfo->indnkeyattrs < indxinfo->indnattrs)
   18915           20 :                 appendPQExpBufferStr(q, ") INCLUDE (");
   18916              : 
   18917         1468 :             for (k = indxinfo->indnkeyattrs; k < indxinfo->indnattrs; k++)
   18918              :             {
   18919           40 :                 int         indkey = (int) indxinfo->indkeys[k];
   18920              :                 const char *attname;
   18921              : 
   18922           40 :                 if (indkey == InvalidAttrNumber)
   18923            0 :                     break;
   18924           40 :                 attname = getAttrName(indkey, tbinfo);
   18925              : 
   18926           80 :                 appendPQExpBuffer(q, "%s%s",
   18927           40 :                                   (k == indxinfo->indnkeyattrs) ? "" : ", ",
   18928              :                                   fmtId(attname));
   18929              :             }
   18930              : 
   18931         1428 :             appendPQExpBufferChar(q, ')');
   18932              : 
   18933         1428 :             if (nonemptyReloptions(indxinfo->indreloptions))
   18934              :             {
   18935            0 :                 appendPQExpBufferStr(q, " WITH (");
   18936            0 :                 appendReloptionsArrayAH(q, indxinfo->indreloptions, "", fout);
   18937            0 :                 appendPQExpBufferChar(q, ')');
   18938              :             }
   18939              : 
   18940         1428 :             if (coninfo->condeferrable)
   18941              :             {
   18942           25 :                 appendPQExpBufferStr(q, " DEFERRABLE");
   18943           25 :                 if (coninfo->condeferred)
   18944           15 :                     appendPQExpBufferStr(q, " INITIALLY DEFERRED");
   18945              :             }
   18946              : 
   18947         1428 :             appendPQExpBufferStr(q, ";\n");
   18948              :         }
   18949              : 
   18950              :         /*
   18951              :          * Append ALTER TABLE commands as needed to set properties that we
   18952              :          * only have ALTER TABLE syntax for.  Keep this in sync with the
   18953              :          * similar code in dumpIndex!
   18954              :          */
   18955              : 
   18956              :         /* If the index is clustered, we need to record that. */
   18957         1438 :         if (indxinfo->indisclustered)
   18958              :         {
   18959           32 :             appendPQExpBuffer(q, "\nALTER TABLE %s CLUSTER",
   18960           32 :                               fmtQualifiedDumpable(tbinfo));
   18961              :             /* index name is not qualified in this syntax */
   18962           32 :             appendPQExpBuffer(q, " ON %s;\n",
   18963           32 :                               fmtId(indxinfo->dobj.name));
   18964              :         }
   18965              : 
   18966              :         /* If the index defines identity, we need to record that. */
   18967         1438 :         if (indxinfo->indisreplident)
   18968              :         {
   18969            0 :             appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY USING",
   18970            0 :                               fmtQualifiedDumpable(tbinfo));
   18971              :             /* index name is not qualified in this syntax */
   18972            0 :             appendPQExpBuffer(q, " INDEX %s;\n",
   18973            0 :                               fmtId(indxinfo->dobj.name));
   18974              :         }
   18975              : 
   18976              :         /* Indexes can depend on extensions */
   18977         1438 :         append_depends_on_extension(fout, q, &indxinfo->dobj,
   18978              :                                     "pg_catalog.pg_class", "INDEX",
   18979         1438 :                                     fmtQualifiedDumpable(indxinfo));
   18980              : 
   18981         1438 :         appendPQExpBuffer(delq, "ALTER %sTABLE ONLY %s ", foreign,
   18982         1438 :                           fmtQualifiedDumpable(tbinfo));
   18983         1438 :         appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
   18984         1438 :                           fmtId(coninfo->dobj.name));
   18985              : 
   18986         1438 :         tag = psprintf("%s %s", tbinfo->dobj.name, coninfo->dobj.name);
   18987              : 
   18988         1438 :         if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   18989         1438 :             ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
   18990         1438 :                          ARCHIVE_OPTS(.tag = tag,
   18991              :                                       .namespace = tbinfo->dobj.namespace->dobj.name,
   18992              :                                       .tablespace = indxinfo->tablespace,
   18993              :                                       .owner = tbinfo->rolname,
   18994              :                                       .description = "CONSTRAINT",
   18995              :                                       .section = SECTION_POST_DATA,
   18996              :                                       .createStmt = q->data,
   18997              :                                       .dropStmt = delq->data));
   18998              :     }
   18999          953 :     else if (coninfo->contype == 'f')
   19000              :     {
   19001              :         char       *only;
   19002              : 
   19003              :         /*
   19004              :          * Foreign keys on partitioned tables are always declared as
   19005              :          * inheriting to partitions; for all other cases, emit them as
   19006              :          * applying ONLY directly to the named table, because that's how they
   19007              :          * work for regular inherited tables.
   19008              :          */
   19009          159 :         only = tbinfo->relkind == RELKIND_PARTITIONED_TABLE ? "" : "ONLY ";
   19010              : 
   19011              :         /*
   19012              :          * XXX Potentially wrap in a 'SET CONSTRAINTS OFF' block so that the
   19013              :          * current table data is not processed
   19014              :          */
   19015          159 :         appendPQExpBuffer(q, "ALTER %sTABLE %s%s\n", foreign,
   19016          159 :                           only, fmtQualifiedDumpable(tbinfo));
   19017          159 :         appendPQExpBuffer(q, "    ADD CONSTRAINT %s %s;\n",
   19018          159 :                           fmtId(coninfo->dobj.name),
   19019          159 :                           coninfo->condef);
   19020              : 
   19021          159 :         appendPQExpBuffer(delq, "ALTER %sTABLE %s%s ", foreign,
   19022          159 :                           only, fmtQualifiedDumpable(tbinfo));
   19023          159 :         appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
   19024          159 :                           fmtId(coninfo->dobj.name));
   19025              : 
   19026          159 :         tag = psprintf("%s %s", tbinfo->dobj.name, coninfo->dobj.name);
   19027              : 
   19028          159 :         if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   19029          159 :             ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
   19030          159 :                          ARCHIVE_OPTS(.tag = tag,
   19031              :                                       .namespace = tbinfo->dobj.namespace->dobj.name,
   19032              :                                       .owner = tbinfo->rolname,
   19033              :                                       .description = "FK CONSTRAINT",
   19034              :                                       .section = SECTION_POST_DATA,
   19035              :                                       .createStmt = q->data,
   19036              :                                       .dropStmt = delq->data));
   19037              :     }
   19038          794 :     else if ((coninfo->contype == 'c' || coninfo->contype == 'n') && tbinfo)
   19039              :     {
   19040              :         /* CHECK or invalid not-null constraint on a table */
   19041              : 
   19042              :         /* Ignore if not to be dumped separately, or if it was inherited */
   19043          640 :         if (coninfo->separate && coninfo->conislocal)
   19044              :         {
   19045              :             const char *keyword;
   19046              : 
   19047          107 :             if (coninfo->contype == 'c')
   19048           45 :                 keyword = "CHECK CONSTRAINT";
   19049              :             else
   19050           62 :                 keyword = "CONSTRAINT";
   19051              : 
   19052              :             /* not ONLY since we want it to propagate to children */
   19053          107 :             appendPQExpBuffer(q, "ALTER %sTABLE %s\n", foreign,
   19054          107 :                               fmtQualifiedDumpable(tbinfo));
   19055          107 :             appendPQExpBuffer(q, "    ADD CONSTRAINT %s %s;\n",
   19056          107 :                               fmtId(coninfo->dobj.name),
   19057          107 :                               coninfo->condef);
   19058              : 
   19059          107 :             appendPQExpBuffer(delq, "ALTER %sTABLE %s ", foreign,
   19060          107 :                               fmtQualifiedDumpable(tbinfo));
   19061          107 :             appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
   19062          107 :                               fmtId(coninfo->dobj.name));
   19063              : 
   19064          107 :             tag = psprintf("%s %s", tbinfo->dobj.name, coninfo->dobj.name);
   19065              : 
   19066          107 :             if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   19067          107 :                 ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
   19068          107 :                              ARCHIVE_OPTS(.tag = tag,
   19069              :                                           .namespace = tbinfo->dobj.namespace->dobj.name,
   19070              :                                           .owner = tbinfo->rolname,
   19071              :                                           .description = keyword,
   19072              :                                           .section = SECTION_POST_DATA,
   19073              :                                           .createStmt = q->data,
   19074              :                                           .dropStmt = delq->data));
   19075              :         }
   19076              :     }
   19077          154 :     else if (tbinfo == NULL)
   19078              :     {
   19079              :         /* CHECK, NOT NULL constraint on a domain */
   19080          154 :         TypeInfo   *tyinfo = coninfo->condomain;
   19081              : 
   19082              :         Assert(coninfo->contype == 'c' || coninfo->contype == 'n');
   19083              : 
   19084              :         /* Ignore if not to be dumped separately */
   19085          154 :         if (coninfo->separate)
   19086              :         {
   19087              :             const char *keyword;
   19088              : 
   19089            5 :             if (coninfo->contype == 'c')
   19090            5 :                 keyword = "CHECK CONSTRAINT";
   19091              :             else
   19092            0 :                 keyword = "CONSTRAINT";
   19093              : 
   19094            5 :             appendPQExpBuffer(q, "ALTER DOMAIN %s\n",
   19095            5 :                               fmtQualifiedDumpable(tyinfo));
   19096            5 :             appendPQExpBuffer(q, "    ADD CONSTRAINT %s %s;\n",
   19097            5 :                               fmtId(coninfo->dobj.name),
   19098            5 :                               coninfo->condef);
   19099              : 
   19100            5 :             appendPQExpBuffer(delq, "ALTER DOMAIN %s ",
   19101            5 :                               fmtQualifiedDumpable(tyinfo));
   19102            5 :             appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
   19103            5 :                               fmtId(coninfo->dobj.name));
   19104              : 
   19105            5 :             tag = psprintf("%s %s", tyinfo->dobj.name, coninfo->dobj.name);
   19106              : 
   19107            5 :             if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   19108            5 :                 ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
   19109            5 :                              ARCHIVE_OPTS(.tag = tag,
   19110              :                                           .namespace = tyinfo->dobj.namespace->dobj.name,
   19111              :                                           .owner = tyinfo->rolname,
   19112              :                                           .description = keyword,
   19113              :                                           .section = SECTION_POST_DATA,
   19114              :                                           .createStmt = q->data,
   19115              :                                           .dropStmt = delq->data));
   19116              : 
   19117            5 :             if (coninfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   19118              :             {
   19119            5 :                 PQExpBuffer conprefix = createPQExpBuffer();
   19120            5 :                 char       *qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
   19121              : 
   19122            5 :                 appendPQExpBuffer(conprefix, "CONSTRAINT %s ON DOMAIN",
   19123            5 :                                   fmtId(coninfo->dobj.name));
   19124              : 
   19125            5 :                 dumpComment(fout, conprefix->data, qtypname,
   19126            5 :                             tyinfo->dobj.namespace->dobj.name,
   19127              :                             tyinfo->rolname,
   19128            5 :                             coninfo->dobj.catId, 0, coninfo->dobj.dumpId);
   19129            5 :                 destroyPQExpBuffer(conprefix);
   19130            5 :                 free(qtypname);
   19131              :             }
   19132              :         }
   19133              :     }
   19134              :     else
   19135              :     {
   19136            0 :         pg_fatal("unrecognized constraint type: %c",
   19137              :                  coninfo->contype);
   19138              :     }
   19139              : 
   19140              :     /* Dump Constraint Comments --- only works for table constraints */
   19141         2391 :     if (tbinfo && coninfo->separate &&
   19142         1734 :         coninfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   19143           47 :         dumpTableConstraintComment(fout, coninfo);
   19144              : 
   19145         2391 :     free(tag);
   19146         2391 :     destroyPQExpBuffer(q);
   19147         2391 :     destroyPQExpBuffer(delq);
   19148              : }
   19149              : 
   19150              : /*
   19151              :  * dumpTableConstraintComment --- dump a constraint's comment if any
   19152              :  *
   19153              :  * This is split out because we need the function in two different places
   19154              :  * depending on whether the constraint is dumped as part of CREATE TABLE
   19155              :  * or as a separate ALTER command.
   19156              :  */
   19157              : static void
   19158           84 : dumpTableConstraintComment(Archive *fout, const ConstraintInfo *coninfo)
   19159              : {
   19160           84 :     TableInfo  *tbinfo = coninfo->contable;
   19161           84 :     PQExpBuffer conprefix = createPQExpBuffer();
   19162              :     char       *qtabname;
   19163              : 
   19164           84 :     qtabname = pg_strdup(fmtId(tbinfo->dobj.name));
   19165              : 
   19166           84 :     appendPQExpBuffer(conprefix, "CONSTRAINT %s ON",
   19167           84 :                       fmtId(coninfo->dobj.name));
   19168              : 
   19169           84 :     if (coninfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   19170           84 :         dumpComment(fout, conprefix->data, qtabname,
   19171           84 :                     tbinfo->dobj.namespace->dobj.name,
   19172              :                     tbinfo->rolname,
   19173              :                     coninfo->dobj.catId, 0,
   19174           84 :                     coninfo->separate ? coninfo->dobj.dumpId : tbinfo->dobj.dumpId);
   19175              : 
   19176           84 :     destroyPQExpBuffer(conprefix);
   19177           84 :     free(qtabname);
   19178           84 : }
   19179              : 
   19180              : static inline SeqType
   19181          646 : parse_sequence_type(const char *name)
   19182              : {
   19183         1449 :     for (int i = 0; i < lengthof(SeqTypeNames); i++)
   19184              :     {
   19185         1449 :         if (strcmp(SeqTypeNames[i], name) == 0)
   19186          646 :             return (SeqType) i;
   19187              :     }
   19188              : 
   19189            0 :     pg_fatal("unrecognized sequence type: %s", name);
   19190              :     return (SeqType) 0;         /* keep compiler quiet */
   19191              : }
   19192              : 
   19193              : /*
   19194              :  * bsearch() comparator for SequenceItem
   19195              :  */
   19196              : static int
   19197         2969 : SequenceItemCmp(const void *p1, const void *p2)
   19198              : {
   19199         2969 :     SequenceItem v1 = *((const SequenceItem *) p1);
   19200         2969 :     SequenceItem v2 = *((const SequenceItem *) p2);
   19201              : 
   19202         2969 :     return pg_cmp_u32(v1.oid, v2.oid);
   19203              : }
   19204              : 
   19205              : /*
   19206              :  * collectSequences
   19207              :  *
   19208              :  * Construct a table of sequence information.  This table is sorted by OID for
   19209              :  * speed in lookup.
   19210              :  */
   19211              : static void
   19212          249 : collectSequences(Archive *fout)
   19213              : {
   19214              :     PGresult   *res;
   19215              :     const char *query;
   19216              : 
   19217              :     /*
   19218              :      * Before Postgres 10, sequence metadata is in the sequence itself.  With
   19219              :      * some extra effort, we might be able to use the sorted table for those
   19220              :      * versions, but for now it seems unlikely to be worth it.
   19221              :      *
   19222              :      * Since version 18, we can gather the sequence data in this query with
   19223              :      * pg_get_sequence_data(), but we only do so for non-schema-only dumps.
   19224              :      */
   19225          249 :     if (fout->remoteVersion < 100000)
   19226            0 :         return;
   19227          249 :     else if (fout->remoteVersion < 180000 ||
   19228          249 :              (!fout->dopt->dumpData && !fout->dopt->sequence_data))
   19229            8 :         query = "SELECT seqrelid, format_type(seqtypid, NULL), "
   19230              :             "seqstart, seqincrement, "
   19231              :             "seqmax, seqmin, "
   19232              :             "seqcache, seqcycle, "
   19233              :             "NULL, 'f' "
   19234              :             "FROM pg_catalog.pg_sequence "
   19235              :             "ORDER BY seqrelid";
   19236              :     else
   19237          241 :         query = "SELECT seqrelid, format_type(seqtypid, NULL), "
   19238              :             "seqstart, seqincrement, "
   19239              :             "seqmax, seqmin, "
   19240              :             "seqcache, seqcycle, "
   19241              :             "last_value, is_called "
   19242              :             "FROM pg_catalog.pg_sequence, "
   19243              :             "pg_get_sequence_data(seqrelid) "
   19244              :             "ORDER BY seqrelid;";
   19245              : 
   19246          249 :     res = ExecuteSqlQuery(fout, query, PGRES_TUPLES_OK);
   19247              : 
   19248          249 :     nsequences = PQntuples(res);
   19249          249 :     sequences = pg_malloc_array(SequenceItem, nsequences);
   19250              : 
   19251          895 :     for (int i = 0; i < nsequences; i++)
   19252              :     {
   19253          646 :         sequences[i].oid = atooid(PQgetvalue(res, i, 0));
   19254          646 :         sequences[i].seqtype = parse_sequence_type(PQgetvalue(res, i, 1));
   19255          646 :         sequences[i].startv = strtoi64(PQgetvalue(res, i, 2), NULL, 10);
   19256          646 :         sequences[i].incby = strtoi64(PQgetvalue(res, i, 3), NULL, 10);
   19257          646 :         sequences[i].maxv = strtoi64(PQgetvalue(res, i, 4), NULL, 10);
   19258          646 :         sequences[i].minv = strtoi64(PQgetvalue(res, i, 5), NULL, 10);
   19259          646 :         sequences[i].cache = strtoi64(PQgetvalue(res, i, 6), NULL, 10);
   19260          646 :         sequences[i].cycled = (strcmp(PQgetvalue(res, i, 7), "t") == 0);
   19261          646 :         sequences[i].last_value = strtoi64(PQgetvalue(res, i, 8), NULL, 10);
   19262          646 :         sequences[i].is_called = (strcmp(PQgetvalue(res, i, 9), "t") == 0);
   19263          646 :         sequences[i].null_seqtuple = (PQgetisnull(res, i, 8) || PQgetisnull(res, i, 9));
   19264              :     }
   19265              : 
   19266          249 :     PQclear(res);
   19267              : }
   19268              : 
   19269              : /*
   19270              :  * dumpSequence
   19271              :  *    write the declaration (not data) of one user-defined sequence
   19272              :  */
   19273              : static void
   19274          383 : dumpSequence(Archive *fout, const TableInfo *tbinfo)
   19275              : {
   19276          383 :     DumpOptions *dopt = fout->dopt;
   19277              :     SequenceItem *seq;
   19278              :     bool        is_ascending;
   19279              :     int64       default_minv,
   19280              :                 default_maxv;
   19281          383 :     PQExpBuffer query = createPQExpBuffer();
   19282          383 :     PQExpBuffer delqry = createPQExpBuffer();
   19283              :     char       *qseqname;
   19284          383 :     TableInfo  *owning_tab = NULL;
   19285              : 
   19286          383 :     qseqname = pg_strdup(fmtId(tbinfo->dobj.name));
   19287              : 
   19288              :     /*
   19289              :      * For versions >= 10, the sequence information is gathered in a sorted
   19290              :      * table before any calls to dumpSequence().  See collectSequences() for
   19291              :      * more information.
   19292              :      */
   19293          383 :     if (fout->remoteVersion >= 100000)
   19294              :     {
   19295          383 :         SequenceItem key = {0};
   19296              : 
   19297              :         Assert(sequences);
   19298              : 
   19299          383 :         key.oid = tbinfo->dobj.catId.oid;
   19300          383 :         seq = bsearch(&key, sequences, nsequences,
   19301              :                       sizeof(SequenceItem), SequenceItemCmp);
   19302              :     }
   19303              :     else
   19304              :     {
   19305              :         PGresult   *res;
   19306              : 
   19307              :         /*
   19308              :          * Before PostgreSQL 10, sequence metadata is in the sequence itself.
   19309              :          *
   19310              :          * Note: it might seem that 'bigint' potentially needs to be
   19311              :          * schema-qualified, but actually that's a keyword.
   19312              :          */
   19313            0 :         appendPQExpBuffer(query,
   19314              :                           "SELECT 'bigint' AS sequence_type, "
   19315              :                           "start_value, increment_by, max_value, min_value, "
   19316              :                           "cache_value, is_cycled FROM %s",
   19317            0 :                           fmtQualifiedDumpable(tbinfo));
   19318              : 
   19319            0 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   19320              : 
   19321            0 :         if (PQntuples(res) != 1)
   19322            0 :             pg_fatal(ngettext("query to get data of sequence \"%s\" returned %d row (expected 1)",
   19323              :                               "query to get data of sequence \"%s\" returned %d rows (expected 1)",
   19324              :                               PQntuples(res)),
   19325              :                      tbinfo->dobj.name, PQntuples(res));
   19326              : 
   19327            0 :         seq = pg_malloc0_object(SequenceItem);
   19328            0 :         seq->seqtype = parse_sequence_type(PQgetvalue(res, 0, 0));
   19329            0 :         seq->startv = strtoi64(PQgetvalue(res, 0, 1), NULL, 10);
   19330            0 :         seq->incby = strtoi64(PQgetvalue(res, 0, 2), NULL, 10);
   19331            0 :         seq->maxv = strtoi64(PQgetvalue(res, 0, 3), NULL, 10);
   19332            0 :         seq->minv = strtoi64(PQgetvalue(res, 0, 4), NULL, 10);
   19333            0 :         seq->cache = strtoi64(PQgetvalue(res, 0, 5), NULL, 10);
   19334            0 :         seq->cycled = (strcmp(PQgetvalue(res, 0, 6), "t") == 0);
   19335              : 
   19336            0 :         PQclear(res);
   19337              :     }
   19338              : 
   19339              :     /* Calculate default limits for a sequence of this type */
   19340          383 :     is_ascending = (seq->incby >= 0);
   19341          383 :     if (seq->seqtype == SEQTYPE_SMALLINT)
   19342              :     {
   19343           25 :         default_minv = is_ascending ? 1 : PG_INT16_MIN;
   19344           25 :         default_maxv = is_ascending ? PG_INT16_MAX : -1;
   19345              :     }
   19346          358 :     else if (seq->seqtype == SEQTYPE_INTEGER)
   19347              :     {
   19348          284 :         default_minv = is_ascending ? 1 : PG_INT32_MIN;
   19349          284 :         default_maxv = is_ascending ? PG_INT32_MAX : -1;
   19350              :     }
   19351           74 :     else if (seq->seqtype == SEQTYPE_BIGINT)
   19352              :     {
   19353           74 :         default_minv = is_ascending ? 1 : PG_INT64_MIN;
   19354           74 :         default_maxv = is_ascending ? PG_INT64_MAX : -1;
   19355              :     }
   19356              :     else
   19357              :     {
   19358            0 :         pg_fatal("unrecognized sequence type: %d", seq->seqtype);
   19359              :         default_minv = default_maxv = 0;    /* keep compiler quiet */
   19360              :     }
   19361              : 
   19362              :     /*
   19363              :      * Identity sequences are not to be dropped separately.
   19364              :      */
   19365          383 :     if (!tbinfo->is_identity_sequence)
   19366              :     {
   19367          241 :         appendPQExpBuffer(delqry, "DROP SEQUENCE %s;\n",
   19368          241 :                           fmtQualifiedDumpable(tbinfo));
   19369              :     }
   19370              : 
   19371          383 :     resetPQExpBuffer(query);
   19372              : 
   19373          383 :     if (dopt->binary_upgrade)
   19374              :     {
   19375           66 :         binary_upgrade_set_pg_class_oids(fout, query,
   19376           66 :                                          tbinfo->dobj.catId.oid);
   19377              : 
   19378              :         /*
   19379              :          * In older PG versions a sequence will have a pg_type entry, but v14
   19380              :          * and up don't use that, so don't attempt to preserve the type OID.
   19381              :          */
   19382              :     }
   19383              : 
   19384          383 :     if (tbinfo->is_identity_sequence)
   19385              :     {
   19386          142 :         owning_tab = findTableByOid(tbinfo->owning_tab);
   19387              : 
   19388          142 :         appendPQExpBuffer(query,
   19389              :                           "ALTER TABLE %s ",
   19390          142 :                           fmtQualifiedDumpable(owning_tab));
   19391          142 :         appendPQExpBuffer(query,
   19392              :                           "ALTER COLUMN %s ADD GENERATED ",
   19393          142 :                           fmtId(owning_tab->attnames[tbinfo->owning_col - 1]));
   19394          142 :         if (owning_tab->attidentity[tbinfo->owning_col - 1] == ATTRIBUTE_IDENTITY_ALWAYS)
   19395          102 :             appendPQExpBufferStr(query, "ALWAYS");
   19396           40 :         else if (owning_tab->attidentity[tbinfo->owning_col - 1] == ATTRIBUTE_IDENTITY_BY_DEFAULT)
   19397           40 :             appendPQExpBufferStr(query, "BY DEFAULT");
   19398          142 :         appendPQExpBuffer(query, " AS IDENTITY (\n    SEQUENCE NAME %s\n",
   19399          142 :                           fmtQualifiedDumpable(tbinfo));
   19400              : 
   19401              :         /*
   19402              :          * Emit persistence option only if it's different from the owning
   19403              :          * table's.  This avoids using this new syntax unnecessarily.
   19404              :          */
   19405          142 :         if (tbinfo->relpersistence != owning_tab->relpersistence)
   19406           10 :             appendPQExpBuffer(query, "    %s\n",
   19407           10 :                               tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED ?
   19408              :                               "UNLOGGED" : "LOGGED");
   19409              :     }
   19410              :     else
   19411              :     {
   19412          241 :         appendPQExpBuffer(query,
   19413              :                           "CREATE %sSEQUENCE %s\n",
   19414          241 :                           tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED ?
   19415              :                           "UNLOGGED " : "",
   19416          241 :                           fmtQualifiedDumpable(tbinfo));
   19417              : 
   19418          241 :         if (seq->seqtype != SEQTYPE_BIGINT)
   19419          182 :             appendPQExpBuffer(query, "    AS %s\n", SeqTypeNames[seq->seqtype]);
   19420              :     }
   19421              : 
   19422          383 :     appendPQExpBuffer(query, "    START WITH " INT64_FORMAT "\n", seq->startv);
   19423              : 
   19424          383 :     appendPQExpBuffer(query, "    INCREMENT BY " INT64_FORMAT "\n", seq->incby);
   19425              : 
   19426          383 :     if (seq->minv != default_minv)
   19427           15 :         appendPQExpBuffer(query, "    MINVALUE " INT64_FORMAT "\n", seq->minv);
   19428              :     else
   19429          368 :         appendPQExpBufferStr(query, "    NO MINVALUE\n");
   19430              : 
   19431          383 :     if (seq->maxv != default_maxv)
   19432           15 :         appendPQExpBuffer(query, "    MAXVALUE " INT64_FORMAT "\n", seq->maxv);
   19433              :     else
   19434          368 :         appendPQExpBufferStr(query, "    NO MAXVALUE\n");
   19435              : 
   19436          383 :     appendPQExpBuffer(query,
   19437              :                       "    CACHE " INT64_FORMAT "%s",
   19438          383 :                       seq->cache, (seq->cycled ? "\n    CYCLE" : ""));
   19439              : 
   19440          383 :     if (tbinfo->is_identity_sequence)
   19441          142 :         appendPQExpBufferStr(query, "\n);\n");
   19442              :     else
   19443          241 :         appendPQExpBufferStr(query, ";\n");
   19444              : 
   19445              :     /* binary_upgrade:  no need to clear TOAST table oid */
   19446              : 
   19447          383 :     if (dopt->binary_upgrade)
   19448           66 :         binary_upgrade_extension_member(query, &tbinfo->dobj,
   19449              :                                         "SEQUENCE", qseqname,
   19450           66 :                                         tbinfo->dobj.namespace->dobj.name);
   19451              : 
   19452          383 :     if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   19453          383 :         ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
   19454          383 :                      ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
   19455              :                                   .namespace = tbinfo->dobj.namespace->dobj.name,
   19456              :                                   .owner = tbinfo->rolname,
   19457              :                                   .description = "SEQUENCE",
   19458              :                                   .section = SECTION_PRE_DATA,
   19459              :                                   .createStmt = query->data,
   19460              :                                   .dropStmt = delqry->data));
   19461              : 
   19462              :     /*
   19463              :      * If the sequence is owned by a table column, emit the ALTER for it as a
   19464              :      * separate TOC entry immediately following the sequence's own entry. It's
   19465              :      * OK to do this rather than using full sorting logic, because the
   19466              :      * dependency that tells us it's owned will have forced the table to be
   19467              :      * created first.  We can't just include the ALTER in the TOC entry
   19468              :      * because it will fail if we haven't reassigned the sequence owner to
   19469              :      * match the table's owner.
   19470              :      *
   19471              :      * We need not schema-qualify the table reference because both sequence
   19472              :      * and table must be in the same schema.
   19473              :      */
   19474          383 :     if (OidIsValid(tbinfo->owning_tab) && !tbinfo->is_identity_sequence)
   19475              :     {
   19476          137 :         owning_tab = findTableByOid(tbinfo->owning_tab);
   19477              : 
   19478          137 :         if (owning_tab == NULL)
   19479            0 :             pg_fatal("failed sanity check, parent table with OID %u of sequence with OID %u not found",
   19480              :                      tbinfo->owning_tab, tbinfo->dobj.catId.oid);
   19481              : 
   19482          137 :         if (owning_tab->dobj.dump & DUMP_COMPONENT_DEFINITION)
   19483              :         {
   19484          135 :             resetPQExpBuffer(query);
   19485          135 :             appendPQExpBuffer(query, "ALTER SEQUENCE %s",
   19486          135 :                               fmtQualifiedDumpable(tbinfo));
   19487          135 :             appendPQExpBuffer(query, " OWNED BY %s",
   19488          135 :                               fmtQualifiedDumpable(owning_tab));
   19489          135 :             appendPQExpBuffer(query, ".%s;\n",
   19490          135 :                               fmtId(owning_tab->attnames[tbinfo->owning_col - 1]));
   19491              : 
   19492          135 :             if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   19493          135 :                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
   19494          135 :                              ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
   19495              :                                           .namespace = tbinfo->dobj.namespace->dobj.name,
   19496              :                                           .owner = tbinfo->rolname,
   19497              :                                           .description = "SEQUENCE OWNED BY",
   19498              :                                           .section = SECTION_PRE_DATA,
   19499              :                                           .createStmt = query->data,
   19500              :                                           .deps = &(tbinfo->dobj.dumpId),
   19501              :                                           .nDeps = 1));
   19502              :         }
   19503              :     }
   19504              : 
   19505              :     /* Dump Sequence Comments and Security Labels */
   19506          383 :     if (tbinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   19507            0 :         dumpComment(fout, "SEQUENCE", qseqname,
   19508            0 :                     tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
   19509            0 :                     tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
   19510              : 
   19511          383 :     if (tbinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
   19512            0 :         dumpSecLabel(fout, "SEQUENCE", qseqname,
   19513            0 :                      tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
   19514            0 :                      tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
   19515              : 
   19516          383 :     if (fout->remoteVersion < 100000)
   19517            0 :         pg_free(seq);
   19518          383 :     destroyPQExpBuffer(query);
   19519          383 :     destroyPQExpBuffer(delqry);
   19520          383 :     free(qseqname);
   19521          383 : }
   19522              : 
   19523              : /*
   19524              :  * dumpSequenceData
   19525              :  *    write the data of one user-defined sequence
   19526              :  */
   19527              : static void
   19528          401 : dumpSequenceData(Archive *fout, const TableDataInfo *tdinfo)
   19529              : {
   19530          401 :     TableInfo  *tbinfo = tdinfo->tdtable;
   19531              :     int64       last;
   19532              :     bool        called;
   19533              :     PQExpBuffer query;
   19534              : 
   19535              :     /* needn't bother if not dumping sequence data */
   19536          401 :     if (!fout->dopt->dumpData && !fout->dopt->sequence_data)
   19537            1 :         return;
   19538              : 
   19539          400 :     query = createPQExpBuffer();
   19540              : 
   19541              :     /*
   19542              :      * For versions >= 18, the sequence information is gathered in the sorted
   19543              :      * array before any calls to dumpSequenceData().  See collectSequences()
   19544              :      * for more information.
   19545              :      *
   19546              :      * For older versions, we have to query the sequence relations
   19547              :      * individually.
   19548              :      */
   19549          400 :     if (fout->remoteVersion < 180000)
   19550              :     {
   19551              :         PGresult   *res;
   19552              : 
   19553            0 :         appendPQExpBuffer(query,
   19554              :                           "SELECT last_value, is_called FROM %s",
   19555            0 :                           fmtQualifiedDumpable(tbinfo));
   19556              : 
   19557            0 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   19558              : 
   19559            0 :         if (PQntuples(res) != 1)
   19560            0 :             pg_fatal(ngettext("query to get data of sequence \"%s\" returned %d row (expected 1)",
   19561              :                               "query to get data of sequence \"%s\" returned %d rows (expected 1)",
   19562              :                               PQntuples(res)),
   19563              :                      tbinfo->dobj.name, PQntuples(res));
   19564              : 
   19565            0 :         last = strtoi64(PQgetvalue(res, 0, 0), NULL, 10);
   19566            0 :         called = (strcmp(PQgetvalue(res, 0, 1), "t") == 0);
   19567              : 
   19568            0 :         PQclear(res);
   19569              :     }
   19570              :     else
   19571              :     {
   19572          400 :         SequenceItem key = {0};
   19573              :         SequenceItem *entry;
   19574              : 
   19575              :         Assert(sequences);
   19576              :         Assert(tbinfo->dobj.catId.oid);
   19577              : 
   19578          400 :         key.oid = tbinfo->dobj.catId.oid;
   19579          400 :         entry = bsearch(&key, sequences, nsequences,
   19580              :                         sizeof(SequenceItem), SequenceItemCmp);
   19581              : 
   19582          400 :         if (entry->null_seqtuple)
   19583            0 :             pg_fatal("failed to get data for sequence \"%s\"; user may lack "
   19584              :                      "SELECT privilege on the sequence or the sequence may "
   19585              :                      "have been concurrently dropped",
   19586              :                      tbinfo->dobj.name);
   19587              : 
   19588          400 :         last = entry->last_value;
   19589          400 :         called = entry->is_called;
   19590              :     }
   19591              : 
   19592          400 :     resetPQExpBuffer(query);
   19593          400 :     appendPQExpBufferStr(query, "SELECT pg_catalog.setval(");
   19594          400 :     appendStringLiteralAH(query, fmtQualifiedDumpable(tbinfo), fout);
   19595          400 :     appendPQExpBuffer(query, ", " INT64_FORMAT ", %s);\n",
   19596              :                       last, (called ? "true" : "false"));
   19597              : 
   19598          400 :     if (tdinfo->dobj.dump & DUMP_COMPONENT_DATA)
   19599          400 :         ArchiveEntry(fout, nilCatalogId, createDumpId(),
   19600          400 :                      ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
   19601              :                                   .namespace = tbinfo->dobj.namespace->dobj.name,
   19602              :                                   .owner = tbinfo->rolname,
   19603              :                                   .description = "SEQUENCE SET",
   19604              :                                   .section = SECTION_DATA,
   19605              :                                   .createStmt = query->data,
   19606              :                                   .deps = &(tbinfo->dobj.dumpId),
   19607              :                                   .nDeps = 1));
   19608              : 
   19609          400 :     destroyPQExpBuffer(query);
   19610              : }
   19611              : 
   19612              : /*
   19613              :  * dumpTrigger
   19614              :  *    write the declaration of one user-defined table trigger
   19615              :  */
   19616              : static void
   19617          523 : dumpTrigger(Archive *fout, const TriggerInfo *tginfo)
   19618              : {
   19619          523 :     DumpOptions *dopt = fout->dopt;
   19620          523 :     TableInfo  *tbinfo = tginfo->tgtable;
   19621              :     PQExpBuffer query;
   19622              :     PQExpBuffer delqry;
   19623              :     PQExpBuffer trigprefix;
   19624              :     PQExpBuffer trigidentity;
   19625              :     char       *qtabname;
   19626              :     char       *tag;
   19627              : 
   19628              :     /* Do nothing if not dumping schema */
   19629          523 :     if (!dopt->dumpSchema)
   19630           31 :         return;
   19631              : 
   19632          492 :     query = createPQExpBuffer();
   19633          492 :     delqry = createPQExpBuffer();
   19634          492 :     trigprefix = createPQExpBuffer();
   19635          492 :     trigidentity = createPQExpBuffer();
   19636              : 
   19637          492 :     qtabname = pg_strdup(fmtId(tbinfo->dobj.name));
   19638              : 
   19639          492 :     appendPQExpBuffer(trigidentity, "%s ", fmtId(tginfo->dobj.name));
   19640          492 :     appendPQExpBuffer(trigidentity, "ON %s", fmtQualifiedDumpable(tbinfo));
   19641              : 
   19642          492 :     appendPQExpBuffer(query, "%s;\n", tginfo->tgdef);
   19643          492 :     appendPQExpBuffer(delqry, "DROP TRIGGER %s;\n", trigidentity->data);
   19644              : 
   19645              :     /* Triggers can depend on extensions */
   19646          492 :     append_depends_on_extension(fout, query, &tginfo->dobj,
   19647              :                                 "pg_catalog.pg_trigger", "TRIGGER",
   19648          492 :                                 trigidentity->data);
   19649              : 
   19650          492 :     if (tginfo->tgispartition)
   19651              :     {
   19652              :         Assert(tbinfo->ispartition);
   19653              : 
   19654              :         /*
   19655              :          * Partition triggers only appear here because their 'tgenabled' flag
   19656              :          * differs from its parent's.  The trigger is created already, so
   19657              :          * remove the CREATE and replace it with an ALTER.  (Clear out the
   19658              :          * DROP query too, so that pg_dump --create does not cause errors.)
   19659              :          */
   19660          109 :         resetPQExpBuffer(query);
   19661          109 :         resetPQExpBuffer(delqry);
   19662          109 :         appendPQExpBuffer(query, "\nALTER %sTABLE %s ",
   19663          109 :                           tbinfo->relkind == RELKIND_FOREIGN_TABLE ? "FOREIGN " : "",
   19664          109 :                           fmtQualifiedDumpable(tbinfo));
   19665          109 :         switch (tginfo->tgenabled)
   19666              :         {
   19667           38 :             case 'f':
   19668              :             case 'D':
   19669           38 :                 appendPQExpBufferStr(query, "DISABLE");
   19670           38 :                 break;
   19671            0 :             case 't':
   19672              :             case 'O':
   19673            0 :                 appendPQExpBufferStr(query, "ENABLE");
   19674            0 :                 break;
   19675           33 :             case 'R':
   19676           33 :                 appendPQExpBufferStr(query, "ENABLE REPLICA");
   19677           33 :                 break;
   19678           38 :             case 'A':
   19679           38 :                 appendPQExpBufferStr(query, "ENABLE ALWAYS");
   19680           38 :                 break;
   19681              :         }
   19682          109 :         appendPQExpBuffer(query, " TRIGGER %s;\n",
   19683          109 :                           fmtId(tginfo->dobj.name));
   19684              :     }
   19685          383 :     else if (tginfo->tgenabled != 't' && tginfo->tgenabled != 'O')
   19686              :     {
   19687            0 :         appendPQExpBuffer(query, "\nALTER %sTABLE %s ",
   19688            0 :                           tbinfo->relkind == RELKIND_FOREIGN_TABLE ? "FOREIGN " : "",
   19689            0 :                           fmtQualifiedDumpable(tbinfo));
   19690            0 :         switch (tginfo->tgenabled)
   19691              :         {
   19692            0 :             case 'D':
   19693              :             case 'f':
   19694            0 :                 appendPQExpBufferStr(query, "DISABLE");
   19695            0 :                 break;
   19696            0 :             case 'A':
   19697            0 :                 appendPQExpBufferStr(query, "ENABLE ALWAYS");
   19698            0 :                 break;
   19699            0 :             case 'R':
   19700            0 :                 appendPQExpBufferStr(query, "ENABLE REPLICA");
   19701            0 :                 break;
   19702            0 :             default:
   19703            0 :                 appendPQExpBufferStr(query, "ENABLE");
   19704            0 :                 break;
   19705              :         }
   19706            0 :         appendPQExpBuffer(query, " TRIGGER %s;\n",
   19707            0 :                           fmtId(tginfo->dobj.name));
   19708              :     }
   19709              : 
   19710          492 :     appendPQExpBuffer(trigprefix, "TRIGGER %s ON",
   19711          492 :                       fmtId(tginfo->dobj.name));
   19712              : 
   19713          492 :     tag = psprintf("%s %s", tbinfo->dobj.name, tginfo->dobj.name);
   19714              : 
   19715          492 :     if (tginfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   19716          492 :         ArchiveEntry(fout, tginfo->dobj.catId, tginfo->dobj.dumpId,
   19717          492 :                      ARCHIVE_OPTS(.tag = tag,
   19718              :                                   .namespace = tbinfo->dobj.namespace->dobj.name,
   19719              :                                   .owner = tbinfo->rolname,
   19720              :                                   .description = "TRIGGER",
   19721              :                                   .section = SECTION_POST_DATA,
   19722              :                                   .createStmt = query->data,
   19723              :                                   .dropStmt = delqry->data));
   19724              : 
   19725          492 :     if (tginfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   19726            0 :         dumpComment(fout, trigprefix->data, qtabname,
   19727            0 :                     tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
   19728            0 :                     tginfo->dobj.catId, 0, tginfo->dobj.dumpId);
   19729              : 
   19730          492 :     free(tag);
   19731          492 :     destroyPQExpBuffer(query);
   19732          492 :     destroyPQExpBuffer(delqry);
   19733          492 :     destroyPQExpBuffer(trigprefix);
   19734          492 :     destroyPQExpBuffer(trigidentity);
   19735          492 :     free(qtabname);
   19736              : }
   19737              : 
   19738              : /*
   19739              :  * dumpEventTrigger
   19740              :  *    write the declaration of one user-defined event trigger
   19741              :  */
   19742              : static void
   19743           42 : dumpEventTrigger(Archive *fout, const EventTriggerInfo *evtinfo)
   19744              : {
   19745           42 :     DumpOptions *dopt = fout->dopt;
   19746              :     PQExpBuffer query;
   19747              :     PQExpBuffer delqry;
   19748              :     char       *qevtname;
   19749              : 
   19750              :     /* Do nothing if not dumping schema */
   19751           42 :     if (!dopt->dumpSchema)
   19752            6 :         return;
   19753              : 
   19754           36 :     query = createPQExpBuffer();
   19755           36 :     delqry = createPQExpBuffer();
   19756              : 
   19757           36 :     qevtname = pg_strdup(fmtId(evtinfo->dobj.name));
   19758              : 
   19759           36 :     appendPQExpBufferStr(query, "CREATE EVENT TRIGGER ");
   19760           36 :     appendPQExpBufferStr(query, qevtname);
   19761           36 :     appendPQExpBufferStr(query, " ON ");
   19762           36 :     appendPQExpBufferStr(query, fmtId(evtinfo->evtevent));
   19763              : 
   19764           36 :     if (strcmp("", evtinfo->evttags) != 0)
   19765              :     {
   19766            5 :         appendPQExpBufferStr(query, "\n         WHEN TAG IN (");
   19767            5 :         appendPQExpBufferStr(query, evtinfo->evttags);
   19768            5 :         appendPQExpBufferChar(query, ')');
   19769              :     }
   19770              : 
   19771           36 :     appendPQExpBufferStr(query, "\n   EXECUTE FUNCTION ");
   19772           36 :     appendPQExpBufferStr(query, evtinfo->evtfname);
   19773           36 :     appendPQExpBufferStr(query, "();\n");
   19774              : 
   19775           36 :     if (evtinfo->evtenabled != 'O')
   19776              :     {
   19777            0 :         appendPQExpBuffer(query, "\nALTER EVENT TRIGGER %s ",
   19778              :                           qevtname);
   19779            0 :         switch (evtinfo->evtenabled)
   19780              :         {
   19781            0 :             case 'D':
   19782            0 :                 appendPQExpBufferStr(query, "DISABLE");
   19783            0 :                 break;
   19784            0 :             case 'A':
   19785            0 :                 appendPQExpBufferStr(query, "ENABLE ALWAYS");
   19786            0 :                 break;
   19787            0 :             case 'R':
   19788            0 :                 appendPQExpBufferStr(query, "ENABLE REPLICA");
   19789            0 :                 break;
   19790            0 :             default:
   19791            0 :                 appendPQExpBufferStr(query, "ENABLE");
   19792            0 :                 break;
   19793              :         }
   19794            0 :         appendPQExpBufferStr(query, ";\n");
   19795              :     }
   19796              : 
   19797           36 :     appendPQExpBuffer(delqry, "DROP EVENT TRIGGER %s;\n",
   19798              :                       qevtname);
   19799              : 
   19800           36 :     if (dopt->binary_upgrade)
   19801            2 :         binary_upgrade_extension_member(query, &evtinfo->dobj,
   19802              :                                         "EVENT TRIGGER", qevtname, NULL);
   19803              : 
   19804           36 :     if (evtinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   19805           36 :         ArchiveEntry(fout, evtinfo->dobj.catId, evtinfo->dobj.dumpId,
   19806           36 :                      ARCHIVE_OPTS(.tag = evtinfo->dobj.name,
   19807              :                                   .owner = evtinfo->evtowner,
   19808              :                                   .description = "EVENT TRIGGER",
   19809              :                                   .section = SECTION_POST_DATA,
   19810              :                                   .createStmt = query->data,
   19811              :                                   .dropStmt = delqry->data));
   19812              : 
   19813           36 :     if (evtinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   19814            0 :         dumpComment(fout, "EVENT TRIGGER", qevtname,
   19815            0 :                     NULL, evtinfo->evtowner,
   19816            0 :                     evtinfo->dobj.catId, 0, evtinfo->dobj.dumpId);
   19817              : 
   19818           36 :     if (evtinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
   19819            0 :         dumpSecLabel(fout, "EVENT TRIGGER", qevtname,
   19820            0 :                      NULL, evtinfo->evtowner,
   19821            0 :                      evtinfo->dobj.catId, 0, evtinfo->dobj.dumpId);
   19822              : 
   19823           36 :     destroyPQExpBuffer(query);
   19824           36 :     destroyPQExpBuffer(delqry);
   19825           36 :     free(qevtname);
   19826              : }
   19827              : 
   19828              : /*
   19829              :  * dumpRule
   19830              :  *      Dump a rule
   19831              :  */
   19832              : static void
   19833         1129 : dumpRule(Archive *fout, const RuleInfo *rinfo)
   19834              : {
   19835         1129 :     DumpOptions *dopt = fout->dopt;
   19836         1129 :     TableInfo  *tbinfo = rinfo->ruletable;
   19837              :     bool        is_view;
   19838              :     PQExpBuffer query;
   19839              :     PQExpBuffer cmd;
   19840              :     PQExpBuffer delcmd;
   19841              :     PQExpBuffer ruleprefix;
   19842              :     char       *qtabname;
   19843              :     PGresult   *res;
   19844              :     char       *tag;
   19845              : 
   19846              :     /* Do nothing if not dumping schema */
   19847         1129 :     if (!dopt->dumpSchema)
   19848           60 :         return;
   19849              : 
   19850              :     /*
   19851              :      * If it is an ON SELECT rule that is created implicitly by CREATE VIEW,
   19852              :      * we do not want to dump it as a separate object.
   19853              :      */
   19854         1069 :     if (!rinfo->separate)
   19855          858 :         return;
   19856              : 
   19857              :     /*
   19858              :      * If it's an ON SELECT rule, we want to print it as a view definition,
   19859              :      * instead of a rule.
   19860              :      */
   19861          211 :     is_view = (rinfo->ev_type == '1' && rinfo->is_instead);
   19862              : 
   19863          211 :     query = createPQExpBuffer();
   19864          211 :     cmd = createPQExpBuffer();
   19865          211 :     delcmd = createPQExpBuffer();
   19866          211 :     ruleprefix = createPQExpBuffer();
   19867              : 
   19868          211 :     qtabname = pg_strdup(fmtId(tbinfo->dobj.name));
   19869              : 
   19870          211 :     if (is_view)
   19871              :     {
   19872              :         PQExpBuffer result;
   19873              : 
   19874              :         /*
   19875              :          * We need OR REPLACE here because we'll be replacing a dummy view.
   19876              :          * Otherwise this should look largely like the regular view dump code.
   19877              :          */
   19878           10 :         appendPQExpBuffer(cmd, "CREATE OR REPLACE VIEW %s",
   19879           10 :                           fmtQualifiedDumpable(tbinfo));
   19880           10 :         if (nonemptyReloptions(tbinfo->reloptions))
   19881              :         {
   19882            0 :             appendPQExpBufferStr(cmd, " WITH (");
   19883            0 :             appendReloptionsArrayAH(cmd, tbinfo->reloptions, "", fout);
   19884            0 :             appendPQExpBufferChar(cmd, ')');
   19885              :         }
   19886           10 :         result = createViewAsClause(fout, tbinfo);
   19887           10 :         appendPQExpBuffer(cmd, " AS\n%s", result->data);
   19888           10 :         destroyPQExpBuffer(result);
   19889           10 :         if (tbinfo->checkoption != NULL)
   19890            0 :             appendPQExpBuffer(cmd, "\n  WITH %s CHECK OPTION",
   19891              :                               tbinfo->checkoption);
   19892           10 :         appendPQExpBufferStr(cmd, ";\n");
   19893              :     }
   19894              :     else
   19895              :     {
   19896              :         /* In the rule case, just print pg_get_ruledef's result verbatim */
   19897          201 :         appendPQExpBuffer(query,
   19898              :                           "SELECT pg_catalog.pg_get_ruledef('%u'::pg_catalog.oid)",
   19899          201 :                           rinfo->dobj.catId.oid);
   19900              : 
   19901          201 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   19902              : 
   19903          201 :         if (PQntuples(res) != 1)
   19904            0 :             pg_fatal("query to get rule \"%s\" for table \"%s\" failed: wrong number of rows returned",
   19905              :                      rinfo->dobj.name, tbinfo->dobj.name);
   19906              : 
   19907          201 :         printfPQExpBuffer(cmd, "%s\n", PQgetvalue(res, 0, 0));
   19908              : 
   19909          201 :         PQclear(res);
   19910              :     }
   19911              : 
   19912              :     /*
   19913              :      * Add the command to alter the rules replication firing semantics if it
   19914              :      * differs from the default.
   19915              :      */
   19916          211 :     if (rinfo->ev_enabled != 'O')
   19917              :     {
   19918           15 :         appendPQExpBuffer(cmd, "ALTER TABLE %s ", fmtQualifiedDumpable(tbinfo));
   19919           15 :         switch (rinfo->ev_enabled)
   19920              :         {
   19921            0 :             case 'A':
   19922            0 :                 appendPQExpBuffer(cmd, "ENABLE ALWAYS RULE %s;\n",
   19923            0 :                                   fmtId(rinfo->dobj.name));
   19924            0 :                 break;
   19925            0 :             case 'R':
   19926            0 :                 appendPQExpBuffer(cmd, "ENABLE REPLICA RULE %s;\n",
   19927            0 :                                   fmtId(rinfo->dobj.name));
   19928            0 :                 break;
   19929           15 :             case 'D':
   19930           15 :                 appendPQExpBuffer(cmd, "DISABLE RULE %s;\n",
   19931           15 :                                   fmtId(rinfo->dobj.name));
   19932           15 :                 break;
   19933              :         }
   19934              :     }
   19935              : 
   19936          211 :     if (is_view)
   19937              :     {
   19938              :         /*
   19939              :          * We can't DROP a view's ON SELECT rule.  Instead, use CREATE OR
   19940              :          * REPLACE VIEW to replace the rule with something with minimal
   19941              :          * dependencies.
   19942              :          */
   19943              :         PQExpBuffer result;
   19944              : 
   19945           10 :         appendPQExpBuffer(delcmd, "CREATE OR REPLACE VIEW %s",
   19946           10 :                           fmtQualifiedDumpable(tbinfo));
   19947           10 :         result = createDummyViewAsClause(fout, tbinfo);
   19948           10 :         appendPQExpBuffer(delcmd, " AS\n%s;\n", result->data);
   19949           10 :         destroyPQExpBuffer(result);
   19950              :     }
   19951              :     else
   19952              :     {
   19953          201 :         appendPQExpBuffer(delcmd, "DROP RULE %s ",
   19954          201 :                           fmtId(rinfo->dobj.name));
   19955          201 :         appendPQExpBuffer(delcmd, "ON %s;\n",
   19956          201 :                           fmtQualifiedDumpable(tbinfo));
   19957              :     }
   19958              : 
   19959          211 :     appendPQExpBuffer(ruleprefix, "RULE %s ON",
   19960          211 :                       fmtId(rinfo->dobj.name));
   19961              : 
   19962          211 :     tag = psprintf("%s %s", tbinfo->dobj.name, rinfo->dobj.name);
   19963              : 
   19964          211 :     if (rinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   19965          211 :         ArchiveEntry(fout, rinfo->dobj.catId, rinfo->dobj.dumpId,
   19966          211 :                      ARCHIVE_OPTS(.tag = tag,
   19967              :                                   .namespace = tbinfo->dobj.namespace->dobj.name,
   19968              :                                   .owner = tbinfo->rolname,
   19969              :                                   .description = "RULE",
   19970              :                                   .section = SECTION_POST_DATA,
   19971              :                                   .createStmt = cmd->data,
   19972              :                                   .dropStmt = delcmd->data));
   19973              : 
   19974              :     /* Dump rule comments */
   19975          211 :     if (rinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   19976            0 :         dumpComment(fout, ruleprefix->data, qtabname,
   19977            0 :                     tbinfo->dobj.namespace->dobj.name,
   19978              :                     tbinfo->rolname,
   19979            0 :                     rinfo->dobj.catId, 0, rinfo->dobj.dumpId);
   19980              : 
   19981          211 :     free(tag);
   19982          211 :     destroyPQExpBuffer(query);
   19983          211 :     destroyPQExpBuffer(cmd);
   19984          211 :     destroyPQExpBuffer(delcmd);
   19985          211 :     destroyPQExpBuffer(ruleprefix);
   19986          211 :     free(qtabname);
   19987              : }
   19988              : 
   19989              : /*
   19990              :  * getExtensionMembership --- obtain extension membership data
   19991              :  *
   19992              :  * We need to identify objects that are extension members as soon as they're
   19993              :  * loaded, so that we can correctly determine whether they need to be dumped.
   19994              :  * Generally speaking, extension member objects will get marked as *not* to
   19995              :  * be dumped, as they will be recreated by the single CREATE EXTENSION
   19996              :  * command.  However, in binary upgrade mode we still need to dump the members
   19997              :  * individually.
   19998              :  */
   19999              : void
   20000          250 : getExtensionMembership(Archive *fout, ExtensionInfo extinfo[],
   20001              :                        int numExtensions)
   20002              : {
   20003              :     PQExpBuffer query;
   20004              :     PGresult   *res;
   20005              :     int         ntups,
   20006              :                 i;
   20007              :     int         i_classid,
   20008              :                 i_objid,
   20009              :                 i_refobjid;
   20010              :     ExtensionInfo *ext;
   20011              : 
   20012              :     /* Nothing to do if no extensions */
   20013          250 :     if (numExtensions == 0)
   20014            0 :         return;
   20015              : 
   20016          250 :     query = createPQExpBuffer();
   20017              : 
   20018              :     /* refclassid constraint is redundant but may speed the search */
   20019          250 :     appendPQExpBufferStr(query, "SELECT "
   20020              :                          "classid, objid, refobjid "
   20021              :                          "FROM pg_depend "
   20022              :                          "WHERE refclassid = 'pg_extension'::regclass "
   20023              :                          "AND deptype = 'e' "
   20024              :                          "ORDER BY 3");
   20025              : 
   20026          250 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   20027              : 
   20028          250 :     ntups = PQntuples(res);
   20029              : 
   20030          250 :     i_classid = PQfnumber(res, "classid");
   20031          250 :     i_objid = PQfnumber(res, "objid");
   20032          250 :     i_refobjid = PQfnumber(res, "refobjid");
   20033              : 
   20034              :     /*
   20035              :      * Since we ordered the SELECT by referenced ID, we can expect that
   20036              :      * multiple entries for the same extension will appear together; this
   20037              :      * saves on searches.
   20038              :      */
   20039          250 :     ext = NULL;
   20040              : 
   20041         1855 :     for (i = 0; i < ntups; i++)
   20042              :     {
   20043              :         CatalogId   objId;
   20044              :         Oid         extId;
   20045              : 
   20046         1605 :         objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
   20047         1605 :         objId.oid = atooid(PQgetvalue(res, i, i_objid));
   20048         1605 :         extId = atooid(PQgetvalue(res, i, i_refobjid));
   20049              : 
   20050         1605 :         if (ext == NULL ||
   20051         1355 :             ext->dobj.catId.oid != extId)
   20052          280 :             ext = findExtensionByOid(extId);
   20053              : 
   20054         1605 :         if (ext == NULL)
   20055              :         {
   20056              :             /* shouldn't happen */
   20057            0 :             pg_log_warning("could not find referenced extension %u", extId);
   20058            0 :             continue;
   20059              :         }
   20060              : 
   20061         1605 :         recordExtensionMembership(objId, ext);
   20062              :     }
   20063              : 
   20064          250 :     PQclear(res);
   20065              : 
   20066          250 :     destroyPQExpBuffer(query);
   20067              : }
   20068              : 
   20069              : /*
   20070              :  * processExtensionTables --- deal with extension configuration tables
   20071              :  *
   20072              :  * There are two parts to this process:
   20073              :  *
   20074              :  * 1. Identify and create dump records for extension configuration tables.
   20075              :  *
   20076              :  *    Extensions can mark tables as "configuration", which means that the user
   20077              :  *    is able and expected to modify those tables after the extension has been
   20078              :  *    loaded.  For these tables, we dump out only the data- the structure is
   20079              :  *    expected to be handled at CREATE EXTENSION time, including any indexes or
   20080              :  *    foreign keys, which brings us to-
   20081              :  *
   20082              :  * 2. Record FK dependencies between configuration tables.
   20083              :  *
   20084              :  *    Due to the FKs being created at CREATE EXTENSION time and therefore before
   20085              :  *    the data is loaded, we have to work out what the best order for reloading
   20086              :  *    the data is, to avoid FK violations when the tables are restored.  This is
   20087              :  *    not perfect- we can't handle circular dependencies and if any exist they
   20088              :  *    will cause an invalid dump to be produced (though at least all of the data
   20089              :  *    is included for a user to manually restore).  This is currently documented
   20090              :  *    but perhaps we can provide a better solution in the future.
   20091              :  */
   20092              : void
   20093          249 : processExtensionTables(Archive *fout, ExtensionInfo extinfo[],
   20094              :                        int numExtensions)
   20095              : {
   20096          249 :     DumpOptions *dopt = fout->dopt;
   20097              :     PQExpBuffer query;
   20098              :     PGresult   *res;
   20099              :     int         ntups,
   20100              :                 i;
   20101              :     int         i_conrelid,
   20102              :                 i_confrelid;
   20103              : 
   20104              :     /* Nothing to do if no extensions */
   20105          249 :     if (numExtensions == 0)
   20106            0 :         return;
   20107              : 
   20108              :     /*
   20109              :      * Identify extension configuration tables and create TableDataInfo
   20110              :      * objects for them, ensuring their data will be dumped even though the
   20111              :      * tables themselves won't be.
   20112              :      *
   20113              :      * Note that we create TableDataInfo objects even in schema-only mode, ie,
   20114              :      * user data in a configuration table is treated like schema data. This
   20115              :      * seems appropriate since system data in a config table would get
   20116              :      * reloaded by CREATE EXTENSION.  If the extension is not listed in the
   20117              :      * list of extensions to be included, none of its data is dumped.
   20118              :      */
   20119          528 :     for (i = 0; i < numExtensions; i++)
   20120              :     {
   20121          279 :         ExtensionInfo *curext = &(extinfo[i]);
   20122          279 :         char       *extconfig = curext->extconfig;
   20123          279 :         char       *extcondition = curext->extcondition;
   20124          279 :         char      **extconfigarray = NULL;
   20125          279 :         char      **extconditionarray = NULL;
   20126          279 :         int         nconfigitems = 0;
   20127          279 :         int         nconditionitems = 0;
   20128              : 
   20129              :         /*
   20130              :          * Check if this extension is listed as to include in the dump.  If
   20131              :          * not, any table data associated with it is discarded.
   20132              :          */
   20133          279 :         if (extension_include_oids.head != NULL &&
   20134            8 :             !simple_oid_list_member(&extension_include_oids,
   20135              :                                     curext->dobj.catId.oid))
   20136            6 :             continue;
   20137              : 
   20138              :         /*
   20139              :          * Check if this extension is listed as to exclude in the dump.  If
   20140              :          * yes, any table data associated with it is discarded.
   20141              :          */
   20142          279 :         if (extension_exclude_oids.head != NULL &&
   20143            4 :             simple_oid_list_member(&extension_exclude_oids,
   20144              :                                    curext->dobj.catId.oid))
   20145            2 :             continue;
   20146              : 
   20147          273 :         if (strlen(extconfig) != 0 || strlen(extcondition) != 0)
   20148              :         {
   20149              :             int         j;
   20150              : 
   20151           20 :             if (!parsePGArray(extconfig, &extconfigarray, &nconfigitems))
   20152            0 :                 pg_fatal("could not parse %s array", "extconfig");
   20153           20 :             if (!parsePGArray(extcondition, &extconditionarray, &nconditionitems))
   20154            0 :                 pg_fatal("could not parse %s array", "extcondition");
   20155           20 :             if (nconfigitems != nconditionitems)
   20156            0 :                 pg_fatal("mismatched number of configurations and conditions for extension");
   20157              : 
   20158           60 :             for (j = 0; j < nconfigitems; j++)
   20159              :             {
   20160              :                 TableInfo  *configtbl;
   20161           40 :                 Oid         configtbloid = atooid(extconfigarray[j]);
   20162           40 :                 bool        dumpobj =
   20163           40 :                     curext->dobj.dump & DUMP_COMPONENT_DEFINITION;
   20164              : 
   20165           40 :                 configtbl = findTableByOid(configtbloid);
   20166           40 :                 if (configtbl == NULL)
   20167            0 :                     continue;
   20168              : 
   20169              :                 /*
   20170              :                  * Tables of not-to-be-dumped extensions shouldn't be dumped
   20171              :                  * unless the table or its schema is explicitly included
   20172              :                  */
   20173           40 :                 if (!(curext->dobj.dump & DUMP_COMPONENT_DEFINITION))
   20174              :                 {
   20175              :                     /* check table explicitly requested */
   20176            2 :                     if (table_include_oids.head != NULL &&
   20177            0 :                         simple_oid_list_member(&table_include_oids,
   20178              :                                                configtbloid))
   20179            0 :                         dumpobj = true;
   20180              : 
   20181              :                     /* check table's schema explicitly requested */
   20182            2 :                     if (configtbl->dobj.namespace->dobj.dump &
   20183              :                         DUMP_COMPONENT_DATA)
   20184            2 :                         dumpobj = true;
   20185              :                 }
   20186              : 
   20187              :                 /* check table excluded by an exclusion switch */
   20188           44 :                 if (table_exclude_oids.head != NULL &&
   20189            4 :                     simple_oid_list_member(&table_exclude_oids,
   20190              :                                            configtbloid))
   20191            1 :                     dumpobj = false;
   20192              : 
   20193              :                 /* check schema excluded by an exclusion switch */
   20194           40 :                 if (simple_oid_list_member(&schema_exclude_oids,
   20195           40 :                                            configtbl->dobj.namespace->dobj.catId.oid))
   20196            0 :                     dumpobj = false;
   20197              : 
   20198           40 :                 if (dumpobj)
   20199              :                 {
   20200           39 :                     makeTableDataInfo(dopt, configtbl);
   20201           39 :                     if (configtbl->dataObj != NULL)
   20202              :                     {
   20203           39 :                         if (strlen(extconditionarray[j]) > 0)
   20204            0 :                             configtbl->dataObj->filtercond = pg_strdup(extconditionarray[j]);
   20205              :                     }
   20206              :                 }
   20207              :             }
   20208              :         }
   20209          273 :         if (extconfigarray)
   20210           20 :             free(extconfigarray);
   20211          273 :         if (extconditionarray)
   20212           20 :             free(extconditionarray);
   20213              :     }
   20214              : 
   20215              :     /*
   20216              :      * Now that all the TableDataInfo objects have been created for all the
   20217              :      * extensions, check their FK dependencies and register them to try and
   20218              :      * dump the data out in an order that they can be restored in.
   20219              :      *
   20220              :      * Note that this is not a problem for user tables as their FKs are
   20221              :      * recreated after the data has been loaded.
   20222              :      */
   20223              : 
   20224          249 :     query = createPQExpBuffer();
   20225              : 
   20226          249 :     printfPQExpBuffer(query,
   20227              :                       "SELECT conrelid, confrelid "
   20228              :                       "FROM pg_constraint "
   20229              :                       "JOIN pg_depend ON (objid = confrelid) "
   20230              :                       "WHERE contype = 'f' "
   20231              :                       "AND refclassid = 'pg_extension'::regclass "
   20232              :                       "AND classid = 'pg_class'::regclass;");
   20233              : 
   20234          249 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   20235          249 :     ntups = PQntuples(res);
   20236              : 
   20237          249 :     i_conrelid = PQfnumber(res, "conrelid");
   20238          249 :     i_confrelid = PQfnumber(res, "confrelid");
   20239              : 
   20240              :     /* Now get the dependencies and register them */
   20241          249 :     for (i = 0; i < ntups; i++)
   20242              :     {
   20243              :         Oid         conrelid,
   20244              :                     confrelid;
   20245              :         TableInfo  *reftable,
   20246              :                    *contable;
   20247              : 
   20248            0 :         conrelid = atooid(PQgetvalue(res, i, i_conrelid));
   20249            0 :         confrelid = atooid(PQgetvalue(res, i, i_confrelid));
   20250            0 :         contable = findTableByOid(conrelid);
   20251            0 :         reftable = findTableByOid(confrelid);
   20252              : 
   20253            0 :         if (reftable == NULL ||
   20254            0 :             reftable->dataObj == NULL ||
   20255            0 :             contable == NULL ||
   20256            0 :             contable->dataObj == NULL)
   20257            0 :             continue;
   20258              : 
   20259              :         /*
   20260              :          * Make referencing TABLE_DATA object depend on the referenced table's
   20261              :          * TABLE_DATA object.
   20262              :          */
   20263            0 :         addObjectDependency(&contable->dataObj->dobj,
   20264            0 :                             reftable->dataObj->dobj.dumpId);
   20265              :     }
   20266          249 :     PQclear(res);
   20267          249 :     destroyPQExpBuffer(query);
   20268              : }
   20269              : 
   20270              : /*
   20271              :  * getDependencies --- obtain available dependency data
   20272              :  */
   20273              : static void
   20274          249 : getDependencies(Archive *fout)
   20275              : {
   20276              :     PQExpBuffer query;
   20277              :     PGresult   *res;
   20278              :     int         ntups,
   20279              :                 i;
   20280              :     int         i_classid,
   20281              :                 i_objid,
   20282              :                 i_refclassid,
   20283              :                 i_refobjid,
   20284              :                 i_deptype;
   20285              :     DumpableObject *dobj,
   20286              :                *refdobj;
   20287              : 
   20288          249 :     pg_log_info("reading dependency data");
   20289              : 
   20290          249 :     query = createPQExpBuffer();
   20291              : 
   20292              :     /*
   20293              :      * Messy query to collect the dependency data we need.  Note that we
   20294              :      * ignore the sub-object column, so that dependencies of or on a column
   20295              :      * look the same as dependencies of or on a whole table.
   20296              :      *
   20297              :      * PIN dependencies aren't interesting, and EXTENSION dependencies were
   20298              :      * already processed by getExtensionMembership.
   20299              :      */
   20300          249 :     appendPQExpBufferStr(query, "SELECT "
   20301              :                          "classid, objid, refclassid, refobjid, deptype "
   20302              :                          "FROM pg_depend "
   20303              :                          "WHERE deptype != 'p' AND deptype != 'e'\n");
   20304              : 
   20305              :     /*
   20306              :      * Since we don't treat pg_amop entries as separate DumpableObjects, we
   20307              :      * have to translate their dependencies into dependencies of their parent
   20308              :      * opfamily.  Ignore internal dependencies though, as those will point to
   20309              :      * their parent opclass, which we needn't consider here (and if we did,
   20310              :      * it'd just result in circular dependencies).  Also, "loose" opfamily
   20311              :      * entries will have dependencies on their parent opfamily, which we
   20312              :      * should drop since they'd likewise become useless self-dependencies.
   20313              :      * (But be sure to keep deps on *other* opfamilies; see amopsortfamily.)
   20314              :      */
   20315          249 :     appendPQExpBufferStr(query, "UNION ALL\n"
   20316              :                          "SELECT 'pg_opfamily'::regclass AS classid, amopfamily AS objid, refclassid, refobjid, deptype "
   20317              :                          "FROM pg_depend d, pg_amop o "
   20318              :                          "WHERE deptype NOT IN ('p', 'e', 'i') AND "
   20319              :                          "classid = 'pg_amop'::regclass AND objid = o.oid "
   20320              :                          "AND NOT (refclassid = 'pg_opfamily'::regclass AND amopfamily = refobjid)\n");
   20321              : 
   20322              :     /* Likewise for pg_amproc entries */
   20323          249 :     appendPQExpBufferStr(query, "UNION ALL\n"
   20324              :                          "SELECT 'pg_opfamily'::regclass AS classid, amprocfamily AS objid, refclassid, refobjid, deptype "
   20325              :                          "FROM pg_depend d, pg_amproc p "
   20326              :                          "WHERE deptype NOT IN ('p', 'e', 'i') AND "
   20327              :                          "classid = 'pg_amproc'::regclass AND objid = p.oid "
   20328              :                          "AND NOT (refclassid = 'pg_opfamily'::regclass AND amprocfamily = refobjid)\n");
   20329              : 
   20330              :     /* Sort the output for efficiency below */
   20331          249 :     appendPQExpBufferStr(query, "ORDER BY 1,2");
   20332              : 
   20333          249 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   20334              : 
   20335          249 :     ntups = PQntuples(res);
   20336              : 
   20337          249 :     i_classid = PQfnumber(res, "classid");
   20338          249 :     i_objid = PQfnumber(res, "objid");
   20339          249 :     i_refclassid = PQfnumber(res, "refclassid");
   20340          249 :     i_refobjid = PQfnumber(res, "refobjid");
   20341          249 :     i_deptype = PQfnumber(res, "deptype");
   20342              : 
   20343              :     /*
   20344              :      * Since we ordered the SELECT by referencing ID, we can expect that
   20345              :      * multiple entries for the same object will appear together; this saves
   20346              :      * on searches.
   20347              :      */
   20348          249 :     dobj = NULL;
   20349              : 
   20350       513668 :     for (i = 0; i < ntups; i++)
   20351              :     {
   20352              :         CatalogId   objId;
   20353              :         CatalogId   refobjId;
   20354              :         char        deptype;
   20355              : 
   20356       513419 :         objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
   20357       513419 :         objId.oid = atooid(PQgetvalue(res, i, i_objid));
   20358       513419 :         refobjId.tableoid = atooid(PQgetvalue(res, i, i_refclassid));
   20359       513419 :         refobjId.oid = atooid(PQgetvalue(res, i, i_refobjid));
   20360       513419 :         deptype = *(PQgetvalue(res, i, i_deptype));
   20361              : 
   20362       513419 :         if (dobj == NULL ||
   20363       487677 :             dobj->catId.tableoid != objId.tableoid ||
   20364       485162 :             dobj->catId.oid != objId.oid)
   20365       216340 :             dobj = findObjectByCatalogId(objId);
   20366              : 
   20367              :         /*
   20368              :          * Failure to find objects mentioned in pg_depend is not unexpected,
   20369              :          * since for example we don't collect info about TOAST tables.
   20370              :          */
   20371       513419 :         if (dobj == NULL)
   20372              :         {
   20373              : #ifdef NOT_USED
   20374              :             pg_log_warning("no referencing object %u %u",
   20375              :                            objId.tableoid, objId.oid);
   20376              : #endif
   20377        26656 :             continue;
   20378              :         }
   20379              : 
   20380       487926 :         refdobj = findObjectByCatalogId(refobjId);
   20381              : 
   20382       487926 :         if (refdobj == NULL)
   20383              :         {
   20384              : #ifdef NOT_USED
   20385              :             pg_log_warning("no referenced object %u %u",
   20386              :                            refobjId.tableoid, refobjId.oid);
   20387              : #endif
   20388         1163 :             continue;
   20389              :         }
   20390              : 
   20391              :         /*
   20392              :          * For 'x' dependencies, mark the object for later; we still add the
   20393              :          * normal dependency, for possible ordering purposes.  Currently
   20394              :          * pg_dump_sort.c knows to put extensions ahead of all object types
   20395              :          * that could possibly depend on them, but this is safer.
   20396              :          */
   20397       486763 :         if (deptype == 'x')
   20398           44 :             dobj->depends_on_ext = true;
   20399              : 
   20400              :         /*
   20401              :          * Ordinarily, table rowtypes have implicit dependencies on their
   20402              :          * tables.  However, for a composite type the implicit dependency goes
   20403              :          * the other way in pg_depend; which is the right thing for DROP but
   20404              :          * it doesn't produce the dependency ordering we need. So in that one
   20405              :          * case, we reverse the direction of the dependency.
   20406              :          */
   20407       486763 :         if (deptype == 'i' &&
   20408       134928 :             dobj->objType == DO_TABLE &&
   20409         1258 :             refdobj->objType == DO_TYPE)
   20410          182 :             addObjectDependency(refdobj, dobj->dumpId);
   20411              :         else
   20412              :             /* normal case */
   20413       486581 :             addObjectDependency(dobj, refdobj->dumpId);
   20414              :     }
   20415              : 
   20416          249 :     PQclear(res);
   20417              : 
   20418          249 :     destroyPQExpBuffer(query);
   20419          249 : }
   20420              : 
   20421              : 
   20422              : /*
   20423              :  * createBoundaryObjects - create dummy DumpableObjects to represent
   20424              :  * dump section boundaries.
   20425              :  */
   20426              : static DumpableObject *
   20427          249 : createBoundaryObjects(void)
   20428              : {
   20429              :     DumpableObject *dobjs;
   20430              : 
   20431          249 :     dobjs = pg_malloc_array(DumpableObject, 2);
   20432              : 
   20433          249 :     dobjs[0].objType = DO_PRE_DATA_BOUNDARY;
   20434          249 :     dobjs[0].catId = nilCatalogId;
   20435          249 :     AssignDumpId(dobjs + 0);
   20436          249 :     dobjs[0].name = pg_strdup("PRE-DATA BOUNDARY");
   20437              : 
   20438          249 :     dobjs[1].objType = DO_POST_DATA_BOUNDARY;
   20439          249 :     dobjs[1].catId = nilCatalogId;
   20440          249 :     AssignDumpId(dobjs + 1);
   20441          249 :     dobjs[1].name = pg_strdup("POST-DATA BOUNDARY");
   20442              : 
   20443          249 :     return dobjs;
   20444              : }
   20445              : 
   20446              : /*
   20447              :  * addBoundaryDependencies - add dependencies as needed to enforce the dump
   20448              :  * section boundaries.
   20449              :  */
   20450              : static void
   20451          249 : addBoundaryDependencies(DumpableObject **dobjs, int numObjs,
   20452              :                         DumpableObject *boundaryObjs)
   20453              : {
   20454          249 :     DumpableObject *preDataBound = boundaryObjs + 0;
   20455          249 :     DumpableObject *postDataBound = boundaryObjs + 1;
   20456              :     int         i;
   20457              : 
   20458       925955 :     for (i = 0; i < numObjs; i++)
   20459              :     {
   20460       925706 :         DumpableObject *dobj = dobjs[i];
   20461              : 
   20462              :         /*
   20463              :          * The classification of object types here must match the SECTION_xxx
   20464              :          * values assigned during subsequent ArchiveEntry calls!
   20465              :          */
   20466       925706 :         switch (dobj->objType)
   20467              :         {
   20468       870274 :             case DO_NAMESPACE:
   20469              :             case DO_EXTENSION:
   20470              :             case DO_TYPE:
   20471              :             case DO_SHELL_TYPE:
   20472              :             case DO_FUNC:
   20473              :             case DO_AGG:
   20474              :             case DO_OPERATOR:
   20475              :             case DO_ACCESS_METHOD:
   20476              :             case DO_OPCLASS:
   20477              :             case DO_OPFAMILY:
   20478              :             case DO_COLLATION:
   20479              :             case DO_CONVERSION:
   20480              :             case DO_TABLE:
   20481              :             case DO_TABLE_ATTACH:
   20482              :             case DO_ATTRDEF:
   20483              :             case DO_PROCLANG:
   20484              :             case DO_CAST:
   20485              :             case DO_DUMMY_TYPE:
   20486              :             case DO_TSPARSER:
   20487              :             case DO_TSDICT:
   20488              :             case DO_TSTEMPLATE:
   20489              :             case DO_TSCONFIG:
   20490              :             case DO_FDW:
   20491              :             case DO_FOREIGN_SERVER:
   20492              :             case DO_TRANSFORM:
   20493              :                 /* Pre-data objects: must come before the pre-data boundary */
   20494       870274 :                 addObjectDependency(preDataBound, dobj->dumpId);
   20495       870274 :                 break;
   20496         4976 :             case DO_TABLE_DATA:
   20497              :             case DO_SEQUENCE_SET:
   20498              :             case DO_LARGE_OBJECT:
   20499              :             case DO_LARGE_OBJECT_DATA:
   20500              :                 /* Data objects: must come between the boundaries */
   20501         4976 :                 addObjectDependency(dobj, preDataBound->dumpId);
   20502         4976 :                 addObjectDependency(postDataBound, dobj->dumpId);
   20503         4976 :                 break;
   20504         5788 :             case DO_INDEX:
   20505              :             case DO_INDEX_ATTACH:
   20506              :             case DO_STATSEXT:
   20507              :             case DO_REFRESH_MATVIEW:
   20508              :             case DO_TRIGGER:
   20509              :             case DO_EVENT_TRIGGER:
   20510              :             case DO_DEFAULT_ACL:
   20511              :             case DO_POLICY:
   20512              :             case DO_PUBLICATION:
   20513              :             case DO_PUBLICATION_REL:
   20514              :             case DO_PUBLICATION_TABLE_IN_SCHEMA:
   20515              :             case DO_SUBSCRIPTION:
   20516              :             case DO_SUBSCRIPTION_REL:
   20517              :                 /* Post-data objects: must come after the post-data boundary */
   20518         5788 :                 addObjectDependency(dobj, postDataBound->dumpId);
   20519         5788 :                 break;
   20520        38244 :             case DO_RULE:
   20521              :                 /* Rules are post-data, but only if dumped separately */
   20522        38244 :                 if (((RuleInfo *) dobj)->separate)
   20523          771 :                     addObjectDependency(dobj, postDataBound->dumpId);
   20524        38244 :                 break;
   20525         2533 :             case DO_CONSTRAINT:
   20526              :             case DO_FK_CONSTRAINT:
   20527              :                 /* Constraints are post-data, but only if dumped separately */
   20528         2533 :                 if (((ConstraintInfo *) dobj)->separate)
   20529         1825 :                     addObjectDependency(dobj, postDataBound->dumpId);
   20530         2533 :                 break;
   20531          249 :             case DO_PRE_DATA_BOUNDARY:
   20532              :                 /* nothing to do */
   20533          249 :                 break;
   20534          249 :             case DO_POST_DATA_BOUNDARY:
   20535              :                 /* must come after the pre-data boundary */
   20536          249 :                 addObjectDependency(dobj, preDataBound->dumpId);
   20537          249 :                 break;
   20538         3393 :             case DO_REL_STATS:
   20539              :                 /* stats section varies by parent object type, DATA or POST */
   20540         3393 :                 if (((RelStatsInfo *) dobj)->section == SECTION_DATA)
   20541              :                 {
   20542         2213 :                     addObjectDependency(dobj, preDataBound->dumpId);
   20543         2213 :                     addObjectDependency(postDataBound, dobj->dumpId);
   20544              :                 }
   20545              :                 else
   20546         1180 :                     addObjectDependency(dobj, postDataBound->dumpId);
   20547         3393 :                 break;
   20548              :         }
   20549              :     }
   20550          249 : }
   20551              : 
   20552              : 
   20553              : /*
   20554              :  * BuildArchiveDependencies - create dependency data for archive TOC entries
   20555              :  *
   20556              :  * The raw dependency data obtained by getDependencies() is not terribly
   20557              :  * useful in an archive dump, because in many cases there are dependency
   20558              :  * chains linking through objects that don't appear explicitly in the dump.
   20559              :  * For example, a view will depend on its _RETURN rule while the _RETURN rule
   20560              :  * will depend on other objects --- but the rule will not appear as a separate
   20561              :  * object in the dump.  We need to adjust the view's dependencies to include
   20562              :  * whatever the rule depends on that is included in the dump.
   20563              :  *
   20564              :  * Just to make things more complicated, there are also "special" dependencies
   20565              :  * such as the dependency of a TABLE DATA item on its TABLE, which we must
   20566              :  * not rearrange because pg_restore knows that TABLE DATA only depends on
   20567              :  * its table.  In these cases we must leave the dependencies strictly as-is
   20568              :  * even if they refer to not-to-be-dumped objects.
   20569              :  *
   20570              :  * To handle this, the convention is that "special" dependencies are created
   20571              :  * during ArchiveEntry calls, and an archive TOC item that has any such
   20572              :  * entries will not be touched here.  Otherwise, we recursively search the
   20573              :  * DumpableObject data structures to build the correct dependencies for each
   20574              :  * archive TOC item.
   20575              :  */
   20576              : static void
   20577          121 : BuildArchiveDependencies(Archive *fout)
   20578              : {
   20579          121 :     ArchiveHandle *AH = (ArchiveHandle *) fout;
   20580              :     TocEntry   *te;
   20581              : 
   20582              :     /* Scan all TOC entries in the archive */
   20583         7350 :     for (te = AH->toc->next; te != AH->toc; te = te->next)
   20584              :     {
   20585              :         DumpableObject *dobj;
   20586              :         DumpId     *dependencies;
   20587              :         int         nDeps;
   20588              :         int         allocDeps;
   20589              : 
   20590              :         /* No need to process entries that will not be dumped */
   20591         7229 :         if (te->reqs == 0)
   20592         3698 :             continue;
   20593              :         /* Ignore entries that already have "special" dependencies */
   20594         7222 :         if (te->nDeps > 0)
   20595         2981 :             continue;
   20596              :         /* Otherwise, look up the item's original DumpableObject, if any */
   20597         4241 :         dobj = findObjectByDumpId(te->dumpId);
   20598         4241 :         if (dobj == NULL)
   20599          610 :             continue;
   20600              :         /* No work if it has no dependencies */
   20601         3631 :         if (dobj->nDeps <= 0)
   20602          100 :             continue;
   20603              :         /* Set up work array */
   20604         3531 :         allocDeps = 64;
   20605         3531 :         dependencies = pg_malloc_array(DumpId, allocDeps);
   20606         3531 :         nDeps = 0;
   20607              :         /* Recursively find all dumpable dependencies */
   20608         3531 :         findDumpableDependencies(AH, dobj,
   20609              :                                  &dependencies, &nDeps, &allocDeps);
   20610              :         /* And save 'em ... */
   20611         3531 :         if (nDeps > 0)
   20612              :         {
   20613         2531 :             dependencies = pg_realloc_array(dependencies, DumpId, nDeps);
   20614         2531 :             te->dependencies = dependencies;
   20615         2531 :             te->nDeps = nDeps;
   20616              :         }
   20617              :         else
   20618         1000 :             free(dependencies);
   20619              :     }
   20620          121 : }
   20621              : 
   20622              : /* Recursive search subroutine for BuildArchiveDependencies */
   20623              : static void
   20624         8602 : findDumpableDependencies(ArchiveHandle *AH, const DumpableObject *dobj,
   20625              :                          DumpId **dependencies, int *nDeps, int *allocDeps)
   20626              : {
   20627              :     int         i;
   20628              : 
   20629              :     /*
   20630              :      * Ignore section boundary objects: if we search through them, we'll
   20631              :      * report lots of bogus dependencies.
   20632              :      */
   20633         8602 :     if (dobj->objType == DO_PRE_DATA_BOUNDARY ||
   20634         8585 :         dobj->objType == DO_POST_DATA_BOUNDARY)
   20635         1409 :         return;
   20636              : 
   20637        17606 :     for (i = 0; i < dobj->nDeps; i++)
   20638              :     {
   20639        10413 :         DumpId      depid = dobj->dependencies[i];
   20640              : 
   20641        10413 :         if (TocIDRequired(AH, depid) != 0)
   20642              :         {
   20643              :             /* Object will be dumped, so just reference it as a dependency */
   20644         5342 :             if (*nDeps >= *allocDeps)
   20645              :             {
   20646            0 :                 *allocDeps *= 2;
   20647            0 :                 *dependencies = pg_realloc_array(*dependencies, DumpId, *allocDeps);
   20648              :             }
   20649         5342 :             (*dependencies)[*nDeps] = depid;
   20650         5342 :             (*nDeps)++;
   20651              :         }
   20652              :         else
   20653              :         {
   20654              :             /*
   20655              :              * Object will not be dumped, so recursively consider its deps. We
   20656              :              * rely on the assumption that sortDumpableObjects already broke
   20657              :              * any dependency loops, else we might recurse infinitely.
   20658              :              */
   20659         5071 :             DumpableObject *otherdobj = findObjectByDumpId(depid);
   20660              : 
   20661         5071 :             if (otherdobj)
   20662         5071 :                 findDumpableDependencies(AH, otherdobj,
   20663              :                                          dependencies, nDeps, allocDeps);
   20664              :         }
   20665              :     }
   20666              : }
   20667              : 
   20668              : 
   20669              : /*
   20670              :  * getFormattedTypeName - retrieve a nicely-formatted type name for the
   20671              :  * given type OID.
   20672              :  *
   20673              :  * This does not guarantee to schema-qualify the output, so it should not
   20674              :  * be used to create the target object name for CREATE or ALTER commands.
   20675              :  *
   20676              :  * Note that the result is cached and must not be freed by the caller.
   20677              :  */
   20678              : static const char *
   20679         2305 : getFormattedTypeName(Archive *fout, Oid oid, OidOptions opts)
   20680              : {
   20681              :     TypeInfo   *typeInfo;
   20682              :     char       *result;
   20683              :     PQExpBuffer query;
   20684              :     PGresult   *res;
   20685              : 
   20686         2305 :     if (oid == 0)
   20687              :     {
   20688            0 :         if ((opts & zeroAsStar) != 0)
   20689            0 :             return "*";
   20690            0 :         else if ((opts & zeroAsNone) != 0)
   20691            0 :             return "NONE";
   20692              :     }
   20693              : 
   20694              :     /* see if we have the result cached in the type's TypeInfo record */
   20695         2305 :     typeInfo = findTypeByOid(oid);
   20696         2305 :     if (typeInfo && typeInfo->ftypname)
   20697         1838 :         return typeInfo->ftypname;
   20698              : 
   20699          467 :     query = createPQExpBuffer();
   20700          467 :     appendPQExpBuffer(query, "SELECT pg_catalog.format_type('%u'::pg_catalog.oid, NULL)",
   20701              :                       oid);
   20702              : 
   20703          467 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   20704              : 
   20705              :     /* result of format_type is already quoted */
   20706          467 :     result = pg_strdup(PQgetvalue(res, 0, 0));
   20707              : 
   20708          467 :     PQclear(res);
   20709          467 :     destroyPQExpBuffer(query);
   20710              : 
   20711              :     /*
   20712              :      * Cache the result for re-use in later requests, if possible.  If we
   20713              :      * don't have a TypeInfo for the type, the string will be leaked once the
   20714              :      * caller is done with it ... but that case really should not happen, so
   20715              :      * leaking if it does seems acceptable.
   20716              :      */
   20717          467 :     if (typeInfo)
   20718          467 :         typeInfo->ftypname = result;
   20719              : 
   20720          467 :     return result;
   20721              : }
   20722              : 
   20723              : /*
   20724              :  * Return a column list clause for the given relation.
   20725              :  *
   20726              :  * Special case: if there are no undropped columns in the relation, return
   20727              :  * "", not an invalid "()" column list.
   20728              :  */
   20729              : static const char *
   20730         8554 : fmtCopyColumnList(const TableInfo *ti, PQExpBuffer buffer)
   20731              : {
   20732         8554 :     int         numatts = ti->numatts;
   20733         8554 :     char      **attnames = ti->attnames;
   20734         8554 :     bool       *attisdropped = ti->attisdropped;
   20735         8554 :     char       *attgenerated = ti->attgenerated;
   20736              :     bool        needComma;
   20737              :     int         i;
   20738              : 
   20739         8554 :     appendPQExpBufferChar(buffer, '(');
   20740         8554 :     needComma = false;
   20741        40954 :     for (i = 0; i < numatts; i++)
   20742              :     {
   20743        32400 :         if (attisdropped[i])
   20744          598 :             continue;
   20745        31802 :         if (attgenerated[i])
   20746         1104 :             continue;
   20747        30698 :         if (needComma)
   20748        22368 :             appendPQExpBufferStr(buffer, ", ");
   20749        30698 :         appendPQExpBufferStr(buffer, fmtId(attnames[i]));
   20750        30698 :         needComma = true;
   20751              :     }
   20752              : 
   20753         8554 :     if (!needComma)
   20754          224 :         return "";                /* no undropped columns */
   20755              : 
   20756         8330 :     appendPQExpBufferChar(buffer, ')');
   20757         8330 :     return buffer->data;
   20758              : }
   20759              : 
   20760              : /*
   20761              :  * Check if a reloptions array is nonempty.
   20762              :  */
   20763              : static bool
   20764        13918 : nonemptyReloptions(const char *reloptions)
   20765              : {
   20766              :     /* Don't want to print it if it's just "{}" */
   20767        13918 :     return (reloptions != NULL && strlen(reloptions) > 2);
   20768              : }
   20769              : 
   20770              : /*
   20771              :  * Format a reloptions array and append it to the given buffer.
   20772              :  *
   20773              :  * "prefix" is prepended to the option names; typically it's "" or "toast.".
   20774              :  */
   20775              : static void
   20776          219 : appendReloptionsArrayAH(PQExpBuffer buffer, const char *reloptions,
   20777              :                         const char *prefix, Archive *fout)
   20778              : {
   20779              :     bool        res;
   20780              : 
   20781          219 :     res = appendReloptionsArray(buffer, reloptions, prefix, fout->encoding,
   20782          219 :                                 fout->std_strings);
   20783          219 :     if (!res)
   20784            0 :         pg_log_warning("could not parse %s array", "reloptions");
   20785          219 : }
   20786              : 
   20787              : /*
   20788              :  * read_dump_filters - retrieve object identifier patterns from file
   20789              :  *
   20790              :  * Parse the specified filter file for include and exclude patterns, and add
   20791              :  * them to the relevant lists.  If the filename is "-" then filters will be
   20792              :  * read from STDIN rather than a file.
   20793              :  */
   20794              : static void
   20795           26 : read_dump_filters(const char *filename, DumpOptions *dopt)
   20796              : {
   20797              :     FilterStateData fstate;
   20798              :     char       *objname;
   20799              :     FilterCommandType comtype;
   20800              :     FilterObjectType objtype;
   20801              : 
   20802           26 :     filter_init(&fstate, filename, exit_nicely);
   20803              : 
   20804           84 :     while (filter_read_item(&fstate, &objname, &comtype, &objtype))
   20805              :     {
   20806           33 :         if (comtype == FILTER_COMMAND_TYPE_INCLUDE)
   20807              :         {
   20808           17 :             switch (objtype)
   20809              :             {
   20810            0 :                 case FILTER_OBJECT_TYPE_NONE:
   20811            0 :                     break;
   20812            0 :                 case FILTER_OBJECT_TYPE_DATABASE:
   20813              :                 case FILTER_OBJECT_TYPE_FUNCTION:
   20814              :                 case FILTER_OBJECT_TYPE_INDEX:
   20815              :                 case FILTER_OBJECT_TYPE_TABLE_DATA:
   20816              :                 case FILTER_OBJECT_TYPE_TABLE_DATA_AND_CHILDREN:
   20817              :                 case FILTER_OBJECT_TYPE_TRIGGER:
   20818            0 :                     pg_log_filter_error(&fstate, _("%s filter for \"%s\" is not allowed"),
   20819              :                                         "include",
   20820              :                                         filter_object_type_name(objtype));
   20821            0 :                     exit_nicely(1);
   20822              :                     break;      /* unreachable */
   20823              : 
   20824            1 :                 case FILTER_OBJECT_TYPE_EXTENSION:
   20825            1 :                     simple_string_list_append(&extension_include_patterns, objname);
   20826            1 :                     break;
   20827            1 :                 case FILTER_OBJECT_TYPE_FOREIGN_DATA:
   20828            1 :                     simple_string_list_append(&foreign_servers_include_patterns, objname);
   20829            1 :                     break;
   20830            1 :                 case FILTER_OBJECT_TYPE_SCHEMA:
   20831            1 :                     simple_string_list_append(&schema_include_patterns, objname);
   20832            1 :                     dopt->include_everything = false;
   20833            1 :                     break;
   20834           13 :                 case FILTER_OBJECT_TYPE_TABLE:
   20835           13 :                     simple_string_list_append(&table_include_patterns, objname);
   20836           13 :                     dopt->include_everything = false;
   20837           13 :                     break;
   20838            1 :                 case FILTER_OBJECT_TYPE_TABLE_AND_CHILDREN:
   20839            1 :                     simple_string_list_append(&table_include_patterns_and_children,
   20840              :                                               objname);
   20841            1 :                     dopt->include_everything = false;
   20842            1 :                     break;
   20843              :             }
   20844              :         }
   20845           16 :         else if (comtype == FILTER_COMMAND_TYPE_EXCLUDE)
   20846              :         {
   20847            9 :             switch (objtype)
   20848              :             {
   20849            0 :                 case FILTER_OBJECT_TYPE_NONE:
   20850            0 :                     break;
   20851            1 :                 case FILTER_OBJECT_TYPE_DATABASE:
   20852              :                 case FILTER_OBJECT_TYPE_FUNCTION:
   20853              :                 case FILTER_OBJECT_TYPE_INDEX:
   20854              :                 case FILTER_OBJECT_TYPE_TRIGGER:
   20855              :                 case FILTER_OBJECT_TYPE_FOREIGN_DATA:
   20856            1 :                     pg_log_filter_error(&fstate, _("%s filter for \"%s\" is not allowed"),
   20857              :                                         "exclude",
   20858              :                                         filter_object_type_name(objtype));
   20859            1 :                     exit_nicely(1);
   20860              :                     break;
   20861              : 
   20862            1 :                 case FILTER_OBJECT_TYPE_EXTENSION:
   20863            1 :                     simple_string_list_append(&extension_exclude_patterns, objname);
   20864            1 :                     break;
   20865            1 :                 case FILTER_OBJECT_TYPE_TABLE_DATA:
   20866            1 :                     simple_string_list_append(&tabledata_exclude_patterns,
   20867              :                                               objname);
   20868            1 :                     break;
   20869            1 :                 case FILTER_OBJECT_TYPE_TABLE_DATA_AND_CHILDREN:
   20870            1 :                     simple_string_list_append(&tabledata_exclude_patterns_and_children,
   20871              :                                               objname);
   20872            1 :                     break;
   20873            2 :                 case FILTER_OBJECT_TYPE_SCHEMA:
   20874            2 :                     simple_string_list_append(&schema_exclude_patterns, objname);
   20875            2 :                     break;
   20876            2 :                 case FILTER_OBJECT_TYPE_TABLE:
   20877            2 :                     simple_string_list_append(&table_exclude_patterns, objname);
   20878            2 :                     break;
   20879            1 :                 case FILTER_OBJECT_TYPE_TABLE_AND_CHILDREN:
   20880            1 :                     simple_string_list_append(&table_exclude_patterns_and_children,
   20881              :                                               objname);
   20882            1 :                     break;
   20883              :             }
   20884              :         }
   20885              :         else
   20886              :         {
   20887              :             Assert(comtype == FILTER_COMMAND_TYPE_NONE);
   20888              :             Assert(objtype == FILTER_OBJECT_TYPE_NONE);
   20889              :         }
   20890              : 
   20891           32 :         if (objname)
   20892           25 :             free(objname);
   20893              :     }
   20894              : 
   20895           22 :     filter_free(&fstate);
   20896           22 : }
        

Generated by: LCOV version 2.0-1