LCOV - code coverage report
Current view: top level - src/bin/pg_dump - pg_dump.c (source / functions) Coverage Total Hit
Test: PostgreSQL 19devel Lines: 90.9 % 8539 7766
Test Date: 2026-03-23 14:16:05 Functions: 98.9 % 189 187
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /*-------------------------------------------------------------------------
       2              :  *
       3              :  * pg_dump.c
       4              :  *    pg_dump is a utility for dumping out a postgres database
       5              :  *    into a script file.
       6              :  *
       7              :  * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
       8              :  * Portions Copyright (c) 1994, Regents of the University of California
       9              :  *
      10              :  *  pg_dump will read the system catalogs in a database and dump out a
      11              :  *  script that reproduces the schema in terms of SQL that is understood
      12              :  *  by PostgreSQL
      13              :  *
      14              :  *  Note that pg_dump runs in a transaction-snapshot mode transaction,
      15              :  *  so it sees a consistent snapshot of the database including system
      16              :  *  catalogs. However, it relies in part on various specialized backend
      17              :  *  functions like pg_get_indexdef(), and those things tend to look at
      18              :  *  the currently committed state.  So it is possible to get 'cache
      19              :  *  lookup failed' error if someone performs DDL changes while a dump is
      20              :  *  happening. The window for this sort of thing is from the acquisition
      21              :  *  of the transaction snapshot to getSchemaData() (when pg_dump acquires
      22              :  *  AccessShareLock on every table it intends to dump). It isn't very large,
      23              :  *  but it can happen.
      24              :  *
      25              :  *  http://archives.postgresql.org/pgsql-bugs/2010-02/msg00187.php
      26              :  *
      27              :  * IDENTIFICATION
      28              :  *    src/bin/pg_dump/pg_dump.c
      29              :  *
      30              :  *-------------------------------------------------------------------------
      31              :  */
      32              : #include "postgres_fe.h"
      33              : 
      34              : #include <unistd.h>
      35              : #include <ctype.h>
      36              : #include <limits.h>
      37              : #ifdef HAVE_TERMIOS_H
      38              : #include <termios.h>
      39              : #endif
      40              : 
      41              : #include "access/attnum.h"
      42              : #include "access/sysattr.h"
      43              : #include "access/transam.h"
      44              : #include "catalog/pg_aggregate_d.h"
      45              : #include "catalog/pg_am_d.h"
      46              : #include "catalog/pg_attribute_d.h"
      47              : #include "catalog/pg_authid_d.h"
      48              : #include "catalog/pg_cast_d.h"
      49              : #include "catalog/pg_class_d.h"
      50              : #include "catalog/pg_constraint_d.h"
      51              : #include "catalog/pg_default_acl_d.h"
      52              : #include "catalog/pg_largeobject_d.h"
      53              : #include "catalog/pg_largeobject_metadata_d.h"
      54              : #include "catalog/pg_proc_d.h"
      55              : #include "catalog/pg_publication_d.h"
      56              : #include "catalog/pg_shdepend_d.h"
      57              : #include "catalog/pg_subscription_d.h"
      58              : #include "catalog/pg_type_d.h"
      59              : #include "common/connect.h"
      60              : #include "common/int.h"
      61              : #include "common/relpath.h"
      62              : #include "common/shortest_dec.h"
      63              : #include "compress_io.h"
      64              : #include "dumputils.h"
      65              : #include "fe_utils/option_utils.h"
      66              : #include "fe_utils/string_utils.h"
      67              : #include "filter.h"
      68              : #include "getopt_long.h"
      69              : #include "libpq/libpq-fs.h"
      70              : #include "parallel.h"
      71              : #include "pg_backup_db.h"
      72              : #include "pg_backup_utils.h"
      73              : #include "pg_dump.h"
      74              : #include "statistics/statistics_format.h"
      75              : #include "storage/block.h"
      76              : 
      77              : typedef struct
      78              : {
      79              :     Oid         roleoid;        /* role's OID */
      80              :     const char *rolename;       /* role's name */
      81              : } RoleNameItem;
      82              : 
      83              : typedef struct
      84              : {
      85              :     const char *descr;          /* comment for an object */
      86              :     Oid         classoid;       /* object class (catalog OID) */
      87              :     Oid         objoid;         /* object OID */
      88              :     int         objsubid;       /* subobject (table column #) */
      89              : } CommentItem;
      90              : 
      91              : typedef struct
      92              : {
      93              :     const char *provider;       /* label provider of this security label */
      94              :     const char *label;          /* security label for an object */
      95              :     Oid         classoid;       /* object class (catalog OID) */
      96              :     Oid         objoid;         /* object OID */
      97              :     int         objsubid;       /* subobject (table column #) */
      98              : } SecLabelItem;
      99              : 
     100              : typedef struct
     101              : {
     102              :     Oid         oid;            /* object OID */
     103              :     char        relkind;        /* object kind */
     104              :     RelFileNumber relfilenumber;    /* object filenode */
     105              :     Oid         toast_oid;      /* toast table OID */
     106              :     RelFileNumber toast_relfilenumber;  /* toast table filenode */
     107              :     Oid         toast_index_oid;    /* toast table index OID */
     108              :     RelFileNumber toast_index_relfilenumber;    /* toast table index filenode */
     109              : } BinaryUpgradeClassOidItem;
     110              : 
     111              : /* sequence types */
     112              : typedef enum SeqType
     113              : {
     114              :     SEQTYPE_SMALLINT,
     115              :     SEQTYPE_INTEGER,
     116              :     SEQTYPE_BIGINT,
     117              : } SeqType;
     118              : 
     119              : static const char *const SeqTypeNames[] =
     120              : {
     121              :     [SEQTYPE_SMALLINT] = "smallint",
     122              :     [SEQTYPE_INTEGER] = "integer",
     123              :     [SEQTYPE_BIGINT] = "bigint",
     124              : };
     125              : 
     126              : StaticAssertDecl(lengthof(SeqTypeNames) == (SEQTYPE_BIGINT + 1),
     127              :                  "array length mismatch");
     128              : 
     129              : typedef struct
     130              : {
     131              :     Oid         oid;            /* sequence OID */
     132              :     SeqType     seqtype;        /* data type of sequence */
     133              :     bool        cycled;         /* whether sequence cycles */
     134              :     int64       minv;           /* minimum value */
     135              :     int64       maxv;           /* maximum value */
     136              :     int64       startv;         /* start value */
     137              :     int64       incby;          /* increment value */
     138              :     int64       cache;          /* cache size */
     139              :     int64       last_value;     /* last value of sequence */
     140              :     bool        is_called;      /* whether nextval advances before returning */
     141              :     bool        null_seqtuple;  /* did pg_get_sequence_data return nulls? */
     142              : } SequenceItem;
     143              : 
     144              : typedef enum OidOptions
     145              : {
     146              :     zeroIsError = 1,
     147              :     zeroAsStar = 2,
     148              :     zeroAsNone = 4,
     149              : } OidOptions;
     150              : 
     151              : /* global decls */
     152              : static bool dosync = true;      /* Issue fsync() to make dump durable on disk. */
     153              : 
     154              : static Oid  g_last_builtin_oid; /* value of the last builtin oid */
     155              : 
     156              : /* The specified names/patterns should to match at least one entity */
     157              : static int  strict_names = 0;
     158              : 
     159              : static pg_compress_algorithm compression_algorithm = PG_COMPRESSION_NONE;
     160              : 
     161              : /*
     162              :  * Object inclusion/exclusion lists
     163              :  *
     164              :  * The string lists record the patterns given by command-line switches,
     165              :  * which we then convert to lists of OIDs of matching objects.
     166              :  */
     167              : static SimpleStringList schema_include_patterns = {NULL, NULL};
     168              : static SimpleOidList schema_include_oids = {NULL, NULL};
     169              : static SimpleStringList schema_exclude_patterns = {NULL, NULL};
     170              : static SimpleOidList schema_exclude_oids = {NULL, NULL};
     171              : 
     172              : static SimpleStringList table_include_patterns = {NULL, NULL};
     173              : static SimpleStringList table_include_patterns_and_children = {NULL, NULL};
     174              : static SimpleOidList table_include_oids = {NULL, NULL};
     175              : static SimpleStringList table_exclude_patterns = {NULL, NULL};
     176              : static SimpleStringList table_exclude_patterns_and_children = {NULL, NULL};
     177              : static SimpleOidList table_exclude_oids = {NULL, NULL};
     178              : static SimpleStringList tabledata_exclude_patterns = {NULL, NULL};
     179              : static SimpleStringList tabledata_exclude_patterns_and_children = {NULL, NULL};
     180              : static SimpleOidList tabledata_exclude_oids = {NULL, NULL};
     181              : 
     182              : static SimpleStringList foreign_servers_include_patterns = {NULL, NULL};
     183              : static SimpleOidList foreign_servers_include_oids = {NULL, NULL};
     184              : 
     185              : static SimpleStringList extension_include_patterns = {NULL, NULL};
     186              : static SimpleOidList extension_include_oids = {NULL, NULL};
     187              : 
     188              : static SimpleStringList extension_exclude_patterns = {NULL, NULL};
     189              : static SimpleOidList extension_exclude_oids = {NULL, NULL};
     190              : 
     191              : static const CatalogId nilCatalogId = {0, 0};
     192              : 
     193              : /* override for standard extra_float_digits setting */
     194              : static bool have_extra_float_digits = false;
     195              : static int  extra_float_digits;
     196              : 
     197              : /* sorted table of role names */
     198              : static RoleNameItem *rolenames = NULL;
     199              : static int  nrolenames = 0;
     200              : 
     201              : /* sorted table of comments */
     202              : static CommentItem *comments = NULL;
     203              : static int  ncomments = 0;
     204              : 
     205              : /* sorted table of security labels */
     206              : static SecLabelItem *seclabels = NULL;
     207              : static int  nseclabels = 0;
     208              : 
     209              : /* sorted table of pg_class information for binary upgrade */
     210              : static BinaryUpgradeClassOidItem *binaryUpgradeClassOids = NULL;
     211              : static int  nbinaryUpgradeClassOids = 0;
     212              : 
     213              : /* sorted table of sequences */
     214              : static SequenceItem *sequences = NULL;
     215              : static int  nsequences = 0;
     216              : 
     217              : /* Maximum number of relations to fetch in a fetchAttributeStats() call. */
     218              : #define MAX_ATTR_STATS_RELS 64
     219              : 
     220              : /*
     221              :  * The default number of rows per INSERT when
     222              :  * --inserts is specified without --rows-per-insert
     223              :  */
     224              : #define DUMP_DEFAULT_ROWS_PER_INSERT 1
     225              : 
     226              : /*
     227              :  * Maximum number of large objects to group into a single ArchiveEntry.
     228              :  * At some point we might want to make this user-controllable, but for now
     229              :  * a hard-wired setting will suffice.
     230              :  */
     231              : #define MAX_BLOBS_PER_ARCHIVE_ENTRY 1000
     232              : 
     233              : /*
     234              :  * Macro for producing quoted, schema-qualified name of a dumpable object.
     235              :  */
     236              : #define fmtQualifiedDumpable(obj) \
     237              :     fmtQualifiedId((obj)->dobj.namespace->dobj.name, \
     238              :                    (obj)->dobj.name)
     239              : 
     240              : static void help(const char *progname);
     241              : static void setup_connection(Archive *AH,
     242              :                              const char *dumpencoding, const char *dumpsnapshot,
     243              :                              char *use_role);
     244              : static ArchiveFormat parseArchiveFormat(const char *format, ArchiveMode *mode);
     245              : static void expand_schema_name_patterns(Archive *fout,
     246              :                                         SimpleStringList *patterns,
     247              :                                         SimpleOidList *oids,
     248              :                                         bool strict_names);
     249              : static void expand_extension_name_patterns(Archive *fout,
     250              :                                            SimpleStringList *patterns,
     251              :                                            SimpleOidList *oids,
     252              :                                            bool strict_names);
     253              : static void expand_foreign_server_name_patterns(Archive *fout,
     254              :                                                 SimpleStringList *patterns,
     255              :                                                 SimpleOidList *oids);
     256              : static void expand_table_name_patterns(Archive *fout,
     257              :                                        SimpleStringList *patterns,
     258              :                                        SimpleOidList *oids,
     259              :                                        bool strict_names,
     260              :                                        bool with_child_tables);
     261              : static void prohibit_crossdb_refs(PGconn *conn, const char *dbname,
     262              :                                   const char *pattern);
     263              : 
     264              : static NamespaceInfo *findNamespace(Oid nsoid);
     265              : static void dumpTableData(Archive *fout, const TableDataInfo *tdinfo);
     266              : static void refreshMatViewData(Archive *fout, const TableDataInfo *tdinfo);
     267              : static const char *getRoleName(const char *roleoid_str);
     268              : static void collectRoleNames(Archive *fout);
     269              : static void getAdditionalACLs(Archive *fout);
     270              : static void dumpCommentExtended(Archive *fout, const char *type,
     271              :                                 const char *name, const char *namespace,
     272              :                                 const char *owner, CatalogId catalogId,
     273              :                                 int subid, DumpId dumpId,
     274              :                                 const char *initdb_comment);
     275              : static inline void dumpComment(Archive *fout, const char *type,
     276              :                                const char *name, const char *namespace,
     277              :                                const char *owner, CatalogId catalogId,
     278              :                                int subid, DumpId dumpId);
     279              : static int  findComments(Oid classoid, Oid objoid, CommentItem **items);
     280              : static void collectComments(Archive *fout);
     281              : static void dumpSecLabel(Archive *fout, const char *type, const char *name,
     282              :                          const char *namespace, const char *owner,
     283              :                          CatalogId catalogId, int subid, DumpId dumpId);
     284              : static int  findSecLabels(Oid classoid, Oid objoid, SecLabelItem **items);
     285              : static void collectSecLabels(Archive *fout);
     286              : static void dumpDumpableObject(Archive *fout, DumpableObject *dobj);
     287              : static void dumpNamespace(Archive *fout, const NamespaceInfo *nspinfo);
     288              : static void dumpExtension(Archive *fout, const ExtensionInfo *extinfo);
     289              : static void dumpType(Archive *fout, const TypeInfo *tyinfo);
     290              : static void dumpBaseType(Archive *fout, const TypeInfo *tyinfo);
     291              : static void dumpEnumType(Archive *fout, const TypeInfo *tyinfo);
     292              : static void dumpRangeType(Archive *fout, const TypeInfo *tyinfo);
     293              : static void dumpUndefinedType(Archive *fout, const TypeInfo *tyinfo);
     294              : static void dumpDomain(Archive *fout, const TypeInfo *tyinfo);
     295              : static void dumpCompositeType(Archive *fout, const TypeInfo *tyinfo);
     296              : static void dumpCompositeTypeColComments(Archive *fout, const TypeInfo *tyinfo,
     297              :                                          PGresult *res);
     298              : static void dumpShellType(Archive *fout, const ShellTypeInfo *stinfo);
     299              : static void dumpProcLang(Archive *fout, const ProcLangInfo *plang);
     300              : static void dumpFunc(Archive *fout, const FuncInfo *finfo);
     301              : static void dumpCast(Archive *fout, const CastInfo *cast);
     302              : static void dumpTransform(Archive *fout, const TransformInfo *transform);
     303              : static void dumpOpr(Archive *fout, const OprInfo *oprinfo);
     304              : static void dumpAccessMethod(Archive *fout, const AccessMethodInfo *aminfo);
     305              : static void dumpOpclass(Archive *fout, const OpclassInfo *opcinfo);
     306              : static void dumpOpfamily(Archive *fout, const OpfamilyInfo *opfinfo);
     307              : static void dumpCollation(Archive *fout, const CollInfo *collinfo);
     308              : static void dumpConversion(Archive *fout, const ConvInfo *convinfo);
     309              : static void dumpRule(Archive *fout, const RuleInfo *rinfo);
     310              : static void dumpAgg(Archive *fout, const AggInfo *agginfo);
     311              : static void dumpTrigger(Archive *fout, const TriggerInfo *tginfo);
     312              : static void dumpEventTrigger(Archive *fout, const EventTriggerInfo *evtinfo);
     313              : static void dumpTable(Archive *fout, const TableInfo *tbinfo);
     314              : static void dumpTableSchema(Archive *fout, const TableInfo *tbinfo);
     315              : static void dumpTableAttach(Archive *fout, const TableAttachInfo *attachinfo);
     316              : static void dumpAttrDef(Archive *fout, const AttrDefInfo *adinfo);
     317              : static void collectSequences(Archive *fout);
     318              : static void dumpSequence(Archive *fout, const TableInfo *tbinfo);
     319              : static void dumpSequenceData(Archive *fout, const TableDataInfo *tdinfo);
     320              : static void dumpIndex(Archive *fout, const IndxInfo *indxinfo);
     321              : static void dumpIndexAttach(Archive *fout, const IndexAttachInfo *attachinfo);
     322              : static void dumpStatisticsExt(Archive *fout, const StatsExtInfo *statsextinfo);
     323              : static void dumpStatisticsExtStats(Archive *fout, const StatsExtInfo *statsextinfo);
     324              : static void dumpConstraint(Archive *fout, const ConstraintInfo *coninfo);
     325              : static void dumpTableConstraintComment(Archive *fout, const ConstraintInfo *coninfo);
     326              : static void dumpTSParser(Archive *fout, const TSParserInfo *prsinfo);
     327              : static void dumpTSDictionary(Archive *fout, const TSDictInfo *dictinfo);
     328              : static void dumpTSTemplate(Archive *fout, const TSTemplateInfo *tmplinfo);
     329              : static void dumpTSConfig(Archive *fout, const TSConfigInfo *cfginfo);
     330              : static void dumpForeignDataWrapper(Archive *fout, const FdwInfo *fdwinfo);
     331              : static void dumpForeignServer(Archive *fout, const ForeignServerInfo *srvinfo);
     332              : static void dumpUserMappings(Archive *fout,
     333              :                              const char *servername, const char *namespace,
     334              :                              const char *owner, CatalogId catalogId, DumpId dumpId);
     335              : static void dumpDefaultACL(Archive *fout, const DefaultACLInfo *daclinfo);
     336              : 
     337              : static DumpId dumpACL(Archive *fout, DumpId objDumpId, DumpId altDumpId,
     338              :                       const char *type, const char *name, const char *subname,
     339              :                       const char *nspname, const char *tag, const char *owner,
     340              :                       const DumpableAcl *dacl);
     341              : 
     342              : static void getDependencies(Archive *fout);
     343              : static void BuildArchiveDependencies(Archive *fout);
     344              : static void findDumpableDependencies(ArchiveHandle *AH, const DumpableObject *dobj,
     345              :                                      DumpId **dependencies, int *nDeps, int *allocDeps);
     346              : 
     347              : static DumpableObject *createBoundaryObjects(void);
     348              : static void addBoundaryDependencies(DumpableObject **dobjs, int numObjs,
     349              :                                     DumpableObject *boundaryObjs);
     350              : 
     351              : static void addConstrChildIdxDeps(DumpableObject *dobj, const IndxInfo *refidx);
     352              : static void getDomainConstraints(Archive *fout, TypeInfo *tyinfo);
     353              : static void getTableData(DumpOptions *dopt, TableInfo *tblinfo, int numTables, char relkind);
     354              : static void makeTableDataInfo(DumpOptions *dopt, TableInfo *tbinfo);
     355              : static void buildMatViewRefreshDependencies(Archive *fout);
     356              : static void getTableDataFKConstraints(void);
     357              : static void determineNotNullFlags(Archive *fout, PGresult *res, int r,
     358              :                                   TableInfo *tbinfo, int j,
     359              :                                   int i_notnull_name,
     360              :                                   int i_notnull_comment,
     361              :                                   int i_notnull_invalidoid,
     362              :                                   int i_notnull_noinherit,
     363              :                                   int i_notnull_islocal,
     364              :                                   PQExpBuffer *invalidnotnulloids);
     365              : static char *format_function_arguments(const FuncInfo *finfo, const char *funcargs,
     366              :                                        bool is_agg);
     367              : static char *format_function_signature(Archive *fout,
     368              :                                        const FuncInfo *finfo, bool honor_quotes);
     369              : static char *convertRegProcReference(const char *proc);
     370              : static char *getFormattedOperatorName(const char *oproid);
     371              : static char *convertTSFunction(Archive *fout, Oid funcOid);
     372              : static const char *getFormattedTypeName(Archive *fout, Oid oid, OidOptions opts);
     373              : static void getLOs(Archive *fout);
     374              : static void dumpLO(Archive *fout, const LoInfo *loinfo);
     375              : static int  dumpLOs(Archive *fout, const void *arg);
     376              : static void dumpPolicy(Archive *fout, const PolicyInfo *polinfo);
     377              : static void dumpPublication(Archive *fout, const PublicationInfo *pubinfo);
     378              : static void dumpPublicationTable(Archive *fout, const PublicationRelInfo *pubrinfo);
     379              : static void dumpSubscription(Archive *fout, const SubscriptionInfo *subinfo);
     380              : static void dumpSubscriptionTable(Archive *fout, const SubRelInfo *subrinfo);
     381              : static void dumpDatabase(Archive *fout);
     382              : static void dumpDatabaseConfig(Archive *AH, PQExpBuffer outbuf,
     383              :                                const char *dbname, Oid dboid);
     384              : static void dumpEncoding(Archive *AH);
     385              : static void dumpStdStrings(Archive *AH);
     386              : static void dumpSearchPath(Archive *AH);
     387              : static void binary_upgrade_set_type_oids_by_type_oid(Archive *fout,
     388              :                                                      PQExpBuffer upgrade_buffer,
     389              :                                                      Oid pg_type_oid,
     390              :                                                      bool force_array_type,
     391              :                                                      bool include_multirange_type);
     392              : static void binary_upgrade_set_type_oids_by_rel(Archive *fout,
     393              :                                                 PQExpBuffer upgrade_buffer,
     394              :                                                 const TableInfo *tbinfo);
     395              : static void collectBinaryUpgradeClassOids(Archive *fout);
     396              : static void binary_upgrade_set_pg_class_oids(Archive *fout,
     397              :                                              PQExpBuffer upgrade_buffer,
     398              :                                              Oid pg_class_oid);
     399              : static void binary_upgrade_extension_member(PQExpBuffer upgrade_buffer,
     400              :                                             const DumpableObject *dobj,
     401              :                                             const char *objtype,
     402              :                                             const char *objname,
     403              :                                             const char *objnamespace);
     404              : static const char *getAttrName(int attrnum, const TableInfo *tblInfo);
     405              : static const char *fmtCopyColumnList(const TableInfo *ti, PQExpBuffer buffer);
     406              : static bool nonemptyReloptions(const char *reloptions);
     407              : static void appendReloptionsArrayAH(PQExpBuffer buffer, const char *reloptions,
     408              :                                     const char *prefix, Archive *fout);
     409              : static char *get_synchronized_snapshot(Archive *fout);
     410              : static void set_restrict_relation_kind(Archive *AH, const char *value);
     411              : static void setupDumpWorker(Archive *AH);
     412              : static TableInfo *getRootTableInfo(const TableInfo *tbinfo);
     413              : static bool forcePartitionRootLoad(const TableInfo *tbinfo);
     414              : static void read_dump_filters(const char *filename, DumpOptions *dopt);
     415              : 
     416              : 
     417              : int
     418          389 : main(int argc, char **argv)
     419              : {
     420              :     int         c;
     421          389 :     const char *filename = NULL;
     422          389 :     const char *format = "p";
     423              :     TableInfo  *tblinfo;
     424              :     int         numTables;
     425              :     DumpableObject **dobjs;
     426              :     int         numObjs;
     427              :     DumpableObject *boundaryObjs;
     428              :     int         i;
     429              :     int         optindex;
     430              :     RestoreOptions *ropt;
     431              :     Archive    *fout;           /* the script file */
     432          389 :     bool        g_verbose = false;
     433          389 :     const char *dumpencoding = NULL;
     434          389 :     const char *dumpsnapshot = NULL;
     435          389 :     char       *use_role = NULL;
     436          389 :     int         numWorkers = 1;
     437          389 :     int         plainText = 0;
     438          389 :     ArchiveFormat archiveFormat = archUnknown;
     439              :     ArchiveMode archiveMode;
     440          389 :     pg_compress_specification compression_spec = {0};
     441          389 :     char       *compression_detail = NULL;
     442          389 :     char       *compression_algorithm_str = "none";
     443          389 :     char       *error_detail = NULL;
     444          389 :     bool        user_compression_defined = false;
     445          389 :     DataDirSyncMethod sync_method = DATA_DIR_SYNC_METHOD_FSYNC;
     446          389 :     bool        data_only = false;
     447          389 :     bool        schema_only = false;
     448          389 :     bool        statistics_only = false;
     449          389 :     bool        with_statistics = false;
     450          389 :     bool        no_data = false;
     451          389 :     bool        no_schema = false;
     452          389 :     bool        no_statistics = false;
     453              : 
     454              :     static DumpOptions dopt;
     455              : 
     456              :     static struct option long_options[] = {
     457              :         {"data-only", no_argument, NULL, 'a'},
     458              :         {"blobs", no_argument, NULL, 'b'},
     459              :         {"large-objects", no_argument, NULL, 'b'},
     460              :         {"no-blobs", no_argument, NULL, 'B'},
     461              :         {"no-large-objects", no_argument, NULL, 'B'},
     462              :         {"clean", no_argument, NULL, 'c'},
     463              :         {"create", no_argument, NULL, 'C'},
     464              :         {"dbname", required_argument, NULL, 'd'},
     465              :         {"extension", required_argument, NULL, 'e'},
     466              :         {"file", required_argument, NULL, 'f'},
     467              :         {"format", required_argument, NULL, 'F'},
     468              :         {"host", required_argument, NULL, 'h'},
     469              :         {"jobs", 1, NULL, 'j'},
     470              :         {"no-reconnect", no_argument, NULL, 'R'},
     471              :         {"no-owner", no_argument, NULL, 'O'},
     472              :         {"port", required_argument, NULL, 'p'},
     473              :         {"schema", required_argument, NULL, 'n'},
     474              :         {"exclude-schema", required_argument, NULL, 'N'},
     475              :         {"schema-only", no_argument, NULL, 's'},
     476              :         {"superuser", required_argument, NULL, 'S'},
     477              :         {"table", required_argument, NULL, 't'},
     478              :         {"exclude-table", required_argument, NULL, 'T'},
     479              :         {"no-password", no_argument, NULL, 'w'},
     480              :         {"password", no_argument, NULL, 'W'},
     481              :         {"username", required_argument, NULL, 'U'},
     482              :         {"verbose", no_argument, NULL, 'v'},
     483              :         {"no-privileges", no_argument, NULL, 'x'},
     484              :         {"no-acl", no_argument, NULL, 'x'},
     485              :         {"compress", required_argument, NULL, 'Z'},
     486              :         {"encoding", required_argument, NULL, 'E'},
     487              :         {"help", no_argument, NULL, '?'},
     488              :         {"version", no_argument, NULL, 'V'},
     489              : 
     490              :         /*
     491              :          * the following options don't have an equivalent short option letter
     492              :          */
     493              :         {"attribute-inserts", no_argument, &dopt.column_inserts, 1},
     494              :         {"binary-upgrade", no_argument, &dopt.binary_upgrade, 1},
     495              :         {"column-inserts", no_argument, &dopt.column_inserts, 1},
     496              :         {"disable-dollar-quoting", no_argument, &dopt.disable_dollar_quoting, 1},
     497              :         {"disable-triggers", no_argument, &dopt.disable_triggers, 1},
     498              :         {"enable-row-security", no_argument, &dopt.enable_row_security, 1},
     499              :         {"exclude-table-data", required_argument, NULL, 4},
     500              :         {"extra-float-digits", required_argument, NULL, 8},
     501              :         {"if-exists", no_argument, &dopt.if_exists, 1},
     502              :         {"inserts", no_argument, NULL, 9},
     503              :         {"lock-wait-timeout", required_argument, NULL, 2},
     504              :         {"no-table-access-method", no_argument, &dopt.outputNoTableAm, 1},
     505              :         {"no-tablespaces", no_argument, &dopt.outputNoTablespaces, 1},
     506              :         {"quote-all-identifiers", no_argument, &quote_all_identifiers, 1},
     507              :         {"load-via-partition-root", no_argument, &dopt.load_via_partition_root, 1},
     508              :         {"role", required_argument, NULL, 3},
     509              :         {"section", required_argument, NULL, 5},
     510              :         {"serializable-deferrable", no_argument, &dopt.serializable_deferrable, 1},
     511              :         {"snapshot", required_argument, NULL, 6},
     512              :         {"statistics", no_argument, NULL, 22},
     513              :         {"statistics-only", no_argument, NULL, 18},
     514              :         {"strict-names", no_argument, &strict_names, 1},
     515              :         {"use-set-session-authorization", no_argument, &dopt.use_setsessauth, 1},
     516              :         {"no-comments", no_argument, &dopt.no_comments, 1},
     517              :         {"no-data", no_argument, NULL, 19},
     518              :         {"no-policies", no_argument, &dopt.no_policies, 1},
     519              :         {"no-publications", no_argument, &dopt.no_publications, 1},
     520              :         {"no-schema", no_argument, NULL, 20},
     521              :         {"no-security-labels", no_argument, &dopt.no_security_labels, 1},
     522              :         {"no-statistics", no_argument, NULL, 21},
     523              :         {"no-subscriptions", no_argument, &dopt.no_subscriptions, 1},
     524              :         {"no-toast-compression", no_argument, &dopt.no_toast_compression, 1},
     525              :         {"no-unlogged-table-data", no_argument, &dopt.no_unlogged_table_data, 1},
     526              :         {"no-sync", no_argument, NULL, 7},
     527              :         {"on-conflict-do-nothing", no_argument, &dopt.do_nothing, 1},
     528              :         {"rows-per-insert", required_argument, NULL, 10},
     529              :         {"include-foreign-data", required_argument, NULL, 11},
     530              :         {"table-and-children", required_argument, NULL, 12},
     531              :         {"exclude-table-and-children", required_argument, NULL, 13},
     532              :         {"exclude-table-data-and-children", required_argument, NULL, 14},
     533              :         {"sync-method", required_argument, NULL, 15},
     534              :         {"filter", required_argument, NULL, 16},
     535              :         {"exclude-extension", required_argument, NULL, 17},
     536              :         {"sequence-data", no_argument, &dopt.sequence_data, 1},
     537              :         {"restrict-key", required_argument, NULL, 25},
     538              : 
     539              :         {NULL, 0, NULL, 0}
     540              :     };
     541              : 
     542          389 :     pg_logging_init(argv[0]);
     543          389 :     pg_logging_set_level(PG_LOG_WARNING);
     544          389 :     set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_dump"));
     545              : 
     546              :     /*
     547              :      * Initialize what we need for parallel execution, especially for thread
     548              :      * support on Windows.
     549              :      */
     550          389 :     init_parallel_dump_utils();
     551              : 
     552          389 :     progname = get_progname(argv[0]);
     553              : 
     554          389 :     if (argc > 1)
     555              :     {
     556          389 :         if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
     557              :         {
     558            1 :             help(progname);
     559            1 :             exit_nicely(0);
     560              :         }
     561          388 :         if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
     562              :         {
     563           84 :             puts("pg_dump (PostgreSQL) " PG_VERSION);
     564           84 :             exit_nicely(0);
     565              :         }
     566              :     }
     567              : 
     568          304 :     InitDumpOptions(&dopt);
     569              : 
     570         1673 :     while ((c = getopt_long(argc, argv, "abBcCd:e:E:f:F:h:j:n:N:Op:RsS:t:T:U:vwWxXZ:",
     571         1673 :                             long_options, &optindex)) != -1)
     572              :     {
     573         1377 :         switch (c)
     574              :         {
     575            9 :             case 'a':           /* Dump data only */
     576            9 :                 data_only = true;
     577            9 :                 break;
     578              : 
     579            1 :             case 'b':           /* Dump LOs */
     580            1 :                 dopt.outputLOs = true;
     581            1 :                 break;
     582              : 
     583            2 :             case 'B':           /* Don't dump LOs */
     584            2 :                 dopt.dontOutputLOs = true;
     585            2 :                 break;
     586              : 
     587            6 :             case 'c':           /* clean (i.e., drop) schema prior to create */
     588            6 :                 dopt.outputClean = 1;
     589            6 :                 break;
     590              : 
     591           82 :             case 'C':           /* Create DB */
     592           82 :                 dopt.outputCreateDB = 1;
     593           82 :                 break;
     594              : 
     595            5 :             case 'd':           /* database name */
     596            5 :                 dopt.cparams.dbname = pg_strdup(optarg);
     597            5 :                 break;
     598              : 
     599            4 :             case 'e':           /* include extension(s) */
     600            4 :                 simple_string_list_append(&extension_include_patterns, optarg);
     601            4 :                 dopt.include_everything = false;
     602            4 :                 break;
     603              : 
     604            2 :             case 'E':           /* Dump encoding */
     605            2 :                 dumpencoding = pg_strdup(optarg);
     606            2 :                 break;
     607              : 
     608          336 :             case 'f':
     609          336 :                 filename = pg_strdup(optarg);
     610          336 :                 break;
     611              : 
     612          184 :             case 'F':
     613          184 :                 format = pg_strdup(optarg);
     614          184 :                 break;
     615              : 
     616           38 :             case 'h':           /* server host */
     617           38 :                 dopt.cparams.pghost = pg_strdup(optarg);
     618           38 :                 break;
     619              : 
     620           11 :             case 'j':           /* number of dump jobs */
     621           11 :                 if (!option_parse_int(optarg, "-j/--jobs", 1,
     622              :                                       PG_MAX_JOBS,
     623              :                                       &numWorkers))
     624            1 :                     exit_nicely(1);
     625           10 :                 break;
     626              : 
     627           17 :             case 'n':           /* include schema(s) */
     628           17 :                 simple_string_list_append(&schema_include_patterns, optarg);
     629           17 :                 dopt.include_everything = false;
     630           17 :                 break;
     631              : 
     632            1 :             case 'N':           /* exclude schema(s) */
     633            1 :                 simple_string_list_append(&schema_exclude_patterns, optarg);
     634            1 :                 break;
     635              : 
     636            2 :             case 'O':           /* Don't reconnect to match owner */
     637            2 :                 dopt.outputNoOwner = 1;
     638            2 :                 break;
     639              : 
     640           77 :             case 'p':           /* server port */
     641           77 :                 dopt.cparams.pgport = pg_strdup(optarg);
     642           77 :                 break;
     643              : 
     644            2 :             case 'R':
     645              :                 /* no-op, still accepted for backwards compatibility */
     646            2 :                 break;
     647              : 
     648            7 :             case 's':           /* dump schema only */
     649            7 :                 schema_only = true;
     650            7 :                 break;
     651              : 
     652            1 :             case 'S':           /* Username for superuser in plain text output */
     653            1 :                 dopt.outputSuperuser = pg_strdup(optarg);
     654            1 :                 break;
     655              : 
     656            8 :             case 't':           /* include table(s) */
     657            8 :                 simple_string_list_append(&table_include_patterns, optarg);
     658            8 :                 dopt.include_everything = false;
     659            8 :                 break;
     660              : 
     661            4 :             case 'T':           /* exclude table(s) */
     662            4 :                 simple_string_list_append(&table_exclude_patterns, optarg);
     663            4 :                 break;
     664              : 
     665           40 :             case 'U':
     666           40 :                 dopt.cparams.username = pg_strdup(optarg);
     667           40 :                 break;
     668              : 
     669            6 :             case 'v':           /* verbose */
     670            6 :                 g_verbose = true;
     671            6 :                 pg_logging_increase_verbosity();
     672            6 :                 break;
     673              : 
     674            1 :             case 'w':
     675            1 :                 dopt.cparams.promptPassword = TRI_NO;
     676            1 :                 break;
     677              : 
     678            0 :             case 'W':
     679            0 :                 dopt.cparams.promptPassword = TRI_YES;
     680            0 :                 break;
     681              : 
     682            2 :             case 'x':           /* skip ACL dump */
     683            2 :                 dopt.aclsSkip = true;
     684            2 :                 break;
     685              : 
     686           13 :             case 'Z':           /* Compression */
     687           13 :                 parse_compress_options(optarg, &compression_algorithm_str,
     688              :                                        &compression_detail);
     689           13 :                 user_compression_defined = true;
     690           13 :                 break;
     691              : 
     692          141 :             case 0:
     693              :                 /* This covers the long options. */
     694          141 :                 break;
     695              : 
     696            2 :             case 2:             /* lock-wait-timeout */
     697            2 :                 dopt.lockWaitTimeout = pg_strdup(optarg);
     698            2 :                 break;
     699              : 
     700            3 :             case 3:             /* SET ROLE */
     701            3 :                 use_role = pg_strdup(optarg);
     702            3 :                 break;
     703              : 
     704            1 :             case 4:             /* exclude table(s) data */
     705            1 :                 simple_string_list_append(&tabledata_exclude_patterns, optarg);
     706            1 :                 break;
     707              : 
     708            6 :             case 5:             /* section */
     709            6 :                 set_dump_section(optarg, &dopt.dumpSections);
     710            6 :                 break;
     711              : 
     712            0 :             case 6:             /* snapshot */
     713            0 :                 dumpsnapshot = pg_strdup(optarg);
     714            0 :                 break;
     715              : 
     716          151 :             case 7:             /* no-sync */
     717          151 :                 dosync = false;
     718          151 :                 break;
     719              : 
     720            1 :             case 8:
     721            1 :                 have_extra_float_digits = true;
     722            1 :                 if (!option_parse_int(optarg, "--extra-float-digits", -15, 3,
     723              :                                       &extra_float_digits))
     724            1 :                     exit_nicely(1);
     725            0 :                 break;
     726              : 
     727            2 :             case 9:             /* inserts */
     728              : 
     729              :                 /*
     730              :                  * dump_inserts also stores --rows-per-insert, careful not to
     731              :                  * overwrite that.
     732              :                  */
     733            2 :                 if (dopt.dump_inserts == 0)
     734            2 :                     dopt.dump_inserts = DUMP_DEFAULT_ROWS_PER_INSERT;
     735            2 :                 break;
     736              : 
     737            2 :             case 10:            /* rows per insert */
     738            2 :                 if (!option_parse_int(optarg, "--rows-per-insert", 1, INT_MAX,
     739              :                                       &dopt.dump_inserts))
     740            1 :                     exit_nicely(1);
     741            1 :                 break;
     742              : 
     743            4 :             case 11:            /* include foreign data */
     744            4 :                 simple_string_list_append(&foreign_servers_include_patterns,
     745              :                                           optarg);
     746            4 :                 break;
     747              : 
     748            1 :             case 12:            /* include table(s) and their children */
     749            1 :                 simple_string_list_append(&table_include_patterns_and_children,
     750              :                                           optarg);
     751            1 :                 dopt.include_everything = false;
     752            1 :                 break;
     753              : 
     754            1 :             case 13:            /* exclude table(s) and their children */
     755            1 :                 simple_string_list_append(&table_exclude_patterns_and_children,
     756              :                                           optarg);
     757            1 :                 break;
     758              : 
     759            1 :             case 14:            /* exclude data of table(s) and children */
     760            1 :                 simple_string_list_append(&tabledata_exclude_patterns_and_children,
     761              :                                           optarg);
     762            1 :                 break;
     763              : 
     764            0 :             case 15:
     765            0 :                 if (!parse_sync_method(optarg, &sync_method))
     766            0 :                     exit_nicely(1);
     767            0 :                 break;
     768              : 
     769           26 :             case 16:            /* read object filters from file */
     770           26 :                 read_dump_filters(optarg, &dopt);
     771           22 :                 break;
     772              : 
     773            1 :             case 17:            /* exclude extension(s) */
     774            1 :                 simple_string_list_append(&extension_exclude_patterns,
     775              :                                           optarg);
     776            1 :                 break;
     777              : 
     778            4 :             case 18:
     779            4 :                 statistics_only = true;
     780            4 :                 break;
     781              : 
     782           40 :             case 19:
     783           40 :                 no_data = true;
     784           40 :                 break;
     785              : 
     786            2 :             case 20:
     787            2 :                 no_schema = true;
     788            2 :                 break;
     789              : 
     790            8 :             case 21:
     791            8 :                 no_statistics = true;
     792            8 :                 break;
     793              : 
     794           92 :             case 22:
     795           92 :                 with_statistics = true;
     796           92 :                 break;
     797              : 
     798           26 :             case 25:
     799           26 :                 dopt.restrict_key = pg_strdup(optarg);
     800           26 :                 break;
     801              : 
     802            1 :             default:
     803              :                 /* getopt_long already emitted a complaint */
     804            1 :                 pg_log_error_hint("Try \"%s --help\" for more information.", progname);
     805            1 :                 exit_nicely(1);
     806              :         }
     807              :     }
     808              : 
     809              :     /*
     810              :      * Non-option argument specifies database name as long as it wasn't
     811              :      * already specified with -d / --dbname
     812              :      */
     813          296 :     if (optind < argc && dopt.cparams.dbname == NULL)
     814          260 :         dopt.cparams.dbname = argv[optind++];
     815              : 
     816              :     /* Complain if any arguments remain */
     817          296 :     if (optind < argc)
     818              :     {
     819            1 :         pg_log_error("too many command-line arguments (first is \"%s\")",
     820              :                      argv[optind]);
     821            1 :         pg_log_error_hint("Try \"%s --help\" for more information.", progname);
     822            1 :         exit_nicely(1);
     823              :     }
     824              : 
     825              :     /* --column-inserts implies --inserts */
     826          295 :     if (dopt.column_inserts && dopt.dump_inserts == 0)
     827            1 :         dopt.dump_inserts = DUMP_DEFAULT_ROWS_PER_INSERT;
     828              : 
     829              :     /* *-only options are incompatible with each other */
     830          295 :     check_mut_excl_opts(data_only, "-a/--data-only",
     831              :                         schema_only, "-s/--schema-only",
     832              :                         statistics_only, "--statistics-only");
     833              : 
     834              :     /* --no-* and *-only for same thing are incompatible */
     835          292 :     check_mut_excl_opts(data_only, "-a/--data-only",
     836              :                         no_data, "--no-data");
     837          292 :     check_mut_excl_opts(schema_only, "-s/--schema-only",
     838              :                         no_schema, "--no-schema");
     839          292 :     check_mut_excl_opts(statistics_only, "--statistics-only",
     840              :                         no_statistics, "--no-statistics");
     841              : 
     842              :     /* --statistics and --no-statistics are incompatible */
     843          291 :     check_mut_excl_opts(with_statistics, "--statistics",
     844              :                         no_statistics, "--no-statistics");
     845              : 
     846              :     /* --statistics is incompatible with *-only (except --statistics-only) */
     847          291 :     check_mut_excl_opts(with_statistics, "--statistics",
     848              :                         data_only, "-a/--data-only",
     849              :                         schema_only, "-s/--schema-only");
     850              : 
     851              :     /* --include-foreign-data is incompatible with --schema-only */
     852          290 :     check_mut_excl_opts(foreign_servers_include_patterns.head, "--include-foreign-data",
     853              :                         schema_only, "-s/--schema-only");
     854              : 
     855          289 :     if (numWorkers > 1 && foreign_servers_include_patterns.head != NULL)
     856            1 :         pg_fatal("option %s is not supported with parallel backup",
     857              :                  "--include-foreign-data");
     858              : 
     859              :     /* --clean is incompatible with --data-only */
     860          288 :     check_mut_excl_opts(dopt.outputClean, "-c/--clean",
     861              :                         data_only, "-a/--data-only");
     862              : 
     863          287 :     if (dopt.if_exists && !dopt.outputClean)
     864            1 :         pg_fatal("option %s requires option %s",
     865              :                  "--if-exists", "-c/--clean");
     866              : 
     867              :     /*
     868              :      * Set derivative flags. Ambiguous or nonsensical combinations, e.g.
     869              :      * "--schema-only --no-schema", will have already caused an error in one
     870              :      * of the checks above.
     871              :      */
     872          286 :     dopt.dumpData = ((dopt.dumpData && !schema_only && !statistics_only) ||
     873          572 :                      data_only) && !no_data;
     874          286 :     dopt.dumpSchema = ((dopt.dumpSchema && !data_only && !statistics_only) ||
     875          572 :                        schema_only) && !no_schema;
     876          286 :     dopt.dumpStatistics = ((dopt.dumpStatistics && !schema_only && !data_only) ||
     877          572 :                            (statistics_only || with_statistics)) && !no_statistics;
     878              : 
     879              : 
     880              :     /*
     881              :      * --inserts are already implied above if --column-inserts or
     882              :      * --rows-per-insert were specified.
     883              :      */
     884          286 :     if (dopt.do_nothing && dopt.dump_inserts == 0)
     885            1 :         pg_fatal("option %s requires option %s, %s, or %s",
     886              :                  "--on-conflict-do-nothing",
     887              :                  "--inserts", "--rows-per-insert", "--column-inserts");
     888              : 
     889              :     /* Identify archive format to emit */
     890          285 :     archiveFormat = parseArchiveFormat(format, &archiveMode);
     891              : 
     892              :     /* archiveFormat specific setup */
     893          284 :     if (archiveFormat == archNull)
     894              :     {
     895          152 :         plainText = 1;
     896              : 
     897              :         /*
     898              :          * If you don't provide a restrict key, one will be appointed for you.
     899              :          */
     900          152 :         if (!dopt.restrict_key)
     901          126 :             dopt.restrict_key = generate_restrict_key();
     902          152 :         if (!dopt.restrict_key)
     903            0 :             pg_fatal("could not generate restrict key");
     904          152 :         if (!valid_restrict_key(dopt.restrict_key))
     905            0 :             pg_fatal("invalid restrict key");
     906              :     }
     907          132 :     else if (dopt.restrict_key)
     908            0 :         pg_fatal("option %s can only be used with %s",
     909              :                  "--restrict-key", "--format=plain");
     910              : 
     911              :     /*
     912              :      * Custom and directory formats are compressed by default with gzip when
     913              :      * available, not the others.  If gzip is not available, no compression is
     914              :      * done by default.
     915              :      */
     916          284 :     if ((archiveFormat == archCustom || archiveFormat == archDirectory) &&
     917          121 :         !user_compression_defined)
     918              :     {
     919              : #ifdef HAVE_LIBZ
     920          115 :         compression_algorithm_str = "gzip";
     921              : #else
     922              :         compression_algorithm_str = "none";
     923              : #endif
     924              :     }
     925              : 
     926              :     /*
     927              :      * Compression options
     928              :      */
     929          284 :     if (!parse_compress_algorithm(compression_algorithm_str,
     930              :                                   &compression_algorithm))
     931            1 :         pg_fatal("unrecognized compression algorithm: \"%s\"",
     932              :                  compression_algorithm_str);
     933              : 
     934          283 :     parse_compress_specification(compression_algorithm, compression_detail,
     935              :                                  &compression_spec);
     936          283 :     error_detail = validate_compress_specification(&compression_spec);
     937          283 :     if (error_detail != NULL)
     938            3 :         pg_fatal("invalid compression specification: %s",
     939              :                  error_detail);
     940              : 
     941          280 :     error_detail = supports_compression(compression_spec);
     942          280 :     if (error_detail != NULL)
     943            0 :         pg_fatal("%s", error_detail);
     944              : 
     945              :     /*
     946              :      * Disable support for zstd workers for now - these are based on
     947              :      * threading, and it's unclear how it interacts with parallel dumps on
     948              :      * platforms where that relies on threads too (e.g. Windows).
     949              :      */
     950          280 :     if (compression_spec.options & PG_COMPRESSION_OPTION_WORKERS)
     951            0 :         pg_log_warning("compression option \"%s\" is not currently supported by pg_dump",
     952              :                        "workers");
     953              : 
     954              :     /*
     955              :      * If emitting an archive format, we always want to emit a DATABASE item,
     956              :      * in case --create is specified at pg_restore time.
     957              :      */
     958          280 :     if (!plainText)
     959          132 :         dopt.outputCreateDB = 1;
     960              : 
     961              :     /* Parallel backup only in the directory archive format so far */
     962          280 :     if (archiveFormat != archDirectory && numWorkers > 1)
     963            1 :         pg_fatal("parallel backup only supported by the directory format");
     964              : 
     965              :     /* Open the output file */
     966          279 :     fout = CreateArchive(filename, archiveFormat, compression_spec,
     967              :                          dosync, archiveMode, setupDumpWorker, sync_method);
     968              : 
     969              :     /* Make dump options accessible right away */
     970          278 :     SetArchiveOptions(fout, &dopt, NULL);
     971              : 
     972              :     /* Register the cleanup hook */
     973          278 :     on_exit_close_archive(fout);
     974              : 
     975              :     /* Let the archiver know how noisy to be */
     976          278 :     fout->verbose = g_verbose;
     977              : 
     978              : 
     979              :     /*
     980              :      * We allow the server to be back to 9.2, and up to any minor release of
     981              :      * our own major version.  (See also version check in pg_dumpall.c.)
     982              :      */
     983          278 :     fout->minRemoteVersion = 90200;
     984          278 :     fout->maxRemoteVersion = (PG_VERSION_NUM / 100) * 100 + 99;
     985              : 
     986          278 :     fout->numWorkers = numWorkers;
     987              : 
     988              :     /*
     989              :      * Open the database using the Archiver, so it knows about it. Errors mean
     990              :      * death.
     991              :      */
     992          278 :     ConnectDatabaseAhx(fout, &dopt.cparams, false);
     993          276 :     setup_connection(fout, dumpencoding, dumpsnapshot, use_role);
     994              : 
     995              :     /*
     996              :      * On hot standbys, never try to dump unlogged table data, since it will
     997              :      * just throw an error.
     998              :      */
     999          276 :     if (fout->isStandby)
    1000            4 :         dopt.no_unlogged_table_data = true;
    1001              : 
    1002              :     /*
    1003              :      * Find the last built-in OID, if needed (prior to 8.1)
    1004              :      *
    1005              :      * With 8.1 and above, we can just use FirstNormalObjectId - 1.
    1006              :      */
    1007          276 :     g_last_builtin_oid = FirstNormalObjectId - 1;
    1008              : 
    1009          276 :     pg_log_info("last built-in OID is %u", g_last_builtin_oid);
    1010              : 
    1011              :     /* Expand schema selection patterns into OID lists */
    1012          276 :     if (schema_include_patterns.head != NULL)
    1013              :     {
    1014           18 :         expand_schema_name_patterns(fout, &schema_include_patterns,
    1015              :                                     &schema_include_oids,
    1016              :                                     strict_names);
    1017           12 :         if (schema_include_oids.head == NULL)
    1018            1 :             pg_fatal("no matching schemas were found");
    1019              :     }
    1020          269 :     expand_schema_name_patterns(fout, &schema_exclude_patterns,
    1021              :                                 &schema_exclude_oids,
    1022              :                                 false);
    1023              :     /* non-matching exclusion patterns aren't an error */
    1024              : 
    1025              :     /* Expand table selection patterns into OID lists */
    1026          269 :     expand_table_name_patterns(fout, &table_include_patterns,
    1027              :                                &table_include_oids,
    1028              :                                strict_names, false);
    1029          264 :     expand_table_name_patterns(fout, &table_include_patterns_and_children,
    1030              :                                &table_include_oids,
    1031              :                                strict_names, true);
    1032          264 :     if ((table_include_patterns.head != NULL ||
    1033          253 :          table_include_patterns_and_children.head != NULL) &&
    1034           13 :         table_include_oids.head == NULL)
    1035            2 :         pg_fatal("no matching tables were found");
    1036              : 
    1037          262 :     expand_table_name_patterns(fout, &table_exclude_patterns,
    1038              :                                &table_exclude_oids,
    1039              :                                false, false);
    1040          262 :     expand_table_name_patterns(fout, &table_exclude_patterns_and_children,
    1041              :                                &table_exclude_oids,
    1042              :                                false, true);
    1043              : 
    1044          262 :     expand_table_name_patterns(fout, &tabledata_exclude_patterns,
    1045              :                                &tabledata_exclude_oids,
    1046              :                                false, false);
    1047          262 :     expand_table_name_patterns(fout, &tabledata_exclude_patterns_and_children,
    1048              :                                &tabledata_exclude_oids,
    1049              :                                false, true);
    1050              : 
    1051          262 :     expand_foreign_server_name_patterns(fout, &foreign_servers_include_patterns,
    1052              :                                         &foreign_servers_include_oids);
    1053              : 
    1054              :     /* non-matching exclusion patterns aren't an error */
    1055              : 
    1056              :     /* Expand extension selection patterns into OID lists */
    1057          261 :     if (extension_include_patterns.head != NULL)
    1058              :     {
    1059            5 :         expand_extension_name_patterns(fout, &extension_include_patterns,
    1060              :                                        &extension_include_oids,
    1061              :                                        strict_names);
    1062            5 :         if (extension_include_oids.head == NULL)
    1063            1 :             pg_fatal("no matching extensions were found");
    1064              :     }
    1065          260 :     expand_extension_name_patterns(fout, &extension_exclude_patterns,
    1066              :                                    &extension_exclude_oids,
    1067              :                                    false);
    1068              :     /* non-matching exclusion patterns aren't an error */
    1069              : 
    1070              :     /*
    1071              :      * Dumping LOs is the default for dumps where an inclusion switch is not
    1072              :      * used (an "include everything" dump).  -B can be used to exclude LOs
    1073              :      * from those dumps.  -b can be used to include LOs even when an inclusion
    1074              :      * switch is used.
    1075              :      *
    1076              :      * -s means "schema only" and LOs are data, not schema, so we never
    1077              :      * include LOs when -s is used.
    1078              :      */
    1079          260 :     if (dopt.include_everything && dopt.dumpData && !dopt.dontOutputLOs)
    1080          191 :         dopt.outputLOs = true;
    1081              : 
    1082              :     /*
    1083              :      * Collect role names so we can map object owner OIDs to names.
    1084              :      */
    1085          260 :     collectRoleNames(fout);
    1086              : 
    1087              :     /*
    1088              :      * Now scan the database and create DumpableObject structs for all the
    1089              :      * objects we intend to dump.
    1090              :      */
    1091          260 :     tblinfo = getSchemaData(fout, &numTables);
    1092              : 
    1093          259 :     if (dopt.dumpData)
    1094              :     {
    1095          215 :         getTableData(&dopt, tblinfo, numTables, 0);
    1096          215 :         buildMatViewRefreshDependencies(fout);
    1097          215 :         if (!dopt.dumpSchema)
    1098            7 :             getTableDataFKConstraints();
    1099              :     }
    1100              : 
    1101          259 :     if (!dopt.dumpData && dopt.sequence_data)
    1102           36 :         getTableData(&dopt, tblinfo, numTables, RELKIND_SEQUENCE);
    1103              : 
    1104              :     /*
    1105              :      * For binary upgrade mode, dump the pg_shdepend rows for large objects
    1106              :      * and maybe even pg_largeobject_metadata (see comment below for details).
    1107              :      * This is faster to restore than the equivalent set of large object
    1108              :      * commands.
    1109              :      */
    1110          259 :     if (dopt.binary_upgrade)
    1111              :     {
    1112              :         TableInfo  *shdepend;
    1113              : 
    1114           40 :         shdepend = findTableByOid(SharedDependRelationId);
    1115           40 :         makeTableDataInfo(&dopt, shdepend);
    1116              : 
    1117              :         /*
    1118              :          * Only dump large object shdepend rows for this database.
    1119              :          */
    1120           40 :         shdepend->dataObj->filtercond = "WHERE classid = 'pg_largeobject'::regclass "
    1121              :             "AND dbid = (SELECT oid FROM pg_database "
    1122              :             "            WHERE datname = current_database())";
    1123              : 
    1124              :         /*
    1125              :          * For binary upgrades from v16 and newer versions, we can copy
    1126              :          * pg_largeobject_metadata's files from the old cluster, so we don't
    1127              :          * need to dump its contents.  pg_upgrade can't copy/link the files
    1128              :          * from older versions because aclitem (needed by
    1129              :          * pg_largeobject_metadata.lomacl) changed its storage format in v16.
    1130              :          */
    1131           40 :         if (fout->remoteVersion < 160000)
    1132              :         {
    1133              :             TableInfo  *lo_metadata;
    1134              : 
    1135            0 :             lo_metadata = findTableByOid(LargeObjectMetadataRelationId);
    1136            0 :             makeTableDataInfo(&dopt, lo_metadata);
    1137              :         }
    1138              :     }
    1139              : 
    1140              :     /*
    1141              :      * In binary-upgrade mode, we do not have to worry about the actual LO
    1142              :      * data or the associated metadata that resides in the pg_largeobject and
    1143              :      * pg_largeobject_metadata tables, respectively.
    1144              :      *
    1145              :      * However, we do need to collect LO information as there may be comments
    1146              :      * or other information on LOs that we do need to dump out.
    1147              :      */
    1148          259 :     if (dopt.outputLOs || dopt.binary_upgrade)
    1149          231 :         getLOs(fout);
    1150              : 
    1151              :     /*
    1152              :      * Collect dependency data to assist in ordering the objects.
    1153              :      */
    1154          259 :     getDependencies(fout);
    1155              : 
    1156              :     /*
    1157              :      * Collect ACLs, comments, and security labels, if wanted.
    1158              :      */
    1159          259 :     if (!dopt.aclsSkip)
    1160          257 :         getAdditionalACLs(fout);
    1161          259 :     if (!dopt.no_comments)
    1162          259 :         collectComments(fout);
    1163          259 :     if (!dopt.no_security_labels)
    1164          259 :         collectSecLabels(fout);
    1165              : 
    1166              :     /* For binary upgrade mode, collect required pg_class information. */
    1167          259 :     if (dopt.binary_upgrade)
    1168           40 :         collectBinaryUpgradeClassOids(fout);
    1169              : 
    1170              :     /* Collect sequence information. */
    1171          259 :     collectSequences(fout);
    1172              : 
    1173              :     /* Lastly, create dummy objects to represent the section boundaries */
    1174          259 :     boundaryObjs = createBoundaryObjects();
    1175              : 
    1176              :     /* Get pointers to all the known DumpableObjects */
    1177          259 :     getDumpableObjects(&dobjs, &numObjs);
    1178              : 
    1179              :     /*
    1180              :      * Add dummy dependencies to enforce the dump section ordering.
    1181              :      */
    1182          259 :     addBoundaryDependencies(dobjs, numObjs, boundaryObjs);
    1183              : 
    1184              :     /*
    1185              :      * Sort the objects into a safe dump order (no forward references).
    1186              :      *
    1187              :      * We rely on dependency information to help us determine a safe order, so
    1188              :      * the initial sort is mostly for cosmetic purposes: we sort by name to
    1189              :      * ensure that logically identical schemas will dump identically.
    1190              :      */
    1191          259 :     sortDumpableObjectsByTypeName(dobjs, numObjs);
    1192              : 
    1193          259 :     sortDumpableObjects(dobjs, numObjs,
    1194          259 :                         boundaryObjs[0].dumpId, boundaryObjs[1].dumpId);
    1195              : 
    1196              :     /*
    1197              :      * Create archive TOC entries for all the objects to be dumped, in a safe
    1198              :      * order.
    1199              :      */
    1200              : 
    1201              :     /*
    1202              :      * First the special entries for ENCODING, STDSTRINGS, and SEARCHPATH.
    1203              :      */
    1204          259 :     dumpEncoding(fout);
    1205          259 :     dumpStdStrings(fout);
    1206          259 :     dumpSearchPath(fout);
    1207              : 
    1208              :     /* The database items are always next, unless we don't want them at all */
    1209          259 :     if (dopt.outputCreateDB)
    1210          160 :         dumpDatabase(fout);
    1211              : 
    1212              :     /* Now the rearrangeable objects. */
    1213       980461 :     for (i = 0; i < numObjs; i++)
    1214       980202 :         dumpDumpableObject(fout, dobjs[i]);
    1215              : 
    1216              :     /*
    1217              :      * Set up options info to ensure we dump what we want.
    1218              :      */
    1219          259 :     ropt = NewRestoreOptions();
    1220          259 :     ropt->filename = filename;
    1221              : 
    1222              :     /* if you change this list, see dumpOptionsFromRestoreOptions */
    1223          259 :     ropt->cparams.dbname = dopt.cparams.dbname ? pg_strdup(dopt.cparams.dbname) : NULL;
    1224          259 :     ropt->cparams.pgport = dopt.cparams.pgport ? pg_strdup(dopt.cparams.pgport) : NULL;
    1225          259 :     ropt->cparams.pghost = dopt.cparams.pghost ? pg_strdup(dopt.cparams.pghost) : NULL;
    1226          259 :     ropt->cparams.username = dopt.cparams.username ? pg_strdup(dopt.cparams.username) : NULL;
    1227          259 :     ropt->cparams.promptPassword = dopt.cparams.promptPassword;
    1228          259 :     ropt->dropSchema = dopt.outputClean;
    1229          259 :     ropt->dumpData = dopt.dumpData;
    1230          259 :     ropt->dumpSchema = dopt.dumpSchema;
    1231          259 :     ropt->dumpStatistics = dopt.dumpStatistics;
    1232          259 :     ropt->if_exists = dopt.if_exists;
    1233          259 :     ropt->column_inserts = dopt.column_inserts;
    1234          259 :     ropt->dumpSections = dopt.dumpSections;
    1235          259 :     ropt->aclsSkip = dopt.aclsSkip;
    1236          259 :     ropt->superuser = dopt.outputSuperuser;
    1237          259 :     ropt->createDB = dopt.outputCreateDB;
    1238          259 :     ropt->noOwner = dopt.outputNoOwner;
    1239          259 :     ropt->noTableAm = dopt.outputNoTableAm;
    1240          259 :     ropt->noTablespace = dopt.outputNoTablespaces;
    1241          259 :     ropt->disable_triggers = dopt.disable_triggers;
    1242          259 :     ropt->use_setsessauth = dopt.use_setsessauth;
    1243          259 :     ropt->disable_dollar_quoting = dopt.disable_dollar_quoting;
    1244          259 :     ropt->dump_inserts = dopt.dump_inserts;
    1245          259 :     ropt->no_comments = dopt.no_comments;
    1246          259 :     ropt->no_policies = dopt.no_policies;
    1247          259 :     ropt->no_publications = dopt.no_publications;
    1248          259 :     ropt->no_security_labels = dopt.no_security_labels;
    1249          259 :     ropt->no_subscriptions = dopt.no_subscriptions;
    1250          259 :     ropt->lockWaitTimeout = dopt.lockWaitTimeout;
    1251          259 :     ropt->include_everything = dopt.include_everything;
    1252          259 :     ropt->enable_row_security = dopt.enable_row_security;
    1253          259 :     ropt->sequence_data = dopt.sequence_data;
    1254          259 :     ropt->binary_upgrade = dopt.binary_upgrade;
    1255          259 :     ropt->restrict_key = dopt.restrict_key ? pg_strdup(dopt.restrict_key) : NULL;
    1256              : 
    1257          259 :     ropt->compression_spec = compression_spec;
    1258              : 
    1259          259 :     ropt->suppressDumpWarnings = true;   /* We've already shown them */
    1260              : 
    1261          259 :     SetArchiveOptions(fout, &dopt, ropt);
    1262              : 
    1263              :     /* Mark which entries should be output */
    1264          259 :     ProcessArchiveRestoreOptions(fout);
    1265              : 
    1266              :     /*
    1267              :      * The archive's TOC entries are now marked as to which ones will actually
    1268              :      * be output, so we can set up their dependency lists properly. This isn't
    1269              :      * necessary for plain-text output, though.
    1270              :      */
    1271          259 :     if (!plainText)
    1272          131 :         BuildArchiveDependencies(fout);
    1273              : 
    1274              :     /*
    1275              :      * And finally we can do the actual output.
    1276              :      *
    1277              :      * Note: for non-plain-text output formats, the output file is written
    1278              :      * inside CloseArchive().  This is, um, bizarre; but not worth changing
    1279              :      * right now.
    1280              :      */
    1281          259 :     if (plainText)
    1282          128 :         RestoreArchive(fout, false);
    1283              : 
    1284          258 :     CloseArchive(fout);
    1285              : 
    1286          258 :     exit_nicely(0);
    1287              : }
    1288              : 
    1289              : 
    1290              : static void
    1291            1 : help(const char *progname)
    1292              : {
    1293            1 :     printf(_("%s exports a PostgreSQL database as an SQL script or to other formats.\n\n"), progname);
    1294            1 :     printf(_("Usage:\n"));
    1295            1 :     printf(_("  %s [OPTION]... [DBNAME]\n"), progname);
    1296              : 
    1297            1 :     printf(_("\nGeneral options:\n"));
    1298            1 :     printf(_("  -f, --file=FILENAME          output file or directory name\n"));
    1299            1 :     printf(_("  -F, --format=c|d|t|p         output file format (custom, directory, tar,\n"
    1300              :              "                               plain text (default))\n"));
    1301            1 :     printf(_("  -j, --jobs=NUM               use this many parallel jobs to dump\n"));
    1302            1 :     printf(_("  -v, --verbose                verbose mode\n"));
    1303            1 :     printf(_("  -V, --version                output version information, then exit\n"));
    1304            1 :     printf(_("  -Z, --compress=METHOD[:DETAIL]\n"
    1305              :              "                               compress as specified\n"));
    1306            1 :     printf(_("  --lock-wait-timeout=TIMEOUT  fail after waiting TIMEOUT for a table lock\n"));
    1307            1 :     printf(_("  --no-sync                    do not wait for changes to be written safely to disk\n"));
    1308            1 :     printf(_("  --sync-method=METHOD         set method for syncing files to disk\n"));
    1309            1 :     printf(_("  -?, --help                   show this help, then exit\n"));
    1310              : 
    1311            1 :     printf(_("\nOptions controlling the output content:\n"));
    1312            1 :     printf(_("  -a, --data-only              dump only the data, not the schema or statistics\n"));
    1313            1 :     printf(_("  -b, --large-objects          include large objects in dump\n"));
    1314            1 :     printf(_("  --blobs                      (same as --large-objects, deprecated)\n"));
    1315            1 :     printf(_("  -B, --no-large-objects       exclude large objects in dump\n"));
    1316            1 :     printf(_("  --no-blobs                   (same as --no-large-objects, deprecated)\n"));
    1317            1 :     printf(_("  -c, --clean                  clean (drop) database objects before recreating\n"));
    1318            1 :     printf(_("  -C, --create                 include commands to create database in dump\n"));
    1319            1 :     printf(_("  -e, --extension=PATTERN      dump the specified extension(s) only\n"));
    1320            1 :     printf(_("  -E, --encoding=ENCODING      dump the data in encoding ENCODING\n"));
    1321            1 :     printf(_("  -n, --schema=PATTERN         dump the specified schema(s) only\n"));
    1322            1 :     printf(_("  -N, --exclude-schema=PATTERN do NOT dump the specified schema(s)\n"));
    1323            1 :     printf(_("  -O, --no-owner               skip restoration of object ownership in\n"
    1324              :              "                               plain-text format\n"));
    1325            1 :     printf(_("  -s, --schema-only            dump only the schema, no data or statistics\n"));
    1326            1 :     printf(_("  -S, --superuser=NAME         superuser user name to use in plain-text format\n"));
    1327            1 :     printf(_("  -t, --table=PATTERN          dump only the specified table(s)\n"));
    1328            1 :     printf(_("  -T, --exclude-table=PATTERN  do NOT dump the specified table(s)\n"));
    1329            1 :     printf(_("  -x, --no-privileges          do not dump privileges (grant/revoke)\n"));
    1330            1 :     printf(_("  --binary-upgrade             for use by upgrade utilities only\n"));
    1331            1 :     printf(_("  --column-inserts             dump data as INSERT commands with column names\n"));
    1332            1 :     printf(_("  --disable-dollar-quoting     disable dollar quoting, use SQL standard quoting\n"));
    1333            1 :     printf(_("  --disable-triggers           disable triggers during data-only restore\n"));
    1334            1 :     printf(_("  --enable-row-security        enable row security (dump only content user has\n"
    1335              :              "                               access to)\n"));
    1336            1 :     printf(_("  --exclude-extension=PATTERN  do NOT dump the specified extension(s)\n"));
    1337            1 :     printf(_("  --exclude-table-and-children=PATTERN\n"
    1338              :              "                               do NOT dump the specified table(s), including\n"
    1339              :              "                               child and partition tables\n"));
    1340            1 :     printf(_("  --exclude-table-data=PATTERN do NOT dump data for the specified table(s)\n"));
    1341            1 :     printf(_("  --exclude-table-data-and-children=PATTERN\n"
    1342              :              "                               do NOT dump data for the specified table(s),\n"
    1343              :              "                               including child and partition tables\n"));
    1344            1 :     printf(_("  --extra-float-digits=NUM     override default setting for extra_float_digits\n"));
    1345            1 :     printf(_("  --filter=FILENAME            include or exclude objects and data from dump\n"
    1346              :              "                               based on expressions in FILENAME\n"));
    1347            1 :     printf(_("  --if-exists                  use IF EXISTS when dropping objects\n"));
    1348            1 :     printf(_("  --include-foreign-data=PATTERN\n"
    1349              :              "                               include data of foreign tables on foreign\n"
    1350              :              "                               servers matching PATTERN\n"));
    1351            1 :     printf(_("  --inserts                    dump data as INSERT commands, rather than COPY\n"));
    1352            1 :     printf(_("  --load-via-partition-root    load partitions via the root table\n"));
    1353            1 :     printf(_("  --no-comments                do not dump comment commands\n"));
    1354            1 :     printf(_("  --no-data                    do not dump data\n"));
    1355            1 :     printf(_("  --no-policies                do not dump row security policies\n"));
    1356            1 :     printf(_("  --no-publications            do not dump publications\n"));
    1357            1 :     printf(_("  --no-schema                  do not dump schema\n"));
    1358            1 :     printf(_("  --no-security-labels         do not dump security label assignments\n"));
    1359            1 :     printf(_("  --no-statistics              do not dump statistics\n"));
    1360            1 :     printf(_("  --no-subscriptions           do not dump subscriptions\n"));
    1361            1 :     printf(_("  --no-table-access-method     do not dump table access methods\n"));
    1362            1 :     printf(_("  --no-tablespaces             do not dump tablespace assignments\n"));
    1363            1 :     printf(_("  --no-toast-compression       do not dump TOAST compression methods\n"));
    1364            1 :     printf(_("  --no-unlogged-table-data     do not dump unlogged table data\n"));
    1365            1 :     printf(_("  --on-conflict-do-nothing     add ON CONFLICT DO NOTHING to INSERT commands\n"));
    1366            1 :     printf(_("  --quote-all-identifiers      quote all identifiers, even if not key words\n"));
    1367            1 :     printf(_("  --restrict-key=RESTRICT_KEY  use provided string as psql \\restrict key\n"));
    1368            1 :     printf(_("  --rows-per-insert=NROWS      number of rows per INSERT; implies --inserts\n"));
    1369            1 :     printf(_("  --section=SECTION            dump named section (pre-data, data, or post-data)\n"));
    1370            1 :     printf(_("  --sequence-data              include sequence data in dump\n"));
    1371            1 :     printf(_("  --serializable-deferrable    wait until the dump can run without anomalies\n"));
    1372            1 :     printf(_("  --snapshot=SNAPSHOT          use given snapshot for the dump\n"));
    1373            1 :     printf(_("  --statistics                 dump the statistics\n"));
    1374            1 :     printf(_("  --statistics-only            dump only the statistics, not schema or data\n"));
    1375            1 :     printf(_("  --strict-names               require table and/or schema include patterns to\n"
    1376              :              "                               match at least one entity each\n"));
    1377            1 :     printf(_("  --table-and-children=PATTERN dump only the specified table(s), including\n"
    1378              :              "                               child and partition tables\n"));
    1379            1 :     printf(_("  --use-set-session-authorization\n"
    1380              :              "                               use SET SESSION AUTHORIZATION commands instead of\n"
    1381              :              "                               ALTER OWNER commands to set ownership\n"));
    1382              : 
    1383            1 :     printf(_("\nConnection options:\n"));
    1384            1 :     printf(_("  -d, --dbname=DBNAME      database to dump\n"));
    1385            1 :     printf(_("  -h, --host=HOSTNAME      database server host or socket directory\n"));
    1386            1 :     printf(_("  -p, --port=PORT          database server port number\n"));
    1387            1 :     printf(_("  -U, --username=NAME      connect as specified database user\n"));
    1388            1 :     printf(_("  -w, --no-password        never prompt for password\n"));
    1389            1 :     printf(_("  -W, --password           force password prompt (should happen automatically)\n"));
    1390            1 :     printf(_("  --role=ROLENAME          do SET ROLE before dump\n"));
    1391              : 
    1392            1 :     printf(_("\nIf no database name is supplied, then the PGDATABASE environment\n"
    1393              :              "variable value is used.\n\n"));
    1394            1 :     printf(_("Report bugs to <%s>.\n"), PACKAGE_BUGREPORT);
    1395            1 :     printf(_("%s home page: <%s>\n"), PACKAGE_NAME, PACKAGE_URL);
    1396            1 : }
    1397              : 
    1398              : static void
    1399          292 : setup_connection(Archive *AH, const char *dumpencoding,
    1400              :                  const char *dumpsnapshot, char *use_role)
    1401              : {
    1402          292 :     DumpOptions *dopt = AH->dopt;
    1403          292 :     PGconn     *conn = GetConnection(AH);
    1404              : 
    1405          292 :     PQclear(ExecuteSqlQueryForSingleRow(AH, ALWAYS_SECURE_SEARCH_PATH_SQL));
    1406              : 
    1407              :     /*
    1408              :      * Set the client encoding if requested.
    1409              :      */
    1410          292 :     if (dumpencoding)
    1411              :     {
    1412           18 :         if (PQsetClientEncoding(conn, dumpencoding) < 0)
    1413            0 :             pg_fatal("invalid client encoding \"%s\" specified",
    1414              :                      dumpencoding);
    1415              :     }
    1416              : 
    1417              :     /*
    1418              :      * Force standard_conforming_strings on, just in case we are dumping from
    1419              :      * an old server that has it disabled.  Without this, literals in views,
    1420              :      * expressions, etc, would be incorrect for modern servers.
    1421              :      */
    1422          292 :     ExecuteSqlStatement(AH, "SET standard_conforming_strings = on");
    1423              : 
    1424              :     /*
    1425              :      * And reflect that to AH->std_strings.  You might think that we should
    1426              :      * just delete that variable and the code that checks it, but that would
    1427              :      * be problematic for pg_restore, which at least for now should still cope
    1428              :      * with archives containing the other setting (cf. processStdStringsEntry
    1429              :      * in pg_backup_archiver.c).
    1430              :      */
    1431          292 :     AH->std_strings = true;
    1432              : 
    1433              :     /*
    1434              :      * Get the active encoding, so we know how to escape strings.
    1435              :      */
    1436          292 :     AH->encoding = PQclientEncoding(conn);
    1437          292 :     setFmtEncoding(AH->encoding);
    1438              : 
    1439              :     /*
    1440              :      * Set the role if requested.  In a parallel dump worker, we'll be passed
    1441              :      * use_role == NULL, but AH->use_role is already set (if user specified it
    1442              :      * originally) and we should use that.
    1443              :      */
    1444          292 :     if (!use_role && AH->use_role)
    1445            2 :         use_role = AH->use_role;
    1446              : 
    1447              :     /* Set the role if requested */
    1448          292 :     if (use_role)
    1449              :     {
    1450            5 :         PQExpBuffer query = createPQExpBuffer();
    1451              : 
    1452            5 :         appendPQExpBuffer(query, "SET ROLE %s", fmtId(use_role));
    1453            5 :         ExecuteSqlStatement(AH, query->data);
    1454            5 :         destroyPQExpBuffer(query);
    1455              : 
    1456              :         /* save it for possible later use by parallel workers */
    1457            5 :         if (!AH->use_role)
    1458            3 :             AH->use_role = pg_strdup(use_role);
    1459              :     }
    1460              : 
    1461              :     /* Set the datestyle to ISO to ensure the dump's portability */
    1462          292 :     ExecuteSqlStatement(AH, "SET DATESTYLE = ISO");
    1463              : 
    1464              :     /* Likewise, avoid using sql_standard intervalstyle */
    1465          292 :     ExecuteSqlStatement(AH, "SET INTERVALSTYLE = POSTGRES");
    1466              : 
    1467              :     /*
    1468              :      * Use an explicitly specified extra_float_digits if it has been provided.
    1469              :      * Otherwise, set extra_float_digits so that we can dump float data
    1470              :      * exactly (given correctly implemented float I/O code, anyway).
    1471              :      */
    1472          292 :     if (have_extra_float_digits)
    1473              :     {
    1474            0 :         PQExpBuffer q = createPQExpBuffer();
    1475              : 
    1476            0 :         appendPQExpBuffer(q, "SET extra_float_digits TO %d",
    1477              :                           extra_float_digits);
    1478            0 :         ExecuteSqlStatement(AH, q->data);
    1479            0 :         destroyPQExpBuffer(q);
    1480              :     }
    1481              :     else
    1482          292 :         ExecuteSqlStatement(AH, "SET extra_float_digits TO 3");
    1483              : 
    1484              :     /*
    1485              :      * Disable synchronized scanning, to prevent unpredictable changes in row
    1486              :      * ordering across a dump and reload.
    1487              :      */
    1488          292 :     ExecuteSqlStatement(AH, "SET synchronize_seqscans TO off");
    1489              : 
    1490              :     /*
    1491              :      * Disable timeouts if supported.
    1492              :      */
    1493          292 :     ExecuteSqlStatement(AH, "SET statement_timeout = 0");
    1494          292 :     if (AH->remoteVersion >= 90300)
    1495          292 :         ExecuteSqlStatement(AH, "SET lock_timeout = 0");
    1496          292 :     if (AH->remoteVersion >= 90600)
    1497          292 :         ExecuteSqlStatement(AH, "SET idle_in_transaction_session_timeout = 0");
    1498          292 :     if (AH->remoteVersion >= 170000)
    1499          292 :         ExecuteSqlStatement(AH, "SET transaction_timeout = 0");
    1500              : 
    1501              :     /*
    1502              :      * Quote all identifiers, if requested.
    1503              :      */
    1504          292 :     if (quote_all_identifiers)
    1505           38 :         ExecuteSqlStatement(AH, "SET quote_all_identifiers = true");
    1506              : 
    1507              :     /*
    1508              :      * Adjust row-security mode, if supported.
    1509              :      */
    1510          292 :     if (AH->remoteVersion >= 90500)
    1511              :     {
    1512          292 :         if (dopt->enable_row_security)
    1513            0 :             ExecuteSqlStatement(AH, "SET row_security = on");
    1514              :         else
    1515          292 :             ExecuteSqlStatement(AH, "SET row_security = off");
    1516              :     }
    1517              : 
    1518              :     /*
    1519              :      * For security reasons, we restrict the expansion of non-system views and
    1520              :      * access to foreign tables during the pg_dump process. This restriction
    1521              :      * is adjusted when dumping foreign table data.
    1522              :      */
    1523          292 :     set_restrict_relation_kind(AH, "view, foreign-table");
    1524              : 
    1525              :     /*
    1526              :      * Initialize prepared-query state to "nothing prepared".  We do this here
    1527              :      * so that a parallel dump worker will have its own state.
    1528              :      */
    1529          292 :     AH->is_prepared = pg_malloc0_array(bool, NUM_PREP_QUERIES);
    1530              : 
    1531              :     /*
    1532              :      * Start transaction-snapshot mode transaction to dump consistent data.
    1533              :      */
    1534          292 :     ExecuteSqlStatement(AH, "BEGIN");
    1535              : 
    1536              :     /*
    1537              :      * To support the combination of serializable_deferrable with the jobs
    1538              :      * option we use REPEATABLE READ for the worker connections that are
    1539              :      * passed a snapshot.  As long as the snapshot is acquired in a
    1540              :      * SERIALIZABLE, READ ONLY, DEFERRABLE transaction, its use within a
    1541              :      * REPEATABLE READ transaction provides the appropriate integrity
    1542              :      * guarantees.  This is a kluge, but safe for back-patching.
    1543              :      */
    1544          292 :     if (dopt->serializable_deferrable && AH->sync_snapshot_id == NULL)
    1545            0 :         ExecuteSqlStatement(AH,
    1546              :                             "SET TRANSACTION ISOLATION LEVEL "
    1547              :                             "SERIALIZABLE, READ ONLY, DEFERRABLE");
    1548              :     else
    1549          292 :         ExecuteSqlStatement(AH,
    1550              :                             "SET TRANSACTION ISOLATION LEVEL "
    1551              :                             "REPEATABLE READ, READ ONLY");
    1552              : 
    1553              :     /*
    1554              :      * If user specified a snapshot to use, select that.  In a parallel dump
    1555              :      * worker, we'll be passed dumpsnapshot == NULL, but AH->sync_snapshot_id
    1556              :      * is already set (if the server can handle it) and we should use that.
    1557              :      */
    1558          292 :     if (dumpsnapshot)
    1559            0 :         AH->sync_snapshot_id = pg_strdup(dumpsnapshot);
    1560              : 
    1561          292 :     if (AH->sync_snapshot_id)
    1562              :     {
    1563           16 :         PQExpBuffer query = createPQExpBuffer();
    1564              : 
    1565           16 :         appendPQExpBufferStr(query, "SET TRANSACTION SNAPSHOT ");
    1566           16 :         appendStringLiteralConn(query, AH->sync_snapshot_id, conn);
    1567           16 :         ExecuteSqlStatement(AH, query->data);
    1568           16 :         destroyPQExpBuffer(query);
    1569              :     }
    1570          276 :     else if (AH->numWorkers > 1)
    1571              :     {
    1572            8 :         if (AH->isStandby && AH->remoteVersion < 100000)
    1573            0 :             pg_fatal("parallel dumps from standby servers are not supported by this server version");
    1574            8 :         AH->sync_snapshot_id = get_synchronized_snapshot(AH);
    1575              :     }
    1576          292 : }
    1577              : 
    1578              : /* Set up connection for a parallel worker process */
    1579              : static void
    1580           16 : setupDumpWorker(Archive *AH)
    1581              : {
    1582              :     /*
    1583              :      * We want to re-select all the same values the leader connection is
    1584              :      * using.  We'll have inherited directly-usable values in
    1585              :      * AH->sync_snapshot_id and AH->use_role, but we need to translate the
    1586              :      * inherited encoding value back to a string to pass to setup_connection.
    1587              :      */
    1588           16 :     setup_connection(AH,
    1589              :                      pg_encoding_to_char(AH->encoding),
    1590              :                      NULL,
    1591              :                      NULL);
    1592           16 : }
    1593              : 
    1594              : static char *
    1595            8 : get_synchronized_snapshot(Archive *fout)
    1596              : {
    1597            8 :     char       *query = "SELECT pg_catalog.pg_export_snapshot()";
    1598              :     char       *result;
    1599              :     PGresult   *res;
    1600              : 
    1601            8 :     res = ExecuteSqlQueryForSingleRow(fout, query);
    1602            8 :     result = pg_strdup(PQgetvalue(res, 0, 0));
    1603            8 :     PQclear(res);
    1604              : 
    1605            8 :     return result;
    1606              : }
    1607              : 
    1608              : static ArchiveFormat
    1609          285 : parseArchiveFormat(const char *format, ArchiveMode *mode)
    1610              : {
    1611              :     ArchiveFormat archiveFormat;
    1612              : 
    1613          285 :     *mode = archModeWrite;
    1614              : 
    1615          285 :     if (pg_strcasecmp(format, "a") == 0 || pg_strcasecmp(format, "append") == 0)
    1616              :     {
    1617              :         /* This is used by pg_dumpall, and is not documented */
    1618           48 :         archiveFormat = archNull;
    1619           48 :         *mode = archModeAppend;
    1620              :     }
    1621          237 :     else if (pg_strcasecmp(format, "c") == 0)
    1622            0 :         archiveFormat = archCustom;
    1623          237 :     else if (pg_strcasecmp(format, "custom") == 0)
    1624           56 :         archiveFormat = archCustom;
    1625          181 :     else if (pg_strcasecmp(format, "d") == 0)
    1626            0 :         archiveFormat = archDirectory;
    1627          181 :     else if (pg_strcasecmp(format, "directory") == 0)
    1628           65 :         archiveFormat = archDirectory;
    1629          116 :     else if (pg_strcasecmp(format, "p") == 0)
    1630          101 :         archiveFormat = archNull;
    1631           15 :     else if (pg_strcasecmp(format, "plain") == 0)
    1632            3 :         archiveFormat = archNull;
    1633           12 :     else if (pg_strcasecmp(format, "t") == 0)
    1634            0 :         archiveFormat = archTar;
    1635           12 :     else if (pg_strcasecmp(format, "tar") == 0)
    1636           11 :         archiveFormat = archTar;
    1637              :     else
    1638            1 :         pg_fatal("invalid output format \"%s\" specified", format);
    1639          284 :     return archiveFormat;
    1640              : }
    1641              : 
    1642              : /*
    1643              :  * Find the OIDs of all schemas matching the given list of patterns,
    1644              :  * and append them to the given OID list.
    1645              :  */
    1646              : static void
    1647          287 : expand_schema_name_patterns(Archive *fout,
    1648              :                             SimpleStringList *patterns,
    1649              :                             SimpleOidList *oids,
    1650              :                             bool strict_names)
    1651              : {
    1652              :     PQExpBuffer query;
    1653              :     PGresult   *res;
    1654              :     SimpleStringListCell *cell;
    1655              :     int         i;
    1656              : 
    1657          287 :     if (patterns->head == NULL)
    1658          266 :         return;                 /* nothing to do */
    1659              : 
    1660           21 :     query = createPQExpBuffer();
    1661              : 
    1662              :     /*
    1663              :      * The loop below runs multiple SELECTs might sometimes result in
    1664              :      * duplicate entries in the OID list, but we don't care.
    1665              :      */
    1666              : 
    1667           36 :     for (cell = patterns->head; cell; cell = cell->next)
    1668              :     {
    1669              :         PQExpBufferData dbbuf;
    1670              :         int         dotcnt;
    1671              : 
    1672           21 :         appendPQExpBufferStr(query,
    1673              :                              "SELECT oid FROM pg_catalog.pg_namespace n\n");
    1674           21 :         initPQExpBuffer(&dbbuf);
    1675           21 :         processSQLNamePattern(GetConnection(fout), query, cell->val, false,
    1676              :                               false, NULL, "n.nspname", NULL, NULL, &dbbuf,
    1677              :                               &dotcnt);
    1678           21 :         if (dotcnt > 1)
    1679            2 :             pg_fatal("improper qualified name (too many dotted names): %s",
    1680              :                      cell->val);
    1681           19 :         else if (dotcnt == 1)
    1682            3 :             prohibit_crossdb_refs(GetConnection(fout), dbbuf.data, cell->val);
    1683           16 :         termPQExpBuffer(&dbbuf);
    1684              : 
    1685           16 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    1686           16 :         if (strict_names && PQntuples(res) == 0)
    1687            1 :             pg_fatal("no matching schemas were found for pattern \"%s\"", cell->val);
    1688              : 
    1689           29 :         for (i = 0; i < PQntuples(res); i++)
    1690              :         {
    1691           14 :             simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
    1692              :         }
    1693              : 
    1694           15 :         PQclear(res);
    1695           15 :         resetPQExpBuffer(query);
    1696              :     }
    1697              : 
    1698           15 :     destroyPQExpBuffer(query);
    1699              : }
    1700              : 
    1701              : /*
    1702              :  * Find the OIDs of all extensions matching the given list of patterns,
    1703              :  * and append them to the given OID list.
    1704              :  */
    1705              : static void
    1706          265 : expand_extension_name_patterns(Archive *fout,
    1707              :                                SimpleStringList *patterns,
    1708              :                                SimpleOidList *oids,
    1709              :                                bool strict_names)
    1710              : {
    1711              :     PQExpBuffer query;
    1712              :     PGresult   *res;
    1713              :     SimpleStringListCell *cell;
    1714              :     int         i;
    1715              : 
    1716          265 :     if (patterns->head == NULL)
    1717          258 :         return;                 /* nothing to do */
    1718              : 
    1719            7 :     query = createPQExpBuffer();
    1720              : 
    1721              :     /*
    1722              :      * The loop below runs multiple SELECTs might sometimes result in
    1723              :      * duplicate entries in the OID list, but we don't care.
    1724              :      */
    1725           14 :     for (cell = patterns->head; cell; cell = cell->next)
    1726              :     {
    1727              :         int         dotcnt;
    1728              : 
    1729            7 :         appendPQExpBufferStr(query,
    1730              :                              "SELECT oid FROM pg_catalog.pg_extension e\n");
    1731            7 :         processSQLNamePattern(GetConnection(fout), query, cell->val, false,
    1732              :                               false, NULL, "e.extname", NULL, NULL, NULL,
    1733              :                               &dotcnt);
    1734            7 :         if (dotcnt > 0)
    1735            0 :             pg_fatal("improper qualified name (too many dotted names): %s",
    1736              :                      cell->val);
    1737              : 
    1738            7 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    1739            7 :         if (strict_names && PQntuples(res) == 0)
    1740            0 :             pg_fatal("no matching extensions were found for pattern \"%s\"", cell->val);
    1741              : 
    1742           13 :         for (i = 0; i < PQntuples(res); i++)
    1743              :         {
    1744            6 :             simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
    1745              :         }
    1746              : 
    1747            7 :         PQclear(res);
    1748            7 :         resetPQExpBuffer(query);
    1749              :     }
    1750              : 
    1751            7 :     destroyPQExpBuffer(query);
    1752              : }
    1753              : 
    1754              : /*
    1755              :  * Find the OIDs of all foreign servers matching the given list of patterns,
    1756              :  * and append them to the given OID list.
    1757              :  */
    1758              : static void
    1759          262 : expand_foreign_server_name_patterns(Archive *fout,
    1760              :                                     SimpleStringList *patterns,
    1761              :                                     SimpleOidList *oids)
    1762              : {
    1763              :     PQExpBuffer query;
    1764              :     PGresult   *res;
    1765              :     SimpleStringListCell *cell;
    1766              :     int         i;
    1767              : 
    1768          262 :     if (patterns->head == NULL)
    1769          259 :         return;                 /* nothing to do */
    1770              : 
    1771            3 :     query = createPQExpBuffer();
    1772              : 
    1773              :     /*
    1774              :      * The loop below runs multiple SELECTs might sometimes result in
    1775              :      * duplicate entries in the OID list, but we don't care.
    1776              :      */
    1777              : 
    1778            5 :     for (cell = patterns->head; cell; cell = cell->next)
    1779              :     {
    1780              :         int         dotcnt;
    1781              : 
    1782            3 :         appendPQExpBufferStr(query,
    1783              :                              "SELECT oid FROM pg_catalog.pg_foreign_server s\n");
    1784            3 :         processSQLNamePattern(GetConnection(fout), query, cell->val, false,
    1785              :                               false, NULL, "s.srvname", NULL, NULL, NULL,
    1786              :                               &dotcnt);
    1787            3 :         if (dotcnt > 0)
    1788            0 :             pg_fatal("improper qualified name (too many dotted names): %s",
    1789              :                      cell->val);
    1790              : 
    1791            3 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    1792            3 :         if (PQntuples(res) == 0)
    1793            1 :             pg_fatal("no matching foreign servers were found for pattern \"%s\"", cell->val);
    1794              : 
    1795            4 :         for (i = 0; i < PQntuples(res); i++)
    1796            2 :             simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
    1797              : 
    1798            2 :         PQclear(res);
    1799            2 :         resetPQExpBuffer(query);
    1800              :     }
    1801              : 
    1802            2 :     destroyPQExpBuffer(query);
    1803              : }
    1804              : 
    1805              : /*
    1806              :  * Find the OIDs of all tables matching the given list of patterns,
    1807              :  * and append them to the given OID list. See also expand_dbname_patterns()
    1808              :  * in pg_dumpall.c
    1809              :  */
    1810              : static void
    1811         1581 : expand_table_name_patterns(Archive *fout,
    1812              :                            SimpleStringList *patterns, SimpleOidList *oids,
    1813              :                            bool strict_names, bool with_child_tables)
    1814              : {
    1815              :     PQExpBuffer query;
    1816              :     PGresult   *res;
    1817              :     SimpleStringListCell *cell;
    1818              :     int         i;
    1819              : 
    1820         1581 :     if (patterns->head == NULL)
    1821         1552 :         return;                 /* nothing to do */
    1822              : 
    1823           29 :     query = createPQExpBuffer();
    1824              : 
    1825              :     /*
    1826              :      * this might sometimes result in duplicate entries in the OID list, but
    1827              :      * we don't care.
    1828              :      */
    1829              : 
    1830           59 :     for (cell = patterns->head; cell; cell = cell->next)
    1831              :     {
    1832              :         PQExpBufferData dbbuf;
    1833              :         int         dotcnt;
    1834              : 
    1835              :         /*
    1836              :          * Query must remain ABSOLUTELY devoid of unqualified names.  This
    1837              :          * would be unnecessary given a pg_table_is_visible() variant taking a
    1838              :          * search_path argument.
    1839              :          *
    1840              :          * For with_child_tables, we start with the basic query's results and
    1841              :          * recursively search the inheritance tree to add child tables.
    1842              :          */
    1843           35 :         if (with_child_tables)
    1844              :         {
    1845            6 :             appendPQExpBufferStr(query, "WITH RECURSIVE partition_tree (relid) AS (\n");
    1846              :         }
    1847              : 
    1848           35 :         appendPQExpBuffer(query,
    1849              :                           "SELECT c.oid"
    1850              :                           "\nFROM pg_catalog.pg_class c"
    1851              :                           "\n     LEFT JOIN pg_catalog.pg_namespace n"
    1852              :                           "\n     ON n.oid OPERATOR(pg_catalog.=) c.relnamespace"
    1853              :                           "\nWHERE c.relkind OPERATOR(pg_catalog.=) ANY"
    1854              :                           "\n    (array['%c', '%c', '%c', '%c', '%c', '%c', '%c'])\n",
    1855              :                           RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_VIEW,
    1856              :                           RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE,
    1857              :                           RELKIND_PARTITIONED_TABLE, RELKIND_PROPGRAPH);
    1858           35 :         initPQExpBuffer(&dbbuf);
    1859           35 :         processSQLNamePattern(GetConnection(fout), query, cell->val, true,
    1860              :                               false, "n.nspname", "c.relname", NULL,
    1861              :                               "pg_catalog.pg_table_is_visible(c.oid)", &dbbuf,
    1862              :                               &dotcnt);
    1863           35 :         if (dotcnt > 2)
    1864            1 :             pg_fatal("improper relation name (too many dotted names): %s",
    1865              :                      cell->val);
    1866           34 :         else if (dotcnt == 2)
    1867            2 :             prohibit_crossdb_refs(GetConnection(fout), dbbuf.data, cell->val);
    1868           32 :         termPQExpBuffer(&dbbuf);
    1869              : 
    1870           32 :         if (with_child_tables)
    1871              :         {
    1872            6 :             appendPQExpBufferStr(query, "UNION"
    1873              :                                  "\nSELECT i.inhrelid"
    1874              :                                  "\nFROM partition_tree p"
    1875              :                                  "\n     JOIN pg_catalog.pg_inherits i"
    1876              :                                  "\n     ON p.relid OPERATOR(pg_catalog.=) i.inhparent"
    1877              :                                  "\n)"
    1878              :                                  "\nSELECT relid FROM partition_tree");
    1879              :         }
    1880              : 
    1881           32 :         ExecuteSqlStatement(fout, "RESET search_path");
    1882           32 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    1883           32 :         PQclear(ExecuteSqlQueryForSingleRow(fout,
    1884              :                                             ALWAYS_SECURE_SEARCH_PATH_SQL));
    1885           32 :         if (strict_names && PQntuples(res) == 0)
    1886            2 :             pg_fatal("no matching tables were found for pattern \"%s\"", cell->val);
    1887              : 
    1888           74 :         for (i = 0; i < PQntuples(res); i++)
    1889              :         {
    1890           44 :             simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
    1891              :         }
    1892              : 
    1893           30 :         PQclear(res);
    1894           30 :         resetPQExpBuffer(query);
    1895              :     }
    1896              : 
    1897           24 :     destroyPQExpBuffer(query);
    1898              : }
    1899              : 
    1900              : /*
    1901              :  * Verifies that the connected database name matches the given database name,
    1902              :  * and if not, dies with an error about the given pattern.
    1903              :  *
    1904              :  * The 'dbname' argument should be a literal name parsed from 'pattern'.
    1905              :  */
    1906              : static void
    1907            5 : prohibit_crossdb_refs(PGconn *conn, const char *dbname, const char *pattern)
    1908              : {
    1909              :     const char *db;
    1910              : 
    1911            5 :     db = PQdb(conn);
    1912            5 :     if (db == NULL)
    1913            0 :         pg_fatal("You are currently not connected to a database.");
    1914              : 
    1915            5 :     if (strcmp(db, dbname) != 0)
    1916            5 :         pg_fatal("cross-database references are not implemented: %s",
    1917              :                  pattern);
    1918            0 : }
    1919              : 
    1920              : /*
    1921              :  * checkExtensionMembership
    1922              :  *      Determine whether object is an extension member, and if so,
    1923              :  *      record an appropriate dependency and set the object's dump flag.
    1924              :  *
    1925              :  * It's important to call this for each object that could be an extension
    1926              :  * member.  Generally, we integrate this with determining the object's
    1927              :  * to-be-dumped-ness, since extension membership overrides other rules for that.
    1928              :  *
    1929              :  * Returns true if object is an extension member, else false.
    1930              :  */
    1931              : static bool
    1932       840268 : checkExtensionMembership(DumpableObject *dobj, Archive *fout)
    1933              : {
    1934       840268 :     ExtensionInfo *ext = findOwningExtension(dobj->catId);
    1935              : 
    1936       840268 :     if (ext == NULL)
    1937       839383 :         return false;
    1938              : 
    1939          885 :     dobj->ext_member = true;
    1940              : 
    1941              :     /* Record dependency so that getDependencies needn't deal with that */
    1942          885 :     addObjectDependency(dobj, ext->dobj.dumpId);
    1943              : 
    1944              :     /*
    1945              :      * In 9.6 and above, mark the member object to have any non-initial ACLs
    1946              :      * dumped.  (Any initial ACLs will be removed later, using data from
    1947              :      * pg_init_privs, so that we'll dump only the delta from the extension's
    1948              :      * initial setup.)
    1949              :      *
    1950              :      * Prior to 9.6, we do not include any extension member components.
    1951              :      *
    1952              :      * In binary upgrades, we still dump all components of the members
    1953              :      * individually, since the idea is to exactly reproduce the database
    1954              :      * contents rather than replace the extension contents with something
    1955              :      * different.
    1956              :      *
    1957              :      * Note: it might be interesting someday to implement storage and delta
    1958              :      * dumping of extension members' RLS policies and/or security labels.
    1959              :      * However there is a pitfall for RLS policies: trying to dump them
    1960              :      * requires getting a lock on their tables, and the calling user might not
    1961              :      * have privileges for that.  We need no lock to examine a table's ACLs,
    1962              :      * so the current feature doesn't have a problem of that sort.
    1963              :      */
    1964          885 :     if (fout->dopt->binary_upgrade)
    1965          186 :         dobj->dump = ext->dobj.dump;
    1966              :     else
    1967              :     {
    1968          699 :         if (fout->remoteVersion < 90600)
    1969            0 :             dobj->dump = DUMP_COMPONENT_NONE;
    1970              :         else
    1971          699 :             dobj->dump = ext->dobj.dump_contains & (DUMP_COMPONENT_ACL);
    1972              :     }
    1973              : 
    1974          885 :     return true;
    1975              : }
    1976              : 
    1977              : /*
    1978              :  * selectDumpableNamespace: policy-setting subroutine
    1979              :  *      Mark a namespace as to be dumped or not
    1980              :  */
    1981              : static void
    1982         1767 : selectDumpableNamespace(NamespaceInfo *nsinfo, Archive *fout)
    1983              : {
    1984              :     /*
    1985              :      * DUMP_COMPONENT_DEFINITION typically implies a CREATE SCHEMA statement
    1986              :      * and (for --clean) a DROP SCHEMA statement.  (In the absence of
    1987              :      * DUMP_COMPONENT_DEFINITION, this value is irrelevant.)
    1988              :      */
    1989         1767 :     nsinfo->create = true;
    1990              : 
    1991              :     /*
    1992              :      * If specific tables are being dumped, do not dump any complete
    1993              :      * namespaces. If specific namespaces are being dumped, dump just those
    1994              :      * namespaces. Otherwise, dump all non-system namespaces.
    1995              :      */
    1996         1767 :     if (table_include_oids.head != NULL)
    1997           50 :         nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
    1998         1717 :     else if (schema_include_oids.head != NULL)
    1999          195 :         nsinfo->dobj.dump_contains = nsinfo->dobj.dump =
    2000          195 :             simple_oid_list_member(&schema_include_oids,
    2001              :                                    nsinfo->dobj.catId.oid) ?
    2002          195 :             DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
    2003         1522 :     else if (fout->remoteVersion >= 90600 &&
    2004         1522 :              strcmp(nsinfo->dobj.name, "pg_catalog") == 0)
    2005              :     {
    2006              :         /*
    2007              :          * In 9.6 and above, we dump out any ACLs defined in pg_catalog, if
    2008              :          * they are interesting (and not the original ACLs which were set at
    2009              :          * initdb time, see pg_init_privs).
    2010              :          */
    2011          238 :         nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_ACL;
    2012              :     }
    2013         1284 :     else if (strncmp(nsinfo->dobj.name, "pg_", 3) == 0 ||
    2014          678 :              strcmp(nsinfo->dobj.name, "information_schema") == 0)
    2015              :     {
    2016              :         /* Other system schemas don't get dumped */
    2017          844 :         nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
    2018              :     }
    2019          440 :     else if (strcmp(nsinfo->dobj.name, "public") == 0)
    2020              :     {
    2021              :         /*
    2022              :          * The public schema is a strange beast that sits in a sort of
    2023              :          * no-mans-land between being a system object and a user object.
    2024              :          * CREATE SCHEMA would fail, so its DUMP_COMPONENT_DEFINITION is just
    2025              :          * a comment and an indication of ownership.  If the owner is the
    2026              :          * default, omit that superfluous DUMP_COMPONENT_DEFINITION.  Before
    2027              :          * v15, the default owner was BOOTSTRAP_SUPERUSERID.
    2028              :          */
    2029          234 :         nsinfo->create = false;
    2030          234 :         nsinfo->dobj.dump = DUMP_COMPONENT_ALL;
    2031          234 :         if (nsinfo->nspowner == ROLE_PG_DATABASE_OWNER)
    2032          192 :             nsinfo->dobj.dump &= ~DUMP_COMPONENT_DEFINITION;
    2033          234 :         nsinfo->dobj.dump_contains = DUMP_COMPONENT_ALL;
    2034              : 
    2035              :         /*
    2036              :          * Also, make like it has a comment even if it doesn't; this is so
    2037              :          * that we'll emit a command to drop the comment, if appropriate.
    2038              :          * (Without this, we'd not call dumpCommentExtended for it.)
    2039              :          */
    2040          234 :         nsinfo->dobj.components |= DUMP_COMPONENT_COMMENT;
    2041              :     }
    2042              :     else
    2043          206 :         nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_ALL;
    2044              : 
    2045              :     /*
    2046              :      * In any case, a namespace can be excluded by an exclusion switch
    2047              :      */
    2048         2456 :     if (nsinfo->dobj.dump_contains &&
    2049          689 :         simple_oid_list_member(&schema_exclude_oids,
    2050              :                                nsinfo->dobj.catId.oid))
    2051            3 :         nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
    2052              : 
    2053              :     /*
    2054              :      * If the schema belongs to an extension, allow extension membership to
    2055              :      * override the dump decision for the schema itself.  However, this does
    2056              :      * not change dump_contains, so this won't change what we do with objects
    2057              :      * within the schema.  (If they belong to the extension, they'll get
    2058              :      * suppressed by it, otherwise not.)
    2059              :      */
    2060         1767 :     (void) checkExtensionMembership(&nsinfo->dobj, fout);
    2061         1767 : }
    2062              : 
    2063              : /*
    2064              :  * selectDumpableTable: policy-setting subroutine
    2065              :  *      Mark a table as to be dumped or not
    2066              :  */
    2067              : static void
    2068        70009 : selectDumpableTable(TableInfo *tbinfo, Archive *fout)
    2069              : {
    2070        70009 :     if (checkExtensionMembership(&tbinfo->dobj, fout))
    2071          225 :         return;                 /* extension membership overrides all else */
    2072              : 
    2073              :     /*
    2074              :      * If specific tables are being dumped, dump just those tables; else, dump
    2075              :      * according to the parent namespace's dump flag.
    2076              :      */
    2077        69784 :     if (table_include_oids.head != NULL)
    2078         5580 :         tbinfo->dobj.dump = simple_oid_list_member(&table_include_oids,
    2079              :                                                    tbinfo->dobj.catId.oid) ?
    2080         2790 :             DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
    2081              :     else
    2082        66994 :         tbinfo->dobj.dump = tbinfo->dobj.namespace->dobj.dump_contains;
    2083              : 
    2084              :     /*
    2085              :      * In any case, a table can be excluded by an exclusion switch
    2086              :      */
    2087       113837 :     if (tbinfo->dobj.dump &&
    2088        44053 :         simple_oid_list_member(&table_exclude_oids,
    2089              :                                tbinfo->dobj.catId.oid))
    2090           12 :         tbinfo->dobj.dump = DUMP_COMPONENT_NONE;
    2091              : }
    2092              : 
    2093              : /*
    2094              :  * selectDumpableType: policy-setting subroutine
    2095              :  *      Mark a type as to be dumped or not
    2096              :  *
    2097              :  * If it's a table's rowtype or an autogenerated array type, we also apply a
    2098              :  * special type code to facilitate sorting into the desired order.  (We don't
    2099              :  * want to consider those to be ordinary types because that would bring tables
    2100              :  * up into the datatype part of the dump order.)  We still set the object's
    2101              :  * dump flag; that's not going to cause the dummy type to be dumped, but we
    2102              :  * need it so that casts involving such types will be dumped correctly -- see
    2103              :  * dumpCast.  This means the flag should be set the same as for the underlying
    2104              :  * object (the table or base type).
    2105              :  */
    2106              : static void
    2107       191483 : selectDumpableType(TypeInfo *tyinfo, Archive *fout)
    2108              : {
    2109              :     /* skip complex types, except for standalone composite types */
    2110       191483 :     if (OidIsValid(tyinfo->typrelid) &&
    2111        69254 :         tyinfo->typrelkind != RELKIND_COMPOSITE_TYPE)
    2112              :     {
    2113        69072 :         TableInfo  *tytable = findTableByOid(tyinfo->typrelid);
    2114              : 
    2115        69072 :         tyinfo->dobj.objType = DO_DUMMY_TYPE;
    2116        69072 :         if (tytable != NULL)
    2117        69072 :             tyinfo->dobj.dump = tytable->dobj.dump;
    2118              :         else
    2119            0 :             tyinfo->dobj.dump = DUMP_COMPONENT_NONE;
    2120        69072 :         return;
    2121              :     }
    2122              : 
    2123              :     /* skip auto-generated array and multirange types */
    2124       122411 :     if (tyinfo->isArray || tyinfo->isMultirange)
    2125              :     {
    2126        93646 :         tyinfo->dobj.objType = DO_DUMMY_TYPE;
    2127              : 
    2128              :         /*
    2129              :          * Fall through to set the dump flag; we assume that the subsequent
    2130              :          * rules will do the same thing as they would for the array's base
    2131              :          * type or multirange's range type.  (We cannot reliably look up the
    2132              :          * base type here, since getTypes may not have processed it yet.)
    2133              :          */
    2134              :     }
    2135              : 
    2136       122411 :     if (checkExtensionMembership(&tyinfo->dobj, fout))
    2137          150 :         return;                 /* extension membership overrides all else */
    2138              : 
    2139              :     /* Dump based on if the contents of the namespace are being dumped */
    2140       122261 :     tyinfo->dobj.dump = tyinfo->dobj.namespace->dobj.dump_contains;
    2141              : }
    2142              : 
    2143              : /*
    2144              :  * selectDumpableDefaultACL: policy-setting subroutine
    2145              :  *      Mark a default ACL as to be dumped or not
    2146              :  *
    2147              :  * For per-schema default ACLs, dump if the schema is to be dumped.
    2148              :  * Otherwise dump if we are dumping "everything".  Note that dumpSchema
    2149              :  * and aclsSkip are checked separately.
    2150              :  */
    2151              : static void
    2152          194 : selectDumpableDefaultACL(DefaultACLInfo *dinfo, DumpOptions *dopt)
    2153              : {
    2154              :     /* Default ACLs can't be extension members */
    2155              : 
    2156          194 :     if (dinfo->dobj.namespace)
    2157              :         /* default ACLs are considered part of the namespace */
    2158           90 :         dinfo->dobj.dump = dinfo->dobj.namespace->dobj.dump_contains;
    2159              :     else
    2160          104 :         dinfo->dobj.dump = dopt->include_everything ?
    2161          104 :             DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
    2162          194 : }
    2163              : 
    2164              : /*
    2165              :  * selectDumpableCast: policy-setting subroutine
    2166              :  *      Mark a cast as to be dumped or not
    2167              :  *
    2168              :  * Casts do not belong to any particular namespace (since they haven't got
    2169              :  * names), nor do they have identifiable owners.  To distinguish user-defined
    2170              :  * casts from built-in ones, we must resort to checking whether the cast's
    2171              :  * OID is in the range reserved for initdb.
    2172              :  */
    2173              : static void
    2174        63024 : selectDumpableCast(CastInfo *cast, Archive *fout)
    2175              : {
    2176        63024 :     if (checkExtensionMembership(&cast->dobj, fout))
    2177            0 :         return;                 /* extension membership overrides all else */
    2178              : 
    2179              :     /*
    2180              :      * This would be DUMP_COMPONENT_ACL for from-initdb casts, but they do not
    2181              :      * support ACLs currently.
    2182              :      */
    2183        63024 :     if (cast->dobj.catId.oid <= g_last_builtin_oid)
    2184        62937 :         cast->dobj.dump = DUMP_COMPONENT_NONE;
    2185              :     else
    2186           87 :         cast->dobj.dump = fout->dopt->include_everything ?
    2187           87 :             DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
    2188              : }
    2189              : 
    2190              : /*
    2191              :  * selectDumpableProcLang: policy-setting subroutine
    2192              :  *      Mark a procedural language as to be dumped or not
    2193              :  *
    2194              :  * Procedural languages do not belong to any particular namespace.  To
    2195              :  * identify built-in languages, we must resort to checking whether the
    2196              :  * language's OID is in the range reserved for initdb.
    2197              :  */
    2198              : static void
    2199          304 : selectDumpableProcLang(ProcLangInfo *plang, Archive *fout)
    2200              : {
    2201          304 :     if (checkExtensionMembership(&plang->dobj, fout))
    2202          259 :         return;                 /* extension membership overrides all else */
    2203              : 
    2204              :     /*
    2205              :      * Only include procedural languages when we are dumping everything.
    2206              :      *
    2207              :      * For from-initdb procedural languages, only include ACLs, as we do for
    2208              :      * the pg_catalog namespace.  We need this because procedural languages do
    2209              :      * not live in any namespace.
    2210              :      */
    2211           45 :     if (!fout->dopt->include_everything)
    2212            8 :         plang->dobj.dump = DUMP_COMPONENT_NONE;
    2213              :     else
    2214              :     {
    2215           37 :         if (plang->dobj.catId.oid <= g_last_builtin_oid)
    2216            0 :             plang->dobj.dump = fout->remoteVersion < 90600 ?
    2217            0 :                 DUMP_COMPONENT_NONE : DUMP_COMPONENT_ACL;
    2218              :         else
    2219           37 :             plang->dobj.dump = DUMP_COMPONENT_ALL;
    2220              :     }
    2221              : }
    2222              : 
    2223              : /*
    2224              :  * selectDumpableAccessMethod: policy-setting subroutine
    2225              :  *      Mark an access method as to be dumped or not
    2226              :  *
    2227              :  * Access methods do not belong to any particular namespace.  To identify
    2228              :  * built-in access methods, we must resort to checking whether the
    2229              :  * method's OID is in the range reserved for initdb.
    2230              :  */
    2231              : static void
    2232         1935 : selectDumpableAccessMethod(AccessMethodInfo *method, Archive *fout)
    2233              : {
    2234              :     /* see getAccessMethods() comment about v9.6. */
    2235         1935 :     if (fout->remoteVersion < 90600)
    2236              :     {
    2237            0 :         method->dobj.dump = DUMP_COMPONENT_NONE;
    2238            0 :         return;
    2239              :     }
    2240              : 
    2241         1935 :     if (checkExtensionMembership(&method->dobj, fout))
    2242           25 :         return;                 /* extension membership overrides all else */
    2243              : 
    2244              :     /*
    2245              :      * This would be DUMP_COMPONENT_ACL for from-initdb access methods, but
    2246              :      * they do not support ACLs currently.
    2247              :      */
    2248         1910 :     if (method->dobj.catId.oid <= g_last_builtin_oid)
    2249         1813 :         method->dobj.dump = DUMP_COMPONENT_NONE;
    2250              :     else
    2251           97 :         method->dobj.dump = fout->dopt->include_everything ?
    2252           97 :             DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
    2253              : }
    2254              : 
    2255              : /*
    2256              :  * selectDumpableExtension: policy-setting subroutine
    2257              :  *      Mark an extension as to be dumped or not
    2258              :  *
    2259              :  * Built-in extensions should be skipped except for checking ACLs, since we
    2260              :  * assume those will already be installed in the target database.  We identify
    2261              :  * such extensions by their having OIDs in the range reserved for initdb.
    2262              :  * We dump all user-added extensions by default.  No extensions are dumped
    2263              :  * if include_everything is false (i.e., a --schema or --table switch was
    2264              :  * given), except if --extension specifies a list of extensions to dump.
    2265              :  */
    2266              : static void
    2267          291 : selectDumpableExtension(ExtensionInfo *extinfo, DumpOptions *dopt)
    2268              : {
    2269              :     /*
    2270              :      * Use DUMP_COMPONENT_ACL for built-in extensions, to allow users to
    2271              :      * change permissions on their member objects, if they wish to, and have
    2272              :      * those changes preserved.
    2273              :      */
    2274          291 :     if (extinfo->dobj.catId.oid <= g_last_builtin_oid)
    2275          260 :         extinfo->dobj.dump = extinfo->dobj.dump_contains = DUMP_COMPONENT_ACL;
    2276              :     else
    2277              :     {
    2278              :         /* check if there is a list of extensions to dump */
    2279           31 :         if (extension_include_oids.head != NULL)
    2280            4 :             extinfo->dobj.dump = extinfo->dobj.dump_contains =
    2281            4 :                 simple_oid_list_member(&extension_include_oids,
    2282              :                                        extinfo->dobj.catId.oid) ?
    2283            4 :                 DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
    2284              :         else
    2285           27 :             extinfo->dobj.dump = extinfo->dobj.dump_contains =
    2286           27 :                 dopt->include_everything ?
    2287           27 :                 DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
    2288              : 
    2289              :         /* check that the extension is not explicitly excluded */
    2290           58 :         if (extinfo->dobj.dump &&
    2291           27 :             simple_oid_list_member(&extension_exclude_oids,
    2292              :                                    extinfo->dobj.catId.oid))
    2293            2 :             extinfo->dobj.dump = extinfo->dobj.dump_contains = DUMP_COMPONENT_NONE;
    2294              :     }
    2295          291 : }
    2296              : 
    2297              : /*
    2298              :  * selectDumpablePublicationObject: policy-setting subroutine
    2299              :  *      Mark a publication object as to be dumped or not
    2300              :  *
    2301              :  * A publication can have schemas and tables which have schemas, but those are
    2302              :  * ignored in decision making, because publications are only dumped when we are
    2303              :  * dumping everything.
    2304              :  */
    2305              : static void
    2306          475 : selectDumpablePublicationObject(DumpableObject *dobj, Archive *fout)
    2307              : {
    2308          475 :     if (checkExtensionMembership(dobj, fout))
    2309            0 :         return;                 /* extension membership overrides all else */
    2310              : 
    2311          475 :     dobj->dump = fout->dopt->include_everything ?
    2312          475 :         DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
    2313              : }
    2314              : 
    2315              : /*
    2316              :  * selectDumpableStatisticsObject: policy-setting subroutine
    2317              :  *      Mark an extended statistics object as to be dumped or not
    2318              :  *
    2319              :  * We dump an extended statistics object if the schema it's in and the table
    2320              :  * it's for are being dumped.  (This'll need more thought if statistics
    2321              :  * objects ever support cross-table stats.)
    2322              :  */
    2323              : static void
    2324          208 : selectDumpableStatisticsObject(StatsExtInfo *sobj, Archive *fout)
    2325              : {
    2326          208 :     if (checkExtensionMembership(&sobj->dobj, fout))
    2327            0 :         return;                 /* extension membership overrides all else */
    2328              : 
    2329          208 :     sobj->dobj.dump = sobj->dobj.namespace->dobj.dump_contains;
    2330          208 :     if (sobj->stattable == NULL ||
    2331          208 :         !(sobj->stattable->dobj.dump & DUMP_COMPONENT_DEFINITION))
    2332           35 :         sobj->dobj.dump = DUMP_COMPONENT_NONE;
    2333              : }
    2334              : 
    2335              : /*
    2336              :  * selectDumpableObject: policy-setting subroutine
    2337              :  *      Mark a generic dumpable object as to be dumped or not
    2338              :  *
    2339              :  * Use this only for object types without a special-case routine above.
    2340              :  */
    2341              : static void
    2342       580135 : selectDumpableObject(DumpableObject *dobj, Archive *fout)
    2343              : {
    2344       580135 :     if (checkExtensionMembership(dobj, fout))
    2345          201 :         return;                 /* extension membership overrides all else */
    2346              : 
    2347              :     /*
    2348              :      * Default policy is to dump if parent namespace is dumpable, or for
    2349              :      * non-namespace-associated items, dump if we're dumping "everything".
    2350              :      */
    2351       579934 :     if (dobj->namespace)
    2352       579070 :         dobj->dump = dobj->namespace->dobj.dump_contains;
    2353              :     else
    2354          864 :         dobj->dump = fout->dopt->include_everything ?
    2355          864 :             DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
    2356              : }
    2357              : 
    2358              : /*
    2359              :  *  Dump a table's contents for loading using the COPY command
    2360              :  *  - this routine is called by the Archiver when it wants the table
    2361              :  *    to be dumped.
    2362              :  */
    2363              : static int
    2364         4463 : dumpTableData_copy(Archive *fout, const void *dcontext)
    2365              : {
    2366         4463 :     const TableDataInfo *tdinfo = dcontext;
    2367         4463 :     const TableInfo *tbinfo = tdinfo->tdtable;
    2368         4463 :     const char *classname = tbinfo->dobj.name;
    2369         4463 :     PQExpBuffer q = createPQExpBuffer();
    2370              : 
    2371              :     /*
    2372              :      * Note: can't use getThreadLocalPQExpBuffer() here, we're calling fmtId
    2373              :      * which uses it already.
    2374              :      */
    2375         4463 :     PQExpBuffer clistBuf = createPQExpBuffer();
    2376         4463 :     PGconn     *conn = GetConnection(fout);
    2377              :     PGresult   *res;
    2378              :     int         ret;
    2379              :     char       *copybuf;
    2380              :     const char *column_list;
    2381              : 
    2382         4463 :     pg_log_info("dumping contents of table \"%s.%s\"",
    2383              :                 tbinfo->dobj.namespace->dobj.name, classname);
    2384              : 
    2385              :     /*
    2386              :      * Specify the column list explicitly so that we have no possibility of
    2387              :      * retrieving data in the wrong column order.  (The default column
    2388              :      * ordering of COPY will not be what we want in certain corner cases
    2389              :      * involving ADD COLUMN and inheritance.)
    2390              :      */
    2391         4463 :     column_list = fmtCopyColumnList(tbinfo, clistBuf);
    2392              : 
    2393              :     /*
    2394              :      * Use COPY (SELECT ...) TO when dumping a foreign table's data, when a
    2395              :      * filter condition was specified, and when in binary upgrade mode and
    2396              :      * dumping an old pg_largeobject_metadata defined WITH OIDS.  For other
    2397              :      * cases a simple COPY suffices.
    2398              :      */
    2399         4463 :     if (tdinfo->filtercond || tbinfo->relkind == RELKIND_FOREIGN_TABLE ||
    2400         4422 :         (fout->dopt->binary_upgrade && fout->remoteVersion < 120000 &&
    2401            0 :          tbinfo->dobj.catId.oid == LargeObjectMetadataRelationId))
    2402              :     {
    2403              :         /* Temporary allows to access to foreign tables to dump data */
    2404           41 :         if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
    2405            1 :             set_restrict_relation_kind(fout, "view");
    2406              : 
    2407           41 :         appendPQExpBufferStr(q, "COPY (SELECT ");
    2408              :         /* klugery to get rid of parens in column list */
    2409           41 :         if (strlen(column_list) > 2)
    2410              :         {
    2411           41 :             appendPQExpBufferStr(q, column_list + 1);
    2412           41 :             q->data[q->len - 1] = ' ';
    2413              :         }
    2414              :         else
    2415            0 :             appendPQExpBufferStr(q, "* ");
    2416              : 
    2417           82 :         appendPQExpBuffer(q, "FROM %s %s) TO stdout;",
    2418           41 :                           fmtQualifiedDumpable(tbinfo),
    2419           41 :                           tdinfo->filtercond ? tdinfo->filtercond : "");
    2420              :     }
    2421              :     else
    2422              :     {
    2423         4422 :         appendPQExpBuffer(q, "COPY %s %s TO stdout;",
    2424         4422 :                           fmtQualifiedDumpable(tbinfo),
    2425              :                           column_list);
    2426              :     }
    2427         4463 :     res = ExecuteSqlQuery(fout, q->data, PGRES_COPY_OUT);
    2428         4462 :     PQclear(res);
    2429         4462 :     destroyPQExpBuffer(clistBuf);
    2430              : 
    2431              :     for (;;)
    2432              :     {
    2433      1823465 :         ret = PQgetCopyData(conn, &copybuf, 0);
    2434              : 
    2435      1823465 :         if (ret < 0)
    2436         4462 :             break;              /* done or error */
    2437              : 
    2438      1819003 :         if (copybuf)
    2439              :         {
    2440      1819003 :             WriteData(fout, copybuf, ret);
    2441      1819003 :             PQfreemem(copybuf);
    2442              :         }
    2443              : 
    2444              :         /* ----------
    2445              :          * THROTTLE:
    2446              :          *
    2447              :          * There was considerable discussion in late July, 2000 regarding
    2448              :          * slowing down pg_dump when backing up large tables. Users with both
    2449              :          * slow & fast (multi-processor) machines experienced performance
    2450              :          * degradation when doing a backup.
    2451              :          *
    2452              :          * Initial attempts based on sleeping for a number of ms for each ms
    2453              :          * of work were deemed too complex, then a simple 'sleep in each loop'
    2454              :          * implementation was suggested. The latter failed because the loop
    2455              :          * was too tight. Finally, the following was implemented:
    2456              :          *
    2457              :          * If throttle is non-zero, then
    2458              :          *      See how long since the last sleep.
    2459              :          *      Work out how long to sleep (based on ratio).
    2460              :          *      If sleep is more than 100ms, then
    2461              :          *          sleep
    2462              :          *          reset timer
    2463              :          *      EndIf
    2464              :          * EndIf
    2465              :          *
    2466              :          * where the throttle value was the number of ms to sleep per ms of
    2467              :          * work. The calculation was done in each loop.
    2468              :          *
    2469              :          * Most of the hard work is done in the backend, and this solution
    2470              :          * still did not work particularly well: on slow machines, the ratio
    2471              :          * was 50:1, and on medium paced machines, 1:1, and on fast
    2472              :          * multi-processor machines, it had little or no effect, for reasons
    2473              :          * that were unclear.
    2474              :          *
    2475              :          * Further discussion ensued, and the proposal was dropped.
    2476              :          *
    2477              :          * For those people who want this feature, it can be implemented using
    2478              :          * gettimeofday in each loop, calculating the time since last sleep,
    2479              :          * multiplying that by the sleep ratio, then if the result is more
    2480              :          * than a preset 'minimum sleep time' (say 100ms), call the 'select'
    2481              :          * function to sleep for a subsecond period ie.
    2482              :          *
    2483              :          * select(0, NULL, NULL, NULL, &tvi);
    2484              :          *
    2485              :          * This will return after the interval specified in the structure tvi.
    2486              :          * Finally, call gettimeofday again to save the 'last sleep time'.
    2487              :          * ----------
    2488              :          */
    2489              :     }
    2490         4462 :     archprintf(fout, "\\.\n\n\n");
    2491              : 
    2492         4462 :     if (ret == -2)
    2493              :     {
    2494              :         /* copy data transfer failed */
    2495            0 :         pg_log_error("Dumping the contents of table \"%s\" failed: PQgetCopyData() failed.", classname);
    2496            0 :         pg_log_error_detail("Error message from server: %s", PQerrorMessage(conn));
    2497            0 :         pg_log_error_detail("Command was: %s", q->data);
    2498            0 :         exit_nicely(1);
    2499              :     }
    2500              : 
    2501              :     /* Check command status and return to normal libpq state */
    2502         4462 :     res = PQgetResult(conn);
    2503         4462 :     if (PQresultStatus(res) != PGRES_COMMAND_OK)
    2504              :     {
    2505            0 :         pg_log_error("Dumping the contents of table \"%s\" failed: PQgetResult() failed.", classname);
    2506            0 :         pg_log_error_detail("Error message from server: %s", PQerrorMessage(conn));
    2507            0 :         pg_log_error_detail("Command was: %s", q->data);
    2508            0 :         exit_nicely(1);
    2509              :     }
    2510         4462 :     PQclear(res);
    2511              : 
    2512              :     /* Do this to ensure we've pumped libpq back to idle state */
    2513         4462 :     if (PQgetResult(conn) != NULL)
    2514            0 :         pg_log_warning("unexpected extra results during COPY of table \"%s\"",
    2515              :                        classname);
    2516              : 
    2517         4462 :     destroyPQExpBuffer(q);
    2518              : 
    2519              :     /* Revert back the setting */
    2520         4462 :     if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
    2521            0 :         set_restrict_relation_kind(fout, "view, foreign-table");
    2522              : 
    2523         4462 :     return 1;
    2524              : }
    2525              : 
    2526              : /*
    2527              :  * Dump table data using INSERT commands.
    2528              :  *
    2529              :  * Caution: when we restore from an archive file direct to database, the
    2530              :  * INSERT commands emitted by this function have to be parsed by
    2531              :  * pg_backup_db.c's ExecuteSimpleCommands(), which will not handle comments,
    2532              :  * E'' strings, or dollar-quoted strings.  So don't emit anything like that.
    2533              :  */
    2534              : static int
    2535           87 : dumpTableData_insert(Archive *fout, const void *dcontext)
    2536              : {
    2537           87 :     const TableDataInfo *tdinfo = dcontext;
    2538           87 :     const TableInfo *tbinfo = tdinfo->tdtable;
    2539           87 :     DumpOptions *dopt = fout->dopt;
    2540           87 :     PQExpBuffer q = createPQExpBuffer();
    2541           87 :     PQExpBuffer insertStmt = NULL;
    2542              :     char       *attgenerated;
    2543              :     PGresult   *res;
    2544              :     int         nfields,
    2545              :                 i;
    2546           87 :     int         rows_per_statement = dopt->dump_inserts;
    2547           87 :     int         rows_this_statement = 0;
    2548              : 
    2549              :     /* Temporary allows to access to foreign tables to dump data */
    2550           87 :     if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
    2551            0 :         set_restrict_relation_kind(fout, "view");
    2552              : 
    2553              :     /*
    2554              :      * If we're going to emit INSERTs with column names, the most efficient
    2555              :      * way to deal with generated columns is to exclude them entirely.  For
    2556              :      * INSERTs without column names, we have to emit DEFAULT rather than the
    2557              :      * actual column value --- but we can save a few cycles by fetching nulls
    2558              :      * rather than the uninteresting-to-us value.
    2559              :      */
    2560           87 :     attgenerated = pg_malloc_array(char, tbinfo->numatts);
    2561           87 :     appendPQExpBufferStr(q, "DECLARE _pg_dump_cursor CURSOR FOR SELECT ");
    2562           87 :     nfields = 0;
    2563          269 :     for (i = 0; i < tbinfo->numatts; i++)
    2564              :     {
    2565          182 :         if (tbinfo->attisdropped[i])
    2566            2 :             continue;
    2567          180 :         if (tbinfo->attgenerated[i] && dopt->column_inserts)
    2568            8 :             continue;
    2569          172 :         if (nfields > 0)
    2570           92 :             appendPQExpBufferStr(q, ", ");
    2571          172 :         if (tbinfo->attgenerated[i])
    2572            8 :             appendPQExpBufferStr(q, "NULL");
    2573              :         else
    2574          164 :             appendPQExpBufferStr(q, fmtId(tbinfo->attnames[i]));
    2575          172 :         attgenerated[nfields] = tbinfo->attgenerated[i];
    2576          172 :         nfields++;
    2577              :     }
    2578              :     /* Servers before 9.4 will complain about zero-column SELECT */
    2579           87 :     if (nfields == 0)
    2580            7 :         appendPQExpBufferStr(q, "NULL");
    2581           87 :     appendPQExpBuffer(q, " FROM ONLY %s",
    2582           87 :                       fmtQualifiedDumpable(tbinfo));
    2583           87 :     if (tdinfo->filtercond)
    2584            0 :         appendPQExpBuffer(q, " %s", tdinfo->filtercond);
    2585              : 
    2586           87 :     ExecuteSqlStatement(fout, q->data);
    2587              : 
    2588              :     while (1)
    2589              :     {
    2590          139 :         res = ExecuteSqlQuery(fout, "FETCH 100 FROM _pg_dump_cursor",
    2591              :                               PGRES_TUPLES_OK);
    2592              : 
    2593              :         /* cross-check field count, allowing for dummy NULL if any */
    2594          139 :         if (nfields != PQnfields(res) &&
    2595           10 :             !(nfields == 0 && PQnfields(res) == 1))
    2596            0 :             pg_fatal("wrong number of fields retrieved from table \"%s\"",
    2597              :                      tbinfo->dobj.name);
    2598              : 
    2599              :         /*
    2600              :          * First time through, we build as much of the INSERT statement as
    2601              :          * possible in "insertStmt", which we can then just print for each
    2602              :          * statement. If the table happens to have zero dumpable columns then
    2603              :          * this will be a complete statement, otherwise it will end in
    2604              :          * "VALUES" and be ready to have the row's column values printed.
    2605              :          */
    2606          139 :         if (insertStmt == NULL)
    2607              :         {
    2608              :             const TableInfo *targettab;
    2609              : 
    2610           87 :             insertStmt = createPQExpBuffer();
    2611              : 
    2612              :             /*
    2613              :              * When load-via-partition-root is set or forced, get the root
    2614              :              * table name for the partition table, so that we can reload data
    2615              :              * through the root table.
    2616              :              */
    2617           87 :             if (tbinfo->ispartition &&
    2618           48 :                 (dopt->load_via_partition_root ||
    2619           24 :                  forcePartitionRootLoad(tbinfo)))
    2620            7 :                 targettab = getRootTableInfo(tbinfo);
    2621              :             else
    2622           80 :                 targettab = tbinfo;
    2623              : 
    2624           87 :             appendPQExpBuffer(insertStmt, "INSERT INTO %s ",
    2625           87 :                               fmtQualifiedDumpable(targettab));
    2626              : 
    2627              :             /* corner case for zero-column table */
    2628           87 :             if (nfields == 0)
    2629              :             {
    2630            7 :                 appendPQExpBufferStr(insertStmt, "DEFAULT VALUES;\n");
    2631              :             }
    2632              :             else
    2633              :             {
    2634              :                 /* append the list of column names if required */
    2635           80 :                 if (dopt->column_inserts)
    2636              :                 {
    2637           36 :                     appendPQExpBufferChar(insertStmt, '(');
    2638          109 :                     for (int field = 0; field < nfields; field++)
    2639              :                     {
    2640           73 :                         if (field > 0)
    2641           37 :                             appendPQExpBufferStr(insertStmt, ", ");
    2642           73 :                         appendPQExpBufferStr(insertStmt,
    2643           73 :                                              fmtId(PQfname(res, field)));
    2644              :                     }
    2645           36 :                     appendPQExpBufferStr(insertStmt, ") ");
    2646              :                 }
    2647              : 
    2648           80 :                 if (tbinfo->needs_override)
    2649            2 :                     appendPQExpBufferStr(insertStmt, "OVERRIDING SYSTEM VALUE ");
    2650              : 
    2651           80 :                 appendPQExpBufferStr(insertStmt, "VALUES");
    2652              :             }
    2653              :         }
    2654              : 
    2655         3608 :         for (int tuple = 0; tuple < PQntuples(res); tuple++)
    2656              :         {
    2657              :             /* Write the INSERT if not in the middle of a multi-row INSERT. */
    2658         3469 :             if (rows_this_statement == 0)
    2659         3463 :                 archputs(insertStmt->data, fout);
    2660              : 
    2661              :             /*
    2662              :              * If it is zero-column table then we've already written the
    2663              :              * complete statement, which will mean we've disobeyed
    2664              :              * --rows-per-insert when it's set greater than 1.  We do support
    2665              :              * a way to make this multi-row with: SELECT UNION ALL SELECT
    2666              :              * UNION ALL ... but that's non-standard so we should avoid it
    2667              :              * given that using INSERTs is mostly only ever needed for
    2668              :              * cross-database exports.
    2669              :              */
    2670         3469 :             if (nfields == 0)
    2671            6 :                 continue;
    2672              : 
    2673              :             /* Emit a row heading */
    2674         3463 :             if (rows_per_statement == 1)
    2675         3454 :                 archputs(" (", fout);
    2676            9 :             else if (rows_this_statement > 0)
    2677            6 :                 archputs(",\n\t(", fout);
    2678              :             else
    2679            3 :                 archputs("\n\t(", fout);
    2680              : 
    2681        10445 :             for (int field = 0; field < nfields; field++)
    2682              :             {
    2683         6982 :                 if (field > 0)
    2684         3519 :                     archputs(", ", fout);
    2685         6982 :                 if (attgenerated[field])
    2686              :                 {
    2687            2 :                     archputs("DEFAULT", fout);
    2688            2 :                     continue;
    2689              :                 }
    2690         6980 :                 if (PQgetisnull(res, tuple, field))
    2691              :                 {
    2692           83 :                     archputs("NULL", fout);
    2693           83 :                     continue;
    2694              :                 }
    2695              : 
    2696              :                 /* XXX This code is partially duplicated in ruleutils.c */
    2697         6897 :                 switch (PQftype(res, field))
    2698              :                 {
    2699         4869 :                     case INT2OID:
    2700              :                     case INT4OID:
    2701              :                     case INT8OID:
    2702              :                     case OIDOID:
    2703              :                     case FLOAT4OID:
    2704              :                     case FLOAT8OID:
    2705              :                     case NUMERICOID:
    2706              :                         {
    2707              :                             /*
    2708              :                              * These types are printed without quotes unless
    2709              :                              * they contain values that aren't accepted by the
    2710              :                              * scanner unquoted (e.g., 'NaN').  Note that
    2711              :                              * strtod() and friends might accept NaN, so we
    2712              :                              * can't use that to test.
    2713              :                              *
    2714              :                              * In reality we only need to defend against
    2715              :                              * infinity and NaN, so we need not get too crazy
    2716              :                              * about pattern matching here.
    2717              :                              */
    2718         4869 :                             const char *s = PQgetvalue(res, tuple, field);
    2719              : 
    2720         4869 :                             if (strspn(s, "0123456789 +-eE.") == strlen(s))
    2721         4867 :                                 archputs(s, fout);
    2722              :                             else
    2723            2 :                                 archprintf(fout, "'%s'", s);
    2724              :                         }
    2725         4869 :                         break;
    2726              : 
    2727            2 :                     case BITOID:
    2728              :                     case VARBITOID:
    2729            2 :                         archprintf(fout, "B'%s'",
    2730              :                                    PQgetvalue(res, tuple, field));
    2731            2 :                         break;
    2732              : 
    2733            4 :                     case BOOLOID:
    2734            4 :                         if (strcmp(PQgetvalue(res, tuple, field), "t") == 0)
    2735            2 :                             archputs("true", fout);
    2736              :                         else
    2737            2 :                             archputs("false", fout);
    2738            4 :                         break;
    2739              : 
    2740         2022 :                     default:
    2741              :                         /* All other types are printed as string literals. */
    2742         2022 :                         resetPQExpBuffer(q);
    2743         2022 :                         appendStringLiteralAH(q,
    2744              :                                               PQgetvalue(res, tuple, field),
    2745              :                                               fout);
    2746         2022 :                         archputs(q->data, fout);
    2747         2022 :                         break;
    2748              :                 }
    2749              :             }
    2750              : 
    2751              :             /* Terminate the row ... */
    2752         3463 :             archputs(")", fout);
    2753              : 
    2754              :             /* ... and the statement, if the target no. of rows is reached */
    2755         3463 :             if (++rows_this_statement >= rows_per_statement)
    2756              :             {
    2757         3456 :                 if (dopt->do_nothing)
    2758            0 :                     archputs(" ON CONFLICT DO NOTHING;\n", fout);
    2759              :                 else
    2760         3456 :                     archputs(";\n", fout);
    2761              :                 /* Reset the row counter */
    2762         3456 :                 rows_this_statement = 0;
    2763              :             }
    2764              :         }
    2765              : 
    2766          139 :         if (PQntuples(res) <= 0)
    2767              :         {
    2768           87 :             PQclear(res);
    2769           87 :             break;
    2770              :         }
    2771           52 :         PQclear(res);
    2772              :     }
    2773              : 
    2774              :     /* Terminate any statements that didn't make the row count. */
    2775           87 :     if (rows_this_statement > 0)
    2776              :     {
    2777            1 :         if (dopt->do_nothing)
    2778            0 :             archputs(" ON CONFLICT DO NOTHING;\n", fout);
    2779              :         else
    2780            1 :             archputs(";\n", fout);
    2781              :     }
    2782              : 
    2783           87 :     archputs("\n\n", fout);
    2784              : 
    2785           87 :     ExecuteSqlStatement(fout, "CLOSE _pg_dump_cursor");
    2786              : 
    2787           87 :     destroyPQExpBuffer(q);
    2788           87 :     if (insertStmt != NULL)
    2789           87 :         destroyPQExpBuffer(insertStmt);
    2790           87 :     free(attgenerated);
    2791              : 
    2792              :     /* Revert back the setting */
    2793           87 :     if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
    2794            0 :         set_restrict_relation_kind(fout, "view, foreign-table");
    2795              : 
    2796           87 :     return 1;
    2797              : }
    2798              : 
    2799              : /*
    2800              :  * getRootTableInfo:
    2801              :  *     get the root TableInfo for the given partition table.
    2802              :  */
    2803              : static TableInfo *
    2804           79 : getRootTableInfo(const TableInfo *tbinfo)
    2805              : {
    2806              :     TableInfo  *parentTbinfo;
    2807              : 
    2808              :     Assert(tbinfo->ispartition);
    2809              :     Assert(tbinfo->numParents == 1);
    2810              : 
    2811           79 :     parentTbinfo = tbinfo->parents[0];
    2812           79 :     while (parentTbinfo->ispartition)
    2813              :     {
    2814              :         Assert(parentTbinfo->numParents == 1);
    2815            0 :         parentTbinfo = parentTbinfo->parents[0];
    2816              :     }
    2817              : 
    2818           79 :     return parentTbinfo;
    2819              : }
    2820              : 
    2821              : /*
    2822              :  * forcePartitionRootLoad
    2823              :  *     Check if we must force load_via_partition_root for this partition.
    2824              :  *
    2825              :  * This is required if any level of ancestral partitioned table has an
    2826              :  * unsafe partitioning scheme.
    2827              :  */
    2828              : static bool
    2829         1076 : forcePartitionRootLoad(const TableInfo *tbinfo)
    2830              : {
    2831              :     TableInfo  *parentTbinfo;
    2832              : 
    2833              :     Assert(tbinfo->ispartition);
    2834              :     Assert(tbinfo->numParents == 1);
    2835              : 
    2836         1076 :     parentTbinfo = tbinfo->parents[0];
    2837         1076 :     if (parentTbinfo->unsafe_partitions)
    2838           79 :         return true;
    2839         1217 :     while (parentTbinfo->ispartition)
    2840              :     {
    2841              :         Assert(parentTbinfo->numParents == 1);
    2842          220 :         parentTbinfo = parentTbinfo->parents[0];
    2843          220 :         if (parentTbinfo->unsafe_partitions)
    2844            0 :             return true;
    2845              :     }
    2846              : 
    2847          997 :     return false;
    2848              : }
    2849              : 
    2850              : /*
    2851              :  * dumpTableData -
    2852              :  *    dump the contents of a single table
    2853              :  *
    2854              :  * Actually, this just makes an ArchiveEntry for the table contents.
    2855              :  */
    2856              : static void
    2857         4636 : dumpTableData(Archive *fout, const TableDataInfo *tdinfo)
    2858              : {
    2859         4636 :     DumpOptions *dopt = fout->dopt;
    2860         4636 :     const TableInfo *tbinfo = tdinfo->tdtable;
    2861         4636 :     PQExpBuffer copyBuf = createPQExpBuffer();
    2862         4636 :     PQExpBuffer clistBuf = createPQExpBuffer();
    2863              :     DataDumperPtr dumpFn;
    2864         4636 :     char       *tdDefn = NULL;
    2865              :     char       *copyStmt;
    2866              :     const char *copyFrom;
    2867              : 
    2868              :     /* We had better have loaded per-column details about this table */
    2869              :     Assert(tbinfo->interesting);
    2870              : 
    2871              :     /*
    2872              :      * When load-via-partition-root is set or forced, get the root table name
    2873              :      * for the partition table, so that we can reload data through the root
    2874              :      * table.  Then construct a comment to be inserted into the TOC entry's
    2875              :      * defn field, so that such cases can be identified reliably.
    2876              :      */
    2877         4636 :     if (tbinfo->ispartition &&
    2878         2104 :         (dopt->load_via_partition_root ||
    2879         1052 :          forcePartitionRootLoad(tbinfo)))
    2880           72 :     {
    2881              :         const TableInfo *parentTbinfo;
    2882              :         char       *sanitized;
    2883              : 
    2884           72 :         parentTbinfo = getRootTableInfo(tbinfo);
    2885           72 :         copyFrom = fmtQualifiedDumpable(parentTbinfo);
    2886           72 :         sanitized = sanitize_line(copyFrom, true);
    2887           72 :         printfPQExpBuffer(copyBuf, "-- load via partition root %s",
    2888              :                           sanitized);
    2889           72 :         free(sanitized);
    2890           72 :         tdDefn = pg_strdup(copyBuf->data);
    2891              :     }
    2892              :     else
    2893         4564 :         copyFrom = fmtQualifiedDumpable(tbinfo);
    2894              : 
    2895         4636 :     if (dopt->dump_inserts == 0)
    2896              :     {
    2897              :         /* Dump/restore using COPY */
    2898         4549 :         dumpFn = dumpTableData_copy;
    2899              :         /* must use 2 steps here 'cause fmtId is nonreentrant */
    2900         4549 :         printfPQExpBuffer(copyBuf, "COPY %s ",
    2901              :                           copyFrom);
    2902         4549 :         appendPQExpBuffer(copyBuf, "%s FROM stdin;\n",
    2903              :                           fmtCopyColumnList(tbinfo, clistBuf));
    2904         4549 :         copyStmt = copyBuf->data;
    2905              :     }
    2906              :     else
    2907              :     {
    2908              :         /* Restore using INSERT */
    2909           87 :         dumpFn = dumpTableData_insert;
    2910           87 :         copyStmt = NULL;
    2911              :     }
    2912              : 
    2913              :     /*
    2914              :      * Note: although the TableDataInfo is a full DumpableObject, we treat its
    2915              :      * dependency on its table as "special" and pass it to ArchiveEntry now.
    2916              :      * See comments for BuildArchiveDependencies.
    2917              :      */
    2918         4636 :     if (tdinfo->dobj.dump & DUMP_COMPONENT_DATA)
    2919              :     {
    2920              :         TocEntry   *te;
    2921              : 
    2922         4636 :         te = ArchiveEntry(fout, tdinfo->dobj.catId, tdinfo->dobj.dumpId,
    2923         4636 :                           ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
    2924              :                                        .namespace = tbinfo->dobj.namespace->dobj.name,
    2925              :                                        .owner = tbinfo->rolname,
    2926              :                                        .description = "TABLE DATA",
    2927              :                                        .section = SECTION_DATA,
    2928              :                                        .createStmt = tdDefn,
    2929              :                                        .copyStmt = copyStmt,
    2930              :                                        .deps = &(tbinfo->dobj.dumpId),
    2931              :                                        .nDeps = 1,
    2932              :                                        .dumpFn = dumpFn,
    2933              :                                        .dumpArg = tdinfo));
    2934              : 
    2935              :         /*
    2936              :          * Set the TocEntry's dataLength in case we are doing a parallel dump
    2937              :          * and want to order dump jobs by table size.  We choose to measure
    2938              :          * dataLength in table pages (including TOAST pages) during dump, so
    2939              :          * no scaling is needed.
    2940              :          *
    2941              :          * However, relpages is declared as "integer" in pg_class, and hence
    2942              :          * also in TableInfo, but it's really BlockNumber a/k/a unsigned int.
    2943              :          * Cast so that we get the right interpretation of table sizes
    2944              :          * exceeding INT_MAX pages.
    2945              :          */
    2946         4636 :         te->dataLength = (BlockNumber) tbinfo->relpages;
    2947         4636 :         te->dataLength += (BlockNumber) tbinfo->toastpages;
    2948              : 
    2949              :         /*
    2950              :          * If pgoff_t is only 32 bits wide, the above refinement is useless,
    2951              :          * and instead we'd better worry about integer overflow.  Clamp to
    2952              :          * INT_MAX if the correct result exceeds that.
    2953              :          */
    2954              :         if (sizeof(te->dataLength) == 4 &&
    2955              :             (tbinfo->relpages < 0 || tbinfo->toastpages < 0 ||
    2956              :              te->dataLength < 0))
    2957              :             te->dataLength = INT_MAX;
    2958              :     }
    2959              : 
    2960         4636 :     destroyPQExpBuffer(copyBuf);
    2961         4636 :     destroyPQExpBuffer(clistBuf);
    2962         4636 : }
    2963              : 
    2964              : /*
    2965              :  * refreshMatViewData -
    2966              :  *    load or refresh the contents of a single materialized view
    2967              :  *
    2968              :  * Actually, this just makes an ArchiveEntry for the REFRESH MATERIALIZED VIEW
    2969              :  * statement.
    2970              :  */
    2971              : static void
    2972          345 : refreshMatViewData(Archive *fout, const TableDataInfo *tdinfo)
    2973              : {
    2974          345 :     TableInfo  *tbinfo = tdinfo->tdtable;
    2975              :     PQExpBuffer q;
    2976              : 
    2977              :     /* If the materialized view is not flagged as populated, skip this. */
    2978          345 :     if (!tbinfo->relispopulated)
    2979           68 :         return;
    2980              : 
    2981          277 :     q = createPQExpBuffer();
    2982              : 
    2983          277 :     appendPQExpBuffer(q, "REFRESH MATERIALIZED VIEW %s;\n",
    2984          277 :                       fmtQualifiedDumpable(tbinfo));
    2985              : 
    2986          277 :     if (tdinfo->dobj.dump & DUMP_COMPONENT_DATA)
    2987          277 :         ArchiveEntry(fout,
    2988              :                      tdinfo->dobj.catId, /* catalog ID */
    2989          277 :                      tdinfo->dobj.dumpId,    /* dump ID */
    2990          277 :                      ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
    2991              :                                   .namespace = tbinfo->dobj.namespace->dobj.name,
    2992              :                                   .owner = tbinfo->rolname,
    2993              :                                   .description = "MATERIALIZED VIEW DATA",
    2994              :                                   .section = SECTION_POST_DATA,
    2995              :                                   .createStmt = q->data,
    2996              :                                   .deps = tdinfo->dobj.dependencies,
    2997              :                                   .nDeps = tdinfo->dobj.nDeps));
    2998              : 
    2999          277 :     destroyPQExpBuffer(q);
    3000              : }
    3001              : 
    3002              : /*
    3003              :  * getTableData -
    3004              :  *    set up dumpable objects representing the contents of tables
    3005              :  */
    3006              : static void
    3007          251 : getTableData(DumpOptions *dopt, TableInfo *tblinfo, int numTables, char relkind)
    3008              : {
    3009              :     int         i;
    3010              : 
    3011        68102 :     for (i = 0; i < numTables; i++)
    3012              :     {
    3013        67851 :         if (tblinfo[i].dobj.dump & DUMP_COMPONENT_DATA &&
    3014         1002 :             (!relkind || tblinfo[i].relkind == relkind))
    3015         6463 :             makeTableDataInfo(dopt, &(tblinfo[i]));
    3016              :     }
    3017          251 : }
    3018              : 
    3019              : /*
    3020              :  * Make a dumpable object for the data of this specific table
    3021              :  *
    3022              :  * Note: we make a TableDataInfo if and only if we are going to dump the
    3023              :  * table data; the "dump" field in such objects isn't very interesting.
    3024              :  */
    3025              : static void
    3026         6542 : makeTableDataInfo(DumpOptions *dopt, TableInfo *tbinfo)
    3027              : {
    3028              :     TableDataInfo *tdinfo;
    3029              : 
    3030              :     /*
    3031              :      * Nothing to do if we already decided to dump the table.  This will
    3032              :      * happen for "config" tables.
    3033              :      */
    3034         6542 :     if (tbinfo->dataObj != NULL)
    3035            1 :         return;
    3036              : 
    3037              :     /* Skip property graphs (no data to dump) */
    3038         6541 :     if (tbinfo->relkind == RELKIND_PROPGRAPH)
    3039           86 :         return;
    3040              :     /* Skip VIEWs (no data to dump) */
    3041         6455 :     if (tbinfo->relkind == RELKIND_VIEW)
    3042          502 :         return;
    3043              :     /* Skip FOREIGN TABLEs (no data to dump) unless requested explicitly */
    3044         5953 :     if (tbinfo->relkind == RELKIND_FOREIGN_TABLE &&
    3045           38 :         (foreign_servers_include_oids.head == NULL ||
    3046            4 :          !simple_oid_list_member(&foreign_servers_include_oids,
    3047              :                                  tbinfo->foreign_server)))
    3048           37 :         return;
    3049              :     /* Skip partitioned tables (data in partitions) */
    3050         5916 :     if (tbinfo->relkind == RELKIND_PARTITIONED_TABLE)
    3051          507 :         return;
    3052              : 
    3053              :     /* Don't dump data in unlogged tables, if so requested */
    3054         5409 :     if (tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED &&
    3055           41 :         dopt->no_unlogged_table_data)
    3056           18 :         return;
    3057              : 
    3058              :     /* Check that the data is not explicitly excluded */
    3059         5391 :     if (simple_oid_list_member(&tabledata_exclude_oids,
    3060              :                                tbinfo->dobj.catId.oid))
    3061            8 :         return;
    3062              : 
    3063              :     /* OK, let's dump it */
    3064         5383 :     tdinfo = pg_malloc_object(TableDataInfo);
    3065              : 
    3066         5383 :     if (tbinfo->relkind == RELKIND_MATVIEW)
    3067          345 :         tdinfo->dobj.objType = DO_REFRESH_MATVIEW;
    3068         5038 :     else if (tbinfo->relkind == RELKIND_SEQUENCE)
    3069          402 :         tdinfo->dobj.objType = DO_SEQUENCE_SET;
    3070              :     else
    3071         4636 :         tdinfo->dobj.objType = DO_TABLE_DATA;
    3072              : 
    3073              :     /*
    3074              :      * Note: use tableoid 0 so that this object won't be mistaken for
    3075              :      * something that pg_depend entries apply to.
    3076              :      */
    3077         5383 :     tdinfo->dobj.catId.tableoid = 0;
    3078         5383 :     tdinfo->dobj.catId.oid = tbinfo->dobj.catId.oid;
    3079         5383 :     AssignDumpId(&tdinfo->dobj);
    3080         5383 :     tdinfo->dobj.name = tbinfo->dobj.name;
    3081         5383 :     tdinfo->dobj.namespace = tbinfo->dobj.namespace;
    3082         5383 :     tdinfo->tdtable = tbinfo;
    3083         5383 :     tdinfo->filtercond = NULL;   /* might get set later */
    3084         5383 :     addObjectDependency(&tdinfo->dobj, tbinfo->dobj.dumpId);
    3085              : 
    3086              :     /* A TableDataInfo contains data, of course */
    3087         5383 :     tdinfo->dobj.components |= DUMP_COMPONENT_DATA;
    3088              : 
    3089         5383 :     tbinfo->dataObj = tdinfo;
    3090              : 
    3091              :     /*
    3092              :      * Materialized view statistics must be restored after the data, because
    3093              :      * REFRESH MATERIALIZED VIEW replaces the storage and resets the stats.
    3094              :      *
    3095              :      * The dependency is added here because the statistics objects are created
    3096              :      * first.
    3097              :      */
    3098         5383 :     if (tbinfo->relkind == RELKIND_MATVIEW && tbinfo->stats != NULL)
    3099              :     {
    3100          268 :         tbinfo->stats->section = SECTION_POST_DATA;
    3101          268 :         addObjectDependency(&tbinfo->stats->dobj, tdinfo->dobj.dumpId);
    3102              :     }
    3103              : 
    3104              :     /* Make sure that we'll collect per-column info for this table. */
    3105         5383 :     tbinfo->interesting = true;
    3106              : }
    3107              : 
    3108              : /*
    3109              :  * The refresh for a materialized view must be dependent on the refresh for
    3110              :  * any materialized view that this one is dependent on.
    3111              :  *
    3112              :  * This must be called after all the objects are created, but before they are
    3113              :  * sorted.
    3114              :  */
    3115              : static void
    3116          215 : buildMatViewRefreshDependencies(Archive *fout)
    3117              : {
    3118              :     PQExpBuffer query;
    3119              :     PGresult   *res;
    3120              :     int         ntups,
    3121              :                 i;
    3122              :     int         i_classid,
    3123              :                 i_objid,
    3124              :                 i_refobjid;
    3125              : 
    3126              :     /* No Mat Views before 9.3. */
    3127          215 :     if (fout->remoteVersion < 90300)
    3128            0 :         return;
    3129              : 
    3130          215 :     query = createPQExpBuffer();
    3131              : 
    3132          215 :     appendPQExpBufferStr(query, "WITH RECURSIVE w AS "
    3133              :                          "( "
    3134              :                          "SELECT d1.objid, d2.refobjid, c2.relkind AS refrelkind "
    3135              :                          "FROM pg_depend d1 "
    3136              :                          "JOIN pg_class c1 ON c1.oid = d1.objid "
    3137              :                          "AND c1.relkind = " CppAsString2(RELKIND_MATVIEW)
    3138              :                          " JOIN pg_rewrite r1 ON r1.ev_class = d1.objid "
    3139              :                          "JOIN pg_depend d2 ON d2.classid = 'pg_rewrite'::regclass "
    3140              :                          "AND d2.objid = r1.oid "
    3141              :                          "AND d2.refobjid <> d1.objid "
    3142              :                          "JOIN pg_class c2 ON c2.oid = d2.refobjid "
    3143              :                          "AND c2.relkind IN (" CppAsString2(RELKIND_MATVIEW) ","
    3144              :                          CppAsString2(RELKIND_VIEW) ") "
    3145              :                          "WHERE d1.classid = 'pg_class'::regclass "
    3146              :                          "UNION "
    3147              :                          "SELECT w.objid, d3.refobjid, c3.relkind "
    3148              :                          "FROM w "
    3149              :                          "JOIN pg_rewrite r3 ON r3.ev_class = w.refobjid "
    3150              :                          "JOIN pg_depend d3 ON d3.classid = 'pg_rewrite'::regclass "
    3151              :                          "AND d3.objid = r3.oid "
    3152              :                          "AND d3.refobjid <> w.refobjid "
    3153              :                          "JOIN pg_class c3 ON c3.oid = d3.refobjid "
    3154              :                          "AND c3.relkind IN (" CppAsString2(RELKIND_MATVIEW) ","
    3155              :                          CppAsString2(RELKIND_VIEW) ") "
    3156              :                          ") "
    3157              :                          "SELECT 'pg_class'::regclass::oid AS classid, objid, refobjid "
    3158              :                          "FROM w "
    3159              :                          "WHERE refrelkind = " CppAsString2(RELKIND_MATVIEW));
    3160              : 
    3161          215 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    3162              : 
    3163          215 :     ntups = PQntuples(res);
    3164              : 
    3165          215 :     i_classid = PQfnumber(res, "classid");
    3166          215 :     i_objid = PQfnumber(res, "objid");
    3167          215 :     i_refobjid = PQfnumber(res, "refobjid");
    3168              : 
    3169          479 :     for (i = 0; i < ntups; i++)
    3170              :     {
    3171              :         CatalogId   objId;
    3172              :         CatalogId   refobjId;
    3173              :         DumpableObject *dobj;
    3174              :         DumpableObject *refdobj;
    3175              :         TableInfo  *tbinfo;
    3176              :         TableInfo  *reftbinfo;
    3177              : 
    3178          264 :         objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
    3179          264 :         objId.oid = atooid(PQgetvalue(res, i, i_objid));
    3180          264 :         refobjId.tableoid = objId.tableoid;
    3181          264 :         refobjId.oid = atooid(PQgetvalue(res, i, i_refobjid));
    3182              : 
    3183          264 :         dobj = findObjectByCatalogId(objId);
    3184          264 :         if (dobj == NULL)
    3185           48 :             continue;
    3186              : 
    3187              :         Assert(dobj->objType == DO_TABLE);
    3188          264 :         tbinfo = (TableInfo *) dobj;
    3189              :         Assert(tbinfo->relkind == RELKIND_MATVIEW);
    3190          264 :         dobj = (DumpableObject *) tbinfo->dataObj;
    3191          264 :         if (dobj == NULL)
    3192           48 :             continue;
    3193              :         Assert(dobj->objType == DO_REFRESH_MATVIEW);
    3194              : 
    3195          216 :         refdobj = findObjectByCatalogId(refobjId);
    3196          216 :         if (refdobj == NULL)
    3197            0 :             continue;
    3198              : 
    3199              :         Assert(refdobj->objType == DO_TABLE);
    3200          216 :         reftbinfo = (TableInfo *) refdobj;
    3201              :         Assert(reftbinfo->relkind == RELKIND_MATVIEW);
    3202          216 :         refdobj = (DumpableObject *) reftbinfo->dataObj;
    3203          216 :         if (refdobj == NULL)
    3204            0 :             continue;
    3205              :         Assert(refdobj->objType == DO_REFRESH_MATVIEW);
    3206              : 
    3207          216 :         addObjectDependency(dobj, refdobj->dumpId);
    3208              : 
    3209          216 :         if (!reftbinfo->relispopulated)
    3210           34 :             tbinfo->relispopulated = false;
    3211              :     }
    3212              : 
    3213          215 :     PQclear(res);
    3214              : 
    3215          215 :     destroyPQExpBuffer(query);
    3216              : }
    3217              : 
    3218              : /*
    3219              :  * getTableDataFKConstraints -
    3220              :  *    add dump-order dependencies reflecting foreign key constraints
    3221              :  *
    3222              :  * This code is executed only in a data-only dump --- in schema+data dumps
    3223              :  * we handle foreign key issues by not creating the FK constraints until
    3224              :  * after the data is loaded.  In a data-only dump, however, we want to
    3225              :  * order the table data objects in such a way that a table's referenced
    3226              :  * tables are restored first.  (In the presence of circular references or
    3227              :  * self-references this may be impossible; we'll detect and complain about
    3228              :  * that during the dependency sorting step.)
    3229              :  */
    3230              : static void
    3231            7 : getTableDataFKConstraints(void)
    3232              : {
    3233              :     DumpableObject **dobjs;
    3234              :     int         numObjs;
    3235              :     int         i;
    3236              : 
    3237              :     /* Search through all the dumpable objects for FK constraints */
    3238            7 :     getDumpableObjects(&dobjs, &numObjs);
    3239        26929 :     for (i = 0; i < numObjs; i++)
    3240              :     {
    3241        26922 :         if (dobjs[i]->objType == DO_FK_CONSTRAINT)
    3242              :         {
    3243            8 :             ConstraintInfo *cinfo = (ConstraintInfo *) dobjs[i];
    3244              :             TableInfo  *ftable;
    3245              : 
    3246              :             /* Not interesting unless both tables are to be dumped */
    3247            8 :             if (cinfo->contable == NULL ||
    3248            8 :                 cinfo->contable->dataObj == NULL)
    3249            4 :                 continue;
    3250            4 :             ftable = findTableByOid(cinfo->confrelid);
    3251            4 :             if (ftable == NULL ||
    3252            4 :                 ftable->dataObj == NULL)
    3253            0 :                 continue;
    3254              : 
    3255              :             /*
    3256              :              * Okay, make referencing table's TABLE_DATA object depend on the
    3257              :              * referenced table's TABLE_DATA object.
    3258              :              */
    3259            4 :             addObjectDependency(&cinfo->contable->dataObj->dobj,
    3260            4 :                                 ftable->dataObj->dobj.dumpId);
    3261              :         }
    3262              :     }
    3263            7 :     free(dobjs);
    3264            7 : }
    3265              : 
    3266              : 
    3267              : /*
    3268              :  * dumpDatabase:
    3269              :  *  dump the database definition
    3270              :  */
    3271              : static void
    3272          160 : dumpDatabase(Archive *fout)
    3273              : {
    3274          160 :     DumpOptions *dopt = fout->dopt;
    3275          160 :     PQExpBuffer dbQry = createPQExpBuffer();
    3276          160 :     PQExpBuffer delQry = createPQExpBuffer();
    3277          160 :     PQExpBuffer creaQry = createPQExpBuffer();
    3278          160 :     PQExpBuffer labelq = createPQExpBuffer();
    3279          160 :     PGconn     *conn = GetConnection(fout);
    3280              :     PGresult   *res;
    3281              :     int         i_tableoid,
    3282              :                 i_oid,
    3283              :                 i_datname,
    3284              :                 i_datdba,
    3285              :                 i_encoding,
    3286              :                 i_datlocprovider,
    3287              :                 i_collate,
    3288              :                 i_ctype,
    3289              :                 i_datlocale,
    3290              :                 i_daticurules,
    3291              :                 i_frozenxid,
    3292              :                 i_minmxid,
    3293              :                 i_datacl,
    3294              :                 i_acldefault,
    3295              :                 i_datistemplate,
    3296              :                 i_datconnlimit,
    3297              :                 i_datcollversion,
    3298              :                 i_tablespace;
    3299              :     CatalogId   dbCatId;
    3300              :     DumpId      dbDumpId;
    3301              :     DumpableAcl dbdacl;
    3302              :     const char *datname,
    3303              :                *dba,
    3304              :                *encoding,
    3305              :                *datlocprovider,
    3306              :                *collate,
    3307              :                *ctype,
    3308              :                *locale,
    3309              :                *icurules,
    3310              :                *datistemplate,
    3311              :                *datconnlimit,
    3312              :                *tablespace;
    3313              :     uint32      frozenxid,
    3314              :                 minmxid;
    3315              :     char       *qdatname;
    3316              : 
    3317          160 :     pg_log_info("saving database definition");
    3318              : 
    3319              :     /*
    3320              :      * Fetch the database-level properties for this database.
    3321              :      */
    3322          160 :     appendPQExpBufferStr(dbQry, "SELECT tableoid, oid, datname, "
    3323              :                          "datdba, "
    3324              :                          "pg_encoding_to_char(encoding) AS encoding, "
    3325              :                          "datcollate, datctype, datfrozenxid, "
    3326              :                          "datacl, acldefault('d', datdba) AS acldefault, "
    3327              :                          "datistemplate, datconnlimit, ");
    3328          160 :     if (fout->remoteVersion >= 90300)
    3329          160 :         appendPQExpBufferStr(dbQry, "datminmxid, ");
    3330              :     else
    3331            0 :         appendPQExpBufferStr(dbQry, "0 AS datminmxid, ");
    3332          160 :     if (fout->remoteVersion >= 170000)
    3333          160 :         appendPQExpBufferStr(dbQry, "datlocprovider, datlocale, datcollversion, ");
    3334            0 :     else if (fout->remoteVersion >= 150000)
    3335            0 :         appendPQExpBufferStr(dbQry, "datlocprovider, daticulocale AS datlocale, datcollversion, ");
    3336              :     else
    3337            0 :         appendPQExpBufferStr(dbQry, "'c' AS datlocprovider, NULL AS datlocale, NULL AS datcollversion, ");
    3338          160 :     if (fout->remoteVersion >= 160000)
    3339          160 :         appendPQExpBufferStr(dbQry, "daticurules, ");
    3340              :     else
    3341            0 :         appendPQExpBufferStr(dbQry, "NULL AS daticurules, ");
    3342          160 :     appendPQExpBufferStr(dbQry,
    3343              :                          "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace, "
    3344              :                          "shobj_description(oid, 'pg_database') AS description "
    3345              :                          "FROM pg_database "
    3346              :                          "WHERE datname = current_database()");
    3347              : 
    3348          160 :     res = ExecuteSqlQueryForSingleRow(fout, dbQry->data);
    3349              : 
    3350          160 :     i_tableoid = PQfnumber(res, "tableoid");
    3351          160 :     i_oid = PQfnumber(res, "oid");
    3352          160 :     i_datname = PQfnumber(res, "datname");
    3353          160 :     i_datdba = PQfnumber(res, "datdba");
    3354          160 :     i_encoding = PQfnumber(res, "encoding");
    3355          160 :     i_datlocprovider = PQfnumber(res, "datlocprovider");
    3356          160 :     i_collate = PQfnumber(res, "datcollate");
    3357          160 :     i_ctype = PQfnumber(res, "datctype");
    3358          160 :     i_datlocale = PQfnumber(res, "datlocale");
    3359          160 :     i_daticurules = PQfnumber(res, "daticurules");
    3360          160 :     i_frozenxid = PQfnumber(res, "datfrozenxid");
    3361          160 :     i_minmxid = PQfnumber(res, "datminmxid");
    3362          160 :     i_datacl = PQfnumber(res, "datacl");
    3363          160 :     i_acldefault = PQfnumber(res, "acldefault");
    3364          160 :     i_datistemplate = PQfnumber(res, "datistemplate");
    3365          160 :     i_datconnlimit = PQfnumber(res, "datconnlimit");
    3366          160 :     i_datcollversion = PQfnumber(res, "datcollversion");
    3367          160 :     i_tablespace = PQfnumber(res, "tablespace");
    3368              : 
    3369          160 :     dbCatId.tableoid = atooid(PQgetvalue(res, 0, i_tableoid));
    3370          160 :     dbCatId.oid = atooid(PQgetvalue(res, 0, i_oid));
    3371          160 :     datname = PQgetvalue(res, 0, i_datname);
    3372          160 :     dba = getRoleName(PQgetvalue(res, 0, i_datdba));
    3373          160 :     encoding = PQgetvalue(res, 0, i_encoding);
    3374          160 :     datlocprovider = PQgetvalue(res, 0, i_datlocprovider);
    3375          160 :     collate = PQgetvalue(res, 0, i_collate);
    3376          160 :     ctype = PQgetvalue(res, 0, i_ctype);
    3377          160 :     if (!PQgetisnull(res, 0, i_datlocale))
    3378           14 :         locale = PQgetvalue(res, 0, i_datlocale);
    3379              :     else
    3380          146 :         locale = NULL;
    3381          160 :     if (!PQgetisnull(res, 0, i_daticurules))
    3382            0 :         icurules = PQgetvalue(res, 0, i_daticurules);
    3383              :     else
    3384          160 :         icurules = NULL;
    3385          160 :     frozenxid = atooid(PQgetvalue(res, 0, i_frozenxid));
    3386          160 :     minmxid = atooid(PQgetvalue(res, 0, i_minmxid));
    3387          160 :     dbdacl.acl = PQgetvalue(res, 0, i_datacl);
    3388          160 :     dbdacl.acldefault = PQgetvalue(res, 0, i_acldefault);
    3389          160 :     datistemplate = PQgetvalue(res, 0, i_datistemplate);
    3390          160 :     datconnlimit = PQgetvalue(res, 0, i_datconnlimit);
    3391          160 :     tablespace = PQgetvalue(res, 0, i_tablespace);
    3392              : 
    3393          160 :     qdatname = pg_strdup(fmtId(datname));
    3394              : 
    3395              :     /*
    3396              :      * Prepare the CREATE DATABASE command.  We must specify OID (if we want
    3397              :      * to preserve that), as well as the encoding, locale, and tablespace
    3398              :      * since those can't be altered later.  Other DB properties are left to
    3399              :      * the DATABASE PROPERTIES entry, so that they can be applied after
    3400              :      * reconnecting to the target DB.
    3401              :      *
    3402              :      * For binary upgrade, we use the FILE_COPY strategy because testing has
    3403              :      * shown it to be faster.  When the server is in binary upgrade mode, it
    3404              :      * will also skip the checkpoints this strategy ordinarily performs.
    3405              :      */
    3406          160 :     if (dopt->binary_upgrade)
    3407              :     {
    3408           39 :         appendPQExpBuffer(creaQry,
    3409              :                           "CREATE DATABASE %s WITH TEMPLATE = template0 "
    3410              :                           "OID = %u STRATEGY = FILE_COPY",
    3411              :                           qdatname, dbCatId.oid);
    3412              :     }
    3413              :     else
    3414              :     {
    3415          121 :         appendPQExpBuffer(creaQry, "CREATE DATABASE %s WITH TEMPLATE = template0",
    3416              :                           qdatname);
    3417              :     }
    3418          160 :     if (strlen(encoding) > 0)
    3419              :     {
    3420          160 :         appendPQExpBufferStr(creaQry, " ENCODING = ");
    3421          160 :         appendStringLiteralAH(creaQry, encoding, fout);
    3422              :     }
    3423              : 
    3424          160 :     appendPQExpBufferStr(creaQry, " LOCALE_PROVIDER = ");
    3425          160 :     if (datlocprovider[0] == 'b')
    3426           14 :         appendPQExpBufferStr(creaQry, "builtin");
    3427          146 :     else if (datlocprovider[0] == 'c')
    3428          146 :         appendPQExpBufferStr(creaQry, "libc");
    3429            0 :     else if (datlocprovider[0] == 'i')
    3430            0 :         appendPQExpBufferStr(creaQry, "icu");
    3431              :     else
    3432            0 :         pg_fatal("unrecognized locale provider: %s",
    3433              :                  datlocprovider);
    3434              : 
    3435          160 :     if (strlen(collate) > 0 && strcmp(collate, ctype) == 0)
    3436              :     {
    3437          160 :         appendPQExpBufferStr(creaQry, " LOCALE = ");
    3438          160 :         appendStringLiteralAH(creaQry, collate, fout);
    3439              :     }
    3440              :     else
    3441              :     {
    3442            0 :         if (strlen(collate) > 0)
    3443              :         {
    3444            0 :             appendPQExpBufferStr(creaQry, " LC_COLLATE = ");
    3445            0 :             appendStringLiteralAH(creaQry, collate, fout);
    3446              :         }
    3447            0 :         if (strlen(ctype) > 0)
    3448              :         {
    3449            0 :             appendPQExpBufferStr(creaQry, " LC_CTYPE = ");
    3450            0 :             appendStringLiteralAH(creaQry, ctype, fout);
    3451              :         }
    3452              :     }
    3453          160 :     if (locale)
    3454              :     {
    3455           14 :         if (datlocprovider[0] == 'b')
    3456           14 :             appendPQExpBufferStr(creaQry, " BUILTIN_LOCALE = ");
    3457              :         else
    3458            0 :             appendPQExpBufferStr(creaQry, " ICU_LOCALE = ");
    3459              : 
    3460           14 :         appendStringLiteralAH(creaQry, locale, fout);
    3461              :     }
    3462              : 
    3463          160 :     if (icurules)
    3464              :     {
    3465            0 :         appendPQExpBufferStr(creaQry, " ICU_RULES = ");
    3466            0 :         appendStringLiteralAH(creaQry, icurules, fout);
    3467              :     }
    3468              : 
    3469              :     /*
    3470              :      * For binary upgrade, carry over the collation version.  For normal
    3471              :      * dump/restore, omit the version, so that it is computed upon restore.
    3472              :      */
    3473          160 :     if (dopt->binary_upgrade)
    3474              :     {
    3475           39 :         if (!PQgetisnull(res, 0, i_datcollversion))
    3476              :         {
    3477           39 :             appendPQExpBufferStr(creaQry, " COLLATION_VERSION = ");
    3478           39 :             appendStringLiteralAH(creaQry,
    3479              :                                   PQgetvalue(res, 0, i_datcollversion),
    3480              :                                   fout);
    3481              :         }
    3482              :     }
    3483              : 
    3484              :     /*
    3485              :      * Note: looking at dopt->outputNoTablespaces here is completely the wrong
    3486              :      * thing; the decision whether to specify a tablespace should be left till
    3487              :      * pg_restore, so that pg_restore --no-tablespaces applies.  Ideally we'd
    3488              :      * label the DATABASE entry with the tablespace and let the normal
    3489              :      * tablespace selection logic work ... but CREATE DATABASE doesn't pay
    3490              :      * attention to default_tablespace, so that won't work.
    3491              :      */
    3492          160 :     if (strlen(tablespace) > 0 && strcmp(tablespace, "pg_default") != 0 &&
    3493            5 :         !dopt->outputNoTablespaces)
    3494            5 :         appendPQExpBuffer(creaQry, " TABLESPACE = %s",
    3495              :                           fmtId(tablespace));
    3496          160 :     appendPQExpBufferStr(creaQry, ";\n");
    3497              : 
    3498          160 :     appendPQExpBuffer(delQry, "DROP DATABASE %s;\n",
    3499              :                       qdatname);
    3500              : 
    3501          160 :     dbDumpId = createDumpId();
    3502              : 
    3503          160 :     ArchiveEntry(fout,
    3504              :                  dbCatId,       /* catalog ID */
    3505              :                  dbDumpId,      /* dump ID */
    3506          160 :                  ARCHIVE_OPTS(.tag = datname,
    3507              :                               .owner = dba,
    3508              :                               .description = "DATABASE",
    3509              :                               .section = SECTION_PRE_DATA,
    3510              :                               .createStmt = creaQry->data,
    3511              :                               .dropStmt = delQry->data));
    3512              : 
    3513              :     /* Compute correct tag for archive entry */
    3514          160 :     appendPQExpBuffer(labelq, "DATABASE %s", qdatname);
    3515              : 
    3516              :     /* Dump DB comment if any */
    3517              :     {
    3518              :         /*
    3519              :          * 8.2 and up keep comments on shared objects in a shared table, so we
    3520              :          * cannot use the dumpComment() code used for other database objects.
    3521              :          * Be careful that the ArchiveEntry parameters match that function.
    3522              :          */
    3523          160 :         char       *comment = PQgetvalue(res, 0, PQfnumber(res, "description"));
    3524              : 
    3525          160 :         if (comment && *comment && !dopt->no_comments)
    3526              :         {
    3527           62 :             resetPQExpBuffer(dbQry);
    3528              : 
    3529              :             /*
    3530              :              * Generates warning when loaded into a differently-named
    3531              :              * database.
    3532              :              */
    3533           62 :             appendPQExpBuffer(dbQry, "COMMENT ON DATABASE %s IS ", qdatname);
    3534           62 :             appendStringLiteralAH(dbQry, comment, fout);
    3535           62 :             appendPQExpBufferStr(dbQry, ";\n");
    3536              : 
    3537           62 :             ArchiveEntry(fout, nilCatalogId, createDumpId(),
    3538           62 :                          ARCHIVE_OPTS(.tag = labelq->data,
    3539              :                                       .owner = dba,
    3540              :                                       .description = "COMMENT",
    3541              :                                       .section = SECTION_NONE,
    3542              :                                       .createStmt = dbQry->data,
    3543              :                                       .deps = &dbDumpId,
    3544              :                                       .nDeps = 1));
    3545              :         }
    3546              :     }
    3547              : 
    3548              :     /* Dump DB security label, if enabled */
    3549          160 :     if (!dopt->no_security_labels)
    3550              :     {
    3551              :         PGresult   *shres;
    3552              :         PQExpBuffer seclabelQry;
    3553              : 
    3554          160 :         seclabelQry = createPQExpBuffer();
    3555              : 
    3556          160 :         buildShSecLabelQuery("pg_database", dbCatId.oid, seclabelQry);
    3557          160 :         shres = ExecuteSqlQuery(fout, seclabelQry->data, PGRES_TUPLES_OK);
    3558          160 :         resetPQExpBuffer(seclabelQry);
    3559          160 :         emitShSecLabels(conn, shres, seclabelQry, "DATABASE", datname);
    3560          160 :         if (seclabelQry->len > 0)
    3561            0 :             ArchiveEntry(fout, nilCatalogId, createDumpId(),
    3562            0 :                          ARCHIVE_OPTS(.tag = labelq->data,
    3563              :                                       .owner = dba,
    3564              :                                       .description = "SECURITY LABEL",
    3565              :                                       .section = SECTION_NONE,
    3566              :                                       .createStmt = seclabelQry->data,
    3567              :                                       .deps = &dbDumpId,
    3568              :                                       .nDeps = 1));
    3569          160 :         destroyPQExpBuffer(seclabelQry);
    3570          160 :         PQclear(shres);
    3571              :     }
    3572              : 
    3573              :     /*
    3574              :      * Dump ACL if any.  Note that we do not support initial privileges
    3575              :      * (pg_init_privs) on databases.
    3576              :      */
    3577          160 :     dbdacl.privtype = 0;
    3578          160 :     dbdacl.initprivs = NULL;
    3579              : 
    3580          160 :     dumpACL(fout, dbDumpId, InvalidDumpId, "DATABASE",
    3581              :             qdatname, NULL, NULL,
    3582              :             NULL, dba, &dbdacl);
    3583              : 
    3584              :     /*
    3585              :      * Now construct a DATABASE PROPERTIES archive entry to restore any
    3586              :      * non-default database-level properties.  (The reason this must be
    3587              :      * separate is that we cannot put any additional commands into the TOC
    3588              :      * entry that has CREATE DATABASE.  pg_restore would execute such a group
    3589              :      * in an implicit transaction block, and the backend won't allow CREATE
    3590              :      * DATABASE in that context.)
    3591              :      */
    3592          160 :     resetPQExpBuffer(creaQry);
    3593          160 :     resetPQExpBuffer(delQry);
    3594              : 
    3595          160 :     if (strlen(datconnlimit) > 0 && strcmp(datconnlimit, "-1") != 0)
    3596            0 :         appendPQExpBuffer(creaQry, "ALTER DATABASE %s CONNECTION LIMIT = %s;\n",
    3597              :                           qdatname, datconnlimit);
    3598              : 
    3599          160 :     if (strcmp(datistemplate, "t") == 0)
    3600              :     {
    3601           21 :         appendPQExpBuffer(creaQry, "ALTER DATABASE %s IS_TEMPLATE = true;\n",
    3602              :                           qdatname);
    3603              : 
    3604              :         /*
    3605              :          * The backend won't accept DROP DATABASE on a template database.  We
    3606              :          * can deal with that by removing the template marking before the DROP
    3607              :          * gets issued.  We'd prefer to use ALTER DATABASE IF EXISTS here, but
    3608              :          * since no such command is currently supported, fake it with a direct
    3609              :          * UPDATE on pg_database.
    3610              :          */
    3611           21 :         appendPQExpBufferStr(delQry, "UPDATE pg_catalog.pg_database "
    3612              :                              "SET datistemplate = false WHERE datname = ");
    3613           21 :         appendStringLiteralAH(delQry, datname, fout);
    3614           21 :         appendPQExpBufferStr(delQry, ";\n");
    3615              :     }
    3616              : 
    3617              :     /*
    3618              :      * We do not restore pg_database.dathasloginevt because it is set
    3619              :      * automatically on login event trigger creation.
    3620              :      */
    3621              : 
    3622              :     /* Add database-specific SET options */
    3623          160 :     dumpDatabaseConfig(fout, creaQry, datname, dbCatId.oid);
    3624              : 
    3625              :     /*
    3626              :      * We stick this binary-upgrade query into the DATABASE PROPERTIES archive
    3627              :      * entry, too, for lack of a better place.
    3628              :      */
    3629          160 :     if (dopt->binary_upgrade)
    3630              :     {
    3631           39 :         appendPQExpBufferStr(creaQry, "\n-- For binary upgrade, set datfrozenxid and datminmxid.\n");
    3632           39 :         appendPQExpBuffer(creaQry, "UPDATE pg_catalog.pg_database\n"
    3633              :                           "SET datfrozenxid = '%u', datminmxid = '%u'\n"
    3634              :                           "WHERE datname = ",
    3635              :                           frozenxid, minmxid);
    3636           39 :         appendStringLiteralAH(creaQry, datname, fout);
    3637           39 :         appendPQExpBufferStr(creaQry, ";\n");
    3638              :     }
    3639              : 
    3640          160 :     if (creaQry->len > 0)
    3641           52 :         ArchiveEntry(fout, nilCatalogId, createDumpId(),
    3642           52 :                      ARCHIVE_OPTS(.tag = datname,
    3643              :                                   .owner = dba,
    3644              :                                   .description = "DATABASE PROPERTIES",
    3645              :                                   .section = SECTION_PRE_DATA,
    3646              :                                   .createStmt = creaQry->data,
    3647              :                                   .dropStmt = delQry->data,
    3648              :                                   .deps = &dbDumpId));
    3649              : 
    3650              :     /*
    3651              :      * pg_largeobject comes from the old system intact, so set its
    3652              :      * relfrozenxids, relminmxids and relfilenode.
    3653              :      *
    3654              :      * pg_largeobject_metadata also comes from the old system intact for
    3655              :      * upgrades from v16 and newer, so set its relfrozenxids, relminmxids, and
    3656              :      * relfilenode, too.  pg_upgrade can't copy/link the files from older
    3657              :      * versions because aclitem (needed by pg_largeobject_metadata.lomacl)
    3658              :      * changed its storage format in v16.
    3659              :      */
    3660          160 :     if (dopt->binary_upgrade)
    3661              :     {
    3662              :         PGresult   *lo_res;
    3663           39 :         PQExpBuffer loFrozenQry = createPQExpBuffer();
    3664           39 :         PQExpBuffer loOutQry = createPQExpBuffer();
    3665           39 :         PQExpBuffer lomOutQry = createPQExpBuffer();
    3666           39 :         PQExpBuffer loHorizonQry = createPQExpBuffer();
    3667           39 :         PQExpBuffer lomHorizonQry = createPQExpBuffer();
    3668              :         int         ii_relfrozenxid,
    3669              :                     ii_relfilenode,
    3670              :                     ii_oid,
    3671              :                     ii_relminmxid;
    3672              : 
    3673           39 :         if (fout->remoteVersion >= 90300)
    3674           39 :             appendPQExpBuffer(loFrozenQry, "SELECT relfrozenxid, relminmxid, relfilenode, oid\n"
    3675              :                               "FROM pg_catalog.pg_class\n"
    3676              :                               "WHERE oid IN (%u, %u, %u, %u);\n",
    3677              :                               LargeObjectRelationId, LargeObjectLOidPNIndexId,
    3678              :                               LargeObjectMetadataRelationId, LargeObjectMetadataOidIndexId);
    3679              :         else
    3680            0 :             appendPQExpBuffer(loFrozenQry, "SELECT relfrozenxid, 0 AS relminmxid, relfilenode, oid\n"
    3681              :                               "FROM pg_catalog.pg_class\n"
    3682              :                               "WHERE oid IN (%u, %u);\n",
    3683              :                               LargeObjectRelationId, LargeObjectLOidPNIndexId);
    3684              : 
    3685           39 :         lo_res = ExecuteSqlQuery(fout, loFrozenQry->data, PGRES_TUPLES_OK);
    3686              : 
    3687           39 :         ii_relfrozenxid = PQfnumber(lo_res, "relfrozenxid");
    3688           39 :         ii_relminmxid = PQfnumber(lo_res, "relminmxid");
    3689           39 :         ii_relfilenode = PQfnumber(lo_res, "relfilenode");
    3690           39 :         ii_oid = PQfnumber(lo_res, "oid");
    3691              : 
    3692           39 :         appendPQExpBufferStr(loHorizonQry, "\n-- For binary upgrade, set pg_largeobject relfrozenxid and relminmxid\n");
    3693           39 :         appendPQExpBufferStr(lomHorizonQry, "\n-- For binary upgrade, set pg_largeobject_metadata relfrozenxid and relminmxid\n");
    3694           39 :         appendPQExpBufferStr(loOutQry, "\n-- For binary upgrade, preserve pg_largeobject and index relfilenodes\n");
    3695           39 :         appendPQExpBufferStr(lomOutQry, "\n-- For binary upgrade, preserve pg_largeobject_metadata and index relfilenodes\n");
    3696          195 :         for (int i = 0; i < PQntuples(lo_res); ++i)
    3697              :         {
    3698              :             Oid         oid;
    3699              :             RelFileNumber relfilenumber;
    3700              :             PQExpBuffer horizonQry;
    3701              :             PQExpBuffer outQry;
    3702              : 
    3703          156 :             oid = atooid(PQgetvalue(lo_res, i, ii_oid));
    3704          156 :             relfilenumber = atooid(PQgetvalue(lo_res, i, ii_relfilenode));
    3705              : 
    3706          156 :             if (oid == LargeObjectRelationId ||
    3707              :                 oid == LargeObjectLOidPNIndexId)
    3708              :             {
    3709           78 :                 horizonQry = loHorizonQry;
    3710           78 :                 outQry = loOutQry;
    3711              :             }
    3712              :             else
    3713              :             {
    3714           78 :                 horizonQry = lomHorizonQry;
    3715           78 :                 outQry = lomOutQry;
    3716              :             }
    3717              : 
    3718          156 :             appendPQExpBuffer(horizonQry, "UPDATE pg_catalog.pg_class\n"
    3719              :                               "SET relfrozenxid = '%u', relminmxid = '%u'\n"
    3720              :                               "WHERE oid = %u;\n",
    3721          156 :                               atooid(PQgetvalue(lo_res, i, ii_relfrozenxid)),
    3722          156 :                               atooid(PQgetvalue(lo_res, i, ii_relminmxid)),
    3723          156 :                               atooid(PQgetvalue(lo_res, i, ii_oid)));
    3724              : 
    3725          156 :             if (oid == LargeObjectRelationId ||
    3726              :                 oid == LargeObjectMetadataRelationId)
    3727           78 :                 appendPQExpBuffer(outQry,
    3728              :                                   "SELECT pg_catalog.binary_upgrade_set_next_heap_relfilenode('%u'::pg_catalog.oid);\n",
    3729              :                                   relfilenumber);
    3730           78 :             else if (oid == LargeObjectLOidPNIndexId ||
    3731              :                      oid == LargeObjectMetadataOidIndexId)
    3732           78 :                 appendPQExpBuffer(outQry,
    3733              :                                   "SELECT pg_catalog.binary_upgrade_set_next_index_relfilenode('%u'::pg_catalog.oid);\n",
    3734              :                                   relfilenumber);
    3735              :         }
    3736              : 
    3737           39 :         appendPQExpBufferStr(loOutQry,
    3738              :                              "TRUNCATE pg_catalog.pg_largeobject;\n");
    3739           39 :         appendPQExpBufferStr(lomOutQry,
    3740              :                              "TRUNCATE pg_catalog.pg_largeobject_metadata;\n");
    3741              : 
    3742           39 :         appendPQExpBufferStr(loOutQry, loHorizonQry->data);
    3743           39 :         appendPQExpBufferStr(lomOutQry, lomHorizonQry->data);
    3744              : 
    3745           39 :         ArchiveEntry(fout, nilCatalogId, createDumpId(),
    3746           39 :                      ARCHIVE_OPTS(.tag = "pg_largeobject",
    3747              :                                   .description = "pg_largeobject",
    3748              :                                   .section = SECTION_PRE_DATA,
    3749              :                                   .createStmt = loOutQry->data));
    3750              : 
    3751           39 :         if (fout->remoteVersion >= 160000)
    3752           39 :             ArchiveEntry(fout, nilCatalogId, createDumpId(),
    3753           39 :                          ARCHIVE_OPTS(.tag = "pg_largeobject_metadata",
    3754              :                                       .description = "pg_largeobject_metadata",
    3755              :                                       .section = SECTION_PRE_DATA,
    3756              :                                       .createStmt = lomOutQry->data));
    3757              : 
    3758           39 :         PQclear(lo_res);
    3759              : 
    3760           39 :         destroyPQExpBuffer(loFrozenQry);
    3761           39 :         destroyPQExpBuffer(loHorizonQry);
    3762           39 :         destroyPQExpBuffer(lomHorizonQry);
    3763           39 :         destroyPQExpBuffer(loOutQry);
    3764           39 :         destroyPQExpBuffer(lomOutQry);
    3765              :     }
    3766              : 
    3767          160 :     PQclear(res);
    3768              : 
    3769          160 :     free(qdatname);
    3770          160 :     destroyPQExpBuffer(dbQry);
    3771          160 :     destroyPQExpBuffer(delQry);
    3772          160 :     destroyPQExpBuffer(creaQry);
    3773          160 :     destroyPQExpBuffer(labelq);
    3774          160 : }
    3775              : 
    3776              : /*
    3777              :  * Collect any database-specific or role-and-database-specific SET options
    3778              :  * for this database, and append them to outbuf.
    3779              :  */
    3780              : static void
    3781          160 : dumpDatabaseConfig(Archive *AH, PQExpBuffer outbuf,
    3782              :                    const char *dbname, Oid dboid)
    3783              : {
    3784          160 :     PGconn     *conn = GetConnection(AH);
    3785          160 :     PQExpBuffer buf = createPQExpBuffer();
    3786              :     PGresult   *res;
    3787              : 
    3788              :     /* First collect database-specific options */
    3789          160 :     printfPQExpBuffer(buf, "SELECT unnest(setconfig) FROM pg_db_role_setting "
    3790              :                       "WHERE setrole = 0 AND setdatabase = '%u'::oid",
    3791              :                       dboid);
    3792              : 
    3793          160 :     res = ExecuteSqlQuery(AH, buf->data, PGRES_TUPLES_OK);
    3794              : 
    3795          190 :     for (int i = 0; i < PQntuples(res); i++)
    3796           30 :         makeAlterConfigCommand(conn, PQgetvalue(res, i, 0),
    3797              :                                "DATABASE", dbname, NULL, NULL,
    3798              :                                outbuf);
    3799              : 
    3800          160 :     PQclear(res);
    3801              : 
    3802              :     /* Now look for role-and-database-specific options */
    3803          160 :     printfPQExpBuffer(buf, "SELECT rolname, unnest(setconfig) "
    3804              :                       "FROM pg_db_role_setting s, pg_roles r "
    3805              :                       "WHERE setrole = r.oid AND setdatabase = '%u'::oid",
    3806              :                       dboid);
    3807              : 
    3808          160 :     res = ExecuteSqlQuery(AH, buf->data, PGRES_TUPLES_OK);
    3809              : 
    3810          160 :     for (int i = 0; i < PQntuples(res); i++)
    3811            0 :         makeAlterConfigCommand(conn, PQgetvalue(res, i, 1),
    3812            0 :                                "ROLE", PQgetvalue(res, i, 0),
    3813              :                                "DATABASE", dbname,
    3814              :                                outbuf);
    3815              : 
    3816          160 :     PQclear(res);
    3817              : 
    3818          160 :     destroyPQExpBuffer(buf);
    3819          160 : }
    3820              : 
    3821              : /*
    3822              :  * dumpEncoding: put the correct encoding into the archive
    3823              :  */
    3824              : static void
    3825          259 : dumpEncoding(Archive *AH)
    3826              : {
    3827          259 :     const char *encname = pg_encoding_to_char(AH->encoding);
    3828          259 :     PQExpBuffer qry = createPQExpBuffer();
    3829              : 
    3830          259 :     pg_log_info("saving encoding = %s", encname);
    3831              : 
    3832          259 :     appendPQExpBufferStr(qry, "SET client_encoding = ");
    3833          259 :     appendStringLiteralAH(qry, encname, AH);
    3834          259 :     appendPQExpBufferStr(qry, ";\n");
    3835              : 
    3836          259 :     ArchiveEntry(AH, nilCatalogId, createDumpId(),
    3837          259 :                  ARCHIVE_OPTS(.tag = "ENCODING",
    3838              :                               .description = "ENCODING",
    3839              :                               .section = SECTION_PRE_DATA,
    3840              :                               .createStmt = qry->data));
    3841              : 
    3842          259 :     destroyPQExpBuffer(qry);
    3843          259 : }
    3844              : 
    3845              : 
    3846              : /*
    3847              :  * dumpStdStrings: put the correct escape string behavior into the archive
    3848              :  */
    3849              : static void
    3850          259 : dumpStdStrings(Archive *AH)
    3851              : {
    3852          259 :     const char *stdstrings = AH->std_strings ? "on" : "off";
    3853          259 :     PQExpBuffer qry = createPQExpBuffer();
    3854              : 
    3855          259 :     pg_log_info("saving \"standard_conforming_strings = %s\"",
    3856              :                 stdstrings);
    3857              : 
    3858          259 :     appendPQExpBuffer(qry, "SET standard_conforming_strings = '%s';\n",
    3859              :                       stdstrings);
    3860              : 
    3861          259 :     ArchiveEntry(AH, nilCatalogId, createDumpId(),
    3862          259 :                  ARCHIVE_OPTS(.tag = "STDSTRINGS",
    3863              :                               .description = "STDSTRINGS",
    3864              :                               .section = SECTION_PRE_DATA,
    3865              :                               .createStmt = qry->data));
    3866              : 
    3867          259 :     destroyPQExpBuffer(qry);
    3868          259 : }
    3869              : 
    3870              : /*
    3871              :  * dumpSearchPath: record the active search_path in the archive
    3872              :  */
    3873              : static void
    3874          259 : dumpSearchPath(Archive *AH)
    3875              : {
    3876          259 :     PQExpBuffer qry = createPQExpBuffer();
    3877          259 :     PQExpBuffer path = createPQExpBuffer();
    3878              :     PGresult   *res;
    3879          259 :     char      **schemanames = NULL;
    3880          259 :     int         nschemanames = 0;
    3881              :     int         i;
    3882              : 
    3883              :     /*
    3884              :      * We use the result of current_schemas(), not the search_path GUC,
    3885              :      * because that might contain wildcards such as "$user", which won't
    3886              :      * necessarily have the same value during restore.  Also, this way avoids
    3887              :      * listing schemas that may appear in search_path but not actually exist,
    3888              :      * which seems like a prudent exclusion.
    3889              :      */
    3890          259 :     res = ExecuteSqlQueryForSingleRow(AH,
    3891              :                                       "SELECT pg_catalog.current_schemas(false)");
    3892              : 
    3893          259 :     if (!parsePGArray(PQgetvalue(res, 0, 0), &schemanames, &nschemanames))
    3894            0 :         pg_fatal("could not parse result of current_schemas()");
    3895              : 
    3896              :     /*
    3897              :      * We use set_config(), not a simple "SET search_path" command, because
    3898              :      * the latter has less-clean behavior if the search path is empty.  While
    3899              :      * that's likely to get fixed at some point, it seems like a good idea to
    3900              :      * be as backwards-compatible as possible in what we put into archives.
    3901              :      */
    3902          259 :     for (i = 0; i < nschemanames; i++)
    3903              :     {
    3904            0 :         if (i > 0)
    3905            0 :             appendPQExpBufferStr(path, ", ");
    3906            0 :         appendPQExpBufferStr(path, fmtId(schemanames[i]));
    3907              :     }
    3908              : 
    3909          259 :     appendPQExpBufferStr(qry, "SELECT pg_catalog.set_config('search_path', ");
    3910          259 :     appendStringLiteralAH(qry, path->data, AH);
    3911          259 :     appendPQExpBufferStr(qry, ", false);\n");
    3912              : 
    3913          259 :     pg_log_info("saving \"search_path = %s\"", path->data);
    3914              : 
    3915          259 :     ArchiveEntry(AH, nilCatalogId, createDumpId(),
    3916          259 :                  ARCHIVE_OPTS(.tag = "SEARCHPATH",
    3917              :                               .description = "SEARCHPATH",
    3918              :                               .section = SECTION_PRE_DATA,
    3919              :                               .createStmt = qry->data));
    3920              : 
    3921              :     /* Also save it in AH->searchpath, in case we're doing plain text dump */
    3922          259 :     AH->searchpath = pg_strdup(qry->data);
    3923              : 
    3924          259 :     free(schemanames);
    3925          259 :     PQclear(res);
    3926          259 :     destroyPQExpBuffer(qry);
    3927          259 :     destroyPQExpBuffer(path);
    3928          259 : }
    3929              : 
    3930              : 
    3931              : /*
    3932              :  * getLOs:
    3933              :  *  Collect schema-level data about large objects
    3934              :  */
    3935              : static void
    3936          231 : getLOs(Archive *fout)
    3937              : {
    3938          231 :     DumpOptions *dopt = fout->dopt;
    3939          231 :     PQExpBuffer loQry = createPQExpBuffer();
    3940              :     PGresult   *res;
    3941              :     int         ntups;
    3942              :     int         i;
    3943              :     int         n;
    3944              :     int         i_oid;
    3945              :     int         i_lomowner;
    3946              :     int         i_lomacl;
    3947              :     int         i_acldefault;
    3948              : 
    3949          231 :     pg_log_info("reading large objects");
    3950              : 
    3951              :     /*
    3952              :      * Fetch LO OIDs and owner/ACL data.  Order the data so that all the blobs
    3953              :      * with the same owner/ACL appear together.
    3954              :      */
    3955          231 :     appendPQExpBufferStr(loQry,
    3956              :                          "SELECT oid, lomowner, lomacl, "
    3957              :                          "acldefault('L', lomowner) AS acldefault "
    3958              :                          "FROM pg_largeobject_metadata ");
    3959              : 
    3960              :     /*
    3961              :      * For binary upgrades, we transfer pg_largeobject_metadata via COPY or by
    3962              :      * copying/linking its files from the old cluster.  On such upgrades, we
    3963              :      * only need to consider large objects that have comments or security
    3964              :      * labels, since we still restore those objects via COMMENT/SECURITY LABEL
    3965              :      * commands.
    3966              :      */
    3967          231 :     if (dopt->binary_upgrade)
    3968           40 :         appendPQExpBufferStr(loQry,
    3969              :                              "WHERE oid IN "
    3970              :                              "(SELECT objoid FROM pg_description "
    3971              :                              "WHERE classoid = " CppAsString2(LargeObjectRelationId) " "
    3972              :                              "UNION SELECT objoid FROM pg_seclabel "
    3973              :                              "WHERE classoid = " CppAsString2(LargeObjectRelationId) ") ");
    3974              : 
    3975          231 :     appendPQExpBufferStr(loQry,
    3976              :                          "ORDER BY lomowner, lomacl::pg_catalog.text, oid");
    3977              : 
    3978          231 :     res = ExecuteSqlQuery(fout, loQry->data, PGRES_TUPLES_OK);
    3979              : 
    3980          231 :     i_oid = PQfnumber(res, "oid");
    3981          231 :     i_lomowner = PQfnumber(res, "lomowner");
    3982          231 :     i_lomacl = PQfnumber(res, "lomacl");
    3983          231 :     i_acldefault = PQfnumber(res, "acldefault");
    3984              : 
    3985          231 :     ntups = PQntuples(res);
    3986              : 
    3987              :     /*
    3988              :      * Group the blobs into suitably-sized groups that have the same owner and
    3989              :      * ACL setting, and build a metadata and a data DumpableObject for each
    3990              :      * group.  (If we supported initprivs for blobs, we'd have to insist that
    3991              :      * groups also share initprivs settings, since the DumpableObject only has
    3992              :      * room for one.)  i is the index of the first tuple in the current group,
    3993              :      * and n is the number of tuples we include in the group.
    3994              :      */
    3995          315 :     for (i = 0; i < ntups; i += n)
    3996              :     {
    3997           84 :         Oid         thisoid = atooid(PQgetvalue(res, i, i_oid));
    3998           84 :         char       *thisowner = PQgetvalue(res, i, i_lomowner);
    3999           84 :         char       *thisacl = PQgetvalue(res, i, i_lomacl);
    4000              :         LoInfo     *loinfo;
    4001              :         DumpableObject *lodata;
    4002              :         char        namebuf[64];
    4003              : 
    4004              :         /* Scan to find first tuple not to be included in group */
    4005           84 :         n = 1;
    4006           98 :         while (n < MAX_BLOBS_PER_ARCHIVE_ENTRY && i + n < ntups)
    4007              :         {
    4008           47 :             if (strcmp(thisowner, PQgetvalue(res, i + n, i_lomowner)) != 0 ||
    4009           47 :                 strcmp(thisacl, PQgetvalue(res, i + n, i_lomacl)) != 0)
    4010              :                 break;
    4011           14 :             n++;
    4012              :         }
    4013              : 
    4014              :         /* Build the metadata DumpableObject */
    4015           84 :         loinfo = (LoInfo *) pg_malloc(offsetof(LoInfo, looids) + n * sizeof(Oid));
    4016              : 
    4017           84 :         loinfo->dobj.objType = DO_LARGE_OBJECT;
    4018           84 :         loinfo->dobj.catId.tableoid = LargeObjectRelationId;
    4019           84 :         loinfo->dobj.catId.oid = thisoid;
    4020           84 :         AssignDumpId(&loinfo->dobj);
    4021              : 
    4022           84 :         if (n > 1)
    4023           10 :             snprintf(namebuf, sizeof(namebuf), "%u..%u", thisoid,
    4024           10 :                      atooid(PQgetvalue(res, i + n - 1, i_oid)));
    4025              :         else
    4026           74 :             snprintf(namebuf, sizeof(namebuf), "%u", thisoid);
    4027           84 :         loinfo->dobj.name = pg_strdup(namebuf);
    4028           84 :         loinfo->dacl.acl = pg_strdup(thisacl);
    4029           84 :         loinfo->dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
    4030           84 :         loinfo->dacl.privtype = 0;
    4031           84 :         loinfo->dacl.initprivs = NULL;
    4032           84 :         loinfo->rolname = getRoleName(thisowner);
    4033           84 :         loinfo->numlos = n;
    4034           84 :         loinfo->looids[0] = thisoid;
    4035              :         /* Collect OIDs of the remaining blobs in this group */
    4036           98 :         for (int k = 1; k < n; k++)
    4037              :         {
    4038              :             CatalogId   extraID;
    4039              : 
    4040           14 :             loinfo->looids[k] = atooid(PQgetvalue(res, i + k, i_oid));
    4041              : 
    4042              :             /* Make sure we can look up loinfo by any of the blobs' OIDs */
    4043           14 :             extraID.tableoid = LargeObjectRelationId;
    4044           14 :             extraID.oid = loinfo->looids[k];
    4045           14 :             recordAdditionalCatalogID(extraID, &loinfo->dobj);
    4046              :         }
    4047              : 
    4048              :         /* LOs have data */
    4049           84 :         loinfo->dobj.components |= DUMP_COMPONENT_DATA;
    4050              : 
    4051              :         /* Mark whether LO group has a non-empty ACL */
    4052           84 :         if (!PQgetisnull(res, i, i_lomacl))
    4053           34 :             loinfo->dobj.components |= DUMP_COMPONENT_ACL;
    4054              : 
    4055              :         /*
    4056              :          * In binary upgrade mode, pg_largeobject and pg_largeobject_metadata
    4057              :          * are transferred via COPY or by copying/linking the files from the
    4058              :          * old cluster.  Thus, we do not need to dump LO data, definitions, or
    4059              :          * ACLs.
    4060              :          */
    4061           84 :         if (dopt->binary_upgrade)
    4062            7 :             loinfo->dobj.dump &= ~(DUMP_COMPONENT_DATA | DUMP_COMPONENT_ACL | DUMP_COMPONENT_DEFINITION);
    4063              : 
    4064              :         /*
    4065              :          * Create a "BLOBS" data item for the group, too. This is just a
    4066              :          * placeholder for sorting; it carries no data now.
    4067              :          */
    4068           84 :         lodata = pg_malloc_object(DumpableObject);
    4069           84 :         lodata->objType = DO_LARGE_OBJECT_DATA;
    4070           84 :         lodata->catId = nilCatalogId;
    4071           84 :         AssignDumpId(lodata);
    4072           84 :         lodata->name = pg_strdup(namebuf);
    4073           84 :         lodata->components |= DUMP_COMPONENT_DATA;
    4074              :         /* Set up explicit dependency from data to metadata */
    4075           84 :         lodata->dependencies = pg_malloc_object(DumpId);
    4076           84 :         lodata->dependencies[0] = loinfo->dobj.dumpId;
    4077           84 :         lodata->nDeps = lodata->allocDeps = 1;
    4078              :     }
    4079              : 
    4080          231 :     PQclear(res);
    4081          231 :     destroyPQExpBuffer(loQry);
    4082          231 : }
    4083              : 
    4084              : /*
    4085              :  * dumpLO
    4086              :  *
    4087              :  * dump the definition (metadata) of the given large object group
    4088              :  */
    4089              : static void
    4090           84 : dumpLO(Archive *fout, const LoInfo *loinfo)
    4091              : {
    4092           84 :     PQExpBuffer cquery = createPQExpBuffer();
    4093              : 
    4094              :     /*
    4095              :      * The "definition" is just a newline-separated list of OIDs.  We need to
    4096              :      * put something into the dropStmt too, but it can just be a comment.
    4097              :      */
    4098          182 :     for (int i = 0; i < loinfo->numlos; i++)
    4099           98 :         appendPQExpBuffer(cquery, "%u\n", loinfo->looids[i]);
    4100              : 
    4101           84 :     if (loinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
    4102           77 :         ArchiveEntry(fout, loinfo->dobj.catId, loinfo->dobj.dumpId,
    4103           77 :                      ARCHIVE_OPTS(.tag = loinfo->dobj.name,
    4104              :                                   .owner = loinfo->rolname,
    4105              :                                   .description = "BLOB METADATA",
    4106              :                                   .section = SECTION_DATA,
    4107              :                                   .createStmt = cquery->data,
    4108              :                                   .dropStmt = "-- dummy"));
    4109              : 
    4110              :     /*
    4111              :      * Dump per-blob comments and seclabels if any.  We assume these are rare
    4112              :      * enough that it's okay to generate retail TOC entries for them.
    4113              :      */
    4114           84 :     if (loinfo->dobj.dump & (DUMP_COMPONENT_COMMENT |
    4115              :                              DUMP_COMPONENT_SECLABEL))
    4116              :     {
    4117          102 :         for (int i = 0; i < loinfo->numlos; i++)
    4118              :         {
    4119              :             CatalogId   catId;
    4120              :             char        namebuf[32];
    4121              : 
    4122              :             /* Build identifying info for this blob */
    4123           58 :             catId.tableoid = loinfo->dobj.catId.tableoid;
    4124           58 :             catId.oid = loinfo->looids[i];
    4125           58 :             snprintf(namebuf, sizeof(namebuf), "%u", loinfo->looids[i]);
    4126              : 
    4127           58 :             if (loinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
    4128           58 :                 dumpComment(fout, "LARGE OBJECT", namebuf,
    4129           58 :                             NULL, loinfo->rolname,
    4130           58 :                             catId, 0, loinfo->dobj.dumpId);
    4131              : 
    4132           58 :             if (loinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
    4133           10 :                 dumpSecLabel(fout, "LARGE OBJECT", namebuf,
    4134           10 :                              NULL, loinfo->rolname,
    4135           10 :                              catId, 0, loinfo->dobj.dumpId);
    4136              :         }
    4137              :     }
    4138              : 
    4139              :     /*
    4140              :      * Dump the ACLs if any (remember that all blobs in the group will have
    4141              :      * the same ACL).  If there's just one blob, dump a simple ACL entry; if
    4142              :      * there's more, make a "LARGE OBJECTS" entry that really contains only
    4143              :      * the ACL for the first blob.  _printTocEntry() will be cued by the tag
    4144              :      * string to emit a mutated version for each blob.
    4145              :      */
    4146           84 :     if (loinfo->dobj.dump & DUMP_COMPONENT_ACL)
    4147              :     {
    4148              :         char        namebuf[32];
    4149              : 
    4150              :         /* Build identifying info for the first blob */
    4151           33 :         snprintf(namebuf, sizeof(namebuf), "%u", loinfo->looids[0]);
    4152              : 
    4153           33 :         if (loinfo->numlos > 1)
    4154              :         {
    4155              :             char        tagbuf[64];
    4156              : 
    4157            0 :             snprintf(tagbuf, sizeof(tagbuf), "LARGE OBJECTS %u..%u",
    4158            0 :                      loinfo->looids[0], loinfo->looids[loinfo->numlos - 1]);
    4159              : 
    4160            0 :             dumpACL(fout, loinfo->dobj.dumpId, InvalidDumpId,
    4161              :                     "LARGE OBJECT", namebuf, NULL, NULL,
    4162            0 :                     tagbuf, loinfo->rolname, &loinfo->dacl);
    4163              :         }
    4164              :         else
    4165              :         {
    4166           33 :             dumpACL(fout, loinfo->dobj.dumpId, InvalidDumpId,
    4167              :                     "LARGE OBJECT", namebuf, NULL, NULL,
    4168           33 :                     NULL, loinfo->rolname, &loinfo->dacl);
    4169              :         }
    4170              :     }
    4171              : 
    4172           84 :     destroyPQExpBuffer(cquery);
    4173           84 : }
    4174              : 
    4175              : /*
    4176              :  * dumpLOs:
    4177              :  *  dump the data contents of the large objects in the given group
    4178              :  */
    4179              : static int
    4180           73 : dumpLOs(Archive *fout, const void *arg)
    4181              : {
    4182           73 :     const LoInfo *loinfo = (const LoInfo *) arg;
    4183           73 :     PGconn     *conn = GetConnection(fout);
    4184              :     char        buf[LOBBUFSIZE];
    4185              : 
    4186           73 :     pg_log_info("saving large objects \"%s\"", loinfo->dobj.name);
    4187              : 
    4188          154 :     for (int i = 0; i < loinfo->numlos; i++)
    4189              :     {
    4190           81 :         Oid         loOid = loinfo->looids[i];
    4191              :         int         loFd;
    4192              :         int         cnt;
    4193              : 
    4194              :         /* Open the LO */
    4195           81 :         loFd = lo_open(conn, loOid, INV_READ);
    4196           81 :         if (loFd == -1)
    4197            0 :             pg_fatal("could not open large object %u: %s",
    4198              :                      loOid, PQerrorMessage(conn));
    4199              : 
    4200           81 :         StartLO(fout, loOid);
    4201              : 
    4202              :         /* Now read it in chunks, sending data to archive */
    4203              :         do
    4204              :         {
    4205          127 :             cnt = lo_read(conn, loFd, buf, LOBBUFSIZE);
    4206          127 :             if (cnt < 0)
    4207            0 :                 pg_fatal("error reading large object %u: %s",
    4208              :                          loOid, PQerrorMessage(conn));
    4209              : 
    4210          127 :             WriteData(fout, buf, cnt);
    4211          127 :         } while (cnt > 0);
    4212              : 
    4213           81 :         lo_close(conn, loFd);
    4214              : 
    4215           81 :         EndLO(fout, loOid);
    4216              :     }
    4217              : 
    4218           73 :     return 1;
    4219              : }
    4220              : 
    4221              : /*
    4222              :  * getPolicies
    4223              :  *    get information about all RLS policies on dumpable tables.
    4224              :  */
    4225              : void
    4226          259 : getPolicies(Archive *fout, TableInfo tblinfo[], int numTables)
    4227              : {
    4228          259 :     DumpOptions *dopt = fout->dopt;
    4229              :     PQExpBuffer query;
    4230              :     PQExpBuffer tbloids;
    4231              :     PGresult   *res;
    4232              :     PolicyInfo *polinfo;
    4233              :     int         i_oid;
    4234              :     int         i_tableoid;
    4235              :     int         i_polrelid;
    4236              :     int         i_polname;
    4237              :     int         i_polcmd;
    4238              :     int         i_polpermissive;
    4239              :     int         i_polroles;
    4240              :     int         i_polqual;
    4241              :     int         i_polwithcheck;
    4242              :     int         i,
    4243              :                 j,
    4244              :                 ntups;
    4245              : 
    4246              :     /* No policies before 9.5 */
    4247          259 :     if (fout->remoteVersion < 90500)
    4248            0 :         return;
    4249              : 
    4250              :     /* Skip if --no-policies was specified */
    4251          259 :     if (dopt->no_policies)
    4252            1 :         return;
    4253              : 
    4254          258 :     query = createPQExpBuffer();
    4255          258 :     tbloids = createPQExpBuffer();
    4256              : 
    4257              :     /*
    4258              :      * Identify tables of interest, and check which ones have RLS enabled.
    4259              :      */
    4260          258 :     appendPQExpBufferChar(tbloids, '{');
    4261        69868 :     for (i = 0; i < numTables; i++)
    4262              :     {
    4263        69610 :         TableInfo  *tbinfo = &tblinfo[i];
    4264              : 
    4265              :         /* Ignore row security on tables not to be dumped */
    4266        69610 :         if (!(tbinfo->dobj.dump & DUMP_COMPONENT_POLICY))
    4267        62087 :             continue;
    4268              : 
    4269              :         /* It can't have RLS or policies if it's not a table */
    4270         7523 :         if (tbinfo->relkind != RELKIND_RELATION &&
    4271         2093 :             tbinfo->relkind != RELKIND_PARTITIONED_TABLE)
    4272         1482 :             continue;
    4273              : 
    4274              :         /* Add it to the list of table OIDs to be probed below */
    4275         6041 :         if (tbloids->len > 1) /* do we have more than the '{'? */
    4276         5866 :             appendPQExpBufferChar(tbloids, ',');
    4277         6041 :         appendPQExpBuffer(tbloids, "%u", tbinfo->dobj.catId.oid);
    4278              : 
    4279              :         /* Is RLS enabled?  (That's separate from whether it has policies) */
    4280         6041 :         if (tbinfo->rowsec)
    4281              :         {
    4282           63 :             tbinfo->dobj.components |= DUMP_COMPONENT_POLICY;
    4283              : 
    4284              :             /*
    4285              :              * We represent RLS being enabled on a table by creating a
    4286              :              * PolicyInfo object with null polname.
    4287              :              *
    4288              :              * Note: use tableoid 0 so that this object won't be mistaken for
    4289              :              * something that pg_depend entries apply to.
    4290              :              */
    4291           63 :             polinfo = pg_malloc_object(PolicyInfo);
    4292           63 :             polinfo->dobj.objType = DO_POLICY;
    4293           63 :             polinfo->dobj.catId.tableoid = 0;
    4294           63 :             polinfo->dobj.catId.oid = tbinfo->dobj.catId.oid;
    4295           63 :             AssignDumpId(&polinfo->dobj);
    4296           63 :             polinfo->dobj.namespace = tbinfo->dobj.namespace;
    4297           63 :             polinfo->dobj.name = pg_strdup(tbinfo->dobj.name);
    4298           63 :             polinfo->poltable = tbinfo;
    4299           63 :             polinfo->polname = NULL;
    4300           63 :             polinfo->polcmd = '\0';
    4301           63 :             polinfo->polpermissive = 0;
    4302           63 :             polinfo->polroles = NULL;
    4303           63 :             polinfo->polqual = NULL;
    4304           63 :             polinfo->polwithcheck = NULL;
    4305              :         }
    4306              :     }
    4307          258 :     appendPQExpBufferChar(tbloids, '}');
    4308              : 
    4309              :     /*
    4310              :      * Now, read all RLS policies belonging to the tables of interest, and
    4311              :      * create PolicyInfo objects for them.  (Note that we must filter the
    4312              :      * results server-side not locally, because we dare not apply pg_get_expr
    4313              :      * to tables we don't have lock on.)
    4314              :      */
    4315          258 :     pg_log_info("reading row-level security policies");
    4316              : 
    4317          258 :     printfPQExpBuffer(query,
    4318              :                       "SELECT pol.oid, pol.tableoid, pol.polrelid, pol.polname, pol.polcmd, ");
    4319          258 :     if (fout->remoteVersion >= 100000)
    4320          258 :         appendPQExpBufferStr(query, "pol.polpermissive, ");
    4321              :     else
    4322            0 :         appendPQExpBufferStr(query, "'t' as polpermissive, ");
    4323          258 :     appendPQExpBuffer(query,
    4324              :                       "CASE WHEN pol.polroles = '{0}' THEN NULL ELSE "
    4325              :                       "   pg_catalog.array_to_string(ARRAY(SELECT pg_catalog.quote_ident(rolname) from pg_catalog.pg_roles WHERE oid = ANY(pol.polroles)), ', ') END AS polroles, "
    4326              :                       "pg_catalog.pg_get_expr(pol.polqual, pol.polrelid) AS polqual, "
    4327              :                       "pg_catalog.pg_get_expr(pol.polwithcheck, pol.polrelid) AS polwithcheck "
    4328              :                       "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
    4329              :                       "JOIN pg_catalog.pg_policy pol ON (src.tbloid = pol.polrelid)",
    4330              :                       tbloids->data);
    4331              : 
    4332          258 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    4333              : 
    4334          258 :     ntups = PQntuples(res);
    4335          258 :     if (ntups > 0)
    4336              :     {
    4337           43 :         i_oid = PQfnumber(res, "oid");
    4338           43 :         i_tableoid = PQfnumber(res, "tableoid");
    4339           43 :         i_polrelid = PQfnumber(res, "polrelid");
    4340           43 :         i_polname = PQfnumber(res, "polname");
    4341           43 :         i_polcmd = PQfnumber(res, "polcmd");
    4342           43 :         i_polpermissive = PQfnumber(res, "polpermissive");
    4343           43 :         i_polroles = PQfnumber(res, "polroles");
    4344           43 :         i_polqual = PQfnumber(res, "polqual");
    4345           43 :         i_polwithcheck = PQfnumber(res, "polwithcheck");
    4346              : 
    4347           43 :         polinfo = pg_malloc_array(PolicyInfo, ntups);
    4348              : 
    4349          316 :         for (j = 0; j < ntups; j++)
    4350              :         {
    4351          273 :             Oid         polrelid = atooid(PQgetvalue(res, j, i_polrelid));
    4352          273 :             TableInfo  *tbinfo = findTableByOid(polrelid);
    4353              : 
    4354          273 :             tbinfo->dobj.components |= DUMP_COMPONENT_POLICY;
    4355              : 
    4356          273 :             polinfo[j].dobj.objType = DO_POLICY;
    4357          273 :             polinfo[j].dobj.catId.tableoid =
    4358          273 :                 atooid(PQgetvalue(res, j, i_tableoid));
    4359          273 :             polinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
    4360          273 :             AssignDumpId(&polinfo[j].dobj);
    4361          273 :             polinfo[j].dobj.namespace = tbinfo->dobj.namespace;
    4362          273 :             polinfo[j].poltable = tbinfo;
    4363          273 :             polinfo[j].polname = pg_strdup(PQgetvalue(res, j, i_polname));
    4364          273 :             polinfo[j].dobj.name = pg_strdup(polinfo[j].polname);
    4365              : 
    4366          273 :             polinfo[j].polcmd = *(PQgetvalue(res, j, i_polcmd));
    4367          273 :             polinfo[j].polpermissive = *(PQgetvalue(res, j, i_polpermissive)) == 't';
    4368              : 
    4369          273 :             if (PQgetisnull(res, j, i_polroles))
    4370          121 :                 polinfo[j].polroles = NULL;
    4371              :             else
    4372          152 :                 polinfo[j].polroles = pg_strdup(PQgetvalue(res, j, i_polroles));
    4373              : 
    4374          273 :             if (PQgetisnull(res, j, i_polqual))
    4375           38 :                 polinfo[j].polqual = NULL;
    4376              :             else
    4377          235 :                 polinfo[j].polqual = pg_strdup(PQgetvalue(res, j, i_polqual));
    4378              : 
    4379          273 :             if (PQgetisnull(res, j, i_polwithcheck))
    4380          144 :                 polinfo[j].polwithcheck = NULL;
    4381              :             else
    4382          129 :                 polinfo[j].polwithcheck
    4383          129 :                     = pg_strdup(PQgetvalue(res, j, i_polwithcheck));
    4384              :         }
    4385              :     }
    4386              : 
    4387          258 :     PQclear(res);
    4388              : 
    4389          258 :     destroyPQExpBuffer(query);
    4390          258 :     destroyPQExpBuffer(tbloids);
    4391              : }
    4392              : 
    4393              : /*
    4394              :  * dumpPolicy
    4395              :  *    dump the definition of the given policy
    4396              :  */
    4397              : static void
    4398          336 : dumpPolicy(Archive *fout, const PolicyInfo *polinfo)
    4399              : {
    4400          336 :     DumpOptions *dopt = fout->dopt;
    4401          336 :     TableInfo  *tbinfo = polinfo->poltable;
    4402              :     PQExpBuffer query;
    4403              :     PQExpBuffer delqry;
    4404              :     PQExpBuffer polprefix;
    4405              :     char       *qtabname;
    4406              :     const char *cmd;
    4407              :     char       *tag;
    4408              : 
    4409              :     /* Do nothing if not dumping schema */
    4410          336 :     if (!dopt->dumpSchema)
    4411           49 :         return;
    4412              : 
    4413              :     /*
    4414              :      * If polname is NULL, then this record is just indicating that ROW LEVEL
    4415              :      * SECURITY is enabled for the table. Dump as ALTER TABLE <table> ENABLE
    4416              :      * ROW LEVEL SECURITY.
    4417              :      */
    4418          287 :     if (polinfo->polname == NULL)
    4419              :     {
    4420           56 :         query = createPQExpBuffer();
    4421              : 
    4422           56 :         appendPQExpBuffer(query, "ALTER TABLE %s ENABLE ROW LEVEL SECURITY;",
    4423           56 :                           fmtQualifiedDumpable(tbinfo));
    4424              : 
    4425              :         /*
    4426              :          * We must emit the ROW SECURITY object's dependency on its table
    4427              :          * explicitly, because it will not match anything in pg_depend (unlike
    4428              :          * the case for other PolicyInfo objects).
    4429              :          */
    4430           56 :         if (polinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
    4431           56 :             ArchiveEntry(fout, polinfo->dobj.catId, polinfo->dobj.dumpId,
    4432           56 :                          ARCHIVE_OPTS(.tag = polinfo->dobj.name,
    4433              :                                       .namespace = polinfo->dobj.namespace->dobj.name,
    4434              :                                       .owner = tbinfo->rolname,
    4435              :                                       .description = "ROW SECURITY",
    4436              :                                       .section = SECTION_POST_DATA,
    4437              :                                       .createStmt = query->data,
    4438              :                                       .deps = &(tbinfo->dobj.dumpId),
    4439              :                                       .nDeps = 1));
    4440              : 
    4441           56 :         destroyPQExpBuffer(query);
    4442           56 :         return;
    4443              :     }
    4444              : 
    4445          231 :     if (polinfo->polcmd == '*')
    4446           77 :         cmd = "";
    4447          154 :     else if (polinfo->polcmd == 'r')
    4448           41 :         cmd = " FOR SELECT";
    4449          113 :     else if (polinfo->polcmd == 'a')
    4450           31 :         cmd = " FOR INSERT";
    4451           82 :     else if (polinfo->polcmd == 'w')
    4452           41 :         cmd = " FOR UPDATE";
    4453           41 :     else if (polinfo->polcmd == 'd')
    4454           41 :         cmd = " FOR DELETE";
    4455              :     else
    4456            0 :         pg_fatal("unexpected policy command type: %c",
    4457              :                  polinfo->polcmd);
    4458              : 
    4459          231 :     query = createPQExpBuffer();
    4460          231 :     delqry = createPQExpBuffer();
    4461          231 :     polprefix = createPQExpBuffer();
    4462              : 
    4463          231 :     qtabname = pg_strdup(fmtId(tbinfo->dobj.name));
    4464              : 
    4465          231 :     appendPQExpBuffer(query, "CREATE POLICY %s", fmtId(polinfo->polname));
    4466              : 
    4467          231 :     appendPQExpBuffer(query, " ON %s%s%s", fmtQualifiedDumpable(tbinfo),
    4468          231 :                       !polinfo->polpermissive ? " AS RESTRICTIVE" : "", cmd);
    4469              : 
    4470          231 :     if (polinfo->polroles != NULL)
    4471          124 :         appendPQExpBuffer(query, " TO %s", polinfo->polroles);
    4472              : 
    4473          231 :     if (polinfo->polqual != NULL)
    4474          200 :         appendPQExpBuffer(query, " USING (%s)", polinfo->polqual);
    4475              : 
    4476          231 :     if (polinfo->polwithcheck != NULL)
    4477          108 :         appendPQExpBuffer(query, " WITH CHECK (%s)", polinfo->polwithcheck);
    4478              : 
    4479          231 :     appendPQExpBufferStr(query, ";\n");
    4480              : 
    4481          231 :     appendPQExpBuffer(delqry, "DROP POLICY %s", fmtId(polinfo->polname));
    4482          231 :     appendPQExpBuffer(delqry, " ON %s;\n", fmtQualifiedDumpable(tbinfo));
    4483              : 
    4484          231 :     appendPQExpBuffer(polprefix, "POLICY %s ON",
    4485          231 :                       fmtId(polinfo->polname));
    4486              : 
    4487          231 :     tag = psprintf("%s %s", tbinfo->dobj.name, polinfo->dobj.name);
    4488              : 
    4489          231 :     if (polinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
    4490          231 :         ArchiveEntry(fout, polinfo->dobj.catId, polinfo->dobj.dumpId,
    4491          231 :                      ARCHIVE_OPTS(.tag = tag,
    4492              :                                   .namespace = polinfo->dobj.namespace->dobj.name,
    4493              :                                   .owner = tbinfo->rolname,
    4494              :                                   .description = "POLICY",
    4495              :                                   .section = SECTION_POST_DATA,
    4496              :                                   .createStmt = query->data,
    4497              :                                   .dropStmt = delqry->data));
    4498              : 
    4499          231 :     if (polinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
    4500           31 :         dumpComment(fout, polprefix->data, qtabname,
    4501           31 :                     tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
    4502           31 :                     polinfo->dobj.catId, 0, polinfo->dobj.dumpId);
    4503              : 
    4504          231 :     free(tag);
    4505          231 :     destroyPQExpBuffer(query);
    4506          231 :     destroyPQExpBuffer(delqry);
    4507          231 :     destroyPQExpBuffer(polprefix);
    4508          231 :     free(qtabname);
    4509              : }
    4510              : 
    4511              : /*
    4512              :  * getPublications
    4513              :  *    get information about publications
    4514              :  */
    4515              : void
    4516          259 : getPublications(Archive *fout)
    4517              : {
    4518          259 :     DumpOptions *dopt = fout->dopt;
    4519              :     PQExpBuffer query;
    4520              :     PGresult   *res;
    4521              :     PublicationInfo *pubinfo;
    4522              :     int         i_tableoid;
    4523              :     int         i_oid;
    4524              :     int         i_pubname;
    4525              :     int         i_pubowner;
    4526              :     int         i_puballtables;
    4527              :     int         i_puballsequences;
    4528              :     int         i_pubinsert;
    4529              :     int         i_pubupdate;
    4530              :     int         i_pubdelete;
    4531              :     int         i_pubtruncate;
    4532              :     int         i_pubviaroot;
    4533              :     int         i_pubgencols;
    4534              :     int         i,
    4535              :                 ntups;
    4536              : 
    4537          259 :     if (dopt->no_publications || fout->remoteVersion < 100000)
    4538            0 :         return;
    4539              : 
    4540          259 :     query = createPQExpBuffer();
    4541              : 
    4542              :     /* Get the publications. */
    4543          259 :     appendPQExpBufferStr(query, "SELECT p.tableoid, p.oid, p.pubname, "
    4544              :                          "p.pubowner, p.puballtables, p.pubinsert, "
    4545              :                          "p.pubupdate, p.pubdelete, ");
    4546              : 
    4547          259 :     if (fout->remoteVersion >= 110000)
    4548          259 :         appendPQExpBufferStr(query, "p.pubtruncate, ");
    4549              :     else
    4550            0 :         appendPQExpBufferStr(query, "false AS pubtruncate, ");
    4551              : 
    4552          259 :     if (fout->remoteVersion >= 130000)
    4553          259 :         appendPQExpBufferStr(query, "p.pubviaroot, ");
    4554              :     else
    4555            0 :         appendPQExpBufferStr(query, "false AS pubviaroot, ");
    4556              : 
    4557          259 :     if (fout->remoteVersion >= 180000)
    4558          259 :         appendPQExpBufferStr(query, "p.pubgencols, ");
    4559              :     else
    4560            0 :         appendPQExpBuffer(query, "'%c' AS pubgencols, ", PUBLISH_GENCOLS_NONE);
    4561              : 
    4562          259 :     if (fout->remoteVersion >= 190000)
    4563          259 :         appendPQExpBufferStr(query, "p.puballsequences ");
    4564              :     else
    4565            0 :         appendPQExpBufferStr(query, "false AS puballsequences ");
    4566              : 
    4567          259 :     appendPQExpBufferStr(query, "FROM pg_publication p");
    4568              : 
    4569          259 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    4570              : 
    4571          259 :     ntups = PQntuples(res);
    4572              : 
    4573          259 :     if (ntups == 0)
    4574          206 :         goto cleanup;
    4575              : 
    4576           53 :     i_tableoid = PQfnumber(res, "tableoid");
    4577           53 :     i_oid = PQfnumber(res, "oid");
    4578           53 :     i_pubname = PQfnumber(res, "pubname");
    4579           53 :     i_pubowner = PQfnumber(res, "pubowner");
    4580           53 :     i_puballtables = PQfnumber(res, "puballtables");
    4581           53 :     i_puballsequences = PQfnumber(res, "puballsequences");
    4582           53 :     i_pubinsert = PQfnumber(res, "pubinsert");
    4583           53 :     i_pubupdate = PQfnumber(res, "pubupdate");
    4584           53 :     i_pubdelete = PQfnumber(res, "pubdelete");
    4585           53 :     i_pubtruncate = PQfnumber(res, "pubtruncate");
    4586           53 :     i_pubviaroot = PQfnumber(res, "pubviaroot");
    4587           53 :     i_pubgencols = PQfnumber(res, "pubgencols");
    4588              : 
    4589           53 :     pubinfo = pg_malloc_array(PublicationInfo, ntups);
    4590              : 
    4591          539 :     for (i = 0; i < ntups; i++)
    4592              :     {
    4593          486 :         pubinfo[i].dobj.objType = DO_PUBLICATION;
    4594          486 :         pubinfo[i].dobj.catId.tableoid =
    4595          486 :             atooid(PQgetvalue(res, i, i_tableoid));
    4596          486 :         pubinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    4597          486 :         AssignDumpId(&pubinfo[i].dobj);
    4598          486 :         pubinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_pubname));
    4599          486 :         pubinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_pubowner));
    4600          486 :         pubinfo[i].puballtables =
    4601          486 :             (strcmp(PQgetvalue(res, i, i_puballtables), "t") == 0);
    4602          486 :         pubinfo[i].puballsequences =
    4603          486 :             (strcmp(PQgetvalue(res, i, i_puballsequences), "t") == 0);
    4604          486 :         pubinfo[i].pubinsert =
    4605          486 :             (strcmp(PQgetvalue(res, i, i_pubinsert), "t") == 0);
    4606          486 :         pubinfo[i].pubupdate =
    4607          486 :             (strcmp(PQgetvalue(res, i, i_pubupdate), "t") == 0);
    4608          486 :         pubinfo[i].pubdelete =
    4609          486 :             (strcmp(PQgetvalue(res, i, i_pubdelete), "t") == 0);
    4610          486 :         pubinfo[i].pubtruncate =
    4611          486 :             (strcmp(PQgetvalue(res, i, i_pubtruncate), "t") == 0);
    4612          486 :         pubinfo[i].pubviaroot =
    4613          486 :             (strcmp(PQgetvalue(res, i, i_pubviaroot), "t") == 0);
    4614          486 :         pubinfo[i].pubgencols_type =
    4615          486 :             *(PQgetvalue(res, i, i_pubgencols));
    4616          486 :         pubinfo[i].except_tables = (SimplePtrList)
    4617              :         {
    4618              :             NULL, NULL
    4619              :         };
    4620              : 
    4621              :         /* Decide whether we want to dump it */
    4622          486 :         selectDumpableObject(&(pubinfo[i].dobj), fout);
    4623              : 
    4624              :         /*
    4625              :          * Get the list of tables for publications specified in the EXCEPT
    4626              :          * TABLE clause.
    4627              :          *
    4628              :          * Although individual EXCEPT TABLE entries could be stored in
    4629              :          * PublicationRelInfo, dumpPublicationTable cannot be used to emit
    4630              :          * them, because there is no ALTER PUBLICATION ... ADD command to add
    4631              :          * individual table entries to the EXCEPT TABLE list.
    4632              :          *
    4633              :          * Therefore, the approach is to dump the complete EXCEPT TABLE list
    4634              :          * in a single CREATE PUBLICATION statement. PublicationInfo is used
    4635              :          * to collect this information, which is then emitted by
    4636              :          * dumpPublication().
    4637              :          */
    4638          486 :         if (fout->remoteVersion >= 190000)
    4639              :         {
    4640              :             int         ntbls;
    4641              :             PGresult   *res_tbls;
    4642              : 
    4643          486 :             resetPQExpBuffer(query);
    4644          486 :             appendPQExpBuffer(query,
    4645              :                               "SELECT prrelid\n"
    4646              :                               "FROM pg_catalog.pg_publication_rel\n"
    4647              :                               "WHERE prpubid = %u AND prexcept",
    4648          486 :                               pubinfo[i].dobj.catId.oid);
    4649              : 
    4650          486 :             res_tbls = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    4651              : 
    4652          486 :             ntbls = PQntuples(res_tbls);
    4653              : 
    4654          711 :             for (int j = 0; j < ntbls; j++)
    4655              :             {
    4656              :                 Oid         prrelid;
    4657              :                 TableInfo  *tbinfo;
    4658              : 
    4659          225 :                 prrelid = atooid(PQgetvalue(res_tbls, j, 0));
    4660              : 
    4661          225 :                 tbinfo = findTableByOid(prrelid);
    4662              : 
    4663          225 :                 if (tbinfo != NULL)
    4664          225 :                     simple_ptr_list_append(&pubinfo[i].except_tables, tbinfo);
    4665              :             }
    4666              : 
    4667          486 :             PQclear(res_tbls);
    4668              :         }
    4669              :     }
    4670              : 
    4671           53 : cleanup:
    4672          259 :     PQclear(res);
    4673              : 
    4674          259 :     destroyPQExpBuffer(query);
    4675              : }
    4676              : 
    4677              : /*
    4678              :  * dumpPublication
    4679              :  *    dump the definition of the given publication
    4680              :  */
    4681              : static void
    4682          396 : dumpPublication(Archive *fout, const PublicationInfo *pubinfo)
    4683              : {
    4684          396 :     DumpOptions *dopt = fout->dopt;
    4685              :     PQExpBuffer delq;
    4686              :     PQExpBuffer query;
    4687              :     char       *qpubname;
    4688          396 :     bool        first = true;
    4689              : 
    4690              :     /* Do nothing if not dumping schema */
    4691          396 :     if (!dopt->dumpSchema)
    4692           60 :         return;
    4693              : 
    4694          336 :     delq = createPQExpBuffer();
    4695          336 :     query = createPQExpBuffer();
    4696              : 
    4697          336 :     qpubname = pg_strdup(fmtId(pubinfo->dobj.name));
    4698              : 
    4699          336 :     appendPQExpBuffer(delq, "DROP PUBLICATION %s;\n",
    4700              :                       qpubname);
    4701              : 
    4702          336 :     appendPQExpBuffer(query, "CREATE PUBLICATION %s",
    4703              :                       qpubname);
    4704              : 
    4705          336 :     if (pubinfo->puballtables)
    4706              :     {
    4707          156 :         int         n_except = 0;
    4708              : 
    4709          156 :         appendPQExpBufferStr(query, " FOR ALL TABLES");
    4710              : 
    4711              :         /* Include EXCEPT TABLE clause if there are except_tables. */
    4712          311 :         for (SimplePtrListCell *cell = pubinfo->except_tables.head; cell; cell = cell->next)
    4713              :         {
    4714          155 :             TableInfo  *tbinfo = (TableInfo *) cell->ptr;
    4715              : 
    4716          155 :             if (++n_except == 1)
    4717           93 :                 appendPQExpBufferStr(query, " EXCEPT TABLE (");
    4718              :             else
    4719           62 :                 appendPQExpBufferStr(query, ", ");
    4720          155 :             appendPQExpBuffer(query, "ONLY %s", fmtQualifiedDumpable(tbinfo));
    4721              :         }
    4722          156 :         if (n_except > 0)
    4723           93 :             appendPQExpBufferStr(query, ")");
    4724              : 
    4725          156 :         if (pubinfo->puballsequences)
    4726           31 :             appendPQExpBufferStr(query, ", ALL SEQUENCES");
    4727              :     }
    4728          180 :     else if (pubinfo->puballsequences)
    4729           31 :         appendPQExpBufferStr(query, " FOR ALL SEQUENCES");
    4730              : 
    4731          336 :     appendPQExpBufferStr(query, " WITH (publish = '");
    4732          336 :     if (pubinfo->pubinsert)
    4733              :     {
    4734          274 :         appendPQExpBufferStr(query, "insert");
    4735          274 :         first = false;
    4736              :     }
    4737              : 
    4738          336 :     if (pubinfo->pubupdate)
    4739              :     {
    4740          274 :         if (!first)
    4741          274 :             appendPQExpBufferStr(query, ", ");
    4742              : 
    4743          274 :         appendPQExpBufferStr(query, "update");
    4744          274 :         first = false;
    4745              :     }
    4746              : 
    4747          336 :     if (pubinfo->pubdelete)
    4748              :     {
    4749          274 :         if (!first)
    4750          274 :             appendPQExpBufferStr(query, ", ");
    4751              : 
    4752          274 :         appendPQExpBufferStr(query, "delete");
    4753          274 :         first = false;
    4754              :     }
    4755              : 
    4756          336 :     if (pubinfo->pubtruncate)
    4757              :     {
    4758          274 :         if (!first)
    4759          274 :             appendPQExpBufferStr(query, ", ");
    4760              : 
    4761          274 :         appendPQExpBufferStr(query, "truncate");
    4762          274 :         first = false;
    4763              :     }
    4764              : 
    4765          336 :     appendPQExpBufferChar(query, '\'');
    4766              : 
    4767          336 :     if (pubinfo->pubviaroot)
    4768            5 :         appendPQExpBufferStr(query, ", publish_via_partition_root = true");
    4769              : 
    4770          336 :     if (pubinfo->pubgencols_type == PUBLISH_GENCOLS_STORED)
    4771           31 :         appendPQExpBufferStr(query, ", publish_generated_columns = stored");
    4772              : 
    4773          336 :     appendPQExpBufferStr(query, ");\n");
    4774              : 
    4775          336 :     if (pubinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
    4776          336 :         ArchiveEntry(fout, pubinfo->dobj.catId, pubinfo->dobj.dumpId,
    4777          336 :                      ARCHIVE_OPTS(.tag = pubinfo->dobj.name,
    4778              :                                   .owner = pubinfo->rolname,
    4779              :                                   .description = "PUBLICATION",
    4780              :                                   .section = SECTION_POST_DATA,
    4781              :                                   .createStmt = query->data,
    4782              :                                   .dropStmt = delq->data));
    4783              : 
    4784          336 :     if (pubinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
    4785           31 :         dumpComment(fout, "PUBLICATION", qpubname,
    4786           31 :                     NULL, pubinfo->rolname,
    4787           31 :                     pubinfo->dobj.catId, 0, pubinfo->dobj.dumpId);
    4788              : 
    4789          336 :     if (pubinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
    4790            0 :         dumpSecLabel(fout, "PUBLICATION", qpubname,
    4791            0 :                      NULL, pubinfo->rolname,
    4792            0 :                      pubinfo->dobj.catId, 0, pubinfo->dobj.dumpId);
    4793              : 
    4794          336 :     destroyPQExpBuffer(delq);
    4795          336 :     destroyPQExpBuffer(query);
    4796          336 :     free(qpubname);
    4797              : }
    4798              : 
    4799              : /*
    4800              :  * getPublicationNamespaces
    4801              :  *    get information about publication membership for dumpable schemas.
    4802              :  */
    4803              : void
    4804          259 : getPublicationNamespaces(Archive *fout)
    4805              : {
    4806              :     PQExpBuffer query;
    4807              :     PGresult   *res;
    4808              :     PublicationSchemaInfo *pubsinfo;
    4809          259 :     DumpOptions *dopt = fout->dopt;
    4810              :     int         i_tableoid;
    4811              :     int         i_oid;
    4812              :     int         i_pnpubid;
    4813              :     int         i_pnnspid;
    4814              :     int         i,
    4815              :                 j,
    4816              :                 ntups;
    4817              : 
    4818          259 :     if (dopt->no_publications || fout->remoteVersion < 150000)
    4819            0 :         return;
    4820              : 
    4821          259 :     query = createPQExpBuffer();
    4822              : 
    4823              :     /* Collect all publication membership info. */
    4824          259 :     appendPQExpBufferStr(query,
    4825              :                          "SELECT tableoid, oid, pnpubid, pnnspid "
    4826              :                          "FROM pg_catalog.pg_publication_namespace");
    4827          259 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    4828              : 
    4829          259 :     ntups = PQntuples(res);
    4830              : 
    4831          259 :     i_tableoid = PQfnumber(res, "tableoid");
    4832          259 :     i_oid = PQfnumber(res, "oid");
    4833          259 :     i_pnpubid = PQfnumber(res, "pnpubid");
    4834          259 :     i_pnnspid = PQfnumber(res, "pnnspid");
    4835              : 
    4836              :     /* this allocation may be more than we need */
    4837          259 :     pubsinfo = pg_malloc_array(PublicationSchemaInfo, ntups);
    4838          259 :     j = 0;
    4839              : 
    4840          384 :     for (i = 0; i < ntups; i++)
    4841              :     {
    4842          125 :         Oid         pnpubid = atooid(PQgetvalue(res, i, i_pnpubid));
    4843          125 :         Oid         pnnspid = atooid(PQgetvalue(res, i, i_pnnspid));
    4844              :         PublicationInfo *pubinfo;
    4845              :         NamespaceInfo *nspinfo;
    4846              : 
    4847              :         /*
    4848              :          * Ignore any entries for which we aren't interested in either the
    4849              :          * publication or the rel.
    4850              :          */
    4851          125 :         pubinfo = findPublicationByOid(pnpubid);
    4852          125 :         if (pubinfo == NULL)
    4853            0 :             continue;
    4854          125 :         nspinfo = findNamespaceByOid(pnnspid);
    4855          125 :         if (nspinfo == NULL)
    4856            0 :             continue;
    4857              : 
    4858              :         /* OK, make a DumpableObject for this relationship */
    4859          125 :         pubsinfo[j].dobj.objType = DO_PUBLICATION_TABLE_IN_SCHEMA;
    4860          125 :         pubsinfo[j].dobj.catId.tableoid =
    4861          125 :             atooid(PQgetvalue(res, i, i_tableoid));
    4862          125 :         pubsinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    4863          125 :         AssignDumpId(&pubsinfo[j].dobj);
    4864          125 :         pubsinfo[j].dobj.namespace = nspinfo->dobj.namespace;
    4865          125 :         pubsinfo[j].dobj.name = nspinfo->dobj.name;
    4866          125 :         pubsinfo[j].publication = pubinfo;
    4867          125 :         pubsinfo[j].pubschema = nspinfo;
    4868              : 
    4869              :         /* Decide whether we want to dump it */
    4870          125 :         selectDumpablePublicationObject(&(pubsinfo[j].dobj), fout);
    4871              : 
    4872          125 :         j++;
    4873              :     }
    4874              : 
    4875          259 :     PQclear(res);
    4876          259 :     destroyPQExpBuffer(query);
    4877              : }
    4878              : 
    4879              : /*
    4880              :  * getPublicationTables
    4881              :  *    get information about publication membership for dumpable tables.
    4882              :  */
    4883              : void
    4884          259 : getPublicationTables(Archive *fout, TableInfo tblinfo[], int numTables)
    4885              : {
    4886              :     PQExpBuffer query;
    4887              :     PGresult   *res;
    4888              :     PublicationRelInfo *pubrinfo;
    4889          259 :     DumpOptions *dopt = fout->dopt;
    4890              :     int         i_tableoid;
    4891              :     int         i_oid;
    4892              :     int         i_prpubid;
    4893              :     int         i_prrelid;
    4894              :     int         i_prrelqual;
    4895              :     int         i_prattrs;
    4896              :     int         i,
    4897              :                 j,
    4898              :                 ntups;
    4899              : 
    4900          259 :     if (dopt->no_publications || fout->remoteVersion < 100000)
    4901            0 :         return;
    4902              : 
    4903          259 :     query = createPQExpBuffer();
    4904              : 
    4905              :     /* Collect all publication membership info. */
    4906          259 :     if (fout->remoteVersion >= 150000)
    4907              :     {
    4908          259 :         appendPQExpBufferStr(query,
    4909              :                              "SELECT tableoid, oid, prpubid, prrelid, "
    4910              :                              "pg_catalog.pg_get_expr(prqual, prrelid) AS prrelqual, "
    4911              :                              "(CASE\n"
    4912              :                              "  WHEN pr.prattrs IS NOT NULL THEN\n"
    4913              :                              "    (SELECT array_agg(attname)\n"
    4914              :                              "       FROM\n"
    4915              :                              "         pg_catalog.generate_series(0, pg_catalog.array_upper(pr.prattrs::pg_catalog.int2[], 1)) s,\n"
    4916              :                              "         pg_catalog.pg_attribute\n"
    4917              :                              "      WHERE attrelid = pr.prrelid AND attnum = prattrs[s])\n"
    4918              :                              "  ELSE NULL END) prattrs "
    4919              :                              "FROM pg_catalog.pg_publication_rel pr");
    4920          259 :         if (fout->remoteVersion >= 190000)
    4921          259 :             appendPQExpBufferStr(query, " WHERE NOT pr.prexcept");
    4922              :     }
    4923              :     else
    4924            0 :         appendPQExpBufferStr(query,
    4925              :                              "SELECT tableoid, oid, prpubid, prrelid, "
    4926              :                              "NULL AS prrelqual, NULL AS prattrs "
    4927              :                              "FROM pg_catalog.pg_publication_rel");
    4928          259 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    4929              : 
    4930          259 :     ntups = PQntuples(res);
    4931              : 
    4932          259 :     i_tableoid = PQfnumber(res, "tableoid");
    4933          259 :     i_oid = PQfnumber(res, "oid");
    4934          259 :     i_prpubid = PQfnumber(res, "prpubid");
    4935          259 :     i_prrelid = PQfnumber(res, "prrelid");
    4936          259 :     i_prrelqual = PQfnumber(res, "prrelqual");
    4937          259 :     i_prattrs = PQfnumber(res, "prattrs");
    4938              : 
    4939              :     /* this allocation may be more than we need */
    4940          259 :     pubrinfo = pg_malloc_array(PublicationRelInfo, ntups);
    4941          259 :     j = 0;
    4942              : 
    4943          609 :     for (i = 0; i < ntups; i++)
    4944              :     {
    4945          350 :         Oid         prpubid = atooid(PQgetvalue(res, i, i_prpubid));
    4946          350 :         Oid         prrelid = atooid(PQgetvalue(res, i, i_prrelid));
    4947              :         PublicationInfo *pubinfo;
    4948              :         TableInfo  *tbinfo;
    4949              : 
    4950              :         /*
    4951              :          * Ignore any entries for which we aren't interested in either the
    4952              :          * publication or the rel.
    4953              :          */
    4954          350 :         pubinfo = findPublicationByOid(prpubid);
    4955          350 :         if (pubinfo == NULL)
    4956            0 :             continue;
    4957          350 :         tbinfo = findTableByOid(prrelid);
    4958          350 :         if (tbinfo == NULL)
    4959            0 :             continue;
    4960              : 
    4961              :         /* OK, make a DumpableObject for this relationship */
    4962          350 :         pubrinfo[j].dobj.objType = DO_PUBLICATION_REL;
    4963          350 :         pubrinfo[j].dobj.catId.tableoid =
    4964          350 :             atooid(PQgetvalue(res, i, i_tableoid));
    4965          350 :         pubrinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    4966          350 :         AssignDumpId(&pubrinfo[j].dobj);
    4967          350 :         pubrinfo[j].dobj.namespace = tbinfo->dobj.namespace;
    4968          350 :         pubrinfo[j].dobj.name = tbinfo->dobj.name;
    4969          350 :         pubrinfo[j].publication = pubinfo;
    4970          350 :         pubrinfo[j].pubtable = tbinfo;
    4971          350 :         if (PQgetisnull(res, i, i_prrelqual))
    4972          194 :             pubrinfo[j].pubrelqual = NULL;
    4973              :         else
    4974          156 :             pubrinfo[j].pubrelqual = pg_strdup(PQgetvalue(res, i, i_prrelqual));
    4975              : 
    4976          350 :         if (!PQgetisnull(res, i, i_prattrs))
    4977              :         {
    4978              :             char      **attnames;
    4979              :             int         nattnames;
    4980              :             PQExpBuffer attribs;
    4981              : 
    4982          111 :             if (!parsePGArray(PQgetvalue(res, i, i_prattrs),
    4983              :                               &attnames, &nattnames))
    4984            0 :                 pg_fatal("could not parse %s array", "prattrs");
    4985          111 :             attribs = createPQExpBuffer();
    4986          319 :             for (int k = 0; k < nattnames; k++)
    4987              :             {
    4988          208 :                 if (k > 0)
    4989           97 :                     appendPQExpBufferStr(attribs, ", ");
    4990              : 
    4991          208 :                 appendPQExpBufferStr(attribs, fmtId(attnames[k]));
    4992              :             }
    4993          111 :             pubrinfo[j].pubrattrs = attribs->data;
    4994          111 :             free(attribs);      /* but not attribs->data */
    4995          111 :             free(attnames);
    4996              :         }
    4997              :         else
    4998          239 :             pubrinfo[j].pubrattrs = NULL;
    4999              : 
    5000              :         /* Decide whether we want to dump it */
    5001          350 :         selectDumpablePublicationObject(&(pubrinfo[j].dobj), fout);
    5002              : 
    5003          350 :         j++;
    5004              :     }
    5005              : 
    5006          259 :     PQclear(res);
    5007          259 :     destroyPQExpBuffer(query);
    5008              : }
    5009              : 
    5010              : /*
    5011              :  * dumpPublicationNamespace
    5012              :  *    dump the definition of the given publication schema mapping.
    5013              :  */
    5014              : static void
    5015           99 : dumpPublicationNamespace(Archive *fout, const PublicationSchemaInfo *pubsinfo)
    5016              : {
    5017           99 :     DumpOptions *dopt = fout->dopt;
    5018           99 :     NamespaceInfo *schemainfo = pubsinfo->pubschema;
    5019           99 :     PublicationInfo *pubinfo = pubsinfo->publication;
    5020              :     PQExpBuffer query;
    5021              :     char       *tag;
    5022              : 
    5023              :     /* Do nothing if not dumping schema */
    5024           99 :     if (!dopt->dumpSchema)
    5025           12 :         return;
    5026              : 
    5027           87 :     tag = psprintf("%s %s", pubinfo->dobj.name, schemainfo->dobj.name);
    5028              : 
    5029           87 :     query = createPQExpBuffer();
    5030              : 
    5031           87 :     appendPQExpBuffer(query, "ALTER PUBLICATION %s ", fmtId(pubinfo->dobj.name));
    5032           87 :     appendPQExpBuffer(query, "ADD TABLES IN SCHEMA %s;\n", fmtId(schemainfo->dobj.name));
    5033              : 
    5034              :     /*
    5035              :      * There is no point in creating drop query as the drop is done by schema
    5036              :      * drop.
    5037              :      */
    5038           87 :     if (pubsinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
    5039           87 :         ArchiveEntry(fout, pubsinfo->dobj.catId, pubsinfo->dobj.dumpId,
    5040           87 :                      ARCHIVE_OPTS(.tag = tag,
    5041              :                                   .namespace = schemainfo->dobj.name,
    5042              :                                   .owner = pubinfo->rolname,
    5043              :                                   .description = "PUBLICATION TABLES IN SCHEMA",
    5044              :                                   .section = SECTION_POST_DATA,
    5045              :                                   .createStmt = query->data));
    5046              : 
    5047              :     /* These objects can't currently have comments or seclabels */
    5048              : 
    5049           87 :     free(tag);
    5050           87 :     destroyPQExpBuffer(query);
    5051              : }
    5052              : 
    5053              : /*
    5054              :  * dumpPublicationTable
    5055              :  *    dump the definition of the given publication table mapping
    5056              :  */
    5057              : static void
    5058          284 : dumpPublicationTable(Archive *fout, const PublicationRelInfo *pubrinfo)
    5059              : {
    5060          284 :     DumpOptions *dopt = fout->dopt;
    5061          284 :     PublicationInfo *pubinfo = pubrinfo->publication;
    5062          284 :     TableInfo  *tbinfo = pubrinfo->pubtable;
    5063              :     PQExpBuffer query;
    5064              :     char       *tag;
    5065              : 
    5066              :     /* Do nothing if not dumping schema */
    5067          284 :     if (!dopt->dumpSchema)
    5068           42 :         return;
    5069              : 
    5070          242 :     tag = psprintf("%s %s", pubinfo->dobj.name, tbinfo->dobj.name);
    5071              : 
    5072          242 :     query = createPQExpBuffer();
    5073              : 
    5074          242 :     appendPQExpBuffer(query, "ALTER PUBLICATION %s ADD TABLE ONLY",
    5075          242 :                       fmtId(pubinfo->dobj.name));
    5076          242 :     appendPQExpBuffer(query, " %s",
    5077          242 :                       fmtQualifiedDumpable(tbinfo));
    5078              : 
    5079          242 :     if (pubrinfo->pubrattrs)
    5080           77 :         appendPQExpBuffer(query, " (%s)", pubrinfo->pubrattrs);
    5081              : 
    5082          242 :     if (pubrinfo->pubrelqual)
    5083              :     {
    5084              :         /*
    5085              :          * It's necessary to add parentheses around the expression because
    5086              :          * pg_get_expr won't supply the parentheses for things like WHERE
    5087              :          * TRUE.
    5088              :          */
    5089          108 :         appendPQExpBuffer(query, " WHERE (%s)", pubrinfo->pubrelqual);
    5090              :     }
    5091          242 :     appendPQExpBufferStr(query, ";\n");
    5092              : 
    5093              :     /*
    5094              :      * There is no point in creating a drop query as the drop is done by table
    5095              :      * drop.  (If you think to change this, see also _printTocEntry().)
    5096              :      * Although this object doesn't really have ownership as such, set the
    5097              :      * owner field anyway to ensure that the command is run by the correct
    5098              :      * role at restore time.
    5099              :      */
    5100          242 :     if (pubrinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
    5101          242 :         ArchiveEntry(fout, pubrinfo->dobj.catId, pubrinfo->dobj.dumpId,
    5102          242 :                      ARCHIVE_OPTS(.tag = tag,
    5103              :                                   .namespace = tbinfo->dobj.namespace->dobj.name,
    5104              :                                   .owner = pubinfo->rolname,
    5105              :                                   .description = "PUBLICATION TABLE",
    5106              :                                   .section = SECTION_POST_DATA,
    5107              :                                   .createStmt = query->data));
    5108              : 
    5109              :     /* These objects can't currently have comments or seclabels */
    5110              : 
    5111          242 :     free(tag);
    5112          242 :     destroyPQExpBuffer(query);
    5113              : }
    5114              : 
    5115              : /*
    5116              :  * Is the currently connected user a superuser?
    5117              :  */
    5118              : static bool
    5119          258 : is_superuser(Archive *fout)
    5120              : {
    5121          258 :     ArchiveHandle *AH = (ArchiveHandle *) fout;
    5122              :     const char *val;
    5123              : 
    5124          258 :     val = PQparameterStatus(AH->connection, "is_superuser");
    5125              : 
    5126          258 :     if (val && strcmp(val, "on") == 0)
    5127          255 :         return true;
    5128              : 
    5129            3 :     return false;
    5130              : }
    5131              : 
    5132              : /*
    5133              :  * Set the given value to restrict_nonsystem_relation_kind value. Since
    5134              :  * restrict_nonsystem_relation_kind is introduced in minor version releases,
    5135              :  * the setting query is effective only where available.
    5136              :  */
    5137              : static void
    5138          293 : set_restrict_relation_kind(Archive *AH, const char *value)
    5139              : {
    5140          293 :     PQExpBuffer query = createPQExpBuffer();
    5141              :     PGresult   *res;
    5142              : 
    5143          293 :     appendPQExpBuffer(query,
    5144              :                       "SELECT set_config(name, '%s', false) "
    5145              :                       "FROM pg_settings "
    5146              :                       "WHERE name = 'restrict_nonsystem_relation_kind'",
    5147              :                       value);
    5148          293 :     res = ExecuteSqlQuery(AH, query->data, PGRES_TUPLES_OK);
    5149              : 
    5150          293 :     PQclear(res);
    5151          293 :     destroyPQExpBuffer(query);
    5152          293 : }
    5153              : 
    5154              : /*
    5155              :  * getSubscriptions
    5156              :  *    get information about subscriptions
    5157              :  */
    5158              : void
    5159          259 : getSubscriptions(Archive *fout)
    5160              : {
    5161          259 :     DumpOptions *dopt = fout->dopt;
    5162              :     PQExpBuffer query;
    5163              :     PGresult   *res;
    5164              :     SubscriptionInfo *subinfo;
    5165              :     int         i_tableoid;
    5166              :     int         i_oid;
    5167              :     int         i_subname;
    5168              :     int         i_subowner;
    5169              :     int         i_subbinary;
    5170              :     int         i_substream;
    5171              :     int         i_subtwophasestate;
    5172              :     int         i_subdisableonerr;
    5173              :     int         i_subpasswordrequired;
    5174              :     int         i_subrunasowner;
    5175              :     int         i_subservername;
    5176              :     int         i_subconninfo;
    5177              :     int         i_subslotname;
    5178              :     int         i_subsynccommit;
    5179              :     int         i_subwalrcvtimeout;
    5180              :     int         i_subpublications;
    5181              :     int         i_suborigin;
    5182              :     int         i_suboriginremotelsn;
    5183              :     int         i_subenabled;
    5184              :     int         i_subfailover;
    5185              :     int         i_subretaindeadtuples;
    5186              :     int         i_submaxretention;
    5187              :     int         i,
    5188              :                 ntups;
    5189              : 
    5190          259 :     if (dopt->no_subscriptions || fout->remoteVersion < 100000)
    5191            1 :         return;
    5192              : 
    5193          258 :     if (!is_superuser(fout))
    5194              :     {
    5195              :         int         n;
    5196              : 
    5197            3 :         res = ExecuteSqlQuery(fout,
    5198              :                               "SELECT count(*) FROM pg_subscription "
    5199              :                               "WHERE subdbid = (SELECT oid FROM pg_database"
    5200              :                               "                 WHERE datname = current_database())",
    5201              :                               PGRES_TUPLES_OK);
    5202            3 :         n = atoi(PQgetvalue(res, 0, 0));
    5203            3 :         if (n > 0)
    5204            2 :             pg_log_warning("subscriptions not dumped because current user is not a superuser");
    5205            3 :         PQclear(res);
    5206            3 :         return;
    5207              :     }
    5208              : 
    5209          255 :     query = createPQExpBuffer();
    5210              : 
    5211              :     /* Get the subscriptions in current database. */
    5212          255 :     appendPQExpBufferStr(query,
    5213              :                          "SELECT s.tableoid, s.oid, s.subname,\n"
    5214              :                          " s.subowner,\n"
    5215              :                          " s.subconninfo, s.subslotname, s.subsynccommit,\n"
    5216              :                          " s.subpublications,\n");
    5217              : 
    5218          255 :     if (fout->remoteVersion >= 140000)
    5219          255 :         appendPQExpBufferStr(query, " s.subbinary,\n");
    5220              :     else
    5221            0 :         appendPQExpBufferStr(query, " false AS subbinary,\n");
    5222              : 
    5223          255 :     if (fout->remoteVersion >= 140000)
    5224          255 :         appendPQExpBufferStr(query, " s.substream,\n");
    5225              :     else
    5226            0 :         appendPQExpBufferStr(query, " 'f' AS substream,\n");
    5227              : 
    5228          255 :     if (fout->remoteVersion >= 150000)
    5229          255 :         appendPQExpBufferStr(query,
    5230              :                              " s.subtwophasestate,\n"
    5231              :                              " s.subdisableonerr,\n");
    5232              :     else
    5233            0 :         appendPQExpBuffer(query,
    5234              :                           " '%c' AS subtwophasestate,\n"
    5235              :                           " false AS subdisableonerr,\n",
    5236              :                           LOGICALREP_TWOPHASE_STATE_DISABLED);
    5237              : 
    5238          255 :     if (fout->remoteVersion >= 160000)
    5239          255 :         appendPQExpBufferStr(query,
    5240              :                              " s.subpasswordrequired,\n"
    5241              :                              " s.subrunasowner,\n"
    5242              :                              " s.suborigin,\n");
    5243              :     else
    5244            0 :         appendPQExpBuffer(query,
    5245              :                           " 't' AS subpasswordrequired,\n"
    5246              :                           " 't' AS subrunasowner,\n"
    5247              :                           " '%s' AS suborigin,\n",
    5248              :                           LOGICALREP_ORIGIN_ANY);
    5249              : 
    5250          255 :     if (dopt->binary_upgrade && fout->remoteVersion >= 170000)
    5251           40 :         appendPQExpBufferStr(query, " o.remote_lsn AS suboriginremotelsn,\n"
    5252              :                              " s.subenabled,\n");
    5253              :     else
    5254          215 :         appendPQExpBufferStr(query, " NULL AS suboriginremotelsn,\n"
    5255              :                              " false AS subenabled,\n");
    5256              : 
    5257          255 :     if (fout->remoteVersion >= 170000)
    5258          255 :         appendPQExpBufferStr(query,
    5259              :                              " s.subfailover,\n");
    5260              :     else
    5261            0 :         appendPQExpBufferStr(query,
    5262              :                              " false AS subfailover,\n");
    5263              : 
    5264          255 :     if (fout->remoteVersion >= 190000)
    5265          255 :         appendPQExpBufferStr(query,
    5266              :                              " s.subretaindeadtuples,\n");
    5267              :     else
    5268            0 :         appendPQExpBufferStr(query,
    5269              :                              " false AS subretaindeadtuples,\n");
    5270              : 
    5271          255 :     if (fout->remoteVersion >= 190000)
    5272          255 :         appendPQExpBufferStr(query,
    5273              :                              " s.submaxretention,\n");
    5274              :     else
    5275            0 :         appendPQExpBuffer(query,
    5276              :                           " 0 AS submaxretention,\n");
    5277              : 
    5278          255 :     if (fout->remoteVersion >= 190000)
    5279          255 :         appendPQExpBufferStr(query,
    5280              :                              " s.subwalrcvtimeout,\n");
    5281              :     else
    5282            0 :         appendPQExpBufferStr(query,
    5283              :                              " '-1' AS subwalrcvtimeout,\n");
    5284              : 
    5285          255 :     if (fout->remoteVersion >= 190000)
    5286          255 :         appendPQExpBufferStr(query, " fs.srvname AS subservername\n");
    5287              :     else
    5288            0 :         appendPQExpBufferStr(query, " NULL AS subservername\n");
    5289              : 
    5290          255 :     appendPQExpBufferStr(query,
    5291              :                          "FROM pg_subscription s\n");
    5292              : 
    5293          255 :     if (fout->remoteVersion >= 190000)
    5294          255 :         appendPQExpBufferStr(query,
    5295              :                              "LEFT JOIN pg_catalog.pg_foreign_server fs \n"
    5296              :                              "    ON fs.oid = s.subserver \n");
    5297              : 
    5298          255 :     if (dopt->binary_upgrade && fout->remoteVersion >= 170000)
    5299           40 :         appendPQExpBufferStr(query,
    5300              :                              "LEFT JOIN pg_catalog.pg_replication_origin_status o \n"
    5301              :                              "    ON o.external_id = 'pg_' || s.oid::text \n");
    5302              : 
    5303          255 :     appendPQExpBufferStr(query,
    5304              :                          "WHERE s.subdbid = (SELECT oid FROM pg_database\n"
    5305              :                          "                   WHERE datname = current_database())");
    5306              : 
    5307          255 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    5308              : 
    5309          255 :     ntups = PQntuples(res);
    5310              : 
    5311              :     /*
    5312              :      * Get subscription fields. We don't include subskiplsn in the dump as
    5313              :      * after restoring the dump this value may no longer be relevant.
    5314              :      */
    5315          255 :     i_tableoid = PQfnumber(res, "tableoid");
    5316          255 :     i_oid = PQfnumber(res, "oid");
    5317          255 :     i_subname = PQfnumber(res, "subname");
    5318          255 :     i_subowner = PQfnumber(res, "subowner");
    5319          255 :     i_subenabled = PQfnumber(res, "subenabled");
    5320          255 :     i_subbinary = PQfnumber(res, "subbinary");
    5321          255 :     i_substream = PQfnumber(res, "substream");
    5322          255 :     i_subtwophasestate = PQfnumber(res, "subtwophasestate");
    5323          255 :     i_subdisableonerr = PQfnumber(res, "subdisableonerr");
    5324          255 :     i_subpasswordrequired = PQfnumber(res, "subpasswordrequired");
    5325          255 :     i_subrunasowner = PQfnumber(res, "subrunasowner");
    5326          255 :     i_subfailover = PQfnumber(res, "subfailover");
    5327          255 :     i_subretaindeadtuples = PQfnumber(res, "subretaindeadtuples");
    5328          255 :     i_submaxretention = PQfnumber(res, "submaxretention");
    5329          255 :     i_subservername = PQfnumber(res, "subservername");
    5330          255 :     i_subconninfo = PQfnumber(res, "subconninfo");
    5331          255 :     i_subslotname = PQfnumber(res, "subslotname");
    5332          255 :     i_subsynccommit = PQfnumber(res, "subsynccommit");
    5333          255 :     i_subwalrcvtimeout = PQfnumber(res, "subwalrcvtimeout");
    5334          255 :     i_subpublications = PQfnumber(res, "subpublications");
    5335          255 :     i_suborigin = PQfnumber(res, "suborigin");
    5336          255 :     i_suboriginremotelsn = PQfnumber(res, "suboriginremotelsn");
    5337              : 
    5338          255 :     subinfo = pg_malloc_array(SubscriptionInfo, ntups);
    5339              : 
    5340          383 :     for (i = 0; i < ntups; i++)
    5341              :     {
    5342          128 :         subinfo[i].dobj.objType = DO_SUBSCRIPTION;
    5343          128 :         subinfo[i].dobj.catId.tableoid =
    5344          128 :             atooid(PQgetvalue(res, i, i_tableoid));
    5345          128 :         subinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    5346          128 :         AssignDumpId(&subinfo[i].dobj);
    5347          128 :         subinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_subname));
    5348          128 :         subinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_subowner));
    5349              : 
    5350          128 :         subinfo[i].subenabled =
    5351          128 :             (strcmp(PQgetvalue(res, i, i_subenabled), "t") == 0);
    5352          128 :         if (PQgetisnull(res, i, i_subservername))
    5353          128 :             subinfo[i].subservername = NULL;
    5354              :         else
    5355            0 :             subinfo[i].subservername = pg_strdup(PQgetvalue(res, i, i_subservername));
    5356          128 :         subinfo[i].subbinary =
    5357          128 :             (strcmp(PQgetvalue(res, i, i_subbinary), "t") == 0);
    5358          128 :         subinfo[i].substream = *(PQgetvalue(res, i, i_substream));
    5359          128 :         subinfo[i].subtwophasestate = *(PQgetvalue(res, i, i_subtwophasestate));
    5360          128 :         subinfo[i].subdisableonerr =
    5361          128 :             (strcmp(PQgetvalue(res, i, i_subdisableonerr), "t") == 0);
    5362          128 :         subinfo[i].subpasswordrequired =
    5363          128 :             (strcmp(PQgetvalue(res, i, i_subpasswordrequired), "t") == 0);
    5364          128 :         subinfo[i].subrunasowner =
    5365          128 :             (strcmp(PQgetvalue(res, i, i_subrunasowner), "t") == 0);
    5366          128 :         subinfo[i].subfailover =
    5367          128 :             (strcmp(PQgetvalue(res, i, i_subfailover), "t") == 0);
    5368          128 :         subinfo[i].subretaindeadtuples =
    5369          128 :             (strcmp(PQgetvalue(res, i, i_subretaindeadtuples), "t") == 0);
    5370          128 :         subinfo[i].submaxretention =
    5371          128 :             atoi(PQgetvalue(res, i, i_submaxretention));
    5372          128 :         if (PQgetisnull(res, i, i_subconninfo))
    5373            0 :             subinfo[i].subconninfo = NULL;
    5374              :         else
    5375          128 :             subinfo[i].subconninfo =
    5376          128 :                 pg_strdup(PQgetvalue(res, i, i_subconninfo));
    5377          128 :         if (PQgetisnull(res, i, i_subslotname))
    5378            0 :             subinfo[i].subslotname = NULL;
    5379              :         else
    5380          128 :             subinfo[i].subslotname =
    5381          128 :                 pg_strdup(PQgetvalue(res, i, i_subslotname));
    5382          256 :         subinfo[i].subsynccommit =
    5383          128 :             pg_strdup(PQgetvalue(res, i, i_subsynccommit));
    5384          256 :         subinfo[i].subwalrcvtimeout =
    5385          128 :             pg_strdup(PQgetvalue(res, i, i_subwalrcvtimeout));
    5386          256 :         subinfo[i].subpublications =
    5387          128 :             pg_strdup(PQgetvalue(res, i, i_subpublications));
    5388          128 :         subinfo[i].suborigin = pg_strdup(PQgetvalue(res, i, i_suborigin));
    5389          128 :         if (PQgetisnull(res, i, i_suboriginremotelsn))
    5390          127 :             subinfo[i].suboriginremotelsn = NULL;
    5391              :         else
    5392            1 :             subinfo[i].suboriginremotelsn =
    5393            1 :                 pg_strdup(PQgetvalue(res, i, i_suboriginremotelsn));
    5394              : 
    5395              :         /* Decide whether we want to dump it */
    5396          128 :         selectDumpableObject(&(subinfo[i].dobj), fout);
    5397              :     }
    5398          255 :     PQclear(res);
    5399              : 
    5400          255 :     destroyPQExpBuffer(query);
    5401              : }
    5402              : 
    5403              : /*
    5404              :  * getSubscriptionRelations
    5405              :  *    Get information about subscription membership for dumpable relations. This
    5406              :  *    will be used only in binary-upgrade mode for PG17 or later versions.
    5407              :  */
    5408              : void
    5409          259 : getSubscriptionRelations(Archive *fout)
    5410              : {
    5411          259 :     DumpOptions *dopt = fout->dopt;
    5412          259 :     SubscriptionInfo *subinfo = NULL;
    5413              :     SubRelInfo *subrinfo;
    5414              :     PGresult   *res;
    5415              :     int         i_srsubid;
    5416              :     int         i_srrelid;
    5417              :     int         i_srsubstate;
    5418              :     int         i_srsublsn;
    5419              :     int         ntups;
    5420          259 :     Oid         last_srsubid = InvalidOid;
    5421              : 
    5422          259 :     if (dopt->no_subscriptions || !dopt->binary_upgrade ||
    5423           40 :         fout->remoteVersion < 170000)
    5424          219 :         return;
    5425              : 
    5426           40 :     res = ExecuteSqlQuery(fout,
    5427              :                           "SELECT srsubid, srrelid, srsubstate, srsublsn "
    5428              :                           "FROM pg_catalog.pg_subscription_rel "
    5429              :                           "ORDER BY srsubid",
    5430              :                           PGRES_TUPLES_OK);
    5431           40 :     ntups = PQntuples(res);
    5432           40 :     if (ntups == 0)
    5433           39 :         goto cleanup;
    5434              : 
    5435              :     /* Get pg_subscription_rel attributes */
    5436            1 :     i_srsubid = PQfnumber(res, "srsubid");
    5437            1 :     i_srrelid = PQfnumber(res, "srrelid");
    5438            1 :     i_srsubstate = PQfnumber(res, "srsubstate");
    5439            1 :     i_srsublsn = PQfnumber(res, "srsublsn");
    5440              : 
    5441            1 :     subrinfo = pg_malloc_array(SubRelInfo, ntups);
    5442            4 :     for (int i = 0; i < ntups; i++)
    5443              :     {
    5444            3 :         Oid         cur_srsubid = atooid(PQgetvalue(res, i, i_srsubid));
    5445            3 :         Oid         relid = atooid(PQgetvalue(res, i, i_srrelid));
    5446              :         TableInfo  *tblinfo;
    5447              : 
    5448              :         /*
    5449              :          * If we switched to a new subscription, check if the subscription
    5450              :          * exists.
    5451              :          */
    5452            3 :         if (cur_srsubid != last_srsubid)
    5453              :         {
    5454            2 :             subinfo = findSubscriptionByOid(cur_srsubid);
    5455            2 :             if (subinfo == NULL)
    5456            0 :                 pg_fatal("subscription with OID %u does not exist", cur_srsubid);
    5457              : 
    5458            2 :             last_srsubid = cur_srsubid;
    5459              :         }
    5460              : 
    5461            3 :         tblinfo = findTableByOid(relid);
    5462            3 :         if (tblinfo == NULL)
    5463            0 :             pg_fatal("failed sanity check, relation with OID %u not found",
    5464              :                      relid);
    5465              : 
    5466              :         /* OK, make a DumpableObject for this relationship */
    5467            3 :         subrinfo[i].dobj.objType = DO_SUBSCRIPTION_REL;
    5468            3 :         subrinfo[i].dobj.catId.tableoid = relid;
    5469            3 :         subrinfo[i].dobj.catId.oid = cur_srsubid;
    5470            3 :         AssignDumpId(&subrinfo[i].dobj);
    5471            3 :         subrinfo[i].dobj.namespace = tblinfo->dobj.namespace;
    5472            3 :         subrinfo[i].dobj.name = tblinfo->dobj.name;
    5473            3 :         subrinfo[i].subinfo = subinfo;
    5474            3 :         subrinfo[i].tblinfo = tblinfo;
    5475            3 :         subrinfo[i].srsubstate = PQgetvalue(res, i, i_srsubstate)[0];
    5476            3 :         if (PQgetisnull(res, i, i_srsublsn))
    5477            1 :             subrinfo[i].srsublsn = NULL;
    5478              :         else
    5479            2 :             subrinfo[i].srsublsn = pg_strdup(PQgetvalue(res, i, i_srsublsn));
    5480              : 
    5481              :         /* Decide whether we want to dump it */
    5482            3 :         selectDumpableObject(&(subrinfo[i].dobj), fout);
    5483              :     }
    5484              : 
    5485            1 : cleanup:
    5486           40 :     PQclear(res);
    5487              : }
    5488              : 
    5489              : /*
    5490              :  * dumpSubscriptionTable
    5491              :  *    Dump the definition of the given subscription table mapping. This will be
    5492              :  *    used only in binary-upgrade mode for PG17 or later versions.
    5493              :  */
    5494              : static void
    5495            3 : dumpSubscriptionTable(Archive *fout, const SubRelInfo *subrinfo)
    5496              : {
    5497            3 :     DumpOptions *dopt = fout->dopt;
    5498            3 :     SubscriptionInfo *subinfo = subrinfo->subinfo;
    5499              :     PQExpBuffer query;
    5500              :     char       *tag;
    5501              : 
    5502              :     /* Do nothing if not dumping schema */
    5503            3 :     if (!dopt->dumpSchema)
    5504            0 :         return;
    5505              : 
    5506              :     Assert(fout->dopt->binary_upgrade && fout->remoteVersion >= 170000);
    5507              : 
    5508            3 :     tag = psprintf("%s %s", subinfo->dobj.name, subrinfo->tblinfo->dobj.name);
    5509              : 
    5510            3 :     query = createPQExpBuffer();
    5511              : 
    5512            3 :     if (subinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
    5513              :     {
    5514              :         /*
    5515              :          * binary_upgrade_add_sub_rel_state will add the subscription relation
    5516              :          * to pg_subscription_rel table. This will be used only in
    5517              :          * binary-upgrade mode.
    5518              :          */
    5519            3 :         appendPQExpBufferStr(query,
    5520              :                              "\n-- For binary upgrade, must preserve the subscriber table.\n");
    5521            3 :         appendPQExpBufferStr(query,
    5522              :                              "SELECT pg_catalog.binary_upgrade_add_sub_rel_state(");
    5523            3 :         appendStringLiteralAH(query, subinfo->dobj.name, fout);
    5524            3 :         appendPQExpBuffer(query,
    5525              :                           ", %u, '%c'",
    5526            3 :                           subrinfo->tblinfo->dobj.catId.oid,
    5527            3 :                           subrinfo->srsubstate);
    5528              : 
    5529            3 :         if (subrinfo->srsublsn && subrinfo->srsublsn[0] != '\0')
    5530            2 :             appendPQExpBuffer(query, ", '%s'", subrinfo->srsublsn);
    5531              :         else
    5532            1 :             appendPQExpBufferStr(query, ", NULL");
    5533              : 
    5534            3 :         appendPQExpBufferStr(query, ");\n");
    5535              :     }
    5536              : 
    5537              :     /*
    5538              :      * There is no point in creating a drop query as the drop is done by table
    5539              :      * drop.  (If you think to change this, see also _printTocEntry().)
    5540              :      * Although this object doesn't really have ownership as such, set the
    5541              :      * owner field anyway to ensure that the command is run by the correct
    5542              :      * role at restore time.
    5543              :      */
    5544            3 :     if (subrinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
    5545            3 :         ArchiveEntry(fout, subrinfo->dobj.catId, subrinfo->dobj.dumpId,
    5546            3 :                      ARCHIVE_OPTS(.tag = tag,
    5547              :                                   .namespace = subrinfo->tblinfo->dobj.namespace->dobj.name,
    5548              :                                   .owner = subinfo->rolname,
    5549              :                                   .description = "SUBSCRIPTION TABLE",
    5550              :                                   .section = SECTION_POST_DATA,
    5551              :                                   .createStmt = query->data));
    5552              : 
    5553              :     /* These objects can't currently have comments or seclabels */
    5554              : 
    5555            3 :     free(tag);
    5556            3 :     destroyPQExpBuffer(query);
    5557              : }
    5558              : 
    5559              : /*
    5560              :  * dumpSubscription
    5561              :  *    dump the definition of the given subscription
    5562              :  */
    5563              : static void
    5564          110 : dumpSubscription(Archive *fout, const SubscriptionInfo *subinfo)
    5565              : {
    5566          110 :     DumpOptions *dopt = fout->dopt;
    5567              :     PQExpBuffer delq;
    5568              :     PQExpBuffer query;
    5569              :     PQExpBuffer publications;
    5570              :     char       *qsubname;
    5571          110 :     char      **pubnames = NULL;
    5572          110 :     int         npubnames = 0;
    5573              :     int         i;
    5574              : 
    5575              :     /* Do nothing if not dumping schema */
    5576          110 :     if (!dopt->dumpSchema)
    5577           18 :         return;
    5578              : 
    5579           92 :     delq = createPQExpBuffer();
    5580           92 :     query = createPQExpBuffer();
    5581              : 
    5582           92 :     qsubname = pg_strdup(fmtId(subinfo->dobj.name));
    5583              : 
    5584           92 :     appendPQExpBuffer(delq, "DROP SUBSCRIPTION %s;\n",
    5585              :                       qsubname);
    5586              : 
    5587           92 :     appendPQExpBuffer(query, "CREATE SUBSCRIPTION %s ",
    5588              :                       qsubname);
    5589           92 :     if (subinfo->subservername)
    5590              :     {
    5591            0 :         appendPQExpBuffer(query, "SERVER %s", fmtId(subinfo->subservername));
    5592              :     }
    5593              :     else
    5594              :     {
    5595           92 :         appendPQExpBuffer(query, "CONNECTION ");
    5596           92 :         appendStringLiteralAH(query, subinfo->subconninfo, fout);
    5597              :     }
    5598              : 
    5599              :     /* Build list of quoted publications and append them to query. */
    5600           92 :     if (!parsePGArray(subinfo->subpublications, &pubnames, &npubnames))
    5601            0 :         pg_fatal("could not parse %s array", "subpublications");
    5602              : 
    5603           92 :     publications = createPQExpBuffer();
    5604          184 :     for (i = 0; i < npubnames; i++)
    5605              :     {
    5606           92 :         if (i > 0)
    5607            0 :             appendPQExpBufferStr(publications, ", ");
    5608              : 
    5609           92 :         appendPQExpBufferStr(publications, fmtId(pubnames[i]));
    5610              :     }
    5611              : 
    5612           92 :     appendPQExpBuffer(query, " PUBLICATION %s WITH (connect = false, slot_name = ", publications->data);
    5613           92 :     if (subinfo->subslotname)
    5614           92 :         appendStringLiteralAH(query, subinfo->subslotname, fout);
    5615              :     else
    5616            0 :         appendPQExpBufferStr(query, "NONE");
    5617              : 
    5618           92 :     if (subinfo->subbinary)
    5619            0 :         appendPQExpBufferStr(query, ", binary = true");
    5620              : 
    5621           92 :     if (subinfo->substream == LOGICALREP_STREAM_ON)
    5622           30 :         appendPQExpBufferStr(query, ", streaming = on");
    5623           62 :     else if (subinfo->substream == LOGICALREP_STREAM_PARALLEL)
    5624           32 :         appendPQExpBufferStr(query, ", streaming = parallel");
    5625              :     else
    5626           30 :         appendPQExpBufferStr(query, ", streaming = off");
    5627              : 
    5628           92 :     if (subinfo->subtwophasestate != LOGICALREP_TWOPHASE_STATE_DISABLED)
    5629            0 :         appendPQExpBufferStr(query, ", two_phase = on");
    5630              : 
    5631           92 :     if (subinfo->subdisableonerr)
    5632            0 :         appendPQExpBufferStr(query, ", disable_on_error = true");
    5633              : 
    5634           92 :     if (!subinfo->subpasswordrequired)
    5635            0 :         appendPQExpBufferStr(query, ", password_required = false");
    5636              : 
    5637           92 :     if (subinfo->subrunasowner)
    5638            0 :         appendPQExpBufferStr(query, ", run_as_owner = true");
    5639              : 
    5640           92 :     if (subinfo->subfailover)
    5641            1 :         appendPQExpBufferStr(query, ", failover = true");
    5642              : 
    5643           92 :     if (subinfo->subretaindeadtuples)
    5644            1 :         appendPQExpBufferStr(query, ", retain_dead_tuples = true");
    5645              : 
    5646           92 :     if (subinfo->submaxretention)
    5647            0 :         appendPQExpBuffer(query, ", max_retention_duration = %d", subinfo->submaxretention);
    5648              : 
    5649           92 :     if (strcmp(subinfo->subsynccommit, "off") != 0)
    5650            0 :         appendPQExpBuffer(query, ", synchronous_commit = %s", fmtId(subinfo->subsynccommit));
    5651              : 
    5652           92 :     if (strcmp(subinfo->subwalrcvtimeout, "-1") != 0)
    5653            0 :         appendPQExpBuffer(query, ", wal_receiver_timeout = %s", fmtId(subinfo->subwalrcvtimeout));
    5654              : 
    5655           92 :     if (pg_strcasecmp(subinfo->suborigin, LOGICALREP_ORIGIN_ANY) != 0)
    5656           30 :         appendPQExpBuffer(query, ", origin = %s", subinfo->suborigin);
    5657              : 
    5658           92 :     appendPQExpBufferStr(query, ");\n");
    5659              : 
    5660              :     /*
    5661              :      * In binary-upgrade mode, we allow the replication to continue after the
    5662              :      * upgrade.
    5663              :      */
    5664           92 :     if (dopt->binary_upgrade && fout->remoteVersion >= 170000)
    5665              :     {
    5666            5 :         if (subinfo->suboriginremotelsn)
    5667              :         {
    5668              :             /*
    5669              :              * Preserve the remote_lsn for the subscriber's replication
    5670              :              * origin. This value is required to start the replication from
    5671              :              * the position before the upgrade. This value will be stale if
    5672              :              * the publisher gets upgraded before the subscriber node.
    5673              :              * However, this shouldn't be a problem as the upgrade of the
    5674              :              * publisher ensures that all the transactions were replicated
    5675              :              * before upgrading it.
    5676              :              */
    5677            1 :             appendPQExpBufferStr(query,
    5678              :                                  "\n-- For binary upgrade, must preserve the remote_lsn for the subscriber's replication origin.\n");
    5679            1 :             appendPQExpBufferStr(query,
    5680              :                                  "SELECT pg_catalog.binary_upgrade_replorigin_advance(");
    5681            1 :             appendStringLiteralAH(query, subinfo->dobj.name, fout);
    5682            1 :             appendPQExpBuffer(query, ", '%s');\n", subinfo->suboriginremotelsn);
    5683              :         }
    5684              : 
    5685            5 :         if (subinfo->subenabled)
    5686              :         {
    5687              :             /*
    5688              :              * Enable the subscription to allow the replication to continue
    5689              :              * after the upgrade.
    5690              :              */
    5691            1 :             appendPQExpBufferStr(query,
    5692              :                                  "\n-- For binary upgrade, must preserve the subscriber's running state.\n");
    5693            1 :             appendPQExpBuffer(query, "ALTER SUBSCRIPTION %s ENABLE;\n", qsubname);
    5694              :         }
    5695              :     }
    5696              : 
    5697           92 :     if (subinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
    5698           92 :         ArchiveEntry(fout, subinfo->dobj.catId, subinfo->dobj.dumpId,
    5699           92 :                      ARCHIVE_OPTS(.tag = subinfo->dobj.name,
    5700              :                                   .owner = subinfo->rolname,
    5701              :                                   .description = "SUBSCRIPTION",
    5702              :                                   .section = SECTION_POST_DATA,
    5703              :                                   .createStmt = query->data,
    5704              :                                   .dropStmt = delq->data));
    5705              : 
    5706           92 :     if (subinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
    5707           30 :         dumpComment(fout, "SUBSCRIPTION", qsubname,
    5708           30 :                     NULL, subinfo->rolname,
    5709           30 :                     subinfo->dobj.catId, 0, subinfo->dobj.dumpId);
    5710              : 
    5711           92 :     if (subinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
    5712            0 :         dumpSecLabel(fout, "SUBSCRIPTION", qsubname,
    5713            0 :                      NULL, subinfo->rolname,
    5714            0 :                      subinfo->dobj.catId, 0, subinfo->dobj.dumpId);
    5715              : 
    5716           92 :     destroyPQExpBuffer(publications);
    5717           92 :     free(pubnames);
    5718              : 
    5719           92 :     destroyPQExpBuffer(delq);
    5720           92 :     destroyPQExpBuffer(query);
    5721           92 :     free(qsubname);
    5722              : }
    5723              : 
    5724              : /*
    5725              :  * Given a "create query", append as many ALTER ... DEPENDS ON EXTENSION as
    5726              :  * the object needs.
    5727              :  */
    5728              : static void
    5729         5264 : append_depends_on_extension(Archive *fout,
    5730              :                             PQExpBuffer create,
    5731              :                             const DumpableObject *dobj,
    5732              :                             const char *catalog,
    5733              :                             const char *keyword,
    5734              :                             const char *objname)
    5735              : {
    5736         5264 :     if (dobj->depends_on_ext)
    5737              :     {
    5738              :         char       *nm;
    5739              :         PGresult   *res;
    5740              :         PQExpBuffer query;
    5741              :         int         ntups;
    5742              :         int         i_extname;
    5743              :         int         i;
    5744              : 
    5745              :         /* dodge fmtId() non-reentrancy */
    5746           42 :         nm = pg_strdup(objname);
    5747              : 
    5748           42 :         query = createPQExpBuffer();
    5749           42 :         appendPQExpBuffer(query,
    5750              :                           "SELECT e.extname "
    5751              :                           "FROM pg_catalog.pg_depend d, pg_catalog.pg_extension e "
    5752              :                           "WHERE d.refobjid = e.oid AND classid = '%s'::pg_catalog.regclass "
    5753              :                           "AND objid = '%u'::pg_catalog.oid AND deptype = 'x' "
    5754              :                           "AND refclassid = 'pg_catalog.pg_extension'::pg_catalog.regclass",
    5755              :                           catalog,
    5756           42 :                           dobj->catId.oid);
    5757           42 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    5758           42 :         ntups = PQntuples(res);
    5759           42 :         i_extname = PQfnumber(res, "extname");
    5760           84 :         for (i = 0; i < ntups; i++)
    5761              :         {
    5762           42 :             appendPQExpBuffer(create, "\nALTER %s %s DEPENDS ON EXTENSION %s;",
    5763              :                               keyword, nm,
    5764           42 :                               fmtId(PQgetvalue(res, i, i_extname)));
    5765              :         }
    5766              : 
    5767           42 :         PQclear(res);
    5768           42 :         destroyPQExpBuffer(query);
    5769           42 :         pg_free(nm);
    5770              :     }
    5771         5264 : }
    5772              : 
    5773              : static Oid
    5774            0 : get_next_possible_free_pg_type_oid(Archive *fout, PQExpBuffer upgrade_query)
    5775              : {
    5776              :     /*
    5777              :      * If the old version didn't assign an array type, but the new version
    5778              :      * does, we must select an unused type OID to assign.  This currently only
    5779              :      * happens for domains, when upgrading pre-v11 to v11 and up.
    5780              :      *
    5781              :      * Note: local state here is kind of ugly, but we must have some, since we
    5782              :      * mustn't choose the same unused OID more than once.
    5783              :      */
    5784              :     static Oid  next_possible_free_oid = FirstNormalObjectId;
    5785              :     PGresult   *res;
    5786              :     bool        is_dup;
    5787              : 
    5788              :     do
    5789              :     {
    5790            0 :         ++next_possible_free_oid;
    5791            0 :         printfPQExpBuffer(upgrade_query,
    5792              :                           "SELECT EXISTS(SELECT 1 "
    5793              :                           "FROM pg_catalog.pg_type "
    5794              :                           "WHERE oid = '%u'::pg_catalog.oid);",
    5795              :                           next_possible_free_oid);
    5796            0 :         res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data);
    5797            0 :         is_dup = (PQgetvalue(res, 0, 0)[0] == 't');
    5798            0 :         PQclear(res);
    5799            0 :     } while (is_dup);
    5800              : 
    5801            0 :     return next_possible_free_oid;
    5802              : }
    5803              : 
    5804              : static void
    5805         1016 : binary_upgrade_set_type_oids_by_type_oid(Archive *fout,
    5806              :                                          PQExpBuffer upgrade_buffer,
    5807              :                                          Oid pg_type_oid,
    5808              :                                          bool force_array_type,
    5809              :                                          bool include_multirange_type)
    5810              : {
    5811         1016 :     PQExpBuffer upgrade_query = createPQExpBuffer();
    5812              :     PGresult   *res;
    5813              :     Oid         pg_type_array_oid;
    5814              :     Oid         pg_type_multirange_oid;
    5815              :     Oid         pg_type_multirange_array_oid;
    5816              :     TypeInfo   *tinfo;
    5817              : 
    5818         1016 :     appendPQExpBufferStr(upgrade_buffer, "\n-- For binary upgrade, must preserve pg_type oid\n");
    5819         1016 :     appendPQExpBuffer(upgrade_buffer,
    5820              :                       "SELECT pg_catalog.binary_upgrade_set_next_pg_type_oid('%u'::pg_catalog.oid);\n\n",
    5821              :                       pg_type_oid);
    5822              : 
    5823         1016 :     tinfo = findTypeByOid(pg_type_oid);
    5824         1016 :     if (tinfo)
    5825         1016 :         pg_type_array_oid = tinfo->typarray;
    5826              :     else
    5827            0 :         pg_type_array_oid = InvalidOid;
    5828              : 
    5829         1016 :     if (!OidIsValid(pg_type_array_oid) && force_array_type)
    5830            0 :         pg_type_array_oid = get_next_possible_free_pg_type_oid(fout, upgrade_query);
    5831              : 
    5832         1016 :     if (OidIsValid(pg_type_array_oid))
    5833              :     {
    5834         1014 :         appendPQExpBufferStr(upgrade_buffer,
    5835              :                              "\n-- For binary upgrade, must preserve pg_type array oid\n");
    5836         1014 :         appendPQExpBuffer(upgrade_buffer,
    5837              :                           "SELECT pg_catalog.binary_upgrade_set_next_array_pg_type_oid('%u'::pg_catalog.oid);\n\n",
    5838              :                           pg_type_array_oid);
    5839              :     }
    5840              : 
    5841              :     /*
    5842              :      * Pre-set the multirange type oid and its own array type oid.
    5843              :      */
    5844         1016 :     if (include_multirange_type)
    5845              :     {
    5846            8 :         if (fout->remoteVersion >= 140000)
    5847              :         {
    5848            8 :             printfPQExpBuffer(upgrade_query,
    5849              :                               "SELECT t.oid, t.typarray "
    5850              :                               "FROM pg_catalog.pg_type t "
    5851              :                               "JOIN pg_catalog.pg_range r "
    5852              :                               "ON t.oid = r.rngmultitypid "
    5853              :                               "WHERE r.rngtypid = '%u'::pg_catalog.oid;",
    5854              :                               pg_type_oid);
    5855              : 
    5856            8 :             res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data);
    5857              : 
    5858            8 :             pg_type_multirange_oid = atooid(PQgetvalue(res, 0, PQfnumber(res, "oid")));
    5859            8 :             pg_type_multirange_array_oid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typarray")));
    5860              : 
    5861            8 :             PQclear(res);
    5862              :         }
    5863              :         else
    5864              :         {
    5865            0 :             pg_type_multirange_oid = get_next_possible_free_pg_type_oid(fout, upgrade_query);
    5866            0 :             pg_type_multirange_array_oid = get_next_possible_free_pg_type_oid(fout, upgrade_query);
    5867              :         }
    5868              : 
    5869            8 :         appendPQExpBufferStr(upgrade_buffer,
    5870              :                              "\n-- For binary upgrade, must preserve multirange pg_type oid\n");
    5871            8 :         appendPQExpBuffer(upgrade_buffer,
    5872              :                           "SELECT pg_catalog.binary_upgrade_set_next_multirange_pg_type_oid('%u'::pg_catalog.oid);\n\n",
    5873              :                           pg_type_multirange_oid);
    5874            8 :         appendPQExpBufferStr(upgrade_buffer,
    5875              :                              "\n-- For binary upgrade, must preserve multirange pg_type array oid\n");
    5876            8 :         appendPQExpBuffer(upgrade_buffer,
    5877              :                           "SELECT pg_catalog.binary_upgrade_set_next_multirange_array_pg_type_oid('%u'::pg_catalog.oid);\n\n",
    5878              :                           pg_type_multirange_array_oid);
    5879              :     }
    5880              : 
    5881         1016 :     destroyPQExpBuffer(upgrade_query);
    5882         1016 : }
    5883              : 
    5884              : static void
    5885          941 : binary_upgrade_set_type_oids_by_rel(Archive *fout,
    5886              :                                     PQExpBuffer upgrade_buffer,
    5887              :                                     const TableInfo *tbinfo)
    5888              : {
    5889          941 :     Oid         pg_type_oid = tbinfo->reltype;
    5890              : 
    5891          941 :     if (OidIsValid(pg_type_oid))
    5892          941 :         binary_upgrade_set_type_oids_by_type_oid(fout, upgrade_buffer,
    5893              :                                                  pg_type_oid, false, false);
    5894          941 : }
    5895              : 
    5896              : /*
    5897              :  * bsearch() comparator for BinaryUpgradeClassOidItem
    5898              :  */
    5899              : static int
    5900        13565 : BinaryUpgradeClassOidItemCmp(const void *p1, const void *p2)
    5901              : {
    5902        13565 :     BinaryUpgradeClassOidItem v1 = *((const BinaryUpgradeClassOidItem *) p1);
    5903        13565 :     BinaryUpgradeClassOidItem v2 = *((const BinaryUpgradeClassOidItem *) p2);
    5904              : 
    5905        13565 :     return pg_cmp_u32(v1.oid, v2.oid);
    5906              : }
    5907              : 
    5908              : /*
    5909              :  * collectBinaryUpgradeClassOids
    5910              :  *
    5911              :  * Construct a table of pg_class information required for
    5912              :  * binary_upgrade_set_pg_class_oids().  The table is sorted by OID for speed in
    5913              :  * lookup.
    5914              :  */
    5915              : static void
    5916           40 : collectBinaryUpgradeClassOids(Archive *fout)
    5917              : {
    5918              :     PGresult   *res;
    5919              :     const char *query;
    5920              : 
    5921           40 :     query = "SELECT c.oid, c.relkind, c.relfilenode, c.reltoastrelid, "
    5922              :         "ct.relfilenode, i.indexrelid, cti.relfilenode "
    5923              :         "FROM pg_catalog.pg_class c LEFT JOIN pg_catalog.pg_index i "
    5924              :         "ON (c.reltoastrelid = i.indrelid AND i.indisvalid) "
    5925              :         "LEFT JOIN pg_catalog.pg_class ct ON (c.reltoastrelid = ct.oid) "
    5926              :         "LEFT JOIN pg_catalog.pg_class AS cti ON (i.indexrelid = cti.oid) "
    5927              :         "ORDER BY c.oid;";
    5928              : 
    5929           40 :     res = ExecuteSqlQuery(fout, query, PGRES_TUPLES_OK);
    5930              : 
    5931           40 :     nbinaryUpgradeClassOids = PQntuples(res);
    5932           40 :     binaryUpgradeClassOids =
    5933           40 :         pg_malloc_array(BinaryUpgradeClassOidItem, nbinaryUpgradeClassOids);
    5934              : 
    5935        19946 :     for (int i = 0; i < nbinaryUpgradeClassOids; i++)
    5936              :     {
    5937        19906 :         binaryUpgradeClassOids[i].oid = atooid(PQgetvalue(res, i, 0));
    5938        19906 :         binaryUpgradeClassOids[i].relkind = *PQgetvalue(res, i, 1);
    5939        19906 :         binaryUpgradeClassOids[i].relfilenumber = atooid(PQgetvalue(res, i, 2));
    5940        19906 :         binaryUpgradeClassOids[i].toast_oid = atooid(PQgetvalue(res, i, 3));
    5941        19906 :         binaryUpgradeClassOids[i].toast_relfilenumber = atooid(PQgetvalue(res, i, 4));
    5942        19906 :         binaryUpgradeClassOids[i].toast_index_oid = atooid(PQgetvalue(res, i, 5));
    5943        19906 :         binaryUpgradeClassOids[i].toast_index_relfilenumber = atooid(PQgetvalue(res, i, 6));
    5944              :     }
    5945              : 
    5946           40 :     PQclear(res);
    5947           40 : }
    5948              : 
    5949              : static void
    5950         1358 : binary_upgrade_set_pg_class_oids(Archive *fout,
    5951              :                                  PQExpBuffer upgrade_buffer, Oid pg_class_oid)
    5952              : {
    5953         1358 :     BinaryUpgradeClassOidItem key = {0};
    5954              :     BinaryUpgradeClassOidItem *entry;
    5955              : 
    5956              :     Assert(binaryUpgradeClassOids);
    5957              : 
    5958              :     /*
    5959              :      * Preserve the OID and relfilenumber of the table, table's index, table's
    5960              :      * toast table and toast table's index if any.
    5961              :      *
    5962              :      * One complexity is that the current table definition might not require
    5963              :      * the creation of a TOAST table, but the old database might have a TOAST
    5964              :      * table that was created earlier, before some wide columns were dropped.
    5965              :      * By setting the TOAST oid we force creation of the TOAST heap and index
    5966              :      * by the new backend, so we can copy the files during binary upgrade
    5967              :      * without worrying about this case.
    5968              :      */
    5969         1358 :     key.oid = pg_class_oid;
    5970         1358 :     entry = bsearch(&key, binaryUpgradeClassOids, nbinaryUpgradeClassOids,
    5971              :                     sizeof(BinaryUpgradeClassOidItem),
    5972              :                     BinaryUpgradeClassOidItemCmp);
    5973              : 
    5974         1358 :     appendPQExpBufferStr(upgrade_buffer,
    5975              :                          "\n-- For binary upgrade, must preserve pg_class oids and relfilenodes\n");
    5976              : 
    5977         1358 :     if (entry->relkind != RELKIND_INDEX &&
    5978         1055 :         entry->relkind != RELKIND_PARTITIONED_INDEX)
    5979              :     {
    5980         1025 :         appendPQExpBuffer(upgrade_buffer,
    5981              :                           "SELECT pg_catalog.binary_upgrade_set_next_heap_pg_class_oid('%u'::pg_catalog.oid);\n",
    5982              :                           pg_class_oid);
    5983              : 
    5984              :         /*
    5985              :          * Not every relation has storage. Also, in a pre-v12 database,
    5986              :          * partitioned tables have a relfilenumber, which should not be
    5987              :          * preserved when upgrading.
    5988              :          */
    5989         1025 :         if (RelFileNumberIsValid(entry->relfilenumber) &&
    5990          841 :             entry->relkind != RELKIND_PARTITIONED_TABLE)
    5991          841 :             appendPQExpBuffer(upgrade_buffer,
    5992              :                               "SELECT pg_catalog.binary_upgrade_set_next_heap_relfilenode('%u'::pg_catalog.oid);\n",
    5993              :                               entry->relfilenumber);
    5994              : 
    5995              :         /*
    5996              :          * In a pre-v12 database, partitioned tables might be marked as having
    5997              :          * toast tables, but we should ignore them if so.
    5998              :          */
    5999         1025 :         if (OidIsValid(entry->toast_oid) &&
    6000          294 :             entry->relkind != RELKIND_PARTITIONED_TABLE)
    6001              :         {
    6002          294 :             appendPQExpBuffer(upgrade_buffer,
    6003              :                               "SELECT pg_catalog.binary_upgrade_set_next_toast_pg_class_oid('%u'::pg_catalog.oid);\n",
    6004              :                               entry->toast_oid);
    6005          294 :             appendPQExpBuffer(upgrade_buffer,
    6006              :                               "SELECT pg_catalog.binary_upgrade_set_next_toast_relfilenode('%u'::pg_catalog.oid);\n",
    6007              :                               entry->toast_relfilenumber);
    6008              : 
    6009              :             /* every toast table has an index */
    6010          294 :             appendPQExpBuffer(upgrade_buffer,
    6011              :                               "SELECT pg_catalog.binary_upgrade_set_next_index_pg_class_oid('%u'::pg_catalog.oid);\n",
    6012              :                               entry->toast_index_oid);
    6013          294 :             appendPQExpBuffer(upgrade_buffer,
    6014              :                               "SELECT pg_catalog.binary_upgrade_set_next_index_relfilenode('%u'::pg_catalog.oid);\n",
    6015              :                               entry->toast_index_relfilenumber);
    6016              :         }
    6017              :     }
    6018              :     else
    6019              :     {
    6020              :         /* Preserve the OID and relfilenumber of the index */
    6021          333 :         appendPQExpBuffer(upgrade_buffer,
    6022              :                           "SELECT pg_catalog.binary_upgrade_set_next_index_pg_class_oid('%u'::pg_catalog.oid);\n",
    6023              :                           pg_class_oid);
    6024          333 :         appendPQExpBuffer(upgrade_buffer,
    6025              :                           "SELECT pg_catalog.binary_upgrade_set_next_index_relfilenode('%u'::pg_catalog.oid);\n",
    6026              :                           entry->relfilenumber);
    6027              :     }
    6028              : 
    6029         1358 :     appendPQExpBufferChar(upgrade_buffer, '\n');
    6030         1358 : }
    6031              : 
    6032              : /*
    6033              :  * If the DumpableObject is a member of an extension, add a suitable
    6034              :  * ALTER EXTENSION ADD command to the creation commands in upgrade_buffer.
    6035              :  *
    6036              :  * For somewhat historical reasons, objname should already be quoted,
    6037              :  * but not objnamespace (if any).
    6038              :  */
    6039              : static void
    6040         1596 : binary_upgrade_extension_member(PQExpBuffer upgrade_buffer,
    6041              :                                 const DumpableObject *dobj,
    6042              :                                 const char *objtype,
    6043              :                                 const char *objname,
    6044              :                                 const char *objnamespace)
    6045              : {
    6046         1596 :     DumpableObject *extobj = NULL;
    6047              :     int         i;
    6048              : 
    6049         1596 :     if (!dobj->ext_member)
    6050         1574 :         return;
    6051              : 
    6052              :     /*
    6053              :      * Find the parent extension.  We could avoid this search if we wanted to
    6054              :      * add a link field to DumpableObject, but the space costs of that would
    6055              :      * be considerable.  We assume that member objects could only have a
    6056              :      * direct dependency on their own extension, not any others.
    6057              :      */
    6058           22 :     for (i = 0; i < dobj->nDeps; i++)
    6059              :     {
    6060           22 :         extobj = findObjectByDumpId(dobj->dependencies[i]);
    6061           22 :         if (extobj && extobj->objType == DO_EXTENSION)
    6062           22 :             break;
    6063            0 :         extobj = NULL;
    6064              :     }
    6065           22 :     if (extobj == NULL)
    6066            0 :         pg_fatal("could not find parent extension for %s %s",
    6067              :                  objtype, objname);
    6068              : 
    6069           22 :     appendPQExpBufferStr(upgrade_buffer,
    6070              :                          "\n-- For binary upgrade, handle extension membership the hard way\n");
    6071           22 :     appendPQExpBuffer(upgrade_buffer, "ALTER EXTENSION %s ADD %s ",
    6072           22 :                       fmtId(extobj->name),
    6073              :                       objtype);
    6074           22 :     if (objnamespace && *objnamespace)
    6075           19 :         appendPQExpBuffer(upgrade_buffer, "%s.", fmtId(objnamespace));
    6076           22 :     appendPQExpBuffer(upgrade_buffer, "%s;\n", objname);
    6077              : }
    6078              : 
    6079              : /*
    6080              :  * getNamespaces:
    6081              :  *    get information about all namespaces in the system catalogs
    6082              :  */
    6083              : void
    6084          260 : getNamespaces(Archive *fout)
    6085              : {
    6086              :     PGresult   *res;
    6087              :     int         ntups;
    6088              :     int         i;
    6089              :     PQExpBuffer query;
    6090              :     NamespaceInfo *nsinfo;
    6091              :     int         i_tableoid;
    6092              :     int         i_oid;
    6093              :     int         i_nspname;
    6094              :     int         i_nspowner;
    6095              :     int         i_nspacl;
    6096              :     int         i_acldefault;
    6097              : 
    6098          260 :     query = createPQExpBuffer();
    6099              : 
    6100              :     /*
    6101              :      * we fetch all namespaces including system ones, so that every object we
    6102              :      * read in can be linked to a containing namespace.
    6103              :      */
    6104          260 :     appendPQExpBufferStr(query, "SELECT n.tableoid, n.oid, n.nspname, "
    6105              :                          "n.nspowner, "
    6106              :                          "n.nspacl, "
    6107              :                          "acldefault('n', n.nspowner) AS acldefault "
    6108              :                          "FROM pg_namespace n");
    6109              : 
    6110          260 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    6111              : 
    6112          260 :     ntups = PQntuples(res);
    6113              : 
    6114          260 :     nsinfo = pg_malloc_array(NamespaceInfo, ntups);
    6115              : 
    6116          260 :     i_tableoid = PQfnumber(res, "tableoid");
    6117          260 :     i_oid = PQfnumber(res, "oid");
    6118          260 :     i_nspname = PQfnumber(res, "nspname");
    6119          260 :     i_nspowner = PQfnumber(res, "nspowner");
    6120          260 :     i_nspacl = PQfnumber(res, "nspacl");
    6121          260 :     i_acldefault = PQfnumber(res, "acldefault");
    6122              : 
    6123         2027 :     for (i = 0; i < ntups; i++)
    6124              :     {
    6125              :         const char *nspowner;
    6126              : 
    6127         1767 :         nsinfo[i].dobj.objType = DO_NAMESPACE;
    6128         1767 :         nsinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    6129         1767 :         nsinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    6130         1767 :         AssignDumpId(&nsinfo[i].dobj);
    6131         1767 :         nsinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_nspname));
    6132         1767 :         nsinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_nspacl));
    6133         1767 :         nsinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
    6134         1767 :         nsinfo[i].dacl.privtype = 0;
    6135         1767 :         nsinfo[i].dacl.initprivs = NULL;
    6136         1767 :         nspowner = PQgetvalue(res, i, i_nspowner);
    6137         1767 :         nsinfo[i].nspowner = atooid(nspowner);
    6138         1767 :         nsinfo[i].rolname = getRoleName(nspowner);
    6139              : 
    6140              :         /* Decide whether to dump this namespace */
    6141         1767 :         selectDumpableNamespace(&nsinfo[i], fout);
    6142              : 
    6143              :         /* Mark whether namespace has an ACL */
    6144         1767 :         if (!PQgetisnull(res, i, i_nspacl))
    6145          879 :             nsinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
    6146              : 
    6147              :         /*
    6148              :          * We ignore any pg_init_privs.initprivs entry for the public schema
    6149              :          * and assume a predetermined default, for several reasons.  First,
    6150              :          * dropping and recreating the schema removes its pg_init_privs entry,
    6151              :          * but an empty destination database starts with this ACL nonetheless.
    6152              :          * Second, we support dump/reload of public schema ownership changes.
    6153              :          * ALTER SCHEMA OWNER filters nspacl through aclnewowner(), but
    6154              :          * initprivs continues to reflect the initial owner.  Hence,
    6155              :          * synthesize the value that nspacl will have after the restore's
    6156              :          * ALTER SCHEMA OWNER.  Third, this makes the destination database
    6157              :          * match the source's ACL, even if the latter was an initdb-default
    6158              :          * ACL, which changed in v15.  An upgrade pulls in changes to most
    6159              :          * system object ACLs that the DBA had not customized.  We've made the
    6160              :          * public schema depart from that, because changing its ACL so easily
    6161              :          * breaks applications.
    6162              :          */
    6163         1767 :         if (strcmp(nsinfo[i].dobj.name, "public") == 0)
    6164              :         {
    6165          256 :             PQExpBuffer aclarray = createPQExpBuffer();
    6166          256 :             PQExpBuffer aclitem = createPQExpBuffer();
    6167              : 
    6168              :             /* Standard ACL as of v15 is {owner=UC/owner,=U/owner} */
    6169          256 :             appendPQExpBufferChar(aclarray, '{');
    6170          256 :             quoteAclUserName(aclitem, nsinfo[i].rolname);
    6171          256 :             appendPQExpBufferStr(aclitem, "=UC/");
    6172          256 :             quoteAclUserName(aclitem, nsinfo[i].rolname);
    6173          256 :             appendPGArray(aclarray, aclitem->data);
    6174          256 :             resetPQExpBuffer(aclitem);
    6175          256 :             appendPQExpBufferStr(aclitem, "=U/");
    6176          256 :             quoteAclUserName(aclitem, nsinfo[i].rolname);
    6177          256 :             appendPGArray(aclarray, aclitem->data);
    6178          256 :             appendPQExpBufferChar(aclarray, '}');
    6179              : 
    6180          256 :             nsinfo[i].dacl.privtype = 'i';
    6181          256 :             nsinfo[i].dacl.initprivs = pstrdup(aclarray->data);
    6182          256 :             nsinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
    6183              : 
    6184          256 :             destroyPQExpBuffer(aclarray);
    6185          256 :             destroyPQExpBuffer(aclitem);
    6186              :         }
    6187              :     }
    6188              : 
    6189          260 :     PQclear(res);
    6190          260 :     destroyPQExpBuffer(query);
    6191          260 : }
    6192              : 
    6193              : /*
    6194              :  * findNamespace:
    6195              :  *      given a namespace OID, look up the info read by getNamespaces
    6196              :  */
    6197              : static NamespaceInfo *
    6198       841241 : findNamespace(Oid nsoid)
    6199              : {
    6200              :     NamespaceInfo *nsinfo;
    6201              : 
    6202       841241 :     nsinfo = findNamespaceByOid(nsoid);
    6203       841241 :     if (nsinfo == NULL)
    6204            0 :         pg_fatal("schema with OID %u does not exist", nsoid);
    6205       841241 :     return nsinfo;
    6206              : }
    6207              : 
    6208              : /*
    6209              :  * getExtensions:
    6210              :  *    read all extensions in the system catalogs and return them in the
    6211              :  * ExtensionInfo* structure
    6212              :  *
    6213              :  *  numExtensions is set to the number of extensions read in
    6214              :  */
    6215              : ExtensionInfo *
    6216          260 : getExtensions(Archive *fout, int *numExtensions)
    6217              : {
    6218          260 :     DumpOptions *dopt = fout->dopt;
    6219              :     PGresult   *res;
    6220              :     int         ntups;
    6221              :     int         i;
    6222              :     PQExpBuffer query;
    6223          260 :     ExtensionInfo *extinfo = NULL;
    6224              :     int         i_tableoid;
    6225              :     int         i_oid;
    6226              :     int         i_extname;
    6227              :     int         i_nspname;
    6228              :     int         i_extrelocatable;
    6229              :     int         i_extversion;
    6230              :     int         i_extconfig;
    6231              :     int         i_extcondition;
    6232              : 
    6233          260 :     query = createPQExpBuffer();
    6234              : 
    6235          260 :     appendPQExpBufferStr(query, "SELECT x.tableoid, x.oid, "
    6236              :                          "x.extname, n.nspname, x.extrelocatable, x.extversion, x.extconfig, x.extcondition "
    6237              :                          "FROM pg_extension x "
    6238              :                          "JOIN pg_namespace n ON n.oid = x.extnamespace");
    6239              : 
    6240          260 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    6241              : 
    6242          260 :     ntups = PQntuples(res);
    6243          260 :     if (ntups == 0)
    6244            0 :         goto cleanup;
    6245              : 
    6246          260 :     extinfo = pg_malloc_array(ExtensionInfo, ntups);
    6247              : 
    6248          260 :     i_tableoid = PQfnumber(res, "tableoid");
    6249          260 :     i_oid = PQfnumber(res, "oid");
    6250          260 :     i_extname = PQfnumber(res, "extname");
    6251          260 :     i_nspname = PQfnumber(res, "nspname");
    6252          260 :     i_extrelocatable = PQfnumber(res, "extrelocatable");
    6253          260 :     i_extversion = PQfnumber(res, "extversion");
    6254          260 :     i_extconfig = PQfnumber(res, "extconfig");
    6255          260 :     i_extcondition = PQfnumber(res, "extcondition");
    6256              : 
    6257          551 :     for (i = 0; i < ntups; i++)
    6258              :     {
    6259          291 :         extinfo[i].dobj.objType = DO_EXTENSION;
    6260          291 :         extinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    6261          291 :         extinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    6262          291 :         AssignDumpId(&extinfo[i].dobj);
    6263          291 :         extinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_extname));
    6264          291 :         extinfo[i].namespace = pg_strdup(PQgetvalue(res, i, i_nspname));
    6265          291 :         extinfo[i].relocatable = *(PQgetvalue(res, i, i_extrelocatable)) == 't';
    6266          291 :         extinfo[i].extversion = pg_strdup(PQgetvalue(res, i, i_extversion));
    6267          291 :         extinfo[i].extconfig = pg_strdup(PQgetvalue(res, i, i_extconfig));
    6268          291 :         extinfo[i].extcondition = pg_strdup(PQgetvalue(res, i, i_extcondition));
    6269              : 
    6270              :         /* Decide whether we want to dump it */
    6271          291 :         selectDumpableExtension(&(extinfo[i]), dopt);
    6272              :     }
    6273              : 
    6274          260 : cleanup:
    6275          260 :     PQclear(res);
    6276          260 :     destroyPQExpBuffer(query);
    6277              : 
    6278          260 :     *numExtensions = ntups;
    6279              : 
    6280          260 :     return extinfo;
    6281              : }
    6282              : 
    6283              : /*
    6284              :  * getTypes:
    6285              :  *    get information about all types in the system catalogs
    6286              :  *
    6287              :  * NB: this must run after getFuncs() because we assume we can do
    6288              :  * findFuncByOid().
    6289              :  */
    6290              : void
    6291          259 : getTypes(Archive *fout)
    6292              : {
    6293              :     PGresult   *res;
    6294              :     int         ntups;
    6295              :     int         i;
    6296          259 :     PQExpBuffer query = createPQExpBuffer();
    6297              :     TypeInfo   *tyinfo;
    6298              :     ShellTypeInfo *stinfo;
    6299              :     int         i_tableoid;
    6300              :     int         i_oid;
    6301              :     int         i_typname;
    6302              :     int         i_typnamespace;
    6303              :     int         i_typacl;
    6304              :     int         i_acldefault;
    6305              :     int         i_typowner;
    6306              :     int         i_typelem;
    6307              :     int         i_typrelid;
    6308              :     int         i_typrelkind;
    6309              :     int         i_typtype;
    6310              :     int         i_typisdefined;
    6311              :     int         i_isarray;
    6312              :     int         i_typarray;
    6313              : 
    6314              :     /*
    6315              :      * we include even the built-in types because those may be used as array
    6316              :      * elements by user-defined types
    6317              :      *
    6318              :      * we filter out the built-in types when we dump out the types
    6319              :      *
    6320              :      * same approach for undefined (shell) types and array types
    6321              :      *
    6322              :      * Note: as of 8.3 we can reliably detect whether a type is an
    6323              :      * auto-generated array type by checking the element type's typarray.
    6324              :      * (Before that the test is capable of generating false positives.) We
    6325              :      * still check for name beginning with '_', though, so as to avoid the
    6326              :      * cost of the subselect probe for all standard types.  This would have to
    6327              :      * be revisited if the backend ever allows renaming of array types.
    6328              :      */
    6329          259 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, typname, "
    6330              :                          "typnamespace, typacl, "
    6331              :                          "acldefault('T', typowner) AS acldefault, "
    6332              :                          "typowner, "
    6333              :                          "typelem, typrelid, typarray, "
    6334              :                          "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
    6335              :                          "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
    6336              :                          "typtype, typisdefined, "
    6337              :                          "typname[0] = '_' AND typelem != 0 AND "
    6338              :                          "(SELECT typarray FROM pg_type te WHERE oid = pg_type.typelem) = oid AS isarray "
    6339              :                          "FROM pg_type");
    6340              : 
    6341          259 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    6342              : 
    6343          259 :     ntups = PQntuples(res);
    6344              : 
    6345          259 :     tyinfo = pg_malloc_array(TypeInfo, ntups);
    6346              : 
    6347          259 :     i_tableoid = PQfnumber(res, "tableoid");
    6348          259 :     i_oid = PQfnumber(res, "oid");
    6349          259 :     i_typname = PQfnumber(res, "typname");
    6350          259 :     i_typnamespace = PQfnumber(res, "typnamespace");
    6351          259 :     i_typacl = PQfnumber(res, "typacl");
    6352          259 :     i_acldefault = PQfnumber(res, "acldefault");
    6353          259 :     i_typowner = PQfnumber(res, "typowner");
    6354          259 :     i_typelem = PQfnumber(res, "typelem");
    6355          259 :     i_typrelid = PQfnumber(res, "typrelid");
    6356          259 :     i_typrelkind = PQfnumber(res, "typrelkind");
    6357          259 :     i_typtype = PQfnumber(res, "typtype");
    6358          259 :     i_typisdefined = PQfnumber(res, "typisdefined");
    6359          259 :     i_isarray = PQfnumber(res, "isarray");
    6360          259 :     i_typarray = PQfnumber(res, "typarray");
    6361              : 
    6362       191742 :     for (i = 0; i < ntups; i++)
    6363              :     {
    6364       191483 :         tyinfo[i].dobj.objType = DO_TYPE;
    6365       191483 :         tyinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    6366       191483 :         tyinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    6367       191483 :         AssignDumpId(&tyinfo[i].dobj);
    6368       191483 :         tyinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_typname));
    6369       382966 :         tyinfo[i].dobj.namespace =
    6370       191483 :             findNamespace(atooid(PQgetvalue(res, i, i_typnamespace)));
    6371       191483 :         tyinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_typacl));
    6372       191483 :         tyinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
    6373       191483 :         tyinfo[i].dacl.privtype = 0;
    6374       191483 :         tyinfo[i].dacl.initprivs = NULL;
    6375       191483 :         tyinfo[i].ftypname = NULL;  /* may get filled later */
    6376       191483 :         tyinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_typowner));
    6377       191483 :         tyinfo[i].typelem = atooid(PQgetvalue(res, i, i_typelem));
    6378       191483 :         tyinfo[i].typrelid = atooid(PQgetvalue(res, i, i_typrelid));
    6379       191483 :         tyinfo[i].typrelkind = *PQgetvalue(res, i, i_typrelkind);
    6380       191483 :         tyinfo[i].typtype = *PQgetvalue(res, i, i_typtype);
    6381       191483 :         tyinfo[i].shellType = NULL;
    6382              : 
    6383       191483 :         if (strcmp(PQgetvalue(res, i, i_typisdefined), "t") == 0)
    6384       191431 :             tyinfo[i].isDefined = true;
    6385              :         else
    6386           52 :             tyinfo[i].isDefined = false;
    6387              : 
    6388       191483 :         if (strcmp(PQgetvalue(res, i, i_isarray), "t") == 0)
    6389        91960 :             tyinfo[i].isArray = true;
    6390              :         else
    6391        99523 :             tyinfo[i].isArray = false;
    6392              : 
    6393       191483 :         tyinfo[i].typarray = atooid(PQgetvalue(res, i, i_typarray));
    6394              : 
    6395       191483 :         if (tyinfo[i].typtype == TYPTYPE_MULTIRANGE)
    6396         1686 :             tyinfo[i].isMultirange = true;
    6397              :         else
    6398       189797 :             tyinfo[i].isMultirange = false;
    6399              : 
    6400              :         /* Decide whether we want to dump it */
    6401       191483 :         selectDumpableType(&tyinfo[i], fout);
    6402              : 
    6403              :         /* Mark whether type has an ACL */
    6404       191483 :         if (!PQgetisnull(res, i, i_typacl))
    6405          205 :             tyinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
    6406              : 
    6407              :         /*
    6408              :          * If it's a domain, fetch info about its constraints, if any
    6409              :          */
    6410       191483 :         tyinfo[i].nDomChecks = 0;
    6411       191483 :         tyinfo[i].domChecks = NULL;
    6412       191483 :         tyinfo[i].notnull = NULL;
    6413       191483 :         if ((tyinfo[i].dobj.dump & DUMP_COMPONENT_DEFINITION) &&
    6414        16275 :             tyinfo[i].typtype == TYPTYPE_DOMAIN)
    6415          158 :             getDomainConstraints(fout, &(tyinfo[i]));
    6416              : 
    6417              :         /*
    6418              :          * If it's a base type, make a DumpableObject representing a shell
    6419              :          * definition of the type.  We will need to dump that ahead of the I/O
    6420              :          * functions for the type.  Similarly, range types need a shell
    6421              :          * definition in case they have a canonicalize function.
    6422              :          *
    6423              :          * Note: the shell type doesn't have a catId.  You might think it
    6424              :          * should copy the base type's catId, but then it might capture the
    6425              :          * pg_depend entries for the type, which we don't want.
    6426              :          */
    6427       191483 :         if ((tyinfo[i].dobj.dump & DUMP_COMPONENT_DEFINITION) &&
    6428        16275 :             (tyinfo[i].typtype == TYPTYPE_BASE ||
    6429         7921 :              tyinfo[i].typtype == TYPTYPE_RANGE))
    6430              :         {
    6431         8478 :             stinfo = pg_malloc_object(ShellTypeInfo);
    6432         8478 :             stinfo->dobj.objType = DO_SHELL_TYPE;
    6433         8478 :             stinfo->dobj.catId = nilCatalogId;
    6434         8478 :             AssignDumpId(&stinfo->dobj);
    6435         8478 :             stinfo->dobj.name = pg_strdup(tyinfo[i].dobj.name);
    6436         8478 :             stinfo->dobj.namespace = tyinfo[i].dobj.namespace;
    6437         8478 :             stinfo->baseType = &(tyinfo[i]);
    6438         8478 :             tyinfo[i].shellType = stinfo;
    6439              : 
    6440              :             /*
    6441              :              * Initially mark the shell type as not to be dumped.  We'll only
    6442              :              * dump it if the I/O or canonicalize functions need to be dumped;
    6443              :              * this is taken care of while sorting dependencies.
    6444              :              */
    6445         8478 :             stinfo->dobj.dump = DUMP_COMPONENT_NONE;
    6446              :         }
    6447              :     }
    6448              : 
    6449          259 :     PQclear(res);
    6450              : 
    6451          259 :     destroyPQExpBuffer(query);
    6452          259 : }
    6453              : 
    6454              : /*
    6455              :  * getOperators:
    6456              :  *    get information about all operators in the system catalogs
    6457              :  */
    6458              : void
    6459          259 : getOperators(Archive *fout)
    6460              : {
    6461              :     PGresult   *res;
    6462              :     int         ntups;
    6463              :     int         i;
    6464          259 :     PQExpBuffer query = createPQExpBuffer();
    6465              :     OprInfo    *oprinfo;
    6466              :     int         i_tableoid;
    6467              :     int         i_oid;
    6468              :     int         i_oprname;
    6469              :     int         i_oprnamespace;
    6470              :     int         i_oprowner;
    6471              :     int         i_oprkind;
    6472              :     int         i_oprleft;
    6473              :     int         i_oprright;
    6474              :     int         i_oprcode;
    6475              : 
    6476              :     /*
    6477              :      * find all operators, including builtin operators; we filter out
    6478              :      * system-defined operators at dump-out time.
    6479              :      */
    6480              : 
    6481          259 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, oprname, "
    6482              :                          "oprnamespace, "
    6483              :                          "oprowner, "
    6484              :                          "oprkind, "
    6485              :                          "oprleft, "
    6486              :                          "oprright, "
    6487              :                          "oprcode::oid AS oprcode "
    6488              :                          "FROM pg_operator");
    6489              : 
    6490          259 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    6491              : 
    6492          259 :     ntups = PQntuples(res);
    6493              : 
    6494          259 :     oprinfo = pg_malloc_array(OprInfo, ntups);
    6495              : 
    6496          259 :     i_tableoid = PQfnumber(res, "tableoid");
    6497          259 :     i_oid = PQfnumber(res, "oid");
    6498          259 :     i_oprname = PQfnumber(res, "oprname");
    6499          259 :     i_oprnamespace = PQfnumber(res, "oprnamespace");
    6500          259 :     i_oprowner = PQfnumber(res, "oprowner");
    6501          259 :     i_oprkind = PQfnumber(res, "oprkind");
    6502          259 :     i_oprleft = PQfnumber(res, "oprleft");
    6503          259 :     i_oprright = PQfnumber(res, "oprright");
    6504          259 :     i_oprcode = PQfnumber(res, "oprcode");
    6505              : 
    6506       208896 :     for (i = 0; i < ntups; i++)
    6507              :     {
    6508       208637 :         oprinfo[i].dobj.objType = DO_OPERATOR;
    6509       208637 :         oprinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    6510       208637 :         oprinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    6511       208637 :         AssignDumpId(&oprinfo[i].dobj);
    6512       208637 :         oprinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_oprname));
    6513       417274 :         oprinfo[i].dobj.namespace =
    6514       208637 :             findNamespace(atooid(PQgetvalue(res, i, i_oprnamespace)));
    6515       208637 :         oprinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_oprowner));
    6516       208637 :         oprinfo[i].oprkind = (PQgetvalue(res, i, i_oprkind))[0];
    6517       208637 :         oprinfo[i].oprleft = atooid(PQgetvalue(res, i, i_oprleft));
    6518       208637 :         oprinfo[i].oprright = atooid(PQgetvalue(res, i, i_oprright));
    6519       208637 :         oprinfo[i].oprcode = atooid(PQgetvalue(res, i, i_oprcode));
    6520              : 
    6521              :         /* Decide whether we want to dump it */
    6522       208637 :         selectDumpableObject(&(oprinfo[i].dobj), fout);
    6523              :     }
    6524              : 
    6525          259 :     PQclear(res);
    6526              : 
    6527          259 :     destroyPQExpBuffer(query);
    6528          259 : }
    6529              : 
    6530              : /*
    6531              :  * getCollations:
    6532              :  *    get information about all collations in the system catalogs
    6533              :  */
    6534              : void
    6535          259 : getCollations(Archive *fout)
    6536              : {
    6537              :     PGresult   *res;
    6538              :     int         ntups;
    6539              :     int         i;
    6540              :     PQExpBuffer query;
    6541              :     CollInfo   *collinfo;
    6542              :     int         i_tableoid;
    6543              :     int         i_oid;
    6544              :     int         i_collname;
    6545              :     int         i_collnamespace;
    6546              :     int         i_collowner;
    6547              :     int         i_collencoding;
    6548              : 
    6549          259 :     query = createPQExpBuffer();
    6550              : 
    6551              :     /*
    6552              :      * find all collations, including builtin collations; we filter out
    6553              :      * system-defined collations at dump-out time.
    6554              :      */
    6555              : 
    6556          259 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, collname, "
    6557              :                          "collnamespace, "
    6558              :                          "collowner, "
    6559              :                          "collencoding "
    6560              :                          "FROM pg_collation");
    6561              : 
    6562          259 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    6563              : 
    6564          259 :     ntups = PQntuples(res);
    6565              : 
    6566          259 :     collinfo = pg_malloc_array(CollInfo, ntups);
    6567              : 
    6568          259 :     i_tableoid = PQfnumber(res, "tableoid");
    6569          259 :     i_oid = PQfnumber(res, "oid");
    6570          259 :     i_collname = PQfnumber(res, "collname");
    6571          259 :     i_collnamespace = PQfnumber(res, "collnamespace");
    6572          259 :     i_collowner = PQfnumber(res, "collowner");
    6573          259 :     i_collencoding = PQfnumber(res, "collencoding");
    6574              : 
    6575       228290 :     for (i = 0; i < ntups; i++)
    6576              :     {
    6577       228031 :         collinfo[i].dobj.objType = DO_COLLATION;
    6578       228031 :         collinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    6579       228031 :         collinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    6580       228031 :         AssignDumpId(&collinfo[i].dobj);
    6581       228031 :         collinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_collname));
    6582       456062 :         collinfo[i].dobj.namespace =
    6583       228031 :             findNamespace(atooid(PQgetvalue(res, i, i_collnamespace)));
    6584       228031 :         collinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_collowner));
    6585       228031 :         collinfo[i].collencoding = atoi(PQgetvalue(res, i, i_collencoding));
    6586              : 
    6587              :         /* Decide whether we want to dump it */
    6588       228031 :         selectDumpableObject(&(collinfo[i].dobj), fout);
    6589              :     }
    6590              : 
    6591          259 :     PQclear(res);
    6592              : 
    6593          259 :     destroyPQExpBuffer(query);
    6594          259 : }
    6595              : 
    6596              : /*
    6597              :  * getConversions:
    6598              :  *    get information about all conversions in the system catalogs
    6599              :  */
    6600              : void
    6601          259 : getConversions(Archive *fout)
    6602              : {
    6603              :     PGresult   *res;
    6604              :     int         ntups;
    6605              :     int         i;
    6606              :     PQExpBuffer query;
    6607              :     ConvInfo   *convinfo;
    6608              :     int         i_tableoid;
    6609              :     int         i_oid;
    6610              :     int         i_conname;
    6611              :     int         i_connamespace;
    6612              :     int         i_conowner;
    6613              : 
    6614          259 :     query = createPQExpBuffer();
    6615              : 
    6616              :     /*
    6617              :      * find all conversions, including builtin conversions; we filter out
    6618              :      * system-defined conversions at dump-out time.
    6619              :      */
    6620              : 
    6621          259 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, conname, "
    6622              :                          "connamespace, "
    6623              :                          "conowner "
    6624              :                          "FROM pg_conversion");
    6625              : 
    6626          259 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    6627              : 
    6628          259 :     ntups = PQntuples(res);
    6629              : 
    6630          259 :     convinfo = pg_malloc_array(ConvInfo, ntups);
    6631              : 
    6632          259 :     i_tableoid = PQfnumber(res, "tableoid");
    6633          259 :     i_oid = PQfnumber(res, "oid");
    6634          259 :     i_conname = PQfnumber(res, "conname");
    6635          259 :     i_connamespace = PQfnumber(res, "connamespace");
    6636          259 :     i_conowner = PQfnumber(res, "conowner");
    6637              : 
    6638        33456 :     for (i = 0; i < ntups; i++)
    6639              :     {
    6640        33197 :         convinfo[i].dobj.objType = DO_CONVERSION;
    6641        33197 :         convinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    6642        33197 :         convinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    6643        33197 :         AssignDumpId(&convinfo[i].dobj);
    6644        33197 :         convinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_conname));
    6645        66394 :         convinfo[i].dobj.namespace =
    6646        33197 :             findNamespace(atooid(PQgetvalue(res, i, i_connamespace)));
    6647        33197 :         convinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_conowner));
    6648              : 
    6649              :         /* Decide whether we want to dump it */
    6650        33197 :         selectDumpableObject(&(convinfo[i].dobj), fout);
    6651              :     }
    6652              : 
    6653          259 :     PQclear(res);
    6654              : 
    6655          259 :     destroyPQExpBuffer(query);
    6656          259 : }
    6657              : 
    6658              : /*
    6659              :  * getAccessMethods:
    6660              :  *    get information about all user-defined access methods
    6661              :  */
    6662              : void
    6663          259 : getAccessMethods(Archive *fout)
    6664              : {
    6665              :     PGresult   *res;
    6666              :     int         ntups;
    6667              :     int         i;
    6668              :     PQExpBuffer query;
    6669              :     AccessMethodInfo *aminfo;
    6670              :     int         i_tableoid;
    6671              :     int         i_oid;
    6672              :     int         i_amname;
    6673              :     int         i_amhandler;
    6674              :     int         i_amtype;
    6675              : 
    6676          259 :     query = createPQExpBuffer();
    6677              : 
    6678              :     /*
    6679              :      * Select all access methods from pg_am table.  v9.6 introduced CREATE
    6680              :      * ACCESS METHOD, so earlier versions usually have only built-in access
    6681              :      * methods.  v9.6 also changed the access method API, replacing dozens of
    6682              :      * pg_am columns with amhandler.  Even if a user created an access method
    6683              :      * by "INSERT INTO pg_am", we have no way to translate pre-v9.6 pg_am
    6684              :      * columns to a v9.6+ CREATE ACCESS METHOD.  Hence, before v9.6, read
    6685              :      * pg_am just to facilitate findAccessMethodByOid() providing the
    6686              :      * OID-to-name mapping.
    6687              :      */
    6688          259 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, amname, ");
    6689          259 :     if (fout->remoteVersion >= 90600)
    6690          259 :         appendPQExpBufferStr(query,
    6691              :                              "amtype, "
    6692              :                              "amhandler::pg_catalog.regproc AS amhandler ");
    6693              :     else
    6694            0 :         appendPQExpBufferStr(query,
    6695              :                              "'i'::pg_catalog.\"char\" AS amtype, "
    6696              :                              "'-'::pg_catalog.regproc AS amhandler ");
    6697          259 :     appendPQExpBufferStr(query, "FROM pg_am");
    6698              : 
    6699          259 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    6700              : 
    6701          259 :     ntups = PQntuples(res);
    6702              : 
    6703          259 :     aminfo = pg_malloc_array(AccessMethodInfo, ntups);
    6704              : 
    6705          259 :     i_tableoid = PQfnumber(res, "tableoid");
    6706          259 :     i_oid = PQfnumber(res, "oid");
    6707          259 :     i_amname = PQfnumber(res, "amname");
    6708          259 :     i_amhandler = PQfnumber(res, "amhandler");
    6709          259 :     i_amtype = PQfnumber(res, "amtype");
    6710              : 
    6711         2194 :     for (i = 0; i < ntups; i++)
    6712              :     {
    6713         1935 :         aminfo[i].dobj.objType = DO_ACCESS_METHOD;
    6714         1935 :         aminfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    6715         1935 :         aminfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    6716         1935 :         AssignDumpId(&aminfo[i].dobj);
    6717         1935 :         aminfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_amname));
    6718         1935 :         aminfo[i].dobj.namespace = NULL;
    6719         1935 :         aminfo[i].amhandler = pg_strdup(PQgetvalue(res, i, i_amhandler));
    6720         1935 :         aminfo[i].amtype = *(PQgetvalue(res, i, i_amtype));
    6721              : 
    6722              :         /* Decide whether we want to dump it */
    6723         1935 :         selectDumpableAccessMethod(&(aminfo[i]), fout);
    6724              :     }
    6725              : 
    6726          259 :     PQclear(res);
    6727              : 
    6728          259 :     destroyPQExpBuffer(query);
    6729          259 : }
    6730              : 
    6731              : 
    6732              : /*
    6733              :  * getOpclasses:
    6734              :  *    get information about all opclasses in the system catalogs
    6735              :  */
    6736              : void
    6737          259 : getOpclasses(Archive *fout)
    6738              : {
    6739              :     PGresult   *res;
    6740              :     int         ntups;
    6741              :     int         i;
    6742          259 :     PQExpBuffer query = createPQExpBuffer();
    6743              :     OpclassInfo *opcinfo;
    6744              :     int         i_tableoid;
    6745              :     int         i_oid;
    6746              :     int         i_opcmethod;
    6747              :     int         i_opcname;
    6748              :     int         i_opcnamespace;
    6749              :     int         i_opcowner;
    6750              : 
    6751              :     /*
    6752              :      * find all opclasses, including builtin opclasses; we filter out
    6753              :      * system-defined opclasses at dump-out time.
    6754              :      */
    6755              : 
    6756          259 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, opcmethod, opcname, "
    6757              :                          "opcnamespace, "
    6758              :                          "opcowner "
    6759              :                          "FROM pg_opclass");
    6760              : 
    6761          259 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    6762              : 
    6763          259 :     ntups = PQntuples(res);
    6764              : 
    6765          259 :     opcinfo = pg_malloc_array(OpclassInfo, ntups);
    6766              : 
    6767          259 :     i_tableoid = PQfnumber(res, "tableoid");
    6768          259 :     i_oid = PQfnumber(res, "oid");
    6769          259 :     i_opcmethod = PQfnumber(res, "opcmethod");
    6770          259 :     i_opcname = PQfnumber(res, "opcname");
    6771          259 :     i_opcnamespace = PQfnumber(res, "opcnamespace");
    6772          259 :     i_opcowner = PQfnumber(res, "opcowner");
    6773              : 
    6774        46776 :     for (i = 0; i < ntups; i++)
    6775              :     {
    6776        46517 :         opcinfo[i].dobj.objType = DO_OPCLASS;
    6777        46517 :         opcinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    6778        46517 :         opcinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    6779        46517 :         AssignDumpId(&opcinfo[i].dobj);
    6780        46517 :         opcinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_opcname));
    6781        93034 :         opcinfo[i].dobj.namespace =
    6782        46517 :             findNamespace(atooid(PQgetvalue(res, i, i_opcnamespace)));
    6783        46517 :         opcinfo[i].opcmethod = atooid(PQgetvalue(res, i, i_opcmethod));
    6784        46517 :         opcinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_opcowner));
    6785              : 
    6786              :         /* Decide whether we want to dump it */
    6787        46517 :         selectDumpableObject(&(opcinfo[i].dobj), fout);
    6788              :     }
    6789              : 
    6790          259 :     PQclear(res);
    6791              : 
    6792          259 :     destroyPQExpBuffer(query);
    6793          259 : }
    6794              : 
    6795              : /*
    6796              :  * getOpfamilies:
    6797              :  *    get information about all opfamilies in the system catalogs
    6798              :  */
    6799              : void
    6800          259 : getOpfamilies(Archive *fout)
    6801              : {
    6802              :     PGresult   *res;
    6803              :     int         ntups;
    6804              :     int         i;
    6805              :     PQExpBuffer query;
    6806              :     OpfamilyInfo *opfinfo;
    6807              :     int         i_tableoid;
    6808              :     int         i_oid;
    6809              :     int         i_opfmethod;
    6810              :     int         i_opfname;
    6811              :     int         i_opfnamespace;
    6812              :     int         i_opfowner;
    6813              : 
    6814          259 :     query = createPQExpBuffer();
    6815              : 
    6816              :     /*
    6817              :      * find all opfamilies, including builtin opfamilies; we filter out
    6818              :      * system-defined opfamilies at dump-out time.
    6819              :      */
    6820              : 
    6821          259 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, opfmethod, opfname, "
    6822              :                          "opfnamespace, "
    6823              :                          "opfowner "
    6824              :                          "FROM pg_opfamily");
    6825              : 
    6826          259 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    6827              : 
    6828          259 :     ntups = PQntuples(res);
    6829              : 
    6830          259 :     opfinfo = pg_malloc_array(OpfamilyInfo, ntups);
    6831              : 
    6832          259 :     i_tableoid = PQfnumber(res, "tableoid");
    6833          259 :     i_oid = PQfnumber(res, "oid");
    6834          259 :     i_opfname = PQfnumber(res, "opfname");
    6835          259 :     i_opfmethod = PQfnumber(res, "opfmethod");
    6836          259 :     i_opfnamespace = PQfnumber(res, "opfnamespace");
    6837          259 :     i_opfowner = PQfnumber(res, "opfowner");
    6838              : 
    6839        38730 :     for (i = 0; i < ntups; i++)
    6840              :     {
    6841        38471 :         opfinfo[i].dobj.objType = DO_OPFAMILY;
    6842        38471 :         opfinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    6843        38471 :         opfinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    6844        38471 :         AssignDumpId(&opfinfo[i].dobj);
    6845        38471 :         opfinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_opfname));
    6846        76942 :         opfinfo[i].dobj.namespace =
    6847        38471 :             findNamespace(atooid(PQgetvalue(res, i, i_opfnamespace)));
    6848        38471 :         opfinfo[i].opfmethod = atooid(PQgetvalue(res, i, i_opfmethod));
    6849        38471 :         opfinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_opfowner));
    6850              : 
    6851              :         /* Decide whether we want to dump it */
    6852        38471 :         selectDumpableObject(&(opfinfo[i].dobj), fout);
    6853              :     }
    6854              : 
    6855          259 :     PQclear(res);
    6856              : 
    6857          259 :     destroyPQExpBuffer(query);
    6858          259 : }
    6859              : 
    6860              : /*
    6861              :  * getAggregates:
    6862              :  *    get information about all user-defined aggregates in the system catalogs
    6863              :  */
    6864              : void
    6865          259 : getAggregates(Archive *fout)
    6866              : {
    6867          259 :     DumpOptions *dopt = fout->dopt;
    6868              :     PGresult   *res;
    6869              :     int         ntups;
    6870              :     int         i;
    6871          259 :     PQExpBuffer query = createPQExpBuffer();
    6872              :     AggInfo    *agginfo;
    6873              :     int         i_tableoid;
    6874              :     int         i_oid;
    6875              :     int         i_aggname;
    6876              :     int         i_aggnamespace;
    6877              :     int         i_pronargs;
    6878              :     int         i_proargtypes;
    6879              :     int         i_proowner;
    6880              :     int         i_aggacl;
    6881              :     int         i_acldefault;
    6882              : 
    6883              :     /*
    6884              :      * Find all interesting aggregates.  See comment in getFuncs() for the
    6885              :      * rationale behind the filtering logic.
    6886              :      */
    6887          259 :     if (fout->remoteVersion >= 90600)
    6888              :     {
    6889              :         const char *agg_check;
    6890              : 
    6891          518 :         agg_check = (fout->remoteVersion >= 110000 ? "p.prokind = 'a'"
    6892          259 :                      : "p.proisagg");
    6893              : 
    6894          259 :         appendPQExpBuffer(query, "SELECT p.tableoid, p.oid, "
    6895              :                           "p.proname AS aggname, "
    6896              :                           "p.pronamespace AS aggnamespace, "
    6897              :                           "p.pronargs, p.proargtypes, "
    6898              :                           "p.proowner, "
    6899              :                           "p.proacl AS aggacl, "
    6900              :                           "acldefault('f', p.proowner) AS acldefault "
    6901              :                           "FROM pg_proc p "
    6902              :                           "LEFT JOIN pg_init_privs pip ON "
    6903              :                           "(p.oid = pip.objoid "
    6904              :                           "AND pip.classoid = 'pg_proc'::regclass "
    6905              :                           "AND pip.objsubid = 0) "
    6906              :                           "WHERE %s AND ("
    6907              :                           "p.pronamespace != "
    6908              :                           "(SELECT oid FROM pg_namespace "
    6909              :                           "WHERE nspname = 'pg_catalog') OR "
    6910              :                           "p.proacl IS DISTINCT FROM pip.initprivs",
    6911              :                           agg_check);
    6912          259 :         if (dopt->binary_upgrade)
    6913           40 :             appendPQExpBufferStr(query,
    6914              :                                  " OR EXISTS(SELECT 1 FROM pg_depend WHERE "
    6915              :                                  "classid = 'pg_proc'::regclass AND "
    6916              :                                  "objid = p.oid AND "
    6917              :                                  "refclassid = 'pg_extension'::regclass AND "
    6918              :                                  "deptype = 'e')");
    6919          259 :         appendPQExpBufferChar(query, ')');
    6920              :     }
    6921              :     else
    6922              :     {
    6923            0 :         appendPQExpBufferStr(query, "SELECT tableoid, oid, proname AS aggname, "
    6924              :                              "pronamespace AS aggnamespace, "
    6925              :                              "pronargs, proargtypes, "
    6926              :                              "proowner, "
    6927              :                              "proacl AS aggacl, "
    6928              :                              "acldefault('f', proowner) AS acldefault "
    6929              :                              "FROM pg_proc p "
    6930              :                              "WHERE proisagg AND ("
    6931              :                              "pronamespace != "
    6932              :                              "(SELECT oid FROM pg_namespace "
    6933              :                              "WHERE nspname = 'pg_catalog')");
    6934            0 :         if (dopt->binary_upgrade)
    6935            0 :             appendPQExpBufferStr(query,
    6936              :                                  " OR EXISTS(SELECT 1 FROM pg_depend WHERE "
    6937              :                                  "classid = 'pg_proc'::regclass AND "
    6938              :                                  "objid = p.oid AND "
    6939              :                                  "refclassid = 'pg_extension'::regclass AND "
    6940              :                                  "deptype = 'e')");
    6941            0 :         appendPQExpBufferChar(query, ')');
    6942              :     }
    6943              : 
    6944          259 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    6945              : 
    6946          259 :     ntups = PQntuples(res);
    6947              : 
    6948          259 :     agginfo = pg_malloc_array(AggInfo, ntups);
    6949              : 
    6950          259 :     i_tableoid = PQfnumber(res, "tableoid");
    6951          259 :     i_oid = PQfnumber(res, "oid");
    6952          259 :     i_aggname = PQfnumber(res, "aggname");
    6953          259 :     i_aggnamespace = PQfnumber(res, "aggnamespace");
    6954          259 :     i_pronargs = PQfnumber(res, "pronargs");
    6955          259 :     i_proargtypes = PQfnumber(res, "proargtypes");
    6956          259 :     i_proowner = PQfnumber(res, "proowner");
    6957          259 :     i_aggacl = PQfnumber(res, "aggacl");
    6958          259 :     i_acldefault = PQfnumber(res, "acldefault");
    6959              : 
    6960          658 :     for (i = 0; i < ntups; i++)
    6961              :     {
    6962          399 :         agginfo[i].aggfn.dobj.objType = DO_AGG;
    6963          399 :         agginfo[i].aggfn.dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    6964          399 :         agginfo[i].aggfn.dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    6965          399 :         AssignDumpId(&agginfo[i].aggfn.dobj);
    6966          399 :         agginfo[i].aggfn.dobj.name = pg_strdup(PQgetvalue(res, i, i_aggname));
    6967          798 :         agginfo[i].aggfn.dobj.namespace =
    6968          399 :             findNamespace(atooid(PQgetvalue(res, i, i_aggnamespace)));
    6969          399 :         agginfo[i].aggfn.dacl.acl = pg_strdup(PQgetvalue(res, i, i_aggacl));
    6970          399 :         agginfo[i].aggfn.dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
    6971          399 :         agginfo[i].aggfn.dacl.privtype = 0;
    6972          399 :         agginfo[i].aggfn.dacl.initprivs = NULL;
    6973          399 :         agginfo[i].aggfn.rolname = getRoleName(PQgetvalue(res, i, i_proowner));
    6974          399 :         agginfo[i].aggfn.lang = InvalidOid; /* not currently interesting */
    6975          399 :         agginfo[i].aggfn.prorettype = InvalidOid;   /* not saved */
    6976          399 :         agginfo[i].aggfn.nargs = atoi(PQgetvalue(res, i, i_pronargs));
    6977          399 :         if (agginfo[i].aggfn.nargs == 0)
    6978           56 :             agginfo[i].aggfn.argtypes = NULL;
    6979              :         else
    6980              :         {
    6981          343 :             agginfo[i].aggfn.argtypes = pg_malloc_array(Oid, agginfo[i].aggfn.nargs);
    6982          343 :             parseOidArray(PQgetvalue(res, i, i_proargtypes),
    6983          343 :                           agginfo[i].aggfn.argtypes,
    6984          343 :                           agginfo[i].aggfn.nargs);
    6985              :         }
    6986          399 :         agginfo[i].aggfn.postponed_def = false; /* might get set during sort */
    6987              : 
    6988              :         /* Decide whether we want to dump it */
    6989          399 :         selectDumpableObject(&(agginfo[i].aggfn.dobj), fout);
    6990              : 
    6991              :         /* Mark whether aggregate has an ACL */
    6992          399 :         if (!PQgetisnull(res, i, i_aggacl))
    6993           25 :             agginfo[i].aggfn.dobj.components |= DUMP_COMPONENT_ACL;
    6994              :     }
    6995              : 
    6996          259 :     PQclear(res);
    6997              : 
    6998          259 :     destroyPQExpBuffer(query);
    6999          259 : }
    7000              : 
    7001              : /*
    7002              :  * getFuncs:
    7003              :  *    get information about all user-defined functions in the system catalogs
    7004              :  */
    7005              : void
    7006          259 : getFuncs(Archive *fout)
    7007              : {
    7008          259 :     DumpOptions *dopt = fout->dopt;
    7009              :     PGresult   *res;
    7010              :     int         ntups;
    7011              :     int         i;
    7012          259 :     PQExpBuffer query = createPQExpBuffer();
    7013              :     FuncInfo   *finfo;
    7014              :     int         i_tableoid;
    7015              :     int         i_oid;
    7016              :     int         i_proname;
    7017              :     int         i_pronamespace;
    7018              :     int         i_proowner;
    7019              :     int         i_prolang;
    7020              :     int         i_pronargs;
    7021              :     int         i_proargtypes;
    7022              :     int         i_prorettype;
    7023              :     int         i_proacl;
    7024              :     int         i_acldefault;
    7025              : 
    7026              :     /*
    7027              :      * Find all interesting functions.  This is a bit complicated:
    7028              :      *
    7029              :      * 1. Always exclude aggregates; those are handled elsewhere.
    7030              :      *
    7031              :      * 2. Always exclude functions that are internally dependent on something
    7032              :      * else, since presumably those will be created as a result of creating
    7033              :      * the something else.  This currently acts only to suppress constructor
    7034              :      * functions for range types.  Note this is OK only because the
    7035              :      * constructors don't have any dependencies the range type doesn't have;
    7036              :      * otherwise we might not get creation ordering correct.
    7037              :      *
    7038              :      * 3. Otherwise, we normally exclude functions in pg_catalog.  However, if
    7039              :      * they're members of extensions and we are in binary-upgrade mode then
    7040              :      * include them, since we want to dump extension members individually in
    7041              :      * that mode.  Also, if they are used by casts or transforms then we need
    7042              :      * to gather the information about them, though they won't be dumped if
    7043              :      * they are built-in.  Also, in 9.6 and up, include functions in
    7044              :      * pg_catalog if they have an ACL different from what's shown in
    7045              :      * pg_init_privs (so we have to join to pg_init_privs; annoying).
    7046              :      */
    7047          259 :     if (fout->remoteVersion >= 90600)
    7048              :     {
    7049              :         const char *not_agg_check;
    7050              : 
    7051          518 :         not_agg_check = (fout->remoteVersion >= 110000 ? "p.prokind <> 'a'"
    7052          259 :                          : "NOT p.proisagg");
    7053              : 
    7054          259 :         appendPQExpBuffer(query,
    7055              :                           "SELECT p.tableoid, p.oid, p.proname, p.prolang, "
    7056              :                           "p.pronargs, p.proargtypes, p.prorettype, "
    7057              :                           "p.proacl, "
    7058              :                           "acldefault('f', p.proowner) AS acldefault, "
    7059              :                           "p.pronamespace, "
    7060              :                           "p.proowner "
    7061              :                           "FROM pg_proc p "
    7062              :                           "LEFT JOIN pg_init_privs pip ON "
    7063              :                           "(p.oid = pip.objoid "
    7064              :                           "AND pip.classoid = 'pg_proc'::regclass "
    7065              :                           "AND pip.objsubid = 0) "
    7066              :                           "WHERE %s"
    7067              :                           "\n  AND NOT EXISTS (SELECT 1 FROM pg_depend "
    7068              :                           "WHERE classid = 'pg_proc'::regclass AND "
    7069              :                           "objid = p.oid AND deptype = 'i')"
    7070              :                           "\n  AND ("
    7071              :                           "\n  pronamespace != "
    7072              :                           "(SELECT oid FROM pg_namespace "
    7073              :                           "WHERE nspname = 'pg_catalog')"
    7074              :                           "\n  OR EXISTS (SELECT 1 FROM pg_cast"
    7075              :                           "\n  WHERE pg_cast.oid > %u "
    7076              :                           "\n  AND p.oid = pg_cast.castfunc)"
    7077              :                           "\n  OR EXISTS (SELECT 1 FROM pg_transform"
    7078              :                           "\n  WHERE pg_transform.oid > %u AND "
    7079              :                           "\n  (p.oid = pg_transform.trffromsql"
    7080              :                           "\n  OR p.oid = pg_transform.trftosql))",
    7081              :                           not_agg_check,
    7082              :                           g_last_builtin_oid,
    7083              :                           g_last_builtin_oid);
    7084          259 :         if (dopt->binary_upgrade)
    7085           40 :             appendPQExpBufferStr(query,
    7086              :                                  "\n  OR EXISTS(SELECT 1 FROM pg_depend WHERE "
    7087              :                                  "classid = 'pg_proc'::regclass AND "
    7088              :                                  "objid = p.oid AND "
    7089              :                                  "refclassid = 'pg_extension'::regclass AND "
    7090              :                                  "deptype = 'e')");
    7091          259 :         appendPQExpBufferStr(query,
    7092              :                              "\n  OR p.proacl IS DISTINCT FROM pip.initprivs");
    7093          259 :         appendPQExpBufferChar(query, ')');
    7094              :     }
    7095              :     else
    7096              :     {
    7097            0 :         appendPQExpBuffer(query,
    7098              :                           "SELECT tableoid, oid, proname, prolang, "
    7099              :                           "pronargs, proargtypes, prorettype, proacl, "
    7100              :                           "acldefault('f', proowner) AS acldefault, "
    7101              :                           "pronamespace, "
    7102              :                           "proowner "
    7103              :                           "FROM pg_proc p "
    7104              :                           "WHERE NOT proisagg"
    7105              :                           "\n  AND NOT EXISTS (SELECT 1 FROM pg_depend "
    7106              :                           "WHERE classid = 'pg_proc'::regclass AND "
    7107              :                           "objid = p.oid AND deptype = 'i')"
    7108              :                           "\n  AND ("
    7109              :                           "\n  pronamespace != "
    7110              :                           "(SELECT oid FROM pg_namespace "
    7111              :                           "WHERE nspname = 'pg_catalog')"
    7112              :                           "\n  OR EXISTS (SELECT 1 FROM pg_cast"
    7113              :                           "\n  WHERE pg_cast.oid > '%u'::oid"
    7114              :                           "\n  AND p.oid = pg_cast.castfunc)",
    7115              :                           g_last_builtin_oid);
    7116              : 
    7117            0 :         if (fout->remoteVersion >= 90500)
    7118            0 :             appendPQExpBuffer(query,
    7119              :                               "\n  OR EXISTS (SELECT 1 FROM pg_transform"
    7120              :                               "\n  WHERE pg_transform.oid > '%u'::oid"
    7121              :                               "\n  AND (p.oid = pg_transform.trffromsql"
    7122              :                               "\n  OR p.oid = pg_transform.trftosql))",
    7123              :                               g_last_builtin_oid);
    7124              : 
    7125            0 :         if (dopt->binary_upgrade)
    7126            0 :             appendPQExpBufferStr(query,
    7127              :                                  "\n  OR EXISTS(SELECT 1 FROM pg_depend WHERE "
    7128              :                                  "classid = 'pg_proc'::regclass AND "
    7129              :                                  "objid = p.oid AND "
    7130              :                                  "refclassid = 'pg_extension'::regclass AND "
    7131              :                                  "deptype = 'e')");
    7132            0 :         appendPQExpBufferChar(query, ')');
    7133              :     }
    7134              : 
    7135          259 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    7136              : 
    7137          259 :     ntups = PQntuples(res);
    7138              : 
    7139          259 :     finfo = pg_malloc0_array(FuncInfo, ntups);
    7140              : 
    7141          259 :     i_tableoid = PQfnumber(res, "tableoid");
    7142          259 :     i_oid = PQfnumber(res, "oid");
    7143          259 :     i_proname = PQfnumber(res, "proname");
    7144          259 :     i_pronamespace = PQfnumber(res, "pronamespace");
    7145          259 :     i_proowner = PQfnumber(res, "proowner");
    7146          259 :     i_prolang = PQfnumber(res, "prolang");
    7147          259 :     i_pronargs = PQfnumber(res, "pronargs");
    7148          259 :     i_proargtypes = PQfnumber(res, "proargtypes");
    7149          259 :     i_prorettype = PQfnumber(res, "prorettype");
    7150          259 :     i_proacl = PQfnumber(res, "proacl");
    7151          259 :     i_acldefault = PQfnumber(res, "acldefault");
    7152              : 
    7153         5874 :     for (i = 0; i < ntups; i++)
    7154              :     {
    7155         5615 :         finfo[i].dobj.objType = DO_FUNC;
    7156         5615 :         finfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    7157         5615 :         finfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    7158         5615 :         AssignDumpId(&finfo[i].dobj);
    7159         5615 :         finfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_proname));
    7160        11230 :         finfo[i].dobj.namespace =
    7161         5615 :             findNamespace(atooid(PQgetvalue(res, i, i_pronamespace)));
    7162         5615 :         finfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_proacl));
    7163         5615 :         finfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
    7164         5615 :         finfo[i].dacl.privtype = 0;
    7165         5615 :         finfo[i].dacl.initprivs = NULL;
    7166         5615 :         finfo[i].rolname = getRoleName(PQgetvalue(res, i, i_proowner));
    7167         5615 :         finfo[i].lang = atooid(PQgetvalue(res, i, i_prolang));
    7168         5615 :         finfo[i].prorettype = atooid(PQgetvalue(res, i, i_prorettype));
    7169         5615 :         finfo[i].nargs = atoi(PQgetvalue(res, i, i_pronargs));
    7170         5615 :         if (finfo[i].nargs == 0)
    7171         1084 :             finfo[i].argtypes = NULL;
    7172              :         else
    7173              :         {
    7174         4531 :             finfo[i].argtypes = pg_malloc_array(Oid, finfo[i].nargs);
    7175         4531 :             parseOidArray(PQgetvalue(res, i, i_proargtypes),
    7176         4531 :                           finfo[i].argtypes, finfo[i].nargs);
    7177              :         }
    7178         5615 :         finfo[i].postponed_def = false; /* might get set during sort */
    7179              : 
    7180              :         /* Decide whether we want to dump it */
    7181         5615 :         selectDumpableObject(&(finfo[i].dobj), fout);
    7182              : 
    7183              :         /* Mark whether function has an ACL */
    7184         5615 :         if (!PQgetisnull(res, i, i_proacl))
    7185          149 :             finfo[i].dobj.components |= DUMP_COMPONENT_ACL;
    7186              :     }
    7187              : 
    7188          259 :     PQclear(res);
    7189              : 
    7190          259 :     destroyPQExpBuffer(query);
    7191          259 : }
    7192              : 
    7193              : /*
    7194              :  * getRelationStatistics
    7195              :  *    register the statistics object as a dependent of the relation.
    7196              :  *
    7197              :  * reltuples is passed as a string to avoid complexities in converting from/to
    7198              :  * floating point.
    7199              :  */
    7200              : static RelStatsInfo *
    7201        10403 : getRelationStatistics(Archive *fout, DumpableObject *rel, int32 relpages,
    7202              :                       char *reltuples, int32 relallvisible,
    7203              :                       int32 relallfrozen, char relkind,
    7204              :                       char **indAttNames, int nindAttNames)
    7205              : {
    7206        10403 :     if (!fout->dopt->dumpStatistics)
    7207         6650 :         return NULL;
    7208              : 
    7209         3753 :     if ((relkind == RELKIND_RELATION) ||
    7210         1557 :         (relkind == RELKIND_PARTITIONED_TABLE) ||
    7211          938 :         (relkind == RELKIND_INDEX) ||
    7212          620 :         (relkind == RELKIND_PARTITIONED_INDEX) ||
    7213          317 :         (relkind == RELKIND_MATVIEW ||
    7214              :          relkind == RELKIND_FOREIGN_TABLE))
    7215              :     {
    7216         3468 :         RelStatsInfo *info = pg_malloc0_object(RelStatsInfo);
    7217         3468 :         DumpableObject *dobj = &info->dobj;
    7218              : 
    7219         3468 :         dobj->objType = DO_REL_STATS;
    7220         3468 :         dobj->catId.tableoid = 0;
    7221         3468 :         dobj->catId.oid = 0;
    7222         3468 :         AssignDumpId(dobj);
    7223         3468 :         dobj->dependencies = pg_malloc_object(DumpId);
    7224         3468 :         dobj->dependencies[0] = rel->dumpId;
    7225         3468 :         dobj->nDeps = 1;
    7226         3468 :         dobj->allocDeps = 1;
    7227         3468 :         dobj->components |= DUMP_COMPONENT_STATISTICS;
    7228         3468 :         dobj->name = pg_strdup(rel->name);
    7229         3468 :         dobj->namespace = rel->namespace;
    7230         3468 :         info->relid = rel->catId.oid;
    7231         3468 :         info->relpages = relpages;
    7232         3468 :         info->reltuples = pstrdup(reltuples);
    7233         3468 :         info->relallvisible = relallvisible;
    7234         3468 :         info->relallfrozen = relallfrozen;
    7235         3468 :         info->relkind = relkind;
    7236         3468 :         info->indAttNames = indAttNames;
    7237         3468 :         info->nindAttNames = nindAttNames;
    7238              : 
    7239              :         /*
    7240              :          * Ordinarily, stats go in SECTION_DATA for tables and
    7241              :          * SECTION_POST_DATA for indexes.
    7242              :          *
    7243              :          * However, the section may be updated later for materialized view
    7244              :          * stats. REFRESH MATERIALIZED VIEW replaces the storage and resets
    7245              :          * the stats, so the stats must be restored after the data. Also, the
    7246              :          * materialized view definition may be postponed to SECTION_POST_DATA
    7247              :          * (see repairMatViewBoundaryMultiLoop()).
    7248              :          */
    7249         3468 :         switch (info->relkind)
    7250              :         {
    7251         2531 :             case RELKIND_RELATION:
    7252              :             case RELKIND_PARTITIONED_TABLE:
    7253              :             case RELKIND_MATVIEW:
    7254              :             case RELKIND_FOREIGN_TABLE:
    7255         2531 :                 info->section = SECTION_DATA;
    7256         2531 :                 break;
    7257          937 :             case RELKIND_INDEX:
    7258              :             case RELKIND_PARTITIONED_INDEX:
    7259          937 :                 info->section = SECTION_POST_DATA;
    7260          937 :                 break;
    7261            0 :             default:
    7262            0 :                 pg_fatal("cannot dump statistics for relation kind \"%c\"",
    7263              :                          info->relkind);
    7264              :         }
    7265              : 
    7266         3468 :         return info;
    7267              :     }
    7268          285 :     return NULL;
    7269              : }
    7270              : 
    7271              : /*
    7272              :  * getTables
    7273              :  *    read all the tables (no indexes) in the system catalogs,
    7274              :  *    and return them as an array of TableInfo structures
    7275              :  *
    7276              :  * *numTables is set to the number of tables read in
    7277              :  */
    7278              : TableInfo *
    7279          260 : getTables(Archive *fout, int *numTables)
    7280              : {
    7281          260 :     DumpOptions *dopt = fout->dopt;
    7282              :     PGresult   *res;
    7283              :     int         ntups;
    7284              :     int         i;
    7285          260 :     PQExpBuffer query = createPQExpBuffer();
    7286              :     TableInfo  *tblinfo;
    7287              :     int         i_reltableoid;
    7288              :     int         i_reloid;
    7289              :     int         i_relname;
    7290              :     int         i_relnamespace;
    7291              :     int         i_relkind;
    7292              :     int         i_reltype;
    7293              :     int         i_relowner;
    7294              :     int         i_relchecks;
    7295              :     int         i_relhasindex;
    7296              :     int         i_relhasrules;
    7297              :     int         i_relpages;
    7298              :     int         i_reltuples;
    7299              :     int         i_relallvisible;
    7300              :     int         i_relallfrozen;
    7301              :     int         i_toastpages;
    7302              :     int         i_owning_tab;
    7303              :     int         i_owning_col;
    7304              :     int         i_reltablespace;
    7305              :     int         i_relhasoids;
    7306              :     int         i_relhastriggers;
    7307              :     int         i_relpersistence;
    7308              :     int         i_relispopulated;
    7309              :     int         i_relreplident;
    7310              :     int         i_relrowsec;
    7311              :     int         i_relforcerowsec;
    7312              :     int         i_relfrozenxid;
    7313              :     int         i_toastfrozenxid;
    7314              :     int         i_toastoid;
    7315              :     int         i_relminmxid;
    7316              :     int         i_toastminmxid;
    7317              :     int         i_reloptions;
    7318              :     int         i_checkoption;
    7319              :     int         i_toastreloptions;
    7320              :     int         i_reloftype;
    7321              :     int         i_foreignserver;
    7322              :     int         i_amname;
    7323              :     int         i_is_identity_sequence;
    7324              :     int         i_relacl;
    7325              :     int         i_acldefault;
    7326              :     int         i_ispartition;
    7327              : 
    7328              :     /*
    7329              :      * Find all the tables and table-like objects.
    7330              :      *
    7331              :      * We must fetch all tables in this phase because otherwise we cannot
    7332              :      * correctly identify inherited columns, owned sequences, etc.
    7333              :      *
    7334              :      * We include system catalogs, so that we can work if a user table is
    7335              :      * defined to inherit from a system catalog (pretty weird, but...)
    7336              :      *
    7337              :      * Note: in this phase we should collect only a minimal amount of
    7338              :      * information about each table, basically just enough to decide if it is
    7339              :      * interesting.  In particular, since we do not yet have lock on any user
    7340              :      * table, we MUST NOT invoke any server-side data collection functions
    7341              :      * (for instance, pg_get_partkeydef()).  Those are likely to fail or give
    7342              :      * wrong answers if any concurrent DDL is happening.
    7343              :      */
    7344              : 
    7345          260 :     appendPQExpBufferStr(query,
    7346              :                          "SELECT c.tableoid, c.oid, c.relname, "
    7347              :                          "c.relnamespace, c.relkind, c.reltype, "
    7348              :                          "c.relowner, "
    7349              :                          "c.relchecks, "
    7350              :                          "c.relhasindex, c.relhasrules, c.relpages, "
    7351              :                          "c.reltuples, c.relallvisible, ");
    7352              : 
    7353          260 :     if (fout->remoteVersion >= 180000)
    7354          260 :         appendPQExpBufferStr(query, "c.relallfrozen, ");
    7355              :     else
    7356            0 :         appendPQExpBufferStr(query, "0 AS relallfrozen, ");
    7357              : 
    7358          260 :     appendPQExpBufferStr(query,
    7359              :                          "c.relhastriggers, c.relpersistence, "
    7360              :                          "c.reloftype, "
    7361              :                          "c.relacl, "
    7362              :                          "acldefault(CASE WHEN c.relkind = " CppAsString2(RELKIND_SEQUENCE)
    7363              :                          " THEN 's'::\"char\" ELSE 'r'::\"char\" END, c.relowner) AS acldefault, "
    7364              :                          "CASE WHEN c.relkind = " CppAsString2(RELKIND_FOREIGN_TABLE) " THEN "
    7365              :                          "(SELECT ftserver FROM pg_catalog.pg_foreign_table WHERE ftrelid = c.oid) "
    7366              :                          "ELSE 0 END AS foreignserver, "
    7367              :                          "c.relfrozenxid, tc.relfrozenxid AS tfrozenxid, "
    7368              :                          "tc.oid AS toid, "
    7369              :                          "tc.relpages AS toastpages, "
    7370              :                          "tc.reloptions AS toast_reloptions, "
    7371              :                          "d.refobjid AS owning_tab, "
    7372              :                          "d.refobjsubid AS owning_col, "
    7373              :                          "tsp.spcname AS reltablespace, ");
    7374              : 
    7375          260 :     if (fout->remoteVersion >= 120000)
    7376          260 :         appendPQExpBufferStr(query,
    7377              :                              "false AS relhasoids, ");
    7378              :     else
    7379            0 :         appendPQExpBufferStr(query,
    7380              :                              "c.relhasoids, ");
    7381              : 
    7382          260 :     if (fout->remoteVersion >= 90300)
    7383          260 :         appendPQExpBufferStr(query,
    7384              :                              "c.relispopulated, ");
    7385              :     else
    7386            0 :         appendPQExpBufferStr(query,
    7387              :                              "'t' as relispopulated, ");
    7388              : 
    7389          260 :     if (fout->remoteVersion >= 90400)
    7390          260 :         appendPQExpBufferStr(query,
    7391              :                              "c.relreplident, ");
    7392              :     else
    7393            0 :         appendPQExpBufferStr(query,
    7394              :                              "'d' AS relreplident, ");
    7395              : 
    7396          260 :     if (fout->remoteVersion >= 90500)
    7397          260 :         appendPQExpBufferStr(query,
    7398              :                              "c.relrowsecurity, c.relforcerowsecurity, ");
    7399              :     else
    7400            0 :         appendPQExpBufferStr(query,
    7401              :                              "false AS relrowsecurity, "
    7402              :                              "false AS relforcerowsecurity, ");
    7403              : 
    7404          260 :     if (fout->remoteVersion >= 90300)
    7405          260 :         appendPQExpBufferStr(query,
    7406              :                              "c.relminmxid, tc.relminmxid AS tminmxid, ");
    7407              :     else
    7408            0 :         appendPQExpBufferStr(query,
    7409              :                              "0 AS relminmxid, 0 AS tminmxid, ");
    7410              : 
    7411          260 :     if (fout->remoteVersion >= 90300)
    7412          260 :         appendPQExpBufferStr(query,
    7413              :                              "array_remove(array_remove(c.reloptions,'check_option=local'),'check_option=cascaded') AS reloptions, "
    7414              :                              "CASE WHEN 'check_option=local' = ANY (c.reloptions) THEN 'LOCAL'::text "
    7415              :                              "WHEN 'check_option=cascaded' = ANY (c.reloptions) THEN 'CASCADED'::text ELSE NULL END AS checkoption, ");
    7416              :     else
    7417            0 :         appendPQExpBufferStr(query,
    7418              :                              "c.reloptions, NULL AS checkoption, ");
    7419              : 
    7420          260 :     if (fout->remoteVersion >= 90600)
    7421          260 :         appendPQExpBufferStr(query,
    7422              :                              "am.amname, ");
    7423              :     else
    7424            0 :         appendPQExpBufferStr(query,
    7425              :                              "NULL AS amname, ");
    7426              : 
    7427          260 :     if (fout->remoteVersion >= 90600)
    7428          260 :         appendPQExpBufferStr(query,
    7429              :                              "(d.deptype = 'i') IS TRUE AS is_identity_sequence, ");
    7430              :     else
    7431            0 :         appendPQExpBufferStr(query,
    7432              :                              "false AS is_identity_sequence, ");
    7433              : 
    7434          260 :     if (fout->remoteVersion >= 100000)
    7435          260 :         appendPQExpBufferStr(query,
    7436              :                              "c.relispartition AS ispartition ");
    7437              :     else
    7438            0 :         appendPQExpBufferStr(query,
    7439              :                              "false AS ispartition ");
    7440              : 
    7441              :     /*
    7442              :      * Left join to pg_depend to pick up dependency info linking sequences to
    7443              :      * their owning column, if any (note this dependency is AUTO except for
    7444              :      * identity sequences, where it's INTERNAL). Also join to pg_tablespace to
    7445              :      * collect the spcname.
    7446              :      */
    7447          260 :     appendPQExpBufferStr(query,
    7448              :                          "\nFROM pg_class c\n"
    7449              :                          "LEFT JOIN pg_depend d ON "
    7450              :                          "(c.relkind = " CppAsString2(RELKIND_SEQUENCE) " AND "
    7451              :                          "d.classid = 'pg_class'::regclass AND d.objid = c.oid AND "
    7452              :                          "d.objsubid = 0 AND "
    7453              :                          "d.refclassid = 'pg_class'::regclass AND d.deptype IN ('a', 'i'))\n"
    7454              :                          "LEFT JOIN pg_tablespace tsp ON (tsp.oid = c.reltablespace)\n");
    7455              : 
    7456              :     /*
    7457              :      * In 9.6 and up, left join to pg_am to pick up the amname.
    7458              :      */
    7459          260 :     if (fout->remoteVersion >= 90600)
    7460          260 :         appendPQExpBufferStr(query,
    7461              :                              "LEFT JOIN pg_am am ON (c.relam = am.oid)\n");
    7462              : 
    7463              :     /*
    7464              :      * We purposefully ignore toast OIDs for partitioned tables; the reason is
    7465              :      * that versions 10 and 11 have them, but later versions do not, so
    7466              :      * emitting them causes the upgrade to fail.
    7467              :      */
    7468          260 :     appendPQExpBufferStr(query,
    7469              :                          "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid"
    7470              :                          " AND tc.relkind = " CppAsString2(RELKIND_TOASTVALUE)
    7471              :                          " AND c.relkind <> " CppAsString2(RELKIND_PARTITIONED_TABLE) ")\n");
    7472              : 
    7473              :     /*
    7474              :      * Restrict to interesting relkinds (in particular, not indexes).  Not all
    7475              :      * relkinds are possible in older servers, but it's not worth the trouble
    7476              :      * to emit a version-dependent list.
    7477              :      *
    7478              :      * Composite-type table entries won't be dumped as such, but we have to
    7479              :      * make a DumpableObject for them so that we can track dependencies of the
    7480              :      * composite type (pg_depend entries for columns of the composite type
    7481              :      * link to the pg_class entry not the pg_type entry).
    7482              :      */
    7483          260 :     appendPQExpBufferStr(query,
    7484              :                          "WHERE c.relkind IN ("
    7485              :                          CppAsString2(RELKIND_RELATION) ", "
    7486              :                          CppAsString2(RELKIND_SEQUENCE) ", "
    7487              :                          CppAsString2(RELKIND_VIEW) ", "
    7488              :                          CppAsString2(RELKIND_COMPOSITE_TYPE) ", "
    7489              :                          CppAsString2(RELKIND_MATVIEW) ", "
    7490              :                          CppAsString2(RELKIND_FOREIGN_TABLE) ", "
    7491              :                          CppAsString2(RELKIND_PARTITIONED_TABLE) ", "
    7492              :                          CppAsString2(RELKIND_PROPGRAPH) ")\n"
    7493              :                          "ORDER BY c.oid");
    7494              : 
    7495          260 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    7496              : 
    7497          260 :     ntups = PQntuples(res);
    7498              : 
    7499          260 :     *numTables = ntups;
    7500              : 
    7501              :     /*
    7502              :      * Extract data from result and lock dumpable tables.  We do the locking
    7503              :      * before anything else, to minimize the window wherein a table could
    7504              :      * disappear under us.
    7505              :      *
    7506              :      * Note that we have to save info about all tables here, even when dumping
    7507              :      * only one, because we don't yet know which tables might be inheritance
    7508              :      * ancestors of the target table.
    7509              :      */
    7510          260 :     tblinfo = pg_malloc0_array(TableInfo, ntups);
    7511              : 
    7512          260 :     i_reltableoid = PQfnumber(res, "tableoid");
    7513          260 :     i_reloid = PQfnumber(res, "oid");
    7514          260 :     i_relname = PQfnumber(res, "relname");
    7515          260 :     i_relnamespace = PQfnumber(res, "relnamespace");
    7516          260 :     i_relkind = PQfnumber(res, "relkind");
    7517          260 :     i_reltype = PQfnumber(res, "reltype");
    7518          260 :     i_relowner = PQfnumber(res, "relowner");
    7519          260 :     i_relchecks = PQfnumber(res, "relchecks");
    7520          260 :     i_relhasindex = PQfnumber(res, "relhasindex");
    7521          260 :     i_relhasrules = PQfnumber(res, "relhasrules");
    7522          260 :     i_relpages = PQfnumber(res, "relpages");
    7523          260 :     i_reltuples = PQfnumber(res, "reltuples");
    7524          260 :     i_relallvisible = PQfnumber(res, "relallvisible");
    7525          260 :     i_relallfrozen = PQfnumber(res, "relallfrozen");
    7526          260 :     i_toastpages = PQfnumber(res, "toastpages");
    7527          260 :     i_owning_tab = PQfnumber(res, "owning_tab");
    7528          260 :     i_owning_col = PQfnumber(res, "owning_col");
    7529          260 :     i_reltablespace = PQfnumber(res, "reltablespace");
    7530          260 :     i_relhasoids = PQfnumber(res, "relhasoids");
    7531          260 :     i_relhastriggers = PQfnumber(res, "relhastriggers");
    7532          260 :     i_relpersistence = PQfnumber(res, "relpersistence");
    7533          260 :     i_relispopulated = PQfnumber(res, "relispopulated");
    7534          260 :     i_relreplident = PQfnumber(res, "relreplident");
    7535          260 :     i_relrowsec = PQfnumber(res, "relrowsecurity");
    7536          260 :     i_relforcerowsec = PQfnumber(res, "relforcerowsecurity");
    7537          260 :     i_relfrozenxid = PQfnumber(res, "relfrozenxid");
    7538          260 :     i_toastfrozenxid = PQfnumber(res, "tfrozenxid");
    7539          260 :     i_toastoid = PQfnumber(res, "toid");
    7540          260 :     i_relminmxid = PQfnumber(res, "relminmxid");
    7541          260 :     i_toastminmxid = PQfnumber(res, "tminmxid");
    7542          260 :     i_reloptions = PQfnumber(res, "reloptions");
    7543          260 :     i_checkoption = PQfnumber(res, "checkoption");
    7544          260 :     i_toastreloptions = PQfnumber(res, "toast_reloptions");
    7545          260 :     i_reloftype = PQfnumber(res, "reloftype");
    7546          260 :     i_foreignserver = PQfnumber(res, "foreignserver");
    7547          260 :     i_amname = PQfnumber(res, "amname");
    7548          260 :     i_is_identity_sequence = PQfnumber(res, "is_identity_sequence");
    7549          260 :     i_relacl = PQfnumber(res, "relacl");
    7550          260 :     i_acldefault = PQfnumber(res, "acldefault");
    7551          260 :     i_ispartition = PQfnumber(res, "ispartition");
    7552              : 
    7553          260 :     if (dopt->lockWaitTimeout)
    7554              :     {
    7555              :         /*
    7556              :          * Arrange to fail instead of waiting forever for a table lock.
    7557              :          *
    7558              :          * NB: this coding assumes that the only queries issued within the
    7559              :          * following loop are LOCK TABLEs; else the timeout may be undesirably
    7560              :          * applied to other things too.
    7561              :          */
    7562            2 :         resetPQExpBuffer(query);
    7563            2 :         appendPQExpBufferStr(query, "SET statement_timeout = ");
    7564            2 :         appendStringLiteralConn(query, dopt->lockWaitTimeout, GetConnection(fout));
    7565            2 :         ExecuteSqlStatement(fout, query->data);
    7566              :     }
    7567              : 
    7568          260 :     resetPQExpBuffer(query);
    7569              : 
    7570        70452 :     for (i = 0; i < ntups; i++)
    7571              :     {
    7572        70192 :         int32       relallvisible = atoi(PQgetvalue(res, i, i_relallvisible));
    7573        70192 :         int32       relallfrozen = atoi(PQgetvalue(res, i, i_relallfrozen));
    7574              : 
    7575        70192 :         tblinfo[i].dobj.objType = DO_TABLE;
    7576        70192 :         tblinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_reltableoid));
    7577        70192 :         tblinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_reloid));
    7578        70192 :         AssignDumpId(&tblinfo[i].dobj);
    7579        70192 :         tblinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_relname));
    7580       140384 :         tblinfo[i].dobj.namespace =
    7581        70192 :             findNamespace(atooid(PQgetvalue(res, i, i_relnamespace)));
    7582        70192 :         tblinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_relacl));
    7583        70192 :         tblinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
    7584        70192 :         tblinfo[i].dacl.privtype = 0;
    7585        70192 :         tblinfo[i].dacl.initprivs = NULL;
    7586        70192 :         tblinfo[i].relkind = *(PQgetvalue(res, i, i_relkind));
    7587        70192 :         tblinfo[i].reltype = atooid(PQgetvalue(res, i, i_reltype));
    7588        70192 :         tblinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_relowner));
    7589        70192 :         tblinfo[i].ncheck = atoi(PQgetvalue(res, i, i_relchecks));
    7590        70192 :         tblinfo[i].hasindex = (strcmp(PQgetvalue(res, i, i_relhasindex), "t") == 0);
    7591        70192 :         tblinfo[i].hasrules = (strcmp(PQgetvalue(res, i, i_relhasrules), "t") == 0);
    7592        70192 :         tblinfo[i].relpages = atoi(PQgetvalue(res, i, i_relpages));
    7593        70192 :         if (PQgetisnull(res, i, i_toastpages))
    7594        56998 :             tblinfo[i].toastpages = 0;
    7595              :         else
    7596        13194 :             tblinfo[i].toastpages = atoi(PQgetvalue(res, i, i_toastpages));
    7597        70192 :         if (PQgetisnull(res, i, i_owning_tab))
    7598              :         {
    7599        69777 :             tblinfo[i].owning_tab = InvalidOid;
    7600        69777 :             tblinfo[i].owning_col = 0;
    7601              :         }
    7602              :         else
    7603              :         {
    7604          415 :             tblinfo[i].owning_tab = atooid(PQgetvalue(res, i, i_owning_tab));
    7605          415 :             tblinfo[i].owning_col = atoi(PQgetvalue(res, i, i_owning_col));
    7606              :         }
    7607        70192 :         tblinfo[i].reltablespace = pg_strdup(PQgetvalue(res, i, i_reltablespace));
    7608        70192 :         tblinfo[i].hasoids = (strcmp(PQgetvalue(res, i, i_relhasoids), "t") == 0);
    7609        70192 :         tblinfo[i].hastriggers = (strcmp(PQgetvalue(res, i, i_relhastriggers), "t") == 0);
    7610        70192 :         tblinfo[i].relpersistence = *(PQgetvalue(res, i, i_relpersistence));
    7611        70192 :         tblinfo[i].relispopulated = (strcmp(PQgetvalue(res, i, i_relispopulated), "t") == 0);
    7612        70192 :         tblinfo[i].relreplident = *(PQgetvalue(res, i, i_relreplident));
    7613        70192 :         tblinfo[i].rowsec = (strcmp(PQgetvalue(res, i, i_relrowsec), "t") == 0);
    7614        70192 :         tblinfo[i].forcerowsec = (strcmp(PQgetvalue(res, i, i_relforcerowsec), "t") == 0);
    7615        70192 :         tblinfo[i].frozenxid = atooid(PQgetvalue(res, i, i_relfrozenxid));
    7616        70192 :         tblinfo[i].toast_frozenxid = atooid(PQgetvalue(res, i, i_toastfrozenxid));
    7617        70192 :         tblinfo[i].toast_oid = atooid(PQgetvalue(res, i, i_toastoid));
    7618        70192 :         tblinfo[i].minmxid = atooid(PQgetvalue(res, i, i_relminmxid));
    7619        70192 :         tblinfo[i].toast_minmxid = atooid(PQgetvalue(res, i, i_toastminmxid));
    7620        70192 :         tblinfo[i].reloptions = pg_strdup(PQgetvalue(res, i, i_reloptions));
    7621        70192 :         if (PQgetisnull(res, i, i_checkoption))
    7622        70146 :             tblinfo[i].checkoption = NULL;
    7623              :         else
    7624           46 :             tblinfo[i].checkoption = pg_strdup(PQgetvalue(res, i, i_checkoption));
    7625        70192 :         tblinfo[i].toast_reloptions = pg_strdup(PQgetvalue(res, i, i_toastreloptions));
    7626        70192 :         tblinfo[i].reloftype = atooid(PQgetvalue(res, i, i_reloftype));
    7627        70192 :         tblinfo[i].foreign_server = atooid(PQgetvalue(res, i, i_foreignserver));
    7628        70192 :         if (PQgetisnull(res, i, i_amname))
    7629        43570 :             tblinfo[i].amname = NULL;
    7630              :         else
    7631        26622 :             tblinfo[i].amname = pg_strdup(PQgetvalue(res, i, i_amname));
    7632        70192 :         tblinfo[i].is_identity_sequence = (strcmp(PQgetvalue(res, i, i_is_identity_sequence), "t") == 0);
    7633        70192 :         tblinfo[i].ispartition = (strcmp(PQgetvalue(res, i, i_ispartition), "t") == 0);
    7634              : 
    7635              :         /* other fields were zeroed above */
    7636              : 
    7637              :         /*
    7638              :          * Decide whether we want to dump this table.
    7639              :          */
    7640        70192 :         if (tblinfo[i].relkind == RELKIND_COMPOSITE_TYPE)
    7641          183 :             tblinfo[i].dobj.dump = DUMP_COMPONENT_NONE;
    7642              :         else
    7643        70009 :             selectDumpableTable(&tblinfo[i], fout);
    7644              : 
    7645              :         /*
    7646              :          * Now, consider the table "interesting" if we need to dump its
    7647              :          * definition, data or its statistics.  Later on, we'll skip a lot of
    7648              :          * data collection for uninteresting tables.
    7649              :          *
    7650              :          * Note: the "interesting" flag will also be set by flagInhTables for
    7651              :          * parents of interesting tables, so that we collect necessary
    7652              :          * inheritance info even when the parents are not themselves being
    7653              :          * dumped.  This is the main reason why we need an "interesting" flag
    7654              :          * that's separate from the components-to-dump bitmask.
    7655              :          */
    7656        70192 :         tblinfo[i].interesting = (tblinfo[i].dobj.dump &
    7657              :                                   (DUMP_COMPONENT_DEFINITION |
    7658              :                                    DUMP_COMPONENT_DATA |
    7659        70192 :                                    DUMP_COMPONENT_STATISTICS)) != 0;
    7660              : 
    7661        70192 :         tblinfo[i].dummy_view = false;  /* might get set during sort */
    7662        70192 :         tblinfo[i].postponed_def = false;   /* might get set during sort */
    7663              : 
    7664              :         /* Tables have data */
    7665        70192 :         tblinfo[i].dobj.components |= DUMP_COMPONENT_DATA;
    7666              : 
    7667              :         /* Mark whether table has an ACL */
    7668        70192 :         if (!PQgetisnull(res, i, i_relacl))
    7669        59174 :             tblinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
    7670        70192 :         tblinfo[i].hascolumnACLs = false;   /* may get set later */
    7671              : 
    7672              :         /* Add statistics */
    7673        70192 :         if (tblinfo[i].interesting)
    7674              :         {
    7675              :             RelStatsInfo *stats;
    7676              : 
    7677        15272 :             stats = getRelationStatistics(fout, &tblinfo[i].dobj,
    7678         7636 :                                           tblinfo[i].relpages,
    7679              :                                           PQgetvalue(res, i, i_reltuples),
    7680              :                                           relallvisible, relallfrozen,
    7681         7636 :                                           tblinfo[i].relkind, NULL, 0);
    7682         7636 :             if (tblinfo[i].relkind == RELKIND_MATVIEW)
    7683          398 :                 tblinfo[i].stats = stats;
    7684              :         }
    7685              : 
    7686              :         /*
    7687              :          * Read-lock target tables to make sure they aren't DROPPED or altered
    7688              :          * in schema before we get around to dumping them.
    7689              :          *
    7690              :          * Note that we don't explicitly lock parents of the target tables; we
    7691              :          * assume our lock on the child is enough to prevent schema
    7692              :          * alterations to parent tables.
    7693              :          *
    7694              :          * NOTE: it'd be kinda nice to lock other relations too, not only
    7695              :          * plain or partitioned tables, but the backend doesn't presently
    7696              :          * allow that.
    7697              :          *
    7698              :          * We only need to lock the table for certain components; see
    7699              :          * pg_dump.h
    7700              :          */
    7701        70192 :         if ((tblinfo[i].dobj.dump & DUMP_COMPONENTS_REQUIRING_LOCK) &&
    7702         7636 :             (tblinfo[i].relkind == RELKIND_RELATION ||
    7703         2128 :              tblinfo[i].relkind == RELKIND_PARTITIONED_TABLE))
    7704              :         {
    7705              :             /*
    7706              :              * Tables are locked in batches.  When dumping from a remote
    7707              :              * server this can save a significant amount of time by reducing
    7708              :              * the number of round trips.
    7709              :              */
    7710         6127 :             if (query->len == 0)
    7711          177 :                 appendPQExpBuffer(query, "LOCK TABLE %s",
    7712          177 :                                   fmtQualifiedDumpable(&tblinfo[i]));
    7713              :             else
    7714              :             {
    7715         5950 :                 appendPQExpBuffer(query, ", %s",
    7716         5950 :                                   fmtQualifiedDumpable(&tblinfo[i]));
    7717              : 
    7718              :                 /* Arbitrarily end a batch when query length reaches 100K. */
    7719         5950 :                 if (query->len >= 100000)
    7720              :                 {
    7721              :                     /* Lock another batch of tables. */
    7722            0 :                     appendPQExpBufferStr(query, " IN ACCESS SHARE MODE");
    7723            0 :                     ExecuteSqlStatement(fout, query->data);
    7724            0 :                     resetPQExpBuffer(query);
    7725              :                 }
    7726              :             }
    7727              :         }
    7728              :     }
    7729              : 
    7730          260 :     if (query->len != 0)
    7731              :     {
    7732              :         /* Lock the tables in the last batch. */
    7733          177 :         appendPQExpBufferStr(query, " IN ACCESS SHARE MODE");
    7734          177 :         ExecuteSqlStatement(fout, query->data);
    7735              :     }
    7736              : 
    7737          259 :     if (dopt->lockWaitTimeout)
    7738              :     {
    7739            2 :         ExecuteSqlStatement(fout, "SET statement_timeout = 0");
    7740              :     }
    7741              : 
    7742          259 :     PQclear(res);
    7743              : 
    7744          259 :     destroyPQExpBuffer(query);
    7745              : 
    7746          259 :     return tblinfo;
    7747              : }
    7748              : 
    7749              : /*
    7750              :  * getOwnedSeqs
    7751              :  *    identify owned sequences and mark them as dumpable if owning table is
    7752              :  *
    7753              :  * We used to do this in getTables(), but it's better to do it after the
    7754              :  * index used by findTableByOid() has been set up.
    7755              :  */
    7756              : void
    7757          259 : getOwnedSeqs(Archive *fout, TableInfo tblinfo[], int numTables)
    7758              : {
    7759              :     int         i;
    7760              : 
    7761              :     /*
    7762              :      * Force sequences that are "owned" by table columns to be dumped whenever
    7763              :      * their owning table is being dumped.
    7764              :      */
    7765        70160 :     for (i = 0; i < numTables; i++)
    7766              :     {
    7767        69901 :         TableInfo  *seqinfo = &tblinfo[i];
    7768              :         TableInfo  *owning_tab;
    7769              : 
    7770        69901 :         if (!OidIsValid(seqinfo->owning_tab))
    7771        69489 :             continue;           /* not an owned sequence */
    7772              : 
    7773          412 :         owning_tab = findTableByOid(seqinfo->owning_tab);
    7774          412 :         if (owning_tab == NULL)
    7775            0 :             pg_fatal("failed sanity check, parent table with OID %u of sequence with OID %u not found",
    7776              :                      seqinfo->owning_tab, seqinfo->dobj.catId.oid);
    7777              : 
    7778              :         /*
    7779              :          * For an identity sequence, dump exactly the same components for the
    7780              :          * sequence as for the owning table.  This is important because we
    7781              :          * treat the identity sequence as an integral part of the table.  For
    7782              :          * example, there is not any DDL command that allows creation of such
    7783              :          * a sequence independently of the table.
    7784              :          *
    7785              :          * For other owned sequences such as serial sequences, we need to dump
    7786              :          * the components that are being dumped for the table and any
    7787              :          * components that the sequence is explicitly marked with.
    7788              :          *
    7789              :          * We can't simply use the set of components which are being dumped
    7790              :          * for the table as the table might be in an extension (and only the
    7791              :          * non-extension components, eg: ACLs if changed, security labels, and
    7792              :          * policies, are being dumped) while the sequence is not (and
    7793              :          * therefore the definition and other components should also be
    7794              :          * dumped).
    7795              :          *
    7796              :          * If the sequence is part of the extension then it should be properly
    7797              :          * marked by checkExtensionMembership() and this will be a no-op as
    7798              :          * the table will be equivalently marked.
    7799              :          */
    7800          412 :         if (seqinfo->is_identity_sequence)
    7801          199 :             seqinfo->dobj.dump = owning_tab->dobj.dump;
    7802              :         else
    7803          213 :             seqinfo->dobj.dump |= owning_tab->dobj.dump;
    7804              : 
    7805              :         /* Make sure that necessary data is available if we're dumping it */
    7806          412 :         if (seqinfo->dobj.dump != DUMP_COMPONENT_NONE)
    7807              :         {
    7808          316 :             seqinfo->interesting = true;
    7809          316 :             owning_tab->interesting = true;
    7810              :         }
    7811              :     }
    7812          259 : }
    7813              : 
    7814              : /*
    7815              :  * getInherits
    7816              :  *    read all the inheritance information
    7817              :  * from the system catalogs return them in the InhInfo* structure
    7818              :  *
    7819              :  * numInherits is set to the number of pairs read in
    7820              :  */
    7821              : InhInfo *
    7822          259 : getInherits(Archive *fout, int *numInherits)
    7823              : {
    7824              :     PGresult   *res;
    7825              :     int         ntups;
    7826              :     int         i;
    7827          259 :     PQExpBuffer query = createPQExpBuffer();
    7828              :     InhInfo    *inhinfo;
    7829              : 
    7830              :     int         i_inhrelid;
    7831              :     int         i_inhparent;
    7832              : 
    7833              :     /* find all the inheritance information */
    7834          259 :     appendPQExpBufferStr(query, "SELECT inhrelid, inhparent FROM pg_inherits");
    7835              : 
    7836          259 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    7837              : 
    7838          259 :     ntups = PQntuples(res);
    7839              : 
    7840          259 :     *numInherits = ntups;
    7841              : 
    7842          259 :     inhinfo = pg_malloc_array(InhInfo, ntups);
    7843              : 
    7844          259 :     i_inhrelid = PQfnumber(res, "inhrelid");
    7845          259 :     i_inhparent = PQfnumber(res, "inhparent");
    7846              : 
    7847         3798 :     for (i = 0; i < ntups; i++)
    7848              :     {
    7849         3539 :         inhinfo[i].inhrelid = atooid(PQgetvalue(res, i, i_inhrelid));
    7850         3539 :         inhinfo[i].inhparent = atooid(PQgetvalue(res, i, i_inhparent));
    7851              :     }
    7852              : 
    7853          259 :     PQclear(res);
    7854              : 
    7855          259 :     destroyPQExpBuffer(query);
    7856              : 
    7857          259 :     return inhinfo;
    7858              : }
    7859              : 
    7860              : /*
    7861              :  * getPartitioningInfo
    7862              :  *    get information about partitioning
    7863              :  *
    7864              :  * For the most part, we only collect partitioning info about tables we
    7865              :  * intend to dump.  However, this function has to consider all partitioned
    7866              :  * tables in the database, because we need to know about parents of partitions
    7867              :  * we are going to dump even if the parents themselves won't be dumped.
    7868              :  *
    7869              :  * Specifically, what we need to know is whether each partitioned table
    7870              :  * has an "unsafe" partitioning scheme that requires us to force
    7871              :  * load-via-partition-root mode for its children.  Currently the only case
    7872              :  * for which we force that is hash partitioning on enum columns, since the
    7873              :  * hash codes depend on enum value OIDs which won't be replicated across
    7874              :  * dump-and-reload.  There are other cases in which load-via-partition-root
    7875              :  * might be necessary, but we expect users to cope with them.
    7876              :  */
    7877              : void
    7878          259 : getPartitioningInfo(Archive *fout)
    7879              : {
    7880              :     PQExpBuffer query;
    7881              :     PGresult   *res;
    7882              :     int         ntups;
    7883              : 
    7884              :     /* hash partitioning didn't exist before v11 */
    7885          259 :     if (fout->remoteVersion < 110000)
    7886            0 :         return;
    7887              :     /* needn't bother if not dumping data */
    7888          259 :     if (!fout->dopt->dumpData)
    7889           44 :         return;
    7890              : 
    7891          215 :     query = createPQExpBuffer();
    7892              : 
    7893              :     /*
    7894              :      * Unsafe partitioning schemes are exactly those for which hash enum_ops
    7895              :      * appears among the partition opclasses.  We needn't check partstrat.
    7896              :      *
    7897              :      * Note that this query may well retrieve info about tables we aren't
    7898              :      * going to dump and hence have no lock on.  That's okay since we need not
    7899              :      * invoke any unsafe server-side functions.
    7900              :      */
    7901          215 :     appendPQExpBufferStr(query,
    7902              :                          "SELECT partrelid FROM pg_partitioned_table WHERE\n"
    7903              :                          "(SELECT c.oid FROM pg_opclass c JOIN pg_am a "
    7904              :                          "ON c.opcmethod = a.oid\n"
    7905              :                          "WHERE opcname = 'enum_ops' "
    7906              :                          "AND opcnamespace = 'pg_catalog'::regnamespace "
    7907              :                          "AND amname = 'hash') = ANY(partclass)");
    7908              : 
    7909          215 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    7910              : 
    7911          215 :     ntups = PQntuples(res);
    7912              : 
    7913          258 :     for (int i = 0; i < ntups; i++)
    7914              :     {
    7915           43 :         Oid         tabrelid = atooid(PQgetvalue(res, i, 0));
    7916              :         TableInfo  *tbinfo;
    7917              : 
    7918           43 :         tbinfo = findTableByOid(tabrelid);
    7919           43 :         if (tbinfo == NULL)
    7920            0 :             pg_fatal("failed sanity check, table OID %u appearing in pg_partitioned_table not found",
    7921              :                      tabrelid);
    7922           43 :         tbinfo->unsafe_partitions = true;
    7923              :     }
    7924              : 
    7925          215 :     PQclear(res);
    7926              : 
    7927          215 :     destroyPQExpBuffer(query);
    7928              : }
    7929              : 
    7930              : /*
    7931              :  * getIndexes
    7932              :  *    get information about every index on a dumpable table
    7933              :  *
    7934              :  * Note: index data is not returned directly to the caller, but it
    7935              :  * does get entered into the DumpableObject tables.
    7936              :  */
    7937              : void
    7938          259 : getIndexes(Archive *fout, TableInfo tblinfo[], int numTables)
    7939              : {
    7940          259 :     PQExpBuffer query = createPQExpBuffer();
    7941          259 :     PQExpBuffer tbloids = createPQExpBuffer();
    7942              :     PGresult   *res;
    7943              :     int         ntups;
    7944              :     int         curtblindx;
    7945              :     IndxInfo   *indxinfo;
    7946              :     int         i_tableoid,
    7947              :                 i_oid,
    7948              :                 i_indrelid,
    7949              :                 i_indexname,
    7950              :                 i_relpages,
    7951              :                 i_reltuples,
    7952              :                 i_relallvisible,
    7953              :                 i_relallfrozen,
    7954              :                 i_parentidx,
    7955              :                 i_indexdef,
    7956              :                 i_indnkeyatts,
    7957              :                 i_indnatts,
    7958              :                 i_indkey,
    7959              :                 i_indisclustered,
    7960              :                 i_indisreplident,
    7961              :                 i_indnullsnotdistinct,
    7962              :                 i_contype,
    7963              :                 i_conname,
    7964              :                 i_condeferrable,
    7965              :                 i_condeferred,
    7966              :                 i_conperiod,
    7967              :                 i_contableoid,
    7968              :                 i_conoid,
    7969              :                 i_condef,
    7970              :                 i_indattnames,
    7971              :                 i_tablespace,
    7972              :                 i_indreloptions,
    7973              :                 i_indstatcols,
    7974              :                 i_indstatvals;
    7975              : 
    7976              :     /*
    7977              :      * We want to perform just one query against pg_index.  However, we
    7978              :      * mustn't try to select every row of the catalog and then sort it out on
    7979              :      * the client side, because some of the server-side functions we need
    7980              :      * would be unsafe to apply to tables we don't have lock on.  Hence, we
    7981              :      * build an array of the OIDs of tables we care about (and now have lock
    7982              :      * on!), and use a WHERE clause to constrain which rows are selected.
    7983              :      */
    7984          259 :     appendPQExpBufferChar(tbloids, '{');
    7985        70160 :     for (int i = 0; i < numTables; i++)
    7986              :     {
    7987        69901 :         TableInfo  *tbinfo = &tblinfo[i];
    7988              : 
    7989        69901 :         if (!tbinfo->hasindex)
    7990        49463 :             continue;
    7991              : 
    7992              :         /*
    7993              :          * We can ignore indexes of uninteresting tables.
    7994              :          */
    7995        20438 :         if (!tbinfo->interesting)
    7996        18295 :             continue;
    7997              : 
    7998              :         /* OK, we need info for this table */
    7999         2143 :         if (tbloids->len > 1) /* do we have more than the '{'? */
    8000         2064 :             appendPQExpBufferChar(tbloids, ',');
    8001         2143 :         appendPQExpBuffer(tbloids, "%u", tbinfo->dobj.catId.oid);
    8002              :     }
    8003          259 :     appendPQExpBufferChar(tbloids, '}');
    8004              : 
    8005          259 :     appendPQExpBufferStr(query,
    8006              :                          "SELECT t.tableoid, t.oid, i.indrelid, "
    8007              :                          "t.relname AS indexname, "
    8008              :                          "t.relpages, t.reltuples, t.relallvisible, ");
    8009              : 
    8010          259 :     if (fout->remoteVersion >= 180000)
    8011          259 :         appendPQExpBufferStr(query, "t.relallfrozen, ");
    8012              :     else
    8013            0 :         appendPQExpBufferStr(query, "0 AS relallfrozen, ");
    8014              : 
    8015          259 :     appendPQExpBufferStr(query,
    8016              :                          "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
    8017              :                          "i.indkey, i.indisclustered, "
    8018              :                          "c.contype, c.conname, "
    8019              :                          "c.condeferrable, c.condeferred, "
    8020              :                          "c.tableoid AS contableoid, "
    8021              :                          "c.oid AS conoid, "
    8022              :                          "pg_catalog.pg_get_constraintdef(c.oid, false) AS condef, "
    8023              :                          "CASE WHEN i.indexprs IS NOT NULL THEN "
    8024              :                          "(SELECT pg_catalog.array_agg(attname ORDER BY attnum)"
    8025              :                          "  FROM pg_catalog.pg_attribute "
    8026              :                          "  WHERE attrelid = i.indexrelid) "
    8027              :                          "ELSE NULL END AS indattnames, "
    8028              :                          "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
    8029              :                          "t.reloptions AS indreloptions, ");
    8030              : 
    8031              : 
    8032          259 :     if (fout->remoteVersion >= 90400)
    8033          259 :         appendPQExpBufferStr(query,
    8034              :                              "i.indisreplident, ");
    8035              :     else
    8036            0 :         appendPQExpBufferStr(query,
    8037              :                              "false AS indisreplident, ");
    8038              : 
    8039          259 :     if (fout->remoteVersion >= 110000)
    8040          259 :         appendPQExpBufferStr(query,
    8041              :                              "inh.inhparent AS parentidx, "
    8042              :                              "i.indnkeyatts AS indnkeyatts, "
    8043              :                              "i.indnatts AS indnatts, "
    8044              :                              "(SELECT pg_catalog.array_agg(attnum ORDER BY attnum) "
    8045              :                              "  FROM pg_catalog.pg_attribute "
    8046              :                              "  WHERE attrelid = i.indexrelid AND "
    8047              :                              "    attstattarget >= 0) AS indstatcols, "
    8048              :                              "(SELECT pg_catalog.array_agg(attstattarget ORDER BY attnum) "
    8049              :                              "  FROM pg_catalog.pg_attribute "
    8050              :                              "  WHERE attrelid = i.indexrelid AND "
    8051              :                              "    attstattarget >= 0) AS indstatvals, ");
    8052              :     else
    8053            0 :         appendPQExpBufferStr(query,
    8054              :                              "0 AS parentidx, "
    8055              :                              "i.indnatts AS indnkeyatts, "
    8056              :                              "i.indnatts AS indnatts, "
    8057              :                              "'' AS indstatcols, "
    8058              :                              "'' AS indstatvals, ");
    8059              : 
    8060          259 :     if (fout->remoteVersion >= 150000)
    8061          259 :         appendPQExpBufferStr(query,
    8062              :                              "i.indnullsnotdistinct, ");
    8063              :     else
    8064            0 :         appendPQExpBufferStr(query,
    8065              :                              "false AS indnullsnotdistinct, ");
    8066              : 
    8067          259 :     if (fout->remoteVersion >= 180000)
    8068          259 :         appendPQExpBufferStr(query,
    8069              :                              "c.conperiod ");
    8070              :     else
    8071            0 :         appendPQExpBufferStr(query,
    8072              :                              "NULL AS conperiod ");
    8073              : 
    8074              :     /*
    8075              :      * The point of the messy-looking outer join is to find a constraint that
    8076              :      * is related by an internal dependency link to the index. If we find one,
    8077              :      * create a CONSTRAINT entry linked to the INDEX entry.  We assume an
    8078              :      * index won't have more than one internal dependency.
    8079              :      *
    8080              :      * Note: the check on conrelid is redundant, but useful because that
    8081              :      * column is indexed while conindid is not.
    8082              :      */
    8083          259 :     if (fout->remoteVersion >= 110000)
    8084              :     {
    8085          259 :         appendPQExpBuffer(query,
    8086              :                           "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
    8087              :                           "JOIN pg_catalog.pg_index i ON (src.tbloid = i.indrelid) "
    8088              :                           "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
    8089              :                           "JOIN pg_catalog.pg_class t2 ON (t2.oid = i.indrelid) "
    8090              :                           "LEFT JOIN pg_catalog.pg_constraint c "
    8091              :                           "ON (i.indrelid = c.conrelid AND "
    8092              :                           "i.indexrelid = c.conindid AND "
    8093              :                           "c.contype IN ('p','u','x')) "
    8094              :                           "LEFT JOIN pg_catalog.pg_inherits inh "
    8095              :                           "ON (inh.inhrelid = indexrelid) "
    8096              :                           "WHERE (i.indisvalid OR t2.relkind = 'p') "
    8097              :                           "AND i.indisready "
    8098              :                           "ORDER BY i.indrelid, indexname",
    8099              :                           tbloids->data);
    8100              :     }
    8101              :     else
    8102              :     {
    8103              :         /*
    8104              :          * the test on indisready is necessary in 9.2, and harmless in
    8105              :          * earlier/later versions
    8106              :          */
    8107            0 :         appendPQExpBuffer(query,
    8108              :                           "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
    8109              :                           "JOIN pg_catalog.pg_index i ON (src.tbloid = i.indrelid) "
    8110              :                           "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
    8111              :                           "LEFT JOIN pg_catalog.pg_constraint c "
    8112              :                           "ON (i.indrelid = c.conrelid AND "
    8113              :                           "i.indexrelid = c.conindid AND "
    8114              :                           "c.contype IN ('p','u','x')) "
    8115              :                           "WHERE i.indisvalid AND i.indisready "
    8116              :                           "ORDER BY i.indrelid, indexname",
    8117              :                           tbloids->data);
    8118              :     }
    8119              : 
    8120          259 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    8121              : 
    8122          259 :     ntups = PQntuples(res);
    8123              : 
    8124          259 :     i_tableoid = PQfnumber(res, "tableoid");
    8125          259 :     i_oid = PQfnumber(res, "oid");
    8126          259 :     i_indrelid = PQfnumber(res, "indrelid");
    8127          259 :     i_indexname = PQfnumber(res, "indexname");
    8128          259 :     i_relpages = PQfnumber(res, "relpages");
    8129          259 :     i_reltuples = PQfnumber(res, "reltuples");
    8130          259 :     i_relallvisible = PQfnumber(res, "relallvisible");
    8131          259 :     i_relallfrozen = PQfnumber(res, "relallfrozen");
    8132          259 :     i_parentidx = PQfnumber(res, "parentidx");
    8133          259 :     i_indexdef = PQfnumber(res, "indexdef");
    8134          259 :     i_indnkeyatts = PQfnumber(res, "indnkeyatts");
    8135          259 :     i_indnatts = PQfnumber(res, "indnatts");
    8136          259 :     i_indkey = PQfnumber(res, "indkey");
    8137          259 :     i_indisclustered = PQfnumber(res, "indisclustered");
    8138          259 :     i_indisreplident = PQfnumber(res, "indisreplident");
    8139          259 :     i_indnullsnotdistinct = PQfnumber(res, "indnullsnotdistinct");
    8140          259 :     i_contype = PQfnumber(res, "contype");
    8141          259 :     i_conname = PQfnumber(res, "conname");
    8142          259 :     i_condeferrable = PQfnumber(res, "condeferrable");
    8143          259 :     i_condeferred = PQfnumber(res, "condeferred");
    8144          259 :     i_conperiod = PQfnumber(res, "conperiod");
    8145          259 :     i_contableoid = PQfnumber(res, "contableoid");
    8146          259 :     i_conoid = PQfnumber(res, "conoid");
    8147          259 :     i_condef = PQfnumber(res, "condef");
    8148          259 :     i_indattnames = PQfnumber(res, "indattnames");
    8149          259 :     i_tablespace = PQfnumber(res, "tablespace");
    8150          259 :     i_indreloptions = PQfnumber(res, "indreloptions");
    8151          259 :     i_indstatcols = PQfnumber(res, "indstatcols");
    8152          259 :     i_indstatvals = PQfnumber(res, "indstatvals");
    8153              : 
    8154          259 :     indxinfo = pg_malloc_array(IndxInfo, ntups);
    8155              : 
    8156              :     /*
    8157              :      * Outer loop iterates once per table, not once per row.  Incrementing of
    8158              :      * j is handled by the inner loop.
    8159              :      */
    8160          259 :     curtblindx = -1;
    8161         2386 :     for (int j = 0; j < ntups;)
    8162              :     {
    8163         2127 :         Oid         indrelid = atooid(PQgetvalue(res, j, i_indrelid));
    8164         2127 :         TableInfo  *tbinfo = NULL;
    8165         2127 :         char      **indAttNames = NULL;
    8166         2127 :         int         nindAttNames = 0;
    8167              :         int         numinds;
    8168              : 
    8169              :         /* Count rows for this table */
    8170         2767 :         for (numinds = 1; numinds < ntups - j; numinds++)
    8171         2688 :             if (atooid(PQgetvalue(res, j + numinds, i_indrelid)) != indrelid)
    8172         2048 :                 break;
    8173              : 
    8174              :         /*
    8175              :          * Locate the associated TableInfo; we rely on tblinfo[] being in OID
    8176              :          * order.
    8177              :          */
    8178        25006 :         while (++curtblindx < numTables)
    8179              :         {
    8180        25006 :             tbinfo = &tblinfo[curtblindx];
    8181        25006 :             if (tbinfo->dobj.catId.oid == indrelid)
    8182         2127 :                 break;
    8183              :         }
    8184         2127 :         if (curtblindx >= numTables)
    8185            0 :             pg_fatal("unrecognized table OID %u", indrelid);
    8186              :         /* cross-check that we only got requested tables */
    8187         2127 :         if (!tbinfo->hasindex ||
    8188         2127 :             !tbinfo->interesting)
    8189            0 :             pg_fatal("unexpected index data for table \"%s\"",
    8190              :                      tbinfo->dobj.name);
    8191              : 
    8192              :         /* Save data for this table */
    8193         2127 :         tbinfo->indexes = indxinfo + j;
    8194         2127 :         tbinfo->numIndexes = numinds;
    8195              : 
    8196         4894 :         for (int c = 0; c < numinds; c++, j++)
    8197              :         {
    8198              :             char        contype;
    8199              :             char        indexkind;
    8200              :             RelStatsInfo *relstats;
    8201         2767 :             int32       relpages = atoi(PQgetvalue(res, j, i_relpages));
    8202         2767 :             int32       relallvisible = atoi(PQgetvalue(res, j, i_relallvisible));
    8203         2767 :             int32       relallfrozen = atoi(PQgetvalue(res, j, i_relallfrozen));
    8204              : 
    8205         2767 :             indxinfo[j].dobj.objType = DO_INDEX;
    8206         2767 :             indxinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
    8207         2767 :             indxinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
    8208         2767 :             AssignDumpId(&indxinfo[j].dobj);
    8209         2767 :             indxinfo[j].dobj.dump = tbinfo->dobj.dump;
    8210         2767 :             indxinfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_indexname));
    8211         2767 :             indxinfo[j].dobj.namespace = tbinfo->dobj.namespace;
    8212         2767 :             indxinfo[j].indextable = tbinfo;
    8213         2767 :             indxinfo[j].indexdef = pg_strdup(PQgetvalue(res, j, i_indexdef));
    8214         2767 :             indxinfo[j].indnkeyattrs = atoi(PQgetvalue(res, j, i_indnkeyatts));
    8215         2767 :             indxinfo[j].indnattrs = atoi(PQgetvalue(res, j, i_indnatts));
    8216         2767 :             indxinfo[j].tablespace = pg_strdup(PQgetvalue(res, j, i_tablespace));
    8217         2767 :             indxinfo[j].indreloptions = pg_strdup(PQgetvalue(res, j, i_indreloptions));
    8218         2767 :             indxinfo[j].indstatcols = pg_strdup(PQgetvalue(res, j, i_indstatcols));
    8219         2767 :             indxinfo[j].indstatvals = pg_strdup(PQgetvalue(res, j, i_indstatvals));
    8220         2767 :             indxinfo[j].indkeys = pg_malloc_array(Oid, indxinfo[j].indnattrs);
    8221         2767 :             parseOidArray(PQgetvalue(res, j, i_indkey),
    8222         2767 :                           indxinfo[j].indkeys, indxinfo[j].indnattrs);
    8223         2767 :             indxinfo[j].indisclustered = (PQgetvalue(res, j, i_indisclustered)[0] == 't');
    8224         2767 :             indxinfo[j].indisreplident = (PQgetvalue(res, j, i_indisreplident)[0] == 't');
    8225         2767 :             indxinfo[j].indnullsnotdistinct = (PQgetvalue(res, j, i_indnullsnotdistinct)[0] == 't');
    8226         2767 :             indxinfo[j].parentidx = atooid(PQgetvalue(res, j, i_parentidx));
    8227         2767 :             indxinfo[j].partattaches = (SimplePtrList)
    8228              :             {
    8229              :                 NULL, NULL
    8230              :             };
    8231              : 
    8232         2767 :             if (indxinfo[j].parentidx == 0)
    8233         2173 :                 indexkind = RELKIND_INDEX;
    8234              :             else
    8235          594 :                 indexkind = RELKIND_PARTITIONED_INDEX;
    8236              : 
    8237         2767 :             if (!PQgetisnull(res, j, i_indattnames))
    8238              :             {
    8239          146 :                 if (!parsePGArray(PQgetvalue(res, j, i_indattnames),
    8240              :                                   &indAttNames, &nindAttNames))
    8241            0 :                     pg_fatal("could not parse %s array", "indattnames");
    8242              :             }
    8243              : 
    8244         2767 :             relstats = getRelationStatistics(fout, &indxinfo[j].dobj, relpages,
    8245              :                                              PQgetvalue(res, j, i_reltuples),
    8246              :                                              relallvisible, relallfrozen, indexkind,
    8247              :                                              indAttNames, nindAttNames);
    8248              : 
    8249         2767 :             contype = *(PQgetvalue(res, j, i_contype));
    8250         2767 :             if (contype == 'p' || contype == 'u' || contype == 'x')
    8251         1672 :             {
    8252              :                 /*
    8253              :                  * If we found a constraint matching the index, create an
    8254              :                  * entry for it.
    8255              :                  */
    8256              :                 ConstraintInfo *constrinfo;
    8257              : 
    8258         1672 :                 constrinfo = pg_malloc_object(ConstraintInfo);
    8259         1672 :                 constrinfo->dobj.objType = DO_CONSTRAINT;
    8260         1672 :                 constrinfo->dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_contableoid));
    8261         1672 :                 constrinfo->dobj.catId.oid = atooid(PQgetvalue(res, j, i_conoid));
    8262         1672 :                 AssignDumpId(&constrinfo->dobj);
    8263         1672 :                 constrinfo->dobj.dump = tbinfo->dobj.dump;
    8264         1672 :                 constrinfo->dobj.name = pg_strdup(PQgetvalue(res, j, i_conname));
    8265         1672 :                 constrinfo->dobj.namespace = tbinfo->dobj.namespace;
    8266         1672 :                 constrinfo->contable = tbinfo;
    8267         1672 :                 constrinfo->condomain = NULL;
    8268         1672 :                 constrinfo->contype = contype;
    8269         1672 :                 if (contype == 'x')
    8270           10 :                     constrinfo->condef = pg_strdup(PQgetvalue(res, j, i_condef));
    8271              :                 else
    8272         1662 :                     constrinfo->condef = NULL;
    8273         1672 :                 constrinfo->confrelid = InvalidOid;
    8274         1672 :                 constrinfo->conindex = indxinfo[j].dobj.dumpId;
    8275         1672 :                 constrinfo->condeferrable = *(PQgetvalue(res, j, i_condeferrable)) == 't';
    8276         1672 :                 constrinfo->condeferred = *(PQgetvalue(res, j, i_condeferred)) == 't';
    8277         1672 :                 constrinfo->conperiod = *(PQgetvalue(res, j, i_conperiod)) == 't';
    8278         1672 :                 constrinfo->conislocal = true;
    8279         1672 :                 constrinfo->separate = true;
    8280              : 
    8281         1672 :                 indxinfo[j].indexconstraint = constrinfo->dobj.dumpId;
    8282         1672 :                 if (relstats != NULL)
    8283          555 :                     addObjectDependency(&relstats->dobj, constrinfo->dobj.dumpId);
    8284              :             }
    8285              :             else
    8286              :             {
    8287              :                 /* Plain secondary index */
    8288         1095 :                 indxinfo[j].indexconstraint = 0;
    8289              :             }
    8290              :         }
    8291              :     }
    8292              : 
    8293          259 :     PQclear(res);
    8294              : 
    8295          259 :     destroyPQExpBuffer(query);
    8296          259 :     destroyPQExpBuffer(tbloids);
    8297          259 : }
    8298              : 
    8299              : /*
    8300              :  * getExtendedStatistics
    8301              :  *    get information about extended-statistics objects.
    8302              :  *
    8303              :  * Note: extended statistics data is not returned directly to the caller, but
    8304              :  * it does get entered into the DumpableObject tables.
    8305              :  */
    8306              : void
    8307          259 : getExtendedStatistics(Archive *fout)
    8308              : {
    8309              :     PQExpBuffer query;
    8310              :     PGresult   *res;
    8311              :     StatsExtInfo *statsextinfo;
    8312              :     int         ntups;
    8313              :     int         i_tableoid;
    8314              :     int         i_oid;
    8315              :     int         i_stxname;
    8316              :     int         i_stxnamespace;
    8317              :     int         i_stxowner;
    8318              :     int         i_stxrelid;
    8319              :     int         i_stattarget;
    8320              :     int         i;
    8321              : 
    8322              :     /* Extended statistics were new in v10 */
    8323          259 :     if (fout->remoteVersion < 100000)
    8324            0 :         return;
    8325              : 
    8326          259 :     query = createPQExpBuffer();
    8327              : 
    8328          259 :     if (fout->remoteVersion < 130000)
    8329            0 :         appendPQExpBufferStr(query, "SELECT tableoid, oid, stxname, "
    8330              :                              "stxnamespace, stxowner, stxrelid, NULL AS stxstattarget "
    8331              :                              "FROM pg_catalog.pg_statistic_ext");
    8332              :     else
    8333          259 :         appendPQExpBufferStr(query, "SELECT tableoid, oid, stxname, "
    8334              :                              "stxnamespace, stxowner, stxrelid, stxstattarget "
    8335              :                              "FROM pg_catalog.pg_statistic_ext");
    8336              : 
    8337          259 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    8338              : 
    8339          259 :     ntups = PQntuples(res);
    8340              : 
    8341          259 :     i_tableoid = PQfnumber(res, "tableoid");
    8342          259 :     i_oid = PQfnumber(res, "oid");
    8343          259 :     i_stxname = PQfnumber(res, "stxname");
    8344          259 :     i_stxnamespace = PQfnumber(res, "stxnamespace");
    8345          259 :     i_stxowner = PQfnumber(res, "stxowner");
    8346          259 :     i_stxrelid = PQfnumber(res, "stxrelid");
    8347          259 :     i_stattarget = PQfnumber(res, "stxstattarget");
    8348              : 
    8349          259 :     statsextinfo = pg_malloc_array(StatsExtInfo, ntups);
    8350              : 
    8351          467 :     for (i = 0; i < ntups; i++)
    8352              :     {
    8353          208 :         statsextinfo[i].dobj.objType = DO_STATSEXT;
    8354          208 :         statsextinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    8355          208 :         statsextinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    8356          208 :         AssignDumpId(&statsextinfo[i].dobj);
    8357          208 :         statsextinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_stxname));
    8358          416 :         statsextinfo[i].dobj.namespace =
    8359          208 :             findNamespace(atooid(PQgetvalue(res, i, i_stxnamespace)));
    8360          208 :         statsextinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_stxowner));
    8361          416 :         statsextinfo[i].stattable =
    8362          208 :             findTableByOid(atooid(PQgetvalue(res, i, i_stxrelid)));
    8363          208 :         if (PQgetisnull(res, i, i_stattarget))
    8364          163 :             statsextinfo[i].stattarget = -1;
    8365              :         else
    8366           45 :             statsextinfo[i].stattarget = atoi(PQgetvalue(res, i, i_stattarget));
    8367              : 
    8368              :         /* Decide whether we want to dump it */
    8369          208 :         selectDumpableStatisticsObject(&(statsextinfo[i]), fout);
    8370              : 
    8371          208 :         if (fout->dopt->dumpStatistics)
    8372          152 :             statsextinfo[i].dobj.components |= DUMP_COMPONENT_STATISTICS;
    8373              :     }
    8374              : 
    8375          259 :     PQclear(res);
    8376          259 :     destroyPQExpBuffer(query);
    8377              : }
    8378              : 
    8379              : /*
    8380              :  * getConstraints
    8381              :  *
    8382              :  * Get info about constraints on dumpable tables.
    8383              :  *
    8384              :  * Currently handles foreign keys only.
    8385              :  * Unique and primary key constraints are handled with indexes,
    8386              :  * while check constraints are processed in getTableAttrs().
    8387              :  */
    8388              : void
    8389          259 : getConstraints(Archive *fout, TableInfo tblinfo[], int numTables)
    8390              : {
    8391          259 :     PQExpBuffer query = createPQExpBuffer();
    8392          259 :     PQExpBuffer tbloids = createPQExpBuffer();
    8393              :     PGresult   *res;
    8394              :     int         ntups;
    8395              :     int         curtblindx;
    8396          259 :     TableInfo  *tbinfo = NULL;
    8397              :     ConstraintInfo *constrinfo;
    8398              :     int         i_contableoid,
    8399              :                 i_conoid,
    8400              :                 i_conrelid,
    8401              :                 i_conname,
    8402              :                 i_confrelid,
    8403              :                 i_conindid,
    8404              :                 i_condef;
    8405              : 
    8406              :     /*
    8407              :      * We want to perform just one query against pg_constraint.  However, we
    8408              :      * mustn't try to select every row of the catalog and then sort it out on
    8409              :      * the client side, because some of the server-side functions we need
    8410              :      * would be unsafe to apply to tables we don't have lock on.  Hence, we
    8411              :      * build an array of the OIDs of tables we care about (and now have lock
    8412              :      * on!), and use a WHERE clause to constrain which rows are selected.
    8413              :      */
    8414          259 :     appendPQExpBufferChar(tbloids, '{');
    8415        70160 :     for (int i = 0; i < numTables; i++)
    8416              :     {
    8417        69901 :         TableInfo  *tinfo = &tblinfo[i];
    8418              : 
    8419        69901 :         if (!(tinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
    8420        62320 :             continue;
    8421              : 
    8422              :         /* OK, we need info for this table */
    8423         7581 :         if (tbloids->len > 1) /* do we have more than the '{'? */
    8424         7403 :             appendPQExpBufferChar(tbloids, ',');
    8425         7581 :         appendPQExpBuffer(tbloids, "%u", tinfo->dobj.catId.oid);
    8426              :     }
    8427          259 :     appendPQExpBufferChar(tbloids, '}');
    8428              : 
    8429          259 :     appendPQExpBufferStr(query,
    8430              :                          "SELECT c.tableoid, c.oid, "
    8431              :                          "conrelid, conname, confrelid, ");
    8432          259 :     if (fout->remoteVersion >= 110000)
    8433          259 :         appendPQExpBufferStr(query, "conindid, ");
    8434              :     else
    8435            0 :         appendPQExpBufferStr(query, "0 AS conindid, ");
    8436          259 :     appendPQExpBuffer(query,
    8437              :                       "pg_catalog.pg_get_constraintdef(c.oid) AS condef\n"
    8438              :                       "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
    8439              :                       "JOIN pg_catalog.pg_constraint c ON (src.tbloid = c.conrelid)\n"
    8440              :                       "WHERE contype = 'f' ",
    8441              :                       tbloids->data);
    8442          259 :     if (fout->remoteVersion >= 110000)
    8443          259 :         appendPQExpBufferStr(query,
    8444              :                              "AND conparentid = 0 ");
    8445          259 :     appendPQExpBufferStr(query,
    8446              :                          "ORDER BY conrelid, conname");
    8447              : 
    8448          259 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    8449              : 
    8450          259 :     ntups = PQntuples(res);
    8451              : 
    8452          259 :     i_contableoid = PQfnumber(res, "tableoid");
    8453          259 :     i_conoid = PQfnumber(res, "oid");
    8454          259 :     i_conrelid = PQfnumber(res, "conrelid");
    8455          259 :     i_conname = PQfnumber(res, "conname");
    8456          259 :     i_confrelid = PQfnumber(res, "confrelid");
    8457          259 :     i_conindid = PQfnumber(res, "conindid");
    8458          259 :     i_condef = PQfnumber(res, "condef");
    8459              : 
    8460          259 :     constrinfo = pg_malloc_array(ConstraintInfo, ntups);
    8461              : 
    8462          259 :     curtblindx = -1;
    8463          490 :     for (int j = 0; j < ntups; j++)
    8464              :     {
    8465          231 :         Oid         conrelid = atooid(PQgetvalue(res, j, i_conrelid));
    8466              :         TableInfo  *reftable;
    8467              : 
    8468              :         /*
    8469              :          * Locate the associated TableInfo; we rely on tblinfo[] being in OID
    8470              :          * order.
    8471              :          */
    8472          231 :         if (tbinfo == NULL || tbinfo->dobj.catId.oid != conrelid)
    8473              :         {
    8474        14602 :             while (++curtblindx < numTables)
    8475              :             {
    8476        14602 :                 tbinfo = &tblinfo[curtblindx];
    8477        14602 :                 if (tbinfo->dobj.catId.oid == conrelid)
    8478          191 :                     break;
    8479              :             }
    8480          191 :             if (curtblindx >= numTables)
    8481            0 :                 pg_fatal("unrecognized table OID %u", conrelid);
    8482              :         }
    8483              : 
    8484          231 :         constrinfo[j].dobj.objType = DO_FK_CONSTRAINT;
    8485          231 :         constrinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_contableoid));
    8486          231 :         constrinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_conoid));
    8487          231 :         AssignDumpId(&constrinfo[j].dobj);
    8488          231 :         constrinfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_conname));
    8489          231 :         constrinfo[j].dobj.namespace = tbinfo->dobj.namespace;
    8490          231 :         constrinfo[j].contable = tbinfo;
    8491          231 :         constrinfo[j].condomain = NULL;
    8492          231 :         constrinfo[j].contype = 'f';
    8493          231 :         constrinfo[j].condef = pg_strdup(PQgetvalue(res, j, i_condef));
    8494          231 :         constrinfo[j].confrelid = atooid(PQgetvalue(res, j, i_confrelid));
    8495          231 :         constrinfo[j].conindex = 0;
    8496          231 :         constrinfo[j].condeferrable = false;
    8497          231 :         constrinfo[j].condeferred = false;
    8498          231 :         constrinfo[j].conislocal = true;
    8499          231 :         constrinfo[j].separate = true;
    8500              : 
    8501              :         /*
    8502              :          * Restoring an FK that points to a partitioned table requires that
    8503              :          * all partition indexes have been attached beforehand. Ensure that
    8504              :          * happens by making the constraint depend on each index partition
    8505              :          * attach object.
    8506              :          */
    8507          231 :         reftable = findTableByOid(constrinfo[j].confrelid);
    8508          231 :         if (reftable && reftable->relkind == RELKIND_PARTITIONED_TABLE)
    8509              :         {
    8510           30 :             Oid         indexOid = atooid(PQgetvalue(res, j, i_conindid));
    8511              : 
    8512           30 :             if (indexOid != InvalidOid)
    8513              :             {
    8514           30 :                 for (int k = 0; k < reftable->numIndexes; k++)
    8515              :                 {
    8516              :                     IndxInfo   *refidx;
    8517              : 
    8518              :                     /* not our index? */
    8519           30 :                     if (reftable->indexes[k].dobj.catId.oid != indexOid)
    8520            0 :                         continue;
    8521              : 
    8522           30 :                     refidx = &reftable->indexes[k];
    8523           30 :                     addConstrChildIdxDeps(&constrinfo[j].dobj, refidx);
    8524           30 :                     break;
    8525              :                 }
    8526              :             }
    8527              :         }
    8528              :     }
    8529              : 
    8530          259 :     PQclear(res);
    8531              : 
    8532          259 :     destroyPQExpBuffer(query);
    8533          259 :     destroyPQExpBuffer(tbloids);
    8534          259 : }
    8535              : 
    8536              : /*
    8537              :  * addConstrChildIdxDeps
    8538              :  *
    8539              :  * Recursive subroutine for getConstraints
    8540              :  *
    8541              :  * Given an object representing a foreign key constraint and an index on the
    8542              :  * partitioned table it references, mark the constraint object as dependent
    8543              :  * on the DO_INDEX_ATTACH object of each index partition, recursively
    8544              :  * drilling down to their partitions if any.  This ensures that the FK is not
    8545              :  * restored until the index is fully marked valid.
    8546              :  */
    8547              : static void
    8548           55 : addConstrChildIdxDeps(DumpableObject *dobj, const IndxInfo *refidx)
    8549              : {
    8550              :     SimplePtrListCell *cell;
    8551              : 
    8552              :     Assert(dobj->objType == DO_FK_CONSTRAINT);
    8553              : 
    8554          185 :     for (cell = refidx->partattaches.head; cell; cell = cell->next)
    8555              :     {
    8556          130 :         IndexAttachInfo *attach = (IndexAttachInfo *) cell->ptr;
    8557              : 
    8558          130 :         addObjectDependency(dobj, attach->dobj.dumpId);
    8559              : 
    8560          130 :         if (attach->partitionIdx->partattaches.head != NULL)
    8561           25 :             addConstrChildIdxDeps(dobj, attach->partitionIdx);
    8562              :     }
    8563           55 : }
    8564              : 
    8565              : /*
    8566              :  * getDomainConstraints
    8567              :  *
    8568              :  * Get info about constraints on a domain.
    8569              :  */
    8570              : static void
    8571          158 : getDomainConstraints(Archive *fout, TypeInfo *tyinfo)
    8572              : {
    8573              :     ConstraintInfo *constrinfo;
    8574          158 :     PQExpBuffer query = createPQExpBuffer();
    8575              :     PGresult   *res;
    8576              :     int         i_tableoid,
    8577              :                 i_oid,
    8578              :                 i_conname,
    8579              :                 i_consrc,
    8580              :                 i_convalidated,
    8581              :                 i_contype;
    8582              :     int         ntups;
    8583              : 
    8584          158 :     if (!fout->is_prepared[PREPQUERY_GETDOMAINCONSTRAINTS])
    8585              :     {
    8586              :         /*
    8587              :          * Set up query for constraint-specific details.  For servers 17 and
    8588              :          * up, domains have constraints of type 'n' as well as 'c', otherwise
    8589              :          * just the latter.
    8590              :          */
    8591           43 :         appendPQExpBuffer(query,
    8592              :                           "PREPARE getDomainConstraints(pg_catalog.oid) AS\n"
    8593              :                           "SELECT tableoid, oid, conname, "
    8594              :                           "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
    8595              :                           "convalidated, contype "
    8596              :                           "FROM pg_catalog.pg_constraint "
    8597              :                           "WHERE contypid = $1 AND contype IN (%s) "
    8598              :                           "ORDER BY conname",
    8599           43 :                           fout->remoteVersion < 170000 ? "'c'" : "'c', 'n'");
    8600              : 
    8601           43 :         ExecuteSqlStatement(fout, query->data);
    8602              : 
    8603           43 :         fout->is_prepared[PREPQUERY_GETDOMAINCONSTRAINTS] = true;
    8604              :     }
    8605              : 
    8606          158 :     printfPQExpBuffer(query,
    8607              :                       "EXECUTE getDomainConstraints('%u')",
    8608              :                       tyinfo->dobj.catId.oid);
    8609              : 
    8610          158 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    8611              : 
    8612          158 :     ntups = PQntuples(res);
    8613              : 
    8614          158 :     i_tableoid = PQfnumber(res, "tableoid");
    8615          158 :     i_oid = PQfnumber(res, "oid");
    8616          158 :     i_conname = PQfnumber(res, "conname");
    8617          158 :     i_consrc = PQfnumber(res, "consrc");
    8618          158 :     i_convalidated = PQfnumber(res, "convalidated");
    8619          158 :     i_contype = PQfnumber(res, "contype");
    8620              : 
    8621          158 :     constrinfo = pg_malloc_array(ConstraintInfo, ntups);
    8622          158 :     tyinfo->domChecks = constrinfo;
    8623              : 
    8624              :     /* 'i' tracks result rows; 'j' counts CHECK constraints */
    8625          324 :     for (int i = 0, j = 0; i < ntups; i++)
    8626              :     {
    8627          166 :         bool        validated = PQgetvalue(res, i, i_convalidated)[0] == 't';
    8628          166 :         char        contype = (PQgetvalue(res, i, i_contype))[0];
    8629              :         ConstraintInfo *constraint;
    8630              : 
    8631          166 :         if (contype == CONSTRAINT_CHECK)
    8632              :         {
    8633          113 :             constraint = &constrinfo[j++];
    8634          113 :             tyinfo->nDomChecks++;
    8635              :         }
    8636              :         else
    8637              :         {
    8638              :             Assert(contype == CONSTRAINT_NOTNULL);
    8639              :             Assert(tyinfo->notnull == NULL);
    8640              :             /* use last item in array for the not-null constraint */
    8641           53 :             tyinfo->notnull = &(constrinfo[ntups - 1]);
    8642           53 :             constraint = tyinfo->notnull;
    8643              :         }
    8644              : 
    8645          166 :         constraint->dobj.objType = DO_CONSTRAINT;
    8646          166 :         constraint->dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    8647          166 :         constraint->dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    8648          166 :         AssignDumpId(&(constraint->dobj));
    8649          166 :         constraint->dobj.name = pg_strdup(PQgetvalue(res, i, i_conname));
    8650          166 :         constraint->dobj.namespace = tyinfo->dobj.namespace;
    8651          166 :         constraint->contable = NULL;
    8652          166 :         constraint->condomain = tyinfo;
    8653          166 :         constraint->contype = contype;
    8654          166 :         constraint->condef = pg_strdup(PQgetvalue(res, i, i_consrc));
    8655          166 :         constraint->confrelid = InvalidOid;
    8656          166 :         constraint->conindex = 0;
    8657          166 :         constraint->condeferrable = false;
    8658          166 :         constraint->condeferred = false;
    8659          166 :         constraint->conislocal = true;
    8660              : 
    8661          166 :         constraint->separate = !validated;
    8662              : 
    8663              :         /*
    8664              :          * Make the domain depend on the constraint, ensuring it won't be
    8665              :          * output till any constraint dependencies are OK.  If the constraint
    8666              :          * has not been validated, it's going to be dumped after the domain
    8667              :          * anyway, so this doesn't matter.
    8668              :          */
    8669          166 :         if (validated)
    8670          161 :             addObjectDependency(&tyinfo->dobj, constraint->dobj.dumpId);
    8671              :     }
    8672              : 
    8673          158 :     PQclear(res);
    8674              : 
    8675          158 :     destroyPQExpBuffer(query);
    8676          158 : }
    8677              : 
    8678              : /*
    8679              :  * getRules
    8680              :  *    get basic information about every rule in the system
    8681              :  */
    8682              : void
    8683          259 : getRules(Archive *fout)
    8684              : {
    8685              :     PGresult   *res;
    8686              :     int         ntups;
    8687              :     int         i;
    8688          259 :     PQExpBuffer query = createPQExpBuffer();
    8689              :     RuleInfo   *ruleinfo;
    8690              :     int         i_tableoid;
    8691              :     int         i_oid;
    8692              :     int         i_rulename;
    8693              :     int         i_ruletable;
    8694              :     int         i_ev_type;
    8695              :     int         i_is_instead;
    8696              :     int         i_ev_enabled;
    8697              : 
    8698          259 :     appendPQExpBufferStr(query, "SELECT "
    8699              :                          "tableoid, oid, rulename, "
    8700              :                          "ev_class AS ruletable, ev_type, is_instead, "
    8701              :                          "ev_enabled "
    8702              :                          "FROM pg_rewrite "
    8703              :                          "ORDER BY oid");
    8704              : 
    8705          259 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    8706              : 
    8707          259 :     ntups = PQntuples(res);
    8708              : 
    8709          259 :     ruleinfo = pg_malloc_array(RuleInfo, ntups);
    8710              : 
    8711          259 :     i_tableoid = PQfnumber(res, "tableoid");
    8712          259 :     i_oid = PQfnumber(res, "oid");
    8713          259 :     i_rulename = PQfnumber(res, "rulename");
    8714          259 :     i_ruletable = PQfnumber(res, "ruletable");
    8715          259 :     i_ev_type = PQfnumber(res, "ev_type");
    8716          259 :     i_is_instead = PQfnumber(res, "is_instead");
    8717          259 :     i_ev_enabled = PQfnumber(res, "ev_enabled");
    8718              : 
    8719        43122 :     for (i = 0; i < ntups; i++)
    8720              :     {
    8721              :         Oid         ruletableoid;
    8722              : 
    8723        42863 :         ruleinfo[i].dobj.objType = DO_RULE;
    8724        42863 :         ruleinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    8725        42863 :         ruleinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    8726        42863 :         AssignDumpId(&ruleinfo[i].dobj);
    8727        42863 :         ruleinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_rulename));
    8728        42863 :         ruletableoid = atooid(PQgetvalue(res, i, i_ruletable));
    8729        42863 :         ruleinfo[i].ruletable = findTableByOid(ruletableoid);
    8730        42863 :         if (ruleinfo[i].ruletable == NULL)
    8731            0 :             pg_fatal("failed sanity check, parent table with OID %u of pg_rewrite entry with OID %u not found",
    8732              :                      ruletableoid, ruleinfo[i].dobj.catId.oid);
    8733        42863 :         ruleinfo[i].dobj.namespace = ruleinfo[i].ruletable->dobj.namespace;
    8734        42863 :         ruleinfo[i].dobj.dump = ruleinfo[i].ruletable->dobj.dump;
    8735        42863 :         ruleinfo[i].ev_type = *(PQgetvalue(res, i, i_ev_type));
    8736        42863 :         ruleinfo[i].is_instead = *(PQgetvalue(res, i, i_is_instead)) == 't';
    8737        42863 :         ruleinfo[i].ev_enabled = *(PQgetvalue(res, i, i_ev_enabled));
    8738        42863 :         if (ruleinfo[i].ruletable)
    8739              :         {
    8740              :             /*
    8741              :              * If the table is a view or materialized view, force its ON
    8742              :              * SELECT rule to be sorted before the view itself --- this
    8743              :              * ensures that any dependencies for the rule affect the table's
    8744              :              * positioning. Other rules are forced to appear after their
    8745              :              * table.
    8746              :              */
    8747        42863 :             if ((ruleinfo[i].ruletable->relkind == RELKIND_VIEW ||
    8748          699 :                  ruleinfo[i].ruletable->relkind == RELKIND_MATVIEW) &&
    8749        42632 :                 ruleinfo[i].ev_type == '1' && ruleinfo[i].is_instead)
    8750              :             {
    8751        42072 :                 addObjectDependency(&ruleinfo[i].ruletable->dobj,
    8752        42072 :                                     ruleinfo[i].dobj.dumpId);
    8753              :                 /* We'll merge the rule into CREATE VIEW, if possible */
    8754        42072 :                 ruleinfo[i].separate = false;
    8755              :             }
    8756              :             else
    8757              :             {
    8758          791 :                 addObjectDependency(&ruleinfo[i].dobj,
    8759          791 :                                     ruleinfo[i].ruletable->dobj.dumpId);
    8760          791 :                 ruleinfo[i].separate = true;
    8761              :             }
    8762              :         }
    8763              :         else
    8764            0 :             ruleinfo[i].separate = true;
    8765              :     }
    8766              : 
    8767          259 :     PQclear(res);
    8768              : 
    8769          259 :     destroyPQExpBuffer(query);
    8770          259 : }
    8771              : 
    8772              : /*
    8773              :  * getTriggers
    8774              :  *    get information about every trigger on a dumpable table
    8775              :  *
    8776              :  * Note: trigger data is not returned directly to the caller, but it
    8777              :  * does get entered into the DumpableObject tables.
    8778              :  */
    8779              : void
    8780          259 : getTriggers(Archive *fout, TableInfo tblinfo[], int numTables)
    8781              : {
    8782          259 :     PQExpBuffer query = createPQExpBuffer();
    8783          259 :     PQExpBuffer tbloids = createPQExpBuffer();
    8784              :     PGresult   *res;
    8785              :     int         ntups;
    8786              :     int         curtblindx;
    8787              :     TriggerInfo *tginfo;
    8788              :     int         i_tableoid,
    8789              :                 i_oid,
    8790              :                 i_tgrelid,
    8791              :                 i_tgname,
    8792              :                 i_tgenabled,
    8793              :                 i_tgispartition,
    8794              :                 i_tgdef;
    8795              : 
    8796              :     /*
    8797              :      * We want to perform just one query against pg_trigger.  However, we
    8798              :      * mustn't try to select every row of the catalog and then sort it out on
    8799              :      * the client side, because some of the server-side functions we need
    8800              :      * would be unsafe to apply to tables we don't have lock on.  Hence, we
    8801              :      * build an array of the OIDs of tables we care about (and now have lock
    8802              :      * on!), and use a WHERE clause to constrain which rows are selected.
    8803              :      */
    8804          259 :     appendPQExpBufferChar(tbloids, '{');
    8805        70160 :     for (int i = 0; i < numTables; i++)
    8806              :     {
    8807        69901 :         TableInfo  *tbinfo = &tblinfo[i];
    8808              : 
    8809        69901 :         if (!tbinfo->hastriggers ||
    8810         1233 :             !(tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
    8811        68964 :             continue;
    8812              : 
    8813              :         /* OK, we need info for this table */
    8814          937 :         if (tbloids->len > 1) /* do we have more than the '{'? */
    8815          886 :             appendPQExpBufferChar(tbloids, ',');
    8816          937 :         appendPQExpBuffer(tbloids, "%u", tbinfo->dobj.catId.oid);
    8817              :     }
    8818          259 :     appendPQExpBufferChar(tbloids, '}');
    8819              : 
    8820          259 :     if (fout->remoteVersion >= 150000)
    8821              :     {
    8822              :         /*
    8823              :          * NB: think not to use pretty=true in pg_get_triggerdef.  It could
    8824              :          * result in non-forward-compatible dumps of WHEN clauses due to
    8825              :          * under-parenthesization.
    8826              :          *
    8827              :          * NB: We need to see partition triggers in case the tgenabled flag
    8828              :          * has been changed from the parent.
    8829              :          */
    8830          259 :         appendPQExpBuffer(query,
    8831              :                           "SELECT t.tgrelid, t.tgname, "
    8832              :                           "pg_catalog.pg_get_triggerdef(t.oid, false) AS tgdef, "
    8833              :                           "t.tgenabled, t.tableoid, t.oid, "
    8834              :                           "t.tgparentid <> 0 AS tgispartition\n"
    8835              :                           "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
    8836              :                           "JOIN pg_catalog.pg_trigger t ON (src.tbloid = t.tgrelid) "
    8837              :                           "LEFT JOIN pg_catalog.pg_trigger u ON (u.oid = t.tgparentid) "
    8838              :                           "WHERE ((NOT t.tgisinternal AND t.tgparentid = 0) "
    8839              :                           "OR t.tgenabled != u.tgenabled) "
    8840              :                           "ORDER BY t.tgrelid, t.tgname",
    8841              :                           tbloids->data);
    8842              :     }
    8843            0 :     else if (fout->remoteVersion >= 130000)
    8844              :     {
    8845              :         /*
    8846              :          * NB: think not to use pretty=true in pg_get_triggerdef.  It could
    8847              :          * result in non-forward-compatible dumps of WHEN clauses due to
    8848              :          * under-parenthesization.
    8849              :          *
    8850              :          * NB: We need to see tgisinternal triggers in partitions, in case the
    8851              :          * tgenabled flag has been changed from the parent.
    8852              :          */
    8853            0 :         appendPQExpBuffer(query,
    8854              :                           "SELECT t.tgrelid, t.tgname, "
    8855              :                           "pg_catalog.pg_get_triggerdef(t.oid, false) AS tgdef, "
    8856              :                           "t.tgenabled, t.tableoid, t.oid, t.tgisinternal as tgispartition\n"
    8857              :                           "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
    8858              :                           "JOIN pg_catalog.pg_trigger t ON (src.tbloid = t.tgrelid) "
    8859              :                           "LEFT JOIN pg_catalog.pg_trigger u ON (u.oid = t.tgparentid) "
    8860              :                           "WHERE (NOT t.tgisinternal OR t.tgenabled != u.tgenabled) "
    8861              :                           "ORDER BY t.tgrelid, t.tgname",
    8862              :                           tbloids->data);
    8863              :     }
    8864            0 :     else if (fout->remoteVersion >= 110000)
    8865              :     {
    8866              :         /*
    8867              :          * NB: We need to see tgisinternal triggers in partitions, in case the
    8868              :          * tgenabled flag has been changed from the parent. No tgparentid in
    8869              :          * version 11-12, so we have to match them via pg_depend.
    8870              :          *
    8871              :          * See above about pretty=true in pg_get_triggerdef.
    8872              :          */
    8873            0 :         appendPQExpBuffer(query,
    8874              :                           "SELECT t.tgrelid, t.tgname, "
    8875              :                           "pg_catalog.pg_get_triggerdef(t.oid, false) AS tgdef, "
    8876              :                           "t.tgenabled, t.tableoid, t.oid, t.tgisinternal as tgispartition "
    8877              :                           "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
    8878              :                           "JOIN pg_catalog.pg_trigger t ON (src.tbloid = t.tgrelid) "
    8879              :                           "LEFT JOIN pg_catalog.pg_depend AS d ON "
    8880              :                           " d.classid = 'pg_catalog.pg_trigger'::pg_catalog.regclass AND "
    8881              :                           " d.refclassid = 'pg_catalog.pg_trigger'::pg_catalog.regclass AND "
    8882              :                           " d.objid = t.oid "
    8883              :                           "LEFT JOIN pg_catalog.pg_trigger AS pt ON pt.oid = refobjid "
    8884              :                           "WHERE (NOT t.tgisinternal OR t.tgenabled != pt.tgenabled) "
    8885              :                           "ORDER BY t.tgrelid, t.tgname",
    8886              :                           tbloids->data);
    8887              :     }
    8888              :     else
    8889              :     {
    8890              :         /* See above about pretty=true in pg_get_triggerdef */
    8891            0 :         appendPQExpBuffer(query,
    8892              :                           "SELECT t.tgrelid, t.tgname, "
    8893              :                           "pg_catalog.pg_get_triggerdef(t.oid, false) AS tgdef, "
    8894              :                           "t.tgenabled, false as tgispartition, "
    8895              :                           "t.tableoid, t.oid "
    8896              :                           "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
    8897              :                           "JOIN pg_catalog.pg_trigger t ON (src.tbloid = t.tgrelid) "
    8898              :                           "WHERE NOT tgisinternal "
    8899              :                           "ORDER BY t.tgrelid, t.tgname",
    8900              :                           tbloids->data);
    8901              :     }
    8902              : 
    8903          259 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    8904              : 
    8905          259 :     ntups = PQntuples(res);
    8906              : 
    8907          259 :     i_tableoid = PQfnumber(res, "tableoid");
    8908          259 :     i_oid = PQfnumber(res, "oid");
    8909          259 :     i_tgrelid = PQfnumber(res, "tgrelid");
    8910          259 :     i_tgname = PQfnumber(res, "tgname");
    8911          259 :     i_tgenabled = PQfnumber(res, "tgenabled");
    8912          259 :     i_tgispartition = PQfnumber(res, "tgispartition");
    8913          259 :     i_tgdef = PQfnumber(res, "tgdef");
    8914              : 
    8915          259 :     tginfo = pg_malloc_array(TriggerInfo, ntups);
    8916              : 
    8917              :     /*
    8918              :      * Outer loop iterates once per table, not once per row.  Incrementing of
    8919              :      * j is handled by the inner loop.
    8920              :      */
    8921          259 :     curtblindx = -1;
    8922          565 :     for (int j = 0; j < ntups;)
    8923              :     {
    8924          306 :         Oid         tgrelid = atooid(PQgetvalue(res, j, i_tgrelid));
    8925          306 :         TableInfo  *tbinfo = NULL;
    8926              :         int         numtrigs;
    8927              : 
    8928              :         /* Count rows for this table */
    8929          523 :         for (numtrigs = 1; numtrigs < ntups - j; numtrigs++)
    8930          472 :             if (atooid(PQgetvalue(res, j + numtrigs, i_tgrelid)) != tgrelid)
    8931          255 :                 break;
    8932              : 
    8933              :         /*
    8934              :          * Locate the associated TableInfo; we rely on tblinfo[] being in OID
    8935              :          * order.
    8936              :          */
    8937        17245 :         while (++curtblindx < numTables)
    8938              :         {
    8939        17245 :             tbinfo = &tblinfo[curtblindx];
    8940        17245 :             if (tbinfo->dobj.catId.oid == tgrelid)
    8941          306 :                 break;
    8942              :         }
    8943          306 :         if (curtblindx >= numTables)
    8944            0 :             pg_fatal("unrecognized table OID %u", tgrelid);
    8945              : 
    8946              :         /* Save data for this table */
    8947          306 :         tbinfo->triggers = tginfo + j;
    8948          306 :         tbinfo->numTriggers = numtrigs;
    8949              : 
    8950          829 :         for (int c = 0; c < numtrigs; c++, j++)
    8951              :         {
    8952          523 :             tginfo[j].dobj.objType = DO_TRIGGER;
    8953          523 :             tginfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
    8954          523 :             tginfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
    8955          523 :             AssignDumpId(&tginfo[j].dobj);
    8956          523 :             tginfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_tgname));
    8957          523 :             tginfo[j].dobj.namespace = tbinfo->dobj.namespace;
    8958          523 :             tginfo[j].tgtable = tbinfo;
    8959          523 :             tginfo[j].tgenabled = *(PQgetvalue(res, j, i_tgenabled));
    8960          523 :             tginfo[j].tgispartition = *(PQgetvalue(res, j, i_tgispartition)) == 't';
    8961          523 :             tginfo[j].tgdef = pg_strdup(PQgetvalue(res, j, i_tgdef));
    8962              :         }
    8963              :     }
    8964              : 
    8965          259 :     PQclear(res);
    8966              : 
    8967          259 :     destroyPQExpBuffer(query);
    8968          259 :     destroyPQExpBuffer(tbloids);
    8969          259 : }
    8970              : 
    8971              : /*
    8972              :  * getEventTriggers
    8973              :  *    get information about event triggers
    8974              :  */
    8975              : void
    8976          259 : getEventTriggers(Archive *fout)
    8977              : {
    8978              :     int         i;
    8979              :     PQExpBuffer query;
    8980              :     PGresult   *res;
    8981              :     EventTriggerInfo *evtinfo;
    8982              :     int         i_tableoid,
    8983              :                 i_oid,
    8984              :                 i_evtname,
    8985              :                 i_evtevent,
    8986              :                 i_evtowner,
    8987              :                 i_evttags,
    8988              :                 i_evtfname,
    8989              :                 i_evtenabled;
    8990              :     int         ntups;
    8991              : 
    8992              :     /* Before 9.3, there are no event triggers */
    8993          259 :     if (fout->remoteVersion < 90300)
    8994            0 :         return;
    8995              : 
    8996          259 :     query = createPQExpBuffer();
    8997              : 
    8998          259 :     appendPQExpBufferStr(query,
    8999              :                          "SELECT e.tableoid, e.oid, evtname, evtenabled, "
    9000              :                          "evtevent, evtowner, "
    9001              :                          "array_to_string(array("
    9002              :                          "select quote_literal(x) "
    9003              :                          " from unnest(evttags) as t(x)), ', ') as evttags, "
    9004              :                          "e.evtfoid::regproc as evtfname "
    9005              :                          "FROM pg_event_trigger e "
    9006              :                          "ORDER BY e.oid");
    9007              : 
    9008          259 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    9009              : 
    9010          259 :     ntups = PQntuples(res);
    9011              : 
    9012          259 :     evtinfo = pg_malloc_array(EventTriggerInfo, ntups);
    9013              : 
    9014          259 :     i_tableoid = PQfnumber(res, "tableoid");
    9015          259 :     i_oid = PQfnumber(res, "oid");
    9016          259 :     i_evtname = PQfnumber(res, "evtname");
    9017          259 :     i_evtevent = PQfnumber(res, "evtevent");
    9018          259 :     i_evtowner = PQfnumber(res, "evtowner");
    9019          259 :     i_evttags = PQfnumber(res, "evttags");
    9020          259 :     i_evtfname = PQfnumber(res, "evtfname");
    9021          259 :     i_evtenabled = PQfnumber(res, "evtenabled");
    9022              : 
    9023          311 :     for (i = 0; i < ntups; i++)
    9024              :     {
    9025           52 :         evtinfo[i].dobj.objType = DO_EVENT_TRIGGER;
    9026           52 :         evtinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    9027           52 :         evtinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    9028           52 :         AssignDumpId(&evtinfo[i].dobj);
    9029           52 :         evtinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_evtname));
    9030           52 :         evtinfo[i].evtname = pg_strdup(PQgetvalue(res, i, i_evtname));
    9031           52 :         evtinfo[i].evtevent = pg_strdup(PQgetvalue(res, i, i_evtevent));
    9032           52 :         evtinfo[i].evtowner = getRoleName(PQgetvalue(res, i, i_evtowner));
    9033           52 :         evtinfo[i].evttags = pg_strdup(PQgetvalue(res, i, i_evttags));
    9034           52 :         evtinfo[i].evtfname = pg_strdup(PQgetvalue(res, i, i_evtfname));
    9035           52 :         evtinfo[i].evtenabled = *(PQgetvalue(res, i, i_evtenabled));
    9036              : 
    9037              :         /* Decide whether we want to dump it */
    9038           52 :         selectDumpableObject(&(evtinfo[i].dobj), fout);
    9039              :     }
    9040              : 
    9041          259 :     PQclear(res);
    9042              : 
    9043          259 :     destroyPQExpBuffer(query);
    9044              : }
    9045              : 
    9046              : /*
    9047              :  * getProcLangs
    9048              :  *    get basic information about every procedural language in the system
    9049              :  *
    9050              :  * NB: this must run after getFuncs() because we assume we can do
    9051              :  * findFuncByOid().
    9052              :  */
    9053              : void
    9054          259 : getProcLangs(Archive *fout)
    9055              : {
    9056              :     PGresult   *res;
    9057              :     int         ntups;
    9058              :     int         i;
    9059          259 :     PQExpBuffer query = createPQExpBuffer();
    9060              :     ProcLangInfo *planginfo;
    9061              :     int         i_tableoid;
    9062              :     int         i_oid;
    9063              :     int         i_lanname;
    9064              :     int         i_lanpltrusted;
    9065              :     int         i_lanplcallfoid;
    9066              :     int         i_laninline;
    9067              :     int         i_lanvalidator;
    9068              :     int         i_lanacl;
    9069              :     int         i_acldefault;
    9070              :     int         i_lanowner;
    9071              : 
    9072          259 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, "
    9073              :                          "lanname, lanpltrusted, lanplcallfoid, "
    9074              :                          "laninline, lanvalidator, "
    9075              :                          "lanacl, "
    9076              :                          "acldefault('l', lanowner) AS acldefault, "
    9077              :                          "lanowner "
    9078              :                          "FROM pg_language "
    9079              :                          "WHERE lanispl "
    9080              :                          "ORDER BY oid");
    9081              : 
    9082          259 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    9083              : 
    9084          259 :     ntups = PQntuples(res);
    9085              : 
    9086          259 :     planginfo = pg_malloc_array(ProcLangInfo, ntups);
    9087              : 
    9088          259 :     i_tableoid = PQfnumber(res, "tableoid");
    9089          259 :     i_oid = PQfnumber(res, "oid");
    9090          259 :     i_lanname = PQfnumber(res, "lanname");
    9091          259 :     i_lanpltrusted = PQfnumber(res, "lanpltrusted");
    9092          259 :     i_lanplcallfoid = PQfnumber(res, "lanplcallfoid");
    9093          259 :     i_laninline = PQfnumber(res, "laninline");
    9094          259 :     i_lanvalidator = PQfnumber(res, "lanvalidator");
    9095          259 :     i_lanacl = PQfnumber(res, "lanacl");
    9096          259 :     i_acldefault = PQfnumber(res, "acldefault");
    9097          259 :     i_lanowner = PQfnumber(res, "lanowner");
    9098              : 
    9099          563 :     for (i = 0; i < ntups; i++)
    9100              :     {
    9101          304 :         planginfo[i].dobj.objType = DO_PROCLANG;
    9102          304 :         planginfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    9103          304 :         planginfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    9104          304 :         AssignDumpId(&planginfo[i].dobj);
    9105              : 
    9106          304 :         planginfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_lanname));
    9107          304 :         planginfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_lanacl));
    9108          304 :         planginfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
    9109          304 :         planginfo[i].dacl.privtype = 0;
    9110          304 :         planginfo[i].dacl.initprivs = NULL;
    9111          304 :         planginfo[i].lanpltrusted = *(PQgetvalue(res, i, i_lanpltrusted)) == 't';
    9112          304 :         planginfo[i].lanplcallfoid = atooid(PQgetvalue(res, i, i_lanplcallfoid));
    9113          304 :         planginfo[i].laninline = atooid(PQgetvalue(res, i, i_laninline));
    9114          304 :         planginfo[i].lanvalidator = atooid(PQgetvalue(res, i, i_lanvalidator));
    9115          304 :         planginfo[i].lanowner = getRoleName(PQgetvalue(res, i, i_lanowner));
    9116              : 
    9117              :         /* Decide whether we want to dump it */
    9118          304 :         selectDumpableProcLang(&(planginfo[i]), fout);
    9119              : 
    9120              :         /* Mark whether language has an ACL */
    9121          304 :         if (!PQgetisnull(res, i, i_lanacl))
    9122           45 :             planginfo[i].dobj.components |= DUMP_COMPONENT_ACL;
    9123              :     }
    9124              : 
    9125          259 :     PQclear(res);
    9126              : 
    9127          259 :     destroyPQExpBuffer(query);
    9128          259 : }
    9129              : 
    9130              : /*
    9131              :  * getCasts
    9132              :  *    get basic information about most casts in the system
    9133              :  *
    9134              :  * Skip casts from a range to its multirange, since we'll create those
    9135              :  * automatically.
    9136              :  */
    9137              : void
    9138          259 : getCasts(Archive *fout)
    9139              : {
    9140              :     PGresult   *res;
    9141              :     int         ntups;
    9142              :     int         i;
    9143          259 :     PQExpBuffer query = createPQExpBuffer();
    9144              :     CastInfo   *castinfo;
    9145              :     int         i_tableoid;
    9146              :     int         i_oid;
    9147              :     int         i_castsource;
    9148              :     int         i_casttarget;
    9149              :     int         i_castfunc;
    9150              :     int         i_castcontext;
    9151              :     int         i_castmethod;
    9152              : 
    9153          259 :     if (fout->remoteVersion >= 140000)
    9154              :     {
    9155          259 :         appendPQExpBufferStr(query, "SELECT tableoid, oid, "
    9156              :                              "castsource, casttarget, castfunc, castcontext, "
    9157              :                              "castmethod "
    9158              :                              "FROM pg_cast c "
    9159              :                              "WHERE NOT EXISTS ( "
    9160              :                              "SELECT 1 FROM pg_range r "
    9161              :                              "WHERE c.castsource = r.rngtypid "
    9162              :                              "AND c.casttarget = r.rngmultitypid "
    9163              :                              ") "
    9164              :                              "ORDER BY 3,4");
    9165              :     }
    9166              :     else
    9167              :     {
    9168            0 :         appendPQExpBufferStr(query, "SELECT tableoid, oid, "
    9169              :                              "castsource, casttarget, castfunc, castcontext, "
    9170              :                              "castmethod "
    9171              :                              "FROM pg_cast ORDER BY 3,4");
    9172              :     }
    9173              : 
    9174          259 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    9175              : 
    9176          259 :     ntups = PQntuples(res);
    9177              : 
    9178          259 :     castinfo = pg_malloc_array(CastInfo, ntups);
    9179              : 
    9180          259 :     i_tableoid = PQfnumber(res, "tableoid");
    9181          259 :     i_oid = PQfnumber(res, "oid");
    9182          259 :     i_castsource = PQfnumber(res, "castsource");
    9183          259 :     i_casttarget = PQfnumber(res, "casttarget");
    9184          259 :     i_castfunc = PQfnumber(res, "castfunc");
    9185          259 :     i_castcontext = PQfnumber(res, "castcontext");
    9186          259 :     i_castmethod = PQfnumber(res, "castmethod");
    9187              : 
    9188        63283 :     for (i = 0; i < ntups; i++)
    9189              :     {
    9190              :         PQExpBufferData namebuf;
    9191              :         TypeInfo   *sTypeInfo;
    9192              :         TypeInfo   *tTypeInfo;
    9193              : 
    9194        63024 :         castinfo[i].dobj.objType = DO_CAST;
    9195        63024 :         castinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    9196        63024 :         castinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    9197        63024 :         AssignDumpId(&castinfo[i].dobj);
    9198        63024 :         castinfo[i].castsource = atooid(PQgetvalue(res, i, i_castsource));
    9199        63024 :         castinfo[i].casttarget = atooid(PQgetvalue(res, i, i_casttarget));
    9200        63024 :         castinfo[i].castfunc = atooid(PQgetvalue(res, i, i_castfunc));
    9201        63024 :         castinfo[i].castcontext = *(PQgetvalue(res, i, i_castcontext));
    9202        63024 :         castinfo[i].castmethod = *(PQgetvalue(res, i, i_castmethod));
    9203              : 
    9204              :         /*
    9205              :          * Try to name cast as concatenation of typnames.  This is only used
    9206              :          * for purposes of sorting.  If we fail to find either type, the name
    9207              :          * will be an empty string.
    9208              :          */
    9209        63024 :         initPQExpBuffer(&namebuf);
    9210        63024 :         sTypeInfo = findTypeByOid(castinfo[i].castsource);
    9211        63024 :         tTypeInfo = findTypeByOid(castinfo[i].casttarget);
    9212        63024 :         if (sTypeInfo && tTypeInfo)
    9213        63024 :             appendPQExpBuffer(&namebuf, "%s %s",
    9214              :                               sTypeInfo->dobj.name, tTypeInfo->dobj.name);
    9215        63024 :         castinfo[i].dobj.name = namebuf.data;
    9216              : 
    9217              :         /* Decide whether we want to dump it */
    9218        63024 :         selectDumpableCast(&(castinfo[i]), fout);
    9219              :     }
    9220              : 
    9221          259 :     PQclear(res);
    9222              : 
    9223          259 :     destroyPQExpBuffer(query);
    9224          259 : }
    9225              : 
    9226              : static char *
    9227           88 : get_language_name(Archive *fout, Oid langid)
    9228              : {
    9229              :     PQExpBuffer query;
    9230              :     PGresult   *res;
    9231              :     char       *lanname;
    9232              : 
    9233           88 :     query = createPQExpBuffer();
    9234           88 :     appendPQExpBuffer(query, "SELECT lanname FROM pg_language WHERE oid = %u", langid);
    9235           88 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
    9236           88 :     lanname = pg_strdup(fmtId(PQgetvalue(res, 0, 0)));
    9237           88 :     destroyPQExpBuffer(query);
    9238           88 :     PQclear(res);
    9239              : 
    9240           88 :     return lanname;
    9241              : }
    9242              : 
    9243              : /*
    9244              :  * getTransforms
    9245              :  *    get basic information about every transform in the system
    9246              :  */
    9247              : void
    9248          259 : getTransforms(Archive *fout)
    9249              : {
    9250              :     PGresult   *res;
    9251              :     int         ntups;
    9252              :     int         i;
    9253              :     PQExpBuffer query;
    9254              :     TransformInfo *transforminfo;
    9255              :     int         i_tableoid;
    9256              :     int         i_oid;
    9257              :     int         i_trftype;
    9258              :     int         i_trflang;
    9259              :     int         i_trffromsql;
    9260              :     int         i_trftosql;
    9261              : 
    9262              :     /* Transforms didn't exist pre-9.5 */
    9263          259 :     if (fout->remoteVersion < 90500)
    9264            0 :         return;
    9265              : 
    9266          259 :     query = createPQExpBuffer();
    9267              : 
    9268          259 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, "
    9269              :                          "trftype, trflang, trffromsql::oid, trftosql::oid "
    9270              :                          "FROM pg_transform "
    9271              :                          "ORDER BY 3,4");
    9272              : 
    9273          259 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    9274              : 
    9275          259 :     ntups = PQntuples(res);
    9276              : 
    9277          259 :     transforminfo = pg_malloc_array(TransformInfo, ntups);
    9278              : 
    9279          259 :     i_tableoid = PQfnumber(res, "tableoid");
    9280          259 :     i_oid = PQfnumber(res, "oid");
    9281          259 :     i_trftype = PQfnumber(res, "trftype");
    9282          259 :     i_trflang = PQfnumber(res, "trflang");
    9283          259 :     i_trffromsql = PQfnumber(res, "trffromsql");
    9284          259 :     i_trftosql = PQfnumber(res, "trftosql");
    9285              : 
    9286          311 :     for (i = 0; i < ntups; i++)
    9287              :     {
    9288              :         PQExpBufferData namebuf;
    9289              :         TypeInfo   *typeInfo;
    9290              :         char       *lanname;
    9291              : 
    9292           52 :         transforminfo[i].dobj.objType = DO_TRANSFORM;
    9293           52 :         transforminfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    9294           52 :         transforminfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    9295           52 :         AssignDumpId(&transforminfo[i].dobj);
    9296           52 :         transforminfo[i].trftype = atooid(PQgetvalue(res, i, i_trftype));
    9297           52 :         transforminfo[i].trflang = atooid(PQgetvalue(res, i, i_trflang));
    9298           52 :         transforminfo[i].trffromsql = atooid(PQgetvalue(res, i, i_trffromsql));
    9299           52 :         transforminfo[i].trftosql = atooid(PQgetvalue(res, i, i_trftosql));
    9300              : 
    9301              :         /*
    9302              :          * Try to name transform as concatenation of type and language name.
    9303              :          * This is only used for purposes of sorting.  If we fail to find
    9304              :          * either, the name will be an empty string.
    9305              :          */
    9306           52 :         initPQExpBuffer(&namebuf);
    9307           52 :         typeInfo = findTypeByOid(transforminfo[i].trftype);
    9308           52 :         lanname = get_language_name(fout, transforminfo[i].trflang);
    9309           52 :         if (typeInfo && lanname)
    9310           52 :             appendPQExpBuffer(&namebuf, "%s %s",
    9311              :                               typeInfo->dobj.name, lanname);
    9312           52 :         transforminfo[i].dobj.name = namebuf.data;
    9313           52 :         free(lanname);
    9314              : 
    9315              :         /* Decide whether we want to dump it */
    9316           52 :         selectDumpableObject(&(transforminfo[i].dobj), fout);
    9317              :     }
    9318              : 
    9319          259 :     PQclear(res);
    9320              : 
    9321          259 :     destroyPQExpBuffer(query);
    9322              : }
    9323              : 
    9324              : /*
    9325              :  * getTableAttrs -
    9326              :  *    for each interesting table, read info about its attributes
    9327              :  *    (names, types, default values, CHECK constraints, etc)
    9328              :  *
    9329              :  *  modifies tblinfo
    9330              :  */
    9331              : void
    9332          259 : getTableAttrs(Archive *fout, TableInfo *tblinfo, int numTables)
    9333              : {
    9334          259 :     DumpOptions *dopt = fout->dopt;
    9335          259 :     PQExpBuffer q = createPQExpBuffer();
    9336          259 :     PQExpBuffer tbloids = createPQExpBuffer();
    9337          259 :     PQExpBuffer checkoids = createPQExpBuffer();
    9338          259 :     PQExpBuffer invalidnotnulloids = NULL;
    9339              :     PGresult   *res;
    9340              :     int         ntups;
    9341              :     int         curtblindx;
    9342              :     int         i_attrelid;
    9343              :     int         i_attnum;
    9344              :     int         i_attname;
    9345              :     int         i_atttypname;
    9346              :     int         i_attstattarget;
    9347              :     int         i_attstorage;
    9348              :     int         i_typstorage;
    9349              :     int         i_attidentity;
    9350              :     int         i_attgenerated;
    9351              :     int         i_attisdropped;
    9352              :     int         i_attlen;
    9353              :     int         i_attalign;
    9354              :     int         i_attislocal;
    9355              :     int         i_notnull_name;
    9356              :     int         i_notnull_comment;
    9357              :     int         i_notnull_noinherit;
    9358              :     int         i_notnull_islocal;
    9359              :     int         i_notnull_invalidoid;
    9360              :     int         i_attoptions;
    9361              :     int         i_attcollation;
    9362              :     int         i_attcompression;
    9363              :     int         i_attfdwoptions;
    9364              :     int         i_attmissingval;
    9365              :     int         i_atthasdef;
    9366              : 
    9367              :     /*
    9368              :      * We want to perform just one query against pg_attribute, and then just
    9369              :      * one against pg_attrdef (for DEFAULTs) and two against pg_constraint
    9370              :      * (for CHECK constraints and for NOT NULL constraints).  However, we
    9371              :      * mustn't try to select every row of those catalogs and then sort it out
    9372              :      * on the client side, because some of the server-side functions we need
    9373              :      * would be unsafe to apply to tables we don't have lock on.  Hence, we
    9374              :      * build an array of the OIDs of tables we care about (and now have lock
    9375              :      * on!), and use a WHERE clause to constrain which rows are selected.
    9376              :      */
    9377          259 :     appendPQExpBufferChar(tbloids, '{');
    9378          259 :     appendPQExpBufferChar(checkoids, '{');
    9379        70160 :     for (int i = 0; i < numTables; i++)
    9380              :     {
    9381        69901 :         TableInfo  *tbinfo = &tblinfo[i];
    9382              : 
    9383              :         /* Don't bother to collect info for sequences */
    9384        69901 :         if (tbinfo->relkind == RELKIND_SEQUENCE)
    9385          647 :             continue;
    9386              : 
    9387              :         /*
    9388              :          * Don't bother with uninteresting tables, either.  For binary
    9389              :          * upgrades, this is bypassed for pg_largeobject_metadata and
    9390              :          * pg_shdepend so that the columns names are collected for the
    9391              :          * corresponding COPY commands.  Restoring the data for those catalogs
    9392              :          * is faster than restoring the equivalent set of large object
    9393              :          * commands.
    9394              :          */
    9395        69254 :         if (!tbinfo->interesting &&
    9396        62035 :             !(fout->dopt->binary_upgrade &&
    9397         9298 :               (tbinfo->dobj.catId.oid == LargeObjectMetadataRelationId ||
    9398         9258 :                tbinfo->dobj.catId.oid == SharedDependRelationId)))
    9399        61955 :             continue;
    9400              : 
    9401              :         /* OK, we need info for this table */
    9402         7299 :         if (tbloids->len > 1) /* do we have more than the '{'? */
    9403         7100 :             appendPQExpBufferChar(tbloids, ',');
    9404         7299 :         appendPQExpBuffer(tbloids, "%u", tbinfo->dobj.catId.oid);
    9405              : 
    9406         7299 :         if (tbinfo->ncheck > 0)
    9407              :         {
    9408              :             /* Also make a list of the ones with check constraints */
    9409          528 :             if (checkoids->len > 1) /* do we have more than the '{'? */
    9410          459 :                 appendPQExpBufferChar(checkoids, ',');
    9411          528 :             appendPQExpBuffer(checkoids, "%u", tbinfo->dobj.catId.oid);
    9412              :         }
    9413              :     }
    9414          259 :     appendPQExpBufferChar(tbloids, '}');
    9415          259 :     appendPQExpBufferChar(checkoids, '}');
    9416              : 
    9417              :     /*
    9418              :      * Find all the user attributes and their types.
    9419              :      *
    9420              :      * Since we only want to dump COLLATE clauses for attributes whose
    9421              :      * collation is different from their type's default, we use a CASE here to
    9422              :      * suppress uninteresting attcollations cheaply.
    9423              :      */
    9424          259 :     appendPQExpBufferStr(q,
    9425              :                          "SELECT\n"
    9426              :                          "a.attrelid,\n"
    9427              :                          "a.attnum,\n"
    9428              :                          "a.attname,\n"
    9429              :                          "a.attstattarget,\n"
    9430              :                          "a.attstorage,\n"
    9431              :                          "t.typstorage,\n"
    9432              :                          "a.atthasdef,\n"
    9433              :                          "a.attisdropped,\n"
    9434              :                          "a.attlen,\n"
    9435              :                          "a.attalign,\n"
    9436              :                          "a.attislocal,\n"
    9437              :                          "pg_catalog.format_type(t.oid, a.atttypmod) AS atttypname,\n"
    9438              :                          "array_to_string(a.attoptions, ', ') AS attoptions,\n"
    9439              :                          "CASE WHEN a.attcollation <> t.typcollation "
    9440              :                          "THEN a.attcollation ELSE 0 END AS attcollation,\n"
    9441              :                          "pg_catalog.array_to_string(ARRAY("
    9442              :                          "SELECT pg_catalog.quote_ident(option_name) || "
    9443              :                          "' ' || pg_catalog.quote_literal(option_value) "
    9444              :                          "FROM pg_catalog.pg_options_to_table(attfdwoptions) "
    9445              :                          "ORDER BY option_name"
    9446              :                          "), E',\n    ') AS attfdwoptions,\n");
    9447              : 
    9448              :     /*
    9449              :      * Find out any NOT NULL markings for each column.  In 18 and up we read
    9450              :      * pg_constraint to obtain the constraint name, and for valid constraints
    9451              :      * also pg_description to obtain its comment.  notnull_noinherit is set
    9452              :      * according to the NO INHERIT property.  For versions prior to 18, we
    9453              :      * store an empty string as the name when a constraint is marked as
    9454              :      * attnotnull (this cues dumpTableSchema to print the NOT NULL clause
    9455              :      * without a name); also, such cases are never NO INHERIT.
    9456              :      *
    9457              :      * For invalid constraints, we need to store their OIDs for processing
    9458              :      * elsewhere, so we bring the pg_constraint.oid value when the constraint
    9459              :      * is invalid, and NULL otherwise.  Their comments are handled not here
    9460              :      * but by collectComments, because they're their own dumpable object.
    9461              :      *
    9462              :      * We track in notnull_islocal whether the constraint was defined directly
    9463              :      * in this table or via an ancestor, for binary upgrade.  flagInhAttrs
    9464              :      * might modify this later.
    9465              :      */
    9466          259 :     if (fout->remoteVersion >= 180000)
    9467          259 :         appendPQExpBufferStr(q,
    9468              :                              "co.conname AS notnull_name,\n"
    9469              :                              "CASE WHEN co.convalidated THEN pt.description"
    9470              :                              " ELSE NULL END AS notnull_comment,\n"
    9471              :                              "CASE WHEN NOT co.convalidated THEN co.oid "
    9472              :                              "ELSE NULL END AS notnull_invalidoid,\n"
    9473              :                              "co.connoinherit AS notnull_noinherit,\n"
    9474              :                              "co.conislocal AS notnull_islocal,\n");
    9475              :     else
    9476            0 :         appendPQExpBufferStr(q,
    9477              :                              "CASE WHEN a.attnotnull THEN '' ELSE NULL END AS notnull_name,\n"
    9478              :                              "NULL AS notnull_comment,\n"
    9479              :                              "NULL AS notnull_invalidoid,\n"
    9480              :                              "false AS notnull_noinherit,\n"
    9481              :                              "CASE WHEN a.attislocal THEN true\n"
    9482              :                              "     WHEN a.attnotnull AND NOT a.attislocal THEN true\n"
    9483              :                              "     ELSE false\n"
    9484              :                              "END AS notnull_islocal,\n");
    9485              : 
    9486          259 :     if (fout->remoteVersion >= 140000)
    9487          259 :         appendPQExpBufferStr(q,
    9488              :                              "a.attcompression AS attcompression,\n");
    9489              :     else
    9490            0 :         appendPQExpBufferStr(q,
    9491              :                              "'' AS attcompression,\n");
    9492              : 
    9493          259 :     if (fout->remoteVersion >= 100000)
    9494          259 :         appendPQExpBufferStr(q,
    9495              :                              "a.attidentity,\n");
    9496              :     else
    9497            0 :         appendPQExpBufferStr(q,
    9498              :                              "'' AS attidentity,\n");
    9499              : 
    9500          259 :     if (fout->remoteVersion >= 110000)
    9501          259 :         appendPQExpBufferStr(q,
    9502              :                              "CASE WHEN a.atthasmissing AND NOT a.attisdropped "
    9503              :                              "THEN a.attmissingval ELSE null END AS attmissingval,\n");
    9504              :     else
    9505            0 :         appendPQExpBufferStr(q,
    9506              :                              "NULL AS attmissingval,\n");
    9507              : 
    9508          259 :     if (fout->remoteVersion >= 120000)
    9509          259 :         appendPQExpBufferStr(q,
    9510              :                              "a.attgenerated\n");
    9511              :     else
    9512            0 :         appendPQExpBufferStr(q,
    9513              :                              "'' AS attgenerated\n");
    9514              : 
    9515              :     /* need left join to pg_type to not fail on dropped columns ... */
    9516          259 :     appendPQExpBuffer(q,
    9517              :                       "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
    9518              :                       "JOIN pg_catalog.pg_attribute a ON (src.tbloid = a.attrelid) "
    9519              :                       "LEFT JOIN pg_catalog.pg_type t "
    9520              :                       "ON (a.atttypid = t.oid)\n",
    9521              :                       tbloids->data);
    9522              : 
    9523              :     /*
    9524              :      * In versions 18 and up, we need pg_constraint for explicit NOT NULL
    9525              :      * entries and pg_description to get their comments.
    9526              :      */
    9527          259 :     if (fout->remoteVersion >= 180000)
    9528          259 :         appendPQExpBufferStr(q,
    9529              :                              " LEFT JOIN pg_catalog.pg_constraint co ON "
    9530              :                              "(a.attrelid = co.conrelid\n"
    9531              :                              "   AND co.contype = 'n' AND "
    9532              :                              "co.conkey = array[a.attnum])\n"
    9533              :                              " LEFT JOIN pg_catalog.pg_description pt ON "
    9534              :                              "(pt.classoid = co.tableoid AND pt.objoid = co.oid)\n");
    9535              : 
    9536          259 :     appendPQExpBufferStr(q,
    9537              :                          "WHERE a.attnum > 0::pg_catalog.int2\n");
    9538              : 
    9539              :     /*
    9540              :      * For binary upgrades from <v12, be sure to pick up
    9541              :      * pg_largeobject_metadata's oid column.
    9542              :      */
    9543          259 :     if (fout->dopt->binary_upgrade && fout->remoteVersion < 120000)
    9544            0 :         appendPQExpBufferStr(q,
    9545              :                              "OR (a.attnum = -2::pg_catalog.int2 AND src.tbloid = "
    9546              :                              CppAsString2(LargeObjectMetadataRelationId) ")\n");
    9547              : 
    9548          259 :     appendPQExpBufferStr(q,
    9549              :                          "ORDER BY a.attrelid, a.attnum");
    9550              : 
    9551          259 :     res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
    9552              : 
    9553          259 :     ntups = PQntuples(res);
    9554              : 
    9555          259 :     i_attrelid = PQfnumber(res, "attrelid");
    9556          259 :     i_attnum = PQfnumber(res, "attnum");
    9557          259 :     i_attname = PQfnumber(res, "attname");
    9558          259 :     i_atttypname = PQfnumber(res, "atttypname");
    9559          259 :     i_attstattarget = PQfnumber(res, "attstattarget");
    9560          259 :     i_attstorage = PQfnumber(res, "attstorage");
    9561          259 :     i_typstorage = PQfnumber(res, "typstorage");
    9562          259 :     i_attidentity = PQfnumber(res, "attidentity");
    9563          259 :     i_attgenerated = PQfnumber(res, "attgenerated");
    9564          259 :     i_attisdropped = PQfnumber(res, "attisdropped");
    9565          259 :     i_attlen = PQfnumber(res, "attlen");
    9566          259 :     i_attalign = PQfnumber(res, "attalign");
    9567          259 :     i_attislocal = PQfnumber(res, "attislocal");
    9568          259 :     i_notnull_name = PQfnumber(res, "notnull_name");
    9569          259 :     i_notnull_comment = PQfnumber(res, "notnull_comment");
    9570          259 :     i_notnull_invalidoid = PQfnumber(res, "notnull_invalidoid");
    9571          259 :     i_notnull_noinherit = PQfnumber(res, "notnull_noinherit");
    9572          259 :     i_notnull_islocal = PQfnumber(res, "notnull_islocal");
    9573          259 :     i_attoptions = PQfnumber(res, "attoptions");
    9574          259 :     i_attcollation = PQfnumber(res, "attcollation");
    9575          259 :     i_attcompression = PQfnumber(res, "attcompression");
    9576          259 :     i_attfdwoptions = PQfnumber(res, "attfdwoptions");
    9577          259 :     i_attmissingval = PQfnumber(res, "attmissingval");
    9578          259 :     i_atthasdef = PQfnumber(res, "atthasdef");
    9579              : 
    9580              :     /* Within the next loop, we'll accumulate OIDs of tables with defaults */
    9581          259 :     resetPQExpBuffer(tbloids);
    9582          259 :     appendPQExpBufferChar(tbloids, '{');
    9583              : 
    9584              :     /*
    9585              :      * Outer loop iterates once per table, not once per row.  Incrementing of
    9586              :      * r is handled by the inner loop.
    9587              :      */
    9588          259 :     curtblindx = -1;
    9589         7317 :     for (int r = 0; r < ntups;)
    9590              :     {
    9591         7058 :         Oid         attrelid = atooid(PQgetvalue(res, r, i_attrelid));
    9592         7058 :         TableInfo  *tbinfo = NULL;
    9593              :         int         numatts;
    9594              :         bool        hasdefaults;
    9595              : 
    9596              :         /* Count rows for this table */
    9597        26200 :         for (numatts = 1; numatts < ntups - r; numatts++)
    9598        26004 :             if (atooid(PQgetvalue(res, r + numatts, i_attrelid)) != attrelid)
    9599         6862 :                 break;
    9600              : 
    9601              :         /*
    9602              :          * Locate the associated TableInfo; we rely on tblinfo[] being in OID
    9603              :          * order.
    9604              :          */
    9605        49214 :         while (++curtblindx < numTables)
    9606              :         {
    9607        49214 :             tbinfo = &tblinfo[curtblindx];
    9608        49214 :             if (tbinfo->dobj.catId.oid == attrelid)
    9609         7058 :                 break;
    9610              :         }
    9611         7058 :         if (curtblindx >= numTables)
    9612            0 :             pg_fatal("unrecognized table OID %u", attrelid);
    9613              :         /* cross-check that we only got requested tables */
    9614         7058 :         if (tbinfo->relkind == RELKIND_SEQUENCE ||
    9615         7058 :             (!tbinfo->interesting &&
    9616           80 :              !(fout->dopt->binary_upgrade &&
    9617           80 :                (tbinfo->dobj.catId.oid == LargeObjectMetadataRelationId ||
    9618           40 :                 tbinfo->dobj.catId.oid == SharedDependRelationId))))
    9619            0 :             pg_fatal("unexpected column data for table \"%s\"",
    9620              :                      tbinfo->dobj.name);
    9621              : 
    9622              :         /* Save data for this table */
    9623         7058 :         tbinfo->numatts = numatts;
    9624         7058 :         tbinfo->attnames = pg_malloc_array(char *, numatts);
    9625         7058 :         tbinfo->atttypnames = pg_malloc_array(char *, numatts);
    9626         7058 :         tbinfo->attstattarget = pg_malloc_array(int, numatts);
    9627         7058 :         tbinfo->attstorage = pg_malloc_array(char, numatts);
    9628         7058 :         tbinfo->typstorage = pg_malloc_array(char, numatts);
    9629         7058 :         tbinfo->attidentity = pg_malloc_array(char, numatts);
    9630         7058 :         tbinfo->attgenerated = pg_malloc_array(char, numatts);
    9631         7058 :         tbinfo->attisdropped = pg_malloc_array(bool, numatts);
    9632         7058 :         tbinfo->attlen = pg_malloc_array(int, numatts);
    9633         7058 :         tbinfo->attalign = pg_malloc_array(char, numatts);
    9634         7058 :         tbinfo->attislocal = pg_malloc_array(bool, numatts);
    9635         7058 :         tbinfo->attoptions = pg_malloc_array(char *, numatts);
    9636         7058 :         tbinfo->attcollation = pg_malloc_array(Oid, numatts);
    9637         7058 :         tbinfo->attcompression = pg_malloc_array(char, numatts);
    9638         7058 :         tbinfo->attfdwoptions = pg_malloc_array(char *, numatts);
    9639         7058 :         tbinfo->attmissingval = pg_malloc_array(char *, numatts);
    9640         7058 :         tbinfo->notnull_constrs = pg_malloc_array(char *, numatts);
    9641         7058 :         tbinfo->notnull_comment = pg_malloc_array(char *, numatts);
    9642         7058 :         tbinfo->notnull_invalid = pg_malloc_array(bool, numatts);
    9643         7058 :         tbinfo->notnull_noinh = pg_malloc_array(bool, numatts);
    9644         7058 :         tbinfo->notnull_islocal = pg_malloc_array(bool, numatts);
    9645         7058 :         tbinfo->attrdefs = pg_malloc_array(AttrDefInfo *, numatts);
    9646         7058 :         hasdefaults = false;
    9647              : 
    9648        33258 :         for (int j = 0; j < numatts; j++, r++)
    9649              :         {
    9650        26200 :             if (j + 1 != atoi(PQgetvalue(res, r, i_attnum)) &&
    9651            0 :                 !(fout->dopt->binary_upgrade && fout->remoteVersion < 120000 &&
    9652            0 :                   tbinfo->dobj.catId.oid == LargeObjectMetadataRelationId))
    9653            0 :                 pg_fatal("invalid column numbering in table \"%s\"",
    9654              :                          tbinfo->dobj.name);
    9655        26200 :             tbinfo->attnames[j] = pg_strdup(PQgetvalue(res, r, i_attname));
    9656        26200 :             tbinfo->atttypnames[j] = pg_strdup(PQgetvalue(res, r, i_atttypname));
    9657        26200 :             if (PQgetisnull(res, r, i_attstattarget))
    9658        26160 :                 tbinfo->attstattarget[j] = -1;
    9659              :             else
    9660           40 :                 tbinfo->attstattarget[j] = atoi(PQgetvalue(res, r, i_attstattarget));
    9661        26200 :             tbinfo->attstorage[j] = *(PQgetvalue(res, r, i_attstorage));
    9662        26200 :             tbinfo->typstorage[j] = *(PQgetvalue(res, r, i_typstorage));
    9663        26200 :             tbinfo->attidentity[j] = *(PQgetvalue(res, r, i_attidentity));
    9664        26200 :             tbinfo->attgenerated[j] = *(PQgetvalue(res, r, i_attgenerated));
    9665        26200 :             tbinfo->needs_override = tbinfo->needs_override || (tbinfo->attidentity[j] == ATTRIBUTE_IDENTITY_ALWAYS);
    9666        26200 :             tbinfo->attisdropped[j] = (PQgetvalue(res, r, i_attisdropped)[0] == 't');
    9667        26200 :             tbinfo->attlen[j] = atoi(PQgetvalue(res, r, i_attlen));
    9668        26200 :             tbinfo->attalign[j] = *(PQgetvalue(res, r, i_attalign));
    9669        26200 :             tbinfo->attislocal[j] = (PQgetvalue(res, r, i_attislocal)[0] == 't');
    9670              : 
    9671              :             /* Handle not-null constraint name and flags */
    9672        26200 :             determineNotNullFlags(fout, res, r,
    9673              :                                   tbinfo, j,
    9674              :                                   i_notnull_name,
    9675              :                                   i_notnull_comment,
    9676              :                                   i_notnull_invalidoid,
    9677              :                                   i_notnull_noinherit,
    9678              :                                   i_notnull_islocal,
    9679              :                                   &invalidnotnulloids);
    9680              : 
    9681        26200 :             tbinfo->notnull_comment[j] = PQgetisnull(res, r, i_notnull_comment) ?
    9682        26200 :                 NULL : pg_strdup(PQgetvalue(res, r, i_notnull_comment));
    9683        26200 :             tbinfo->attoptions[j] = pg_strdup(PQgetvalue(res, r, i_attoptions));
    9684        26200 :             tbinfo->attcollation[j] = atooid(PQgetvalue(res, r, i_attcollation));
    9685        26200 :             tbinfo->attcompression[j] = *(PQgetvalue(res, r, i_attcompression));
    9686        26200 :             tbinfo->attfdwoptions[j] = pg_strdup(PQgetvalue(res, r, i_attfdwoptions));
    9687        26200 :             tbinfo->attmissingval[j] = pg_strdup(PQgetvalue(res, r, i_attmissingval));
    9688        26200 :             tbinfo->attrdefs[j] = NULL; /* fix below */
    9689        26200 :             if (PQgetvalue(res, r, i_atthasdef)[0] == 't')
    9690         1283 :                 hasdefaults = true;
    9691              :         }
    9692              : 
    9693         7058 :         if (hasdefaults)
    9694              :         {
    9695              :             /* Collect OIDs of interesting tables that have defaults */
    9696          962 :             if (tbloids->len > 1) /* do we have more than the '{'? */
    9697          894 :                 appendPQExpBufferChar(tbloids, ',');
    9698          962 :             appendPQExpBuffer(tbloids, "%u", tbinfo->dobj.catId.oid);
    9699              :         }
    9700              :     }
    9701              : 
    9702              :     /* If invalidnotnulloids has any data, finalize it */
    9703          259 :     if (invalidnotnulloids != NULL)
    9704           43 :         appendPQExpBufferChar(invalidnotnulloids, '}');
    9705              : 
    9706          259 :     PQclear(res);
    9707              : 
    9708              :     /*
    9709              :      * Now get info about column defaults.  This is skipped for a data-only
    9710              :      * dump, as it is only needed for table schemas.
    9711              :      */
    9712          259 :     if (dopt->dumpSchema && tbloids->len > 1)
    9713              :     {
    9714              :         AttrDefInfo *attrdefs;
    9715              :         int         numDefaults;
    9716           60 :         TableInfo  *tbinfo = NULL;
    9717              : 
    9718           60 :         pg_log_info("finding table default expressions");
    9719              : 
    9720           60 :         appendPQExpBufferChar(tbloids, '}');
    9721              : 
    9722           60 :         printfPQExpBuffer(q, "SELECT a.tableoid, a.oid, adrelid, adnum, "
    9723              :                           "pg_catalog.pg_get_expr(adbin, adrelid) AS adsrc\n"
    9724              :                           "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
    9725              :                           "JOIN pg_catalog.pg_attrdef a ON (src.tbloid = a.adrelid)\n"
    9726              :                           "ORDER BY a.adrelid, a.adnum",
    9727              :                           tbloids->data);
    9728              : 
    9729           60 :         res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
    9730              : 
    9731           60 :         numDefaults = PQntuples(res);
    9732           60 :         attrdefs = pg_malloc_array(AttrDefInfo, numDefaults);
    9733              : 
    9734           60 :         curtblindx = -1;
    9735         1245 :         for (int j = 0; j < numDefaults; j++)
    9736              :         {
    9737         1185 :             Oid         adtableoid = atooid(PQgetvalue(res, j, 0));
    9738         1185 :             Oid         adoid = atooid(PQgetvalue(res, j, 1));
    9739         1185 :             Oid         adrelid = atooid(PQgetvalue(res, j, 2));
    9740         1185 :             int         adnum = atoi(PQgetvalue(res, j, 3));
    9741         1185 :             char       *adsrc = PQgetvalue(res, j, 4);
    9742              : 
    9743              :             /*
    9744              :              * Locate the associated TableInfo; we rely on tblinfo[] being in
    9745              :              * OID order.
    9746              :              */
    9747         1185 :             if (tbinfo == NULL || tbinfo->dobj.catId.oid != adrelid)
    9748              :             {
    9749        20109 :                 while (++curtblindx < numTables)
    9750              :                 {
    9751        20109 :                     tbinfo = &tblinfo[curtblindx];
    9752        20109 :                     if (tbinfo->dobj.catId.oid == adrelid)
    9753          894 :                         break;
    9754              :                 }
    9755          894 :                 if (curtblindx >= numTables)
    9756            0 :                     pg_fatal("unrecognized table OID %u", adrelid);
    9757              :             }
    9758              : 
    9759         1185 :             if (adnum <= 0 || adnum > tbinfo->numatts)
    9760            0 :                 pg_fatal("invalid adnum value %d for table \"%s\"",
    9761              :                          adnum, tbinfo->dobj.name);
    9762              : 
    9763              :             /*
    9764              :              * dropped columns shouldn't have defaults, but just in case,
    9765              :              * ignore 'em
    9766              :              */
    9767         1185 :             if (tbinfo->attisdropped[adnum - 1])
    9768            0 :                 continue;
    9769              : 
    9770         1185 :             attrdefs[j].dobj.objType = DO_ATTRDEF;
    9771         1185 :             attrdefs[j].dobj.catId.tableoid = adtableoid;
    9772         1185 :             attrdefs[j].dobj.catId.oid = adoid;
    9773         1185 :             AssignDumpId(&attrdefs[j].dobj);
    9774         1185 :             attrdefs[j].adtable = tbinfo;
    9775         1185 :             attrdefs[j].adnum = adnum;
    9776         1185 :             attrdefs[j].adef_expr = pg_strdup(adsrc);
    9777              : 
    9778         1185 :             attrdefs[j].dobj.name = pg_strdup(tbinfo->dobj.name);
    9779         1185 :             attrdefs[j].dobj.namespace = tbinfo->dobj.namespace;
    9780              : 
    9781         1185 :             attrdefs[j].dobj.dump = tbinfo->dobj.dump;
    9782              : 
    9783              :             /*
    9784              :              * Figure out whether the default/generation expression should be
    9785              :              * dumped as part of the main CREATE TABLE (or similar) command or
    9786              :              * as a separate ALTER TABLE (or similar) command. The preference
    9787              :              * is to put it into the CREATE command, but in some cases that's
    9788              :              * not possible.
    9789              :              */
    9790         1185 :             if (tbinfo->attgenerated[adnum - 1])
    9791              :             {
    9792              :                 /*
    9793              :                  * Column generation expressions cannot be dumped separately,
    9794              :                  * because there is no syntax for it.  By setting separate to
    9795              :                  * false here we prevent the "default" from being processed as
    9796              :                  * its own dumpable object.  Later, flagInhAttrs() will mark
    9797              :                  * it as not to be dumped at all, if possible (that is, if it
    9798              :                  * can be inherited from a parent).
    9799              :                  */
    9800          656 :                 attrdefs[j].separate = false;
    9801              :             }
    9802          529 :             else if (tbinfo->relkind == RELKIND_VIEW)
    9803              :             {
    9804              :                 /*
    9805              :                  * Defaults on a VIEW must always be dumped as separate ALTER
    9806              :                  * TABLE commands.
    9807              :                  */
    9808           32 :                 attrdefs[j].separate = true;
    9809              :             }
    9810          497 :             else if (!shouldPrintColumn(dopt, tbinfo, adnum - 1))
    9811              :             {
    9812              :                 /* column will be suppressed, print default separately */
    9813            4 :                 attrdefs[j].separate = true;
    9814              :             }
    9815              :             else
    9816              :             {
    9817          493 :                 attrdefs[j].separate = false;
    9818              :             }
    9819              : 
    9820         1185 :             if (!attrdefs[j].separate)
    9821              :             {
    9822              :                 /*
    9823              :                  * Mark the default as needing to appear before the table, so
    9824              :                  * that any dependencies it has must be emitted before the
    9825              :                  * CREATE TABLE.  If this is not possible, we'll change to
    9826              :                  * "separate" mode while sorting dependencies.
    9827              :                  */
    9828         1149 :                 addObjectDependency(&tbinfo->dobj,
    9829         1149 :                                     attrdefs[j].dobj.dumpId);
    9830              :             }
    9831              : 
    9832         1185 :             tbinfo->attrdefs[adnum - 1] = &attrdefs[j];
    9833              :         }
    9834              : 
    9835           60 :         PQclear(res);
    9836              :     }
    9837              : 
    9838              :     /*
    9839              :      * Get info about NOT NULL NOT VALID constraints.  This is skipped for a
    9840              :      * data-only dump, as it is only needed for table schemas.
    9841              :      */
    9842          259 :     if (dopt->dumpSchema && invalidnotnulloids)
    9843              :     {
    9844              :         ConstraintInfo *constrs;
    9845              :         int         numConstrs;
    9846              :         int         i_tableoid;
    9847              :         int         i_oid;
    9848              :         int         i_conrelid;
    9849              :         int         i_conname;
    9850              :         int         i_consrc;
    9851              :         int         i_conislocal;
    9852              : 
    9853           37 :         pg_log_info("finding invalid not-null constraints");
    9854              : 
    9855           37 :         resetPQExpBuffer(q);
    9856           37 :         appendPQExpBuffer(q,
    9857              :                           "SELECT c.tableoid, c.oid, conrelid, conname, "
    9858              :                           "pg_catalog.pg_get_constraintdef(c.oid) AS consrc, "
    9859              :                           "conislocal, convalidated "
    9860              :                           "FROM unnest('%s'::pg_catalog.oid[]) AS src(conoid)\n"
    9861              :                           "JOIN pg_catalog.pg_constraint c ON (src.conoid = c.oid)\n"
    9862              :                           "ORDER BY c.conrelid, c.conname",
    9863           37 :                           invalidnotnulloids->data);
    9864              : 
    9865           37 :         res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
    9866              : 
    9867           37 :         numConstrs = PQntuples(res);
    9868           37 :         constrs = pg_malloc_array(ConstraintInfo, numConstrs);
    9869              : 
    9870           37 :         i_tableoid = PQfnumber(res, "tableoid");
    9871           37 :         i_oid = PQfnumber(res, "oid");
    9872           37 :         i_conrelid = PQfnumber(res, "conrelid");
    9873           37 :         i_conname = PQfnumber(res, "conname");
    9874           37 :         i_consrc = PQfnumber(res, "consrc");
    9875           37 :         i_conislocal = PQfnumber(res, "conislocal");
    9876              : 
    9877              :         /* As above, this loop iterates once per table, not once per row */
    9878           37 :         curtblindx = -1;
    9879          104 :         for (int j = 0; j < numConstrs;)
    9880              :         {
    9881           67 :             Oid         conrelid = atooid(PQgetvalue(res, j, i_conrelid));
    9882           67 :             TableInfo  *tbinfo = NULL;
    9883              :             int         numcons;
    9884              : 
    9885              :             /* Count rows for this table */
    9886           67 :             for (numcons = 1; numcons < numConstrs - j; numcons++)
    9887           30 :                 if (atooid(PQgetvalue(res, j + numcons, i_conrelid)) != conrelid)
    9888           30 :                     break;
    9889              : 
    9890              :             /*
    9891              :              * Locate the associated TableInfo; we rely on tblinfo[] being in
    9892              :              * OID order.
    9893              :              */
    9894        13417 :             while (++curtblindx < numTables)
    9895              :             {
    9896        13417 :                 tbinfo = &tblinfo[curtblindx];
    9897        13417 :                 if (tbinfo->dobj.catId.oid == conrelid)
    9898           67 :                     break;
    9899              :             }
    9900           67 :             if (curtblindx >= numTables)
    9901            0 :                 pg_fatal("unrecognized table OID %u", conrelid);
    9902              : 
    9903          134 :             for (int c = 0; c < numcons; c++, j++)
    9904              :             {
    9905           67 :                 constrs[j].dobj.objType = DO_CONSTRAINT;
    9906           67 :                 constrs[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
    9907           67 :                 constrs[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
    9908           67 :                 AssignDumpId(&constrs[j].dobj);
    9909           67 :                 constrs[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_conname));
    9910           67 :                 constrs[j].dobj.namespace = tbinfo->dobj.namespace;
    9911           67 :                 constrs[j].contable = tbinfo;
    9912           67 :                 constrs[j].condomain = NULL;
    9913           67 :                 constrs[j].contype = 'n';
    9914           67 :                 constrs[j].condef = pg_strdup(PQgetvalue(res, j, i_consrc));
    9915           67 :                 constrs[j].confrelid = InvalidOid;
    9916           67 :                 constrs[j].conindex = 0;
    9917           67 :                 constrs[j].condeferrable = false;
    9918           67 :                 constrs[j].condeferred = false;
    9919           67 :                 constrs[j].conislocal = (PQgetvalue(res, j, i_conislocal)[0] == 't');
    9920              : 
    9921              :                 /*
    9922              :                  * All invalid not-null constraints must be dumped separately,
    9923              :                  * because CREATE TABLE would not create them as invalid, and
    9924              :                  * also because they must be created after potentially
    9925              :                  * violating data has been loaded.
    9926              :                  */
    9927           67 :                 constrs[j].separate = true;
    9928              : 
    9929           67 :                 constrs[j].dobj.dump = tbinfo->dobj.dump;
    9930              :             }
    9931              :         }
    9932           37 :         PQclear(res);
    9933              :     }
    9934              : 
    9935              :     /*
    9936              :      * Get info about table CHECK constraints.  This is skipped for a
    9937              :      * data-only dump, as it is only needed for table schemas.
    9938              :      */
    9939          259 :     if (dopt->dumpSchema && checkoids->len > 2)
    9940              :     {
    9941              :         ConstraintInfo *constrs;
    9942              :         int         numConstrs;
    9943              :         int         i_tableoid;
    9944              :         int         i_oid;
    9945              :         int         i_conrelid;
    9946              :         int         i_conname;
    9947              :         int         i_consrc;
    9948              :         int         i_conislocal;
    9949              :         int         i_convalidated;
    9950              : 
    9951           61 :         pg_log_info("finding table check constraints");
    9952              : 
    9953           61 :         resetPQExpBuffer(q);
    9954           61 :         appendPQExpBuffer(q,
    9955              :                           "SELECT c.tableoid, c.oid, conrelid, conname, "
    9956              :                           "pg_catalog.pg_get_constraintdef(c.oid) AS consrc, "
    9957              :                           "conislocal, convalidated "
    9958              :                           "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
    9959              :                           "JOIN pg_catalog.pg_constraint c ON (src.tbloid = c.conrelid)\n"
    9960              :                           "WHERE contype = 'c' "
    9961              :                           "ORDER BY c.conrelid, c.conname",
    9962              :                           checkoids->data);
    9963              : 
    9964           61 :         res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
    9965              : 
    9966           61 :         numConstrs = PQntuples(res);
    9967           61 :         constrs = pg_malloc_array(ConstraintInfo, numConstrs);
    9968              : 
    9969           61 :         i_tableoid = PQfnumber(res, "tableoid");
    9970           61 :         i_oid = PQfnumber(res, "oid");
    9971           61 :         i_conrelid = PQfnumber(res, "conrelid");
    9972           61 :         i_conname = PQfnumber(res, "conname");
    9973           61 :         i_consrc = PQfnumber(res, "consrc");
    9974           61 :         i_conislocal = PQfnumber(res, "conislocal");
    9975           61 :         i_convalidated = PQfnumber(res, "convalidated");
    9976              : 
    9977              :         /* As above, this loop iterates once per table, not once per row */
    9978           61 :         curtblindx = -1;
    9979          538 :         for (int j = 0; j < numConstrs;)
    9980              :         {
    9981          477 :             Oid         conrelid = atooid(PQgetvalue(res, j, i_conrelid));
    9982          477 :             TableInfo  *tbinfo = NULL;
    9983              :             int         numcons;
    9984              : 
    9985              :             /* Count rows for this table */
    9986          612 :             for (numcons = 1; numcons < numConstrs - j; numcons++)
    9987          551 :                 if (atooid(PQgetvalue(res, j + numcons, i_conrelid)) != conrelid)
    9988          416 :                     break;
    9989              : 
    9990              :             /*
    9991              :              * Locate the associated TableInfo; we rely on tblinfo[] being in
    9992              :              * OID order.
    9993              :              */
    9994        19408 :             while (++curtblindx < numTables)
    9995              :             {
    9996        19408 :                 tbinfo = &tblinfo[curtblindx];
    9997        19408 :                 if (tbinfo->dobj.catId.oid == conrelid)
    9998          477 :                     break;
    9999              :             }
   10000          477 :             if (curtblindx >= numTables)
   10001            0 :                 pg_fatal("unrecognized table OID %u", conrelid);
   10002              : 
   10003          477 :             if (numcons != tbinfo->ncheck)
   10004              :             {
   10005            0 :                 pg_log_error(ngettext("expected %d check constraint on table \"%s\" but found %d",
   10006              :                                       "expected %d check constraints on table \"%s\" but found %d",
   10007              :                                       tbinfo->ncheck),
   10008              :                              tbinfo->ncheck, tbinfo->dobj.name, numcons);
   10009            0 :                 pg_log_error_hint("The system catalogs might be corrupted.");
   10010            0 :                 exit_nicely(1);
   10011              :             }
   10012              : 
   10013          477 :             tbinfo->checkexprs = constrs + j;
   10014              : 
   10015         1089 :             for (int c = 0; c < numcons; c++, j++)
   10016              :             {
   10017          612 :                 bool        validated = PQgetvalue(res, j, i_convalidated)[0] == 't';
   10018              : 
   10019          612 :                 constrs[j].dobj.objType = DO_CONSTRAINT;
   10020          612 :                 constrs[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
   10021          612 :                 constrs[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
   10022          612 :                 AssignDumpId(&constrs[j].dobj);
   10023          612 :                 constrs[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_conname));
   10024          612 :                 constrs[j].dobj.namespace = tbinfo->dobj.namespace;
   10025          612 :                 constrs[j].contable = tbinfo;
   10026          612 :                 constrs[j].condomain = NULL;
   10027          612 :                 constrs[j].contype = 'c';
   10028          612 :                 constrs[j].condef = pg_strdup(PQgetvalue(res, j, i_consrc));
   10029          612 :                 constrs[j].confrelid = InvalidOid;
   10030          612 :                 constrs[j].conindex = 0;
   10031          612 :                 constrs[j].condeferrable = false;
   10032          612 :                 constrs[j].condeferred = false;
   10033          612 :                 constrs[j].conislocal = (PQgetvalue(res, j, i_conislocal)[0] == 't');
   10034              : 
   10035              :                 /*
   10036              :                  * An unvalidated constraint needs to be dumped separately, so
   10037              :                  * that potentially-violating existing data is loaded before
   10038              :                  * the constraint.
   10039              :                  */
   10040          612 :                 constrs[j].separate = !validated;
   10041              : 
   10042          612 :                 constrs[j].dobj.dump = tbinfo->dobj.dump;
   10043              : 
   10044              :                 /*
   10045              :                  * Mark the constraint as needing to appear before the table
   10046              :                  * --- this is so that any other dependencies of the
   10047              :                  * constraint will be emitted before we try to create the
   10048              :                  * table.  If the constraint is to be dumped separately, it
   10049              :                  * will be dumped after data is loaded anyway, so don't do it.
   10050              :                  * (There's an automatic dependency in the opposite direction
   10051              :                  * anyway, so don't need to add one manually here.)
   10052              :                  */
   10053          612 :                 if (!constrs[j].separate)
   10054          547 :                     addObjectDependency(&tbinfo->dobj,
   10055          547 :                                         constrs[j].dobj.dumpId);
   10056              : 
   10057              :                 /*
   10058              :                  * We will detect later whether the constraint must be split
   10059              :                  * out from the table definition.
   10060              :                  */
   10061              :             }
   10062              :         }
   10063              : 
   10064           61 :         PQclear(res);
   10065              :     }
   10066              : 
   10067          259 :     destroyPQExpBuffer(q);
   10068          259 :     destroyPQExpBuffer(tbloids);
   10069          259 :     destroyPQExpBuffer(checkoids);
   10070          259 : }
   10071              : 
   10072              : /*
   10073              :  * Based on the getTableAttrs query's row corresponding to one column, set
   10074              :  * the name and flags to handle a not-null constraint for that column in
   10075              :  * the tbinfo struct.
   10076              :  *
   10077              :  * Result row 'r' is for tbinfo's attribute 'j'.
   10078              :  *
   10079              :  * There are four possibilities:
   10080              :  * 1) the column has no not-null constraints. In that case, ->notnull_constrs
   10081              :  *    (the constraint name) remains NULL.
   10082              :  * 2) The column has a constraint with no name (this is the case when
   10083              :  *    constraints come from pre-18 servers).  In this case, ->notnull_constrs
   10084              :  *    is set to the empty string; dumpTableSchema will print just "NOT NULL".
   10085              :  * 3) The column has an invalid not-null constraint.  This must be treated
   10086              :  *    as a separate object (because it must be created after the table data
   10087              :  *    is loaded).  So we add its OID to invalidnotnulloids for processing
   10088              :  *    elsewhere and do nothing further with it here.  We distinguish this
   10089              :  *    case because the "notnull_invalidoid" column has been set to a non-NULL
   10090              :  *    value, which is the constraint OID.  Valid constraints have a null OID.
   10091              :  * 4) The column has a constraint with a known name; in that case
   10092              :  *    notnull_constrs carries that name and dumpTableSchema will print
   10093              :  *    "CONSTRAINT the_name NOT NULL".  However, if the name is the default
   10094              :  *    (table_column_not_null) and there's no comment on the constraint,
   10095              :  *    there's no need to print that name in the dump, so notnull_constrs
   10096              :  *    is set to the empty string and it behaves as case 2.
   10097              :  *
   10098              :  * In a child table that inherits from a parent already containing NOT NULL
   10099              :  * constraints and the columns in the child don't have their own NOT NULL
   10100              :  * declarations, we suppress printing constraints in the child: the
   10101              :  * constraints are acquired at the point where the child is attached to the
   10102              :  * parent.  This is tracked in ->notnull_islocal; for servers pre-18 this is
   10103              :  * set not here but in flagInhAttrs.  That flag is also used when the
   10104              :  * constraint was validated in a child but all its parent have it as NOT
   10105              :  * VALID.
   10106              :  *
   10107              :  * Any of these constraints might have the NO INHERIT bit.  If so we set
   10108              :  * ->notnull_noinh and NO INHERIT will be printed by dumpTableSchema.
   10109              :  *
   10110              :  * In case 4 above, the name comparison is a bit of a hack; it actually fails
   10111              :  * to do the right thing in all but the trivial case.  However, the downside
   10112              :  * of getting it wrong is simply that the name is printed rather than
   10113              :  * suppressed, so it's not a big deal.
   10114              :  *
   10115              :  * invalidnotnulloids is expected to be given as NULL; if any invalid not-null
   10116              :  * constraints are found, it is initialized and filled with the array of
   10117              :  * OIDs of such constraints, for later processing.
   10118              :  */
   10119              : static void
   10120        26200 : determineNotNullFlags(Archive *fout, PGresult *res, int r,
   10121              :                       TableInfo *tbinfo, int j,
   10122              :                       int i_notnull_name,
   10123              :                       int i_notnull_comment,
   10124              :                       int i_notnull_invalidoid,
   10125              :                       int i_notnull_noinherit,
   10126              :                       int i_notnull_islocal,
   10127              :                       PQExpBuffer *invalidnotnulloids)
   10128              : {
   10129        26200 :     DumpOptions *dopt = fout->dopt;
   10130              : 
   10131              :     /*
   10132              :      * If this not-null constraint is not valid, list its OID in
   10133              :      * invalidnotnulloids and do nothing further.  It'll be processed
   10134              :      * elsewhere later.
   10135              :      *
   10136              :      * Because invalid not-null constraints are rare, we don't want to malloc
   10137              :      * invalidnotnulloids until we're sure we're going it need it, which
   10138              :      * happens here.
   10139              :      */
   10140        26200 :     if (!PQgetisnull(res, r, i_notnull_invalidoid))
   10141              :     {
   10142           73 :         char       *constroid = PQgetvalue(res, r, i_notnull_invalidoid);
   10143              : 
   10144           73 :         if (*invalidnotnulloids == NULL)
   10145              :         {
   10146           43 :             *invalidnotnulloids = createPQExpBuffer();
   10147           43 :             appendPQExpBufferChar(*invalidnotnulloids, '{');
   10148           43 :             appendPQExpBufferStr(*invalidnotnulloids, constroid);
   10149              :         }
   10150              :         else
   10151           30 :             appendPQExpBuffer(*invalidnotnulloids, ",%s", constroid);
   10152              : 
   10153              :         /*
   10154              :          * Track when a parent constraint is invalid for the cases where a
   10155              :          * child constraint has been validated independenly.
   10156              :          */
   10157           73 :         tbinfo->notnull_invalid[j] = true;
   10158              : 
   10159              :         /* nothing else to do */
   10160           73 :         tbinfo->notnull_constrs[j] = NULL;
   10161           73 :         return;
   10162              :     }
   10163              : 
   10164              :     /*
   10165              :      * notnull_noinh is straight from the query result. notnull_islocal also,
   10166              :      * though flagInhAttrs may change that one later.
   10167              :      */
   10168        26127 :     tbinfo->notnull_noinh[j] = PQgetvalue(res, r, i_notnull_noinherit)[0] == 't';
   10169        26127 :     tbinfo->notnull_islocal[j] = PQgetvalue(res, r, i_notnull_islocal)[0] == 't';
   10170        26127 :     tbinfo->notnull_invalid[j] = false;
   10171              : 
   10172              :     /*
   10173              :      * Determine a constraint name to use.  If the column is not marked not-
   10174              :      * null, we set NULL which cues ... to do nothing.  An empty string says
   10175              :      * to print an unnamed NOT NULL, and anything else is a constraint name to
   10176              :      * use.
   10177              :      */
   10178        26127 :     if (fout->remoteVersion < 180000)
   10179              :     {
   10180              :         /*
   10181              :          * < 18 doesn't have not-null names, so an unnamed constraint is
   10182              :          * sufficient.
   10183              :          */
   10184            0 :         if (PQgetisnull(res, r, i_notnull_name))
   10185            0 :             tbinfo->notnull_constrs[j] = NULL;
   10186              :         else
   10187            0 :             tbinfo->notnull_constrs[j] = "";
   10188              :     }
   10189              :     else
   10190              :     {
   10191        26127 :         if (PQgetisnull(res, r, i_notnull_name))
   10192        23274 :             tbinfo->notnull_constrs[j] = NULL;
   10193              :         else
   10194              :         {
   10195              :             /*
   10196              :              * In binary upgrade of inheritance child tables, must have a
   10197              :              * constraint name that we can UPDATE later; same if there's a
   10198              :              * comment on the constraint.
   10199              :              */
   10200         2853 :             if ((dopt->binary_upgrade &&
   10201          364 :                  !tbinfo->ispartition &&
   10202         3112 :                  !tbinfo->notnull_islocal[j]) ||
   10203         2832 :                 !PQgetisnull(res, r, i_notnull_comment))
   10204              :             {
   10205           67 :                 tbinfo->notnull_constrs[j] =
   10206           67 :                     pstrdup(PQgetvalue(res, r, i_notnull_name));
   10207              :             }
   10208              :             else
   10209              :             {
   10210              :                 char       *default_name;
   10211              : 
   10212              :                 /* XXX should match ChooseConstraintName better */
   10213         2786 :                 default_name = psprintf("%s_%s_not_null", tbinfo->dobj.name,
   10214         2786 :                                         tbinfo->attnames[j]);
   10215         2786 :                 if (strcmp(default_name,
   10216         2786 :                            PQgetvalue(res, r, i_notnull_name)) == 0)
   10217         1873 :                     tbinfo->notnull_constrs[j] = "";
   10218              :                 else
   10219              :                 {
   10220          913 :                     tbinfo->notnull_constrs[j] =
   10221          913 :                         pstrdup(PQgetvalue(res, r, i_notnull_name));
   10222              :                 }
   10223         2786 :                 free(default_name);
   10224              :             }
   10225              :         }
   10226              :     }
   10227              : }
   10228              : 
   10229              : /*
   10230              :  * Test whether a column should be printed as part of table's CREATE TABLE.
   10231              :  * Column number is zero-based.
   10232              :  *
   10233              :  * Normally this is always true, but it's false for dropped columns, as well
   10234              :  * as those that were inherited without any local definition.  (If we print
   10235              :  * such a column it will mistakenly get pg_attribute.attislocal set to true.)
   10236              :  * For partitions, it's always true, because we want the partitions to be
   10237              :  * created independently and ATTACH PARTITION used afterwards.
   10238              :  *
   10239              :  * In binary_upgrade mode, we must print all columns and fix the attislocal/
   10240              :  * attisdropped state later, so as to keep control of the physical column
   10241              :  * order.
   10242              :  *
   10243              :  * This function exists because there are scattered nonobvious places that
   10244              :  * must be kept in sync with this decision.
   10245              :  */
   10246              : bool
   10247        42698 : shouldPrintColumn(const DumpOptions *dopt, const TableInfo *tbinfo, int colno)
   10248              : {
   10249        42698 :     if (dopt->binary_upgrade)
   10250         6560 :         return true;
   10251        36138 :     if (tbinfo->attisdropped[colno])
   10252          734 :         return false;
   10253        35404 :     return (tbinfo->attislocal[colno] || tbinfo->ispartition);
   10254              : }
   10255              : 
   10256              : 
   10257              : /*
   10258              :  * getTSParsers:
   10259              :  *    get information about all text search parsers in the system catalogs
   10260              :  */
   10261              : void
   10262          259 : getTSParsers(Archive *fout)
   10263              : {
   10264              :     PGresult   *res;
   10265              :     int         ntups;
   10266              :     int         i;
   10267              :     PQExpBuffer query;
   10268              :     TSParserInfo *prsinfo;
   10269              :     int         i_tableoid;
   10270              :     int         i_oid;
   10271              :     int         i_prsname;
   10272              :     int         i_prsnamespace;
   10273              :     int         i_prsstart;
   10274              :     int         i_prstoken;
   10275              :     int         i_prsend;
   10276              :     int         i_prsheadline;
   10277              :     int         i_prslextype;
   10278              : 
   10279          259 :     query = createPQExpBuffer();
   10280              : 
   10281              :     /*
   10282              :      * find all text search objects, including builtin ones; we filter out
   10283              :      * system-defined objects at dump-out time.
   10284              :      */
   10285              : 
   10286          259 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, prsname, prsnamespace, "
   10287              :                          "prsstart::oid, prstoken::oid, "
   10288              :                          "prsend::oid, prsheadline::oid, prslextype::oid "
   10289              :                          "FROM pg_ts_parser");
   10290              : 
   10291          259 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   10292              : 
   10293          259 :     ntups = PQntuples(res);
   10294              : 
   10295          259 :     prsinfo = pg_malloc_array(TSParserInfo, ntups);
   10296              : 
   10297          259 :     i_tableoid = PQfnumber(res, "tableoid");
   10298          259 :     i_oid = PQfnumber(res, "oid");
   10299          259 :     i_prsname = PQfnumber(res, "prsname");
   10300          259 :     i_prsnamespace = PQfnumber(res, "prsnamespace");
   10301          259 :     i_prsstart = PQfnumber(res, "prsstart");
   10302          259 :     i_prstoken = PQfnumber(res, "prstoken");
   10303          259 :     i_prsend = PQfnumber(res, "prsend");
   10304          259 :     i_prsheadline = PQfnumber(res, "prsheadline");
   10305          259 :     i_prslextype = PQfnumber(res, "prslextype");
   10306              : 
   10307          563 :     for (i = 0; i < ntups; i++)
   10308              :     {
   10309          304 :         prsinfo[i].dobj.objType = DO_TSPARSER;
   10310          304 :         prsinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
   10311          304 :         prsinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
   10312          304 :         AssignDumpId(&prsinfo[i].dobj);
   10313          304 :         prsinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_prsname));
   10314          608 :         prsinfo[i].dobj.namespace =
   10315          304 :             findNamespace(atooid(PQgetvalue(res, i, i_prsnamespace)));
   10316          304 :         prsinfo[i].prsstart = atooid(PQgetvalue(res, i, i_prsstart));
   10317          304 :         prsinfo[i].prstoken = atooid(PQgetvalue(res, i, i_prstoken));
   10318          304 :         prsinfo[i].prsend = atooid(PQgetvalue(res, i, i_prsend));
   10319          304 :         prsinfo[i].prsheadline = atooid(PQgetvalue(res, i, i_prsheadline));
   10320          304 :         prsinfo[i].prslextype = atooid(PQgetvalue(res, i, i_prslextype));
   10321              : 
   10322              :         /* Decide whether we want to dump it */
   10323          304 :         selectDumpableObject(&(prsinfo[i].dobj), fout);
   10324              :     }
   10325              : 
   10326          259 :     PQclear(res);
   10327              : 
   10328          259 :     destroyPQExpBuffer(query);
   10329          259 : }
   10330              : 
   10331              : /*
   10332              :  * getTSDictionaries:
   10333              :  *    get information about all text search dictionaries in the system catalogs
   10334              :  */
   10335              : void
   10336          259 : getTSDictionaries(Archive *fout)
   10337              : {
   10338              :     PGresult   *res;
   10339              :     int         ntups;
   10340              :     int         i;
   10341              :     PQExpBuffer query;
   10342              :     TSDictInfo *dictinfo;
   10343              :     int         i_tableoid;
   10344              :     int         i_oid;
   10345              :     int         i_dictname;
   10346              :     int         i_dictnamespace;
   10347              :     int         i_dictowner;
   10348              :     int         i_dicttemplate;
   10349              :     int         i_dictinitoption;
   10350              : 
   10351          259 :     query = createPQExpBuffer();
   10352              : 
   10353          259 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, dictname, "
   10354              :                          "dictnamespace, dictowner, "
   10355              :                          "dicttemplate, dictinitoption "
   10356              :                          "FROM pg_ts_dict");
   10357              : 
   10358          259 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   10359              : 
   10360          259 :     ntups = PQntuples(res);
   10361              : 
   10362          259 :     dictinfo = pg_malloc_array(TSDictInfo, ntups);
   10363              : 
   10364          259 :     i_tableoid = PQfnumber(res, "tableoid");
   10365          259 :     i_oid = PQfnumber(res, "oid");
   10366          259 :     i_dictname = PQfnumber(res, "dictname");
   10367          259 :     i_dictnamespace = PQfnumber(res, "dictnamespace");
   10368          259 :     i_dictowner = PQfnumber(res, "dictowner");
   10369          259 :     i_dictinitoption = PQfnumber(res, "dictinitoption");
   10370          259 :     i_dicttemplate = PQfnumber(res, "dicttemplate");
   10371              : 
   10372         8655 :     for (i = 0; i < ntups; i++)
   10373              :     {
   10374         8396 :         dictinfo[i].dobj.objType = DO_TSDICT;
   10375         8396 :         dictinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
   10376         8396 :         dictinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
   10377         8396 :         AssignDumpId(&dictinfo[i].dobj);
   10378         8396 :         dictinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_dictname));
   10379        16792 :         dictinfo[i].dobj.namespace =
   10380         8396 :             findNamespace(atooid(PQgetvalue(res, i, i_dictnamespace)));
   10381         8396 :         dictinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_dictowner));
   10382         8396 :         dictinfo[i].dicttemplate = atooid(PQgetvalue(res, i, i_dicttemplate));
   10383         8396 :         if (PQgetisnull(res, i, i_dictinitoption))
   10384          304 :             dictinfo[i].dictinitoption = NULL;
   10385              :         else
   10386         8092 :             dictinfo[i].dictinitoption = pg_strdup(PQgetvalue(res, i, i_dictinitoption));
   10387              : 
   10388              :         /* Decide whether we want to dump it */
   10389         8396 :         selectDumpableObject(&(dictinfo[i].dobj), fout);
   10390              :     }
   10391              : 
   10392          259 :     PQclear(res);
   10393              : 
   10394          259 :     destroyPQExpBuffer(query);
   10395          259 : }
   10396              : 
   10397              : /*
   10398              :  * getTSTemplates:
   10399              :  *    get information about all text search templates in the system catalogs
   10400              :  */
   10401              : void
   10402          259 : getTSTemplates(Archive *fout)
   10403              : {
   10404              :     PGresult   *res;
   10405              :     int         ntups;
   10406              :     int         i;
   10407              :     PQExpBuffer query;
   10408              :     TSTemplateInfo *tmplinfo;
   10409              :     int         i_tableoid;
   10410              :     int         i_oid;
   10411              :     int         i_tmplname;
   10412              :     int         i_tmplnamespace;
   10413              :     int         i_tmplinit;
   10414              :     int         i_tmpllexize;
   10415              : 
   10416          259 :     query = createPQExpBuffer();
   10417              : 
   10418          259 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, tmplname, "
   10419              :                          "tmplnamespace, tmplinit::oid, tmpllexize::oid "
   10420              :                          "FROM pg_ts_template");
   10421              : 
   10422          259 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   10423              : 
   10424          259 :     ntups = PQntuples(res);
   10425              : 
   10426          259 :     tmplinfo = pg_malloc_array(TSTemplateInfo, ntups);
   10427              : 
   10428          259 :     i_tableoid = PQfnumber(res, "tableoid");
   10429          259 :     i_oid = PQfnumber(res, "oid");
   10430          259 :     i_tmplname = PQfnumber(res, "tmplname");
   10431          259 :     i_tmplnamespace = PQfnumber(res, "tmplnamespace");
   10432          259 :     i_tmplinit = PQfnumber(res, "tmplinit");
   10433          259 :     i_tmpllexize = PQfnumber(res, "tmpllexize");
   10434              : 
   10435         1599 :     for (i = 0; i < ntups; i++)
   10436              :     {
   10437         1340 :         tmplinfo[i].dobj.objType = DO_TSTEMPLATE;
   10438         1340 :         tmplinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
   10439         1340 :         tmplinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
   10440         1340 :         AssignDumpId(&tmplinfo[i].dobj);
   10441         1340 :         tmplinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_tmplname));
   10442         2680 :         tmplinfo[i].dobj.namespace =
   10443         1340 :             findNamespace(atooid(PQgetvalue(res, i, i_tmplnamespace)));
   10444         1340 :         tmplinfo[i].tmplinit = atooid(PQgetvalue(res, i, i_tmplinit));
   10445         1340 :         tmplinfo[i].tmpllexize = atooid(PQgetvalue(res, i, i_tmpllexize));
   10446              : 
   10447              :         /* Decide whether we want to dump it */
   10448         1340 :         selectDumpableObject(&(tmplinfo[i].dobj), fout);
   10449              :     }
   10450              : 
   10451          259 :     PQclear(res);
   10452              : 
   10453          259 :     destroyPQExpBuffer(query);
   10454          259 : }
   10455              : 
   10456              : /*
   10457              :  * getTSConfigurations:
   10458              :  *    get information about all text search configurations
   10459              :  */
   10460              : void
   10461          259 : getTSConfigurations(Archive *fout)
   10462              : {
   10463              :     PGresult   *res;
   10464              :     int         ntups;
   10465              :     int         i;
   10466              :     PQExpBuffer query;
   10467              :     TSConfigInfo *cfginfo;
   10468              :     int         i_tableoid;
   10469              :     int         i_oid;
   10470              :     int         i_cfgname;
   10471              :     int         i_cfgnamespace;
   10472              :     int         i_cfgowner;
   10473              :     int         i_cfgparser;
   10474              : 
   10475          259 :     query = createPQExpBuffer();
   10476              : 
   10477          259 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, cfgname, "
   10478              :                          "cfgnamespace, cfgowner, cfgparser "
   10479              :                          "FROM pg_ts_config");
   10480              : 
   10481          259 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   10482              : 
   10483          259 :     ntups = PQntuples(res);
   10484              : 
   10485          259 :     cfginfo = pg_malloc_array(TSConfigInfo, ntups);
   10486              : 
   10487          259 :     i_tableoid = PQfnumber(res, "tableoid");
   10488          259 :     i_oid = PQfnumber(res, "oid");
   10489          259 :     i_cfgname = PQfnumber(res, "cfgname");
   10490          259 :     i_cfgnamespace = PQfnumber(res, "cfgnamespace");
   10491          259 :     i_cfgowner = PQfnumber(res, "cfgowner");
   10492          259 :     i_cfgparser = PQfnumber(res, "cfgparser");
   10493              : 
   10494         8620 :     for (i = 0; i < ntups; i++)
   10495              :     {
   10496         8361 :         cfginfo[i].dobj.objType = DO_TSCONFIG;
   10497         8361 :         cfginfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
   10498         8361 :         cfginfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
   10499         8361 :         AssignDumpId(&cfginfo[i].dobj);
   10500         8361 :         cfginfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_cfgname));
   10501        16722 :         cfginfo[i].dobj.namespace =
   10502         8361 :             findNamespace(atooid(PQgetvalue(res, i, i_cfgnamespace)));
   10503         8361 :         cfginfo[i].rolname = getRoleName(PQgetvalue(res, i, i_cfgowner));
   10504         8361 :         cfginfo[i].cfgparser = atooid(PQgetvalue(res, i, i_cfgparser));
   10505              : 
   10506              :         /* Decide whether we want to dump it */
   10507         8361 :         selectDumpableObject(&(cfginfo[i].dobj), fout);
   10508              :     }
   10509              : 
   10510          259 :     PQclear(res);
   10511              : 
   10512          259 :     destroyPQExpBuffer(query);
   10513          259 : }
   10514              : 
   10515              : /*
   10516              :  * getForeignDataWrappers:
   10517              :  *    get information about all foreign-data wrappers in the system catalogs
   10518              :  */
   10519              : void
   10520          259 : getForeignDataWrappers(Archive *fout)
   10521              : {
   10522              :     PGresult   *res;
   10523              :     int         ntups;
   10524              :     int         i;
   10525              :     PQExpBuffer query;
   10526              :     FdwInfo    *fdwinfo;
   10527              :     int         i_tableoid;
   10528              :     int         i_oid;
   10529              :     int         i_fdwname;
   10530              :     int         i_fdwowner;
   10531              :     int         i_fdwhandler;
   10532              :     int         i_fdwvalidator;
   10533              :     int         i_fdwconnection;
   10534              :     int         i_fdwacl;
   10535              :     int         i_acldefault;
   10536              :     int         i_fdwoptions;
   10537              : 
   10538          259 :     query = createPQExpBuffer();
   10539              : 
   10540          259 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, fdwname, "
   10541              :                          "fdwowner, "
   10542              :                          "fdwhandler::pg_catalog.regproc, "
   10543              :                          "fdwvalidator::pg_catalog.regproc, ");
   10544              : 
   10545          259 :     if (fout->remoteVersion >= 190000)
   10546          259 :         appendPQExpBufferStr(query, "fdwconnection::pg_catalog.regproc, ");
   10547              :     else
   10548            0 :         appendPQExpBufferStr(query, "'-' AS fdwconnection, ");
   10549              : 
   10550          259 :     appendPQExpBufferStr(query,
   10551              :                          "fdwacl, "
   10552              :                          "acldefault('F', fdwowner) AS acldefault, "
   10553              :                          "array_to_string(ARRAY("
   10554              :                          "SELECT quote_ident(option_name) || ' ' || "
   10555              :                          "quote_literal(option_value) "
   10556              :                          "FROM pg_options_to_table(fdwoptions) "
   10557              :                          "ORDER BY option_name"
   10558              :                          "), E',\n    ') AS fdwoptions "
   10559              :                          "FROM pg_foreign_data_wrapper");
   10560              : 
   10561          259 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   10562              : 
   10563          259 :     ntups = PQntuples(res);
   10564              : 
   10565          259 :     fdwinfo = pg_malloc_array(FdwInfo, ntups);
   10566              : 
   10567          259 :     i_tableoid = PQfnumber(res, "tableoid");
   10568          259 :     i_oid = PQfnumber(res, "oid");
   10569          259 :     i_fdwname = PQfnumber(res, "fdwname");
   10570          259 :     i_fdwowner = PQfnumber(res, "fdwowner");
   10571          259 :     i_fdwhandler = PQfnumber(res, "fdwhandler");
   10572          259 :     i_fdwvalidator = PQfnumber(res, "fdwvalidator");
   10573          259 :     i_fdwconnection = PQfnumber(res, "fdwconnection");
   10574          259 :     i_fdwacl = PQfnumber(res, "fdwacl");
   10575          259 :     i_acldefault = PQfnumber(res, "acldefault");
   10576          259 :     i_fdwoptions = PQfnumber(res, "fdwoptions");
   10577              : 
   10578          330 :     for (i = 0; i < ntups; i++)
   10579              :     {
   10580           71 :         fdwinfo[i].dobj.objType = DO_FDW;
   10581           71 :         fdwinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
   10582           71 :         fdwinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
   10583           71 :         AssignDumpId(&fdwinfo[i].dobj);
   10584           71 :         fdwinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_fdwname));
   10585           71 :         fdwinfo[i].dobj.namespace = NULL;
   10586           71 :         fdwinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_fdwacl));
   10587           71 :         fdwinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
   10588           71 :         fdwinfo[i].dacl.privtype = 0;
   10589           71 :         fdwinfo[i].dacl.initprivs = NULL;
   10590           71 :         fdwinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_fdwowner));
   10591           71 :         fdwinfo[i].fdwhandler = pg_strdup(PQgetvalue(res, i, i_fdwhandler));
   10592           71 :         fdwinfo[i].fdwvalidator = pg_strdup(PQgetvalue(res, i, i_fdwvalidator));
   10593           71 :         fdwinfo[i].fdwconnection = pg_strdup(PQgetvalue(res, i, i_fdwconnection));
   10594           71 :         fdwinfo[i].fdwoptions = pg_strdup(PQgetvalue(res, i, i_fdwoptions));
   10595              : 
   10596              :         /* Decide whether we want to dump it */
   10597           71 :         selectDumpableObject(&(fdwinfo[i].dobj), fout);
   10598              : 
   10599              :         /* Mark whether FDW has an ACL */
   10600           71 :         if (!PQgetisnull(res, i, i_fdwacl))
   10601           45 :             fdwinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
   10602              :     }
   10603              : 
   10604          259 :     PQclear(res);
   10605              : 
   10606          259 :     destroyPQExpBuffer(query);
   10607          259 : }
   10608              : 
   10609              : /*
   10610              :  * getForeignServers:
   10611              :  *    get information about all foreign servers in the system catalogs
   10612              :  */
   10613              : void
   10614          259 : getForeignServers(Archive *fout)
   10615              : {
   10616              :     PGresult   *res;
   10617              :     int         ntups;
   10618              :     int         i;
   10619              :     PQExpBuffer query;
   10620              :     ForeignServerInfo *srvinfo;
   10621              :     int         i_tableoid;
   10622              :     int         i_oid;
   10623              :     int         i_srvname;
   10624              :     int         i_srvowner;
   10625              :     int         i_srvfdw;
   10626              :     int         i_srvtype;
   10627              :     int         i_srvversion;
   10628              :     int         i_srvacl;
   10629              :     int         i_acldefault;
   10630              :     int         i_srvoptions;
   10631              : 
   10632          259 :     query = createPQExpBuffer();
   10633              : 
   10634          259 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, srvname, "
   10635              :                          "srvowner, "
   10636              :                          "srvfdw, srvtype, srvversion, srvacl, "
   10637              :                          "acldefault('S', srvowner) AS acldefault, "
   10638              :                          "array_to_string(ARRAY("
   10639              :                          "SELECT quote_ident(option_name) || ' ' || "
   10640              :                          "quote_literal(option_value) "
   10641              :                          "FROM pg_options_to_table(srvoptions) "
   10642              :                          "ORDER BY option_name"
   10643              :                          "), E',\n    ') AS srvoptions "
   10644              :                          "FROM pg_foreign_server");
   10645              : 
   10646          259 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   10647              : 
   10648          259 :     ntups = PQntuples(res);
   10649              : 
   10650          259 :     srvinfo = pg_malloc_array(ForeignServerInfo, ntups);
   10651              : 
   10652          259 :     i_tableoid = PQfnumber(res, "tableoid");
   10653          259 :     i_oid = PQfnumber(res, "oid");
   10654          259 :     i_srvname = PQfnumber(res, "srvname");
   10655          259 :     i_srvowner = PQfnumber(res, "srvowner");
   10656          259 :     i_srvfdw = PQfnumber(res, "srvfdw");
   10657          259 :     i_srvtype = PQfnumber(res, "srvtype");
   10658          259 :     i_srvversion = PQfnumber(res, "srvversion");
   10659          259 :     i_srvacl = PQfnumber(res, "srvacl");
   10660          259 :     i_acldefault = PQfnumber(res, "acldefault");
   10661          259 :     i_srvoptions = PQfnumber(res, "srvoptions");
   10662              : 
   10663          334 :     for (i = 0; i < ntups; i++)
   10664              :     {
   10665           75 :         srvinfo[i].dobj.objType = DO_FOREIGN_SERVER;
   10666           75 :         srvinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
   10667           75 :         srvinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
   10668           75 :         AssignDumpId(&srvinfo[i].dobj);
   10669           75 :         srvinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_srvname));
   10670           75 :         srvinfo[i].dobj.namespace = NULL;
   10671           75 :         srvinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_srvacl));
   10672           75 :         srvinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
   10673           75 :         srvinfo[i].dacl.privtype = 0;
   10674           75 :         srvinfo[i].dacl.initprivs = NULL;
   10675           75 :         srvinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_srvowner));
   10676           75 :         srvinfo[i].srvfdw = atooid(PQgetvalue(res, i, i_srvfdw));
   10677           75 :         srvinfo[i].srvtype = pg_strdup(PQgetvalue(res, i, i_srvtype));
   10678           75 :         srvinfo[i].srvversion = pg_strdup(PQgetvalue(res, i, i_srvversion));
   10679           75 :         srvinfo[i].srvoptions = pg_strdup(PQgetvalue(res, i, i_srvoptions));
   10680              : 
   10681              :         /* Decide whether we want to dump it */
   10682           75 :         selectDumpableObject(&(srvinfo[i].dobj), fout);
   10683              : 
   10684              :         /* Servers have user mappings */
   10685           75 :         srvinfo[i].dobj.components |= DUMP_COMPONENT_USERMAP;
   10686              : 
   10687              :         /* Mark whether server has an ACL */
   10688           75 :         if (!PQgetisnull(res, i, i_srvacl))
   10689           45 :             srvinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
   10690              :     }
   10691              : 
   10692          259 :     PQclear(res);
   10693              : 
   10694          259 :     destroyPQExpBuffer(query);
   10695          259 : }
   10696              : 
   10697              : /*
   10698              :  * getDefaultACLs:
   10699              :  *    get information about all default ACL information in the system catalogs
   10700              :  */
   10701              : void
   10702          259 : getDefaultACLs(Archive *fout)
   10703              : {
   10704          259 :     DumpOptions *dopt = fout->dopt;
   10705              :     DefaultACLInfo *daclinfo;
   10706              :     PQExpBuffer query;
   10707              :     PGresult   *res;
   10708              :     int         i_oid;
   10709              :     int         i_tableoid;
   10710              :     int         i_defaclrole;
   10711              :     int         i_defaclnamespace;
   10712              :     int         i_defaclobjtype;
   10713              :     int         i_defaclacl;
   10714              :     int         i_acldefault;
   10715              :     int         i,
   10716              :                 ntups;
   10717              : 
   10718          259 :     query = createPQExpBuffer();
   10719              : 
   10720              :     /*
   10721              :      * Global entries (with defaclnamespace=0) replace the hard-wired default
   10722              :      * ACL for their object type.  We should dump them as deltas from the
   10723              :      * default ACL, since that will be used as a starting point for
   10724              :      * interpreting the ALTER DEFAULT PRIVILEGES commands.  On the other hand,
   10725              :      * non-global entries can only add privileges not revoke them.  We must
   10726              :      * dump those as-is (i.e., as deltas from an empty ACL).
   10727              :      *
   10728              :      * We can use defaclobjtype as the object type for acldefault(), except
   10729              :      * for the case of 'S' (DEFACLOBJ_SEQUENCE) which must be converted to
   10730              :      * 's'.
   10731              :      */
   10732          259 :     appendPQExpBufferStr(query,
   10733              :                          "SELECT oid, tableoid, "
   10734              :                          "defaclrole, "
   10735              :                          "defaclnamespace, "
   10736              :                          "defaclobjtype, "
   10737              :                          "defaclacl, "
   10738              :                          "CASE WHEN defaclnamespace = 0 THEN "
   10739              :                          "acldefault(CASE WHEN defaclobjtype = 'S' "
   10740              :                          "THEN 's'::\"char\" ELSE defaclobjtype END, "
   10741              :                          "defaclrole) ELSE '{}' END AS acldefault "
   10742              :                          "FROM pg_default_acl");
   10743              : 
   10744          259 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   10745              : 
   10746          259 :     ntups = PQntuples(res);
   10747              : 
   10748          259 :     daclinfo = pg_malloc_array(DefaultACLInfo, ntups);
   10749              : 
   10750          259 :     i_oid = PQfnumber(res, "oid");
   10751          259 :     i_tableoid = PQfnumber(res, "tableoid");
   10752          259 :     i_defaclrole = PQfnumber(res, "defaclrole");
   10753          259 :     i_defaclnamespace = PQfnumber(res, "defaclnamespace");
   10754          259 :     i_defaclobjtype = PQfnumber(res, "defaclobjtype");
   10755          259 :     i_defaclacl = PQfnumber(res, "defaclacl");
   10756          259 :     i_acldefault = PQfnumber(res, "acldefault");
   10757              : 
   10758          453 :     for (i = 0; i < ntups; i++)
   10759              :     {
   10760          194 :         Oid         nspid = atooid(PQgetvalue(res, i, i_defaclnamespace));
   10761              : 
   10762          194 :         daclinfo[i].dobj.objType = DO_DEFAULT_ACL;
   10763          194 :         daclinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
   10764          194 :         daclinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
   10765          194 :         AssignDumpId(&daclinfo[i].dobj);
   10766              :         /* cheesy ... is it worth coming up with a better object name? */
   10767          194 :         daclinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_defaclobjtype));
   10768              : 
   10769          194 :         if (nspid != InvalidOid)
   10770           90 :             daclinfo[i].dobj.namespace = findNamespace(nspid);
   10771              :         else
   10772          104 :             daclinfo[i].dobj.namespace = NULL;
   10773              : 
   10774          194 :         daclinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_defaclacl));
   10775          194 :         daclinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
   10776          194 :         daclinfo[i].dacl.privtype = 0;
   10777          194 :         daclinfo[i].dacl.initprivs = NULL;
   10778          194 :         daclinfo[i].defaclrole = getRoleName(PQgetvalue(res, i, i_defaclrole));
   10779          194 :         daclinfo[i].defaclobjtype = *(PQgetvalue(res, i, i_defaclobjtype));
   10780              : 
   10781              :         /* Default ACLs are ACLs, of course */
   10782          194 :         daclinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
   10783              : 
   10784              :         /* Decide whether we want to dump it */
   10785          194 :         selectDumpableDefaultACL(&(daclinfo[i]), dopt);
   10786              :     }
   10787              : 
   10788          259 :     PQclear(res);
   10789              : 
   10790          259 :     destroyPQExpBuffer(query);
   10791          259 : }
   10792              : 
   10793              : /*
   10794              :  * getRoleName -- look up the name of a role, given its OID
   10795              :  *
   10796              :  * In current usage, we don't expect failures, so error out for a bad OID.
   10797              :  */
   10798              : static const char *
   10799       842828 : getRoleName(const char *roleoid_str)
   10800              : {
   10801       842828 :     Oid         roleoid = atooid(roleoid_str);
   10802              : 
   10803              :     /*
   10804              :      * Do binary search to find the appropriate item.
   10805              :      */
   10806       842828 :     if (nrolenames > 0)
   10807              :     {
   10808       842828 :         RoleNameItem *low = &rolenames[0];
   10809       842828 :         RoleNameItem *high = &rolenames[nrolenames - 1];
   10810              : 
   10811      3371374 :         while (low <= high)
   10812              :         {
   10813      3371374 :             RoleNameItem *middle = low + (high - low) / 2;
   10814              : 
   10815      3371374 :             if (roleoid < middle->roleoid)
   10816      2527262 :                 high = middle - 1;
   10817       844112 :             else if (roleoid > middle->roleoid)
   10818         1284 :                 low = middle + 1;
   10819              :             else
   10820       842828 :                 return middle->rolename; /* found a match */
   10821              :         }
   10822              :     }
   10823              : 
   10824            0 :     pg_fatal("role with OID %u does not exist", roleoid);
   10825              :     return NULL;                /* keep compiler quiet */
   10826              : }
   10827              : 
   10828              : /*
   10829              :  * collectRoleNames --
   10830              :  *
   10831              :  * Construct a table of all known roles.
   10832              :  * The table is sorted by OID for speed in lookup.
   10833              :  */
   10834              : static void
   10835          260 : collectRoleNames(Archive *fout)
   10836              : {
   10837              :     PGresult   *res;
   10838              :     const char *query;
   10839              :     int         i;
   10840              : 
   10841          260 :     query = "SELECT oid, rolname FROM pg_catalog.pg_roles ORDER BY 1";
   10842              : 
   10843          260 :     res = ExecuteSqlQuery(fout, query, PGRES_TUPLES_OK);
   10844              : 
   10845          260 :     nrolenames = PQntuples(res);
   10846              : 
   10847          260 :     rolenames = pg_malloc_array(RoleNameItem, nrolenames);
   10848              : 
   10849         5772 :     for (i = 0; i < nrolenames; i++)
   10850              :     {
   10851         5512 :         rolenames[i].roleoid = atooid(PQgetvalue(res, i, 0));
   10852         5512 :         rolenames[i].rolename = pg_strdup(PQgetvalue(res, i, 1));
   10853              :     }
   10854              : 
   10855          260 :     PQclear(res);
   10856          260 : }
   10857              : 
   10858              : /*
   10859              :  * getAdditionalACLs
   10860              :  *
   10861              :  * We have now created all the DumpableObjects, and collected the ACL data
   10862              :  * that appears in the directly-associated catalog entries.  However, there's
   10863              :  * more ACL-related info to collect.  If any of a table's columns have ACLs,
   10864              :  * we must set the TableInfo's DUMP_COMPONENT_ACL components flag, as well as
   10865              :  * its hascolumnACLs flag (we won't store the ACLs themselves here, though).
   10866              :  * Also, in versions having the pg_init_privs catalog, read that and load the
   10867              :  * information into the relevant DumpableObjects.
   10868              :  */
   10869              : static void
   10870          257 : getAdditionalACLs(Archive *fout)
   10871              : {
   10872          257 :     PQExpBuffer query = createPQExpBuffer();
   10873              :     PGresult   *res;
   10874              :     int         ntups,
   10875              :                 i;
   10876              : 
   10877              :     /* Check for per-column ACLs */
   10878          257 :     appendPQExpBufferStr(query,
   10879              :                          "SELECT DISTINCT attrelid FROM pg_attribute "
   10880              :                          "WHERE attacl IS NOT NULL");
   10881              : 
   10882          257 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   10883              : 
   10884          257 :     ntups = PQntuples(res);
   10885          684 :     for (i = 0; i < ntups; i++)
   10886              :     {
   10887          427 :         Oid         relid = atooid(PQgetvalue(res, i, 0));
   10888              :         TableInfo  *tblinfo;
   10889              : 
   10890          427 :         tblinfo = findTableByOid(relid);
   10891              :         /* OK to ignore tables we haven't got a DumpableObject for */
   10892          427 :         if (tblinfo)
   10893              :         {
   10894          427 :             tblinfo->dobj.components |= DUMP_COMPONENT_ACL;
   10895          427 :             tblinfo->hascolumnACLs = true;
   10896              :         }
   10897              :     }
   10898          257 :     PQclear(res);
   10899              : 
   10900              :     /* Fetch initial-privileges data */
   10901          257 :     if (fout->remoteVersion >= 90600)
   10902              :     {
   10903          257 :         printfPQExpBuffer(query,
   10904              :                           "SELECT objoid, classoid, objsubid, privtype, initprivs "
   10905              :                           "FROM pg_init_privs");
   10906              : 
   10907          257 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   10908              : 
   10909          257 :         ntups = PQntuples(res);
   10910        63016 :         for (i = 0; i < ntups; i++)
   10911              :         {
   10912        62759 :             Oid         objoid = atooid(PQgetvalue(res, i, 0));
   10913        62759 :             Oid         classoid = atooid(PQgetvalue(res, i, 1));
   10914        62759 :             int         objsubid = atoi(PQgetvalue(res, i, 2));
   10915        62759 :             char        privtype = *(PQgetvalue(res, i, 3));
   10916        62759 :             char       *initprivs = PQgetvalue(res, i, 4);
   10917              :             CatalogId   objId;
   10918              :             DumpableObject *dobj;
   10919              : 
   10920        62759 :             objId.tableoid = classoid;
   10921        62759 :             objId.oid = objoid;
   10922        62759 :             dobj = findObjectByCatalogId(objId);
   10923              :             /* OK to ignore entries we haven't got a DumpableObject for */
   10924        62759 :             if (dobj)
   10925              :             {
   10926              :                 /* Cope with sub-object initprivs */
   10927        45584 :                 if (objsubid != 0)
   10928              :                 {
   10929         5421 :                     if (dobj->objType == DO_TABLE)
   10930              :                     {
   10931              :                         /* For a column initprivs, set the table's ACL flags */
   10932         5421 :                         dobj->components |= DUMP_COMPONENT_ACL;
   10933         5421 :                         ((TableInfo *) dobj)->hascolumnACLs = true;
   10934              :                     }
   10935              :                     else
   10936            0 :                         pg_log_warning("unsupported pg_init_privs entry: %u %u %d",
   10937              :                                        classoid, objoid, objsubid);
   10938         5674 :                     continue;
   10939              :                 }
   10940              : 
   10941              :                 /*
   10942              :                  * We ignore any pg_init_privs.initprivs entry for the public
   10943              :                  * schema, as explained in getNamespaces().
   10944              :                  */
   10945        40163 :                 if (dobj->objType == DO_NAMESPACE &&
   10946          510 :                     strcmp(dobj->name, "public") == 0)
   10947          253 :                     continue;
   10948              : 
   10949              :                 /* Else it had better be of a type we think has ACLs */
   10950        39910 :                 if (dobj->objType == DO_NAMESPACE ||
   10951        39653 :                     dobj->objType == DO_TYPE ||
   10952        39629 :                     dobj->objType == DO_FUNC ||
   10953        39537 :                     dobj->objType == DO_AGG ||
   10954        39513 :                     dobj->objType == DO_TABLE ||
   10955            0 :                     dobj->objType == DO_PROCLANG ||
   10956            0 :                     dobj->objType == DO_FDW ||
   10957            0 :                     dobj->objType == DO_FOREIGN_SERVER)
   10958        39910 :                 {
   10959        39910 :                     DumpableObjectWithAcl *daobj = (DumpableObjectWithAcl *) dobj;
   10960              : 
   10961        39910 :                     daobj->dacl.privtype = privtype;
   10962        39910 :                     daobj->dacl.initprivs = pstrdup(initprivs);
   10963              :                 }
   10964              :                 else
   10965            0 :                     pg_log_warning("unsupported pg_init_privs entry: %u %u %d",
   10966              :                                    classoid, objoid, objsubid);
   10967              :             }
   10968              :         }
   10969          257 :         PQclear(res);
   10970              :     }
   10971              : 
   10972          257 :     destroyPQExpBuffer(query);
   10973          257 : }
   10974              : 
   10975              : /*
   10976              :  * dumpCommentExtended --
   10977              :  *
   10978              :  * This routine is used to dump any comments associated with the
   10979              :  * object handed to this routine. The routine takes the object type
   10980              :  * and object name (ready to print, except for schema decoration), plus
   10981              :  * the namespace and owner of the object (for labeling the ArchiveEntry),
   10982              :  * plus catalog ID and subid which are the lookup key for pg_description,
   10983              :  * plus the dump ID for the object (for setting a dependency).
   10984              :  * If a matching pg_description entry is found, it is dumped.
   10985              :  *
   10986              :  * Note: in some cases, such as comments for triggers and rules, the "type"
   10987              :  * string really looks like, e.g., "TRIGGER name ON".  This is a bit of a hack
   10988              :  * but it doesn't seem worth complicating the API for all callers to make
   10989              :  * it cleaner.
   10990              :  *
   10991              :  * Note: although this routine takes a dumpId for dependency purposes,
   10992              :  * that purpose is just to mark the dependency in the emitted dump file
   10993              :  * for possible future use by pg_restore.  We do NOT use it for determining
   10994              :  * ordering of the comment in the dump file, because this routine is called
   10995              :  * after dependency sorting occurs.  This routine should be called just after
   10996              :  * calling ArchiveEntry() for the specified object.
   10997              :  */
   10998              : static void
   10999         6764 : dumpCommentExtended(Archive *fout, const char *type,
   11000              :                     const char *name, const char *namespace,
   11001              :                     const char *owner, CatalogId catalogId,
   11002              :                     int subid, DumpId dumpId,
   11003              :                     const char *initdb_comment)
   11004              : {
   11005         6764 :     DumpOptions *dopt = fout->dopt;
   11006              :     CommentItem *comments;
   11007              :     int         ncomments;
   11008              : 
   11009              :     /* do nothing, if --no-comments is supplied */
   11010         6764 :     if (dopt->no_comments)
   11011            0 :         return;
   11012              : 
   11013              :     /* Comments are schema not data ... except LO comments are data */
   11014         6764 :     if (strcmp(type, "LARGE OBJECT") != 0)
   11015              :     {
   11016         6706 :         if (!dopt->dumpSchema)
   11017            0 :             return;
   11018              :     }
   11019              :     else
   11020              :     {
   11021              :         /* We do dump LO comments in binary-upgrade mode */
   11022           58 :         if (!dopt->dumpData && !dopt->binary_upgrade)
   11023            0 :             return;
   11024              :     }
   11025              : 
   11026              :     /* Search for comments associated with catalogId, using table */
   11027         6764 :     ncomments = findComments(catalogId.tableoid, catalogId.oid,
   11028              :                              &comments);
   11029              : 
   11030              :     /* Is there one matching the subid? */
   11031         6764 :     while (ncomments > 0)
   11032              :     {
   11033         6719 :         if (comments->objsubid == subid)
   11034         6719 :             break;
   11035            0 :         comments++;
   11036            0 :         ncomments--;
   11037              :     }
   11038              : 
   11039         6764 :     if (initdb_comment != NULL)
   11040              :     {
   11041              :         static CommentItem empty_comment = {.descr = ""};
   11042              : 
   11043              :         /*
   11044              :          * initdb creates this object with a comment.  Skip dumping the
   11045              :          * initdb-provided comment, which would complicate matters for
   11046              :          * non-superuser use of pg_dump.  When the DBA has removed initdb's
   11047              :          * comment, replicate that.
   11048              :          */
   11049          186 :         if (ncomments == 0)
   11050              :         {
   11051            4 :             comments = &empty_comment;
   11052            4 :             ncomments = 1;
   11053              :         }
   11054          182 :         else if (strcmp(comments->descr, initdb_comment) == 0)
   11055          182 :             ncomments = 0;
   11056              :     }
   11057              : 
   11058              :     /* If a comment exists, build COMMENT ON statement */
   11059         6764 :     if (ncomments > 0)
   11060              :     {
   11061         6541 :         PQExpBuffer query = createPQExpBuffer();
   11062         6541 :         PQExpBuffer tag = createPQExpBuffer();
   11063              : 
   11064         6541 :         appendPQExpBuffer(query, "COMMENT ON %s ", type);
   11065         6541 :         if (namespace && *namespace)
   11066         6360 :             appendPQExpBuffer(query, "%s.", fmtId(namespace));
   11067         6541 :         appendPQExpBuffer(query, "%s IS ", name);
   11068         6541 :         appendStringLiteralAH(query, comments->descr, fout);
   11069         6541 :         appendPQExpBufferStr(query, ";\n");
   11070              : 
   11071         6541 :         appendPQExpBuffer(tag, "%s %s", type, name);
   11072              : 
   11073              :         /*
   11074              :          * We mark comments as SECTION_NONE because they really belong in the
   11075              :          * same section as their parent, whether that is pre-data or
   11076              :          * post-data.
   11077              :          */
   11078         6541 :         ArchiveEntry(fout, nilCatalogId, createDumpId(),
   11079         6541 :                      ARCHIVE_OPTS(.tag = tag->data,
   11080              :                                   .namespace = namespace,
   11081              :                                   .owner = owner,
   11082              :                                   .description = "COMMENT",
   11083              :                                   .section = SECTION_NONE,
   11084              :                                   .createStmt = query->data,
   11085              :                                   .deps = &dumpId,
   11086              :                                   .nDeps = 1));
   11087              : 
   11088         6541 :         destroyPQExpBuffer(query);
   11089         6541 :         destroyPQExpBuffer(tag);
   11090              :     }
   11091              : }
   11092              : 
   11093              : /*
   11094              :  * dumpComment --
   11095              :  *
   11096              :  * Typical simplification of the above function.
   11097              :  */
   11098              : static inline void
   11099         6535 : dumpComment(Archive *fout, const char *type,
   11100              :             const char *name, const char *namespace,
   11101              :             const char *owner, CatalogId catalogId,
   11102              :             int subid, DumpId dumpId)
   11103              : {
   11104         6535 :     dumpCommentExtended(fout, type, name, namespace, owner,
   11105              :                         catalogId, subid, dumpId, NULL);
   11106         6535 : }
   11107              : 
   11108              : /*
   11109              :  * appendNamedArgument --
   11110              :  *
   11111              :  * Convenience routine for constructing parameters of the form:
   11112              :  * 'paraname', 'value'::type
   11113              :  */
   11114              : static void
   11115         5646 : appendNamedArgument(PQExpBuffer out, Archive *fout, const char *argname,
   11116              :                     const char *argtype, const char *argval)
   11117              : {
   11118         5646 :     appendPQExpBufferStr(out, ",\n\t");
   11119              : 
   11120         5646 :     appendStringLiteralAH(out, argname, fout);
   11121         5646 :     appendPQExpBufferStr(out, ", ");
   11122              : 
   11123         5646 :     appendStringLiteralAH(out, argval, fout);
   11124         5646 :     appendPQExpBuffer(out, "::%s", argtype);
   11125         5646 : }
   11126              : 
   11127              : /*
   11128              :  * fetchAttributeStats --
   11129              :  *
   11130              :  * Fetch next batch of attribute statistics for dumpRelationStats_dumper().
   11131              :  */
   11132              : static PGresult *
   11133         1039 : fetchAttributeStats(Archive *fout)
   11134              : {
   11135         1039 :     ArchiveHandle *AH = (ArchiveHandle *) fout;
   11136         1039 :     PQExpBuffer relids = createPQExpBuffer();
   11137         1039 :     PQExpBuffer nspnames = createPQExpBuffer();
   11138         1039 :     PQExpBuffer relnames = createPQExpBuffer();
   11139         1039 :     int         count = 0;
   11140         1039 :     PGresult   *res = NULL;
   11141              :     static TocEntry *te;
   11142              :     static bool restarted;
   11143         1039 :     int         max_rels = MAX_ATTR_STATS_RELS;
   11144              : 
   11145              :     /*
   11146              :      * Our query for retrieving statistics for multiple relations uses WITH
   11147              :      * ORDINALITY and multi-argument UNNEST(), both of which were introduced
   11148              :      * in v9.4.  For older versions, we resort to gathering statistics for a
   11149              :      * single relation at a time.
   11150              :      */
   11151         1039 :     if (fout->remoteVersion < 90400)
   11152            0 :         max_rels = 1;
   11153              : 
   11154              :     /* If we're just starting, set our TOC pointer. */
   11155         1039 :     if (!te)
   11156           62 :         te = AH->toc->next;
   11157              : 
   11158              :     /*
   11159              :      * We can't easily avoid a second TOC scan for the tar format because it
   11160              :      * writes restore.sql separately, which means we must execute the queries
   11161              :      * twice.  This feels risky, but there is no known reason it should
   11162              :      * generate different output than the first pass.  Even if it does, the
   11163              :      * worst-case scenario is that restore.sql might have different statistics
   11164              :      * data than the archive.
   11165              :      */
   11166         1039 :     if (!restarted && te == AH->toc && AH->format == archTar)
   11167              :     {
   11168            1 :         te = AH->toc->next;
   11169            1 :         restarted = true;
   11170              :     }
   11171              : 
   11172         1039 :     appendPQExpBufferChar(relids, '{');
   11173         1039 :     appendPQExpBufferChar(nspnames, '{');
   11174         1039 :     appendPQExpBufferChar(relnames, '{');
   11175              : 
   11176              :     /*
   11177              :      * Scan the TOC for the next set of relevant stats entries.  We assume
   11178              :      * that statistics are dumped in the order they are listed in the TOC.
   11179              :      * This is perhaps not the sturdiest assumption, so we verify it matches
   11180              :      * reality in dumpRelationStats_dumper().
   11181              :      */
   11182        16322 :     for (; te != AH->toc && count < max_rels; te = te->next)
   11183              :     {
   11184        15283 :         if ((te->reqs & REQ_STATS) == 0 ||
   11185         3431 :             strcmp(te->desc, "STATISTICS DATA") != 0)
   11186        11887 :             continue;
   11187              : 
   11188         3396 :         if (fout->remoteVersion >= 190000)
   11189              :         {
   11190         3396 :             RelStatsInfo *rsinfo = (RelStatsInfo *) te->defnDumperArg;
   11191              :             char        relid[32];
   11192              : 
   11193         3396 :             sprintf(relid, "%u", rsinfo->relid);
   11194         3396 :             appendPGArray(relids, relid);
   11195              :         }
   11196              :         else
   11197              :         {
   11198            0 :             appendPGArray(nspnames, te->namespace);
   11199            0 :             appendPGArray(relnames, te->tag);
   11200              :         }
   11201              : 
   11202         3396 :         count++;
   11203              :     }
   11204              : 
   11205         1039 :     appendPQExpBufferChar(relids, '}');
   11206         1039 :     appendPQExpBufferChar(nspnames, '}');
   11207         1039 :     appendPQExpBufferChar(relnames, '}');
   11208              : 
   11209              :     /* Execute the query for the next batch of relations. */
   11210         1039 :     if (count > 0)
   11211              :     {
   11212          107 :         PQExpBuffer query = createPQExpBuffer();
   11213              : 
   11214          107 :         appendPQExpBufferStr(query, "EXECUTE getAttributeStats(");
   11215              : 
   11216          107 :         if (fout->remoteVersion >= 190000)
   11217              :         {
   11218          107 :             appendStringLiteralAH(query, relids->data, fout);
   11219          107 :             appendPQExpBufferStr(query, "::pg_catalog.oid[])");
   11220              :         }
   11221              :         else
   11222              :         {
   11223            0 :             appendStringLiteralAH(query, nspnames->data, fout);
   11224            0 :             appendPQExpBufferStr(query, "::pg_catalog.name[],");
   11225            0 :             appendStringLiteralAH(query, relnames->data, fout);
   11226            0 :             appendPQExpBufferStr(query, "::pg_catalog.name[])");
   11227              :         }
   11228              : 
   11229          107 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   11230          107 :         destroyPQExpBuffer(query);
   11231              :     }
   11232              : 
   11233         1039 :     destroyPQExpBuffer(relids);
   11234         1039 :     destroyPQExpBuffer(nspnames);
   11235         1039 :     destroyPQExpBuffer(relnames);
   11236         1039 :     return res;
   11237              : }
   11238              : 
   11239              : /*
   11240              :  * dumpRelationStats_dumper --
   11241              :  *
   11242              :  * Generate command to import stats into the relation on the new database.
   11243              :  * This routine is called by the Archiver when it wants the statistics to be
   11244              :  * dumped.
   11245              :  */
   11246              : static char *
   11247         3396 : dumpRelationStats_dumper(Archive *fout, const void *userArg, const TocEntry *te)
   11248              : {
   11249         3396 :     const RelStatsInfo *rsinfo = userArg;
   11250              :     static PGresult *res;
   11251              :     static int  rownum;
   11252              :     PQExpBuffer query;
   11253              :     PQExpBufferData out_data;
   11254         3396 :     PQExpBuffer out = &out_data;
   11255              :     int         i_schemaname;
   11256              :     int         i_tablename;
   11257              :     int         i_attname;
   11258              :     int         i_inherited;
   11259              :     int         i_null_frac;
   11260              :     int         i_avg_width;
   11261              :     int         i_n_distinct;
   11262              :     int         i_most_common_vals;
   11263              :     int         i_most_common_freqs;
   11264              :     int         i_histogram_bounds;
   11265              :     int         i_correlation;
   11266              :     int         i_most_common_elems;
   11267              :     int         i_most_common_elem_freqs;
   11268              :     int         i_elem_count_histogram;
   11269              :     int         i_range_length_histogram;
   11270              :     int         i_range_empty_frac;
   11271              :     int         i_range_bounds_histogram;
   11272              :     static TocEntry *expected_te;
   11273              : 
   11274              :     /*
   11275              :      * fetchAttributeStats() assumes that the statistics are dumped in the
   11276              :      * order they are listed in the TOC.  We verify that here for safety.
   11277              :      */
   11278         3396 :     if (!expected_te)
   11279           62 :         expected_te = ((ArchiveHandle *) fout)->toc;
   11280              : 
   11281         3396 :     expected_te = expected_te->next;
   11282        13350 :     while ((expected_te->reqs & REQ_STATS) == 0 ||
   11283         3397 :            strcmp(expected_te->desc, "STATISTICS DATA") != 0)
   11284         9954 :         expected_te = expected_te->next;
   11285              : 
   11286         3396 :     if (te != expected_te)
   11287            0 :         pg_fatal("statistics dumped out of order (current: %d %s %s, expected: %d %s %s)",
   11288              :                  te->dumpId, te->desc, te->tag,
   11289              :                  expected_te->dumpId, expected_te->desc, expected_te->tag);
   11290              : 
   11291         3396 :     query = createPQExpBuffer();
   11292         3396 :     if (!fout->is_prepared[PREPQUERY_GETATTRIBUTESTATS])
   11293              :     {
   11294           62 :         if (fout->remoteVersion >= 190000)
   11295           62 :             appendPQExpBufferStr(query,
   11296              :                                  "PREPARE getAttributeStats(pg_catalog.oid[]) AS\n");
   11297              :         else
   11298            0 :             appendPQExpBufferStr(query,
   11299              :                                  "PREPARE getAttributeStats(pg_catalog.name[], pg_catalog.name[]) AS\n");
   11300              : 
   11301           62 :         appendPQExpBufferStr(query,
   11302              :                              "SELECT s.schemaname, s.tablename, s.attname, s.inherited, "
   11303              :                              "s.null_frac, s.avg_width, s.n_distinct, "
   11304              :                              "s.most_common_vals, s.most_common_freqs, "
   11305              :                              "s.histogram_bounds, s.correlation, "
   11306              :                              "s.most_common_elems, s.most_common_elem_freqs, "
   11307              :                              "s.elem_count_histogram, ");
   11308              : 
   11309           62 :         if (fout->remoteVersion >= 170000)
   11310           62 :             appendPQExpBufferStr(query,
   11311              :                                  "s.range_length_histogram, "
   11312              :                                  "s.range_empty_frac, "
   11313              :                                  "s.range_bounds_histogram ");
   11314              :         else
   11315            0 :             appendPQExpBufferStr(query,
   11316              :                                  "NULL AS range_length_histogram,"
   11317              :                                  "NULL AS range_empty_frac,"
   11318              :                                  "NULL AS range_bounds_histogram ");
   11319              : 
   11320              :         /*
   11321              :          * The results must be in the order of the relations supplied in the
   11322              :          * parameters to ensure we remain in sync as we walk through the TOC.
   11323              :          *
   11324              :          * For v9.4 through v18, the redundant filter clause on s.tablename =
   11325              :          * ANY(...) seems sufficient to convince the planner to use
   11326              :          * pg_class_relname_nsp_index, which avoids a full scan of pg_stats.
   11327              :          * In newer versions, pg_stats returns the table OIDs, eliminating the
   11328              :          * need for that hack.
   11329              :          *
   11330              :          * Our query for retrieving statistics for multiple relations uses
   11331              :          * WITH ORDINALITY and multi-argument UNNEST(), both of which were
   11332              :          * introduced in v9.4.  For older versions, we resort to gathering
   11333              :          * statistics for a single relation at a time.
   11334              :          */
   11335           62 :         if (fout->remoteVersion >= 190000)
   11336           62 :             appendPQExpBufferStr(query,
   11337              :                                  "FROM pg_catalog.pg_stats s "
   11338              :                                  "JOIN unnest($1) WITH ORDINALITY AS u (tableid, ord) "
   11339              :                                  "ON s.tableid = u.tableid "
   11340              :                                  "ORDER BY u.ord, s.attname, s.inherited");
   11341            0 :         else if (fout->remoteVersion >= 90400)
   11342            0 :             appendPQExpBufferStr(query,
   11343              :                                  "FROM pg_catalog.pg_stats s "
   11344              :                                  "JOIN unnest($1, $2) WITH ORDINALITY AS u (schemaname, tablename, ord) "
   11345              :                                  "ON s.schemaname = u.schemaname "
   11346              :                                  "AND s.tablename = u.tablename "
   11347              :                                  "WHERE s.tablename = ANY($2) "
   11348              :                                  "ORDER BY u.ord, s.attname, s.inherited");
   11349              :         else
   11350            0 :             appendPQExpBufferStr(query,
   11351              :                                  "FROM pg_catalog.pg_stats s "
   11352              :                                  "WHERE s.schemaname = $1[1] "
   11353              :                                  "AND s.tablename = $2[1] "
   11354              :                                  "ORDER BY s.attname, s.inherited");
   11355              : 
   11356           62 :         ExecuteSqlStatement(fout, query->data);
   11357              : 
   11358           62 :         fout->is_prepared[PREPQUERY_GETATTRIBUTESTATS] = true;
   11359           62 :         resetPQExpBuffer(query);
   11360              :     }
   11361              : 
   11362         3396 :     initPQExpBuffer(out);
   11363              : 
   11364              :     /* restore relation stats */
   11365         3396 :     appendPQExpBufferStr(out, "SELECT * FROM pg_catalog.pg_restore_relation_stats(\n");
   11366         3396 :     appendPQExpBuffer(out, "\t'version', '%d'::integer,\n",
   11367              :                       fout->remoteVersion);
   11368         3396 :     appendPQExpBufferStr(out, "\t'schemaname', ");
   11369         3396 :     appendStringLiteralAH(out, rsinfo->dobj.namespace->dobj.name, fout);
   11370         3396 :     appendPQExpBufferStr(out, ",\n");
   11371         3396 :     appendPQExpBufferStr(out, "\t'relname', ");
   11372         3396 :     appendStringLiteralAH(out, rsinfo->dobj.name, fout);
   11373         3396 :     appendPQExpBufferStr(out, ",\n");
   11374         3396 :     appendPQExpBuffer(out, "\t'relpages', '%d'::integer,\n", rsinfo->relpages);
   11375              : 
   11376              :     /*
   11377              :      * Before v14, a reltuples value of 0 was ambiguous: it could either mean
   11378              :      * the relation is empty, or it could mean that it hadn't yet been
   11379              :      * vacuumed or analyzed.  (Newer versions use -1 for the latter case.)
   11380              :      * This ambiguity allegedly can cause the planner to choose inefficient
   11381              :      * plans after restoring to v18 or newer.  To deal with this, let's just
   11382              :      * set reltuples to -1 in that case.
   11383              :      */
   11384         3396 :     if (fout->remoteVersion < 140000 && strcmp("0", rsinfo->reltuples) == 0)
   11385            0 :         appendPQExpBufferStr(out, "\t'reltuples', '-1'::real,\n");
   11386              :     else
   11387         3396 :         appendPQExpBuffer(out, "\t'reltuples', '%s'::real,\n", rsinfo->reltuples);
   11388              : 
   11389         3396 :     appendPQExpBuffer(out, "\t'relallvisible', '%d'::integer",
   11390         3396 :                       rsinfo->relallvisible);
   11391              : 
   11392         3396 :     if (fout->remoteVersion >= 180000)
   11393         3396 :         appendPQExpBuffer(out, ",\n\t'relallfrozen', '%d'::integer", rsinfo->relallfrozen);
   11394              : 
   11395         3396 :     appendPQExpBufferStr(out, "\n);\n");
   11396              : 
   11397              :     /* Fetch the next batch of attribute statistics if needed. */
   11398         3396 :     if (rownum >= PQntuples(res))
   11399              :     {
   11400         1039 :         PQclear(res);
   11401         1039 :         res = fetchAttributeStats(fout);
   11402         1039 :         rownum = 0;
   11403              :     }
   11404              : 
   11405         3396 :     i_schemaname = PQfnumber(res, "schemaname");
   11406         3396 :     i_tablename = PQfnumber(res, "tablename");
   11407         3396 :     i_attname = PQfnumber(res, "attname");
   11408         3396 :     i_inherited = PQfnumber(res, "inherited");
   11409         3396 :     i_null_frac = PQfnumber(res, "null_frac");
   11410         3396 :     i_avg_width = PQfnumber(res, "avg_width");
   11411         3396 :     i_n_distinct = PQfnumber(res, "n_distinct");
   11412         3396 :     i_most_common_vals = PQfnumber(res, "most_common_vals");
   11413         3396 :     i_most_common_freqs = PQfnumber(res, "most_common_freqs");
   11414         3396 :     i_histogram_bounds = PQfnumber(res, "histogram_bounds");
   11415         3396 :     i_correlation = PQfnumber(res, "correlation");
   11416         3396 :     i_most_common_elems = PQfnumber(res, "most_common_elems");
   11417         3396 :     i_most_common_elem_freqs = PQfnumber(res, "most_common_elem_freqs");
   11418         3396 :     i_elem_count_histogram = PQfnumber(res, "elem_count_histogram");
   11419         3396 :     i_range_length_histogram = PQfnumber(res, "range_length_histogram");
   11420         3396 :     i_range_empty_frac = PQfnumber(res, "range_empty_frac");
   11421         3396 :     i_range_bounds_histogram = PQfnumber(res, "range_bounds_histogram");
   11422              : 
   11423              :     /* restore attribute stats */
   11424         4213 :     for (; rownum < PQntuples(res); rownum++)
   11425              :     {
   11426              :         const char *attname;
   11427              : 
   11428              :         /* Stop if the next stat row in our cache isn't for this relation. */
   11429         3174 :         if (strcmp(te->tag, PQgetvalue(res, rownum, i_tablename)) != 0 ||
   11430          817 :             strcmp(te->namespace, PQgetvalue(res, rownum, i_schemaname)) != 0)
   11431              :             break;
   11432              : 
   11433          817 :         appendPQExpBufferStr(out, "SELECT * FROM pg_catalog.pg_restore_attribute_stats(\n");
   11434          817 :         appendPQExpBuffer(out, "\t'version', '%d'::integer,\n",
   11435              :                           fout->remoteVersion);
   11436          817 :         appendPQExpBufferStr(out, "\t'schemaname', ");
   11437          817 :         appendStringLiteralAH(out, rsinfo->dobj.namespace->dobj.name, fout);
   11438          817 :         appendPQExpBufferStr(out, ",\n\t'relname', ");
   11439          817 :         appendStringLiteralAH(out, rsinfo->dobj.name, fout);
   11440              : 
   11441          817 :         if (PQgetisnull(res, rownum, i_attname))
   11442            0 :             pg_fatal("unexpected null attname");
   11443          817 :         attname = PQgetvalue(res, rownum, i_attname);
   11444              : 
   11445              :         /*
   11446              :          * Indexes look up attname in indAttNames to derive attnum, all others
   11447              :          * use attname directly.  We must specify attnum for indexes, since
   11448              :          * their attnames are not necessarily stable across dump/reload.
   11449              :          */
   11450          817 :         if (rsinfo->nindAttNames == 0)
   11451              :         {
   11452          782 :             appendPQExpBufferStr(out, ",\n\t'attname', ");
   11453          782 :             appendStringLiteralAH(out, attname, fout);
   11454              :         }
   11455              :         else
   11456              :         {
   11457           35 :             bool        found = false;
   11458              : 
   11459           66 :             for (int i = 0; i < rsinfo->nindAttNames; i++)
   11460              :             {
   11461           66 :                 if (strcmp(attname, rsinfo->indAttNames[i]) == 0)
   11462              :                 {
   11463           35 :                     appendPQExpBuffer(out, ",\n\t'attnum', '%d'::smallint",
   11464              :                                       i + 1);
   11465           35 :                     found = true;
   11466           35 :                     break;
   11467              :                 }
   11468              :             }
   11469              : 
   11470           35 :             if (!found)
   11471            0 :                 pg_fatal("could not find index attname \"%s\"", attname);
   11472              :         }
   11473              : 
   11474          817 :         if (!PQgetisnull(res, rownum, i_inherited))
   11475          817 :             appendNamedArgument(out, fout, "inherited", "boolean",
   11476          817 :                                 PQgetvalue(res, rownum, i_inherited));
   11477          817 :         if (!PQgetisnull(res, rownum, i_null_frac))
   11478          817 :             appendNamedArgument(out, fout, "null_frac", "real",
   11479          817 :                                 PQgetvalue(res, rownum, i_null_frac));
   11480          817 :         if (!PQgetisnull(res, rownum, i_avg_width))
   11481          817 :             appendNamedArgument(out, fout, "avg_width", "integer",
   11482          817 :                                 PQgetvalue(res, rownum, i_avg_width));
   11483          817 :         if (!PQgetisnull(res, rownum, i_n_distinct))
   11484          817 :             appendNamedArgument(out, fout, "n_distinct", "real",
   11485          817 :                                 PQgetvalue(res, rownum, i_n_distinct));
   11486          817 :         if (!PQgetisnull(res, rownum, i_most_common_vals))
   11487          405 :             appendNamedArgument(out, fout, "most_common_vals", "text",
   11488          405 :                                 PQgetvalue(res, rownum, i_most_common_vals));
   11489          817 :         if (!PQgetisnull(res, rownum, i_most_common_freqs))
   11490          405 :             appendNamedArgument(out, fout, "most_common_freqs", "real[]",
   11491          405 :                                 PQgetvalue(res, rownum, i_most_common_freqs));
   11492          817 :         if (!PQgetisnull(res, rownum, i_histogram_bounds))
   11493          513 :             appendNamedArgument(out, fout, "histogram_bounds", "text",
   11494          513 :                                 PQgetvalue(res, rownum, i_histogram_bounds));
   11495          817 :         if (!PQgetisnull(res, rownum, i_correlation))
   11496          784 :             appendNamedArgument(out, fout, "correlation", "real",
   11497          784 :                                 PQgetvalue(res, rownum, i_correlation));
   11498          817 :         if (!PQgetisnull(res, rownum, i_most_common_elems))
   11499            8 :             appendNamedArgument(out, fout, "most_common_elems", "text",
   11500            8 :                                 PQgetvalue(res, rownum, i_most_common_elems));
   11501          817 :         if (!PQgetisnull(res, rownum, i_most_common_elem_freqs))
   11502            8 :             appendNamedArgument(out, fout, "most_common_elem_freqs", "real[]",
   11503            8 :                                 PQgetvalue(res, rownum, i_most_common_elem_freqs));
   11504          817 :         if (!PQgetisnull(res, rownum, i_elem_count_histogram))
   11505            7 :             appendNamedArgument(out, fout, "elem_count_histogram", "real[]",
   11506            7 :                                 PQgetvalue(res, rownum, i_elem_count_histogram));
   11507          817 :         if (fout->remoteVersion >= 170000)
   11508              :         {
   11509          817 :             if (!PQgetisnull(res, rownum, i_range_length_histogram))
   11510            3 :                 appendNamedArgument(out, fout, "range_length_histogram", "text",
   11511            3 :                                     PQgetvalue(res, rownum, i_range_length_histogram));
   11512          817 :             if (!PQgetisnull(res, rownum, i_range_empty_frac))
   11513            3 :                 appendNamedArgument(out, fout, "range_empty_frac", "real",
   11514            3 :                                     PQgetvalue(res, rownum, i_range_empty_frac));
   11515          817 :             if (!PQgetisnull(res, rownum, i_range_bounds_histogram))
   11516            3 :                 appendNamedArgument(out, fout, "range_bounds_histogram", "text",
   11517            3 :                                     PQgetvalue(res, rownum, i_range_bounds_histogram));
   11518              :         }
   11519          817 :         appendPQExpBufferStr(out, "\n);\n");
   11520              :     }
   11521              : 
   11522         3396 :     destroyPQExpBuffer(query);
   11523         3396 :     return out->data;
   11524              : }
   11525              : 
   11526              : /*
   11527              :  * dumpRelationStats --
   11528              :  *
   11529              :  * Make an ArchiveEntry for the relation statistics.  The Archiver will take
   11530              :  * care of gathering the statistics and generating the restore commands when
   11531              :  * they are needed.
   11532              :  */
   11533              : static void
   11534         3468 : dumpRelationStats(Archive *fout, const RelStatsInfo *rsinfo)
   11535              : {
   11536         3468 :     const DumpableObject *dobj = &rsinfo->dobj;
   11537              : 
   11538              :     /* nothing to do if we are not dumping statistics */
   11539         3468 :     if (!fout->dopt->dumpStatistics)
   11540            0 :         return;
   11541              : 
   11542         3468 :     ArchiveEntry(fout, nilCatalogId, createDumpId(),
   11543         3468 :                  ARCHIVE_OPTS(.tag = dobj->name,
   11544              :                               .namespace = dobj->namespace->dobj.name,
   11545              :                               .description = "STATISTICS DATA",
   11546              :                               .section = rsinfo->section,
   11547              :                               .defnFn = dumpRelationStats_dumper,
   11548              :                               .defnArg = rsinfo,
   11549              :                               .deps = dobj->dependencies,
   11550              :                               .nDeps = dobj->nDeps));
   11551              : }
   11552              : 
   11553              : /*
   11554              :  * dumpTableComment --
   11555              :  *
   11556              :  * As above, but dump comments for both the specified table (or view)
   11557              :  * and its columns.
   11558              :  */
   11559              : static void
   11560           74 : dumpTableComment(Archive *fout, const TableInfo *tbinfo,
   11561              :                  const char *reltypename)
   11562              : {
   11563           74 :     DumpOptions *dopt = fout->dopt;
   11564              :     CommentItem *comments;
   11565              :     int         ncomments;
   11566              :     PQExpBuffer query;
   11567              :     PQExpBuffer tag;
   11568              : 
   11569              :     /* do nothing, if --no-comments is supplied */
   11570           74 :     if (dopt->no_comments)
   11571            0 :         return;
   11572              : 
   11573              :     /* Comments are SCHEMA not data */
   11574           74 :     if (!dopt->dumpSchema)
   11575            0 :         return;
   11576              : 
   11577              :     /* Search for comments associated with relation, using table */
   11578           74 :     ncomments = findComments(tbinfo->dobj.catId.tableoid,
   11579           74 :                              tbinfo->dobj.catId.oid,
   11580              :                              &comments);
   11581              : 
   11582              :     /* If comments exist, build COMMENT ON statements */
   11583           74 :     if (ncomments <= 0)
   11584            0 :         return;
   11585              : 
   11586           74 :     query = createPQExpBuffer();
   11587           74 :     tag = createPQExpBuffer();
   11588              : 
   11589          212 :     while (ncomments > 0)
   11590              :     {
   11591          138 :         const char *descr = comments->descr;
   11592          138 :         int         objsubid = comments->objsubid;
   11593              : 
   11594          138 :         if (objsubid == 0)
   11595              :         {
   11596           32 :             resetPQExpBuffer(tag);
   11597           32 :             appendPQExpBuffer(tag, "%s %s", reltypename,
   11598           32 :                               fmtId(tbinfo->dobj.name));
   11599              : 
   11600           32 :             resetPQExpBuffer(query);
   11601           32 :             appendPQExpBuffer(query, "COMMENT ON %s %s IS ", reltypename,
   11602           32 :                               fmtQualifiedDumpable(tbinfo));
   11603           32 :             appendStringLiteralAH(query, descr, fout);
   11604           32 :             appendPQExpBufferStr(query, ";\n");
   11605              : 
   11606           32 :             ArchiveEntry(fout, nilCatalogId, createDumpId(),
   11607           32 :                          ARCHIVE_OPTS(.tag = tag->data,
   11608              :                                       .namespace = tbinfo->dobj.namespace->dobj.name,
   11609              :                                       .owner = tbinfo->rolname,
   11610              :                                       .description = "COMMENT",
   11611              :                                       .section = SECTION_NONE,
   11612              :                                       .createStmt = query->data,
   11613              :                                       .deps = &(tbinfo->dobj.dumpId),
   11614              :                                       .nDeps = 1));
   11615              :         }
   11616          106 :         else if (objsubid > 0 && objsubid <= tbinfo->numatts)
   11617              :         {
   11618          106 :             resetPQExpBuffer(tag);
   11619          106 :             appendPQExpBuffer(tag, "COLUMN %s.",
   11620          106 :                               fmtId(tbinfo->dobj.name));
   11621          106 :             appendPQExpBufferStr(tag, fmtId(tbinfo->attnames[objsubid - 1]));
   11622              : 
   11623          106 :             resetPQExpBuffer(query);
   11624          106 :             appendPQExpBuffer(query, "COMMENT ON COLUMN %s.",
   11625          106 :                               fmtQualifiedDumpable(tbinfo));
   11626          106 :             appendPQExpBuffer(query, "%s IS ",
   11627          106 :                               fmtId(tbinfo->attnames[objsubid - 1]));
   11628          106 :             appendStringLiteralAH(query, descr, fout);
   11629          106 :             appendPQExpBufferStr(query, ";\n");
   11630              : 
   11631          106 :             ArchiveEntry(fout, nilCatalogId, createDumpId(),
   11632          106 :                          ARCHIVE_OPTS(.tag = tag->data,
   11633              :                                       .namespace = tbinfo->dobj.namespace->dobj.name,
   11634              :                                       .owner = tbinfo->rolname,
   11635              :                                       .description = "COMMENT",
   11636              :                                       .section = SECTION_NONE,
   11637              :                                       .createStmt = query->data,
   11638              :                                       .deps = &(tbinfo->dobj.dumpId),
   11639              :                                       .nDeps = 1));
   11640              :         }
   11641              : 
   11642          138 :         comments++;
   11643          138 :         ncomments--;
   11644              :     }
   11645              : 
   11646           74 :     destroyPQExpBuffer(query);
   11647           74 :     destroyPQExpBuffer(tag);
   11648              : }
   11649              : 
   11650              : /*
   11651              :  * findComments --
   11652              :  *
   11653              :  * Find the comment(s), if any, associated with the given object.  All the
   11654              :  * objsubid values associated with the given classoid/objoid are found with
   11655              :  * one search.
   11656              :  */
   11657              : static int
   11658         6870 : findComments(Oid classoid, Oid objoid, CommentItem **items)
   11659              : {
   11660         6870 :     CommentItem *middle = NULL;
   11661              :     CommentItem *low;
   11662              :     CommentItem *high;
   11663              :     int         nmatch;
   11664              : 
   11665              :     /*
   11666              :      * Do binary search to find some item matching the object.
   11667              :      */
   11668         6870 :     low = &comments[0];
   11669         6870 :     high = &comments[ncomments - 1];
   11670        67409 :     while (low <= high)
   11671              :     {
   11672        67364 :         middle = low + (high - low) / 2;
   11673              : 
   11674        67364 :         if (classoid < middle->classoid)
   11675         6853 :             high = middle - 1;
   11676        60511 :         else if (classoid > middle->classoid)
   11677         7216 :             low = middle + 1;
   11678        53295 :         else if (objoid < middle->objoid)
   11679        23236 :             high = middle - 1;
   11680        30059 :         else if (objoid > middle->objoid)
   11681        23234 :             low = middle + 1;
   11682              :         else
   11683         6825 :             break;              /* found a match */
   11684              :     }
   11685              : 
   11686         6870 :     if (low > high)              /* no matches */
   11687              :     {
   11688           45 :         *items = NULL;
   11689           45 :         return 0;
   11690              :     }
   11691              : 
   11692              :     /*
   11693              :      * Now determine how many items match the object.  The search loop
   11694              :      * invariant still holds: only items between low and high inclusive could
   11695              :      * match.
   11696              :      */
   11697         6825 :     nmatch = 1;
   11698         6825 :     while (middle > low)
   11699              :     {
   11700         3477 :         if (classoid != middle[-1].classoid ||
   11701         3373 :             objoid != middle[-1].objoid)
   11702              :             break;
   11703            0 :         middle--;
   11704            0 :         nmatch++;
   11705              :     }
   11706              : 
   11707         6825 :     *items = middle;
   11708              : 
   11709         6825 :     middle += nmatch;
   11710         6889 :     while (middle <= high)
   11711              :     {
   11712         3673 :         if (classoid != middle->classoid ||
   11713         3159 :             objoid != middle->objoid)
   11714              :             break;
   11715           64 :         middle++;
   11716           64 :         nmatch++;
   11717              :     }
   11718              : 
   11719         6825 :     return nmatch;
   11720              : }
   11721              : 
   11722              : /*
   11723              :  * collectComments --
   11724              :  *
   11725              :  * Construct a table of all comments available for database objects;
   11726              :  * also set the has-comment component flag for each relevant object.
   11727              :  *
   11728              :  * We used to do per-object queries for the comments, but it's much faster
   11729              :  * to pull them all over at once, and on most databases the memory cost
   11730              :  * isn't high.
   11731              :  *
   11732              :  * The table is sorted by classoid/objid/objsubid for speed in lookup.
   11733              :  */
   11734              : static void
   11735          259 : collectComments(Archive *fout)
   11736              : {
   11737              :     PGresult   *res;
   11738              :     PQExpBuffer query;
   11739              :     int         i_description;
   11740              :     int         i_classoid;
   11741              :     int         i_objoid;
   11742              :     int         i_objsubid;
   11743              :     int         ntups;
   11744              :     int         i;
   11745              :     DumpableObject *dobj;
   11746              : 
   11747          259 :     query = createPQExpBuffer();
   11748              : 
   11749          259 :     appendPQExpBufferStr(query, "SELECT description, classoid, objoid, objsubid "
   11750              :                          "FROM pg_catalog.pg_description "
   11751              :                          "ORDER BY classoid, objoid, objsubid");
   11752              : 
   11753          259 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   11754              : 
   11755              :     /* Construct lookup table containing OIDs in numeric form */
   11756              : 
   11757          259 :     i_description = PQfnumber(res, "description");
   11758          259 :     i_classoid = PQfnumber(res, "classoid");
   11759          259 :     i_objoid = PQfnumber(res, "objoid");
   11760          259 :     i_objsubid = PQfnumber(res, "objsubid");
   11761              : 
   11762          259 :     ntups = PQntuples(res);
   11763              : 
   11764          259 :     comments = pg_malloc_array(CommentItem, ntups);
   11765          259 :     ncomments = 0;
   11766          259 :     dobj = NULL;
   11767              : 
   11768      1407078 :     for (i = 0; i < ntups; i++)
   11769              :     {
   11770              :         CatalogId   objId;
   11771              :         int         subid;
   11772              : 
   11773      1406819 :         objId.tableoid = atooid(PQgetvalue(res, i, i_classoid));
   11774      1406819 :         objId.oid = atooid(PQgetvalue(res, i, i_objoid));
   11775      1406819 :         subid = atoi(PQgetvalue(res, i, i_objsubid));
   11776              : 
   11777              :         /* We needn't remember comments that don't match any dumpable object */
   11778      1406819 :         if (dobj == NULL ||
   11779       514923 :             dobj->catId.tableoid != objId.tableoid ||
   11780       511837 :             dobj->catId.oid != objId.oid)
   11781      1406729 :             dobj = findObjectByCatalogId(objId);
   11782      1406819 :         if (dobj == NULL)
   11783       891643 :             continue;
   11784              : 
   11785              :         /*
   11786              :          * Comments on columns of composite types are linked to the type's
   11787              :          * pg_class entry, but we need to set the DUMP_COMPONENT_COMMENT flag
   11788              :          * in the type's own DumpableObject.
   11789              :          */
   11790       515176 :         if (subid != 0 && dobj->objType == DO_TABLE &&
   11791          194 :             ((TableInfo *) dobj)->relkind == RELKIND_COMPOSITE_TYPE)
   11792           45 :         {
   11793              :             TypeInfo   *cTypeInfo;
   11794              : 
   11795           45 :             cTypeInfo = findTypeByOid(((TableInfo *) dobj)->reltype);
   11796           45 :             if (cTypeInfo)
   11797           45 :                 cTypeInfo->dobj.components |= DUMP_COMPONENT_COMMENT;
   11798              :         }
   11799              :         else
   11800       515131 :             dobj->components |= DUMP_COMPONENT_COMMENT;
   11801              : 
   11802       515176 :         comments[ncomments].descr = pg_strdup(PQgetvalue(res, i, i_description));
   11803       515176 :         comments[ncomments].classoid = objId.tableoid;
   11804       515176 :         comments[ncomments].objoid = objId.oid;
   11805       515176 :         comments[ncomments].objsubid = subid;
   11806       515176 :         ncomments++;
   11807              :     }
   11808              : 
   11809          259 :     PQclear(res);
   11810          259 :     destroyPQExpBuffer(query);
   11811          259 : }
   11812              : 
   11813              : /*
   11814              :  * dumpDumpableObject
   11815              :  *
   11816              :  * This routine and its subsidiaries are responsible for creating
   11817              :  * ArchiveEntries (TOC objects) for each object to be dumped.
   11818              :  */
   11819              : static void
   11820       980202 : dumpDumpableObject(Archive *fout, DumpableObject *dobj)
   11821              : {
   11822              :     /*
   11823              :      * Clear any dump-request bits for components that don't exist for this
   11824              :      * object.  (This makes it safe to initially use DUMP_COMPONENT_ALL as the
   11825              :      * request for every kind of object.)
   11826              :      */
   11827       980202 :     dobj->dump &= dobj->components;
   11828              : 
   11829              :     /* Now, short-circuit if there's nothing to be done here. */
   11830       980202 :     if (dobj->dump == 0)
   11831       887962 :         return;
   11832              : 
   11833        92240 :     switch (dobj->objType)
   11834              :     {
   11835          660 :         case DO_NAMESPACE:
   11836          660 :             dumpNamespace(fout, (const NamespaceInfo *) dobj);
   11837          660 :             break;
   11838           25 :         case DO_EXTENSION:
   11839           25 :             dumpExtension(fout, (const ExtensionInfo *) dobj);
   11840           25 :             break;
   11841          923 :         case DO_TYPE:
   11842          923 :             dumpType(fout, (const TypeInfo *) dobj);
   11843          923 :             break;
   11844           73 :         case DO_SHELL_TYPE:
   11845           73 :             dumpShellType(fout, (const ShellTypeInfo *) dobj);
   11846           73 :             break;
   11847         1858 :         case DO_FUNC:
   11848         1858 :             dumpFunc(fout, (const FuncInfo *) dobj);
   11849         1858 :             break;
   11850          292 :         case DO_AGG:
   11851          292 :             dumpAgg(fout, (const AggInfo *) dobj);
   11852          292 :             break;
   11853         2522 :         case DO_OPERATOR:
   11854         2522 :             dumpOpr(fout, (const OprInfo *) dobj);
   11855         2522 :             break;
   11856           80 :         case DO_ACCESS_METHOD:
   11857           80 :             dumpAccessMethod(fout, (const AccessMethodInfo *) dobj);
   11858           80 :             break;
   11859          666 :         case DO_OPCLASS:
   11860          666 :             dumpOpclass(fout, (const OpclassInfo *) dobj);
   11861          666 :             break;
   11862          555 :         case DO_OPFAMILY:
   11863          555 :             dumpOpfamily(fout, (const OpfamilyInfo *) dobj);
   11864          555 :             break;
   11865         2729 :         case DO_COLLATION:
   11866         2729 :             dumpCollation(fout, (const CollInfo *) dobj);
   11867         2729 :             break;
   11868          422 :         case DO_CONVERSION:
   11869          422 :             dumpConversion(fout, (const ConvInfo *) dobj);
   11870          422 :             break;
   11871        44004 :         case DO_TABLE:
   11872        44004 :             dumpTable(fout, (const TableInfo *) dobj);
   11873        44004 :             break;
   11874         1421 :         case DO_TABLE_ATTACH:
   11875         1421 :             dumpTableAttach(fout, (const TableAttachInfo *) dobj);
   11876         1421 :             break;
   11877         1047 :         case DO_ATTRDEF:
   11878         1047 :             dumpAttrDef(fout, (const AttrDefInfo *) dobj);
   11879         1047 :             break;
   11880         2758 :         case DO_INDEX:
   11881         2758 :             dumpIndex(fout, (const IndxInfo *) dobj);
   11882         2758 :             break;
   11883          594 :         case DO_INDEX_ATTACH:
   11884          594 :             dumpIndexAttach(fout, (const IndexAttachInfo *) dobj);
   11885          594 :             break;
   11886          171 :         case DO_STATSEXT:
   11887          171 :             dumpStatisticsExt(fout, (const StatsExtInfo *) dobj);
   11888          171 :             dumpStatisticsExtStats(fout, (const StatsExtInfo *) dobj);
   11889          171 :             break;
   11890          345 :         case DO_REFRESH_MATVIEW:
   11891          345 :             refreshMatViewData(fout, (const TableDataInfo *) dobj);
   11892          345 :             break;
   11893         1150 :         case DO_RULE:
   11894         1150 :             dumpRule(fout, (const RuleInfo *) dobj);
   11895         1150 :             break;
   11896          523 :         case DO_TRIGGER:
   11897          523 :             dumpTrigger(fout, (const TriggerInfo *) dobj);
   11898          523 :             break;
   11899           42 :         case DO_EVENT_TRIGGER:
   11900           42 :             dumpEventTrigger(fout, (const EventTriggerInfo *) dobj);
   11901           42 :             break;
   11902         2473 :         case DO_CONSTRAINT:
   11903         2473 :             dumpConstraint(fout, (const ConstraintInfo *) dobj);
   11904         2473 :             break;
   11905          231 :         case DO_FK_CONSTRAINT:
   11906          231 :             dumpConstraint(fout, (const ConstraintInfo *) dobj);
   11907          231 :             break;
   11908           82 :         case DO_PROCLANG:
   11909           82 :             dumpProcLang(fout, (const ProcLangInfo *) dobj);
   11910           82 :             break;
   11911           67 :         case DO_CAST:
   11912           67 :             dumpCast(fout, (const CastInfo *) dobj);
   11913           67 :             break;
   11914           42 :         case DO_TRANSFORM:
   11915           42 :             dumpTransform(fout, (const TransformInfo *) dobj);
   11916           42 :             break;
   11917          402 :         case DO_SEQUENCE_SET:
   11918          402 :             dumpSequenceData(fout, (const TableDataInfo *) dobj);
   11919          402 :             break;
   11920         4636 :         case DO_TABLE_DATA:
   11921         4636 :             dumpTableData(fout, (const TableDataInfo *) dobj);
   11922         4636 :             break;
   11923        15370 :         case DO_DUMMY_TYPE:
   11924              :             /* table rowtypes and array types are never dumped separately */
   11925        15370 :             break;
   11926           41 :         case DO_TSPARSER:
   11927           41 :             dumpTSParser(fout, (const TSParserInfo *) dobj);
   11928           41 :             break;
   11929          179 :         case DO_TSDICT:
   11930          179 :             dumpTSDictionary(fout, (const TSDictInfo *) dobj);
   11931          179 :             break;
   11932           53 :         case DO_TSTEMPLATE:
   11933           53 :             dumpTSTemplate(fout, (const TSTemplateInfo *) dobj);
   11934           53 :             break;
   11935          154 :         case DO_TSCONFIG:
   11936          154 :             dumpTSConfig(fout, (const TSConfigInfo *) dobj);
   11937          154 :             break;
   11938           52 :         case DO_FDW:
   11939           52 :             dumpForeignDataWrapper(fout, (const FdwInfo *) dobj);
   11940           52 :             break;
   11941           56 :         case DO_FOREIGN_SERVER:
   11942           56 :             dumpForeignServer(fout, (const ForeignServerInfo *) dobj);
   11943           56 :             break;
   11944          160 :         case DO_DEFAULT_ACL:
   11945          160 :             dumpDefaultACL(fout, (const DefaultACLInfo *) dobj);
   11946          160 :             break;
   11947           84 :         case DO_LARGE_OBJECT:
   11948           84 :             dumpLO(fout, (const LoInfo *) dobj);
   11949           84 :             break;
   11950           84 :         case DO_LARGE_OBJECT_DATA:
   11951           84 :             if (dobj->dump & DUMP_COMPONENT_DATA)
   11952              :             {
   11953              :                 LoInfo     *loinfo;
   11954              :                 TocEntry   *te;
   11955              : 
   11956           84 :                 loinfo = (LoInfo *) findObjectByDumpId(dobj->dependencies[0]);
   11957           84 :                 if (loinfo == NULL)
   11958            0 :                     pg_fatal("missing metadata for large objects \"%s\"",
   11959              :                              dobj->name);
   11960              : 
   11961           84 :                 te = ArchiveEntry(fout, dobj->catId, dobj->dumpId,
   11962           84 :                                   ARCHIVE_OPTS(.tag = dobj->name,
   11963              :                                                .owner = loinfo->rolname,
   11964              :                                                .description = "BLOBS",
   11965              :                                                .section = SECTION_DATA,
   11966              :                                                .deps = dobj->dependencies,
   11967              :                                                .nDeps = dobj->nDeps,
   11968              :                                                .dumpFn = dumpLOs,
   11969              :                                                .dumpArg = loinfo));
   11970              : 
   11971              :                 /*
   11972              :                  * Set the TocEntry's dataLength in case we are doing a
   11973              :                  * parallel dump and want to order dump jobs by table size.
   11974              :                  * (We need some size estimate for every TocEntry with a
   11975              :                  * DataDumper function.)  We don't currently have any cheap
   11976              :                  * way to estimate the size of LOs, but fortunately it doesn't
   11977              :                  * matter too much as long as we get large batches of LOs
   11978              :                  * processed reasonably early.  Assume 8K per blob.
   11979              :                  */
   11980           84 :                 te->dataLength = loinfo->numlos * (pgoff_t) 8192;
   11981              :             }
   11982           84 :             break;
   11983          336 :         case DO_POLICY:
   11984          336 :             dumpPolicy(fout, (const PolicyInfo *) dobj);
   11985          336 :             break;
   11986          396 :         case DO_PUBLICATION:
   11987          396 :             dumpPublication(fout, (const PublicationInfo *) dobj);
   11988          396 :             break;
   11989          284 :         case DO_PUBLICATION_REL:
   11990          284 :             dumpPublicationTable(fout, (const PublicationRelInfo *) dobj);
   11991          284 :             break;
   11992           99 :         case DO_PUBLICATION_TABLE_IN_SCHEMA:
   11993           99 :             dumpPublicationNamespace(fout,
   11994              :                                      (const PublicationSchemaInfo *) dobj);
   11995           99 :             break;
   11996          110 :         case DO_SUBSCRIPTION:
   11997          110 :             dumpSubscription(fout, (const SubscriptionInfo *) dobj);
   11998          110 :             break;
   11999            3 :         case DO_SUBSCRIPTION_REL:
   12000            3 :             dumpSubscriptionTable(fout, (const SubRelInfo *) dobj);
   12001            3 :             break;
   12002         3468 :         case DO_REL_STATS:
   12003         3468 :             dumpRelationStats(fout, (const RelStatsInfo *) dobj);
   12004         3468 :             break;
   12005          518 :         case DO_PRE_DATA_BOUNDARY:
   12006              :         case DO_POST_DATA_BOUNDARY:
   12007              :             /* never dumped, nothing to do */
   12008          518 :             break;
   12009              :     }
   12010              : }
   12011              : 
   12012              : /*
   12013              :  * dumpNamespace
   12014              :  *    writes out to fout the queries to recreate a user-defined namespace
   12015              :  */
   12016              : static void
   12017          660 : dumpNamespace(Archive *fout, const NamespaceInfo *nspinfo)
   12018              : {
   12019          660 :     DumpOptions *dopt = fout->dopt;
   12020              :     PQExpBuffer q;
   12021              :     PQExpBuffer delq;
   12022              :     char       *qnspname;
   12023              : 
   12024              :     /* Do nothing if not dumping schema */
   12025          660 :     if (!dopt->dumpSchema)
   12026           28 :         return;
   12027              : 
   12028          632 :     q = createPQExpBuffer();
   12029          632 :     delq = createPQExpBuffer();
   12030              : 
   12031          632 :     qnspname = pg_strdup(fmtId(nspinfo->dobj.name));
   12032              : 
   12033          632 :     if (nspinfo->create)
   12034              :     {
   12035          408 :         appendPQExpBuffer(delq, "DROP SCHEMA %s;\n", qnspname);
   12036          408 :         appendPQExpBuffer(q, "CREATE SCHEMA %s;\n", qnspname);
   12037              :     }
   12038              :     else
   12039              :     {
   12040              :         /* see selectDumpableNamespace() */
   12041          224 :         appendPQExpBufferStr(delq,
   12042              :                              "-- *not* dropping schema, since initdb creates it\n");
   12043          224 :         appendPQExpBufferStr(q,
   12044              :                              "-- *not* creating schema, since initdb creates it\n");
   12045              :     }
   12046              : 
   12047          632 :     if (dopt->binary_upgrade)
   12048          102 :         binary_upgrade_extension_member(q, &nspinfo->dobj,
   12049              :                                         "SCHEMA", qnspname, NULL);
   12050              : 
   12051          632 :     if (nspinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   12052          214 :         ArchiveEntry(fout, nspinfo->dobj.catId, nspinfo->dobj.dumpId,
   12053          214 :                      ARCHIVE_OPTS(.tag = nspinfo->dobj.name,
   12054              :                                   .owner = nspinfo->rolname,
   12055              :                                   .description = "SCHEMA",
   12056              :                                   .section = SECTION_PRE_DATA,
   12057              :                                   .createStmt = q->data,
   12058              :                                   .dropStmt = delq->data));
   12059              : 
   12060              :     /* Dump Schema Comments and Security Labels */
   12061          632 :     if (nspinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   12062              :     {
   12063          229 :         const char *initdb_comment = NULL;
   12064              : 
   12065          229 :         if (!nspinfo->create && strcmp(qnspname, "public") == 0)
   12066          186 :             initdb_comment = "standard public schema";
   12067          229 :         dumpCommentExtended(fout, "SCHEMA", qnspname,
   12068          229 :                             NULL, nspinfo->rolname,
   12069          229 :                             nspinfo->dobj.catId, 0, nspinfo->dobj.dumpId,
   12070              :                             initdb_comment);
   12071              :     }
   12072              : 
   12073          632 :     if (nspinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
   12074            0 :         dumpSecLabel(fout, "SCHEMA", qnspname,
   12075            0 :                      NULL, nspinfo->rolname,
   12076            0 :                      nspinfo->dobj.catId, 0, nspinfo->dobj.dumpId);
   12077              : 
   12078          632 :     if (nspinfo->dobj.dump & DUMP_COMPONENT_ACL)
   12079          530 :         dumpACL(fout, nspinfo->dobj.dumpId, InvalidDumpId, "SCHEMA",
   12080              :                 qnspname, NULL, NULL,
   12081          530 :                 NULL, nspinfo->rolname, &nspinfo->dacl);
   12082              : 
   12083          632 :     free(qnspname);
   12084              : 
   12085          632 :     destroyPQExpBuffer(q);
   12086          632 :     destroyPQExpBuffer(delq);
   12087              : }
   12088              : 
   12089              : /*
   12090              :  * dumpExtension
   12091              :  *    writes out to fout the queries to recreate an extension
   12092              :  */
   12093              : static void
   12094           25 : dumpExtension(Archive *fout, const ExtensionInfo *extinfo)
   12095              : {
   12096           25 :     DumpOptions *dopt = fout->dopt;
   12097              :     PQExpBuffer q;
   12098              :     PQExpBuffer delq;
   12099              :     char       *qextname;
   12100              : 
   12101              :     /* Do nothing if not dumping schema */
   12102           25 :     if (!dopt->dumpSchema)
   12103            1 :         return;
   12104              : 
   12105           24 :     q = createPQExpBuffer();
   12106           24 :     delq = createPQExpBuffer();
   12107              : 
   12108           24 :     qextname = pg_strdup(fmtId(extinfo->dobj.name));
   12109              : 
   12110           24 :     appendPQExpBuffer(delq, "DROP EXTENSION %s;\n", qextname);
   12111              : 
   12112           24 :     if (!dopt->binary_upgrade)
   12113              :     {
   12114              :         /*
   12115              :          * In a regular dump, we simply create the extension, intentionally
   12116              :          * not specifying a version, so that the destination installation's
   12117              :          * default version is used.
   12118              :          *
   12119              :          * Use of IF NOT EXISTS here is unlike our behavior for other object
   12120              :          * types; but there are various scenarios in which it's convenient to
   12121              :          * manually create the desired extension before restoring, so we
   12122              :          * prefer to allow it to exist already.
   12123              :          */
   12124           17 :         appendPQExpBuffer(q, "CREATE EXTENSION IF NOT EXISTS %s WITH SCHEMA %s;\n",
   12125           17 :                           qextname, fmtId(extinfo->namespace));
   12126              :     }
   12127              :     else
   12128              :     {
   12129              :         /*
   12130              :          * In binary-upgrade mode, it's critical to reproduce the state of the
   12131              :          * database exactly, so our procedure is to create an empty extension,
   12132              :          * restore all the contained objects normally, and add them to the
   12133              :          * extension one by one.  This function performs just the first of
   12134              :          * those steps.  binary_upgrade_extension_member() takes care of
   12135              :          * adding member objects as they're created.
   12136              :          */
   12137              :         int         i;
   12138              :         int         n;
   12139              : 
   12140            7 :         appendPQExpBufferStr(q, "-- For binary upgrade, create an empty extension and insert objects into it\n");
   12141              : 
   12142              :         /*
   12143              :          * We unconditionally create the extension, so we must drop it if it
   12144              :          * exists.  This could happen if the user deleted 'plpgsql' and then
   12145              :          * readded it, causing its oid to be greater than g_last_builtin_oid.
   12146              :          */
   12147            7 :         appendPQExpBuffer(q, "DROP EXTENSION IF EXISTS %s;\n", qextname);
   12148              : 
   12149            7 :         appendPQExpBufferStr(q,
   12150              :                              "SELECT pg_catalog.binary_upgrade_create_empty_extension(");
   12151            7 :         appendStringLiteralAH(q, extinfo->dobj.name, fout);
   12152            7 :         appendPQExpBufferStr(q, ", ");
   12153            7 :         appendStringLiteralAH(q, extinfo->namespace, fout);
   12154            7 :         appendPQExpBufferStr(q, ", ");
   12155            7 :         appendPQExpBuffer(q, "%s, ", extinfo->relocatable ? "true" : "false");
   12156            7 :         appendStringLiteralAH(q, extinfo->extversion, fout);
   12157            7 :         appendPQExpBufferStr(q, ", ");
   12158              : 
   12159              :         /*
   12160              :          * Note that we're pushing extconfig (an OID array) back into
   12161              :          * pg_extension exactly as-is.  This is OK because pg_class OIDs are
   12162              :          * preserved in binary upgrade.
   12163              :          */
   12164            7 :         if (strlen(extinfo->extconfig) > 2)
   12165            1 :             appendStringLiteralAH(q, extinfo->extconfig, fout);
   12166              :         else
   12167            6 :             appendPQExpBufferStr(q, "NULL");
   12168            7 :         appendPQExpBufferStr(q, ", ");
   12169            7 :         if (strlen(extinfo->extcondition) > 2)
   12170            1 :             appendStringLiteralAH(q, extinfo->extcondition, fout);
   12171              :         else
   12172            6 :             appendPQExpBufferStr(q, "NULL");
   12173            7 :         appendPQExpBufferStr(q, ", ");
   12174            7 :         appendPQExpBufferStr(q, "ARRAY[");
   12175            7 :         n = 0;
   12176           14 :         for (i = 0; i < extinfo->dobj.nDeps; i++)
   12177              :         {
   12178              :             DumpableObject *extobj;
   12179              : 
   12180            7 :             extobj = findObjectByDumpId(extinfo->dobj.dependencies[i]);
   12181            7 :             if (extobj && extobj->objType == DO_EXTENSION)
   12182              :             {
   12183            0 :                 if (n++ > 0)
   12184            0 :                     appendPQExpBufferChar(q, ',');
   12185            0 :                 appendStringLiteralAH(q, extobj->name, fout);
   12186              :             }
   12187              :         }
   12188            7 :         appendPQExpBufferStr(q, "]::pg_catalog.text[]");
   12189            7 :         appendPQExpBufferStr(q, ");\n");
   12190              :     }
   12191              : 
   12192           24 :     if (extinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   12193           24 :         ArchiveEntry(fout, extinfo->dobj.catId, extinfo->dobj.dumpId,
   12194           24 :                      ARCHIVE_OPTS(.tag = extinfo->dobj.name,
   12195              :                                   .description = "EXTENSION",
   12196              :                                   .section = SECTION_PRE_DATA,
   12197              :                                   .createStmt = q->data,
   12198              :                                   .dropStmt = delq->data));
   12199              : 
   12200              :     /* Dump Extension Comments */
   12201           24 :     if (extinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   12202           24 :         dumpComment(fout, "EXTENSION", qextname,
   12203              :                     NULL, "",
   12204           24 :                     extinfo->dobj.catId, 0, extinfo->dobj.dumpId);
   12205              : 
   12206           24 :     free(qextname);
   12207              : 
   12208           24 :     destroyPQExpBuffer(q);
   12209           24 :     destroyPQExpBuffer(delq);
   12210              : }
   12211              : 
   12212              : /*
   12213              :  * dumpType
   12214              :  *    writes out to fout the queries to recreate a user-defined type
   12215              :  */
   12216              : static void
   12217          923 : dumpType(Archive *fout, const TypeInfo *tyinfo)
   12218              : {
   12219          923 :     DumpOptions *dopt = fout->dopt;
   12220              : 
   12221              :     /* Do nothing if not dumping schema */
   12222          923 :     if (!dopt->dumpSchema)
   12223           49 :         return;
   12224              : 
   12225              :     /* Dump out in proper style */
   12226          874 :     if (tyinfo->typtype == TYPTYPE_BASE)
   12227          283 :         dumpBaseType(fout, tyinfo);
   12228          591 :     else if (tyinfo->typtype == TYPTYPE_DOMAIN)
   12229          152 :         dumpDomain(fout, tyinfo);
   12230          439 :     else if (tyinfo->typtype == TYPTYPE_COMPOSITE)
   12231          130 :         dumpCompositeType(fout, tyinfo);
   12232          309 :     else if (tyinfo->typtype == TYPTYPE_ENUM)
   12233           85 :         dumpEnumType(fout, tyinfo);
   12234          224 :     else if (tyinfo->typtype == TYPTYPE_RANGE)
   12235          112 :         dumpRangeType(fout, tyinfo);
   12236          112 :     else if (tyinfo->typtype == TYPTYPE_PSEUDO && !tyinfo->isDefined)
   12237           37 :         dumpUndefinedType(fout, tyinfo);
   12238              :     else
   12239           75 :         pg_log_warning("typtype of data type \"%s\" appears to be invalid",
   12240              :                        tyinfo->dobj.name);
   12241              : }
   12242              : 
   12243              : /*
   12244              :  * dumpEnumType
   12245              :  *    writes out to fout the queries to recreate a user-defined enum type
   12246              :  */
   12247              : static void
   12248           85 : dumpEnumType(Archive *fout, const TypeInfo *tyinfo)
   12249              : {
   12250           85 :     DumpOptions *dopt = fout->dopt;
   12251           85 :     PQExpBuffer q = createPQExpBuffer();
   12252           85 :     PQExpBuffer delq = createPQExpBuffer();
   12253           85 :     PQExpBuffer query = createPQExpBuffer();
   12254              :     PGresult   *res;
   12255              :     int         num,
   12256              :                 i;
   12257              :     Oid         enum_oid;
   12258              :     char       *qtypname;
   12259              :     char       *qualtypname;
   12260              :     char       *label;
   12261              :     int         i_enumlabel;
   12262              :     int         i_oid;
   12263              : 
   12264           85 :     if (!fout->is_prepared[PREPQUERY_DUMPENUMTYPE])
   12265              :     {
   12266              :         /* Set up query for enum-specific details */
   12267           40 :         appendPQExpBufferStr(query,
   12268              :                              "PREPARE dumpEnumType(pg_catalog.oid) AS\n"
   12269              :                              "SELECT oid, enumlabel "
   12270              :                              "FROM pg_catalog.pg_enum "
   12271              :                              "WHERE enumtypid = $1 "
   12272              :                              "ORDER BY enumsortorder");
   12273              : 
   12274           40 :         ExecuteSqlStatement(fout, query->data);
   12275              : 
   12276           40 :         fout->is_prepared[PREPQUERY_DUMPENUMTYPE] = true;
   12277              :     }
   12278              : 
   12279           85 :     printfPQExpBuffer(query,
   12280              :                       "EXECUTE dumpEnumType('%u')",
   12281           85 :                       tyinfo->dobj.catId.oid);
   12282              : 
   12283           85 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   12284              : 
   12285           85 :     num = PQntuples(res);
   12286              : 
   12287           85 :     qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
   12288           85 :     qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
   12289              : 
   12290              :     /*
   12291              :      * CASCADE shouldn't be required here as for normal types since the I/O
   12292              :      * functions are generic and do not get dropped.
   12293              :      */
   12294           85 :     appendPQExpBuffer(delq, "DROP TYPE %s;\n", qualtypname);
   12295              : 
   12296           85 :     if (dopt->binary_upgrade)
   12297            6 :         binary_upgrade_set_type_oids_by_type_oid(fout, q,
   12298            6 :                                                  tyinfo->dobj.catId.oid,
   12299              :                                                  false, false);
   12300              : 
   12301           85 :     appendPQExpBuffer(q, "CREATE TYPE %s AS ENUM (",
   12302              :                       qualtypname);
   12303              : 
   12304           85 :     if (!dopt->binary_upgrade)
   12305              :     {
   12306           79 :         i_enumlabel = PQfnumber(res, "enumlabel");
   12307              : 
   12308              :         /* Labels with server-assigned oids */
   12309          482 :         for (i = 0; i < num; i++)
   12310              :         {
   12311          403 :             label = PQgetvalue(res, i, i_enumlabel);
   12312          403 :             if (i > 0)
   12313          324 :                 appendPQExpBufferChar(q, ',');
   12314          403 :             appendPQExpBufferStr(q, "\n    ");
   12315          403 :             appendStringLiteralAH(q, label, fout);
   12316              :         }
   12317              :     }
   12318              : 
   12319           85 :     appendPQExpBufferStr(q, "\n);\n");
   12320              : 
   12321           85 :     if (dopt->binary_upgrade)
   12322              :     {
   12323            6 :         i_oid = PQfnumber(res, "oid");
   12324            6 :         i_enumlabel = PQfnumber(res, "enumlabel");
   12325              : 
   12326              :         /* Labels with dump-assigned (preserved) oids */
   12327           62 :         for (i = 0; i < num; i++)
   12328              :         {
   12329           56 :             enum_oid = atooid(PQgetvalue(res, i, i_oid));
   12330           56 :             label = PQgetvalue(res, i, i_enumlabel);
   12331              : 
   12332           56 :             if (i == 0)
   12333            6 :                 appendPQExpBufferStr(q, "\n-- For binary upgrade, must preserve pg_enum oids\n");
   12334           56 :             appendPQExpBuffer(q,
   12335              :                               "SELECT pg_catalog.binary_upgrade_set_next_pg_enum_oid('%u'::pg_catalog.oid);\n",
   12336              :                               enum_oid);
   12337           56 :             appendPQExpBuffer(q, "ALTER TYPE %s ADD VALUE ", qualtypname);
   12338           56 :             appendStringLiteralAH(q, label, fout);
   12339           56 :             appendPQExpBufferStr(q, ";\n\n");
   12340              :         }
   12341              :     }
   12342              : 
   12343           85 :     if (dopt->binary_upgrade)
   12344            6 :         binary_upgrade_extension_member(q, &tyinfo->dobj,
   12345              :                                         "TYPE", qtypname,
   12346            6 :                                         tyinfo->dobj.namespace->dobj.name);
   12347              : 
   12348           85 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   12349           85 :         ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
   12350           85 :                      ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
   12351              :                                   .namespace = tyinfo->dobj.namespace->dobj.name,
   12352              :                                   .owner = tyinfo->rolname,
   12353              :                                   .description = "TYPE",
   12354              :                                   .section = SECTION_PRE_DATA,
   12355              :                                   .createStmt = q->data,
   12356              :                                   .dropStmt = delq->data));
   12357              : 
   12358              :     /* Dump Type Comments and Security Labels */
   12359           85 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   12360           32 :         dumpComment(fout, "TYPE", qtypname,
   12361           32 :                     tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
   12362           32 :                     tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
   12363              : 
   12364           85 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
   12365            0 :         dumpSecLabel(fout, "TYPE", qtypname,
   12366            0 :                      tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
   12367            0 :                      tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
   12368              : 
   12369           85 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
   12370           32 :         dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
   12371              :                 qtypname, NULL,
   12372           32 :                 tyinfo->dobj.namespace->dobj.name,
   12373           32 :                 NULL, tyinfo->rolname, &tyinfo->dacl);
   12374              : 
   12375           85 :     PQclear(res);
   12376           85 :     destroyPQExpBuffer(q);
   12377           85 :     destroyPQExpBuffer(delq);
   12378           85 :     destroyPQExpBuffer(query);
   12379           85 :     free(qtypname);
   12380           85 :     free(qualtypname);
   12381           85 : }
   12382              : 
   12383              : /*
   12384              :  * dumpRangeType
   12385              :  *    writes out to fout the queries to recreate a user-defined range type
   12386              :  */
   12387              : static void
   12388          112 : dumpRangeType(Archive *fout, const TypeInfo *tyinfo)
   12389              : {
   12390          112 :     DumpOptions *dopt = fout->dopt;
   12391          112 :     PQExpBuffer q = createPQExpBuffer();
   12392          112 :     PQExpBuffer delq = createPQExpBuffer();
   12393          112 :     PQExpBuffer query = createPQExpBuffer();
   12394              :     PGresult   *res;
   12395              :     Oid         collationOid;
   12396              :     char       *qtypname;
   12397              :     char       *qualtypname;
   12398              :     char       *procname;
   12399              : 
   12400          112 :     if (!fout->is_prepared[PREPQUERY_DUMPRANGETYPE])
   12401              :     {
   12402              :         /* Set up query for range-specific details */
   12403           40 :         appendPQExpBufferStr(query,
   12404              :                              "PREPARE dumpRangeType(pg_catalog.oid) AS\n");
   12405              : 
   12406           40 :         appendPQExpBufferStr(query,
   12407              :                              "SELECT ");
   12408              : 
   12409           40 :         if (fout->remoteVersion >= 140000)
   12410           40 :             appendPQExpBufferStr(query,
   12411              :                                  "pg_catalog.format_type(rngmultitypid, NULL) AS rngmultitype, ");
   12412              :         else
   12413            0 :             appendPQExpBufferStr(query,
   12414              :                                  "NULL AS rngmultitype, ");
   12415              : 
   12416           40 :         appendPQExpBufferStr(query,
   12417              :                              "pg_catalog.format_type(rngsubtype, NULL) AS rngsubtype, "
   12418              :                              "opc.opcname AS opcname, "
   12419              :                              "(SELECT nspname FROM pg_catalog.pg_namespace nsp "
   12420              :                              "  WHERE nsp.oid = opc.opcnamespace) AS opcnsp, "
   12421              :                              "opc.opcdefault, "
   12422              :                              "CASE WHEN rngcollation = st.typcollation THEN 0 "
   12423              :                              "     ELSE rngcollation END AS collation, "
   12424              :                              "rngcanonical, rngsubdiff "
   12425              :                              "FROM pg_catalog.pg_range r, pg_catalog.pg_type st, "
   12426              :                              "     pg_catalog.pg_opclass opc "
   12427              :                              "WHERE st.oid = rngsubtype AND opc.oid = rngsubopc AND "
   12428              :                              "rngtypid = $1");
   12429              : 
   12430           40 :         ExecuteSqlStatement(fout, query->data);
   12431              : 
   12432           40 :         fout->is_prepared[PREPQUERY_DUMPRANGETYPE] = true;
   12433              :     }
   12434              : 
   12435          112 :     printfPQExpBuffer(query,
   12436              :                       "EXECUTE dumpRangeType('%u')",
   12437          112 :                       tyinfo->dobj.catId.oid);
   12438              : 
   12439          112 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   12440              : 
   12441          112 :     qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
   12442          112 :     qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
   12443              : 
   12444              :     /*
   12445              :      * CASCADE shouldn't be required here as for normal types since the I/O
   12446              :      * functions are generic and do not get dropped.
   12447              :      */
   12448          112 :     appendPQExpBuffer(delq, "DROP TYPE %s;\n", qualtypname);
   12449              : 
   12450          112 :     if (dopt->binary_upgrade)
   12451            8 :         binary_upgrade_set_type_oids_by_type_oid(fout, q,
   12452            8 :                                                  tyinfo->dobj.catId.oid,
   12453              :                                                  false, true);
   12454              : 
   12455          112 :     appendPQExpBuffer(q, "CREATE TYPE %s AS RANGE (",
   12456              :                       qualtypname);
   12457              : 
   12458          112 :     appendPQExpBuffer(q, "\n    subtype = %s",
   12459              :                       PQgetvalue(res, 0, PQfnumber(res, "rngsubtype")));
   12460              : 
   12461          112 :     if (!PQgetisnull(res, 0, PQfnumber(res, "rngmultitype")))
   12462          112 :         appendPQExpBuffer(q, ",\n    multirange_type_name = %s",
   12463              :                           PQgetvalue(res, 0, PQfnumber(res, "rngmultitype")));
   12464              : 
   12465              :     /* print subtype_opclass only if not default for subtype */
   12466          112 :     if (PQgetvalue(res, 0, PQfnumber(res, "opcdefault"))[0] != 't')
   12467              :     {
   12468           32 :         char       *opcname = PQgetvalue(res, 0, PQfnumber(res, "opcname"));
   12469           32 :         char       *nspname = PQgetvalue(res, 0, PQfnumber(res, "opcnsp"));
   12470              : 
   12471           32 :         appendPQExpBuffer(q, ",\n    subtype_opclass = %s.",
   12472              :                           fmtId(nspname));
   12473           32 :         appendPQExpBufferStr(q, fmtId(opcname));
   12474              :     }
   12475              : 
   12476          112 :     collationOid = atooid(PQgetvalue(res, 0, PQfnumber(res, "collation")));
   12477          112 :     if (OidIsValid(collationOid))
   12478              :     {
   12479           37 :         CollInfo   *coll = findCollationByOid(collationOid);
   12480              : 
   12481           37 :         if (coll)
   12482           37 :             appendPQExpBuffer(q, ",\n    collation = %s",
   12483           37 :                               fmtQualifiedDumpable(coll));
   12484              :     }
   12485              : 
   12486          112 :     procname = PQgetvalue(res, 0, PQfnumber(res, "rngcanonical"));
   12487          112 :     if (strcmp(procname, "-") != 0)
   12488            9 :         appendPQExpBuffer(q, ",\n    canonical = %s", procname);
   12489              : 
   12490          112 :     procname = PQgetvalue(res, 0, PQfnumber(res, "rngsubdiff"));
   12491          112 :     if (strcmp(procname, "-") != 0)
   12492           23 :         appendPQExpBuffer(q, ",\n    subtype_diff = %s", procname);
   12493              : 
   12494          112 :     appendPQExpBufferStr(q, "\n);\n");
   12495              : 
   12496          112 :     if (dopt->binary_upgrade)
   12497            8 :         binary_upgrade_extension_member(q, &tyinfo->dobj,
   12498              :                                         "TYPE", qtypname,
   12499            8 :                                         tyinfo->dobj.namespace->dobj.name);
   12500              : 
   12501          112 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   12502          112 :         ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
   12503          112 :                      ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
   12504              :                                   .namespace = tyinfo->dobj.namespace->dobj.name,
   12505              :                                   .owner = tyinfo->rolname,
   12506              :                                   .description = "TYPE",
   12507              :                                   .section = SECTION_PRE_DATA,
   12508              :                                   .createStmt = q->data,
   12509              :                                   .dropStmt = delq->data));
   12510              : 
   12511              :     /* Dump Type Comments and Security Labels */
   12512          112 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   12513           50 :         dumpComment(fout, "TYPE", qtypname,
   12514           50 :                     tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
   12515           50 :                     tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
   12516              : 
   12517          112 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
   12518            0 :         dumpSecLabel(fout, "TYPE", qtypname,
   12519            0 :                      tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
   12520            0 :                      tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
   12521              : 
   12522          112 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
   12523           32 :         dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
   12524              :                 qtypname, NULL,
   12525           32 :                 tyinfo->dobj.namespace->dobj.name,
   12526           32 :                 NULL, tyinfo->rolname, &tyinfo->dacl);
   12527              : 
   12528          112 :     PQclear(res);
   12529          112 :     destroyPQExpBuffer(q);
   12530          112 :     destroyPQExpBuffer(delq);
   12531          112 :     destroyPQExpBuffer(query);
   12532          112 :     free(qtypname);
   12533          112 :     free(qualtypname);
   12534          112 : }
   12535              : 
   12536              : /*
   12537              :  * dumpUndefinedType
   12538              :  *    writes out to fout the queries to recreate a !typisdefined type
   12539              :  *
   12540              :  * This is a shell type, but we use different terminology to distinguish
   12541              :  * this case from where we have to emit a shell type definition to break
   12542              :  * circular dependencies.  An undefined type shouldn't ever have anything
   12543              :  * depending on it.
   12544              :  */
   12545              : static void
   12546           37 : dumpUndefinedType(Archive *fout, const TypeInfo *tyinfo)
   12547              : {
   12548           37 :     DumpOptions *dopt = fout->dopt;
   12549           37 :     PQExpBuffer q = createPQExpBuffer();
   12550           37 :     PQExpBuffer delq = createPQExpBuffer();
   12551              :     char       *qtypname;
   12552              :     char       *qualtypname;
   12553              : 
   12554           37 :     qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
   12555           37 :     qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
   12556              : 
   12557           37 :     appendPQExpBuffer(delq, "DROP TYPE %s;\n", qualtypname);
   12558              : 
   12559           37 :     if (dopt->binary_upgrade)
   12560            2 :         binary_upgrade_set_type_oids_by_type_oid(fout, q,
   12561            2 :                                                  tyinfo->dobj.catId.oid,
   12562              :                                                  false, false);
   12563              : 
   12564           37 :     appendPQExpBuffer(q, "CREATE TYPE %s;\n",
   12565              :                       qualtypname);
   12566              : 
   12567           37 :     if (dopt->binary_upgrade)
   12568            2 :         binary_upgrade_extension_member(q, &tyinfo->dobj,
   12569              :                                         "TYPE", qtypname,
   12570            2 :                                         tyinfo->dobj.namespace->dobj.name);
   12571              : 
   12572           37 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   12573           37 :         ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
   12574           37 :                      ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
   12575              :                                   .namespace = tyinfo->dobj.namespace->dobj.name,
   12576              :                                   .owner = tyinfo->rolname,
   12577              :                                   .description = "TYPE",
   12578              :                                   .section = SECTION_PRE_DATA,
   12579              :                                   .createStmt = q->data,
   12580              :                                   .dropStmt = delq->data));
   12581              : 
   12582              :     /* Dump Type Comments and Security Labels */
   12583           37 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   12584           32 :         dumpComment(fout, "TYPE", qtypname,
   12585           32 :                     tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
   12586           32 :                     tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
   12587              : 
   12588           37 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
   12589            0 :         dumpSecLabel(fout, "TYPE", qtypname,
   12590            0 :                      tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
   12591            0 :                      tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
   12592              : 
   12593           37 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
   12594            0 :         dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
   12595              :                 qtypname, NULL,
   12596            0 :                 tyinfo->dobj.namespace->dobj.name,
   12597            0 :                 NULL, tyinfo->rolname, &tyinfo->dacl);
   12598              : 
   12599           37 :     destroyPQExpBuffer(q);
   12600           37 :     destroyPQExpBuffer(delq);
   12601           37 :     free(qtypname);
   12602           37 :     free(qualtypname);
   12603           37 : }
   12604              : 
   12605              : /*
   12606              :  * dumpBaseType
   12607              :  *    writes out to fout the queries to recreate a user-defined base type
   12608              :  */
   12609              : static void
   12610          283 : dumpBaseType(Archive *fout, const TypeInfo *tyinfo)
   12611              : {
   12612          283 :     DumpOptions *dopt = fout->dopt;
   12613          283 :     PQExpBuffer q = createPQExpBuffer();
   12614          283 :     PQExpBuffer delq = createPQExpBuffer();
   12615          283 :     PQExpBuffer query = createPQExpBuffer();
   12616              :     PGresult   *res;
   12617              :     char       *qtypname;
   12618              :     char       *qualtypname;
   12619              :     char       *typlen;
   12620              :     char       *typinput;
   12621              :     char       *typoutput;
   12622              :     char       *typreceive;
   12623              :     char       *typsend;
   12624              :     char       *typmodin;
   12625              :     char       *typmodout;
   12626              :     char       *typanalyze;
   12627              :     char       *typsubscript;
   12628              :     Oid         typreceiveoid;
   12629              :     Oid         typsendoid;
   12630              :     Oid         typmodinoid;
   12631              :     Oid         typmodoutoid;
   12632              :     Oid         typanalyzeoid;
   12633              :     Oid         typsubscriptoid;
   12634              :     char       *typcategory;
   12635              :     char       *typispreferred;
   12636              :     char       *typdelim;
   12637              :     char       *typbyval;
   12638              :     char       *typalign;
   12639              :     char       *typstorage;
   12640              :     char       *typcollatable;
   12641              :     char       *typdefault;
   12642          283 :     bool        typdefault_is_literal = false;
   12643              : 
   12644          283 :     if (!fout->is_prepared[PREPQUERY_DUMPBASETYPE])
   12645              :     {
   12646              :         /* Set up query for type-specific details */
   12647           40 :         appendPQExpBufferStr(query,
   12648              :                              "PREPARE dumpBaseType(pg_catalog.oid) AS\n"
   12649              :                              "SELECT typlen, "
   12650              :                              "typinput, typoutput, typreceive, typsend, "
   12651              :                              "typreceive::pg_catalog.oid AS typreceiveoid, "
   12652              :                              "typsend::pg_catalog.oid AS typsendoid, "
   12653              :                              "typanalyze, "
   12654              :                              "typanalyze::pg_catalog.oid AS typanalyzeoid, "
   12655              :                              "typdelim, typbyval, typalign, typstorage, "
   12656              :                              "typmodin, typmodout, "
   12657              :                              "typmodin::pg_catalog.oid AS typmodinoid, "
   12658              :                              "typmodout::pg_catalog.oid AS typmodoutoid, "
   12659              :                              "typcategory, typispreferred, "
   12660              :                              "(typcollation <> 0) AS typcollatable, "
   12661              :                              "pg_catalog.pg_get_expr(typdefaultbin, 0) AS typdefaultbin, typdefault, ");
   12662              : 
   12663           40 :         if (fout->remoteVersion >= 140000)
   12664           40 :             appendPQExpBufferStr(query,
   12665              :                                  "typsubscript, "
   12666              :                                  "typsubscript::pg_catalog.oid AS typsubscriptoid ");
   12667              :         else
   12668            0 :             appendPQExpBufferStr(query,
   12669              :                                  "'-' AS typsubscript, 0 AS typsubscriptoid ");
   12670              : 
   12671           40 :         appendPQExpBufferStr(query, "FROM pg_catalog.pg_type "
   12672              :                              "WHERE oid = $1");
   12673              : 
   12674           40 :         ExecuteSqlStatement(fout, query->data);
   12675              : 
   12676           40 :         fout->is_prepared[PREPQUERY_DUMPBASETYPE] = true;
   12677              :     }
   12678              : 
   12679          283 :     printfPQExpBuffer(query,
   12680              :                       "EXECUTE dumpBaseType('%u')",
   12681          283 :                       tyinfo->dobj.catId.oid);
   12682              : 
   12683          283 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   12684              : 
   12685          283 :     typlen = PQgetvalue(res, 0, PQfnumber(res, "typlen"));
   12686          283 :     typinput = PQgetvalue(res, 0, PQfnumber(res, "typinput"));
   12687          283 :     typoutput = PQgetvalue(res, 0, PQfnumber(res, "typoutput"));
   12688          283 :     typreceive = PQgetvalue(res, 0, PQfnumber(res, "typreceive"));
   12689          283 :     typsend = PQgetvalue(res, 0, PQfnumber(res, "typsend"));
   12690          283 :     typmodin = PQgetvalue(res, 0, PQfnumber(res, "typmodin"));
   12691          283 :     typmodout = PQgetvalue(res, 0, PQfnumber(res, "typmodout"));
   12692          283 :     typanalyze = PQgetvalue(res, 0, PQfnumber(res, "typanalyze"));
   12693          283 :     typsubscript = PQgetvalue(res, 0, PQfnumber(res, "typsubscript"));
   12694          283 :     typreceiveoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typreceiveoid")));
   12695          283 :     typsendoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typsendoid")));
   12696          283 :     typmodinoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typmodinoid")));
   12697          283 :     typmodoutoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typmodoutoid")));
   12698          283 :     typanalyzeoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typanalyzeoid")));
   12699          283 :     typsubscriptoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typsubscriptoid")));
   12700          283 :     typcategory = PQgetvalue(res, 0, PQfnumber(res, "typcategory"));
   12701          283 :     typispreferred = PQgetvalue(res, 0, PQfnumber(res, "typispreferred"));
   12702          283 :     typdelim = PQgetvalue(res, 0, PQfnumber(res, "typdelim"));
   12703          283 :     typbyval = PQgetvalue(res, 0, PQfnumber(res, "typbyval"));
   12704          283 :     typalign = PQgetvalue(res, 0, PQfnumber(res, "typalign"));
   12705          283 :     typstorage = PQgetvalue(res, 0, PQfnumber(res, "typstorage"));
   12706          283 :     typcollatable = PQgetvalue(res, 0, PQfnumber(res, "typcollatable"));
   12707          283 :     if (!PQgetisnull(res, 0, PQfnumber(res, "typdefaultbin")))
   12708            0 :         typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefaultbin"));
   12709          283 :     else if (!PQgetisnull(res, 0, PQfnumber(res, "typdefault")))
   12710              :     {
   12711           42 :         typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefault"));
   12712           42 :         typdefault_is_literal = true;   /* it needs quotes */
   12713              :     }
   12714              :     else
   12715          241 :         typdefault = NULL;
   12716              : 
   12717          283 :     qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
   12718          283 :     qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
   12719              : 
   12720              :     /*
   12721              :      * The reason we include CASCADE is that the circular dependency between
   12722              :      * the type and its I/O functions makes it impossible to drop the type any
   12723              :      * other way.
   12724              :      */
   12725          283 :     appendPQExpBuffer(delq, "DROP TYPE %s CASCADE;\n", qualtypname);
   12726              : 
   12727              :     /*
   12728              :      * We might already have a shell type, but setting pg_type_oid is
   12729              :      * harmless, and in any case we'd better set the array type OID.
   12730              :      */
   12731          283 :     if (dopt->binary_upgrade)
   12732            8 :         binary_upgrade_set_type_oids_by_type_oid(fout, q,
   12733            8 :                                                  tyinfo->dobj.catId.oid,
   12734              :                                                  false, false);
   12735              : 
   12736          283 :     appendPQExpBuffer(q,
   12737              :                       "CREATE TYPE %s (\n"
   12738              :                       "    INTERNALLENGTH = %s",
   12739              :                       qualtypname,
   12740          283 :                       (strcmp(typlen, "-1") == 0) ? "variable" : typlen);
   12741              : 
   12742              :     /* regproc result is sufficiently quoted already */
   12743          283 :     appendPQExpBuffer(q, ",\n    INPUT = %s", typinput);
   12744          283 :     appendPQExpBuffer(q, ",\n    OUTPUT = %s", typoutput);
   12745          283 :     if (OidIsValid(typreceiveoid))
   12746          210 :         appendPQExpBuffer(q, ",\n    RECEIVE = %s", typreceive);
   12747          283 :     if (OidIsValid(typsendoid))
   12748          210 :         appendPQExpBuffer(q, ",\n    SEND = %s", typsend);
   12749          283 :     if (OidIsValid(typmodinoid))
   12750           35 :         appendPQExpBuffer(q, ",\n    TYPMOD_IN = %s", typmodin);
   12751          283 :     if (OidIsValid(typmodoutoid))
   12752           35 :         appendPQExpBuffer(q, ",\n    TYPMOD_OUT = %s", typmodout);
   12753          283 :     if (OidIsValid(typanalyzeoid))
   12754            3 :         appendPQExpBuffer(q, ",\n    ANALYZE = %s", typanalyze);
   12755              : 
   12756          283 :     if (strcmp(typcollatable, "t") == 0)
   12757           30 :         appendPQExpBufferStr(q, ",\n    COLLATABLE = true");
   12758              : 
   12759          283 :     if (typdefault != NULL)
   12760              :     {
   12761           42 :         appendPQExpBufferStr(q, ",\n    DEFAULT = ");
   12762           42 :         if (typdefault_is_literal)
   12763           42 :             appendStringLiteralAH(q, typdefault, fout);
   12764              :         else
   12765            0 :             appendPQExpBufferStr(q, typdefault);
   12766              :     }
   12767              : 
   12768          283 :     if (OidIsValid(typsubscriptoid))
   12769           29 :         appendPQExpBuffer(q, ",\n    SUBSCRIPT = %s", typsubscript);
   12770              : 
   12771          283 :     if (OidIsValid(tyinfo->typelem))
   12772           26 :         appendPQExpBuffer(q, ",\n    ELEMENT = %s",
   12773           26 :                           getFormattedTypeName(fout, tyinfo->typelem,
   12774              :                                                zeroIsError));
   12775              : 
   12776          283 :     if (strcmp(typcategory, "U") != 0)
   12777              :     {
   12778          161 :         appendPQExpBufferStr(q, ",\n    CATEGORY = ");
   12779          161 :         appendStringLiteralAH(q, typcategory, fout);
   12780              :     }
   12781              : 
   12782          283 :     if (strcmp(typispreferred, "t") == 0)
   12783           29 :         appendPQExpBufferStr(q, ",\n    PREFERRED = true");
   12784              : 
   12785          283 :     if (typdelim && strcmp(typdelim, ",") != 0)
   12786              :     {
   12787            3 :         appendPQExpBufferStr(q, ",\n    DELIMITER = ");
   12788            3 :         appendStringLiteralAH(q, typdelim, fout);
   12789              :     }
   12790              : 
   12791          283 :     if (*typalign == TYPALIGN_CHAR)
   12792           12 :         appendPQExpBufferStr(q, ",\n    ALIGNMENT = char");
   12793          271 :     else if (*typalign == TYPALIGN_SHORT)
   12794            6 :         appendPQExpBufferStr(q, ",\n    ALIGNMENT = int2");
   12795          265 :     else if (*typalign == TYPALIGN_INT)
   12796          187 :         appendPQExpBufferStr(q, ",\n    ALIGNMENT = int4");
   12797           78 :     else if (*typalign == TYPALIGN_DOUBLE)
   12798           78 :         appendPQExpBufferStr(q, ",\n    ALIGNMENT = double");
   12799              : 
   12800          283 :     if (*typstorage == TYPSTORAGE_PLAIN)
   12801          208 :         appendPQExpBufferStr(q, ",\n    STORAGE = plain");
   12802           75 :     else if (*typstorage == TYPSTORAGE_EXTERNAL)
   12803            0 :         appendPQExpBufferStr(q, ",\n    STORAGE = external");
   12804           75 :     else if (*typstorage == TYPSTORAGE_EXTENDED)
   12805           66 :         appendPQExpBufferStr(q, ",\n    STORAGE = extended");
   12806            9 :     else if (*typstorage == TYPSTORAGE_MAIN)
   12807            9 :         appendPQExpBufferStr(q, ",\n    STORAGE = main");
   12808              : 
   12809          283 :     if (strcmp(typbyval, "t") == 0)
   12810          137 :         appendPQExpBufferStr(q, ",\n    PASSEDBYVALUE");
   12811              : 
   12812          283 :     appendPQExpBufferStr(q, "\n);\n");
   12813              : 
   12814          283 :     if (dopt->binary_upgrade)
   12815            8 :         binary_upgrade_extension_member(q, &tyinfo->dobj,
   12816              :                                         "TYPE", qtypname,
   12817            8 :                                         tyinfo->dobj.namespace->dobj.name);
   12818              : 
   12819          283 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   12820          283 :         ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
   12821          283 :                      ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
   12822              :                                   .namespace = tyinfo->dobj.namespace->dobj.name,
   12823              :                                   .owner = tyinfo->rolname,
   12824              :                                   .description = "TYPE",
   12825              :                                   .section = SECTION_PRE_DATA,
   12826              :                                   .createStmt = q->data,
   12827              :                                   .dropStmt = delq->data));
   12828              : 
   12829              :     /* Dump Type Comments and Security Labels */
   12830          283 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   12831          248 :         dumpComment(fout, "TYPE", qtypname,
   12832          248 :                     tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
   12833          248 :                     tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
   12834              : 
   12835          283 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
   12836            0 :         dumpSecLabel(fout, "TYPE", qtypname,
   12837            0 :                      tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
   12838            0 :                      tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
   12839              : 
   12840          283 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
   12841           32 :         dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
   12842              :                 qtypname, NULL,
   12843           32 :                 tyinfo->dobj.namespace->dobj.name,
   12844           32 :                 NULL, tyinfo->rolname, &tyinfo->dacl);
   12845              : 
   12846          283 :     PQclear(res);
   12847          283 :     destroyPQExpBuffer(q);
   12848          283 :     destroyPQExpBuffer(delq);
   12849          283 :     destroyPQExpBuffer(query);
   12850          283 :     free(qtypname);
   12851          283 :     free(qualtypname);
   12852          283 : }
   12853              : 
   12854              : /*
   12855              :  * dumpDomain
   12856              :  *    writes out to fout the queries to recreate a user-defined domain
   12857              :  */
   12858              : static void
   12859          152 : dumpDomain(Archive *fout, const TypeInfo *tyinfo)
   12860              : {
   12861          152 :     DumpOptions *dopt = fout->dopt;
   12862          152 :     PQExpBuffer q = createPQExpBuffer();
   12863          152 :     PQExpBuffer delq = createPQExpBuffer();
   12864          152 :     PQExpBuffer query = createPQExpBuffer();
   12865              :     PGresult   *res;
   12866              :     int         i;
   12867              :     char       *qtypname;
   12868              :     char       *qualtypname;
   12869              :     char       *typnotnull;
   12870              :     char       *typdefn;
   12871              :     char       *typdefault;
   12872              :     Oid         typcollation;
   12873          152 :     bool        typdefault_is_literal = false;
   12874              : 
   12875          152 :     if (!fout->is_prepared[PREPQUERY_DUMPDOMAIN])
   12876              :     {
   12877              :         /* Set up query for domain-specific details */
   12878           37 :         appendPQExpBufferStr(query,
   12879              :                              "PREPARE dumpDomain(pg_catalog.oid) AS\n");
   12880              : 
   12881           37 :         appendPQExpBufferStr(query, "SELECT t.typnotnull, "
   12882              :                              "pg_catalog.format_type(t.typbasetype, t.typtypmod) AS typdefn, "
   12883              :                              "pg_catalog.pg_get_expr(t.typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, "
   12884              :                              "t.typdefault, "
   12885              :                              "CASE WHEN t.typcollation <> u.typcollation "
   12886              :                              "THEN t.typcollation ELSE 0 END AS typcollation "
   12887              :                              "FROM pg_catalog.pg_type t "
   12888              :                              "LEFT JOIN pg_catalog.pg_type u ON (t.typbasetype = u.oid) "
   12889              :                              "WHERE t.oid = $1");
   12890              : 
   12891           37 :         ExecuteSqlStatement(fout, query->data);
   12892              : 
   12893           37 :         fout->is_prepared[PREPQUERY_DUMPDOMAIN] = true;
   12894              :     }
   12895              : 
   12896          152 :     printfPQExpBuffer(query,
   12897              :                       "EXECUTE dumpDomain('%u')",
   12898          152 :                       tyinfo->dobj.catId.oid);
   12899              : 
   12900          152 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   12901              : 
   12902          152 :     typnotnull = PQgetvalue(res, 0, PQfnumber(res, "typnotnull"));
   12903          152 :     typdefn = PQgetvalue(res, 0, PQfnumber(res, "typdefn"));
   12904          152 :     if (!PQgetisnull(res, 0, PQfnumber(res, "typdefaultbin")))
   12905           37 :         typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefaultbin"));
   12906          115 :     else if (!PQgetisnull(res, 0, PQfnumber(res, "typdefault")))
   12907              :     {
   12908            0 :         typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefault"));
   12909            0 :         typdefault_is_literal = true;   /* it needs quotes */
   12910              :     }
   12911              :     else
   12912          115 :         typdefault = NULL;
   12913          152 :     typcollation = atooid(PQgetvalue(res, 0, PQfnumber(res, "typcollation")));
   12914              : 
   12915          152 :     if (dopt->binary_upgrade)
   12916           25 :         binary_upgrade_set_type_oids_by_type_oid(fout, q,
   12917           25 :                                                  tyinfo->dobj.catId.oid,
   12918              :                                                  true,  /* force array type */
   12919              :                                                  false);    /* force multirange type */
   12920              : 
   12921          152 :     qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
   12922          152 :     qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
   12923              : 
   12924          152 :     appendPQExpBuffer(q,
   12925              :                       "CREATE DOMAIN %s AS %s",
   12926              :                       qualtypname,
   12927              :                       typdefn);
   12928              : 
   12929              :     /* Print collation only if different from base type's collation */
   12930          152 :     if (OidIsValid(typcollation))
   12931              :     {
   12932              :         CollInfo   *coll;
   12933              : 
   12934           32 :         coll = findCollationByOid(typcollation);
   12935           32 :         if (coll)
   12936           32 :             appendPQExpBuffer(q, " COLLATE %s", fmtQualifiedDumpable(coll));
   12937              :     }
   12938              : 
   12939              :     /*
   12940              :      * Print a not-null constraint if there's one.  In servers older than 17
   12941              :      * these don't have names, so just print it unadorned; in newer ones they
   12942              :      * do, but most of the time it's going to be the standard generated one,
   12943              :      * so omit the name in that case also.
   12944              :      */
   12945          152 :     if (typnotnull[0] == 't')
   12946              :     {
   12947           47 :         if (fout->remoteVersion < 170000 || tyinfo->notnull == NULL)
   12948            0 :             appendPQExpBufferStr(q, " NOT NULL");
   12949              :         else
   12950              :         {
   12951           47 :             ConstraintInfo *notnull = tyinfo->notnull;
   12952              : 
   12953           47 :             if (!notnull->separate)
   12954              :             {
   12955              :                 char       *default_name;
   12956              : 
   12957              :                 /* XXX should match ChooseConstraintName better */
   12958           47 :                 default_name = psprintf("%s_not_null", tyinfo->dobj.name);
   12959              : 
   12960           47 :                 if (strcmp(default_name, notnull->dobj.name) == 0)
   12961           15 :                     appendPQExpBufferStr(q, " NOT NULL");
   12962              :                 else
   12963           32 :                     appendPQExpBuffer(q, " CONSTRAINT %s %s",
   12964           32 :                                       fmtId(notnull->dobj.name), notnull->condef);
   12965           47 :                 free(default_name);
   12966              :             }
   12967              :         }
   12968              :     }
   12969              : 
   12970          152 :     if (typdefault != NULL)
   12971              :     {
   12972           37 :         appendPQExpBufferStr(q, " DEFAULT ");
   12973           37 :         if (typdefault_is_literal)
   12974            0 :             appendStringLiteralAH(q, typdefault, fout);
   12975              :         else
   12976           37 :             appendPQExpBufferStr(q, typdefault);
   12977              :     }
   12978              : 
   12979          152 :     PQclear(res);
   12980              : 
   12981              :     /*
   12982              :      * Add any CHECK constraints for the domain
   12983              :      */
   12984          259 :     for (i = 0; i < tyinfo->nDomChecks; i++)
   12985              :     {
   12986          107 :         ConstraintInfo *domcheck = &(tyinfo->domChecks[i]);
   12987              : 
   12988          107 :         if (!domcheck->separate && domcheck->contype == 'c')
   12989          102 :             appendPQExpBuffer(q, "\n\tCONSTRAINT %s %s",
   12990          102 :                               fmtId(domcheck->dobj.name), domcheck->condef);
   12991              :     }
   12992              : 
   12993          152 :     appendPQExpBufferStr(q, ";\n");
   12994              : 
   12995          152 :     appendPQExpBuffer(delq, "DROP DOMAIN %s;\n", qualtypname);
   12996              : 
   12997          152 :     if (dopt->binary_upgrade)
   12998           25 :         binary_upgrade_extension_member(q, &tyinfo->dobj,
   12999              :                                         "DOMAIN", qtypname,
   13000           25 :                                         tyinfo->dobj.namespace->dobj.name);
   13001              : 
   13002          152 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   13003          152 :         ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
   13004          152 :                      ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
   13005              :                                   .namespace = tyinfo->dobj.namespace->dobj.name,
   13006              :                                   .owner = tyinfo->rolname,
   13007              :                                   .description = "DOMAIN",
   13008              :                                   .section = SECTION_PRE_DATA,
   13009              :                                   .createStmt = q->data,
   13010              :                                   .dropStmt = delq->data));
   13011              : 
   13012              :     /* Dump Domain Comments and Security Labels */
   13013          152 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   13014            0 :         dumpComment(fout, "DOMAIN", qtypname,
   13015            0 :                     tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
   13016            0 :                     tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
   13017              : 
   13018          152 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
   13019            0 :         dumpSecLabel(fout, "DOMAIN", qtypname,
   13020            0 :                      tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
   13021            0 :                      tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
   13022              : 
   13023          152 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
   13024           32 :         dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
   13025              :                 qtypname, NULL,
   13026           32 :                 tyinfo->dobj.namespace->dobj.name,
   13027           32 :                 NULL, tyinfo->rolname, &tyinfo->dacl);
   13028              : 
   13029              :     /* Dump any per-constraint comments */
   13030          259 :     for (i = 0; i < tyinfo->nDomChecks; i++)
   13031              :     {
   13032          107 :         ConstraintInfo *domcheck = &(tyinfo->domChecks[i]);
   13033              :         PQExpBuffer conprefix;
   13034              : 
   13035              :         /* but only if the constraint itself was dumped here */
   13036          107 :         if (domcheck->separate)
   13037            5 :             continue;
   13038              : 
   13039          102 :         conprefix = createPQExpBuffer();
   13040          102 :         appendPQExpBuffer(conprefix, "CONSTRAINT %s ON DOMAIN",
   13041          102 :                           fmtId(domcheck->dobj.name));
   13042              : 
   13043          102 :         if (domcheck->dobj.dump & DUMP_COMPONENT_COMMENT)
   13044           32 :             dumpComment(fout, conprefix->data, qtypname,
   13045           32 :                         tyinfo->dobj.namespace->dobj.name,
   13046           32 :                         tyinfo->rolname,
   13047           32 :                         domcheck->dobj.catId, 0, tyinfo->dobj.dumpId);
   13048              : 
   13049          102 :         destroyPQExpBuffer(conprefix);
   13050              :     }
   13051              : 
   13052              :     /*
   13053              :      * And a comment on the not-null constraint, if there's one -- but only if
   13054              :      * the constraint itself was dumped here
   13055              :      */
   13056          152 :     if (tyinfo->notnull != NULL && !tyinfo->notnull->separate)
   13057              :     {
   13058           47 :         PQExpBuffer conprefix = createPQExpBuffer();
   13059              : 
   13060           47 :         appendPQExpBuffer(conprefix, "CONSTRAINT %s ON DOMAIN",
   13061           47 :                           fmtId(tyinfo->notnull->dobj.name));
   13062              : 
   13063           47 :         if (tyinfo->notnull->dobj.dump & DUMP_COMPONENT_COMMENT)
   13064           32 :             dumpComment(fout, conprefix->data, qtypname,
   13065           32 :                         tyinfo->dobj.namespace->dobj.name,
   13066           32 :                         tyinfo->rolname,
   13067           32 :                         tyinfo->notnull->dobj.catId, 0, tyinfo->dobj.dumpId);
   13068           47 :         destroyPQExpBuffer(conprefix);
   13069              :     }
   13070              : 
   13071          152 :     destroyPQExpBuffer(q);
   13072          152 :     destroyPQExpBuffer(delq);
   13073          152 :     destroyPQExpBuffer(query);
   13074          152 :     free(qtypname);
   13075          152 :     free(qualtypname);
   13076          152 : }
   13077              : 
   13078              : /*
   13079              :  * dumpCompositeType
   13080              :  *    writes out to fout the queries to recreate a user-defined stand-alone
   13081              :  *    composite type
   13082              :  */
   13083              : static void
   13084          130 : dumpCompositeType(Archive *fout, const TypeInfo *tyinfo)
   13085              : {
   13086          130 :     DumpOptions *dopt = fout->dopt;
   13087          130 :     PQExpBuffer q = createPQExpBuffer();
   13088          130 :     PQExpBuffer dropped = createPQExpBuffer();
   13089          130 :     PQExpBuffer delq = createPQExpBuffer();
   13090          130 :     PQExpBuffer query = createPQExpBuffer();
   13091              :     PGresult   *res;
   13092              :     char       *qtypname;
   13093              :     char       *qualtypname;
   13094              :     int         ntups;
   13095              :     int         i_attname;
   13096              :     int         i_atttypdefn;
   13097              :     int         i_attlen;
   13098              :     int         i_attalign;
   13099              :     int         i_attisdropped;
   13100              :     int         i_attcollation;
   13101              :     int         i;
   13102              :     int         actual_atts;
   13103              : 
   13104          130 :     if (!fout->is_prepared[PREPQUERY_DUMPCOMPOSITETYPE])
   13105              :     {
   13106              :         /*
   13107              :          * Set up query for type-specific details.
   13108              :          *
   13109              :          * Since we only want to dump COLLATE clauses for attributes whose
   13110              :          * collation is different from their type's default, we use a CASE
   13111              :          * here to suppress uninteresting attcollations cheaply.  atttypid
   13112              :          * will be 0 for dropped columns; collation does not matter for those.
   13113              :          */
   13114           55 :         appendPQExpBufferStr(query,
   13115              :                              "PREPARE dumpCompositeType(pg_catalog.oid) AS\n"
   13116              :                              "SELECT a.attname, a.attnum, "
   13117              :                              "pg_catalog.format_type(a.atttypid, a.atttypmod) AS atttypdefn, "
   13118              :                              "a.attlen, a.attalign, a.attisdropped, "
   13119              :                              "CASE WHEN a.attcollation <> at.typcollation "
   13120              :                              "THEN a.attcollation ELSE 0 END AS attcollation "
   13121              :                              "FROM pg_catalog.pg_type ct "
   13122              :                              "JOIN pg_catalog.pg_attribute a ON a.attrelid = ct.typrelid "
   13123              :                              "LEFT JOIN pg_catalog.pg_type at ON at.oid = a.atttypid "
   13124              :                              "WHERE ct.oid = $1 "
   13125              :                              "ORDER BY a.attnum");
   13126              : 
   13127           55 :         ExecuteSqlStatement(fout, query->data);
   13128              : 
   13129           55 :         fout->is_prepared[PREPQUERY_DUMPCOMPOSITETYPE] = true;
   13130              :     }
   13131              : 
   13132          130 :     printfPQExpBuffer(query,
   13133              :                       "EXECUTE dumpCompositeType('%u')",
   13134          130 :                       tyinfo->dobj.catId.oid);
   13135              : 
   13136          130 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   13137              : 
   13138          130 :     ntups = PQntuples(res);
   13139              : 
   13140          130 :     i_attname = PQfnumber(res, "attname");
   13141          130 :     i_atttypdefn = PQfnumber(res, "atttypdefn");
   13142          130 :     i_attlen = PQfnumber(res, "attlen");
   13143          130 :     i_attalign = PQfnumber(res, "attalign");
   13144          130 :     i_attisdropped = PQfnumber(res, "attisdropped");
   13145          130 :     i_attcollation = PQfnumber(res, "attcollation");
   13146              : 
   13147          130 :     if (dopt->binary_upgrade)
   13148              :     {
   13149           18 :         binary_upgrade_set_type_oids_by_type_oid(fout, q,
   13150           18 :                                                  tyinfo->dobj.catId.oid,
   13151              :                                                  false, false);
   13152           18 :         binary_upgrade_set_pg_class_oids(fout, q, tyinfo->typrelid);
   13153              :     }
   13154              : 
   13155          130 :     qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
   13156          130 :     qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
   13157              : 
   13158          130 :     appendPQExpBuffer(q, "CREATE TYPE %s AS (",
   13159              :                       qualtypname);
   13160              : 
   13161          130 :     actual_atts = 0;
   13162          412 :     for (i = 0; i < ntups; i++)
   13163              :     {
   13164              :         char       *attname;
   13165              :         char       *atttypdefn;
   13166              :         char       *attlen;
   13167              :         char       *attalign;
   13168              :         bool        attisdropped;
   13169              :         Oid         attcollation;
   13170              : 
   13171          282 :         attname = PQgetvalue(res, i, i_attname);
   13172          282 :         atttypdefn = PQgetvalue(res, i, i_atttypdefn);
   13173          282 :         attlen = PQgetvalue(res, i, i_attlen);
   13174          282 :         attalign = PQgetvalue(res, i, i_attalign);
   13175          282 :         attisdropped = (PQgetvalue(res, i, i_attisdropped)[0] == 't');
   13176          282 :         attcollation = atooid(PQgetvalue(res, i, i_attcollation));
   13177              : 
   13178          282 :         if (attisdropped && !dopt->binary_upgrade)
   13179            8 :             continue;
   13180              : 
   13181              :         /* Format properly if not first attr */
   13182          274 :         if (actual_atts++ > 0)
   13183          144 :             appendPQExpBufferChar(q, ',');
   13184          274 :         appendPQExpBufferStr(q, "\n\t");
   13185              : 
   13186          274 :         if (!attisdropped)
   13187              :         {
   13188          272 :             appendPQExpBuffer(q, "%s %s", fmtId(attname), atttypdefn);
   13189              : 
   13190              :             /* Add collation if not default for the column type */
   13191          272 :             if (OidIsValid(attcollation))
   13192              :             {
   13193              :                 CollInfo   *coll;
   13194              : 
   13195            0 :                 coll = findCollationByOid(attcollation);
   13196            0 :                 if (coll)
   13197            0 :                     appendPQExpBuffer(q, " COLLATE %s",
   13198            0 :                                       fmtQualifiedDumpable(coll));
   13199              :             }
   13200              :         }
   13201              :         else
   13202              :         {
   13203              :             /*
   13204              :              * This is a dropped attribute and we're in binary_upgrade mode.
   13205              :              * Insert a placeholder for it in the CREATE TYPE command, and set
   13206              :              * length and alignment with direct UPDATE to the catalogs
   13207              :              * afterwards. See similar code in dumpTableSchema().
   13208              :              */
   13209            2 :             appendPQExpBuffer(q, "%s INTEGER /* dummy */", fmtId(attname));
   13210              : 
   13211              :             /* stash separately for insertion after the CREATE TYPE */
   13212            2 :             appendPQExpBufferStr(dropped,
   13213              :                                  "\n-- For binary upgrade, recreate dropped column.\n");
   13214            2 :             appendPQExpBuffer(dropped, "UPDATE pg_catalog.pg_attribute\n"
   13215              :                               "SET attlen = %s, "
   13216              :                               "attalign = '%s', attbyval = false\n"
   13217              :                               "WHERE attname = ", attlen, attalign);
   13218            2 :             appendStringLiteralAH(dropped, attname, fout);
   13219            2 :             appendPQExpBufferStr(dropped, "\n  AND attrelid = ");
   13220            2 :             appendStringLiteralAH(dropped, qualtypname, fout);
   13221            2 :             appendPQExpBufferStr(dropped, "::pg_catalog.regclass;\n");
   13222              : 
   13223            2 :             appendPQExpBuffer(dropped, "ALTER TYPE %s ",
   13224              :                               qualtypname);
   13225            2 :             appendPQExpBuffer(dropped, "DROP ATTRIBUTE %s;\n",
   13226              :                               fmtId(attname));
   13227              :         }
   13228              :     }
   13229          130 :     appendPQExpBufferStr(q, "\n);\n");
   13230          130 :     appendPQExpBufferStr(q, dropped->data);
   13231              : 
   13232          130 :     appendPQExpBuffer(delq, "DROP TYPE %s;\n", qualtypname);
   13233              : 
   13234          130 :     if (dopt->binary_upgrade)
   13235           18 :         binary_upgrade_extension_member(q, &tyinfo->dobj,
   13236              :                                         "TYPE", qtypname,
   13237           18 :                                         tyinfo->dobj.namespace->dobj.name);
   13238              : 
   13239          130 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   13240          113 :         ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
   13241          113 :                      ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
   13242              :                                   .namespace = tyinfo->dobj.namespace->dobj.name,
   13243              :                                   .owner = tyinfo->rolname,
   13244              :                                   .description = "TYPE",
   13245              :                                   .section = SECTION_PRE_DATA,
   13246              :                                   .createStmt = q->data,
   13247              :                                   .dropStmt = delq->data));
   13248              : 
   13249              : 
   13250              :     /* Dump Type Comments and Security Labels */
   13251          130 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   13252           32 :         dumpComment(fout, "TYPE", qtypname,
   13253           32 :                     tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
   13254           32 :                     tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
   13255              : 
   13256          130 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
   13257            0 :         dumpSecLabel(fout, "TYPE", qtypname,
   13258            0 :                      tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
   13259            0 :                      tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
   13260              : 
   13261          130 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
   13262           18 :         dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
   13263              :                 qtypname, NULL,
   13264           18 :                 tyinfo->dobj.namespace->dobj.name,
   13265           18 :                 NULL, tyinfo->rolname, &tyinfo->dacl);
   13266              : 
   13267              :     /* Dump any per-column comments */
   13268          130 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   13269           32 :         dumpCompositeTypeColComments(fout, tyinfo, res);
   13270              : 
   13271          130 :     PQclear(res);
   13272          130 :     destroyPQExpBuffer(q);
   13273          130 :     destroyPQExpBuffer(dropped);
   13274          130 :     destroyPQExpBuffer(delq);
   13275          130 :     destroyPQExpBuffer(query);
   13276          130 :     free(qtypname);
   13277          130 :     free(qualtypname);
   13278          130 : }
   13279              : 
   13280              : /*
   13281              :  * dumpCompositeTypeColComments
   13282              :  *    writes out to fout the queries to recreate comments on the columns of
   13283              :  *    a user-defined stand-alone composite type.
   13284              :  *
   13285              :  * The caller has already made a query to collect the names and attnums
   13286              :  * of the type's columns, so we just pass that result into here rather
   13287              :  * than reading them again.
   13288              :  */
   13289              : static void
   13290           32 : dumpCompositeTypeColComments(Archive *fout, const TypeInfo *tyinfo,
   13291              :                              PGresult *res)
   13292              : {
   13293              :     CommentItem *comments;
   13294              :     int         ncomments;
   13295              :     PQExpBuffer query;
   13296              :     PQExpBuffer target;
   13297              :     int         i;
   13298              :     int         ntups;
   13299              :     int         i_attname;
   13300              :     int         i_attnum;
   13301              :     int         i_attisdropped;
   13302              : 
   13303              :     /* do nothing, if --no-comments is supplied */
   13304           32 :     if (fout->dopt->no_comments)
   13305            0 :         return;
   13306              : 
   13307              :     /* Search for comments associated with type's pg_class OID */
   13308           32 :     ncomments = findComments(RelationRelationId, tyinfo->typrelid,
   13309              :                              &comments);
   13310              : 
   13311              :     /* If no comments exist, we're done */
   13312           32 :     if (ncomments <= 0)
   13313            0 :         return;
   13314              : 
   13315              :     /* Build COMMENT ON statements */
   13316           32 :     query = createPQExpBuffer();
   13317           32 :     target = createPQExpBuffer();
   13318              : 
   13319           32 :     ntups = PQntuples(res);
   13320           32 :     i_attnum = PQfnumber(res, "attnum");
   13321           32 :     i_attname = PQfnumber(res, "attname");
   13322           32 :     i_attisdropped = PQfnumber(res, "attisdropped");
   13323           64 :     while (ncomments > 0)
   13324              :     {
   13325              :         const char *attname;
   13326              : 
   13327           32 :         attname = NULL;
   13328           32 :         for (i = 0; i < ntups; i++)
   13329              :         {
   13330           32 :             if (atoi(PQgetvalue(res, i, i_attnum)) == comments->objsubid &&
   13331           32 :                 PQgetvalue(res, i, i_attisdropped)[0] != 't')
   13332              :             {
   13333           32 :                 attname = PQgetvalue(res, i, i_attname);
   13334           32 :                 break;
   13335              :             }
   13336              :         }
   13337           32 :         if (attname)            /* just in case we don't find it */
   13338              :         {
   13339           32 :             const char *descr = comments->descr;
   13340              : 
   13341           32 :             resetPQExpBuffer(target);
   13342           32 :             appendPQExpBuffer(target, "COLUMN %s.",
   13343           32 :                               fmtId(tyinfo->dobj.name));
   13344           32 :             appendPQExpBufferStr(target, fmtId(attname));
   13345              : 
   13346           32 :             resetPQExpBuffer(query);
   13347           32 :             appendPQExpBuffer(query, "COMMENT ON COLUMN %s.",
   13348           32 :                               fmtQualifiedDumpable(tyinfo));
   13349           32 :             appendPQExpBuffer(query, "%s IS ", fmtId(attname));
   13350           32 :             appendStringLiteralAH(query, descr, fout);
   13351           32 :             appendPQExpBufferStr(query, ";\n");
   13352              : 
   13353           32 :             ArchiveEntry(fout, nilCatalogId, createDumpId(),
   13354           32 :                          ARCHIVE_OPTS(.tag = target->data,
   13355              :                                       .namespace = tyinfo->dobj.namespace->dobj.name,
   13356              :                                       .owner = tyinfo->rolname,
   13357              :                                       .description = "COMMENT",
   13358              :                                       .section = SECTION_NONE,
   13359              :                                       .createStmt = query->data,
   13360              :                                       .deps = &(tyinfo->dobj.dumpId),
   13361              :                                       .nDeps = 1));
   13362              :         }
   13363              : 
   13364           32 :         comments++;
   13365           32 :         ncomments--;
   13366              :     }
   13367              : 
   13368           32 :     destroyPQExpBuffer(query);
   13369           32 :     destroyPQExpBuffer(target);
   13370              : }
   13371              : 
   13372              : /*
   13373              :  * dumpShellType
   13374              :  *    writes out to fout the queries to create a shell type
   13375              :  *
   13376              :  * We dump a shell definition in advance of the I/O functions for the type.
   13377              :  */
   13378              : static void
   13379           73 : dumpShellType(Archive *fout, const ShellTypeInfo *stinfo)
   13380              : {
   13381           73 :     DumpOptions *dopt = fout->dopt;
   13382              :     PQExpBuffer q;
   13383              : 
   13384              :     /* Do nothing if not dumping schema */
   13385           73 :     if (!dopt->dumpSchema)
   13386            6 :         return;
   13387              : 
   13388           67 :     q = createPQExpBuffer();
   13389              : 
   13390              :     /*
   13391              :      * Note the lack of a DROP command for the shell type; any required DROP
   13392              :      * is driven off the base type entry, instead.  This interacts with
   13393              :      * _printTocEntry()'s use of the presence of a DROP command to decide
   13394              :      * whether an entry needs an ALTER OWNER command.  We don't want to alter
   13395              :      * the shell type's owner immediately on creation; that should happen only
   13396              :      * after it's filled in, otherwise the backend complains.
   13397              :      */
   13398              : 
   13399           67 :     if (dopt->binary_upgrade)
   13400            8 :         binary_upgrade_set_type_oids_by_type_oid(fout, q,
   13401            8 :                                                  stinfo->baseType->dobj.catId.oid,
   13402              :                                                  false, false);
   13403              : 
   13404           67 :     appendPQExpBuffer(q, "CREATE TYPE %s;\n",
   13405           67 :                       fmtQualifiedDumpable(stinfo));
   13406              : 
   13407           67 :     if (stinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   13408           67 :         ArchiveEntry(fout, stinfo->dobj.catId, stinfo->dobj.dumpId,
   13409           67 :                      ARCHIVE_OPTS(.tag = stinfo->dobj.name,
   13410              :                                   .namespace = stinfo->dobj.namespace->dobj.name,
   13411              :                                   .owner = stinfo->baseType->rolname,
   13412              :                                   .description = "SHELL TYPE",
   13413              :                                   .section = SECTION_PRE_DATA,
   13414              :                                   .createStmt = q->data));
   13415              : 
   13416           67 :     destroyPQExpBuffer(q);
   13417              : }
   13418              : 
   13419              : /*
   13420              :  * dumpProcLang
   13421              :  *        writes out to fout the queries to recreate a user-defined
   13422              :  *        procedural language
   13423              :  */
   13424              : static void
   13425           82 : dumpProcLang(Archive *fout, const ProcLangInfo *plang)
   13426              : {
   13427           82 :     DumpOptions *dopt = fout->dopt;
   13428              :     PQExpBuffer defqry;
   13429              :     PQExpBuffer delqry;
   13430              :     bool        useParams;
   13431              :     char       *qlanname;
   13432              :     FuncInfo   *funcInfo;
   13433           82 :     FuncInfo   *inlineInfo = NULL;
   13434           82 :     FuncInfo   *validatorInfo = NULL;
   13435              : 
   13436              :     /* Do nothing if not dumping schema */
   13437           82 :     if (!dopt->dumpSchema)
   13438           13 :         return;
   13439              : 
   13440              :     /*
   13441              :      * Try to find the support function(s).  It is not an error if we don't
   13442              :      * find them --- if the functions are in the pg_catalog schema, as is
   13443              :      * standard in 8.1 and up, then we won't have loaded them. (In this case
   13444              :      * we will emit a parameterless CREATE LANGUAGE command, which will
   13445              :      * require PL template knowledge in the backend to reload.)
   13446              :      */
   13447              : 
   13448           69 :     funcInfo = findFuncByOid(plang->lanplcallfoid);
   13449           69 :     if (funcInfo != NULL && !funcInfo->dobj.dump)
   13450            2 :         funcInfo = NULL;        /* treat not-dumped same as not-found */
   13451              : 
   13452           69 :     if (OidIsValid(plang->laninline))
   13453              :     {
   13454           38 :         inlineInfo = findFuncByOid(plang->laninline);
   13455           38 :         if (inlineInfo != NULL && !inlineInfo->dobj.dump)
   13456            1 :             inlineInfo = NULL;
   13457              :     }
   13458              : 
   13459           69 :     if (OidIsValid(plang->lanvalidator))
   13460              :     {
   13461           38 :         validatorInfo = findFuncByOid(plang->lanvalidator);
   13462           38 :         if (validatorInfo != NULL && !validatorInfo->dobj.dump)
   13463            1 :             validatorInfo = NULL;
   13464              :     }
   13465              : 
   13466              :     /*
   13467              :      * If the functions are dumpable then emit a complete CREATE LANGUAGE with
   13468              :      * parameters.  Otherwise, we'll write a parameterless command, which will
   13469              :      * be interpreted as CREATE EXTENSION.
   13470              :      */
   13471           30 :     useParams = (funcInfo != NULL &&
   13472          129 :                  (inlineInfo != NULL || !OidIsValid(plang->laninline)) &&
   13473           30 :                  (validatorInfo != NULL || !OidIsValid(plang->lanvalidator)));
   13474              : 
   13475           69 :     defqry = createPQExpBuffer();
   13476           69 :     delqry = createPQExpBuffer();
   13477              : 
   13478           69 :     qlanname = pg_strdup(fmtId(plang->dobj.name));
   13479              : 
   13480           69 :     appendPQExpBuffer(delqry, "DROP PROCEDURAL LANGUAGE %s;\n",
   13481              :                       qlanname);
   13482              : 
   13483           69 :     if (useParams)
   13484              :     {
   13485           30 :         appendPQExpBuffer(defqry, "CREATE %sPROCEDURAL LANGUAGE %s",
   13486           30 :                           plang->lanpltrusted ? "TRUSTED " : "",
   13487              :                           qlanname);
   13488           30 :         appendPQExpBuffer(defqry, " HANDLER %s",
   13489           30 :                           fmtQualifiedDumpable(funcInfo));
   13490           30 :         if (OidIsValid(plang->laninline))
   13491            0 :             appendPQExpBuffer(defqry, " INLINE %s",
   13492            0 :                               fmtQualifiedDumpable(inlineInfo));
   13493           30 :         if (OidIsValid(plang->lanvalidator))
   13494            0 :             appendPQExpBuffer(defqry, " VALIDATOR %s",
   13495            0 :                               fmtQualifiedDumpable(validatorInfo));
   13496              :     }
   13497              :     else
   13498              :     {
   13499              :         /*
   13500              :          * If not dumping parameters, then use CREATE OR REPLACE so that the
   13501              :          * command will not fail if the language is preinstalled in the target
   13502              :          * database.
   13503              :          *
   13504              :          * Modern servers will interpret this as CREATE EXTENSION IF NOT
   13505              :          * EXISTS; perhaps we should emit that instead?  But it might just add
   13506              :          * confusion.
   13507              :          */
   13508           39 :         appendPQExpBuffer(defqry, "CREATE OR REPLACE PROCEDURAL LANGUAGE %s",
   13509              :                           qlanname);
   13510              :     }
   13511           69 :     appendPQExpBufferStr(defqry, ";\n");
   13512              : 
   13513           69 :     if (dopt->binary_upgrade)
   13514            2 :         binary_upgrade_extension_member(defqry, &plang->dobj,
   13515              :                                         "LANGUAGE", qlanname, NULL);
   13516              : 
   13517           69 :     if (plang->dobj.dump & DUMP_COMPONENT_DEFINITION)
   13518           31 :         ArchiveEntry(fout, plang->dobj.catId, plang->dobj.dumpId,
   13519           31 :                      ARCHIVE_OPTS(.tag = plang->dobj.name,
   13520              :                                   .owner = plang->lanowner,
   13521              :                                   .description = "PROCEDURAL LANGUAGE",
   13522              :                                   .section = SECTION_PRE_DATA,
   13523              :                                   .createStmt = defqry->data,
   13524              :                                   .dropStmt = delqry->data,
   13525              :                                   ));
   13526              : 
   13527              :     /* Dump Proc Lang Comments and Security Labels */
   13528           69 :     if (plang->dobj.dump & DUMP_COMPONENT_COMMENT)
   13529            0 :         dumpComment(fout, "LANGUAGE", qlanname,
   13530            0 :                     NULL, plang->lanowner,
   13531            0 :                     plang->dobj.catId, 0, plang->dobj.dumpId);
   13532              : 
   13533           69 :     if (plang->dobj.dump & DUMP_COMPONENT_SECLABEL)
   13534            0 :         dumpSecLabel(fout, "LANGUAGE", qlanname,
   13535            0 :                      NULL, plang->lanowner,
   13536            0 :                      plang->dobj.catId, 0, plang->dobj.dumpId);
   13537              : 
   13538           69 :     if (plang->lanpltrusted && plang->dobj.dump & DUMP_COMPONENT_ACL)
   13539           38 :         dumpACL(fout, plang->dobj.dumpId, InvalidDumpId, "LANGUAGE",
   13540              :                 qlanname, NULL, NULL,
   13541           38 :                 NULL, plang->lanowner, &plang->dacl);
   13542              : 
   13543           69 :     free(qlanname);
   13544              : 
   13545           69 :     destroyPQExpBuffer(defqry);
   13546           69 :     destroyPQExpBuffer(delqry);
   13547              : }
   13548              : 
   13549              : /*
   13550              :  * format_function_arguments: generate function name and argument list
   13551              :  *
   13552              :  * This is used when we can rely on pg_get_function_arguments to format
   13553              :  * the argument list.  Note, however, that pg_get_function_arguments
   13554              :  * does not special-case zero-argument aggregates.
   13555              :  */
   13556              : static char *
   13557         4162 : format_function_arguments(const FuncInfo *finfo, const char *funcargs, bool is_agg)
   13558              : {
   13559              :     PQExpBufferData fn;
   13560              : 
   13561         4162 :     initPQExpBuffer(&fn);
   13562         4162 :     appendPQExpBufferStr(&fn, fmtId(finfo->dobj.name));
   13563         4162 :     if (is_agg && finfo->nargs == 0)
   13564           80 :         appendPQExpBufferStr(&fn, "(*)");
   13565              :     else
   13566         4082 :         appendPQExpBuffer(&fn, "(%s)", funcargs);
   13567         4162 :     return fn.data;
   13568              : }
   13569              : 
   13570              : /*
   13571              :  * format_function_signature: generate function name and argument list
   13572              :  *
   13573              :  * Only a minimal list of input argument types is generated; this is
   13574              :  * sufficient to reference the function, but not to define it.
   13575              :  *
   13576              :  * If honor_quotes is false then the function name is never quoted.
   13577              :  * This is appropriate for use in TOC tags, but not in SQL commands.
   13578              :  */
   13579              : static char *
   13580         2189 : format_function_signature(Archive *fout, const FuncInfo *finfo, bool honor_quotes)
   13581              : {
   13582              :     PQExpBufferData fn;
   13583              :     int         j;
   13584              : 
   13585         2189 :     initPQExpBuffer(&fn);
   13586         2189 :     if (honor_quotes)
   13587          393 :         appendPQExpBuffer(&fn, "%s(", fmtId(finfo->dobj.name));
   13588              :     else
   13589         1796 :         appendPQExpBuffer(&fn, "%s(", finfo->dobj.name);
   13590         4020 :     for (j = 0; j < finfo->nargs; j++)
   13591              :     {
   13592         1831 :         if (j > 0)
   13593          432 :             appendPQExpBufferStr(&fn, ", ");
   13594              : 
   13595         1831 :         appendPQExpBufferStr(&fn,
   13596         1831 :                              getFormattedTypeName(fout, finfo->argtypes[j],
   13597              :                                                   zeroIsError));
   13598              :     }
   13599         2189 :     appendPQExpBufferChar(&fn, ')');
   13600         2189 :     return fn.data;
   13601              : }
   13602              : 
   13603              : 
   13604              : /*
   13605              :  * dumpFunc:
   13606              :  *    dump out one function
   13607              :  */
   13608              : static void
   13609         1858 : dumpFunc(Archive *fout, const FuncInfo *finfo)
   13610              : {
   13611         1858 :     DumpOptions *dopt = fout->dopt;
   13612              :     PQExpBuffer query;
   13613              :     PQExpBuffer q;
   13614              :     PQExpBuffer delqry;
   13615              :     PQExpBuffer asPart;
   13616              :     PGresult   *res;
   13617              :     char       *funcsig;        /* identity signature */
   13618         1858 :     char       *funcfullsig = NULL; /* full signature */
   13619              :     char       *funcsig_tag;
   13620              :     char       *qual_funcsig;
   13621              :     char       *proretset;
   13622              :     char       *prosrc;
   13623              :     char       *probin;
   13624              :     char       *prosqlbody;
   13625              :     char       *funcargs;
   13626              :     char       *funciargs;
   13627              :     char       *funcresult;
   13628              :     char       *protrftypes;
   13629              :     char       *prokind;
   13630              :     char       *provolatile;
   13631              :     char       *proisstrict;
   13632              :     char       *prosecdef;
   13633              :     char       *proleakproof;
   13634              :     char       *proconfig;
   13635              :     char       *procost;
   13636              :     char       *prorows;
   13637              :     char       *prosupport;
   13638              :     char       *proparallel;
   13639              :     char       *lanname;
   13640         1858 :     char      **configitems = NULL;
   13641         1858 :     int         nconfigitems = 0;
   13642              :     const char *keyword;
   13643              : 
   13644              :     /* Do nothing if not dumping schema */
   13645         1858 :     if (!dopt->dumpSchema)
   13646           62 :         return;
   13647              : 
   13648         1796 :     query = createPQExpBuffer();
   13649         1796 :     q = createPQExpBuffer();
   13650         1796 :     delqry = createPQExpBuffer();
   13651         1796 :     asPart = createPQExpBuffer();
   13652              : 
   13653         1796 :     if (!fout->is_prepared[PREPQUERY_DUMPFUNC])
   13654              :     {
   13655              :         /* Set up query for function-specific details */
   13656           76 :         appendPQExpBufferStr(query,
   13657              :                              "PREPARE dumpFunc(pg_catalog.oid) AS\n");
   13658              : 
   13659           76 :         appendPQExpBufferStr(query,
   13660              :                              "SELECT\n"
   13661              :                              "proretset,\n"
   13662              :                              "prosrc,\n"
   13663              :                              "probin,\n"
   13664              :                              "provolatile,\n"
   13665              :                              "proisstrict,\n"
   13666              :                              "prosecdef,\n"
   13667              :                              "lanname,\n"
   13668              :                              "proconfig,\n"
   13669              :                              "procost,\n"
   13670              :                              "prorows,\n"
   13671              :                              "pg_catalog.pg_get_function_arguments(p.oid) AS funcargs,\n"
   13672              :                              "pg_catalog.pg_get_function_identity_arguments(p.oid) AS funciargs,\n"
   13673              :                              "pg_catalog.pg_get_function_result(p.oid) AS funcresult,\n"
   13674              :                              "proleakproof,\n");
   13675              : 
   13676           76 :         if (fout->remoteVersion >= 90500)
   13677           76 :             appendPQExpBufferStr(query,
   13678              :                                  "array_to_string(protrftypes, ' ') AS protrftypes,\n");
   13679              :         else
   13680            0 :             appendPQExpBufferStr(query,
   13681              :                                  "NULL AS protrftypes,\n");
   13682              : 
   13683           76 :         if (fout->remoteVersion >= 90600)
   13684           76 :             appendPQExpBufferStr(query,
   13685              :                                  "proparallel,\n");
   13686              :         else
   13687            0 :             appendPQExpBufferStr(query,
   13688              :                                  "'u' AS proparallel,\n");
   13689              : 
   13690           76 :         if (fout->remoteVersion >= 110000)
   13691           76 :             appendPQExpBufferStr(query,
   13692              :                                  "prokind,\n");
   13693              :         else
   13694            0 :             appendPQExpBufferStr(query,
   13695              :                                  "CASE WHEN proiswindow THEN 'w' ELSE 'f' END AS prokind,\n");
   13696              : 
   13697           76 :         if (fout->remoteVersion >= 120000)
   13698           76 :             appendPQExpBufferStr(query,
   13699              :                                  "prosupport,\n");
   13700              :         else
   13701            0 :             appendPQExpBufferStr(query,
   13702              :                                  "'-' AS prosupport,\n");
   13703              : 
   13704           76 :         if (fout->remoteVersion >= 140000)
   13705           76 :             appendPQExpBufferStr(query,
   13706              :                                  "pg_get_function_sqlbody(p.oid) AS prosqlbody\n");
   13707              :         else
   13708            0 :             appendPQExpBufferStr(query,
   13709              :                                  "NULL AS prosqlbody\n");
   13710              : 
   13711           76 :         appendPQExpBufferStr(query,
   13712              :                              "FROM pg_catalog.pg_proc p, pg_catalog.pg_language l\n"
   13713              :                              "WHERE p.oid = $1 "
   13714              :                              "AND l.oid = p.prolang");
   13715              : 
   13716           76 :         ExecuteSqlStatement(fout, query->data);
   13717              : 
   13718           76 :         fout->is_prepared[PREPQUERY_DUMPFUNC] = true;
   13719              :     }
   13720              : 
   13721         1796 :     printfPQExpBuffer(query,
   13722              :                       "EXECUTE dumpFunc('%u')",
   13723         1796 :                       finfo->dobj.catId.oid);
   13724              : 
   13725         1796 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   13726              : 
   13727         1796 :     proretset = PQgetvalue(res, 0, PQfnumber(res, "proretset"));
   13728         1796 :     if (PQgetisnull(res, 0, PQfnumber(res, "prosqlbody")))
   13729              :     {
   13730         1748 :         prosrc = PQgetvalue(res, 0, PQfnumber(res, "prosrc"));
   13731         1748 :         probin = PQgetvalue(res, 0, PQfnumber(res, "probin"));
   13732         1748 :         prosqlbody = NULL;
   13733              :     }
   13734              :     else
   13735              :     {
   13736           48 :         prosrc = NULL;
   13737           48 :         probin = NULL;
   13738           48 :         prosqlbody = PQgetvalue(res, 0, PQfnumber(res, "prosqlbody"));
   13739              :     }
   13740         1796 :     funcargs = PQgetvalue(res, 0, PQfnumber(res, "funcargs"));
   13741         1796 :     funciargs = PQgetvalue(res, 0, PQfnumber(res, "funciargs"));
   13742         1796 :     funcresult = PQgetvalue(res, 0, PQfnumber(res, "funcresult"));
   13743         1796 :     protrftypes = PQgetvalue(res, 0, PQfnumber(res, "protrftypes"));
   13744         1796 :     prokind = PQgetvalue(res, 0, PQfnumber(res, "prokind"));
   13745         1796 :     provolatile = PQgetvalue(res, 0, PQfnumber(res, "provolatile"));
   13746         1796 :     proisstrict = PQgetvalue(res, 0, PQfnumber(res, "proisstrict"));
   13747         1796 :     prosecdef = PQgetvalue(res, 0, PQfnumber(res, "prosecdef"));
   13748         1796 :     proleakproof = PQgetvalue(res, 0, PQfnumber(res, "proleakproof"));
   13749         1796 :     proconfig = PQgetvalue(res, 0, PQfnumber(res, "proconfig"));
   13750         1796 :     procost = PQgetvalue(res, 0, PQfnumber(res, "procost"));
   13751         1796 :     prorows = PQgetvalue(res, 0, PQfnumber(res, "prorows"));
   13752         1796 :     prosupport = PQgetvalue(res, 0, PQfnumber(res, "prosupport"));
   13753         1796 :     proparallel = PQgetvalue(res, 0, PQfnumber(res, "proparallel"));
   13754         1796 :     lanname = PQgetvalue(res, 0, PQfnumber(res, "lanname"));
   13755              : 
   13756              :     /*
   13757              :      * See backend/commands/functioncmds.c for details of how the 'AS' clause
   13758              :      * is used.
   13759              :      */
   13760         1796 :     if (prosqlbody)
   13761              :     {
   13762           48 :         appendPQExpBufferStr(asPart, prosqlbody);
   13763              :     }
   13764         1748 :     else if (probin[0] != '\0')
   13765              :     {
   13766          153 :         appendPQExpBufferStr(asPart, "AS ");
   13767          153 :         appendStringLiteralAH(asPart, probin, fout);
   13768          153 :         if (prosrc[0] != '\0')
   13769              :         {
   13770          153 :             appendPQExpBufferStr(asPart, ", ");
   13771              : 
   13772              :             /*
   13773              :              * where we have bin, use dollar quoting if allowed and src
   13774              :              * contains quote or backslash; else use regular quoting.
   13775              :              */
   13776          153 :             if (dopt->disable_dollar_quoting ||
   13777          153 :                 (strchr(prosrc, '\'') == NULL && strchr(prosrc, '\\') == NULL))
   13778          153 :                 appendStringLiteralAH(asPart, prosrc, fout);
   13779              :             else
   13780            0 :                 appendStringLiteralDQ(asPart, prosrc, NULL);
   13781              :         }
   13782              :     }
   13783              :     else
   13784              :     {
   13785         1595 :         appendPQExpBufferStr(asPart, "AS ");
   13786              :         /* with no bin, dollar quote src unconditionally if allowed */
   13787         1595 :         if (dopt->disable_dollar_quoting)
   13788            0 :             appendStringLiteralAH(asPart, prosrc, fout);
   13789              :         else
   13790         1595 :             appendStringLiteralDQ(asPart, prosrc, NULL);
   13791              :     }
   13792              : 
   13793         1796 :     if (*proconfig)
   13794              :     {
   13795           15 :         if (!parsePGArray(proconfig, &configitems, &nconfigitems))
   13796            0 :             pg_fatal("could not parse %s array", "proconfig");
   13797              :     }
   13798              :     else
   13799              :     {
   13800         1781 :         configitems = NULL;
   13801         1781 :         nconfigitems = 0;
   13802              :     }
   13803              : 
   13804         1796 :     funcfullsig = format_function_arguments(finfo, funcargs, false);
   13805         1796 :     funcsig = format_function_arguments(finfo, funciargs, false);
   13806              : 
   13807         1796 :     funcsig_tag = format_function_signature(fout, finfo, false);
   13808              : 
   13809         1796 :     qual_funcsig = psprintf("%s.%s",
   13810         1796 :                             fmtId(finfo->dobj.namespace->dobj.name),
   13811              :                             funcsig);
   13812              : 
   13813         1796 :     if (prokind[0] == PROKIND_PROCEDURE)
   13814           92 :         keyword = "PROCEDURE";
   13815              :     else
   13816         1704 :         keyword = "FUNCTION"; /* works for window functions too */
   13817              : 
   13818         1796 :     appendPQExpBuffer(delqry, "DROP %s %s;\n",
   13819              :                       keyword, qual_funcsig);
   13820              : 
   13821         3592 :     appendPQExpBuffer(q, "CREATE %s %s.%s",
   13822              :                       keyword,
   13823         1796 :                       fmtId(finfo->dobj.namespace->dobj.name),
   13824              :                       funcfullsig ? funcfullsig :
   13825              :                       funcsig);
   13826              : 
   13827         1796 :     if (prokind[0] == PROKIND_PROCEDURE)
   13828              :          /* no result type to output */ ;
   13829         1704 :     else if (funcresult)
   13830         1704 :         appendPQExpBuffer(q, " RETURNS %s", funcresult);
   13831              :     else
   13832            0 :         appendPQExpBuffer(q, " RETURNS %s%s",
   13833            0 :                           (proretset[0] == 't') ? "SETOF " : "",
   13834            0 :                           getFormattedTypeName(fout, finfo->prorettype,
   13835              :                                                zeroIsError));
   13836              : 
   13837         1796 :     appendPQExpBuffer(q, "\n    LANGUAGE %s", fmtId(lanname));
   13838              : 
   13839         1796 :     if (*protrftypes)
   13840              :     {
   13841            0 :         Oid        *typeids = pg_malloc_array(Oid, FUNC_MAX_ARGS);
   13842              :         int         i;
   13843              : 
   13844            0 :         appendPQExpBufferStr(q, " TRANSFORM ");
   13845            0 :         parseOidArray(protrftypes, typeids, FUNC_MAX_ARGS);
   13846            0 :         for (i = 0; typeids[i]; i++)
   13847              :         {
   13848            0 :             if (i != 0)
   13849            0 :                 appendPQExpBufferStr(q, ", ");
   13850            0 :             appendPQExpBuffer(q, "FOR TYPE %s",
   13851            0 :                               getFormattedTypeName(fout, typeids[i], zeroAsNone));
   13852              :         }
   13853              : 
   13854            0 :         free(typeids);
   13855              :     }
   13856              : 
   13857         1796 :     if (prokind[0] == PROKIND_WINDOW)
   13858            5 :         appendPQExpBufferStr(q, " WINDOW");
   13859              : 
   13860         1796 :     if (provolatile[0] != PROVOLATILE_VOLATILE)
   13861              :     {
   13862          351 :         if (provolatile[0] == PROVOLATILE_IMMUTABLE)
   13863          330 :             appendPQExpBufferStr(q, " IMMUTABLE");
   13864           21 :         else if (provolatile[0] == PROVOLATILE_STABLE)
   13865           21 :             appendPQExpBufferStr(q, " STABLE");
   13866            0 :         else if (provolatile[0] != PROVOLATILE_VOLATILE)
   13867            0 :             pg_fatal("unrecognized provolatile value for function \"%s\"",
   13868              :                      finfo->dobj.name);
   13869              :     }
   13870              : 
   13871         1796 :     if (proisstrict[0] == 't')
   13872          358 :         appendPQExpBufferStr(q, " STRICT");
   13873              : 
   13874         1796 :     if (prosecdef[0] == 't')
   13875            0 :         appendPQExpBufferStr(q, " SECURITY DEFINER");
   13876              : 
   13877         1796 :     if (proleakproof[0] == 't')
   13878           10 :         appendPQExpBufferStr(q, " LEAKPROOF");
   13879              : 
   13880              :     /*
   13881              :      * COST and ROWS are emitted only if present and not default, so as not to
   13882              :      * break backwards-compatibility of the dump without need.  Keep this code
   13883              :      * in sync with the defaults in functioncmds.c.
   13884              :      */
   13885         1796 :     if (strcmp(procost, "0") != 0)
   13886              :     {
   13887         1796 :         if (strcmp(lanname, "internal") == 0 || strcmp(lanname, "c") == 0)
   13888              :         {
   13889              :             /* default cost is 1 */
   13890          382 :             if (strcmp(procost, "1") != 0)
   13891            0 :                 appendPQExpBuffer(q, " COST %s", procost);
   13892              :         }
   13893              :         else
   13894              :         {
   13895              :             /* default cost is 100 */
   13896         1414 :             if (strcmp(procost, "100") != 0)
   13897           11 :                 appendPQExpBuffer(q, " COST %s", procost);
   13898              :         }
   13899              :     }
   13900         1796 :     if (proretset[0] == 't' &&
   13901          192 :         strcmp(prorows, "0") != 0 && strcmp(prorows, "1000") != 0)
   13902            0 :         appendPQExpBuffer(q, " ROWS %s", prorows);
   13903              : 
   13904         1796 :     if (strcmp(prosupport, "-") != 0)
   13905              :     {
   13906              :         /* We rely on regprocout to provide quoting and qualification */
   13907           42 :         appendPQExpBuffer(q, " SUPPORT %s", prosupport);
   13908              :     }
   13909              : 
   13910         1796 :     if (proparallel[0] != PROPARALLEL_UNSAFE)
   13911              :     {
   13912          116 :         if (proparallel[0] == PROPARALLEL_SAFE)
   13913          111 :             appendPQExpBufferStr(q, " PARALLEL SAFE");
   13914            5 :         else if (proparallel[0] == PROPARALLEL_RESTRICTED)
   13915            5 :             appendPQExpBufferStr(q, " PARALLEL RESTRICTED");
   13916            0 :         else if (proparallel[0] != PROPARALLEL_UNSAFE)
   13917            0 :             pg_fatal("unrecognized proparallel value for function \"%s\"",
   13918              :                      finfo->dobj.name);
   13919              :     }
   13920              : 
   13921         1836 :     for (int i = 0; i < nconfigitems; i++)
   13922              :     {
   13923              :         /* we feel free to scribble on configitems[] here */
   13924           40 :         char       *configitem = configitems[i];
   13925              :         char       *pos;
   13926              : 
   13927           40 :         pos = strchr(configitem, '=');
   13928           40 :         if (pos == NULL)
   13929            0 :             continue;
   13930           40 :         *pos++ = '\0';
   13931           40 :         appendPQExpBuffer(q, "\n    SET %s TO ", fmtId(configitem));
   13932              : 
   13933              :         /*
   13934              :          * Variables that are marked GUC_LIST_QUOTE were already fully quoted
   13935              :          * by flatten_set_variable_args() before they were put into the
   13936              :          * proconfig array.  However, because the quoting rules used there
   13937              :          * aren't exactly like SQL's, we have to break the list value apart
   13938              :          * and then quote the elements as string literals.  (The elements may
   13939              :          * be double-quoted as-is, but we can't just feed them to the SQL
   13940              :          * parser; it would do the wrong thing with elements that are
   13941              :          * zero-length or longer than NAMEDATALEN.)  Also, we need a special
   13942              :          * case for empty lists.
   13943              :          *
   13944              :          * Variables that are not so marked should just be emitted as simple
   13945              :          * string literals.  If the variable is not known to
   13946              :          * variable_is_guc_list_quote(), we'll do that; this makes it unsafe
   13947              :          * to use GUC_LIST_QUOTE for extension variables.
   13948              :          */
   13949           40 :         if (variable_is_guc_list_quote(configitem))
   13950              :         {
   13951              :             char      **namelist;
   13952              :             char      **nameptr;
   13953              : 
   13954              :             /* Parse string into list of identifiers */
   13955              :             /* this shouldn't fail really */
   13956           15 :             if (SplitGUCList(pos, ',', &namelist))
   13957              :             {
   13958              :                 /* Special case: represent an empty list as NULL */
   13959           15 :                 if (*namelist == NULL)
   13960            5 :                     appendPQExpBufferStr(q, "NULL");
   13961           40 :                 for (nameptr = namelist; *nameptr; nameptr++)
   13962              :                 {
   13963           25 :                     if (nameptr != namelist)
   13964           15 :                         appendPQExpBufferStr(q, ", ");
   13965           25 :                     appendStringLiteralAH(q, *nameptr, fout);
   13966              :                 }
   13967              :             }
   13968           15 :             pg_free(namelist);
   13969              :         }
   13970              :         else
   13971           25 :             appendStringLiteralAH(q, pos, fout);
   13972              :     }
   13973              : 
   13974         1796 :     appendPQExpBuffer(q, "\n    %s;\n", asPart->data);
   13975              : 
   13976         1796 :     append_depends_on_extension(fout, q, &finfo->dobj,
   13977              :                                 "pg_catalog.pg_proc", keyword,
   13978              :                                 qual_funcsig);
   13979              : 
   13980         1796 :     if (dopt->binary_upgrade)
   13981          300 :         binary_upgrade_extension_member(q, &finfo->dobj,
   13982              :                                         keyword, funcsig,
   13983          300 :                                         finfo->dobj.namespace->dobj.name);
   13984              : 
   13985         1796 :     if (finfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   13986         1700 :         ArchiveEntry(fout, finfo->dobj.catId, finfo->dobj.dumpId,
   13987         1700 :                      ARCHIVE_OPTS(.tag = funcsig_tag,
   13988              :                                   .namespace = finfo->dobj.namespace->dobj.name,
   13989              :                                   .owner = finfo->rolname,
   13990              :                                   .description = keyword,
   13991              :                                   .section = finfo->postponed_def ?
   13992              :                                   SECTION_POST_DATA : SECTION_PRE_DATA,
   13993              :                                   .createStmt = q->data,
   13994              :                                   .dropStmt = delqry->data));
   13995              : 
   13996              :     /* Dump Function Comments and Security Labels */
   13997         1796 :     if (finfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   13998            9 :         dumpComment(fout, keyword, funcsig,
   13999            9 :                     finfo->dobj.namespace->dobj.name, finfo->rolname,
   14000            9 :                     finfo->dobj.catId, 0, finfo->dobj.dumpId);
   14001              : 
   14002         1796 :     if (finfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
   14003            0 :         dumpSecLabel(fout, keyword, funcsig,
   14004            0 :                      finfo->dobj.namespace->dobj.name, finfo->rolname,
   14005            0 :                      finfo->dobj.catId, 0, finfo->dobj.dumpId);
   14006              : 
   14007         1796 :     if (finfo->dobj.dump & DUMP_COMPONENT_ACL)
   14008          109 :         dumpACL(fout, finfo->dobj.dumpId, InvalidDumpId, keyword,
   14009              :                 funcsig, NULL,
   14010          109 :                 finfo->dobj.namespace->dobj.name,
   14011          109 :                 NULL, finfo->rolname, &finfo->dacl);
   14012              : 
   14013         1796 :     PQclear(res);
   14014              : 
   14015         1796 :     destroyPQExpBuffer(query);
   14016         1796 :     destroyPQExpBuffer(q);
   14017         1796 :     destroyPQExpBuffer(delqry);
   14018         1796 :     destroyPQExpBuffer(asPart);
   14019         1796 :     free(funcsig);
   14020         1796 :     free(funcfullsig);
   14021         1796 :     free(funcsig_tag);
   14022         1796 :     free(qual_funcsig);
   14023         1796 :     free(configitems);
   14024              : }
   14025              : 
   14026              : 
   14027              : /*
   14028              :  * Dump a user-defined cast
   14029              :  */
   14030              : static void
   14031           67 : dumpCast(Archive *fout, const CastInfo *cast)
   14032              : {
   14033           67 :     DumpOptions *dopt = fout->dopt;
   14034              :     PQExpBuffer defqry;
   14035              :     PQExpBuffer delqry;
   14036              :     PQExpBuffer labelq;
   14037              :     PQExpBuffer castargs;
   14038           67 :     FuncInfo   *funcInfo = NULL;
   14039              :     const char *sourceType;
   14040              :     const char *targetType;
   14041              : 
   14042              :     /* Do nothing if not dumping schema */
   14043           67 :     if (!dopt->dumpSchema)
   14044            6 :         return;
   14045              : 
   14046              :     /* Cannot dump if we don't have the cast function's info */
   14047           61 :     if (OidIsValid(cast->castfunc))
   14048              :     {
   14049           36 :         funcInfo = findFuncByOid(cast->castfunc);
   14050           36 :         if (funcInfo == NULL)
   14051            0 :             pg_fatal("could not find function definition for function with OID %u",
   14052              :                      cast->castfunc);
   14053              :     }
   14054              : 
   14055           61 :     defqry = createPQExpBuffer();
   14056           61 :     delqry = createPQExpBuffer();
   14057           61 :     labelq = createPQExpBuffer();
   14058           61 :     castargs = createPQExpBuffer();
   14059              : 
   14060           61 :     sourceType = getFormattedTypeName(fout, cast->castsource, zeroAsNone);
   14061           61 :     targetType = getFormattedTypeName(fout, cast->casttarget, zeroAsNone);
   14062           61 :     appendPQExpBuffer(delqry, "DROP CAST (%s AS %s);\n",
   14063              :                       sourceType, targetType);
   14064              : 
   14065           61 :     appendPQExpBuffer(defqry, "CREATE CAST (%s AS %s) ",
   14066              :                       sourceType, targetType);
   14067              : 
   14068           61 :     switch (cast->castmethod)
   14069              :     {
   14070           25 :         case COERCION_METHOD_BINARY:
   14071           25 :             appendPQExpBufferStr(defqry, "WITHOUT FUNCTION");
   14072           25 :             break;
   14073            0 :         case COERCION_METHOD_INOUT:
   14074            0 :             appendPQExpBufferStr(defqry, "WITH INOUT");
   14075            0 :             break;
   14076           36 :         case COERCION_METHOD_FUNCTION:
   14077           36 :             if (funcInfo)
   14078              :             {
   14079           36 :                 char       *fsig = format_function_signature(fout, funcInfo, true);
   14080              : 
   14081              :                 /*
   14082              :                  * Always qualify the function name (format_function_signature
   14083              :                  * won't qualify it).
   14084              :                  */
   14085           36 :                 appendPQExpBuffer(defqry, "WITH FUNCTION %s.%s",
   14086           36 :                                   fmtId(funcInfo->dobj.namespace->dobj.name), fsig);
   14087           36 :                 free(fsig);
   14088              :             }
   14089              :             else
   14090            0 :                 pg_log_warning("bogus value in pg_cast.castfunc or pg_cast.castmethod field");
   14091           36 :             break;
   14092            0 :         default:
   14093            0 :             pg_log_warning("bogus value in pg_cast.castmethod field");
   14094              :     }
   14095              : 
   14096           61 :     if (cast->castcontext == 'a')
   14097           31 :         appendPQExpBufferStr(defqry, " AS ASSIGNMENT");
   14098           30 :     else if (cast->castcontext == 'i')
   14099           10 :         appendPQExpBufferStr(defqry, " AS IMPLICIT");
   14100           61 :     appendPQExpBufferStr(defqry, ";\n");
   14101              : 
   14102           61 :     appendPQExpBuffer(labelq, "CAST (%s AS %s)",
   14103              :                       sourceType, targetType);
   14104              : 
   14105           61 :     appendPQExpBuffer(castargs, "(%s AS %s)",
   14106              :                       sourceType, targetType);
   14107              : 
   14108           61 :     if (dopt->binary_upgrade)
   14109            7 :         binary_upgrade_extension_member(defqry, &cast->dobj,
   14110            7 :                                         "CAST", castargs->data, NULL);
   14111              : 
   14112           61 :     if (cast->dobj.dump & DUMP_COMPONENT_DEFINITION)
   14113           61 :         ArchiveEntry(fout, cast->dobj.catId, cast->dobj.dumpId,
   14114           61 :                      ARCHIVE_OPTS(.tag = labelq->data,
   14115              :                                   .description = "CAST",
   14116              :                                   .section = SECTION_PRE_DATA,
   14117              :                                   .createStmt = defqry->data,
   14118              :                                   .dropStmt = delqry->data));
   14119              : 
   14120              :     /* Dump Cast Comments */
   14121           61 :     if (cast->dobj.dump & DUMP_COMPONENT_COMMENT)
   14122            0 :         dumpComment(fout, "CAST", castargs->data,
   14123              :                     NULL, "",
   14124            0 :                     cast->dobj.catId, 0, cast->dobj.dumpId);
   14125              : 
   14126           61 :     destroyPQExpBuffer(defqry);
   14127           61 :     destroyPQExpBuffer(delqry);
   14128           61 :     destroyPQExpBuffer(labelq);
   14129           61 :     destroyPQExpBuffer(castargs);
   14130              : }
   14131              : 
   14132              : /*
   14133              :  * Dump a transform
   14134              :  */
   14135              : static void
   14136           42 : dumpTransform(Archive *fout, const TransformInfo *transform)
   14137              : {
   14138           42 :     DumpOptions *dopt = fout->dopt;
   14139              :     PQExpBuffer defqry;
   14140              :     PQExpBuffer delqry;
   14141              :     PQExpBuffer labelq;
   14142              :     PQExpBuffer transformargs;
   14143           42 :     FuncInfo   *fromsqlFuncInfo = NULL;
   14144           42 :     FuncInfo   *tosqlFuncInfo = NULL;
   14145              :     char       *lanname;
   14146              :     const char *transformType;
   14147              : 
   14148              :     /* Do nothing if not dumping schema */
   14149           42 :     if (!dopt->dumpSchema)
   14150            6 :         return;
   14151              : 
   14152              :     /* Cannot dump if we don't have the transform functions' info */
   14153           36 :     if (OidIsValid(transform->trffromsql))
   14154              :     {
   14155           36 :         fromsqlFuncInfo = findFuncByOid(transform->trffromsql);
   14156           36 :         if (fromsqlFuncInfo == NULL)
   14157            0 :             pg_fatal("could not find function definition for function with OID %u",
   14158              :                      transform->trffromsql);
   14159              :     }
   14160           36 :     if (OidIsValid(transform->trftosql))
   14161              :     {
   14162           36 :         tosqlFuncInfo = findFuncByOid(transform->trftosql);
   14163           36 :         if (tosqlFuncInfo == NULL)
   14164            0 :             pg_fatal("could not find function definition for function with OID %u",
   14165              :                      transform->trftosql);
   14166              :     }
   14167              : 
   14168           36 :     defqry = createPQExpBuffer();
   14169           36 :     delqry = createPQExpBuffer();
   14170           36 :     labelq = createPQExpBuffer();
   14171           36 :     transformargs = createPQExpBuffer();
   14172              : 
   14173           36 :     lanname = get_language_name(fout, transform->trflang);
   14174           36 :     transformType = getFormattedTypeName(fout, transform->trftype, zeroAsNone);
   14175              : 
   14176           36 :     appendPQExpBuffer(delqry, "DROP TRANSFORM FOR %s LANGUAGE %s;\n",
   14177              :                       transformType, lanname);
   14178              : 
   14179           36 :     appendPQExpBuffer(defqry, "CREATE TRANSFORM FOR %s LANGUAGE %s (",
   14180              :                       transformType, lanname);
   14181              : 
   14182           36 :     if (!transform->trffromsql && !transform->trftosql)
   14183            0 :         pg_log_warning("bogus transform definition, at least one of trffromsql and trftosql should be nonzero");
   14184              : 
   14185           36 :     if (transform->trffromsql)
   14186              :     {
   14187           36 :         if (fromsqlFuncInfo)
   14188              :         {
   14189           36 :             char       *fsig = format_function_signature(fout, fromsqlFuncInfo, true);
   14190              : 
   14191              :             /*
   14192              :              * Always qualify the function name (format_function_signature
   14193              :              * won't qualify it).
   14194              :              */
   14195           36 :             appendPQExpBuffer(defqry, "FROM SQL WITH FUNCTION %s.%s",
   14196           36 :                               fmtId(fromsqlFuncInfo->dobj.namespace->dobj.name), fsig);
   14197           36 :             free(fsig);
   14198              :         }
   14199              :         else
   14200            0 :             pg_log_warning("bogus value in pg_transform.trffromsql field");
   14201              :     }
   14202              : 
   14203           36 :     if (transform->trftosql)
   14204              :     {
   14205           36 :         if (transform->trffromsql)
   14206           36 :             appendPQExpBufferStr(defqry, ", ");
   14207              : 
   14208           36 :         if (tosqlFuncInfo)
   14209              :         {
   14210           36 :             char       *fsig = format_function_signature(fout, tosqlFuncInfo, true);
   14211              : 
   14212              :             /*
   14213              :              * Always qualify the function name (format_function_signature
   14214              :              * won't qualify it).
   14215              :              */
   14216           36 :             appendPQExpBuffer(defqry, "TO SQL WITH FUNCTION %s.%s",
   14217           36 :                               fmtId(tosqlFuncInfo->dobj.namespace->dobj.name), fsig);
   14218           36 :             free(fsig);
   14219              :         }
   14220              :         else
   14221            0 :             pg_log_warning("bogus value in pg_transform.trftosql field");
   14222              :     }
   14223              : 
   14224           36 :     appendPQExpBufferStr(defqry, ");\n");
   14225              : 
   14226           36 :     appendPQExpBuffer(labelq, "TRANSFORM FOR %s LANGUAGE %s",
   14227              :                       transformType, lanname);
   14228              : 
   14229           36 :     appendPQExpBuffer(transformargs, "FOR %s LANGUAGE %s",
   14230              :                       transformType, lanname);
   14231              : 
   14232           36 :     if (dopt->binary_upgrade)
   14233            2 :         binary_upgrade_extension_member(defqry, &transform->dobj,
   14234            2 :                                         "TRANSFORM", transformargs->data, NULL);
   14235              : 
   14236           36 :     if (transform->dobj.dump & DUMP_COMPONENT_DEFINITION)
   14237           36 :         ArchiveEntry(fout, transform->dobj.catId, transform->dobj.dumpId,
   14238           36 :                      ARCHIVE_OPTS(.tag = labelq->data,
   14239              :                                   .description = "TRANSFORM",
   14240              :                                   .section = SECTION_PRE_DATA,
   14241              :                                   .createStmt = defqry->data,
   14242              :                                   .dropStmt = delqry->data,
   14243              :                                   .deps = transform->dobj.dependencies,
   14244              :                                   .nDeps = transform->dobj.nDeps));
   14245              : 
   14246              :     /* Dump Transform Comments */
   14247           36 :     if (transform->dobj.dump & DUMP_COMPONENT_COMMENT)
   14248            0 :         dumpComment(fout, "TRANSFORM", transformargs->data,
   14249              :                     NULL, "",
   14250            0 :                     transform->dobj.catId, 0, transform->dobj.dumpId);
   14251              : 
   14252           36 :     free(lanname);
   14253           36 :     destroyPQExpBuffer(defqry);
   14254           36 :     destroyPQExpBuffer(delqry);
   14255           36 :     destroyPQExpBuffer(labelq);
   14256           36 :     destroyPQExpBuffer(transformargs);
   14257              : }
   14258              : 
   14259              : 
   14260              : /*
   14261              :  * dumpOpr
   14262              :  *    write out a single operator definition
   14263              :  */
   14264              : static void
   14265         2522 : dumpOpr(Archive *fout, const OprInfo *oprinfo)
   14266              : {
   14267         2522 :     DumpOptions *dopt = fout->dopt;
   14268              :     PQExpBuffer query;
   14269              :     PQExpBuffer q;
   14270              :     PQExpBuffer delq;
   14271              :     PQExpBuffer oprid;
   14272              :     PQExpBuffer details;
   14273              :     PGresult   *res;
   14274              :     int         i_oprkind;
   14275              :     int         i_oprcode;
   14276              :     int         i_oprleft;
   14277              :     int         i_oprright;
   14278              :     int         i_oprcom;
   14279              :     int         i_oprnegate;
   14280              :     int         i_oprrest;
   14281              :     int         i_oprjoin;
   14282              :     int         i_oprcanmerge;
   14283              :     int         i_oprcanhash;
   14284              :     char       *oprkind;
   14285              :     char       *oprcode;
   14286              :     char       *oprleft;
   14287              :     char       *oprright;
   14288              :     char       *oprcom;
   14289              :     char       *oprnegate;
   14290              :     char       *oprrest;
   14291              :     char       *oprjoin;
   14292              :     char       *oprcanmerge;
   14293              :     char       *oprcanhash;
   14294              :     char       *oprregproc;
   14295              :     char       *oprref;
   14296              : 
   14297              :     /* Do nothing if not dumping schema */
   14298         2522 :     if (!dopt->dumpSchema)
   14299            6 :         return;
   14300              : 
   14301              :     /*
   14302              :      * some operators are invalid because they were the result of user
   14303              :      * defining operators before commutators exist
   14304              :      */
   14305         2516 :     if (!OidIsValid(oprinfo->oprcode))
   14306           14 :         return;
   14307              : 
   14308         2502 :     query = createPQExpBuffer();
   14309         2502 :     q = createPQExpBuffer();
   14310         2502 :     delq = createPQExpBuffer();
   14311         2502 :     oprid = createPQExpBuffer();
   14312         2502 :     details = createPQExpBuffer();
   14313              : 
   14314         2502 :     if (!fout->is_prepared[PREPQUERY_DUMPOPR])
   14315              :     {
   14316              :         /* Set up query for operator-specific details */
   14317           40 :         appendPQExpBufferStr(query,
   14318              :                              "PREPARE dumpOpr(pg_catalog.oid) AS\n"
   14319              :                              "SELECT oprkind, "
   14320              :                              "oprcode::pg_catalog.regprocedure, "
   14321              :                              "oprleft::pg_catalog.regtype, "
   14322              :                              "oprright::pg_catalog.regtype, "
   14323              :                              "oprcom, "
   14324              :                              "oprnegate, "
   14325              :                              "oprrest::pg_catalog.regprocedure, "
   14326              :                              "oprjoin::pg_catalog.regprocedure, "
   14327              :                              "oprcanmerge, oprcanhash "
   14328              :                              "FROM pg_catalog.pg_operator "
   14329              :                              "WHERE oid = $1");
   14330              : 
   14331           40 :         ExecuteSqlStatement(fout, query->data);
   14332              : 
   14333           40 :         fout->is_prepared[PREPQUERY_DUMPOPR] = true;
   14334              :     }
   14335              : 
   14336         2502 :     printfPQExpBuffer(query,
   14337              :                       "EXECUTE dumpOpr('%u')",
   14338         2502 :                       oprinfo->dobj.catId.oid);
   14339              : 
   14340         2502 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   14341              : 
   14342         2502 :     i_oprkind = PQfnumber(res, "oprkind");
   14343         2502 :     i_oprcode = PQfnumber(res, "oprcode");
   14344         2502 :     i_oprleft = PQfnumber(res, "oprleft");
   14345         2502 :     i_oprright = PQfnumber(res, "oprright");
   14346         2502 :     i_oprcom = PQfnumber(res, "oprcom");
   14347         2502 :     i_oprnegate = PQfnumber(res, "oprnegate");
   14348         2502 :     i_oprrest = PQfnumber(res, "oprrest");
   14349         2502 :     i_oprjoin = PQfnumber(res, "oprjoin");
   14350         2502 :     i_oprcanmerge = PQfnumber(res, "oprcanmerge");
   14351         2502 :     i_oprcanhash = PQfnumber(res, "oprcanhash");
   14352              : 
   14353         2502 :     oprkind = PQgetvalue(res, 0, i_oprkind);
   14354         2502 :     oprcode = PQgetvalue(res, 0, i_oprcode);
   14355         2502 :     oprleft = PQgetvalue(res, 0, i_oprleft);
   14356         2502 :     oprright = PQgetvalue(res, 0, i_oprright);
   14357         2502 :     oprcom = PQgetvalue(res, 0, i_oprcom);
   14358         2502 :     oprnegate = PQgetvalue(res, 0, i_oprnegate);
   14359         2502 :     oprrest = PQgetvalue(res, 0, i_oprrest);
   14360         2502 :     oprjoin = PQgetvalue(res, 0, i_oprjoin);
   14361         2502 :     oprcanmerge = PQgetvalue(res, 0, i_oprcanmerge);
   14362         2502 :     oprcanhash = PQgetvalue(res, 0, i_oprcanhash);
   14363              : 
   14364              :     /* In PG14 upwards postfix operator support does not exist anymore. */
   14365         2502 :     if (strcmp(oprkind, "r") == 0)
   14366            0 :         pg_log_warning("postfix operators are not supported anymore (operator \"%s\")",
   14367              :                        oprcode);
   14368              : 
   14369         2502 :     oprregproc = convertRegProcReference(oprcode);
   14370         2502 :     if (oprregproc)
   14371              :     {
   14372         2502 :         appendPQExpBuffer(details, "    FUNCTION = %s", oprregproc);
   14373         2502 :         free(oprregproc);
   14374              :     }
   14375              : 
   14376         2502 :     appendPQExpBuffer(oprid, "%s (",
   14377         2502 :                       oprinfo->dobj.name);
   14378              : 
   14379              :     /*
   14380              :      * right unary means there's a left arg and left unary means there's a
   14381              :      * right arg.  (Although the "r" case is dead code for PG14 and later,
   14382              :      * continue to support it in case we're dumping from an old server.)
   14383              :      */
   14384         2502 :     if (strcmp(oprkind, "r") == 0 ||
   14385         2502 :         strcmp(oprkind, "b") == 0)
   14386              :     {
   14387         2359 :         appendPQExpBuffer(details, ",\n    LEFTARG = %s", oprleft);
   14388         2359 :         appendPQExpBufferStr(oprid, oprleft);
   14389              :     }
   14390              :     else
   14391          143 :         appendPQExpBufferStr(oprid, "NONE");
   14392              : 
   14393         2502 :     if (strcmp(oprkind, "l") == 0 ||
   14394         2359 :         strcmp(oprkind, "b") == 0)
   14395              :     {
   14396         2502 :         appendPQExpBuffer(details, ",\n    RIGHTARG = %s", oprright);
   14397         2502 :         appendPQExpBuffer(oprid, ", %s)", oprright);
   14398              :     }
   14399              :     else
   14400            0 :         appendPQExpBufferStr(oprid, ", NONE)");
   14401              : 
   14402         2502 :     oprref = getFormattedOperatorName(oprcom);
   14403         2502 :     if (oprref)
   14404              :     {
   14405         1679 :         appendPQExpBuffer(details, ",\n    COMMUTATOR = %s", oprref);
   14406         1679 :         free(oprref);
   14407              :     }
   14408              : 
   14409         2502 :     oprref = getFormattedOperatorName(oprnegate);
   14410         2502 :     if (oprref)
   14411              :     {
   14412         1181 :         appendPQExpBuffer(details, ",\n    NEGATOR = %s", oprref);
   14413         1181 :         free(oprref);
   14414              :     }
   14415              : 
   14416         2502 :     if (strcmp(oprcanmerge, "t") == 0)
   14417          188 :         appendPQExpBufferStr(details, ",\n    MERGES");
   14418              : 
   14419         2502 :     if (strcmp(oprcanhash, "t") == 0)
   14420          141 :         appendPQExpBufferStr(details, ",\n    HASHES");
   14421              : 
   14422         2502 :     oprregproc = convertRegProcReference(oprrest);
   14423         2502 :     if (oprregproc)
   14424              :     {
   14425         1532 :         appendPQExpBuffer(details, ",\n    RESTRICT = %s", oprregproc);
   14426         1532 :         free(oprregproc);
   14427              :     }
   14428              : 
   14429         2502 :     oprregproc = convertRegProcReference(oprjoin);
   14430         2502 :     if (oprregproc)
   14431              :     {
   14432         1532 :         appendPQExpBuffer(details, ",\n    JOIN = %s", oprregproc);
   14433         1532 :         free(oprregproc);
   14434              :     }
   14435              : 
   14436         2502 :     appendPQExpBuffer(delq, "DROP OPERATOR %s.%s;\n",
   14437         2502 :                       fmtId(oprinfo->dobj.namespace->dobj.name),
   14438              :                       oprid->data);
   14439              : 
   14440         2502 :     appendPQExpBuffer(q, "CREATE OPERATOR %s.%s (\n%s\n);\n",
   14441         2502 :                       fmtId(oprinfo->dobj.namespace->dobj.name),
   14442         2502 :                       oprinfo->dobj.name, details->data);
   14443              : 
   14444         2502 :     if (dopt->binary_upgrade)
   14445           12 :         binary_upgrade_extension_member(q, &oprinfo->dobj,
   14446           12 :                                         "OPERATOR", oprid->data,
   14447           12 :                                         oprinfo->dobj.namespace->dobj.name);
   14448              : 
   14449         2502 :     if (oprinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   14450         2502 :         ArchiveEntry(fout, oprinfo->dobj.catId, oprinfo->dobj.dumpId,
   14451         2502 :                      ARCHIVE_OPTS(.tag = oprinfo->dobj.name,
   14452              :                                   .namespace = oprinfo->dobj.namespace->dobj.name,
   14453              :                                   .owner = oprinfo->rolname,
   14454              :                                   .description = "OPERATOR",
   14455              :                                   .section = SECTION_PRE_DATA,
   14456              :                                   .createStmt = q->data,
   14457              :                                   .dropStmt = delq->data));
   14458              : 
   14459              :     /* Dump Operator Comments */
   14460         2502 :     if (oprinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   14461         2415 :         dumpComment(fout, "OPERATOR", oprid->data,
   14462         2415 :                     oprinfo->dobj.namespace->dobj.name, oprinfo->rolname,
   14463         2415 :                     oprinfo->dobj.catId, 0, oprinfo->dobj.dumpId);
   14464              : 
   14465         2502 :     PQclear(res);
   14466              : 
   14467         2502 :     destroyPQExpBuffer(query);
   14468         2502 :     destroyPQExpBuffer(q);
   14469         2502 :     destroyPQExpBuffer(delq);
   14470         2502 :     destroyPQExpBuffer(oprid);
   14471         2502 :     destroyPQExpBuffer(details);
   14472              : }
   14473              : 
   14474              : /*
   14475              :  * Convert a function reference obtained from pg_operator
   14476              :  *
   14477              :  * Returns allocated string of what to print, or NULL if function references
   14478              :  * is InvalidOid. Returned string is expected to be free'd by the caller.
   14479              :  *
   14480              :  * The input is a REGPROCEDURE display; we have to strip the argument-types
   14481              :  * part.
   14482              :  */
   14483              : static char *
   14484         7506 : convertRegProcReference(const char *proc)
   14485              : {
   14486              :     char       *name;
   14487              :     char       *paren;
   14488              :     bool        inquote;
   14489              : 
   14490              :     /* In all cases "-" means a null reference */
   14491         7506 :     if (strcmp(proc, "-") == 0)
   14492         1940 :         return NULL;
   14493              : 
   14494         5566 :     name = pg_strdup(proc);
   14495              :     /* find non-double-quoted left paren */
   14496         5566 :     inquote = false;
   14497        66996 :     for (paren = name; *paren; paren++)
   14498              :     {
   14499        66996 :         if (*paren == '(' && !inquote)
   14500              :         {
   14501         5566 :             *paren = '\0';
   14502         5566 :             break;
   14503              :         }
   14504        61430 :         if (*paren == '"')
   14505           50 :             inquote = !inquote;
   14506              :     }
   14507         5566 :     return name;
   14508              : }
   14509              : 
   14510              : /*
   14511              :  * getFormattedOperatorName - retrieve the operator name for the
   14512              :  * given operator OID (presented in string form).
   14513              :  *
   14514              :  * Returns an allocated string, or NULL if the given OID is invalid.
   14515              :  * Caller is responsible for free'ing result string.
   14516              :  *
   14517              :  * What we produce has the format "OPERATOR(schema.oprname)".  This is only
   14518              :  * useful in commands where the operator's argument types can be inferred from
   14519              :  * context.  We always schema-qualify the name, though.  The predecessor to
   14520              :  * this code tried to skip the schema qualification if possible, but that led
   14521              :  * to wrong results in corner cases, such as if an operator and its negator
   14522              :  * are in different schemas.
   14523              :  */
   14524              : static char *
   14525         5289 : getFormattedOperatorName(const char *oproid)
   14526              : {
   14527              :     OprInfo    *oprInfo;
   14528              : 
   14529              :     /* In all cases "0" means a null reference */
   14530         5289 :     if (strcmp(oproid, "0") == 0)
   14531         2429 :         return NULL;
   14532              : 
   14533         2860 :     oprInfo = findOprByOid(atooid(oproid));
   14534         2860 :     if (oprInfo == NULL)
   14535              :     {
   14536            0 :         pg_log_warning("could not find operator with OID %s",
   14537              :                        oproid);
   14538            0 :         return NULL;
   14539              :     }
   14540              : 
   14541         2860 :     return psprintf("OPERATOR(%s.%s)",
   14542         2860 :                     fmtId(oprInfo->dobj.namespace->dobj.name),
   14543              :                     oprInfo->dobj.name);
   14544              : }
   14545              : 
   14546              : /*
   14547              :  * Convert a function OID obtained from pg_ts_parser or pg_ts_template
   14548              :  *
   14549              :  * It is sufficient to use REGPROC rather than REGPROCEDURE, since the
   14550              :  * argument lists of these functions are predetermined.  Note that the
   14551              :  * caller should ensure we are in the proper schema, because the results
   14552              :  * are search path dependent!
   14553              :  */
   14554              : static char *
   14555          205 : convertTSFunction(Archive *fout, Oid funcOid)
   14556              : {
   14557              :     char       *result;
   14558              :     char        query[128];
   14559              :     PGresult   *res;
   14560              : 
   14561          205 :     snprintf(query, sizeof(query),
   14562              :              "SELECT '%u'::pg_catalog.regproc", funcOid);
   14563          205 :     res = ExecuteSqlQueryForSingleRow(fout, query);
   14564              : 
   14565          205 :     result = pg_strdup(PQgetvalue(res, 0, 0));
   14566              : 
   14567          205 :     PQclear(res);
   14568              : 
   14569          205 :     return result;
   14570              : }
   14571              : 
   14572              : /*
   14573              :  * dumpAccessMethod
   14574              :  *    write out a single access method definition
   14575              :  */
   14576              : static void
   14577           80 : dumpAccessMethod(Archive *fout, const AccessMethodInfo *aminfo)
   14578              : {
   14579           80 :     DumpOptions *dopt = fout->dopt;
   14580              :     PQExpBuffer q;
   14581              :     PQExpBuffer delq;
   14582              :     char       *qamname;
   14583              : 
   14584              :     /* Do nothing if not dumping schema */
   14585           80 :     if (!dopt->dumpSchema)
   14586           12 :         return;
   14587              : 
   14588           68 :     q = createPQExpBuffer();
   14589           68 :     delq = createPQExpBuffer();
   14590              : 
   14591           68 :     qamname = pg_strdup(fmtId(aminfo->dobj.name));
   14592              : 
   14593           68 :     appendPQExpBuffer(q, "CREATE ACCESS METHOD %s ", qamname);
   14594              : 
   14595           68 :     switch (aminfo->amtype)
   14596              :     {
   14597           32 :         case AMTYPE_INDEX:
   14598           32 :             appendPQExpBufferStr(q, "TYPE INDEX ");
   14599           32 :             break;
   14600           36 :         case AMTYPE_TABLE:
   14601           36 :             appendPQExpBufferStr(q, "TYPE TABLE ");
   14602           36 :             break;
   14603            0 :         default:
   14604            0 :             pg_log_warning("invalid type \"%c\" of access method \"%s\"",
   14605              :                            aminfo->amtype, qamname);
   14606            0 :             destroyPQExpBuffer(q);
   14607            0 :             destroyPQExpBuffer(delq);
   14608            0 :             free(qamname);
   14609            0 :             return;
   14610              :     }
   14611              : 
   14612           68 :     appendPQExpBuffer(q, "HANDLER %s;\n", aminfo->amhandler);
   14613              : 
   14614           68 :     appendPQExpBuffer(delq, "DROP ACCESS METHOD %s;\n",
   14615              :                       qamname);
   14616              : 
   14617           68 :     if (dopt->binary_upgrade)
   14618            4 :         binary_upgrade_extension_member(q, &aminfo->dobj,
   14619              :                                         "ACCESS METHOD", qamname, NULL);
   14620              : 
   14621           68 :     if (aminfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   14622           68 :         ArchiveEntry(fout, aminfo->dobj.catId, aminfo->dobj.dumpId,
   14623           68 :                      ARCHIVE_OPTS(.tag = aminfo->dobj.name,
   14624              :                                   .description = "ACCESS METHOD",
   14625              :                                   .section = SECTION_PRE_DATA,
   14626              :                                   .createStmt = q->data,
   14627              :                                   .dropStmt = delq->data));
   14628              : 
   14629              :     /* Dump Access Method Comments */
   14630           68 :     if (aminfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   14631            0 :         dumpComment(fout, "ACCESS METHOD", qamname,
   14632              :                     NULL, "",
   14633            0 :                     aminfo->dobj.catId, 0, aminfo->dobj.dumpId);
   14634              : 
   14635           68 :     destroyPQExpBuffer(q);
   14636           68 :     destroyPQExpBuffer(delq);
   14637           68 :     free(qamname);
   14638              : }
   14639              : 
   14640              : /*
   14641              :  * dumpOpclass
   14642              :  *    write out a single operator class definition
   14643              :  */
   14644              : static void
   14645          666 : dumpOpclass(Archive *fout, const OpclassInfo *opcinfo)
   14646              : {
   14647          666 :     DumpOptions *dopt = fout->dopt;
   14648              :     PQExpBuffer query;
   14649              :     PQExpBuffer q;
   14650              :     PQExpBuffer delq;
   14651              :     PQExpBuffer nameusing;
   14652              :     PGresult   *res;
   14653              :     int         ntups;
   14654              :     int         i_opcintype;
   14655              :     int         i_opckeytype;
   14656              :     int         i_opcdefault;
   14657              :     int         i_opcfamily;
   14658              :     int         i_opcfamilyname;
   14659              :     int         i_opcfamilynsp;
   14660              :     int         i_amname;
   14661              :     int         i_amopstrategy;
   14662              :     int         i_amopopr;
   14663              :     int         i_sortfamily;
   14664              :     int         i_sortfamilynsp;
   14665              :     int         i_amprocnum;
   14666              :     int         i_amproc;
   14667              :     int         i_amproclefttype;
   14668              :     int         i_amprocrighttype;
   14669              :     char       *opcintype;
   14670              :     char       *opckeytype;
   14671              :     char       *opcdefault;
   14672              :     char       *opcfamily;
   14673              :     char       *opcfamilyname;
   14674              :     char       *opcfamilynsp;
   14675              :     char       *amname;
   14676              :     char       *amopstrategy;
   14677              :     char       *amopopr;
   14678              :     char       *sortfamily;
   14679              :     char       *sortfamilynsp;
   14680              :     char       *amprocnum;
   14681              :     char       *amproc;
   14682              :     char       *amproclefttype;
   14683              :     char       *amprocrighttype;
   14684              :     bool        needComma;
   14685              :     int         i;
   14686              : 
   14687              :     /* Do nothing if not dumping schema */
   14688          666 :     if (!dopt->dumpSchema)
   14689           18 :         return;
   14690              : 
   14691          648 :     query = createPQExpBuffer();
   14692          648 :     q = createPQExpBuffer();
   14693          648 :     delq = createPQExpBuffer();
   14694          648 :     nameusing = createPQExpBuffer();
   14695              : 
   14696              :     /* Get additional fields from the pg_opclass row */
   14697          648 :     appendPQExpBuffer(query, "SELECT opcintype::pg_catalog.regtype, "
   14698              :                       "opckeytype::pg_catalog.regtype, "
   14699              :                       "opcdefault, opcfamily, "
   14700              :                       "opfname AS opcfamilyname, "
   14701              :                       "nspname AS opcfamilynsp, "
   14702              :                       "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opcmethod) AS amname "
   14703              :                       "FROM pg_catalog.pg_opclass c "
   14704              :                       "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = opcfamily "
   14705              :                       "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
   14706              :                       "WHERE c.oid = '%u'::pg_catalog.oid",
   14707          648 :                       opcinfo->dobj.catId.oid);
   14708              : 
   14709          648 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   14710              : 
   14711          648 :     i_opcintype = PQfnumber(res, "opcintype");
   14712          648 :     i_opckeytype = PQfnumber(res, "opckeytype");
   14713          648 :     i_opcdefault = PQfnumber(res, "opcdefault");
   14714          648 :     i_opcfamily = PQfnumber(res, "opcfamily");
   14715          648 :     i_opcfamilyname = PQfnumber(res, "opcfamilyname");
   14716          648 :     i_opcfamilynsp = PQfnumber(res, "opcfamilynsp");
   14717          648 :     i_amname = PQfnumber(res, "amname");
   14718              : 
   14719              :     /* opcintype may still be needed after we PQclear res */
   14720          648 :     opcintype = pg_strdup(PQgetvalue(res, 0, i_opcintype));
   14721          648 :     opckeytype = PQgetvalue(res, 0, i_opckeytype);
   14722          648 :     opcdefault = PQgetvalue(res, 0, i_opcdefault);
   14723              :     /* opcfamily will still be needed after we PQclear res */
   14724          648 :     opcfamily = pg_strdup(PQgetvalue(res, 0, i_opcfamily));
   14725          648 :     opcfamilyname = PQgetvalue(res, 0, i_opcfamilyname);
   14726          648 :     opcfamilynsp = PQgetvalue(res, 0, i_opcfamilynsp);
   14727              :     /* amname will still be needed after we PQclear res */
   14728          648 :     amname = pg_strdup(PQgetvalue(res, 0, i_amname));
   14729              : 
   14730          648 :     appendPQExpBuffer(delq, "DROP OPERATOR CLASS %s",
   14731          648 :                       fmtQualifiedDumpable(opcinfo));
   14732          648 :     appendPQExpBuffer(delq, " USING %s;\n",
   14733              :                       fmtId(amname));
   14734              : 
   14735              :     /* Build the fixed portion of the CREATE command */
   14736          648 :     appendPQExpBuffer(q, "CREATE OPERATOR CLASS %s\n    ",
   14737          648 :                       fmtQualifiedDumpable(opcinfo));
   14738          648 :     if (strcmp(opcdefault, "t") == 0)
   14739          366 :         appendPQExpBufferStr(q, "DEFAULT ");
   14740          648 :     appendPQExpBuffer(q, "FOR TYPE %s USING %s",
   14741              :                       opcintype,
   14742              :                       fmtId(amname));
   14743          648 :     if (strlen(opcfamilyname) > 0)
   14744              :     {
   14745          648 :         appendPQExpBufferStr(q, " FAMILY ");
   14746          648 :         appendPQExpBuffer(q, "%s.", fmtId(opcfamilynsp));
   14747          648 :         appendPQExpBufferStr(q, fmtId(opcfamilyname));
   14748              :     }
   14749          648 :     appendPQExpBufferStr(q, " AS\n    ");
   14750              : 
   14751          648 :     needComma = false;
   14752              : 
   14753          648 :     if (strcmp(opckeytype, "-") != 0)
   14754              :     {
   14755          252 :         appendPQExpBuffer(q, "STORAGE %s",
   14756              :                           opckeytype);
   14757          252 :         needComma = true;
   14758              :     }
   14759              : 
   14760          648 :     PQclear(res);
   14761              : 
   14762              :     /*
   14763              :      * Now fetch and print the OPERATOR entries (pg_amop rows).
   14764              :      *
   14765              :      * Print only those opfamily members that are tied to the opclass by
   14766              :      * pg_depend entries.
   14767              :      */
   14768          648 :     resetPQExpBuffer(query);
   14769          648 :     appendPQExpBuffer(query, "SELECT amopstrategy, "
   14770              :                       "amopopr::pg_catalog.regoperator, "
   14771              :                       "opfname AS sortfamily, "
   14772              :                       "nspname AS sortfamilynsp "
   14773              :                       "FROM pg_catalog.pg_amop ao JOIN pg_catalog.pg_depend ON "
   14774              :                       "(classid = 'pg_catalog.pg_amop'::pg_catalog.regclass AND objid = ao.oid) "
   14775              :                       "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = amopsortfamily "
   14776              :                       "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
   14777              :                       "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
   14778              :                       "AND refobjid = '%u'::pg_catalog.oid "
   14779              :                       "AND amopfamily = '%s'::pg_catalog.oid "
   14780              :                       "ORDER BY amopstrategy",
   14781          648 :                       opcinfo->dobj.catId.oid,
   14782              :                       opcfamily);
   14783              : 
   14784          648 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   14785              : 
   14786          648 :     ntups = PQntuples(res);
   14787              : 
   14788          648 :     i_amopstrategy = PQfnumber(res, "amopstrategy");
   14789          648 :     i_amopopr = PQfnumber(res, "amopopr");
   14790          648 :     i_sortfamily = PQfnumber(res, "sortfamily");
   14791          648 :     i_sortfamilynsp = PQfnumber(res, "sortfamilynsp");
   14792              : 
   14793          850 :     for (i = 0; i < ntups; i++)
   14794              :     {
   14795          202 :         amopstrategy = PQgetvalue(res, i, i_amopstrategy);
   14796          202 :         amopopr = PQgetvalue(res, i, i_amopopr);
   14797          202 :         sortfamily = PQgetvalue(res, i, i_sortfamily);
   14798          202 :         sortfamilynsp = PQgetvalue(res, i, i_sortfamilynsp);
   14799              : 
   14800          202 :         if (needComma)
   14801          128 :             appendPQExpBufferStr(q, " ,\n    ");
   14802              : 
   14803          202 :         appendPQExpBuffer(q, "OPERATOR %s %s",
   14804              :                           amopstrategy, amopopr);
   14805              : 
   14806          202 :         if (strlen(sortfamily) > 0)
   14807              :         {
   14808            0 :             appendPQExpBufferStr(q, " FOR ORDER BY ");
   14809            0 :             appendPQExpBuffer(q, "%s.", fmtId(sortfamilynsp));
   14810            0 :             appendPQExpBufferStr(q, fmtId(sortfamily));
   14811              :         }
   14812              : 
   14813          202 :         needComma = true;
   14814              :     }
   14815              : 
   14816          648 :     PQclear(res);
   14817              : 
   14818              :     /*
   14819              :      * Now fetch and print the FUNCTION entries (pg_amproc rows).
   14820              :      *
   14821              :      * Print only those opfamily members that are tied to the opclass by
   14822              :      * pg_depend entries.
   14823              :      *
   14824              :      * We print the amproclefttype/amprocrighttype even though in most cases
   14825              :      * the backend could deduce the right values, because of the corner case
   14826              :      * of a btree sort support function for a cross-type comparison.
   14827              :      */
   14828          648 :     resetPQExpBuffer(query);
   14829              : 
   14830          648 :     appendPQExpBuffer(query, "SELECT amprocnum, "
   14831              :                       "amproc::pg_catalog.regprocedure, "
   14832              :                       "amproclefttype::pg_catalog.regtype, "
   14833              :                       "amprocrighttype::pg_catalog.regtype "
   14834              :                       "FROM pg_catalog.pg_amproc ap, pg_catalog.pg_depend "
   14835              :                       "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
   14836              :                       "AND refobjid = '%u'::pg_catalog.oid "
   14837              :                       "AND classid = 'pg_catalog.pg_amproc'::pg_catalog.regclass "
   14838              :                       "AND objid = ap.oid "
   14839              :                       "ORDER BY amprocnum",
   14840          648 :                       opcinfo->dobj.catId.oid);
   14841              : 
   14842          648 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   14843              : 
   14844          648 :     ntups = PQntuples(res);
   14845              : 
   14846          648 :     i_amprocnum = PQfnumber(res, "amprocnum");
   14847          648 :     i_amproc = PQfnumber(res, "amproc");
   14848          648 :     i_amproclefttype = PQfnumber(res, "amproclefttype");
   14849          648 :     i_amprocrighttype = PQfnumber(res, "amprocrighttype");
   14850              : 
   14851          680 :     for (i = 0; i < ntups; i++)
   14852              :     {
   14853           32 :         amprocnum = PQgetvalue(res, i, i_amprocnum);
   14854           32 :         amproc = PQgetvalue(res, i, i_amproc);
   14855           32 :         amproclefttype = PQgetvalue(res, i, i_amproclefttype);
   14856           32 :         amprocrighttype = PQgetvalue(res, i, i_amprocrighttype);
   14857              : 
   14858           32 :         if (needComma)
   14859           32 :             appendPQExpBufferStr(q, " ,\n    ");
   14860              : 
   14861           32 :         appendPQExpBuffer(q, "FUNCTION %s", amprocnum);
   14862              : 
   14863           32 :         if (*amproclefttype && *amprocrighttype)
   14864           32 :             appendPQExpBuffer(q, " (%s, %s)", amproclefttype, amprocrighttype);
   14865              : 
   14866           32 :         appendPQExpBuffer(q, " %s", amproc);
   14867              : 
   14868           32 :         needComma = true;
   14869              :     }
   14870              : 
   14871          648 :     PQclear(res);
   14872              : 
   14873              :     /*
   14874              :      * If needComma is still false it means we haven't added anything after
   14875              :      * the AS keyword.  To avoid printing broken SQL, append a dummy STORAGE
   14876              :      * clause with the same datatype.  This isn't sanctioned by the
   14877              :      * documentation, but actually DefineOpClass will treat it as a no-op.
   14878              :      */
   14879          648 :     if (!needComma)
   14880          322 :         appendPQExpBuffer(q, "STORAGE %s", opcintype);
   14881              : 
   14882          648 :     appendPQExpBufferStr(q, ";\n");
   14883              : 
   14884          648 :     appendPQExpBufferStr(nameusing, fmtId(opcinfo->dobj.name));
   14885          648 :     appendPQExpBuffer(nameusing, " USING %s",
   14886              :                       fmtId(amname));
   14887              : 
   14888          648 :     if (dopt->binary_upgrade)
   14889            6 :         binary_upgrade_extension_member(q, &opcinfo->dobj,
   14890            6 :                                         "OPERATOR CLASS", nameusing->data,
   14891            6 :                                         opcinfo->dobj.namespace->dobj.name);
   14892              : 
   14893          648 :     if (opcinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   14894          648 :         ArchiveEntry(fout, opcinfo->dobj.catId, opcinfo->dobj.dumpId,
   14895          648 :                      ARCHIVE_OPTS(.tag = opcinfo->dobj.name,
   14896              :                                   .namespace = opcinfo->dobj.namespace->dobj.name,
   14897              :                                   .owner = opcinfo->rolname,
   14898              :                                   .description = "OPERATOR CLASS",
   14899              :                                   .section = SECTION_PRE_DATA,
   14900              :                                   .createStmt = q->data,
   14901              :                                   .dropStmt = delq->data));
   14902              : 
   14903              :     /* Dump Operator Class Comments */
   14904          648 :     if (opcinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   14905            0 :         dumpComment(fout, "OPERATOR CLASS", nameusing->data,
   14906            0 :                     opcinfo->dobj.namespace->dobj.name, opcinfo->rolname,
   14907            0 :                     opcinfo->dobj.catId, 0, opcinfo->dobj.dumpId);
   14908              : 
   14909          648 :     free(opcintype);
   14910          648 :     free(opcfamily);
   14911          648 :     free(amname);
   14912          648 :     destroyPQExpBuffer(query);
   14913          648 :     destroyPQExpBuffer(q);
   14914          648 :     destroyPQExpBuffer(delq);
   14915          648 :     destroyPQExpBuffer(nameusing);
   14916              : }
   14917              : 
   14918              : /*
   14919              :  * dumpOpfamily
   14920              :  *    write out a single operator family definition
   14921              :  *
   14922              :  * Note: this also dumps any "loose" operator members that aren't bound to a
   14923              :  * specific opclass within the opfamily.
   14924              :  */
   14925              : static void
   14926          555 : dumpOpfamily(Archive *fout, const OpfamilyInfo *opfinfo)
   14927              : {
   14928          555 :     DumpOptions *dopt = fout->dopt;
   14929              :     PQExpBuffer query;
   14930              :     PQExpBuffer q;
   14931              :     PQExpBuffer delq;
   14932              :     PQExpBuffer nameusing;
   14933              :     PGresult   *res;
   14934              :     PGresult   *res_ops;
   14935              :     PGresult   *res_procs;
   14936              :     int         ntups;
   14937              :     int         i_amname;
   14938              :     int         i_amopstrategy;
   14939              :     int         i_amopopr;
   14940              :     int         i_sortfamily;
   14941              :     int         i_sortfamilynsp;
   14942              :     int         i_amprocnum;
   14943              :     int         i_amproc;
   14944              :     int         i_amproclefttype;
   14945              :     int         i_amprocrighttype;
   14946              :     char       *amname;
   14947              :     char       *amopstrategy;
   14948              :     char       *amopopr;
   14949              :     char       *sortfamily;
   14950              :     char       *sortfamilynsp;
   14951              :     char       *amprocnum;
   14952              :     char       *amproc;
   14953              :     char       *amproclefttype;
   14954              :     char       *amprocrighttype;
   14955              :     bool        needComma;
   14956              :     int         i;
   14957              : 
   14958              :     /* Do nothing if not dumping schema */
   14959          555 :     if (!dopt->dumpSchema)
   14960           12 :         return;
   14961              : 
   14962          543 :     query = createPQExpBuffer();
   14963          543 :     q = createPQExpBuffer();
   14964          543 :     delq = createPQExpBuffer();
   14965          543 :     nameusing = createPQExpBuffer();
   14966              : 
   14967              :     /*
   14968              :      * Fetch only those opfamily members that are tied directly to the
   14969              :      * opfamily by pg_depend entries.
   14970              :      */
   14971          543 :     appendPQExpBuffer(query, "SELECT amopstrategy, "
   14972              :                       "amopopr::pg_catalog.regoperator, "
   14973              :                       "opfname AS sortfamily, "
   14974              :                       "nspname AS sortfamilynsp "
   14975              :                       "FROM pg_catalog.pg_amop ao JOIN pg_catalog.pg_depend ON "
   14976              :                       "(classid = 'pg_catalog.pg_amop'::pg_catalog.regclass AND objid = ao.oid) "
   14977              :                       "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = amopsortfamily "
   14978              :                       "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
   14979              :                       "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
   14980              :                       "AND refobjid = '%u'::pg_catalog.oid "
   14981              :                       "AND amopfamily = '%u'::pg_catalog.oid "
   14982              :                       "ORDER BY amopstrategy",
   14983          543 :                       opfinfo->dobj.catId.oid,
   14984          543 :                       opfinfo->dobj.catId.oid);
   14985              : 
   14986          543 :     res_ops = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   14987              : 
   14988          543 :     resetPQExpBuffer(query);
   14989              : 
   14990          543 :     appendPQExpBuffer(query, "SELECT amprocnum, "
   14991              :                       "amproc::pg_catalog.regprocedure, "
   14992              :                       "amproclefttype::pg_catalog.regtype, "
   14993              :                       "amprocrighttype::pg_catalog.regtype "
   14994              :                       "FROM pg_catalog.pg_amproc ap, pg_catalog.pg_depend "
   14995              :                       "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
   14996              :                       "AND refobjid = '%u'::pg_catalog.oid "
   14997              :                       "AND classid = 'pg_catalog.pg_amproc'::pg_catalog.regclass "
   14998              :                       "AND objid = ap.oid "
   14999              :                       "ORDER BY amprocnum",
   15000          543 :                       opfinfo->dobj.catId.oid);
   15001              : 
   15002          543 :     res_procs = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   15003              : 
   15004              :     /* Get additional fields from the pg_opfamily row */
   15005          543 :     resetPQExpBuffer(query);
   15006              : 
   15007          543 :     appendPQExpBuffer(query, "SELECT "
   15008              :                       "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opfmethod) AS amname "
   15009              :                       "FROM pg_catalog.pg_opfamily "
   15010              :                       "WHERE oid = '%u'::pg_catalog.oid",
   15011          543 :                       opfinfo->dobj.catId.oid);
   15012              : 
   15013          543 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   15014              : 
   15015          543 :     i_amname = PQfnumber(res, "amname");
   15016              : 
   15017              :     /* amname will still be needed after we PQclear res */
   15018          543 :     amname = pg_strdup(PQgetvalue(res, 0, i_amname));
   15019              : 
   15020          543 :     appendPQExpBuffer(delq, "DROP OPERATOR FAMILY %s",
   15021          543 :                       fmtQualifiedDumpable(opfinfo));
   15022          543 :     appendPQExpBuffer(delq, " USING %s;\n",
   15023              :                       fmtId(amname));
   15024              : 
   15025              :     /* Build the fixed portion of the CREATE command */
   15026          543 :     appendPQExpBuffer(q, "CREATE OPERATOR FAMILY %s",
   15027          543 :                       fmtQualifiedDumpable(opfinfo));
   15028          543 :     appendPQExpBuffer(q, " USING %s;\n",
   15029              :                       fmtId(amname));
   15030              : 
   15031          543 :     PQclear(res);
   15032              : 
   15033              :     /* Do we need an ALTER to add loose members? */
   15034          543 :     if (PQntuples(res_ops) > 0 || PQntuples(res_procs) > 0)
   15035              :     {
   15036           47 :         appendPQExpBuffer(q, "ALTER OPERATOR FAMILY %s",
   15037           47 :                           fmtQualifiedDumpable(opfinfo));
   15038           47 :         appendPQExpBuffer(q, " USING %s ADD\n    ",
   15039              :                           fmtId(amname));
   15040              : 
   15041           47 :         needComma = false;
   15042              : 
   15043              :         /*
   15044              :          * Now fetch and print the OPERATOR entries (pg_amop rows).
   15045              :          */
   15046           47 :         ntups = PQntuples(res_ops);
   15047              : 
   15048           47 :         i_amopstrategy = PQfnumber(res_ops, "amopstrategy");
   15049           47 :         i_amopopr = PQfnumber(res_ops, "amopopr");
   15050           47 :         i_sortfamily = PQfnumber(res_ops, "sortfamily");
   15051           47 :         i_sortfamilynsp = PQfnumber(res_ops, "sortfamilynsp");
   15052              : 
   15053          207 :         for (i = 0; i < ntups; i++)
   15054              :         {
   15055          160 :             amopstrategy = PQgetvalue(res_ops, i, i_amopstrategy);
   15056          160 :             amopopr = PQgetvalue(res_ops, i, i_amopopr);
   15057          160 :             sortfamily = PQgetvalue(res_ops, i, i_sortfamily);
   15058          160 :             sortfamilynsp = PQgetvalue(res_ops, i, i_sortfamilynsp);
   15059              : 
   15060          160 :             if (needComma)
   15061          128 :                 appendPQExpBufferStr(q, " ,\n    ");
   15062              : 
   15063          160 :             appendPQExpBuffer(q, "OPERATOR %s %s",
   15064              :                               amopstrategy, amopopr);
   15065              : 
   15066          160 :             if (strlen(sortfamily) > 0)
   15067              :             {
   15068            0 :                 appendPQExpBufferStr(q, " FOR ORDER BY ");
   15069            0 :                 appendPQExpBuffer(q, "%s.", fmtId(sortfamilynsp));
   15070            0 :                 appendPQExpBufferStr(q, fmtId(sortfamily));
   15071              :             }
   15072              : 
   15073          160 :             needComma = true;
   15074              :         }
   15075              : 
   15076              :         /*
   15077              :          * Now fetch and print the FUNCTION entries (pg_amproc rows).
   15078              :          */
   15079           47 :         ntups = PQntuples(res_procs);
   15080              : 
   15081           47 :         i_amprocnum = PQfnumber(res_procs, "amprocnum");
   15082           47 :         i_amproc = PQfnumber(res_procs, "amproc");
   15083           47 :         i_amproclefttype = PQfnumber(res_procs, "amproclefttype");
   15084           47 :         i_amprocrighttype = PQfnumber(res_procs, "amprocrighttype");
   15085              : 
   15086          222 :         for (i = 0; i < ntups; i++)
   15087              :         {
   15088          175 :             amprocnum = PQgetvalue(res_procs, i, i_amprocnum);
   15089          175 :             amproc = PQgetvalue(res_procs, i, i_amproc);
   15090          175 :             amproclefttype = PQgetvalue(res_procs, i, i_amproclefttype);
   15091          175 :             amprocrighttype = PQgetvalue(res_procs, i, i_amprocrighttype);
   15092              : 
   15093          175 :             if (needComma)
   15094          160 :                 appendPQExpBufferStr(q, " ,\n    ");
   15095              : 
   15096          175 :             appendPQExpBuffer(q, "FUNCTION %s (%s, %s) %s",
   15097              :                               amprocnum, amproclefttype, amprocrighttype,
   15098              :                               amproc);
   15099              : 
   15100          175 :             needComma = true;
   15101              :         }
   15102              : 
   15103           47 :         appendPQExpBufferStr(q, ";\n");
   15104              :     }
   15105              : 
   15106          543 :     appendPQExpBufferStr(nameusing, fmtId(opfinfo->dobj.name));
   15107          543 :     appendPQExpBuffer(nameusing, " USING %s",
   15108              :                       fmtId(amname));
   15109              : 
   15110          543 :     if (dopt->binary_upgrade)
   15111            9 :         binary_upgrade_extension_member(q, &opfinfo->dobj,
   15112            9 :                                         "OPERATOR FAMILY", nameusing->data,
   15113            9 :                                         opfinfo->dobj.namespace->dobj.name);
   15114              : 
   15115          543 :     if (opfinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   15116          543 :         ArchiveEntry(fout, opfinfo->dobj.catId, opfinfo->dobj.dumpId,
   15117          543 :                      ARCHIVE_OPTS(.tag = opfinfo->dobj.name,
   15118              :                                   .namespace = opfinfo->dobj.namespace->dobj.name,
   15119              :                                   .owner = opfinfo->rolname,
   15120              :                                   .description = "OPERATOR FAMILY",
   15121              :                                   .section = SECTION_PRE_DATA,
   15122              :                                   .createStmt = q->data,
   15123              :                                   .dropStmt = delq->data));
   15124              : 
   15125              :     /* Dump Operator Family Comments */
   15126          543 :     if (opfinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   15127            0 :         dumpComment(fout, "OPERATOR FAMILY", nameusing->data,
   15128            0 :                     opfinfo->dobj.namespace->dobj.name, opfinfo->rolname,
   15129            0 :                     opfinfo->dobj.catId, 0, opfinfo->dobj.dumpId);
   15130              : 
   15131          543 :     free(amname);
   15132          543 :     PQclear(res_ops);
   15133          543 :     PQclear(res_procs);
   15134          543 :     destroyPQExpBuffer(query);
   15135          543 :     destroyPQExpBuffer(q);
   15136          543 :     destroyPQExpBuffer(delq);
   15137          543 :     destroyPQExpBuffer(nameusing);
   15138              : }
   15139              : 
   15140              : /*
   15141              :  * dumpCollation
   15142              :  *    write out a single collation definition
   15143              :  */
   15144              : static void
   15145         2729 : dumpCollation(Archive *fout, const CollInfo *collinfo)
   15146              : {
   15147         2729 :     DumpOptions *dopt = fout->dopt;
   15148              :     PQExpBuffer query;
   15149              :     PQExpBuffer q;
   15150              :     PQExpBuffer delq;
   15151              :     char       *qcollname;
   15152              :     PGresult   *res;
   15153              :     int         i_collprovider;
   15154              :     int         i_collisdeterministic;
   15155              :     int         i_collcollate;
   15156              :     int         i_collctype;
   15157              :     int         i_colllocale;
   15158              :     int         i_collicurules;
   15159              :     const char *collprovider;
   15160              :     const char *collcollate;
   15161              :     const char *collctype;
   15162              :     const char *colllocale;
   15163              :     const char *collicurules;
   15164              : 
   15165              :     /* Do nothing if not dumping schema */
   15166         2729 :     if (!dopt->dumpSchema)
   15167           12 :         return;
   15168              : 
   15169         2717 :     query = createPQExpBuffer();
   15170         2717 :     q = createPQExpBuffer();
   15171         2717 :     delq = createPQExpBuffer();
   15172              : 
   15173         2717 :     qcollname = pg_strdup(fmtId(collinfo->dobj.name));
   15174              : 
   15175              :     /* Get collation-specific details */
   15176         2717 :     appendPQExpBufferStr(query, "SELECT ");
   15177              : 
   15178         2717 :     if (fout->remoteVersion >= 100000)
   15179         2717 :         appendPQExpBufferStr(query,
   15180              :                              "collprovider, "
   15181              :                              "collversion, ");
   15182              :     else
   15183            0 :         appendPQExpBufferStr(query,
   15184              :                              "'c' AS collprovider, "
   15185              :                              "NULL AS collversion, ");
   15186              : 
   15187         2717 :     if (fout->remoteVersion >= 120000)
   15188         2717 :         appendPQExpBufferStr(query,
   15189              :                              "collisdeterministic, ");
   15190              :     else
   15191            0 :         appendPQExpBufferStr(query,
   15192              :                              "true AS collisdeterministic, ");
   15193              : 
   15194         2717 :     if (fout->remoteVersion >= 170000)
   15195         2717 :         appendPQExpBufferStr(query,
   15196              :                              "colllocale, ");
   15197            0 :     else if (fout->remoteVersion >= 150000)
   15198            0 :         appendPQExpBufferStr(query,
   15199              :                              "colliculocale AS colllocale, ");
   15200              :     else
   15201            0 :         appendPQExpBufferStr(query,
   15202              :                              "NULL AS colllocale, ");
   15203              : 
   15204         2717 :     if (fout->remoteVersion >= 160000)
   15205         2717 :         appendPQExpBufferStr(query,
   15206              :                              "collicurules, ");
   15207              :     else
   15208            0 :         appendPQExpBufferStr(query,
   15209              :                              "NULL AS collicurules, ");
   15210              : 
   15211         2717 :     appendPQExpBuffer(query,
   15212              :                       "collcollate, "
   15213              :                       "collctype "
   15214              :                       "FROM pg_catalog.pg_collation c "
   15215              :                       "WHERE c.oid = '%u'::pg_catalog.oid",
   15216         2717 :                       collinfo->dobj.catId.oid);
   15217              : 
   15218         2717 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   15219              : 
   15220         2717 :     i_collprovider = PQfnumber(res, "collprovider");
   15221         2717 :     i_collisdeterministic = PQfnumber(res, "collisdeterministic");
   15222         2717 :     i_collcollate = PQfnumber(res, "collcollate");
   15223         2717 :     i_collctype = PQfnumber(res, "collctype");
   15224         2717 :     i_colllocale = PQfnumber(res, "colllocale");
   15225         2717 :     i_collicurules = PQfnumber(res, "collicurules");
   15226              : 
   15227         2717 :     collprovider = PQgetvalue(res, 0, i_collprovider);
   15228              : 
   15229         2717 :     if (!PQgetisnull(res, 0, i_collcollate))
   15230           46 :         collcollate = PQgetvalue(res, 0, i_collcollate);
   15231              :     else
   15232         2671 :         collcollate = NULL;
   15233              : 
   15234         2717 :     if (!PQgetisnull(res, 0, i_collctype))
   15235           46 :         collctype = PQgetvalue(res, 0, i_collctype);
   15236              :     else
   15237         2671 :         collctype = NULL;
   15238              : 
   15239              :     /*
   15240              :      * Before version 15, collcollate and collctype were of type NAME and
   15241              :      * non-nullable. Treat empty strings as NULL for consistency.
   15242              :      */
   15243         2717 :     if (fout->remoteVersion < 150000)
   15244              :     {
   15245            0 :         if (collcollate[0] == '\0')
   15246            0 :             collcollate = NULL;
   15247            0 :         if (collctype[0] == '\0')
   15248            0 :             collctype = NULL;
   15249              :     }
   15250              : 
   15251         2717 :     if (!PQgetisnull(res, 0, i_colllocale))
   15252         2668 :         colllocale = PQgetvalue(res, 0, i_colllocale);
   15253              :     else
   15254           49 :         colllocale = NULL;
   15255              : 
   15256         2717 :     if (!PQgetisnull(res, 0, i_collicurules))
   15257            0 :         collicurules = PQgetvalue(res, 0, i_collicurules);
   15258              :     else
   15259         2717 :         collicurules = NULL;
   15260              : 
   15261         2717 :     appendPQExpBuffer(delq, "DROP COLLATION %s;\n",
   15262         2717 :                       fmtQualifiedDumpable(collinfo));
   15263              : 
   15264         2717 :     appendPQExpBuffer(q, "CREATE COLLATION %s (",
   15265         2717 :                       fmtQualifiedDumpable(collinfo));
   15266              : 
   15267         2717 :     appendPQExpBufferStr(q, "provider = ");
   15268         2717 :     if (collprovider[0] == 'b')
   15269           19 :         appendPQExpBufferStr(q, "builtin");
   15270         2698 :     else if (collprovider[0] == 'c')
   15271           46 :         appendPQExpBufferStr(q, "libc");
   15272         2652 :     else if (collprovider[0] == 'i')
   15273         2649 :         appendPQExpBufferStr(q, "icu");
   15274            3 :     else if (collprovider[0] == 'd')
   15275              :         /* to allow dumping pg_catalog; not accepted on input */
   15276            3 :         appendPQExpBufferStr(q, "default");
   15277              :     else
   15278            0 :         pg_fatal("unrecognized collation provider: %s",
   15279              :                  collprovider);
   15280              : 
   15281         2717 :     if (strcmp(PQgetvalue(res, 0, i_collisdeterministic), "f") == 0)
   15282            0 :         appendPQExpBufferStr(q, ", deterministic = false");
   15283              : 
   15284         2717 :     if (collprovider[0] == 'd')
   15285              :     {
   15286            3 :         if (collcollate || collctype || colllocale || collicurules)
   15287            0 :             pg_log_warning("invalid collation \"%s\"", qcollname);
   15288              : 
   15289              :         /* no locale -- the default collation cannot be reloaded anyway */
   15290              :     }
   15291         2714 :     else if (collprovider[0] == 'b')
   15292              :     {
   15293           19 :         if (collcollate || collctype || !colllocale || collicurules)
   15294            0 :             pg_log_warning("invalid collation \"%s\"", qcollname);
   15295              : 
   15296           19 :         appendPQExpBufferStr(q, ", locale = ");
   15297           19 :         appendStringLiteralAH(q, colllocale ? colllocale : "",
   15298              :                               fout);
   15299              :     }
   15300         2695 :     else if (collprovider[0] == 'i')
   15301              :     {
   15302         2649 :         if (fout->remoteVersion >= 150000)
   15303              :         {
   15304         2649 :             if (collcollate || collctype || !colllocale)
   15305            0 :                 pg_log_warning("invalid collation \"%s\"", qcollname);
   15306              : 
   15307         2649 :             appendPQExpBufferStr(q, ", locale = ");
   15308         2649 :             appendStringLiteralAH(q, colllocale ? colllocale : "",
   15309              :                                   fout);
   15310              :         }
   15311              :         else
   15312              :         {
   15313            0 :             if (!collcollate || !collctype || colllocale ||
   15314            0 :                 strcmp(collcollate, collctype) != 0)
   15315            0 :                 pg_log_warning("invalid collation \"%s\"", qcollname);
   15316              : 
   15317            0 :             appendPQExpBufferStr(q, ", locale = ");
   15318            0 :             appendStringLiteralAH(q, collcollate ? collcollate : "", fout);
   15319              :         }
   15320              : 
   15321         2649 :         if (collicurules)
   15322              :         {
   15323            0 :             appendPQExpBufferStr(q, ", rules = ");
   15324            0 :             appendStringLiteralAH(q, collicurules ? collicurules : "", fout);
   15325              :         }
   15326              :     }
   15327           46 :     else if (collprovider[0] == 'c')
   15328              :     {
   15329           46 :         if (colllocale || collicurules || !collcollate || !collctype)
   15330            0 :             pg_log_warning("invalid collation \"%s\"", qcollname);
   15331              : 
   15332           46 :         if (collcollate && collctype && strcmp(collcollate, collctype) == 0)
   15333              :         {
   15334           46 :             appendPQExpBufferStr(q, ", locale = ");
   15335           46 :             appendStringLiteralAH(q, collcollate ? collcollate : "", fout);
   15336              :         }
   15337              :         else
   15338              :         {
   15339            0 :             appendPQExpBufferStr(q, ", lc_collate = ");
   15340            0 :             appendStringLiteralAH(q, collcollate ? collcollate : "", fout);
   15341            0 :             appendPQExpBufferStr(q, ", lc_ctype = ");
   15342            0 :             appendStringLiteralAH(q, collctype ? collctype : "", fout);
   15343              :         }
   15344              :     }
   15345              :     else
   15346            0 :         pg_fatal("unrecognized collation provider: %s", collprovider);
   15347              : 
   15348              :     /*
   15349              :      * For binary upgrade, carry over the collation version.  For normal
   15350              :      * dump/restore, omit the version, so that it is computed upon restore.
   15351              :      */
   15352         2717 :     if (dopt->binary_upgrade)
   15353              :     {
   15354              :         int         i_collversion;
   15355              : 
   15356            5 :         i_collversion = PQfnumber(res, "collversion");
   15357            5 :         if (!PQgetisnull(res, 0, i_collversion))
   15358              :         {
   15359            4 :             appendPQExpBufferStr(q, ", version = ");
   15360            4 :             appendStringLiteralAH(q,
   15361              :                                   PQgetvalue(res, 0, i_collversion),
   15362              :                                   fout);
   15363              :         }
   15364              :     }
   15365              : 
   15366         2717 :     appendPQExpBufferStr(q, ");\n");
   15367              : 
   15368         2717 :     if (dopt->binary_upgrade)
   15369            5 :         binary_upgrade_extension_member(q, &collinfo->dobj,
   15370              :                                         "COLLATION", qcollname,
   15371            5 :                                         collinfo->dobj.namespace->dobj.name);
   15372              : 
   15373         2717 :     if (collinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   15374         2717 :         ArchiveEntry(fout, collinfo->dobj.catId, collinfo->dobj.dumpId,
   15375         2717 :                      ARCHIVE_OPTS(.tag = collinfo->dobj.name,
   15376              :                                   .namespace = collinfo->dobj.namespace->dobj.name,
   15377              :                                   .owner = collinfo->rolname,
   15378              :                                   .description = "COLLATION",
   15379              :                                   .section = SECTION_PRE_DATA,
   15380              :                                   .createStmt = q->data,
   15381              :                                   .dropStmt = delq->data));
   15382              : 
   15383              :     /* Dump Collation Comments */
   15384         2717 :     if (collinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   15385         2611 :         dumpComment(fout, "COLLATION", qcollname,
   15386         2611 :                     collinfo->dobj.namespace->dobj.name, collinfo->rolname,
   15387         2611 :                     collinfo->dobj.catId, 0, collinfo->dobj.dumpId);
   15388              : 
   15389         2717 :     PQclear(res);
   15390              : 
   15391         2717 :     destroyPQExpBuffer(query);
   15392         2717 :     destroyPQExpBuffer(q);
   15393         2717 :     destroyPQExpBuffer(delq);
   15394         2717 :     free(qcollname);
   15395              : }
   15396              : 
   15397              : /*
   15398              :  * dumpConversion
   15399              :  *    write out a single conversion definition
   15400              :  */
   15401              : static void
   15402          422 : dumpConversion(Archive *fout, const ConvInfo *convinfo)
   15403              : {
   15404          422 :     DumpOptions *dopt = fout->dopt;
   15405              :     PQExpBuffer query;
   15406              :     PQExpBuffer q;
   15407              :     PQExpBuffer delq;
   15408              :     char       *qconvname;
   15409              :     PGresult   *res;
   15410              :     int         i_conforencoding;
   15411              :     int         i_contoencoding;
   15412              :     int         i_conproc;
   15413              :     int         i_condefault;
   15414              :     const char *conforencoding;
   15415              :     const char *contoencoding;
   15416              :     const char *conproc;
   15417              :     bool        condefault;
   15418              : 
   15419              :     /* Do nothing if not dumping schema */
   15420          422 :     if (!dopt->dumpSchema)
   15421            6 :         return;
   15422              : 
   15423          416 :     query = createPQExpBuffer();
   15424          416 :     q = createPQExpBuffer();
   15425          416 :     delq = createPQExpBuffer();
   15426              : 
   15427          416 :     qconvname = pg_strdup(fmtId(convinfo->dobj.name));
   15428              : 
   15429              :     /* Get conversion-specific details */
   15430          416 :     appendPQExpBuffer(query, "SELECT "
   15431              :                       "pg_catalog.pg_encoding_to_char(conforencoding) AS conforencoding, "
   15432              :                       "pg_catalog.pg_encoding_to_char(contoencoding) AS contoencoding, "
   15433              :                       "conproc, condefault "
   15434              :                       "FROM pg_catalog.pg_conversion c "
   15435              :                       "WHERE c.oid = '%u'::pg_catalog.oid",
   15436          416 :                       convinfo->dobj.catId.oid);
   15437              : 
   15438          416 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   15439              : 
   15440          416 :     i_conforencoding = PQfnumber(res, "conforencoding");
   15441          416 :     i_contoencoding = PQfnumber(res, "contoencoding");
   15442          416 :     i_conproc = PQfnumber(res, "conproc");
   15443          416 :     i_condefault = PQfnumber(res, "condefault");
   15444              : 
   15445          416 :     conforencoding = PQgetvalue(res, 0, i_conforencoding);
   15446          416 :     contoencoding = PQgetvalue(res, 0, i_contoencoding);
   15447          416 :     conproc = PQgetvalue(res, 0, i_conproc);
   15448          416 :     condefault = (PQgetvalue(res, 0, i_condefault)[0] == 't');
   15449              : 
   15450          416 :     appendPQExpBuffer(delq, "DROP CONVERSION %s;\n",
   15451          416 :                       fmtQualifiedDumpable(convinfo));
   15452              : 
   15453          416 :     appendPQExpBuffer(q, "CREATE %sCONVERSION %s FOR ",
   15454              :                       (condefault) ? "DEFAULT " : "",
   15455          416 :                       fmtQualifiedDumpable(convinfo));
   15456          416 :     appendStringLiteralAH(q, conforencoding, fout);
   15457          416 :     appendPQExpBufferStr(q, " TO ");
   15458          416 :     appendStringLiteralAH(q, contoencoding, fout);
   15459              :     /* regproc output is already sufficiently quoted */
   15460          416 :     appendPQExpBuffer(q, " FROM %s;\n", conproc);
   15461              : 
   15462          416 :     if (dopt->binary_upgrade)
   15463            1 :         binary_upgrade_extension_member(q, &convinfo->dobj,
   15464              :                                         "CONVERSION", qconvname,
   15465            1 :                                         convinfo->dobj.namespace->dobj.name);
   15466              : 
   15467          416 :     if (convinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   15468          416 :         ArchiveEntry(fout, convinfo->dobj.catId, convinfo->dobj.dumpId,
   15469          416 :                      ARCHIVE_OPTS(.tag = convinfo->dobj.name,
   15470              :                                   .namespace = convinfo->dobj.namespace->dobj.name,
   15471              :                                   .owner = convinfo->rolname,
   15472              :                                   .description = "CONVERSION",
   15473              :                                   .section = SECTION_PRE_DATA,
   15474              :                                   .createStmt = q->data,
   15475              :                                   .dropStmt = delq->data));
   15476              : 
   15477              :     /* Dump Conversion Comments */
   15478          416 :     if (convinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   15479          416 :         dumpComment(fout, "CONVERSION", qconvname,
   15480          416 :                     convinfo->dobj.namespace->dobj.name, convinfo->rolname,
   15481          416 :                     convinfo->dobj.catId, 0, convinfo->dobj.dumpId);
   15482              : 
   15483          416 :     PQclear(res);
   15484              : 
   15485          416 :     destroyPQExpBuffer(query);
   15486          416 :     destroyPQExpBuffer(q);
   15487          416 :     destroyPQExpBuffer(delq);
   15488          416 :     free(qconvname);
   15489              : }
   15490              : 
   15491              : /*
   15492              :  * format_aggregate_signature: generate aggregate name and argument list
   15493              :  *
   15494              :  * The argument type names are qualified if needed.  The aggregate name
   15495              :  * is never qualified.
   15496              :  */
   15497              : static char *
   15498          285 : format_aggregate_signature(const AggInfo *agginfo, Archive *fout, bool honor_quotes)
   15499              : {
   15500              :     PQExpBufferData buf;
   15501              :     int         j;
   15502              : 
   15503          285 :     initPQExpBuffer(&buf);
   15504          285 :     if (honor_quotes)
   15505            0 :         appendPQExpBufferStr(&buf, fmtId(agginfo->aggfn.dobj.name));
   15506              :     else
   15507          285 :         appendPQExpBufferStr(&buf, agginfo->aggfn.dobj.name);
   15508              : 
   15509          285 :     if (agginfo->aggfn.nargs == 0)
   15510           40 :         appendPQExpBufferStr(&buf, "(*)");
   15511              :     else
   15512              :     {
   15513          245 :         appendPQExpBufferChar(&buf, '(');
   15514          535 :         for (j = 0; j < agginfo->aggfn.nargs; j++)
   15515          290 :             appendPQExpBuffer(&buf, "%s%s",
   15516              :                               (j > 0) ? ", " : "",
   15517              :                               getFormattedTypeName(fout,
   15518          290 :                                                    agginfo->aggfn.argtypes[j],
   15519              :                                                    zeroIsError));
   15520          245 :         appendPQExpBufferChar(&buf, ')');
   15521              :     }
   15522          285 :     return buf.data;
   15523              : }
   15524              : 
   15525              : /*
   15526              :  * dumpAgg
   15527              :  *    write out a single aggregate definition
   15528              :  */
   15529              : static void
   15530          292 : dumpAgg(Archive *fout, const AggInfo *agginfo)
   15531              : {
   15532          292 :     DumpOptions *dopt = fout->dopt;
   15533              :     PQExpBuffer query;
   15534              :     PQExpBuffer q;
   15535              :     PQExpBuffer delq;
   15536              :     PQExpBuffer details;
   15537              :     char       *aggsig;         /* identity signature */
   15538          292 :     char       *aggfullsig = NULL;  /* full signature */
   15539              :     char       *aggsig_tag;
   15540              :     PGresult   *res;
   15541              :     int         i_agginitval;
   15542              :     int         i_aggminitval;
   15543              :     const char *aggtransfn;
   15544              :     const char *aggfinalfn;
   15545              :     const char *aggcombinefn;
   15546              :     const char *aggserialfn;
   15547              :     const char *aggdeserialfn;
   15548              :     const char *aggmtransfn;
   15549              :     const char *aggminvtransfn;
   15550              :     const char *aggmfinalfn;
   15551              :     bool        aggfinalextra;
   15552              :     bool        aggmfinalextra;
   15553              :     char        aggfinalmodify;
   15554              :     char        aggmfinalmodify;
   15555              :     const char *aggsortop;
   15556              :     char       *aggsortconvop;
   15557              :     char        aggkind;
   15558              :     const char *aggtranstype;
   15559              :     const char *aggtransspace;
   15560              :     const char *aggmtranstype;
   15561              :     const char *aggmtransspace;
   15562              :     const char *agginitval;
   15563              :     const char *aggminitval;
   15564              :     const char *proparallel;
   15565              :     char        defaultfinalmodify;
   15566              : 
   15567              :     /* Do nothing if not dumping schema */
   15568          292 :     if (!dopt->dumpSchema)
   15569            7 :         return;
   15570              : 
   15571          285 :     query = createPQExpBuffer();
   15572          285 :     q = createPQExpBuffer();
   15573          285 :     delq = createPQExpBuffer();
   15574          285 :     details = createPQExpBuffer();
   15575              : 
   15576          285 :     if (!fout->is_prepared[PREPQUERY_DUMPAGG])
   15577              :     {
   15578              :         /* Set up query for aggregate-specific details */
   15579           55 :         appendPQExpBufferStr(query,
   15580              :                              "PREPARE dumpAgg(pg_catalog.oid) AS\n");
   15581              : 
   15582           55 :         appendPQExpBufferStr(query,
   15583              :                              "SELECT "
   15584              :                              "aggtransfn,\n"
   15585              :                              "aggfinalfn,\n"
   15586              :                              "aggtranstype::pg_catalog.regtype,\n"
   15587              :                              "agginitval,\n"
   15588              :                              "aggsortop,\n"
   15589              :                              "pg_catalog.pg_get_function_arguments(p.oid) AS funcargs,\n"
   15590              :                              "pg_catalog.pg_get_function_identity_arguments(p.oid) AS funciargs,\n");
   15591              : 
   15592           55 :         if (fout->remoteVersion >= 90400)
   15593           55 :             appendPQExpBufferStr(query,
   15594              :                                  "aggkind,\n"
   15595              :                                  "aggmtransfn,\n"
   15596              :                                  "aggminvtransfn,\n"
   15597              :                                  "aggmfinalfn,\n"
   15598              :                                  "aggmtranstype::pg_catalog.regtype,\n"
   15599              :                                  "aggfinalextra,\n"
   15600              :                                  "aggmfinalextra,\n"
   15601              :                                  "aggtransspace,\n"
   15602              :                                  "aggmtransspace,\n"
   15603              :                                  "aggminitval,\n");
   15604              :         else
   15605            0 :             appendPQExpBufferStr(query,
   15606              :                                  "'n' AS aggkind,\n"
   15607              :                                  "'-' AS aggmtransfn,\n"
   15608              :                                  "'-' AS aggminvtransfn,\n"
   15609              :                                  "'-' AS aggmfinalfn,\n"
   15610              :                                  "0 AS aggmtranstype,\n"
   15611              :                                  "false AS aggfinalextra,\n"
   15612              :                                  "false AS aggmfinalextra,\n"
   15613              :                                  "0 AS aggtransspace,\n"
   15614              :                                  "0 AS aggmtransspace,\n"
   15615              :                                  "NULL AS aggminitval,\n");
   15616              : 
   15617           55 :         if (fout->remoteVersion >= 90600)
   15618           55 :             appendPQExpBufferStr(query,
   15619              :                                  "aggcombinefn,\n"
   15620              :                                  "aggserialfn,\n"
   15621              :                                  "aggdeserialfn,\n"
   15622              :                                  "proparallel,\n");
   15623              :         else
   15624            0 :             appendPQExpBufferStr(query,
   15625              :                                  "'-' AS aggcombinefn,\n"
   15626              :                                  "'-' AS aggserialfn,\n"
   15627              :                                  "'-' AS aggdeserialfn,\n"
   15628              :                                  "'u' AS proparallel,\n");
   15629              : 
   15630           55 :         if (fout->remoteVersion >= 110000)
   15631           55 :             appendPQExpBufferStr(query,
   15632              :                                  "aggfinalmodify,\n"
   15633              :                                  "aggmfinalmodify\n");
   15634              :         else
   15635            0 :             appendPQExpBufferStr(query,
   15636              :                                  "'0' AS aggfinalmodify,\n"
   15637              :                                  "'0' AS aggmfinalmodify\n");
   15638              : 
   15639           55 :         appendPQExpBufferStr(query,
   15640              :                              "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
   15641              :                              "WHERE a.aggfnoid = p.oid "
   15642              :                              "AND p.oid = $1");
   15643              : 
   15644           55 :         ExecuteSqlStatement(fout, query->data);
   15645              : 
   15646           55 :         fout->is_prepared[PREPQUERY_DUMPAGG] = true;
   15647              :     }
   15648              : 
   15649          285 :     printfPQExpBuffer(query,
   15650              :                       "EXECUTE dumpAgg('%u')",
   15651          285 :                       agginfo->aggfn.dobj.catId.oid);
   15652              : 
   15653          285 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   15654              : 
   15655          285 :     i_agginitval = PQfnumber(res, "agginitval");
   15656          285 :     i_aggminitval = PQfnumber(res, "aggminitval");
   15657              : 
   15658          285 :     aggtransfn = PQgetvalue(res, 0, PQfnumber(res, "aggtransfn"));
   15659          285 :     aggfinalfn = PQgetvalue(res, 0, PQfnumber(res, "aggfinalfn"));
   15660          285 :     aggcombinefn = PQgetvalue(res, 0, PQfnumber(res, "aggcombinefn"));
   15661          285 :     aggserialfn = PQgetvalue(res, 0, PQfnumber(res, "aggserialfn"));
   15662          285 :     aggdeserialfn = PQgetvalue(res, 0, PQfnumber(res, "aggdeserialfn"));
   15663          285 :     aggmtransfn = PQgetvalue(res, 0, PQfnumber(res, "aggmtransfn"));
   15664          285 :     aggminvtransfn = PQgetvalue(res, 0, PQfnumber(res, "aggminvtransfn"));
   15665          285 :     aggmfinalfn = PQgetvalue(res, 0, PQfnumber(res, "aggmfinalfn"));
   15666          285 :     aggfinalextra = (PQgetvalue(res, 0, PQfnumber(res, "aggfinalextra"))[0] == 't');
   15667          285 :     aggmfinalextra = (PQgetvalue(res, 0, PQfnumber(res, "aggmfinalextra"))[0] == 't');
   15668          285 :     aggfinalmodify = PQgetvalue(res, 0, PQfnumber(res, "aggfinalmodify"))[0];
   15669          285 :     aggmfinalmodify = PQgetvalue(res, 0, PQfnumber(res, "aggmfinalmodify"))[0];
   15670          285 :     aggsortop = PQgetvalue(res, 0, PQfnumber(res, "aggsortop"));
   15671          285 :     aggkind = PQgetvalue(res, 0, PQfnumber(res, "aggkind"))[0];
   15672          285 :     aggtranstype = PQgetvalue(res, 0, PQfnumber(res, "aggtranstype"));
   15673          285 :     aggtransspace = PQgetvalue(res, 0, PQfnumber(res, "aggtransspace"));
   15674          285 :     aggmtranstype = PQgetvalue(res, 0, PQfnumber(res, "aggmtranstype"));
   15675          285 :     aggmtransspace = PQgetvalue(res, 0, PQfnumber(res, "aggmtransspace"));
   15676          285 :     agginitval = PQgetvalue(res, 0, i_agginitval);
   15677          285 :     aggminitval = PQgetvalue(res, 0, i_aggminitval);
   15678          285 :     proparallel = PQgetvalue(res, 0, PQfnumber(res, "proparallel"));
   15679              : 
   15680              :     {
   15681              :         char       *funcargs;
   15682              :         char       *funciargs;
   15683              : 
   15684          285 :         funcargs = PQgetvalue(res, 0, PQfnumber(res, "funcargs"));
   15685          285 :         funciargs = PQgetvalue(res, 0, PQfnumber(res, "funciargs"));
   15686          285 :         aggfullsig = format_function_arguments(&agginfo->aggfn, funcargs, true);
   15687          285 :         aggsig = format_function_arguments(&agginfo->aggfn, funciargs, true);
   15688              :     }
   15689              : 
   15690          285 :     aggsig_tag = format_aggregate_signature(agginfo, fout, false);
   15691              : 
   15692              :     /* identify default modify flag for aggkind (must match DefineAggregate) */
   15693          285 :     defaultfinalmodify = (aggkind == AGGKIND_NORMAL) ? AGGMODIFY_READ_ONLY : AGGMODIFY_READ_WRITE;
   15694              :     /* replace omitted flags for old versions */
   15695          285 :     if (aggfinalmodify == '0')
   15696            0 :         aggfinalmodify = defaultfinalmodify;
   15697          285 :     if (aggmfinalmodify == '0')
   15698            0 :         aggmfinalmodify = defaultfinalmodify;
   15699              : 
   15700              :     /* regproc and regtype output is already sufficiently quoted */
   15701          285 :     appendPQExpBuffer(details, "    SFUNC = %s,\n    STYPE = %s",
   15702              :                       aggtransfn, aggtranstype);
   15703              : 
   15704          285 :     if (strcmp(aggtransspace, "0") != 0)
   15705              :     {
   15706            5 :         appendPQExpBuffer(details, ",\n    SSPACE = %s",
   15707              :                           aggtransspace);
   15708              :     }
   15709              : 
   15710          285 :     if (!PQgetisnull(res, 0, i_agginitval))
   15711              :     {
   15712          207 :         appendPQExpBufferStr(details, ",\n    INITCOND = ");
   15713          207 :         appendStringLiteralAH(details, agginitval, fout);
   15714              :     }
   15715              : 
   15716          285 :     if (strcmp(aggfinalfn, "-") != 0)
   15717              :     {
   15718          132 :         appendPQExpBuffer(details, ",\n    FINALFUNC = %s",
   15719              :                           aggfinalfn);
   15720          132 :         if (aggfinalextra)
   15721           10 :             appendPQExpBufferStr(details, ",\n    FINALFUNC_EXTRA");
   15722          132 :         if (aggfinalmodify != defaultfinalmodify)
   15723              :         {
   15724           32 :             switch (aggfinalmodify)
   15725              :             {
   15726            0 :                 case AGGMODIFY_READ_ONLY:
   15727            0 :                     appendPQExpBufferStr(details, ",\n    FINALFUNC_MODIFY = READ_ONLY");
   15728            0 :                     break;
   15729           32 :                 case AGGMODIFY_SHAREABLE:
   15730           32 :                     appendPQExpBufferStr(details, ",\n    FINALFUNC_MODIFY = SHAREABLE");
   15731           32 :                     break;
   15732            0 :                 case AGGMODIFY_READ_WRITE:
   15733            0 :                     appendPQExpBufferStr(details, ",\n    FINALFUNC_MODIFY = READ_WRITE");
   15734            0 :                     break;
   15735            0 :                 default:
   15736            0 :                     pg_fatal("unrecognized aggfinalmodify value for aggregate \"%s\"",
   15737              :                              agginfo->aggfn.dobj.name);
   15738              :                     break;
   15739              :             }
   15740              :         }
   15741              :     }
   15742              : 
   15743          285 :     if (strcmp(aggcombinefn, "-") != 0)
   15744            0 :         appendPQExpBuffer(details, ",\n    COMBINEFUNC = %s", aggcombinefn);
   15745              : 
   15746          285 :     if (strcmp(aggserialfn, "-") != 0)
   15747            0 :         appendPQExpBuffer(details, ",\n    SERIALFUNC = %s", aggserialfn);
   15748              : 
   15749          285 :     if (strcmp(aggdeserialfn, "-") != 0)
   15750            0 :         appendPQExpBuffer(details, ",\n    DESERIALFUNC = %s", aggdeserialfn);
   15751              : 
   15752          285 :     if (strcmp(aggmtransfn, "-") != 0)
   15753              :     {
   15754           30 :         appendPQExpBuffer(details, ",\n    MSFUNC = %s,\n    MINVFUNC = %s,\n    MSTYPE = %s",
   15755              :                           aggmtransfn,
   15756              :                           aggminvtransfn,
   15757              :                           aggmtranstype);
   15758              :     }
   15759              : 
   15760          285 :     if (strcmp(aggmtransspace, "0") != 0)
   15761              :     {
   15762            0 :         appendPQExpBuffer(details, ",\n    MSSPACE = %s",
   15763              :                           aggmtransspace);
   15764              :     }
   15765              : 
   15766          285 :     if (!PQgetisnull(res, 0, i_aggminitval))
   15767              :     {
   15768           10 :         appendPQExpBufferStr(details, ",\n    MINITCOND = ");
   15769           10 :         appendStringLiteralAH(details, aggminitval, fout);
   15770              :     }
   15771              : 
   15772          285 :     if (strcmp(aggmfinalfn, "-") != 0)
   15773              :     {
   15774            0 :         appendPQExpBuffer(details, ",\n    MFINALFUNC = %s",
   15775              :                           aggmfinalfn);
   15776            0 :         if (aggmfinalextra)
   15777            0 :             appendPQExpBufferStr(details, ",\n    MFINALFUNC_EXTRA");
   15778            0 :         if (aggmfinalmodify != defaultfinalmodify)
   15779              :         {
   15780            0 :             switch (aggmfinalmodify)
   15781              :             {
   15782            0 :                 case AGGMODIFY_READ_ONLY:
   15783            0 :                     appendPQExpBufferStr(details, ",\n    MFINALFUNC_MODIFY = READ_ONLY");
   15784            0 :                     break;
   15785            0 :                 case AGGMODIFY_SHAREABLE:
   15786            0 :                     appendPQExpBufferStr(details, ",\n    MFINALFUNC_MODIFY = SHAREABLE");
   15787            0 :                     break;
   15788            0 :                 case AGGMODIFY_READ_WRITE:
   15789            0 :                     appendPQExpBufferStr(details, ",\n    MFINALFUNC_MODIFY = READ_WRITE");
   15790            0 :                     break;
   15791            0 :                 default:
   15792            0 :                     pg_fatal("unrecognized aggmfinalmodify value for aggregate \"%s\"",
   15793              :                              agginfo->aggfn.dobj.name);
   15794              :                     break;
   15795              :             }
   15796              :         }
   15797              :     }
   15798              : 
   15799          285 :     aggsortconvop = getFormattedOperatorName(aggsortop);
   15800          285 :     if (aggsortconvop)
   15801              :     {
   15802            0 :         appendPQExpBuffer(details, ",\n    SORTOP = %s",
   15803              :                           aggsortconvop);
   15804            0 :         free(aggsortconvop);
   15805              :     }
   15806              : 
   15807          285 :     if (aggkind == AGGKIND_HYPOTHETICAL)
   15808            5 :         appendPQExpBufferStr(details, ",\n    HYPOTHETICAL");
   15809              : 
   15810          285 :     if (proparallel[0] != PROPARALLEL_UNSAFE)
   15811              :     {
   15812            5 :         if (proparallel[0] == PROPARALLEL_SAFE)
   15813            5 :             appendPQExpBufferStr(details, ",\n    PARALLEL = safe");
   15814            0 :         else if (proparallel[0] == PROPARALLEL_RESTRICTED)
   15815            0 :             appendPQExpBufferStr(details, ",\n    PARALLEL = restricted");
   15816            0 :         else if (proparallel[0] != PROPARALLEL_UNSAFE)
   15817            0 :             pg_fatal("unrecognized proparallel value for function \"%s\"",
   15818              :                      agginfo->aggfn.dobj.name);
   15819              :     }
   15820              : 
   15821          285 :     appendPQExpBuffer(delq, "DROP AGGREGATE %s.%s;\n",
   15822          285 :                       fmtId(agginfo->aggfn.dobj.namespace->dobj.name),
   15823              :                       aggsig);
   15824              : 
   15825          570 :     appendPQExpBuffer(q, "CREATE AGGREGATE %s.%s (\n%s\n);\n",
   15826          285 :                       fmtId(agginfo->aggfn.dobj.namespace->dobj.name),
   15827              :                       aggfullsig ? aggfullsig : aggsig, details->data);
   15828              : 
   15829          285 :     if (dopt->binary_upgrade)
   15830           49 :         binary_upgrade_extension_member(q, &agginfo->aggfn.dobj,
   15831              :                                         "AGGREGATE", aggsig,
   15832           49 :                                         agginfo->aggfn.dobj.namespace->dobj.name);
   15833              : 
   15834          285 :     if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_DEFINITION)
   15835          268 :         ArchiveEntry(fout, agginfo->aggfn.dobj.catId,
   15836          268 :                      agginfo->aggfn.dobj.dumpId,
   15837          268 :                      ARCHIVE_OPTS(.tag = aggsig_tag,
   15838              :                                   .namespace = agginfo->aggfn.dobj.namespace->dobj.name,
   15839              :                                   .owner = agginfo->aggfn.rolname,
   15840              :                                   .description = "AGGREGATE",
   15841              :                                   .section = SECTION_PRE_DATA,
   15842              :                                   .createStmt = q->data,
   15843              :                                   .dropStmt = delq->data));
   15844              : 
   15845              :     /* Dump Aggregate Comments */
   15846          285 :     if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_COMMENT)
   15847           10 :         dumpComment(fout, "AGGREGATE", aggsig,
   15848           10 :                     agginfo->aggfn.dobj.namespace->dobj.name,
   15849           10 :                     agginfo->aggfn.rolname,
   15850           10 :                     agginfo->aggfn.dobj.catId, 0, agginfo->aggfn.dobj.dumpId);
   15851              : 
   15852          285 :     if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_SECLABEL)
   15853            0 :         dumpSecLabel(fout, "AGGREGATE", aggsig,
   15854            0 :                      agginfo->aggfn.dobj.namespace->dobj.name,
   15855            0 :                      agginfo->aggfn.rolname,
   15856            0 :                      agginfo->aggfn.dobj.catId, 0, agginfo->aggfn.dobj.dumpId);
   15857              : 
   15858              :     /*
   15859              :      * Since there is no GRANT ON AGGREGATE syntax, we have to make the ACL
   15860              :      * command look like a function's GRANT; in particular this affects the
   15861              :      * syntax for zero-argument aggregates and ordered-set aggregates.
   15862              :      */
   15863          285 :     free(aggsig);
   15864              : 
   15865          285 :     aggsig = format_function_signature(fout, &agginfo->aggfn, true);
   15866              : 
   15867          285 :     if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_ACL)
   15868           18 :         dumpACL(fout, agginfo->aggfn.dobj.dumpId, InvalidDumpId,
   15869              :                 "FUNCTION", aggsig, NULL,
   15870           18 :                 agginfo->aggfn.dobj.namespace->dobj.name,
   15871           18 :                 NULL, agginfo->aggfn.rolname, &agginfo->aggfn.dacl);
   15872              : 
   15873          285 :     free(aggsig);
   15874          285 :     free(aggfullsig);
   15875          285 :     free(aggsig_tag);
   15876              : 
   15877          285 :     PQclear(res);
   15878              : 
   15879          285 :     destroyPQExpBuffer(query);
   15880          285 :     destroyPQExpBuffer(q);
   15881          285 :     destroyPQExpBuffer(delq);
   15882          285 :     destroyPQExpBuffer(details);
   15883              : }
   15884              : 
   15885              : /*
   15886              :  * dumpTSParser
   15887              :  *    write out a single text search parser
   15888              :  */
   15889              : static void
   15890           41 : dumpTSParser(Archive *fout, const TSParserInfo *prsinfo)
   15891              : {
   15892           41 :     DumpOptions *dopt = fout->dopt;
   15893              :     PQExpBuffer q;
   15894              :     PQExpBuffer delq;
   15895              :     char       *qprsname;
   15896              : 
   15897              :     /* Do nothing if not dumping schema */
   15898           41 :     if (!dopt->dumpSchema)
   15899            6 :         return;
   15900              : 
   15901           35 :     q = createPQExpBuffer();
   15902           35 :     delq = createPQExpBuffer();
   15903              : 
   15904           35 :     qprsname = pg_strdup(fmtId(prsinfo->dobj.name));
   15905              : 
   15906           35 :     appendPQExpBuffer(q, "CREATE TEXT SEARCH PARSER %s (\n",
   15907           35 :                       fmtQualifiedDumpable(prsinfo));
   15908              : 
   15909           35 :     appendPQExpBuffer(q, "    START = %s,\n",
   15910           35 :                       convertTSFunction(fout, prsinfo->prsstart));
   15911           35 :     appendPQExpBuffer(q, "    GETTOKEN = %s,\n",
   15912           35 :                       convertTSFunction(fout, prsinfo->prstoken));
   15913           35 :     appendPQExpBuffer(q, "    END = %s,\n",
   15914           35 :                       convertTSFunction(fout, prsinfo->prsend));
   15915           35 :     if (prsinfo->prsheadline != InvalidOid)
   15916            3 :         appendPQExpBuffer(q, "    HEADLINE = %s,\n",
   15917            3 :                           convertTSFunction(fout, prsinfo->prsheadline));
   15918           35 :     appendPQExpBuffer(q, "    LEXTYPES = %s );\n",
   15919           35 :                       convertTSFunction(fout, prsinfo->prslextype));
   15920              : 
   15921           35 :     appendPQExpBuffer(delq, "DROP TEXT SEARCH PARSER %s;\n",
   15922           35 :                       fmtQualifiedDumpable(prsinfo));
   15923              : 
   15924           35 :     if (dopt->binary_upgrade)
   15925            1 :         binary_upgrade_extension_member(q, &prsinfo->dobj,
   15926              :                                         "TEXT SEARCH PARSER", qprsname,
   15927            1 :                                         prsinfo->dobj.namespace->dobj.name);
   15928              : 
   15929           35 :     if (prsinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   15930           35 :         ArchiveEntry(fout, prsinfo->dobj.catId, prsinfo->dobj.dumpId,
   15931           35 :                      ARCHIVE_OPTS(.tag = prsinfo->dobj.name,
   15932              :                                   .namespace = prsinfo->dobj.namespace->dobj.name,
   15933              :                                   .description = "TEXT SEARCH PARSER",
   15934              :                                   .section = SECTION_PRE_DATA,
   15935              :                                   .createStmt = q->data,
   15936              :                                   .dropStmt = delq->data));
   15937              : 
   15938              :     /* Dump Parser Comments */
   15939           35 :     if (prsinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   15940           35 :         dumpComment(fout, "TEXT SEARCH PARSER", qprsname,
   15941           35 :                     prsinfo->dobj.namespace->dobj.name, "",
   15942           35 :                     prsinfo->dobj.catId, 0, prsinfo->dobj.dumpId);
   15943              : 
   15944           35 :     destroyPQExpBuffer(q);
   15945           35 :     destroyPQExpBuffer(delq);
   15946           35 :     free(qprsname);
   15947              : }
   15948              : 
   15949              : /*
   15950              :  * dumpTSDictionary
   15951              :  *    write out a single text search dictionary
   15952              :  */
   15953              : static void
   15954          179 : dumpTSDictionary(Archive *fout, const TSDictInfo *dictinfo)
   15955              : {
   15956          179 :     DumpOptions *dopt = fout->dopt;
   15957              :     PQExpBuffer q;
   15958              :     PQExpBuffer delq;
   15959              :     PQExpBuffer query;
   15960              :     char       *qdictname;
   15961              :     PGresult   *res;
   15962              :     char       *nspname;
   15963              :     char       *tmplname;
   15964              : 
   15965              :     /* Do nothing if not dumping schema */
   15966          179 :     if (!dopt->dumpSchema)
   15967            6 :         return;
   15968              : 
   15969          173 :     q = createPQExpBuffer();
   15970          173 :     delq = createPQExpBuffer();
   15971          173 :     query = createPQExpBuffer();
   15972              : 
   15973          173 :     qdictname = pg_strdup(fmtId(dictinfo->dobj.name));
   15974              : 
   15975              :     /* Fetch name and namespace of the dictionary's template */
   15976          173 :     appendPQExpBuffer(query, "SELECT nspname, tmplname "
   15977              :                       "FROM pg_ts_template p, pg_namespace n "
   15978              :                       "WHERE p.oid = '%u' AND n.oid = tmplnamespace",
   15979          173 :                       dictinfo->dicttemplate);
   15980          173 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   15981          173 :     nspname = PQgetvalue(res, 0, 0);
   15982          173 :     tmplname = PQgetvalue(res, 0, 1);
   15983              : 
   15984          173 :     appendPQExpBuffer(q, "CREATE TEXT SEARCH DICTIONARY %s (\n",
   15985          173 :                       fmtQualifiedDumpable(dictinfo));
   15986              : 
   15987          173 :     appendPQExpBufferStr(q, "    TEMPLATE = ");
   15988          173 :     appendPQExpBuffer(q, "%s.", fmtId(nspname));
   15989          173 :     appendPQExpBufferStr(q, fmtId(tmplname));
   15990              : 
   15991          173 :     PQclear(res);
   15992              : 
   15993              :     /* the dictinitoption can be dumped straight into the command */
   15994          173 :     if (dictinfo->dictinitoption)
   15995          138 :         appendPQExpBuffer(q, ",\n    %s", dictinfo->dictinitoption);
   15996              : 
   15997          173 :     appendPQExpBufferStr(q, " );\n");
   15998              : 
   15999          173 :     appendPQExpBuffer(delq, "DROP TEXT SEARCH DICTIONARY %s;\n",
   16000          173 :                       fmtQualifiedDumpable(dictinfo));
   16001              : 
   16002          173 :     if (dopt->binary_upgrade)
   16003           10 :         binary_upgrade_extension_member(q, &dictinfo->dobj,
   16004              :                                         "TEXT SEARCH DICTIONARY", qdictname,
   16005           10 :                                         dictinfo->dobj.namespace->dobj.name);
   16006              : 
   16007          173 :     if (dictinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   16008          173 :         ArchiveEntry(fout, dictinfo->dobj.catId, dictinfo->dobj.dumpId,
   16009          173 :                      ARCHIVE_OPTS(.tag = dictinfo->dobj.name,
   16010              :                                   .namespace = dictinfo->dobj.namespace->dobj.name,
   16011              :                                   .owner = dictinfo->rolname,
   16012              :                                   .description = "TEXT SEARCH DICTIONARY",
   16013              :                                   .section = SECTION_PRE_DATA,
   16014              :                                   .createStmt = q->data,
   16015              :                                   .dropStmt = delq->data));
   16016              : 
   16017              :     /* Dump Dictionary Comments */
   16018          173 :     if (dictinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   16019          128 :         dumpComment(fout, "TEXT SEARCH DICTIONARY", qdictname,
   16020          128 :                     dictinfo->dobj.namespace->dobj.name, dictinfo->rolname,
   16021          128 :                     dictinfo->dobj.catId, 0, dictinfo->dobj.dumpId);
   16022              : 
   16023          173 :     destroyPQExpBuffer(q);
   16024          173 :     destroyPQExpBuffer(delq);
   16025          173 :     destroyPQExpBuffer(query);
   16026          173 :     free(qdictname);
   16027              : }
   16028              : 
   16029              : /*
   16030              :  * dumpTSTemplate
   16031              :  *    write out a single text search template
   16032              :  */
   16033              : static void
   16034           53 : dumpTSTemplate(Archive *fout, const TSTemplateInfo *tmplinfo)
   16035              : {
   16036           53 :     DumpOptions *dopt = fout->dopt;
   16037              :     PQExpBuffer q;
   16038              :     PQExpBuffer delq;
   16039              :     char       *qtmplname;
   16040              : 
   16041              :     /* Do nothing if not dumping schema */
   16042           53 :     if (!dopt->dumpSchema)
   16043            6 :         return;
   16044              : 
   16045           47 :     q = createPQExpBuffer();
   16046           47 :     delq = createPQExpBuffer();
   16047              : 
   16048           47 :     qtmplname = pg_strdup(fmtId(tmplinfo->dobj.name));
   16049              : 
   16050           47 :     appendPQExpBuffer(q, "CREATE TEXT SEARCH TEMPLATE %s (\n",
   16051           47 :                       fmtQualifiedDumpable(tmplinfo));
   16052              : 
   16053           47 :     if (tmplinfo->tmplinit != InvalidOid)
   16054           15 :         appendPQExpBuffer(q, "    INIT = %s,\n",
   16055           15 :                           convertTSFunction(fout, tmplinfo->tmplinit));
   16056           47 :     appendPQExpBuffer(q, "    LEXIZE = %s );\n",
   16057           47 :                       convertTSFunction(fout, tmplinfo->tmpllexize));
   16058              : 
   16059           47 :     appendPQExpBuffer(delq, "DROP TEXT SEARCH TEMPLATE %s;\n",
   16060           47 :                       fmtQualifiedDumpable(tmplinfo));
   16061              : 
   16062           47 :     if (dopt->binary_upgrade)
   16063            1 :         binary_upgrade_extension_member(q, &tmplinfo->dobj,
   16064              :                                         "TEXT SEARCH TEMPLATE", qtmplname,
   16065            1 :                                         tmplinfo->dobj.namespace->dobj.name);
   16066              : 
   16067           47 :     if (tmplinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   16068           47 :         ArchiveEntry(fout, tmplinfo->dobj.catId, tmplinfo->dobj.dumpId,
   16069           47 :                      ARCHIVE_OPTS(.tag = tmplinfo->dobj.name,
   16070              :                                   .namespace = tmplinfo->dobj.namespace->dobj.name,
   16071              :                                   .description = "TEXT SEARCH TEMPLATE",
   16072              :                                   .section = SECTION_PRE_DATA,
   16073              :                                   .createStmt = q->data,
   16074              :                                   .dropStmt = delq->data));
   16075              : 
   16076              :     /* Dump Template Comments */
   16077           47 :     if (tmplinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   16078           47 :         dumpComment(fout, "TEXT SEARCH TEMPLATE", qtmplname,
   16079           47 :                     tmplinfo->dobj.namespace->dobj.name, "",
   16080           47 :                     tmplinfo->dobj.catId, 0, tmplinfo->dobj.dumpId);
   16081              : 
   16082           47 :     destroyPQExpBuffer(q);
   16083           47 :     destroyPQExpBuffer(delq);
   16084           47 :     free(qtmplname);
   16085              : }
   16086              : 
   16087              : /*
   16088              :  * dumpTSConfig
   16089              :  *    write out a single text search configuration
   16090              :  */
   16091              : static void
   16092          154 : dumpTSConfig(Archive *fout, const TSConfigInfo *cfginfo)
   16093              : {
   16094          154 :     DumpOptions *dopt = fout->dopt;
   16095              :     PQExpBuffer q;
   16096              :     PQExpBuffer delq;
   16097              :     PQExpBuffer query;
   16098              :     char       *qcfgname;
   16099              :     PGresult   *res;
   16100              :     char       *nspname;
   16101              :     char       *prsname;
   16102              :     int         ntups,
   16103              :                 i;
   16104              :     int         i_tokenname;
   16105              :     int         i_dictname;
   16106              : 
   16107              :     /* Do nothing if not dumping schema */
   16108          154 :     if (!dopt->dumpSchema)
   16109            6 :         return;
   16110              : 
   16111          148 :     q = createPQExpBuffer();
   16112          148 :     delq = createPQExpBuffer();
   16113          148 :     query = createPQExpBuffer();
   16114              : 
   16115          148 :     qcfgname = pg_strdup(fmtId(cfginfo->dobj.name));
   16116              : 
   16117              :     /* Fetch name and namespace of the config's parser */
   16118          148 :     appendPQExpBuffer(query, "SELECT nspname, prsname "
   16119              :                       "FROM pg_ts_parser p, pg_namespace n "
   16120              :                       "WHERE p.oid = '%u' AND n.oid = prsnamespace",
   16121          148 :                       cfginfo->cfgparser);
   16122          148 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   16123          148 :     nspname = PQgetvalue(res, 0, 0);
   16124          148 :     prsname = PQgetvalue(res, 0, 1);
   16125              : 
   16126          148 :     appendPQExpBuffer(q, "CREATE TEXT SEARCH CONFIGURATION %s (\n",
   16127          148 :                       fmtQualifiedDumpable(cfginfo));
   16128              : 
   16129          148 :     appendPQExpBuffer(q, "    PARSER = %s.", fmtId(nspname));
   16130          148 :     appendPQExpBuffer(q, "%s );\n", fmtId(prsname));
   16131              : 
   16132          148 :     PQclear(res);
   16133              : 
   16134          148 :     resetPQExpBuffer(query);
   16135          148 :     appendPQExpBuffer(query,
   16136              :                       "SELECT\n"
   16137              :                       "  ( SELECT alias FROM pg_catalog.ts_token_type('%u'::pg_catalog.oid) AS t\n"
   16138              :                       "    WHERE t.tokid = m.maptokentype ) AS tokenname,\n"
   16139              :                       "  m.mapdict::pg_catalog.regdictionary AS dictname\n"
   16140              :                       "FROM pg_catalog.pg_ts_config_map AS m\n"
   16141              :                       "WHERE m.mapcfg = '%u'\n"
   16142              :                       "ORDER BY m.mapcfg, m.maptokentype, m.mapseqno",
   16143          148 :                       cfginfo->cfgparser, cfginfo->dobj.catId.oid);
   16144              : 
   16145          148 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   16146          148 :     ntups = PQntuples(res);
   16147              : 
   16148          148 :     i_tokenname = PQfnumber(res, "tokenname");
   16149          148 :     i_dictname = PQfnumber(res, "dictname");
   16150              : 
   16151         3095 :     for (i = 0; i < ntups; i++)
   16152              :     {
   16153         2947 :         char       *tokenname = PQgetvalue(res, i, i_tokenname);
   16154         2947 :         char       *dictname = PQgetvalue(res, i, i_dictname);
   16155              : 
   16156         2947 :         if (i == 0 ||
   16157         2799 :             strcmp(tokenname, PQgetvalue(res, i - 1, i_tokenname)) != 0)
   16158              :         {
   16159              :             /* starting a new token type, so start a new command */
   16160         2812 :             if (i > 0)
   16161         2664 :                 appendPQExpBufferStr(q, ";\n");
   16162         2812 :             appendPQExpBuffer(q, "\nALTER TEXT SEARCH CONFIGURATION %s\n",
   16163         2812 :                               fmtQualifiedDumpable(cfginfo));
   16164              :             /* tokenname needs quoting, dictname does NOT */
   16165         2812 :             appendPQExpBuffer(q, "    ADD MAPPING FOR %s WITH %s",
   16166              :                               fmtId(tokenname), dictname);
   16167              :         }
   16168              :         else
   16169          135 :             appendPQExpBuffer(q, ", %s", dictname);
   16170              :     }
   16171              : 
   16172          148 :     if (ntups > 0)
   16173          148 :         appendPQExpBufferStr(q, ";\n");
   16174              : 
   16175          148 :     PQclear(res);
   16176              : 
   16177          148 :     appendPQExpBuffer(delq, "DROP TEXT SEARCH CONFIGURATION %s;\n",
   16178          148 :                       fmtQualifiedDumpable(cfginfo));
   16179              : 
   16180          148 :     if (dopt->binary_upgrade)
   16181            5 :         binary_upgrade_extension_member(q, &cfginfo->dobj,
   16182              :                                         "TEXT SEARCH CONFIGURATION", qcfgname,
   16183            5 :                                         cfginfo->dobj.namespace->dobj.name);
   16184              : 
   16185          148 :     if (cfginfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   16186          148 :         ArchiveEntry(fout, cfginfo->dobj.catId, cfginfo->dobj.dumpId,
   16187          148 :                      ARCHIVE_OPTS(.tag = cfginfo->dobj.name,
   16188              :                                   .namespace = cfginfo->dobj.namespace->dobj.name,
   16189              :                                   .owner = cfginfo->rolname,
   16190              :                                   .description = "TEXT SEARCH CONFIGURATION",
   16191              :                                   .section = SECTION_PRE_DATA,
   16192              :                                   .createStmt = q->data,
   16193              :                                   .dropStmt = delq->data));
   16194              : 
   16195              :     /* Dump Configuration Comments */
   16196          148 :     if (cfginfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   16197          128 :         dumpComment(fout, "TEXT SEARCH CONFIGURATION", qcfgname,
   16198          128 :                     cfginfo->dobj.namespace->dobj.name, cfginfo->rolname,
   16199          128 :                     cfginfo->dobj.catId, 0, cfginfo->dobj.dumpId);
   16200              : 
   16201          148 :     destroyPQExpBuffer(q);
   16202          148 :     destroyPQExpBuffer(delq);
   16203          148 :     destroyPQExpBuffer(query);
   16204          148 :     free(qcfgname);
   16205              : }
   16206              : 
   16207              : /*
   16208              :  * dumpForeignDataWrapper
   16209              :  *    write out a single foreign-data wrapper definition
   16210              :  */
   16211              : static void
   16212           52 : dumpForeignDataWrapper(Archive *fout, const FdwInfo *fdwinfo)
   16213              : {
   16214           52 :     DumpOptions *dopt = fout->dopt;
   16215              :     PQExpBuffer q;
   16216              :     PQExpBuffer delq;
   16217              :     char       *qfdwname;
   16218              : 
   16219              :     /* Do nothing if not dumping schema */
   16220           52 :     if (!dopt->dumpSchema)
   16221            7 :         return;
   16222              : 
   16223           45 :     q = createPQExpBuffer();
   16224           45 :     delq = createPQExpBuffer();
   16225              : 
   16226           45 :     qfdwname = pg_strdup(fmtId(fdwinfo->dobj.name));
   16227              : 
   16228           45 :     appendPQExpBuffer(q, "CREATE FOREIGN DATA WRAPPER %s",
   16229              :                       qfdwname);
   16230              : 
   16231           45 :     if (strcmp(fdwinfo->fdwhandler, "-") != 0)
   16232            0 :         appendPQExpBuffer(q, " HANDLER %s", fdwinfo->fdwhandler);
   16233              : 
   16234           45 :     if (strcmp(fdwinfo->fdwvalidator, "-") != 0)
   16235            0 :         appendPQExpBuffer(q, " VALIDATOR %s", fdwinfo->fdwvalidator);
   16236              : 
   16237           45 :     if (strcmp(fdwinfo->fdwconnection, "-") != 0)
   16238            0 :         appendPQExpBuffer(q, " CONNECTION %s", fdwinfo->fdwconnection);
   16239              : 
   16240           45 :     if (strlen(fdwinfo->fdwoptions) > 0)
   16241            0 :         appendPQExpBuffer(q, " OPTIONS (\n    %s\n)", fdwinfo->fdwoptions);
   16242              : 
   16243           45 :     appendPQExpBufferStr(q, ";\n");
   16244              : 
   16245           45 :     appendPQExpBuffer(delq, "DROP FOREIGN DATA WRAPPER %s;\n",
   16246              :                       qfdwname);
   16247              : 
   16248           45 :     if (dopt->binary_upgrade)
   16249            2 :         binary_upgrade_extension_member(q, &fdwinfo->dobj,
   16250              :                                         "FOREIGN DATA WRAPPER", qfdwname,
   16251              :                                         NULL);
   16252              : 
   16253           45 :     if (fdwinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   16254           45 :         ArchiveEntry(fout, fdwinfo->dobj.catId, fdwinfo->dobj.dumpId,
   16255           45 :                      ARCHIVE_OPTS(.tag = fdwinfo->dobj.name,
   16256              :                                   .owner = fdwinfo->rolname,
   16257              :                                   .description = "FOREIGN DATA WRAPPER",
   16258              :                                   .section = SECTION_PRE_DATA,
   16259              :                                   .createStmt = q->data,
   16260              :                                   .dropStmt = delq->data));
   16261              : 
   16262              :     /* Dump Foreign Data Wrapper Comments */
   16263           45 :     if (fdwinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   16264            0 :         dumpComment(fout, "FOREIGN DATA WRAPPER", qfdwname,
   16265            0 :                     NULL, fdwinfo->rolname,
   16266            0 :                     fdwinfo->dobj.catId, 0, fdwinfo->dobj.dumpId);
   16267              : 
   16268              :     /* Handle the ACL */
   16269           45 :     if (fdwinfo->dobj.dump & DUMP_COMPONENT_ACL)
   16270           31 :         dumpACL(fout, fdwinfo->dobj.dumpId, InvalidDumpId,
   16271              :                 "FOREIGN DATA WRAPPER", qfdwname, NULL, NULL,
   16272           31 :                 NULL, fdwinfo->rolname, &fdwinfo->dacl);
   16273              : 
   16274           45 :     free(qfdwname);
   16275              : 
   16276           45 :     destroyPQExpBuffer(q);
   16277           45 :     destroyPQExpBuffer(delq);
   16278              : }
   16279              : 
   16280              : /*
   16281              :  * dumpForeignServer
   16282              :  *    write out a foreign server definition
   16283              :  */
   16284              : static void
   16285           56 : dumpForeignServer(Archive *fout, const ForeignServerInfo *srvinfo)
   16286              : {
   16287           56 :     DumpOptions *dopt = fout->dopt;
   16288              :     PQExpBuffer q;
   16289              :     PQExpBuffer delq;
   16290              :     PQExpBuffer query;
   16291              :     PGresult   *res;
   16292              :     char       *qsrvname;
   16293              :     char       *fdwname;
   16294              : 
   16295              :     /* Do nothing if not dumping schema */
   16296           56 :     if (!dopt->dumpSchema)
   16297            9 :         return;
   16298              : 
   16299           47 :     q = createPQExpBuffer();
   16300           47 :     delq = createPQExpBuffer();
   16301           47 :     query = createPQExpBuffer();
   16302              : 
   16303           47 :     qsrvname = pg_strdup(fmtId(srvinfo->dobj.name));
   16304              : 
   16305              :     /* look up the foreign-data wrapper */
   16306           47 :     appendPQExpBuffer(query, "SELECT fdwname "
   16307              :                       "FROM pg_foreign_data_wrapper w "
   16308              :                       "WHERE w.oid = '%u'",
   16309           47 :                       srvinfo->srvfdw);
   16310           47 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   16311           47 :     fdwname = PQgetvalue(res, 0, 0);
   16312              : 
   16313           47 :     appendPQExpBuffer(q, "CREATE SERVER %s", qsrvname);
   16314           47 :     if (srvinfo->srvtype && strlen(srvinfo->srvtype) > 0)
   16315              :     {
   16316            0 :         appendPQExpBufferStr(q, " TYPE ");
   16317            0 :         appendStringLiteralAH(q, srvinfo->srvtype, fout);
   16318              :     }
   16319           47 :     if (srvinfo->srvversion && strlen(srvinfo->srvversion) > 0)
   16320              :     {
   16321            0 :         appendPQExpBufferStr(q, " VERSION ");
   16322            0 :         appendStringLiteralAH(q, srvinfo->srvversion, fout);
   16323              :     }
   16324              : 
   16325           47 :     appendPQExpBufferStr(q, " FOREIGN DATA WRAPPER ");
   16326           47 :     appendPQExpBufferStr(q, fmtId(fdwname));
   16327              : 
   16328           47 :     if (srvinfo->srvoptions && strlen(srvinfo->srvoptions) > 0)
   16329            0 :         appendPQExpBuffer(q, " OPTIONS (\n    %s\n)", srvinfo->srvoptions);
   16330              : 
   16331           47 :     appendPQExpBufferStr(q, ";\n");
   16332              : 
   16333           47 :     appendPQExpBuffer(delq, "DROP SERVER %s;\n",
   16334              :                       qsrvname);
   16335              : 
   16336           47 :     if (dopt->binary_upgrade)
   16337            2 :         binary_upgrade_extension_member(q, &srvinfo->dobj,
   16338              :                                         "SERVER", qsrvname, NULL);
   16339              : 
   16340           47 :     if (srvinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   16341           47 :         ArchiveEntry(fout, srvinfo->dobj.catId, srvinfo->dobj.dumpId,
   16342           47 :                      ARCHIVE_OPTS(.tag = srvinfo->dobj.name,
   16343              :                                   .owner = srvinfo->rolname,
   16344              :                                   .description = "SERVER",
   16345              :                                   .section = SECTION_PRE_DATA,
   16346              :                                   .createStmt = q->data,
   16347              :                                   .dropStmt = delq->data));
   16348              : 
   16349              :     /* Dump Foreign Server Comments */
   16350           47 :     if (srvinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   16351            0 :         dumpComment(fout, "SERVER", qsrvname,
   16352            0 :                     NULL, srvinfo->rolname,
   16353            0 :                     srvinfo->dobj.catId, 0, srvinfo->dobj.dumpId);
   16354              : 
   16355              :     /* Handle the ACL */
   16356           47 :     if (srvinfo->dobj.dump & DUMP_COMPONENT_ACL)
   16357           31 :         dumpACL(fout, srvinfo->dobj.dumpId, InvalidDumpId,
   16358              :                 "FOREIGN SERVER", qsrvname, NULL, NULL,
   16359           31 :                 NULL, srvinfo->rolname, &srvinfo->dacl);
   16360              : 
   16361              :     /* Dump user mappings */
   16362           47 :     if (srvinfo->dobj.dump & DUMP_COMPONENT_USERMAP)
   16363           47 :         dumpUserMappings(fout,
   16364           47 :                          srvinfo->dobj.name, NULL,
   16365           47 :                          srvinfo->rolname,
   16366           47 :                          srvinfo->dobj.catId, srvinfo->dobj.dumpId);
   16367              : 
   16368           47 :     PQclear(res);
   16369              : 
   16370           47 :     free(qsrvname);
   16371              : 
   16372           47 :     destroyPQExpBuffer(q);
   16373           47 :     destroyPQExpBuffer(delq);
   16374           47 :     destroyPQExpBuffer(query);
   16375              : }
   16376              : 
   16377              : /*
   16378              :  * dumpUserMappings
   16379              :  *
   16380              :  * This routine is used to dump any user mappings associated with the
   16381              :  * server handed to this routine. Should be called after ArchiveEntry()
   16382              :  * for the server.
   16383              :  */
   16384              : static void
   16385           47 : dumpUserMappings(Archive *fout,
   16386              :                  const char *servername, const char *namespace,
   16387              :                  const char *owner,
   16388              :                  CatalogId catalogId, DumpId dumpId)
   16389              : {
   16390              :     PQExpBuffer q;
   16391              :     PQExpBuffer delq;
   16392              :     PQExpBuffer query;
   16393              :     PQExpBuffer tag;
   16394              :     PGresult   *res;
   16395              :     int         ntups;
   16396              :     int         i_usename;
   16397              :     int         i_umoptions;
   16398              :     int         i;
   16399              : 
   16400           47 :     q = createPQExpBuffer();
   16401           47 :     tag = createPQExpBuffer();
   16402           47 :     delq = createPQExpBuffer();
   16403           47 :     query = createPQExpBuffer();
   16404              : 
   16405              :     /*
   16406              :      * We read from the publicly accessible view pg_user_mappings, so as not
   16407              :      * to fail if run by a non-superuser.  Note that the view will show
   16408              :      * umoptions as null if the user hasn't got privileges for the associated
   16409              :      * server; this means that pg_dump will dump such a mapping, but with no
   16410              :      * OPTIONS clause.  A possible alternative is to skip such mappings
   16411              :      * altogether, but it's not clear that that's an improvement.
   16412              :      */
   16413           47 :     appendPQExpBuffer(query,
   16414              :                       "SELECT usename, "
   16415              :                       "array_to_string(ARRAY("
   16416              :                       "SELECT quote_ident(option_name) || ' ' || "
   16417              :                       "quote_literal(option_value) "
   16418              :                       "FROM pg_options_to_table(umoptions) "
   16419              :                       "ORDER BY option_name"
   16420              :                       "), E',\n    ') AS umoptions "
   16421              :                       "FROM pg_user_mappings "
   16422              :                       "WHERE srvid = '%u' "
   16423              :                       "ORDER BY usename",
   16424              :                       catalogId.oid);
   16425              : 
   16426           47 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   16427              : 
   16428           47 :     ntups = PQntuples(res);
   16429           47 :     i_usename = PQfnumber(res, "usename");
   16430           47 :     i_umoptions = PQfnumber(res, "umoptions");
   16431              : 
   16432           78 :     for (i = 0; i < ntups; i++)
   16433              :     {
   16434              :         char       *usename;
   16435              :         char       *umoptions;
   16436              : 
   16437           31 :         usename = PQgetvalue(res, i, i_usename);
   16438           31 :         umoptions = PQgetvalue(res, i, i_umoptions);
   16439              : 
   16440           31 :         resetPQExpBuffer(q);
   16441           31 :         appendPQExpBuffer(q, "CREATE USER MAPPING FOR %s", fmtId(usename));
   16442           31 :         appendPQExpBuffer(q, " SERVER %s", fmtId(servername));
   16443              : 
   16444           31 :         if (umoptions && strlen(umoptions) > 0)
   16445            0 :             appendPQExpBuffer(q, " OPTIONS (\n    %s\n)", umoptions);
   16446              : 
   16447           31 :         appendPQExpBufferStr(q, ";\n");
   16448              : 
   16449           31 :         resetPQExpBuffer(delq);
   16450           31 :         appendPQExpBuffer(delq, "DROP USER MAPPING FOR %s", fmtId(usename));
   16451           31 :         appendPQExpBuffer(delq, " SERVER %s;\n", fmtId(servername));
   16452              : 
   16453           31 :         resetPQExpBuffer(tag);
   16454           31 :         appendPQExpBuffer(tag, "USER MAPPING %s SERVER %s",
   16455              :                           usename, servername);
   16456              : 
   16457           31 :         ArchiveEntry(fout, nilCatalogId, createDumpId(),
   16458           31 :                      ARCHIVE_OPTS(.tag = tag->data,
   16459              :                                   .namespace = namespace,
   16460              :                                   .owner = owner,
   16461              :                                   .description = "USER MAPPING",
   16462              :                                   .section = SECTION_PRE_DATA,
   16463              :                                   .createStmt = q->data,
   16464              :                                   .dropStmt = delq->data));
   16465              :     }
   16466              : 
   16467           47 :     PQclear(res);
   16468              : 
   16469           47 :     destroyPQExpBuffer(query);
   16470           47 :     destroyPQExpBuffer(delq);
   16471           47 :     destroyPQExpBuffer(tag);
   16472           47 :     destroyPQExpBuffer(q);
   16473           47 : }
   16474              : 
   16475              : /*
   16476              :  * Write out default privileges information
   16477              :  */
   16478              : static void
   16479          160 : dumpDefaultACL(Archive *fout, const DefaultACLInfo *daclinfo)
   16480              : {
   16481          160 :     DumpOptions *dopt = fout->dopt;
   16482              :     PQExpBuffer q;
   16483              :     PQExpBuffer tag;
   16484              :     const char *type;
   16485              : 
   16486              :     /* Do nothing if not dumping schema, or if we're skipping ACLs */
   16487          160 :     if (!dopt->dumpSchema || dopt->aclsSkip)
   16488           28 :         return;
   16489              : 
   16490          132 :     q = createPQExpBuffer();
   16491          132 :     tag = createPQExpBuffer();
   16492              : 
   16493          132 :     switch (daclinfo->defaclobjtype)
   16494              :     {
   16495           61 :         case DEFACLOBJ_RELATION:
   16496           61 :             type = "TABLES";
   16497           61 :             break;
   16498            0 :         case DEFACLOBJ_SEQUENCE:
   16499            0 :             type = "SEQUENCES";
   16500            0 :             break;
   16501           61 :         case DEFACLOBJ_FUNCTION:
   16502           61 :             type = "FUNCTIONS";
   16503           61 :             break;
   16504           10 :         case DEFACLOBJ_TYPE:
   16505           10 :             type = "TYPES";
   16506           10 :             break;
   16507            0 :         case DEFACLOBJ_NAMESPACE:
   16508            0 :             type = "SCHEMAS";
   16509            0 :             break;
   16510            0 :         case DEFACLOBJ_LARGEOBJECT:
   16511            0 :             type = "LARGE OBJECTS";
   16512            0 :             break;
   16513            0 :         default:
   16514              :             /* shouldn't get here */
   16515            0 :             pg_fatal("unrecognized object type in default privileges: %d",
   16516              :                      (int) daclinfo->defaclobjtype);
   16517              :             type = "";            /* keep compiler quiet */
   16518              :     }
   16519              : 
   16520          132 :     appendPQExpBuffer(tag, "DEFAULT PRIVILEGES FOR %s", type);
   16521              : 
   16522              :     /* build the actual command(s) for this tuple */
   16523          132 :     if (!buildDefaultACLCommands(type,
   16524          132 :                                  daclinfo->dobj.namespace != NULL ?
   16525           62 :                                  daclinfo->dobj.namespace->dobj.name : NULL,
   16526          132 :                                  daclinfo->dacl.acl,
   16527          132 :                                  daclinfo->dacl.acldefault,
   16528          132 :                                  daclinfo->defaclrole,
   16529              :                                  fout->remoteVersion,
   16530              :                                  q))
   16531            0 :         pg_fatal("could not parse default ACL list (%s)",
   16532              :                  daclinfo->dacl.acl);
   16533              : 
   16534          132 :     if (daclinfo->dobj.dump & DUMP_COMPONENT_ACL)
   16535          132 :         ArchiveEntry(fout, daclinfo->dobj.catId, daclinfo->dobj.dumpId,
   16536          132 :                      ARCHIVE_OPTS(.tag = tag->data,
   16537              :                                   .namespace = daclinfo->dobj.namespace ?
   16538              :                                   daclinfo->dobj.namespace->dobj.name : NULL,
   16539              :                                   .owner = daclinfo->defaclrole,
   16540              :                                   .description = "DEFAULT ACL",
   16541              :                                   .section = SECTION_POST_DATA,
   16542              :                                   .createStmt = q->data));
   16543              : 
   16544          132 :     destroyPQExpBuffer(tag);
   16545          132 :     destroyPQExpBuffer(q);
   16546              : }
   16547              : 
   16548              : /*----------
   16549              :  * Write out grant/revoke information
   16550              :  *
   16551              :  * 'objDumpId' is the dump ID of the underlying object.
   16552              :  * 'altDumpId' can be a second dumpId that the ACL entry must also depend on,
   16553              :  *      or InvalidDumpId if there is no need for a second dependency.
   16554              :  * 'type' must be one of
   16555              :  *      TABLE, SEQUENCE, FUNCTION, LANGUAGE, SCHEMA, DATABASE, TABLESPACE,
   16556              :  *      FOREIGN DATA WRAPPER, SERVER, or LARGE OBJECT.
   16557              :  * 'name' is the formatted name of the object.  Must be quoted etc. already.
   16558              :  * 'subname' is the formatted name of the sub-object, if any.  Must be quoted.
   16559              :  *      (Currently we assume that subname is only provided for table columns.)
   16560              :  * 'nspname' is the namespace the object is in (NULL if none).
   16561              :  * 'tag' is the tag to use for the ACL TOC entry; typically, this is NULL
   16562              :  *      to use the default for the object type.
   16563              :  * 'owner' is the owner, NULL if there is no owner (for languages).
   16564              :  * 'dacl' is the DumpableAcl struct for the object.
   16565              :  *
   16566              :  * Returns the dump ID assigned to the ACL TocEntry, or InvalidDumpId if
   16567              :  * no ACL entry was created.
   16568              :  *----------
   16569              :  */
   16570              : static DumpId
   16571        42985 : dumpACL(Archive *fout, DumpId objDumpId, DumpId altDumpId,
   16572              :         const char *type, const char *name, const char *subname,
   16573              :         const char *nspname, const char *tag, const char *owner,
   16574              :         const DumpableAcl *dacl)
   16575              : {
   16576        42985 :     DumpId      aclDumpId = InvalidDumpId;
   16577        42985 :     DumpOptions *dopt = fout->dopt;
   16578        42985 :     const char *acls = dacl->acl;
   16579        42985 :     const char *acldefault = dacl->acldefault;
   16580        42985 :     char        privtype = dacl->privtype;
   16581        42985 :     const char *initprivs = dacl->initprivs;
   16582              :     const char *baseacls;
   16583              :     PQExpBuffer sql;
   16584              : 
   16585              :     /* Do nothing if ACL dump is not enabled */
   16586        42985 :     if (dopt->aclsSkip)
   16587          341 :         return InvalidDumpId;
   16588              : 
   16589              :     /* --data-only skips ACLs *except* large object ACLs */
   16590        42644 :     if (!dopt->dumpSchema && strcmp(type, "LARGE OBJECT") != 0)
   16591            0 :         return InvalidDumpId;
   16592              : 
   16593        42644 :     sql = createPQExpBuffer();
   16594              : 
   16595              :     /*
   16596              :      * In binary upgrade mode, we don't run an extension's script but instead
   16597              :      * dump out the objects independently and then recreate them.  To preserve
   16598              :      * any initial privileges which were set on extension objects, we need to
   16599              :      * compute the set of GRANT and REVOKE commands necessary to get from the
   16600              :      * default privileges of an object to its initial privileges as recorded
   16601              :      * in pg_init_privs.
   16602              :      *
   16603              :      * At restore time, we apply these commands after having called
   16604              :      * binary_upgrade_set_record_init_privs(true).  That tells the backend to
   16605              :      * copy the results into pg_init_privs.  This is how we preserve the
   16606              :      * contents of that catalog across binary upgrades.
   16607              :      */
   16608        42644 :     if (dopt->binary_upgrade && privtype == 'e' &&
   16609           13 :         initprivs && *initprivs != '\0')
   16610              :     {
   16611           13 :         appendPQExpBufferStr(sql, "SELECT pg_catalog.binary_upgrade_set_record_init_privs(true);\n");
   16612           13 :         if (!buildACLCommands(name, subname, nspname, type,
   16613              :                               initprivs, acldefault, owner,
   16614              :                               "", fout->remoteVersion, sql))
   16615            0 :             pg_fatal("could not parse initial ACL list (%s) or default (%s) for object \"%s\" (%s)",
   16616              :                      initprivs, acldefault, name, type);
   16617           13 :         appendPQExpBufferStr(sql, "SELECT pg_catalog.binary_upgrade_set_record_init_privs(false);\n");
   16618              :     }
   16619              : 
   16620              :     /*
   16621              :      * Now figure the GRANT and REVOKE commands needed to get to the object's
   16622              :      * actual current ACL, starting from the initprivs if given, else from the
   16623              :      * object-type-specific default.  Also, while buildACLCommands will assume
   16624              :      * that a NULL/empty acls string means it needn't do anything, what that
   16625              :      * actually represents is the object-type-specific default; so we need to
   16626              :      * substitute the acldefault string to get the right results in that case.
   16627              :      */
   16628        42644 :     if (initprivs && *initprivs != '\0')
   16629              :     {
   16630        40726 :         baseacls = initprivs;
   16631        40726 :         if (acls == NULL || *acls == '\0')
   16632           17 :             acls = acldefault;
   16633              :     }
   16634              :     else
   16635         1918 :         baseacls = acldefault;
   16636              : 
   16637        42644 :     if (!buildACLCommands(name, subname, nspname, type,
   16638              :                           acls, baseacls, owner,
   16639              :                           "", fout->remoteVersion, sql))
   16640            0 :         pg_fatal("could not parse ACL list (%s) or default (%s) for object \"%s\" (%s)",
   16641              :                  acls, baseacls, name, type);
   16642              : 
   16643        42644 :     if (sql->len > 0)
   16644              :     {
   16645         1921 :         PQExpBuffer tagbuf = createPQExpBuffer();
   16646              :         DumpId      aclDeps[2];
   16647         1921 :         int         nDeps = 0;
   16648              : 
   16649         1921 :         if (tag)
   16650            0 :             appendPQExpBufferStr(tagbuf, tag);
   16651         1921 :         else if (subname)
   16652         1047 :             appendPQExpBuffer(tagbuf, "COLUMN %s.%s", name, subname);
   16653              :         else
   16654          874 :             appendPQExpBuffer(tagbuf, "%s %s", type, name);
   16655              : 
   16656         1921 :         aclDeps[nDeps++] = objDumpId;
   16657         1921 :         if (altDumpId != InvalidDumpId)
   16658          963 :             aclDeps[nDeps++] = altDumpId;
   16659              : 
   16660         1921 :         aclDumpId = createDumpId();
   16661              : 
   16662         1921 :         ArchiveEntry(fout, nilCatalogId, aclDumpId,
   16663         1921 :                      ARCHIVE_OPTS(.tag = tagbuf->data,
   16664              :                                   .namespace = nspname,
   16665              :                                   .owner = owner,
   16666              :                                   .description = "ACL",
   16667              :                                   .section = SECTION_NONE,
   16668              :                                   .createStmt = sql->data,
   16669              :                                   .deps = aclDeps,
   16670              :                                   .nDeps = nDeps));
   16671              : 
   16672         1921 :         destroyPQExpBuffer(tagbuf);
   16673              :     }
   16674              : 
   16675        42644 :     destroyPQExpBuffer(sql);
   16676              : 
   16677        42644 :     return aclDumpId;
   16678              : }
   16679              : 
   16680              : /*
   16681              :  * dumpSecLabel
   16682              :  *
   16683              :  * This routine is used to dump any security labels associated with the
   16684              :  * object handed to this routine. The routine takes the object type
   16685              :  * and object name (ready to print, except for schema decoration), plus
   16686              :  * the namespace and owner of the object (for labeling the ArchiveEntry),
   16687              :  * plus catalog ID and subid which are the lookup key for pg_seclabel,
   16688              :  * plus the dump ID for the object (for setting a dependency).
   16689              :  * If a matching pg_seclabel entry is found, it is dumped.
   16690              :  *
   16691              :  * Note: although this routine takes a dumpId for dependency purposes,
   16692              :  * that purpose is just to mark the dependency in the emitted dump file
   16693              :  * for possible future use by pg_restore.  We do NOT use it for determining
   16694              :  * ordering of the label in the dump file, because this routine is called
   16695              :  * after dependency sorting occurs.  This routine should be called just after
   16696              :  * calling ArchiveEntry() for the specified object.
   16697              :  */
   16698              : static void
   16699           10 : dumpSecLabel(Archive *fout, const char *type, const char *name,
   16700              :              const char *namespace, const char *owner,
   16701              :              CatalogId catalogId, int subid, DumpId dumpId)
   16702              : {
   16703           10 :     DumpOptions *dopt = fout->dopt;
   16704              :     SecLabelItem *labels;
   16705              :     int         nlabels;
   16706              :     int         i;
   16707              :     PQExpBuffer query;
   16708              : 
   16709              :     /* do nothing, if --no-security-labels is supplied */
   16710           10 :     if (dopt->no_security_labels)
   16711            0 :         return;
   16712              : 
   16713              :     /*
   16714              :      * Security labels are schema not data ... except large object labels are
   16715              :      * data
   16716              :      */
   16717           10 :     if (strcmp(type, "LARGE OBJECT") != 0)
   16718              :     {
   16719            0 :         if (!dopt->dumpSchema)
   16720            0 :             return;
   16721              :     }
   16722              :     else
   16723              :     {
   16724              :         /* We do dump large object security labels in binary-upgrade mode */
   16725           10 :         if (!dopt->dumpData && !dopt->binary_upgrade)
   16726            0 :             return;
   16727              :     }
   16728              : 
   16729              :     /* Search for security labels associated with catalogId, using table */
   16730           10 :     nlabels = findSecLabels(catalogId.tableoid, catalogId.oid, &labels);
   16731              : 
   16732           10 :     query = createPQExpBuffer();
   16733              : 
   16734           15 :     for (i = 0; i < nlabels; i++)
   16735              :     {
   16736              :         /*
   16737              :          * Ignore label entries for which the subid doesn't match.
   16738              :          */
   16739            5 :         if (labels[i].objsubid != subid)
   16740            0 :             continue;
   16741              : 
   16742            5 :         appendPQExpBuffer(query,
   16743              :                           "SECURITY LABEL FOR %s ON %s ",
   16744            5 :                           fmtId(labels[i].provider), type);
   16745            5 :         if (namespace && *namespace)
   16746            0 :             appendPQExpBuffer(query, "%s.", fmtId(namespace));
   16747            5 :         appendPQExpBuffer(query, "%s IS ", name);
   16748            5 :         appendStringLiteralAH(query, labels[i].label, fout);
   16749            5 :         appendPQExpBufferStr(query, ";\n");
   16750              :     }
   16751              : 
   16752           10 :     if (query->len > 0)
   16753              :     {
   16754            5 :         PQExpBuffer tag = createPQExpBuffer();
   16755              : 
   16756            5 :         appendPQExpBuffer(tag, "%s %s", type, name);
   16757            5 :         ArchiveEntry(fout, nilCatalogId, createDumpId(),
   16758            5 :                      ARCHIVE_OPTS(.tag = tag->data,
   16759              :                                   .namespace = namespace,
   16760              :                                   .owner = owner,
   16761              :                                   .description = "SECURITY LABEL",
   16762              :                                   .section = SECTION_NONE,
   16763              :                                   .createStmt = query->data,
   16764              :                                   .deps = &dumpId,
   16765              :                                   .nDeps = 1));
   16766            5 :         destroyPQExpBuffer(tag);
   16767              :     }
   16768              : 
   16769           10 :     destroyPQExpBuffer(query);
   16770              : }
   16771              : 
   16772              : /*
   16773              :  * dumpTableSecLabel
   16774              :  *
   16775              :  * As above, but dump security label for both the specified table (or view)
   16776              :  * and its columns.
   16777              :  */
   16778              : static void
   16779            0 : dumpTableSecLabel(Archive *fout, const TableInfo *tbinfo, const char *reltypename)
   16780              : {
   16781            0 :     DumpOptions *dopt = fout->dopt;
   16782              :     SecLabelItem *labels;
   16783              :     int         nlabels;
   16784              :     int         i;
   16785              :     PQExpBuffer query;
   16786              :     PQExpBuffer target;
   16787              : 
   16788              :     /* do nothing, if --no-security-labels is supplied */
   16789            0 :     if (dopt->no_security_labels)
   16790            0 :         return;
   16791              : 
   16792              :     /* SecLabel are SCHEMA not data */
   16793            0 :     if (!dopt->dumpSchema)
   16794            0 :         return;
   16795              : 
   16796              :     /* Search for comments associated with relation, using table */
   16797            0 :     nlabels = findSecLabels(tbinfo->dobj.catId.tableoid,
   16798            0 :                             tbinfo->dobj.catId.oid,
   16799              :                             &labels);
   16800              : 
   16801              :     /* If security labels exist, build SECURITY LABEL statements */
   16802            0 :     if (nlabels <= 0)
   16803            0 :         return;
   16804              : 
   16805            0 :     query = createPQExpBuffer();
   16806            0 :     target = createPQExpBuffer();
   16807              : 
   16808            0 :     for (i = 0; i < nlabels; i++)
   16809              :     {
   16810              :         const char *colname;
   16811            0 :         const char *provider = labels[i].provider;
   16812            0 :         const char *label = labels[i].label;
   16813            0 :         int         objsubid = labels[i].objsubid;
   16814              : 
   16815            0 :         resetPQExpBuffer(target);
   16816            0 :         if (objsubid == 0)
   16817              :         {
   16818            0 :             appendPQExpBuffer(target, "%s %s", reltypename,
   16819            0 :                               fmtQualifiedDumpable(tbinfo));
   16820              :         }
   16821              :         else
   16822              :         {
   16823            0 :             colname = getAttrName(objsubid, tbinfo);
   16824              :             /* first fmtXXX result must be consumed before calling again */
   16825            0 :             appendPQExpBuffer(target, "COLUMN %s",
   16826            0 :                               fmtQualifiedDumpable(tbinfo));
   16827            0 :             appendPQExpBuffer(target, ".%s", fmtId(colname));
   16828              :         }
   16829            0 :         appendPQExpBuffer(query, "SECURITY LABEL FOR %s ON %s IS ",
   16830              :                           fmtId(provider), target->data);
   16831            0 :         appendStringLiteralAH(query, label, fout);
   16832            0 :         appendPQExpBufferStr(query, ";\n");
   16833              :     }
   16834            0 :     if (query->len > 0)
   16835              :     {
   16836            0 :         resetPQExpBuffer(target);
   16837            0 :         appendPQExpBuffer(target, "%s %s", reltypename,
   16838            0 :                           fmtId(tbinfo->dobj.name));
   16839            0 :         ArchiveEntry(fout, nilCatalogId, createDumpId(),
   16840            0 :                      ARCHIVE_OPTS(.tag = target->data,
   16841              :                                   .namespace = tbinfo->dobj.namespace->dobj.name,
   16842              :                                   .owner = tbinfo->rolname,
   16843              :                                   .description = "SECURITY LABEL",
   16844              :                                   .section = SECTION_NONE,
   16845              :                                   .createStmt = query->data,
   16846              :                                   .deps = &(tbinfo->dobj.dumpId),
   16847              :                                   .nDeps = 1));
   16848              :     }
   16849            0 :     destroyPQExpBuffer(query);
   16850            0 :     destroyPQExpBuffer(target);
   16851              : }
   16852              : 
   16853              : /*
   16854              :  * findSecLabels
   16855              :  *
   16856              :  * Find the security label(s), if any, associated with the given object.
   16857              :  * All the objsubid values associated with the given classoid/objoid are
   16858              :  * found with one search.
   16859              :  */
   16860              : static int
   16861           10 : findSecLabels(Oid classoid, Oid objoid, SecLabelItem **items)
   16862              : {
   16863           10 :     SecLabelItem *middle = NULL;
   16864              :     SecLabelItem *low;
   16865              :     SecLabelItem *high;
   16866              :     int         nmatch;
   16867              : 
   16868           10 :     if (nseclabels <= 0)     /* no labels, so no match is possible */
   16869              :     {
   16870            0 :         *items = NULL;
   16871            0 :         return 0;
   16872              :     }
   16873              : 
   16874              :     /*
   16875              :      * Do binary search to find some item matching the object.
   16876              :      */
   16877           10 :     low = &seclabels[0];
   16878           10 :     high = &seclabels[nseclabels - 1];
   16879           15 :     while (low <= high)
   16880              :     {
   16881           10 :         middle = low + (high - low) / 2;
   16882              : 
   16883           10 :         if (classoid < middle->classoid)
   16884            0 :             high = middle - 1;
   16885           10 :         else if (classoid > middle->classoid)
   16886            0 :             low = middle + 1;
   16887           10 :         else if (objoid < middle->objoid)
   16888            5 :             high = middle - 1;
   16889            5 :         else if (objoid > middle->objoid)
   16890            0 :             low = middle + 1;
   16891              :         else
   16892            5 :             break;              /* found a match */
   16893              :     }
   16894              : 
   16895           10 :     if (low > high)              /* no matches */
   16896              :     {
   16897            5 :         *items = NULL;
   16898            5 :         return 0;
   16899              :     }
   16900              : 
   16901              :     /*
   16902              :      * Now determine how many items match the object.  The search loop
   16903              :      * invariant still holds: only items between low and high inclusive could
   16904              :      * match.
   16905              :      */
   16906            5 :     nmatch = 1;
   16907            5 :     while (middle > low)
   16908              :     {
   16909            0 :         if (classoid != middle[-1].classoid ||
   16910            0 :             objoid != middle[-1].objoid)
   16911              :             break;
   16912            0 :         middle--;
   16913            0 :         nmatch++;
   16914              :     }
   16915              : 
   16916            5 :     *items = middle;
   16917              : 
   16918            5 :     middle += nmatch;
   16919            5 :     while (middle <= high)
   16920              :     {
   16921            0 :         if (classoid != middle->classoid ||
   16922            0 :             objoid != middle->objoid)
   16923              :             break;
   16924            0 :         middle++;
   16925            0 :         nmatch++;
   16926              :     }
   16927              : 
   16928            5 :     return nmatch;
   16929              : }
   16930              : 
   16931              : /*
   16932              :  * collectSecLabels
   16933              :  *
   16934              :  * Construct a table of all security labels available for database objects;
   16935              :  * also set the has-seclabel component flag for each relevant object.
   16936              :  *
   16937              :  * The table is sorted by classoid/objid/objsubid for speed in lookup.
   16938              :  */
   16939              : static void
   16940          259 : collectSecLabels(Archive *fout)
   16941              : {
   16942              :     PGresult   *res;
   16943              :     PQExpBuffer query;
   16944              :     int         i_label;
   16945              :     int         i_provider;
   16946              :     int         i_classoid;
   16947              :     int         i_objoid;
   16948              :     int         i_objsubid;
   16949              :     int         ntups;
   16950              :     int         i;
   16951              :     DumpableObject *dobj;
   16952              : 
   16953          259 :     query = createPQExpBuffer();
   16954              : 
   16955          259 :     appendPQExpBufferStr(query,
   16956              :                          "SELECT label, provider, classoid, objoid, objsubid "
   16957              :                          "FROM pg_catalog.pg_seclabels "
   16958              :                          "ORDER BY classoid, objoid, objsubid");
   16959              : 
   16960          259 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   16961              : 
   16962              :     /* Construct lookup table containing OIDs in numeric form */
   16963          259 :     i_label = PQfnumber(res, "label");
   16964          259 :     i_provider = PQfnumber(res, "provider");
   16965          259 :     i_classoid = PQfnumber(res, "classoid");
   16966          259 :     i_objoid = PQfnumber(res, "objoid");
   16967          259 :     i_objsubid = PQfnumber(res, "objsubid");
   16968              : 
   16969          259 :     ntups = PQntuples(res);
   16970              : 
   16971          259 :     seclabels = pg_malloc_array(SecLabelItem, ntups);
   16972          259 :     nseclabels = 0;
   16973          259 :     dobj = NULL;
   16974              : 
   16975          264 :     for (i = 0; i < ntups; i++)
   16976              :     {
   16977              :         CatalogId   objId;
   16978              :         int         subid;
   16979              : 
   16980            5 :         objId.tableoid = atooid(PQgetvalue(res, i, i_classoid));
   16981            5 :         objId.oid = atooid(PQgetvalue(res, i, i_objoid));
   16982            5 :         subid = atoi(PQgetvalue(res, i, i_objsubid));
   16983              : 
   16984              :         /* We needn't remember labels that don't match any dumpable object */
   16985            5 :         if (dobj == NULL ||
   16986            0 :             dobj->catId.tableoid != objId.tableoid ||
   16987            0 :             dobj->catId.oid != objId.oid)
   16988            5 :             dobj = findObjectByCatalogId(objId);
   16989            5 :         if (dobj == NULL)
   16990            0 :             continue;
   16991              : 
   16992              :         /*
   16993              :          * Labels on columns of composite types are linked to the type's
   16994              :          * pg_class entry, but we need to set the DUMP_COMPONENT_SECLABEL flag
   16995              :          * in the type's own DumpableObject.
   16996              :          */
   16997            5 :         if (subid != 0 && dobj->objType == DO_TABLE &&
   16998            0 :             ((TableInfo *) dobj)->relkind == RELKIND_COMPOSITE_TYPE)
   16999            0 :         {
   17000              :             TypeInfo   *cTypeInfo;
   17001              : 
   17002            0 :             cTypeInfo = findTypeByOid(((TableInfo *) dobj)->reltype);
   17003            0 :             if (cTypeInfo)
   17004            0 :                 cTypeInfo->dobj.components |= DUMP_COMPONENT_SECLABEL;
   17005              :         }
   17006              :         else
   17007            5 :             dobj->components |= DUMP_COMPONENT_SECLABEL;
   17008              : 
   17009            5 :         seclabels[nseclabels].label = pg_strdup(PQgetvalue(res, i, i_label));
   17010            5 :         seclabels[nseclabels].provider = pg_strdup(PQgetvalue(res, i, i_provider));
   17011            5 :         seclabels[nseclabels].classoid = objId.tableoid;
   17012            5 :         seclabels[nseclabels].objoid = objId.oid;
   17013            5 :         seclabels[nseclabels].objsubid = subid;
   17014            5 :         nseclabels++;
   17015              :     }
   17016              : 
   17017          259 :     PQclear(res);
   17018          259 :     destroyPQExpBuffer(query);
   17019          259 : }
   17020              : 
   17021              : /*
   17022              :  * dumpTable
   17023              :  *    write out to fout the declarations (not data) of a user-defined table
   17024              :  */
   17025              : static void
   17026        44004 : dumpTable(Archive *fout, const TableInfo *tbinfo)
   17027              : {
   17028        44004 :     DumpOptions *dopt = fout->dopt;
   17029        44004 :     DumpId      tableAclDumpId = InvalidDumpId;
   17030              :     char       *namecopy;
   17031              : 
   17032              :     /* Do nothing if not dumping schema */
   17033        44004 :     if (!dopt->dumpSchema)
   17034         1588 :         return;
   17035              : 
   17036        42416 :     if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   17037              :     {
   17038         7226 :         if (tbinfo->relkind == RELKIND_SEQUENCE)
   17039          384 :             dumpSequence(fout, tbinfo);
   17040              :         else
   17041         6842 :             dumpTableSchema(fout, tbinfo);
   17042              :     }
   17043              : 
   17044              :     /* Handle the ACL here */
   17045        42416 :     namecopy = pg_strdup(fmtId(tbinfo->dobj.name));
   17046        42416 :     if (tbinfo->dobj.dump & DUMP_COMPONENT_ACL)
   17047              :     {
   17048              :         const char *objtype;
   17049              : 
   17050        36012 :         switch (tbinfo->relkind)
   17051              :         {
   17052           99 :             case RELKIND_SEQUENCE:
   17053           99 :                 objtype = "SEQUENCE";
   17054           99 :                 break;
   17055           37 :             case RELKIND_PROPGRAPH:
   17056           37 :                 objtype = "PROPERTY GRAPH";
   17057           37 :                 break;
   17058        35876 :             default:
   17059        35876 :                 objtype = "TABLE";
   17060        35876 :                 break;
   17061              :         }
   17062              : 
   17063              :         tableAclDumpId =
   17064        36012 :             dumpACL(fout, tbinfo->dobj.dumpId, InvalidDumpId,
   17065              :                     objtype, namecopy, NULL,
   17066        36012 :                     tbinfo->dobj.namespace->dobj.name,
   17067        36012 :                     NULL, tbinfo->rolname, &tbinfo->dacl);
   17068              :     }
   17069              : 
   17070              :     /*
   17071              :      * Handle column ACLs, if any.  Note: we pull these with a separate query
   17072              :      * rather than trying to fetch them during getTableAttrs, so that we won't
   17073              :      * miss ACLs on system columns.  Doing it this way also allows us to dump
   17074              :      * ACLs for catalogs that we didn't mark "interesting" back in getTables.
   17075              :      */
   17076        42416 :     if ((tbinfo->dobj.dump & DUMP_COMPONENT_ACL) && tbinfo->hascolumnACLs)
   17077              :     {
   17078          354 :         PQExpBuffer query = createPQExpBuffer();
   17079              :         PGresult   *res;
   17080              :         int         i;
   17081              : 
   17082          354 :         if (!fout->is_prepared[PREPQUERY_GETCOLUMNACLS])
   17083              :         {
   17084              :             /* Set up query for column ACLs */
   17085          233 :             appendPQExpBufferStr(query,
   17086              :                                  "PREPARE getColumnACLs(pg_catalog.oid) AS\n");
   17087              : 
   17088          233 :             if (fout->remoteVersion >= 90600)
   17089              :             {
   17090              :                 /*
   17091              :                  * In principle we should call acldefault('c', relowner) to
   17092              :                  * get the default ACL for a column.  However, we don't
   17093              :                  * currently store the numeric OID of the relowner in
   17094              :                  * TableInfo.  We could convert the owner name using regrole,
   17095              :                  * but that creates a risk of failure due to concurrent role
   17096              :                  * renames.  Given that the default ACL for columns is empty
   17097              :                  * and is likely to stay that way, it's not worth extra cycles
   17098              :                  * and risk to avoid hard-wiring that knowledge here.
   17099              :                  */
   17100          233 :                 appendPQExpBufferStr(query,
   17101              :                                      "SELECT at.attname, "
   17102              :                                      "at.attacl, "
   17103              :                                      "'{}' AS acldefault, "
   17104              :                                      "pip.privtype, pip.initprivs "
   17105              :                                      "FROM pg_catalog.pg_attribute at "
   17106              :                                      "LEFT JOIN pg_catalog.pg_init_privs pip ON "
   17107              :                                      "(at.attrelid = pip.objoid "
   17108              :                                      "AND pip.classoid = 'pg_catalog.pg_class'::pg_catalog.regclass "
   17109              :                                      "AND at.attnum = pip.objsubid) "
   17110              :                                      "WHERE at.attrelid = $1 AND "
   17111              :                                      "NOT at.attisdropped "
   17112              :                                      "AND (at.attacl IS NOT NULL OR pip.initprivs IS NOT NULL) "
   17113              :                                      "ORDER BY at.attnum");
   17114              :             }
   17115              :             else
   17116              :             {
   17117            0 :                 appendPQExpBufferStr(query,
   17118              :                                      "SELECT attname, attacl, '{}' AS acldefault, "
   17119              :                                      "NULL AS privtype, NULL AS initprivs "
   17120              :                                      "FROM pg_catalog.pg_attribute "
   17121              :                                      "WHERE attrelid = $1 AND NOT attisdropped "
   17122              :                                      "AND attacl IS NOT NULL "
   17123              :                                      "ORDER BY attnum");
   17124              :             }
   17125              : 
   17126          233 :             ExecuteSqlStatement(fout, query->data);
   17127              : 
   17128          233 :             fout->is_prepared[PREPQUERY_GETCOLUMNACLS] = true;
   17129              :         }
   17130              : 
   17131          354 :         printfPQExpBuffer(query,
   17132              :                           "EXECUTE getColumnACLs('%u')",
   17133          354 :                           tbinfo->dobj.catId.oid);
   17134              : 
   17135          354 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   17136              : 
   17137         6231 :         for (i = 0; i < PQntuples(res); i++)
   17138              :         {
   17139         5877 :             char       *attname = PQgetvalue(res, i, 0);
   17140         5877 :             char       *attacl = PQgetvalue(res, i, 1);
   17141         5877 :             char       *acldefault = PQgetvalue(res, i, 2);
   17142         5877 :             char        privtype = *(PQgetvalue(res, i, 3));
   17143         5877 :             char       *initprivs = PQgetvalue(res, i, 4);
   17144              :             DumpableAcl coldacl;
   17145              :             char       *attnamecopy;
   17146              : 
   17147         5877 :             coldacl.acl = attacl;
   17148         5877 :             coldacl.acldefault = acldefault;
   17149         5877 :             coldacl.privtype = privtype;
   17150         5877 :             coldacl.initprivs = initprivs;
   17151         5877 :             attnamecopy = pg_strdup(fmtId(attname));
   17152              : 
   17153              :             /*
   17154              :              * Column's GRANT type is always TABLE.  Each column ACL depends
   17155              :              * on the table-level ACL, since we can restore column ACLs in
   17156              :              * parallel but the table-level ACL has to be done first.
   17157              :              */
   17158         5877 :             dumpACL(fout, tbinfo->dobj.dumpId, tableAclDumpId,
   17159              :                     "TABLE", namecopy, attnamecopy,
   17160         5877 :                     tbinfo->dobj.namespace->dobj.name,
   17161         5877 :                     NULL, tbinfo->rolname, &coldacl);
   17162         5877 :             free(attnamecopy);
   17163              :         }
   17164          354 :         PQclear(res);
   17165          354 :         destroyPQExpBuffer(query);
   17166              :     }
   17167              : 
   17168        42416 :     free(namecopy);
   17169              : }
   17170              : 
   17171              : /*
   17172              :  * Create the AS clause for a view or materialized view. The semicolon is
   17173              :  * stripped because a materialized view must add a WITH NO DATA clause.
   17174              :  *
   17175              :  * This returns a new buffer which must be freed by the caller.
   17176              :  */
   17177              : static PQExpBuffer
   17178          889 : createViewAsClause(Archive *fout, const TableInfo *tbinfo)
   17179              : {
   17180          889 :     PQExpBuffer query = createPQExpBuffer();
   17181          889 :     PQExpBuffer result = createPQExpBuffer();
   17182              :     PGresult   *res;
   17183              :     int         len;
   17184              : 
   17185              :     /* Fetch the view definition */
   17186          889 :     appendPQExpBuffer(query,
   17187              :                       "SELECT pg_catalog.pg_get_viewdef('%u'::pg_catalog.oid) AS viewdef",
   17188          889 :                       tbinfo->dobj.catId.oid);
   17189              : 
   17190          889 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   17191              : 
   17192          889 :     if (PQntuples(res) != 1)
   17193              :     {
   17194            0 :         if (PQntuples(res) < 1)
   17195            0 :             pg_fatal("query to obtain definition of view \"%s\" returned no data",
   17196              :                      tbinfo->dobj.name);
   17197              :         else
   17198            0 :             pg_fatal("query to obtain definition of view \"%s\" returned more than one definition",
   17199              :                      tbinfo->dobj.name);
   17200              :     }
   17201              : 
   17202          889 :     len = PQgetlength(res, 0, 0);
   17203              : 
   17204          889 :     if (len == 0)
   17205            0 :         pg_fatal("definition of view \"%s\" appears to be empty (length zero)",
   17206              :                  tbinfo->dobj.name);
   17207              : 
   17208              :     /* Strip off the trailing semicolon so that other things may follow. */
   17209              :     Assert(PQgetvalue(res, 0, 0)[len - 1] == ';');
   17210          889 :     appendBinaryPQExpBuffer(result, PQgetvalue(res, 0, 0), len - 1);
   17211              : 
   17212          889 :     PQclear(res);
   17213          889 :     destroyPQExpBuffer(query);
   17214              : 
   17215          889 :     return result;
   17216              : }
   17217              : 
   17218              : /*
   17219              :  * Create a dummy AS clause for a view.  This is used when the real view
   17220              :  * definition has to be postponed because of circular dependencies.
   17221              :  * We must duplicate the view's external properties -- column names and types
   17222              :  * (including collation) -- so that it works for subsequent references.
   17223              :  *
   17224              :  * This returns a new buffer which must be freed by the caller.
   17225              :  */
   17226              : static PQExpBuffer
   17227           20 : createDummyViewAsClause(Archive *fout, const TableInfo *tbinfo)
   17228              : {
   17229           20 :     PQExpBuffer result = createPQExpBuffer();
   17230              :     int         j;
   17231              : 
   17232           20 :     appendPQExpBufferStr(result, "SELECT");
   17233              : 
   17234           40 :     for (j = 0; j < tbinfo->numatts; j++)
   17235              :     {
   17236           20 :         if (j > 0)
   17237           10 :             appendPQExpBufferChar(result, ',');
   17238           20 :         appendPQExpBufferStr(result, "\n    ");
   17239              : 
   17240           20 :         appendPQExpBuffer(result, "NULL::%s", tbinfo->atttypnames[j]);
   17241              : 
   17242              :         /*
   17243              :          * Must add collation if not default for the type, because CREATE OR
   17244              :          * REPLACE VIEW won't change it
   17245              :          */
   17246           20 :         if (OidIsValid(tbinfo->attcollation[j]))
   17247              :         {
   17248              :             CollInfo   *coll;
   17249              : 
   17250            0 :             coll = findCollationByOid(tbinfo->attcollation[j]);
   17251            0 :             if (coll)
   17252            0 :                 appendPQExpBuffer(result, " COLLATE %s",
   17253            0 :                                   fmtQualifiedDumpable(coll));
   17254              :         }
   17255              : 
   17256           20 :         appendPQExpBuffer(result, " AS %s", fmtId(tbinfo->attnames[j]));
   17257              :     }
   17258              : 
   17259           20 :     return result;
   17260              : }
   17261              : 
   17262              : /*
   17263              :  * dumpTableSchema
   17264              :  *    write the declaration (not data) of one user-defined table or view
   17265              :  */
   17266              : static void
   17267         6842 : dumpTableSchema(Archive *fout, const TableInfo *tbinfo)
   17268              : {
   17269         6842 :     DumpOptions *dopt = fout->dopt;
   17270         6842 :     PQExpBuffer q = createPQExpBuffer();
   17271         6842 :     PQExpBuffer delq = createPQExpBuffer();
   17272         6842 :     PQExpBuffer extra = createPQExpBuffer();
   17273              :     char       *qrelname;
   17274              :     char       *qualrelname;
   17275              :     int         numParents;
   17276              :     TableInfo **parents;
   17277              :     int         actual_atts;    /* number of attrs in this CREATE statement */
   17278              :     const char *reltypename;
   17279              :     char       *storage;
   17280              :     int         j,
   17281              :                 k;
   17282              : 
   17283              :     /* We had better have loaded per-column details about this table */
   17284              :     Assert(tbinfo->interesting);
   17285              : 
   17286         6842 :     qrelname = pg_strdup(fmtId(tbinfo->dobj.name));
   17287         6842 :     qualrelname = pg_strdup(fmtQualifiedDumpable(tbinfo));
   17288              : 
   17289         6842 :     if (tbinfo->hasoids)
   17290            0 :         pg_log_warning("WITH OIDS is not supported anymore (table \"%s\")",
   17291              :                        qrelname);
   17292              : 
   17293         6842 :     if (dopt->binary_upgrade)
   17294          941 :         binary_upgrade_set_type_oids_by_rel(fout, q, tbinfo);
   17295              : 
   17296              :     /* Is it a table or a view? */
   17297         6842 :     if (tbinfo->relkind == RELKIND_VIEW)
   17298              :     {
   17299              :         PQExpBuffer result;
   17300              : 
   17301              :         /*
   17302              :          * Note: keep this code in sync with the is_view case in dumpRule()
   17303              :          */
   17304              : 
   17305          554 :         reltypename = "VIEW";
   17306              : 
   17307          554 :         if (dopt->binary_upgrade)
   17308           55 :             binary_upgrade_set_pg_class_oids(fout, q,
   17309           55 :                                              tbinfo->dobj.catId.oid);
   17310              : 
   17311          554 :         appendPQExpBuffer(q, "CREATE VIEW %s", qualrelname);
   17312              : 
   17313          554 :         if (tbinfo->dummy_view)
   17314           10 :             result = createDummyViewAsClause(fout, tbinfo);
   17315              :         else
   17316              :         {
   17317          544 :             if (nonemptyReloptions(tbinfo->reloptions))
   17318              :             {
   17319           61 :                 appendPQExpBufferStr(q, " WITH (");
   17320           61 :                 appendReloptionsArrayAH(q, tbinfo->reloptions, "", fout);
   17321           61 :                 appendPQExpBufferChar(q, ')');
   17322              :             }
   17323          544 :             result = createViewAsClause(fout, tbinfo);
   17324              :         }
   17325          554 :         appendPQExpBuffer(q, " AS\n%s", result->data);
   17326          554 :         destroyPQExpBuffer(result);
   17327              : 
   17328          554 :         if (tbinfo->checkoption != NULL && !tbinfo->dummy_view)
   17329           32 :             appendPQExpBuffer(q, "\n  WITH %s CHECK OPTION", tbinfo->checkoption);
   17330          554 :         appendPQExpBufferStr(q, ";\n");
   17331              :     }
   17332         6288 :     else if (tbinfo->relkind == RELKIND_PROPGRAPH)
   17333              :     {
   17334           97 :         PQExpBuffer query = createPQExpBuffer();
   17335              :         PGresult   *res;
   17336              :         int         len;
   17337              : 
   17338           97 :         reltypename = "PROPERTY GRAPH";
   17339              : 
   17340           97 :         if (dopt->binary_upgrade)
   17341           14 :             binary_upgrade_set_pg_class_oids(fout, q,
   17342           14 :                                              tbinfo->dobj.catId.oid);
   17343              : 
   17344           97 :         appendPQExpBuffer(query,
   17345              :                           "SELECT pg_catalog.pg_get_propgraphdef('%u'::pg_catalog.oid) AS pgdef",
   17346           97 :                           tbinfo->dobj.catId.oid);
   17347              : 
   17348           97 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   17349              : 
   17350           97 :         if (PQntuples(res) != 1)
   17351              :         {
   17352            0 :             if (PQntuples(res) < 1)
   17353            0 :                 pg_fatal("query to obtain definition of property graph \"%s\" returned no data",
   17354              :                          tbinfo->dobj.name);
   17355              :             else
   17356            0 :                 pg_fatal("query to obtain definition of property graph \"%s\" returned more than one definition",
   17357              :                          tbinfo->dobj.name);
   17358              :         }
   17359              : 
   17360           97 :         len = PQgetlength(res, 0, 0);
   17361              : 
   17362           97 :         if (len == 0)
   17363            0 :             pg_fatal("definition of property graph \"%s\" appears to be empty (length zero)",
   17364              :                      tbinfo->dobj.name);
   17365              : 
   17366           97 :         appendPQExpBufferStr(q, PQgetvalue(res, 0, 0));
   17367              : 
   17368           97 :         PQclear(res);
   17369           97 :         destroyPQExpBuffer(query);
   17370              : 
   17371           97 :         appendPQExpBufferStr(q, ";\n");
   17372              :     }
   17373              :     else
   17374              :     {
   17375         6191 :         char       *partkeydef = NULL;
   17376         6191 :         char       *ftoptions = NULL;
   17377         6191 :         char       *srvname = NULL;
   17378         6191 :         const char *foreign = "";
   17379              : 
   17380              :         /*
   17381              :          * Set reltypename, and collect any relkind-specific data that we
   17382              :          * didn't fetch during getTables().
   17383              :          */
   17384         6191 :         switch (tbinfo->relkind)
   17385              :         {
   17386          591 :             case RELKIND_PARTITIONED_TABLE:
   17387              :                 {
   17388          591 :                     PQExpBuffer query = createPQExpBuffer();
   17389              :                     PGresult   *res;
   17390              : 
   17391          591 :                     reltypename = "TABLE";
   17392              : 
   17393              :                     /* retrieve partition key definition */
   17394          591 :                     appendPQExpBuffer(query,
   17395              :                                       "SELECT pg_get_partkeydef('%u')",
   17396          591 :                                       tbinfo->dobj.catId.oid);
   17397          591 :                     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   17398          591 :                     partkeydef = pg_strdup(PQgetvalue(res, 0, 0));
   17399          591 :                     PQclear(res);
   17400          591 :                     destroyPQExpBuffer(query);
   17401          591 :                     break;
   17402              :                 }
   17403           34 :             case RELKIND_FOREIGN_TABLE:
   17404              :                 {
   17405           34 :                     PQExpBuffer query = createPQExpBuffer();
   17406              :                     PGresult   *res;
   17407              :                     int         i_srvname;
   17408              :                     int         i_ftoptions;
   17409              : 
   17410           34 :                     reltypename = "FOREIGN TABLE";
   17411              : 
   17412              :                     /* retrieve name of foreign server and generic options */
   17413           34 :                     appendPQExpBuffer(query,
   17414              :                                       "SELECT fs.srvname, "
   17415              :                                       "pg_catalog.array_to_string(ARRAY("
   17416              :                                       "SELECT pg_catalog.quote_ident(option_name) || "
   17417              :                                       "' ' || pg_catalog.quote_literal(option_value) "
   17418              :                                       "FROM pg_catalog.pg_options_to_table(ftoptions) "
   17419              :                                       "ORDER BY option_name"
   17420              :                                       "), E',\n    ') AS ftoptions "
   17421              :                                       "FROM pg_catalog.pg_foreign_table ft "
   17422              :                                       "JOIN pg_catalog.pg_foreign_server fs "
   17423              :                                       "ON (fs.oid = ft.ftserver) "
   17424              :                                       "WHERE ft.ftrelid = '%u'",
   17425           34 :                                       tbinfo->dobj.catId.oid);
   17426           34 :                     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   17427           34 :                     i_srvname = PQfnumber(res, "srvname");
   17428           34 :                     i_ftoptions = PQfnumber(res, "ftoptions");
   17429           34 :                     srvname = pg_strdup(PQgetvalue(res, 0, i_srvname));
   17430           34 :                     ftoptions = pg_strdup(PQgetvalue(res, 0, i_ftoptions));
   17431           34 :                     PQclear(res);
   17432           34 :                     destroyPQExpBuffer(query);
   17433              : 
   17434           34 :                     foreign = "FOREIGN ";
   17435           34 :                     break;
   17436              :                 }
   17437          335 :             case RELKIND_MATVIEW:
   17438          335 :                 reltypename = "MATERIALIZED VIEW";
   17439          335 :                 break;
   17440         5231 :             default:
   17441         5231 :                 reltypename = "TABLE";
   17442         5231 :                 break;
   17443              :         }
   17444              : 
   17445         6191 :         numParents = tbinfo->numParents;
   17446         6191 :         parents = tbinfo->parents;
   17447              : 
   17448         6191 :         if (dopt->binary_upgrade)
   17449          872 :             binary_upgrade_set_pg_class_oids(fout, q,
   17450          872 :                                              tbinfo->dobj.catId.oid);
   17451              : 
   17452              :         /*
   17453              :          * PostgreSQL 18 has disabled UNLOGGED for partitioned tables, so
   17454              :          * ignore it when dumping if it was set in this case.
   17455              :          */
   17456         6191 :         appendPQExpBuffer(q, "CREATE %s%s %s",
   17457         6191 :                           (tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED &&
   17458           20 :                            tbinfo->relkind != RELKIND_PARTITIONED_TABLE) ?
   17459              :                           "UNLOGGED " : "",
   17460              :                           reltypename,
   17461              :                           qualrelname);
   17462              : 
   17463              :         /*
   17464              :          * Attach to type, if reloftype; except in case of a binary upgrade,
   17465              :          * we dump the table normally and attach it to the type afterward.
   17466              :          */
   17467         6191 :         if (OidIsValid(tbinfo->reloftype) && !dopt->binary_upgrade)
   17468           24 :             appendPQExpBuffer(q, " OF %s",
   17469           24 :                               getFormattedTypeName(fout, tbinfo->reloftype,
   17470              :                                                    zeroIsError));
   17471              : 
   17472         6191 :         if (tbinfo->relkind != RELKIND_MATVIEW)
   17473              :         {
   17474              :             /* Dump the attributes */
   17475         5856 :             actual_atts = 0;
   17476        26991 :             for (j = 0; j < tbinfo->numatts; j++)
   17477              :             {
   17478              :                 /*
   17479              :                  * Normally, dump if it's locally defined in this table, and
   17480              :                  * not dropped.  But for binary upgrade, we'll dump all the
   17481              :                  * columns, and then fix up the dropped and nonlocal cases
   17482              :                  * below.
   17483              :                  */
   17484        21135 :                 if (shouldPrintColumn(dopt, tbinfo, j))
   17485              :                 {
   17486              :                     bool        print_default;
   17487              :                     bool        print_notnull;
   17488              : 
   17489              :                     /*
   17490              :                      * Default value --- suppress if to be printed separately
   17491              :                      * or not at all.
   17492              :                      */
   17493        41134 :                     print_default = (tbinfo->attrdefs[j] != NULL &&
   17494        21049 :                                      tbinfo->attrdefs[j]->dobj.dump &&
   17495         1011 :                                      !tbinfo->attrdefs[j]->separate);
   17496              : 
   17497              :                     /*
   17498              :                      * Not Null constraint --- print it if it is locally
   17499              :                      * defined, or if binary upgrade.  (In the latter case, we
   17500              :                      * reset conislocal below.)
   17501              :                      */
   17502        22452 :                     print_notnull = (tbinfo->notnull_constrs[j] != NULL &&
   17503         2414 :                                      (tbinfo->notnull_islocal[j] ||
   17504          637 :                                       dopt->binary_upgrade ||
   17505          547 :                                       tbinfo->ispartition));
   17506              : 
   17507              :                     /*
   17508              :                      * Skip column if fully defined by reloftype, except in
   17509              :                      * binary upgrade
   17510              :                      */
   17511        20038 :                     if (OidIsValid(tbinfo->reloftype) &&
   17512           50 :                         !print_default && !print_notnull &&
   17513           30 :                         !dopt->binary_upgrade)
   17514           24 :                         continue;
   17515              : 
   17516              :                     /* Format properly if not first attr */
   17517        20014 :                     if (actual_atts == 0)
   17518         5483 :                         appendPQExpBufferStr(q, " (");
   17519              :                     else
   17520        14531 :                         appendPQExpBufferChar(q, ',');
   17521        20014 :                     appendPQExpBufferStr(q, "\n    ");
   17522        20014 :                     actual_atts++;
   17523              : 
   17524              :                     /* Attribute name */
   17525        20014 :                     appendPQExpBufferStr(q, fmtId(tbinfo->attnames[j]));
   17526              : 
   17527        20014 :                     if (tbinfo->attisdropped[j])
   17528              :                     {
   17529              :                         /*
   17530              :                          * ALTER TABLE DROP COLUMN clears
   17531              :                          * pg_attribute.atttypid, so we will not have gotten a
   17532              :                          * valid type name; insert INTEGER as a stopgap. We'll
   17533              :                          * clean things up later.
   17534              :                          */
   17535           85 :                         appendPQExpBufferStr(q, " INTEGER /* dummy */");
   17536              :                         /* and skip to the next column */
   17537           85 :                         continue;
   17538              :                     }
   17539              : 
   17540              :                     /*
   17541              :                      * Attribute type; print it except when creating a typed
   17542              :                      * table ('OF type_name'), but in binary-upgrade mode,
   17543              :                      * print it in that case too.
   17544              :                      */
   17545        19929 :                     if (dopt->binary_upgrade || !OidIsValid(tbinfo->reloftype))
   17546              :                     {
   17547        19913 :                         appendPQExpBuffer(q, " %s",
   17548        19913 :                                           tbinfo->atttypnames[j]);
   17549              :                     }
   17550              : 
   17551        19929 :                     if (print_default)
   17552              :                     {
   17553          881 :                         if (tbinfo->attgenerated[j] == ATTRIBUTE_GENERATED_STORED)
   17554          277 :                             appendPQExpBuffer(q, " GENERATED ALWAYS AS (%s) STORED",
   17555          277 :                                               tbinfo->attrdefs[j]->adef_expr);
   17556          604 :                         else if (tbinfo->attgenerated[j] == ATTRIBUTE_GENERATED_VIRTUAL)
   17557          223 :                             appendPQExpBuffer(q, " GENERATED ALWAYS AS (%s)",
   17558          223 :                                               tbinfo->attrdefs[j]->adef_expr);
   17559              :                         else
   17560          381 :                             appendPQExpBuffer(q, " DEFAULT %s",
   17561          381 :                                               tbinfo->attrdefs[j]->adef_expr);
   17562              :                     }
   17563              : 
   17564        19929 :                     if (print_notnull)
   17565              :                     {
   17566         2383 :                         if (tbinfo->notnull_constrs[j][0] == '\0')
   17567         1718 :                             appendPQExpBufferStr(q, " NOT NULL");
   17568              :                         else
   17569          665 :                             appendPQExpBuffer(q, " CONSTRAINT %s NOT NULL",
   17570          665 :                                               fmtId(tbinfo->notnull_constrs[j]));
   17571              : 
   17572         2383 :                         if (tbinfo->notnull_noinh[j])
   17573           33 :                             appendPQExpBufferStr(q, " NO INHERIT");
   17574              :                     }
   17575              : 
   17576              :                     /* Add collation if not default for the type */
   17577        19929 :                     if (OidIsValid(tbinfo->attcollation[j]))
   17578              :                     {
   17579              :                         CollInfo   *coll;
   17580              : 
   17581          213 :                         coll = findCollationByOid(tbinfo->attcollation[j]);
   17582          213 :                         if (coll)
   17583          213 :                             appendPQExpBuffer(q, " COLLATE %s",
   17584          213 :                                               fmtQualifiedDumpable(coll));
   17585              :                     }
   17586              :                 }
   17587              : 
   17588              :                 /*
   17589              :                  * On the other hand, if we choose not to print a column
   17590              :                  * (likely because it is created by inheritance), but the
   17591              :                  * column has a locally-defined not-null constraint, we need
   17592              :                  * to dump the constraint as a standalone object.
   17593              :                  *
   17594              :                  * This syntax isn't SQL-conforming, but if you wanted
   17595              :                  * standard output you wouldn't be creating non-standard
   17596              :                  * objects to begin with.
   17597              :                  */
   17598        21026 :                 if (!shouldPrintColumn(dopt, tbinfo, j) &&
   17599         1097 :                     !tbinfo->attisdropped[j] &&
   17600          730 :                     tbinfo->notnull_constrs[j] != NULL &&
   17601          208 :                     tbinfo->notnull_islocal[j])
   17602              :                 {
   17603              :                     /* Format properly if not first attr */
   17604           90 :                     if (actual_atts == 0)
   17605           86 :                         appendPQExpBufferStr(q, " (");
   17606              :                     else
   17607            4 :                         appendPQExpBufferChar(q, ',');
   17608           90 :                     appendPQExpBufferStr(q, "\n    ");
   17609           90 :                     actual_atts++;
   17610              : 
   17611           90 :                     if (tbinfo->notnull_constrs[j][0] == '\0')
   17612            8 :                         appendPQExpBuffer(q, "NOT NULL %s",
   17613            8 :                                           fmtId(tbinfo->attnames[j]));
   17614              :                     else
   17615          164 :                         appendPQExpBuffer(q, "CONSTRAINT %s NOT NULL %s",
   17616           82 :                                           tbinfo->notnull_constrs[j],
   17617           82 :                                           fmtId(tbinfo->attnames[j]));
   17618              : 
   17619           90 :                     if (tbinfo->notnull_noinh[j])
   17620           31 :                         appendPQExpBufferStr(q, " NO INHERIT");
   17621              :                 }
   17622              :             }
   17623              : 
   17624              :             /*
   17625              :              * Add non-inherited CHECK constraints, if any.
   17626              :              *
   17627              :              * For partitions, we need to include check constraints even if
   17628              :              * they're not defined locally, because the ALTER TABLE ATTACH
   17629              :              * PARTITION that we'll emit later expects the constraint to be
   17630              :              * there.  (No need to fix conislocal: ATTACH PARTITION does that)
   17631              :              */
   17632         6429 :             for (j = 0; j < tbinfo->ncheck; j++)
   17633              :             {
   17634          573 :                 ConstraintInfo *constr = &(tbinfo->checkexprs[j]);
   17635              : 
   17636          573 :                 if (constr->separate ||
   17637          503 :                     (!constr->conislocal && !tbinfo->ispartition))
   17638          107 :                     continue;
   17639              : 
   17640          466 :                 if (actual_atts == 0)
   17641           16 :                     appendPQExpBufferStr(q, " (\n    ");
   17642              :                 else
   17643          450 :                     appendPQExpBufferStr(q, ",\n    ");
   17644              : 
   17645          466 :                 appendPQExpBuffer(q, "CONSTRAINT %s ",
   17646          466 :                                   fmtId(constr->dobj.name));
   17647          466 :                 appendPQExpBufferStr(q, constr->condef);
   17648              : 
   17649          466 :                 actual_atts++;
   17650              :             }
   17651              : 
   17652         5856 :             if (actual_atts)
   17653         5585 :                 appendPQExpBufferStr(q, "\n)");
   17654          271 :             else if (!(OidIsValid(tbinfo->reloftype) && !dopt->binary_upgrade))
   17655              :             {
   17656              :                 /*
   17657              :                  * No attributes? we must have a parenthesized attribute list,
   17658              :                  * even though empty, when not using the OF TYPE syntax.
   17659              :                  */
   17660          259 :                 appendPQExpBufferStr(q, " (\n)");
   17661              :             }
   17662              : 
   17663              :             /*
   17664              :              * Emit the INHERITS clause (not for partitions), except in
   17665              :              * binary-upgrade mode.
   17666              :              */
   17667         5856 :             if (numParents > 0 && !tbinfo->ispartition &&
   17668          541 :                 !dopt->binary_upgrade)
   17669              :             {
   17670          472 :                 appendPQExpBufferStr(q, "\nINHERITS (");
   17671         1015 :                 for (k = 0; k < numParents; k++)
   17672              :                 {
   17673          543 :                     TableInfo  *parentRel = parents[k];
   17674              : 
   17675          543 :                     if (k > 0)
   17676           71 :                         appendPQExpBufferStr(q, ", ");
   17677          543 :                     appendPQExpBufferStr(q, fmtQualifiedDumpable(parentRel));
   17678              :                 }
   17679          472 :                 appendPQExpBufferChar(q, ')');
   17680              :             }
   17681              : 
   17682         5856 :             if (tbinfo->relkind == RELKIND_PARTITIONED_TABLE)
   17683          591 :                 appendPQExpBuffer(q, "\nPARTITION BY %s", partkeydef);
   17684              : 
   17685         5856 :             if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
   17686           34 :                 appendPQExpBuffer(q, "\nSERVER %s", fmtId(srvname));
   17687              :         }
   17688              : 
   17689        12229 :         if (nonemptyReloptions(tbinfo->reloptions) ||
   17690         6038 :             nonemptyReloptions(tbinfo->toast_reloptions))
   17691              :         {
   17692          153 :             bool        addcomma = false;
   17693              : 
   17694          153 :             appendPQExpBufferStr(q, "\nWITH (");
   17695          153 :             if (nonemptyReloptions(tbinfo->reloptions))
   17696              :             {
   17697          153 :                 addcomma = true;
   17698          153 :                 appendReloptionsArrayAH(q, tbinfo->reloptions, "", fout);
   17699              :             }
   17700          153 :             if (nonemptyReloptions(tbinfo->toast_reloptions))
   17701              :             {
   17702            5 :                 if (addcomma)
   17703            5 :                     appendPQExpBufferStr(q, ", ");
   17704            5 :                 appendReloptionsArrayAH(q, tbinfo->toast_reloptions, "toast.",
   17705              :                                         fout);
   17706              :             }
   17707          153 :             appendPQExpBufferChar(q, ')');
   17708              :         }
   17709              : 
   17710              :         /* Dump generic options if any */
   17711         6191 :         if (ftoptions && ftoptions[0])
   17712           32 :             appendPQExpBuffer(q, "\nOPTIONS (\n    %s\n)", ftoptions);
   17713              : 
   17714              :         /*
   17715              :          * For materialized views, create the AS clause just like a view. At
   17716              :          * this point, we always mark the view as not populated.
   17717              :          */
   17718         6191 :         if (tbinfo->relkind == RELKIND_MATVIEW)
   17719              :         {
   17720              :             PQExpBuffer result;
   17721              : 
   17722          335 :             result = createViewAsClause(fout, tbinfo);
   17723          335 :             appendPQExpBuffer(q, " AS\n%s\n  WITH NO DATA;\n",
   17724              :                               result->data);
   17725          335 :             destroyPQExpBuffer(result);
   17726              :         }
   17727              :         else
   17728         5856 :             appendPQExpBufferStr(q, ";\n");
   17729              : 
   17730              :         /* Materialized views can depend on extensions */
   17731         6191 :         if (tbinfo->relkind == RELKIND_MATVIEW)
   17732          335 :             append_depends_on_extension(fout, q, &tbinfo->dobj,
   17733              :                                         "pg_catalog.pg_class",
   17734              :                                         "MATERIALIZED VIEW",
   17735              :                                         qualrelname);
   17736              : 
   17737              :         /*
   17738              :          * in binary upgrade mode, update the catalog with any missing values
   17739              :          * that might be present.
   17740              :          */
   17741         6191 :         if (dopt->binary_upgrade)
   17742              :         {
   17743         4183 :             for (j = 0; j < tbinfo->numatts; j++)
   17744              :             {
   17745         3311 :                 if (tbinfo->attmissingval[j][0] != '\0')
   17746              :                 {
   17747            4 :                     appendPQExpBufferStr(q, "\n-- set missing value.\n");
   17748            4 :                     appendPQExpBufferStr(q,
   17749              :                                          "SELECT pg_catalog.binary_upgrade_set_missing_value(");
   17750            4 :                     appendStringLiteralAH(q, qualrelname, fout);
   17751            4 :                     appendPQExpBufferStr(q, "::pg_catalog.regclass,");
   17752            4 :                     appendStringLiteralAH(q, tbinfo->attnames[j], fout);
   17753            4 :                     appendPQExpBufferChar(q, ',');
   17754            4 :                     appendStringLiteralAH(q, tbinfo->attmissingval[j], fout);
   17755            4 :                     appendPQExpBufferStr(q, ");\n\n");
   17756              :                 }
   17757              :             }
   17758              :         }
   17759              : 
   17760              :         /*
   17761              :          * To create binary-compatible heap files, we have to ensure the same
   17762              :          * physical column order, including dropped columns, as in the
   17763              :          * original.  Therefore, we create dropped columns above and drop them
   17764              :          * here, also updating their attlen/attalign values so that the
   17765              :          * dropped column can be skipped properly.  (We do not bother with
   17766              :          * restoring the original attbyval setting.)  Also, inheritance
   17767              :          * relationships are set up by doing ALTER TABLE INHERIT rather than
   17768              :          * using an INHERITS clause --- the latter would possibly mess up the
   17769              :          * column order.  That also means we have to take care about setting
   17770              :          * attislocal correctly, plus fix up any inherited CHECK constraints.
   17771              :          * Analogously, we set up typed tables using ALTER TABLE / OF here.
   17772              :          *
   17773              :          * We process foreign and partitioned tables here, even though they
   17774              :          * lack heap storage, because they can participate in inheritance
   17775              :          * relationships and we want this stuff to be consistent across the
   17776              :          * inheritance tree.  We can exclude indexes, toast tables, sequences
   17777              :          * and matviews, even though they have storage, because we don't
   17778              :          * support altering or dropping columns in them, nor can they be part
   17779              :          * of inheritance trees.
   17780              :          */
   17781         6191 :         if (dopt->binary_upgrade &&
   17782          872 :             (tbinfo->relkind == RELKIND_RELATION ||
   17783          114 :              tbinfo->relkind == RELKIND_FOREIGN_TABLE ||
   17784          113 :              tbinfo->relkind == RELKIND_PARTITIONED_TABLE))
   17785              :         {
   17786              :             bool        firstitem;
   17787              :             bool        firstitem_extra;
   17788              : 
   17789              :             /*
   17790              :              * Drop any dropped columns.  Merge the pg_attribute manipulations
   17791              :              * into a single SQL command, so that we don't cause repeated
   17792              :              * relcache flushes on the target table.  Otherwise we risk O(N^2)
   17793              :              * relcache bloat while dropping N columns.
   17794              :              */
   17795          855 :             resetPQExpBuffer(extra);
   17796          855 :             firstitem = true;
   17797         4145 :             for (j = 0; j < tbinfo->numatts; j++)
   17798              :             {
   17799         3290 :                 if (tbinfo->attisdropped[j])
   17800              :                 {
   17801           85 :                     if (firstitem)
   17802              :                     {
   17803           39 :                         appendPQExpBufferStr(q, "\n-- For binary upgrade, recreate dropped columns.\n"
   17804              :                                              "UPDATE pg_catalog.pg_attribute\n"
   17805              :                                              "SET attlen = v.dlen, "
   17806              :                                              "attalign = v.dalign, "
   17807              :                                              "attbyval = false\n"
   17808              :                                              "FROM (VALUES ");
   17809           39 :                         firstitem = false;
   17810              :                     }
   17811              :                     else
   17812           46 :                         appendPQExpBufferStr(q, ",\n             ");
   17813           85 :                     appendPQExpBufferChar(q, '(');
   17814           85 :                     appendStringLiteralAH(q, tbinfo->attnames[j], fout);
   17815           85 :                     appendPQExpBuffer(q, ", %d, '%c')",
   17816           85 :                                       tbinfo->attlen[j],
   17817           85 :                                       tbinfo->attalign[j]);
   17818              :                     /* The ALTER ... DROP COLUMN commands must come after */
   17819           85 :                     appendPQExpBuffer(extra, "ALTER %sTABLE ONLY %s ",
   17820              :                                       foreign, qualrelname);
   17821           85 :                     appendPQExpBuffer(extra, "DROP COLUMN %s;\n",
   17822           85 :                                       fmtId(tbinfo->attnames[j]));
   17823              :                 }
   17824              :             }
   17825          855 :             if (!firstitem)
   17826              :             {
   17827           39 :                 appendPQExpBufferStr(q, ") v(dname, dlen, dalign)\n"
   17828              :                                      "WHERE attrelid = ");
   17829           39 :                 appendStringLiteralAH(q, qualrelname, fout);
   17830           39 :                 appendPQExpBufferStr(q, "::pg_catalog.regclass\n"
   17831              :                                      "  AND attname = v.dname;\n");
   17832              :                 /* Now we can issue the actual DROP COLUMN commands */
   17833           39 :                 appendBinaryPQExpBuffer(q, extra->data, extra->len);
   17834              :             }
   17835              : 
   17836              :             /*
   17837              :              * Fix up inherited columns.  As above, do the pg_attribute
   17838              :              * manipulations in a single SQL command.
   17839              :              */
   17840          855 :             firstitem = true;
   17841         4145 :             for (j = 0; j < tbinfo->numatts; j++)
   17842              :             {
   17843         3290 :                 if (!tbinfo->attisdropped[j] &&
   17844         3205 :                     !tbinfo->attislocal[j])
   17845              :                 {
   17846          640 :                     if (firstitem)
   17847              :                     {
   17848          280 :                         appendPQExpBufferStr(q, "\n-- For binary upgrade, recreate inherited columns.\n");
   17849          280 :                         appendPQExpBufferStr(q, "UPDATE pg_catalog.pg_attribute\n"
   17850              :                                              "SET attislocal = false\n"
   17851              :                                              "WHERE attrelid = ");
   17852          280 :                         appendStringLiteralAH(q, qualrelname, fout);
   17853          280 :                         appendPQExpBufferStr(q, "::pg_catalog.regclass\n"
   17854              :                                              "  AND attname IN (");
   17855          280 :                         firstitem = false;
   17856              :                     }
   17857              :                     else
   17858          360 :                         appendPQExpBufferStr(q, ", ");
   17859          640 :                     appendStringLiteralAH(q, tbinfo->attnames[j], fout);
   17860              :                 }
   17861              :             }
   17862          855 :             if (!firstitem)
   17863          280 :                 appendPQExpBufferStr(q, ");\n");
   17864              : 
   17865              :             /*
   17866              :              * Fix up not-null constraints that come from inheritance.  As
   17867              :              * above, do the pg_constraint manipulations in a single SQL
   17868              :              * command.  (Actually, two in special cases, if we're doing an
   17869              :              * upgrade from < 18).
   17870              :              */
   17871          855 :             firstitem = true;
   17872          855 :             firstitem_extra = true;
   17873          855 :             resetPQExpBuffer(extra);
   17874         4145 :             for (j = 0; j < tbinfo->numatts; j++)
   17875              :             {
   17876              :                 /*
   17877              :                  * If a not-null constraint comes from inheritance, reset
   17878              :                  * conislocal.  The inhcount is fixed by ALTER TABLE INHERIT,
   17879              :                  * below.  Special hack: in versions < 18, columns with no
   17880              :                  * local definition need their constraint to be matched by
   17881              :                  * column number in conkeys instead of by constraint name,
   17882              :                  * because the latter is not available.  (We distinguish the
   17883              :                  * case because the constraint name is the empty string.)
   17884              :                  */
   17885         3290 :                 if (tbinfo->notnull_constrs[j] != NULL &&
   17886          324 :                     !tbinfo->notnull_islocal[j])
   17887              :                 {
   17888           90 :                     if (tbinfo->notnull_constrs[j][0] != '\0')
   17889              :                     {
   17890           77 :                         if (firstitem)
   17891              :                         {
   17892           67 :                             appendPQExpBufferStr(q, "UPDATE pg_catalog.pg_constraint\n"
   17893              :                                                  "SET conislocal = false\n"
   17894              :                                                  "WHERE contype = 'n' AND conrelid = ");
   17895           67 :                             appendStringLiteralAH(q, qualrelname, fout);
   17896           67 :                             appendPQExpBufferStr(q, "::pg_catalog.regclass AND\n"
   17897              :                                                  "conname IN (");
   17898           67 :                             firstitem = false;
   17899              :                         }
   17900              :                         else
   17901           10 :                             appendPQExpBufferStr(q, ", ");
   17902           77 :                         appendStringLiteralAH(q, tbinfo->notnull_constrs[j], fout);
   17903              :                     }
   17904              :                     else
   17905              :                     {
   17906           13 :                         if (firstitem_extra)
   17907              :                         {
   17908           13 :                             appendPQExpBufferStr(extra, "UPDATE pg_catalog.pg_constraint\n"
   17909              :                                                  "SET conislocal = false\n"
   17910              :                                                  "WHERE contype = 'n' AND conrelid = ");
   17911           13 :                             appendStringLiteralAH(extra, qualrelname, fout);
   17912           13 :                             appendPQExpBufferStr(extra, "::pg_catalog.regclass AND\n"
   17913              :                                                  "conkey IN (");
   17914           13 :                             firstitem_extra = false;
   17915              :                         }
   17916              :                         else
   17917            0 :                             appendPQExpBufferStr(extra, ", ");
   17918           13 :                         appendPQExpBuffer(extra, "'{%d}'", j + 1);
   17919              :                     }
   17920              :                 }
   17921              :             }
   17922          855 :             if (!firstitem)
   17923           67 :                 appendPQExpBufferStr(q, ");\n");
   17924          855 :             if (!firstitem_extra)
   17925           13 :                 appendPQExpBufferStr(extra, ");\n");
   17926              : 
   17927          855 :             if (extra->len > 0)
   17928           13 :                 appendBinaryPQExpBuffer(q, extra->data, extra->len);
   17929              : 
   17930              :             /*
   17931              :              * Add inherited CHECK constraints, if any.
   17932              :              *
   17933              :              * For partitions, they were already dumped, and conislocal
   17934              :              * doesn't need fixing.
   17935              :              *
   17936              :              * As above, issue only one direct manipulation of pg_constraint.
   17937              :              * Although it is tempting to merge the ALTER ADD CONSTRAINT
   17938              :              * commands into one as well, refrain for now due to concern about
   17939              :              * possible backend memory bloat if there are many such
   17940              :              * constraints.
   17941              :              */
   17942          855 :             resetPQExpBuffer(extra);
   17943          855 :             firstitem = true;
   17944          917 :             for (k = 0; k < tbinfo->ncheck; k++)
   17945              :             {
   17946           62 :                 ConstraintInfo *constr = &(tbinfo->checkexprs[k]);
   17947              : 
   17948           62 :                 if (constr->separate || constr->conislocal || tbinfo->ispartition)
   17949           60 :                     continue;
   17950              : 
   17951            2 :                 if (firstitem)
   17952            2 :                     appendPQExpBufferStr(q, "\n-- For binary upgrade, set up inherited constraints.\n");
   17953            2 :                 appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s ADD CONSTRAINT %s %s;\n",
   17954              :                                   foreign, qualrelname,
   17955            2 :                                   fmtId(constr->dobj.name),
   17956              :                                   constr->condef);
   17957              :                 /* Update pg_constraint after all the ALTER TABLEs */
   17958            2 :                 if (firstitem)
   17959              :                 {
   17960            2 :                     appendPQExpBufferStr(extra, "UPDATE pg_catalog.pg_constraint\n"
   17961              :                                          "SET conislocal = false\n"
   17962              :                                          "WHERE contype = 'c' AND conrelid = ");
   17963            2 :                     appendStringLiteralAH(extra, qualrelname, fout);
   17964            2 :                     appendPQExpBufferStr(extra, "::pg_catalog.regclass\n");
   17965            2 :                     appendPQExpBufferStr(extra, "  AND conname IN (");
   17966            2 :                     firstitem = false;
   17967              :                 }
   17968              :                 else
   17969            0 :                     appendPQExpBufferStr(extra, ", ");
   17970            2 :                 appendStringLiteralAH(extra, constr->dobj.name, fout);
   17971              :             }
   17972          855 :             if (!firstitem)
   17973              :             {
   17974            2 :                 appendPQExpBufferStr(extra, ");\n");
   17975            2 :                 appendBinaryPQExpBuffer(q, extra->data, extra->len);
   17976              :             }
   17977              : 
   17978          855 :             if (numParents > 0 && !tbinfo->ispartition)
   17979              :             {
   17980           69 :                 appendPQExpBufferStr(q, "\n-- For binary upgrade, set up inheritance this way.\n");
   17981          149 :                 for (k = 0; k < numParents; k++)
   17982              :                 {
   17983           80 :                     TableInfo  *parentRel = parents[k];
   17984              : 
   17985           80 :                     appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s INHERIT %s;\n", foreign,
   17986              :                                       qualrelname,
   17987           80 :                                       fmtQualifiedDumpable(parentRel));
   17988              :                 }
   17989              :             }
   17990              : 
   17991          855 :             if (OidIsValid(tbinfo->reloftype))
   17992              :             {
   17993            6 :                 appendPQExpBufferStr(q, "\n-- For binary upgrade, set up typed tables this way.\n");
   17994            6 :                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s OF %s;\n",
   17995              :                                   qualrelname,
   17996            6 :                                   getFormattedTypeName(fout, tbinfo->reloftype,
   17997              :                                                        zeroIsError));
   17998              :             }
   17999              :         }
   18000              : 
   18001              :         /*
   18002              :          * In binary_upgrade mode, arrange to restore the old relfrozenxid and
   18003              :          * relminmxid of all vacuumable relations.  (While vacuum.c processes
   18004              :          * TOAST tables semi-independently, here we see them only as children
   18005              :          * of other relations; so this "if" lacks RELKIND_TOASTVALUE, and the
   18006              :          * child toast table is handled below.)
   18007              :          */
   18008         6191 :         if (dopt->binary_upgrade &&
   18009          872 :             (tbinfo->relkind == RELKIND_RELATION ||
   18010          114 :              tbinfo->relkind == RELKIND_MATVIEW))
   18011              :         {
   18012          775 :             appendPQExpBufferStr(q, "\n-- For binary upgrade, set heap's relfrozenxid and relminmxid\n");
   18013          775 :             appendPQExpBuffer(q, "UPDATE pg_catalog.pg_class\n"
   18014              :                               "SET relfrozenxid = '%u', relminmxid = '%u'\n"
   18015              :                               "WHERE oid = ",
   18016          775 :                               tbinfo->frozenxid, tbinfo->minmxid);
   18017          775 :             appendStringLiteralAH(q, qualrelname, fout);
   18018          775 :             appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
   18019              : 
   18020          775 :             if (tbinfo->toast_oid)
   18021              :             {
   18022              :                 /*
   18023              :                  * The toast table will have the same OID at restore, so we
   18024              :                  * can safely target it by OID.
   18025              :                  */
   18026          294 :                 appendPQExpBufferStr(q, "\n-- For binary upgrade, set toast's relfrozenxid and relminmxid\n");
   18027          294 :                 appendPQExpBuffer(q, "UPDATE pg_catalog.pg_class\n"
   18028              :                                   "SET relfrozenxid = '%u', relminmxid = '%u'\n"
   18029              :                                   "WHERE oid = '%u';\n",
   18030          294 :                                   tbinfo->toast_frozenxid,
   18031          294 :                                   tbinfo->toast_minmxid, tbinfo->toast_oid);
   18032              :             }
   18033              :         }
   18034              : 
   18035              :         /*
   18036              :          * In binary_upgrade mode, restore matviews' populated status by
   18037              :          * poking pg_class directly.  This is pretty ugly, but we can't use
   18038              :          * REFRESH MATERIALIZED VIEW since it's possible that some underlying
   18039              :          * matview is not populated even though this matview is; in any case,
   18040              :          * we want to transfer the matview's heap storage, not run REFRESH.
   18041              :          */
   18042         6191 :         if (dopt->binary_upgrade && tbinfo->relkind == RELKIND_MATVIEW &&
   18043           17 :             tbinfo->relispopulated)
   18044              :         {
   18045           15 :             appendPQExpBufferStr(q, "\n-- For binary upgrade, mark materialized view as populated\n");
   18046           15 :             appendPQExpBufferStr(q, "UPDATE pg_catalog.pg_class\n"
   18047              :                                  "SET relispopulated = 't'\n"
   18048              :                                  "WHERE oid = ");
   18049           15 :             appendStringLiteralAH(q, qualrelname, fout);
   18050           15 :             appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
   18051              :         }
   18052              : 
   18053              :         /*
   18054              :          * Dump additional per-column properties that we can't handle in the
   18055              :          * main CREATE TABLE command.
   18056              :          */
   18057        27735 :         for (j = 0; j < tbinfo->numatts; j++)
   18058              :         {
   18059              :             /* None of this applies to dropped columns */
   18060        21544 :             if (tbinfo->attisdropped[j])
   18061          452 :                 continue;
   18062              : 
   18063              :             /*
   18064              :              * Dump per-column statistics information. We only issue an ALTER
   18065              :              * TABLE statement if the attstattarget entry for this column is
   18066              :              * not the default value.
   18067              :              */
   18068        21092 :             if (tbinfo->attstattarget[j] >= 0)
   18069           32 :                 appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s ALTER COLUMN %s SET STATISTICS %d;\n",
   18070              :                                   foreign, qualrelname,
   18071           32 :                                   fmtId(tbinfo->attnames[j]),
   18072           32 :                                   tbinfo->attstattarget[j]);
   18073              : 
   18074              :             /*
   18075              :              * Dump per-column storage information.  The statement is only
   18076              :              * dumped if the storage has been changed from the type's default.
   18077              :              */
   18078        21092 :             if (tbinfo->attstorage[j] != tbinfo->typstorage[j])
   18079              :             {
   18080           79 :                 switch (tbinfo->attstorage[j])
   18081              :                 {
   18082           10 :                     case TYPSTORAGE_PLAIN:
   18083           10 :                         storage = "PLAIN";
   18084           10 :                         break;
   18085           37 :                     case TYPSTORAGE_EXTERNAL:
   18086           37 :                         storage = "EXTERNAL";
   18087           37 :                         break;
   18088            0 :                     case TYPSTORAGE_EXTENDED:
   18089            0 :                         storage = "EXTENDED";
   18090            0 :                         break;
   18091           32 :                     case TYPSTORAGE_MAIN:
   18092           32 :                         storage = "MAIN";
   18093           32 :                         break;
   18094            0 :                     default:
   18095            0 :                         storage = NULL;
   18096              :                 }
   18097              : 
   18098              :                 /*
   18099              :                  * Only dump the statement if it's a storage type we recognize
   18100              :                  */
   18101           79 :                 if (storage != NULL)
   18102           79 :                     appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s ALTER COLUMN %s SET STORAGE %s;\n",
   18103              :                                       foreign, qualrelname,
   18104           79 :                                       fmtId(tbinfo->attnames[j]),
   18105              :                                       storage);
   18106              :             }
   18107              : 
   18108              :             /*
   18109              :              * Dump per-column compression, if it's been set.
   18110              :              */
   18111        21092 :             if (!dopt->no_toast_compression)
   18112              :             {
   18113              :                 const char *cmname;
   18114              : 
   18115        20992 :                 switch (tbinfo->attcompression[j])
   18116              :                 {
   18117           71 :                     case 'p':
   18118           71 :                         cmname = "pglz";
   18119           71 :                         break;
   18120           39 :                     case 'l':
   18121           39 :                         cmname = "lz4";
   18122           39 :                         break;
   18123        20882 :                     default:
   18124        20882 :                         cmname = NULL;
   18125        20882 :                         break;
   18126              :                 }
   18127              : 
   18128        20992 :                 if (cmname != NULL)
   18129          110 :                     appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s ALTER COLUMN %s SET COMPRESSION %s;\n",
   18130              :                                       foreign, qualrelname,
   18131          110 :                                       fmtId(tbinfo->attnames[j]),
   18132              :                                       cmname);
   18133              :             }
   18134              : 
   18135              :             /*
   18136              :              * Dump per-column attributes.
   18137              :              */
   18138        21092 :             if (tbinfo->attoptions[j][0] != '\0')
   18139           32 :                 appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s ALTER COLUMN %s SET (%s);\n",
   18140              :                                   foreign, qualrelname,
   18141           32 :                                   fmtId(tbinfo->attnames[j]),
   18142           32 :                                   tbinfo->attoptions[j]);
   18143              : 
   18144              :             /*
   18145              :              * Dump per-column fdw options.
   18146              :              */
   18147        21092 :             if (tbinfo->relkind == RELKIND_FOREIGN_TABLE &&
   18148           34 :                 tbinfo->attfdwoptions[j][0] != '\0')
   18149           32 :                 appendPQExpBuffer(q,
   18150              :                                   "ALTER FOREIGN TABLE ONLY %s ALTER COLUMN %s OPTIONS (\n"
   18151              :                                   "    %s\n"
   18152              :                                   ");\n",
   18153              :                                   qualrelname,
   18154           32 :                                   fmtId(tbinfo->attnames[j]),
   18155           32 :                                   tbinfo->attfdwoptions[j]);
   18156              :         }                       /* end loop over columns */
   18157              : 
   18158         6191 :         free(partkeydef);
   18159         6191 :         free(ftoptions);
   18160         6191 :         free(srvname);
   18161              :     }
   18162              : 
   18163              :     /*
   18164              :      * dump properties we only have ALTER TABLE syntax for
   18165              :      */
   18166         6842 :     if ((tbinfo->relkind == RELKIND_RELATION ||
   18167         1611 :          tbinfo->relkind == RELKIND_PARTITIONED_TABLE ||
   18168         1020 :          tbinfo->relkind == RELKIND_MATVIEW) &&
   18169         6157 :         tbinfo->relreplident != REPLICA_IDENTITY_DEFAULT)
   18170              :     {
   18171          207 :         if (tbinfo->relreplident == REPLICA_IDENTITY_INDEX)
   18172              :         {
   18173              :             /* nothing to do, will be set when the index is dumped */
   18174              :         }
   18175          207 :         else if (tbinfo->relreplident == REPLICA_IDENTITY_NOTHING)
   18176              :         {
   18177          207 :             appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY NOTHING;\n",
   18178              :                               qualrelname);
   18179              :         }
   18180            0 :         else if (tbinfo->relreplident == REPLICA_IDENTITY_FULL)
   18181              :         {
   18182            0 :             appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY FULL;\n",
   18183              :                               qualrelname);
   18184              :         }
   18185              :     }
   18186              : 
   18187         6842 :     if (tbinfo->forcerowsec)
   18188           10 :         appendPQExpBuffer(q, "\nALTER TABLE ONLY %s FORCE ROW LEVEL SECURITY;\n",
   18189              :                           qualrelname);
   18190              : 
   18191         6842 :     appendPQExpBuffer(delq, "DROP %s %s;\n", reltypename, qualrelname);
   18192              : 
   18193         6842 :     if (dopt->binary_upgrade)
   18194          941 :         binary_upgrade_extension_member(q, &tbinfo->dobj,
   18195              :                                         reltypename, qrelname,
   18196          941 :                                         tbinfo->dobj.namespace->dobj.name);
   18197              : 
   18198         6842 :     if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   18199              :     {
   18200         6842 :         char       *tablespace = NULL;
   18201         6842 :         char       *tableam = NULL;
   18202              : 
   18203              :         /*
   18204              :          * _selectTablespace() relies on tablespace-enabled objects in the
   18205              :          * default tablespace to have a tablespace of "" (empty string) versus
   18206              :          * non-tablespace-enabled objects to have a tablespace of NULL.
   18207              :          * getTables() sets tbinfo->reltablespace to "" for the default
   18208              :          * tablespace (not NULL).
   18209              :          */
   18210         6842 :         if (RELKIND_HAS_TABLESPACE(tbinfo->relkind))
   18211         6157 :             tablespace = tbinfo->reltablespace;
   18212              : 
   18213         6842 :         if (RELKIND_HAS_TABLE_AM(tbinfo->relkind) ||
   18214         1276 :             tbinfo->relkind == RELKIND_PARTITIONED_TABLE)
   18215         6157 :             tableam = tbinfo->amname;
   18216              : 
   18217         6842 :         ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
   18218         6842 :                      ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
   18219              :                                   .namespace = tbinfo->dobj.namespace->dobj.name,
   18220              :                                   .tablespace = tablespace,
   18221              :                                   .tableam = tableam,
   18222              :                                   .relkind = tbinfo->relkind,
   18223              :                                   .owner = tbinfo->rolname,
   18224              :                                   .description = reltypename,
   18225              :                                   .section = tbinfo->postponed_def ?
   18226              :                                   SECTION_POST_DATA : SECTION_PRE_DATA,
   18227              :                                   .createStmt = q->data,
   18228              :                                   .dropStmt = delq->data));
   18229              :     }
   18230              : 
   18231              :     /* Dump Table Comments */
   18232         6842 :     if (tbinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   18233           74 :         dumpTableComment(fout, tbinfo, reltypename);
   18234              : 
   18235              :     /* Dump Table Security Labels */
   18236         6842 :     if (tbinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
   18237            0 :         dumpTableSecLabel(fout, tbinfo, reltypename);
   18238              : 
   18239              :     /*
   18240              :      * Dump comments for not-null constraints that aren't to be dumped
   18241              :      * separately (those are processed by collectComments/dumpComment).
   18242              :      */
   18243         6842 :     if (!fout->dopt->no_comments && dopt->dumpSchema &&
   18244         6842 :         fout->remoteVersion >= 180000)
   18245              :     {
   18246         6842 :         PQExpBuffer comment = NULL;
   18247         6842 :         PQExpBuffer tag = NULL;
   18248              : 
   18249        31947 :         for (j = 0; j < tbinfo->numatts; j++)
   18250              :         {
   18251        25105 :             if (tbinfo->notnull_constrs[j] != NULL &&
   18252         2622 :                 tbinfo->notnull_comment[j] != NULL)
   18253              :             {
   18254           42 :                 if (comment == NULL)
   18255              :                 {
   18256           42 :                     comment = createPQExpBuffer();
   18257           42 :                     tag = createPQExpBuffer();
   18258              :                 }
   18259              :                 else
   18260              :                 {
   18261            0 :                     resetPQExpBuffer(comment);
   18262            0 :                     resetPQExpBuffer(tag);
   18263              :                 }
   18264              : 
   18265           42 :                 appendPQExpBuffer(comment, "COMMENT ON CONSTRAINT %s ON %s IS ",
   18266           42 :                                   fmtId(tbinfo->notnull_constrs[j]), qualrelname);
   18267           42 :                 appendStringLiteralAH(comment, tbinfo->notnull_comment[j], fout);
   18268           42 :                 appendPQExpBufferStr(comment, ";\n");
   18269              : 
   18270           42 :                 appendPQExpBuffer(tag, "CONSTRAINT %s ON %s",
   18271           42 :                                   fmtId(tbinfo->notnull_constrs[j]), qrelname);
   18272              : 
   18273           42 :                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
   18274           42 :                              ARCHIVE_OPTS(.tag = tag->data,
   18275              :                                           .namespace = tbinfo->dobj.namespace->dobj.name,
   18276              :                                           .owner = tbinfo->rolname,
   18277              :                                           .description = "COMMENT",
   18278              :                                           .section = SECTION_NONE,
   18279              :                                           .createStmt = comment->data,
   18280              :                                           .deps = &(tbinfo->dobj.dumpId),
   18281              :                                           .nDeps = 1));
   18282              :             }
   18283              :         }
   18284              : 
   18285         6842 :         destroyPQExpBuffer(comment);
   18286         6842 :         destroyPQExpBuffer(tag);
   18287              :     }
   18288              : 
   18289              :     /* Dump comments on inlined table constraints */
   18290         7415 :     for (j = 0; j < tbinfo->ncheck; j++)
   18291              :     {
   18292          573 :         ConstraintInfo *constr = &(tbinfo->checkexprs[j]);
   18293              : 
   18294          573 :         if (constr->separate || !constr->conislocal)
   18295          244 :             continue;
   18296              : 
   18297          329 :         if (constr->dobj.dump & DUMP_COMPONENT_COMMENT)
   18298           37 :             dumpTableConstraintComment(fout, constr);
   18299              :     }
   18300              : 
   18301         6842 :     destroyPQExpBuffer(q);
   18302         6842 :     destroyPQExpBuffer(delq);
   18303         6842 :     destroyPQExpBuffer(extra);
   18304         6842 :     free(qrelname);
   18305         6842 :     free(qualrelname);
   18306         6842 : }
   18307              : 
   18308              : /*
   18309              :  * dumpTableAttach
   18310              :  *    write to fout the commands to attach a child partition
   18311              :  *
   18312              :  * Child partitions are always made by creating them separately
   18313              :  * and then using ATTACH PARTITION, rather than using
   18314              :  * CREATE TABLE ... PARTITION OF.  This is important for preserving
   18315              :  * any possible discrepancy in column layout, to allow assigning the
   18316              :  * correct tablespace if different, and so that it's possible to restore
   18317              :  * a partition without restoring its parent.  (You'll get an error from
   18318              :  * the ATTACH PARTITION command, but that can be ignored, or skipped
   18319              :  * using "pg_restore -L" if you prefer.)  The last point motivates
   18320              :  * treating ATTACH PARTITION as a completely separate ArchiveEntry
   18321              :  * rather than emitting it within the child partition's ArchiveEntry.
   18322              :  */
   18323              : static void
   18324         1421 : dumpTableAttach(Archive *fout, const TableAttachInfo *attachinfo)
   18325              : {
   18326         1421 :     DumpOptions *dopt = fout->dopt;
   18327              :     PQExpBuffer q;
   18328              :     PGresult   *res;
   18329              :     char       *partbound;
   18330              : 
   18331              :     /* Do nothing if not dumping schema */
   18332         1421 :     if (!dopt->dumpSchema)
   18333           54 :         return;
   18334              : 
   18335         1367 :     q = createPQExpBuffer();
   18336              : 
   18337         1367 :     if (!fout->is_prepared[PREPQUERY_DUMPTABLEATTACH])
   18338              :     {
   18339              :         /* Set up query for partbound details */
   18340           43 :         appendPQExpBufferStr(q,
   18341              :                              "PREPARE dumpTableAttach(pg_catalog.oid) AS\n");
   18342              : 
   18343           43 :         appendPQExpBufferStr(q,
   18344              :                              "SELECT pg_get_expr(c.relpartbound, c.oid) "
   18345              :                              "FROM pg_class c "
   18346              :                              "WHERE c.oid = $1");
   18347              : 
   18348           43 :         ExecuteSqlStatement(fout, q->data);
   18349              : 
   18350           43 :         fout->is_prepared[PREPQUERY_DUMPTABLEATTACH] = true;
   18351              :     }
   18352              : 
   18353         1367 :     printfPQExpBuffer(q,
   18354              :                       "EXECUTE dumpTableAttach('%u')",
   18355         1367 :                       attachinfo->partitionTbl->dobj.catId.oid);
   18356              : 
   18357         1367 :     res = ExecuteSqlQueryForSingleRow(fout, q->data);
   18358         1367 :     partbound = PQgetvalue(res, 0, 0);
   18359              : 
   18360              :     /* Perform ALTER TABLE on the parent */
   18361         1367 :     printfPQExpBuffer(q,
   18362              :                       "ALTER TABLE ONLY %s ",
   18363         1367 :                       fmtQualifiedDumpable(attachinfo->parentTbl));
   18364         1367 :     appendPQExpBuffer(q,
   18365              :                       "ATTACH PARTITION %s %s;\n",
   18366         1367 :                       fmtQualifiedDumpable(attachinfo->partitionTbl),
   18367              :                       partbound);
   18368              : 
   18369              :     /*
   18370              :      * There is no point in creating a drop query as the drop is done by table
   18371              :      * drop.  (If you think to change this, see also _printTocEntry().)
   18372              :      * Although this object doesn't really have ownership as such, set the
   18373              :      * owner field anyway to ensure that the command is run by the correct
   18374              :      * role at restore time.
   18375              :      */
   18376         1367 :     ArchiveEntry(fout, attachinfo->dobj.catId, attachinfo->dobj.dumpId,
   18377         1367 :                  ARCHIVE_OPTS(.tag = attachinfo->dobj.name,
   18378              :                               .namespace = attachinfo->dobj.namespace->dobj.name,
   18379              :                               .owner = attachinfo->partitionTbl->rolname,
   18380              :                               .description = "TABLE ATTACH",
   18381              :                               .section = SECTION_PRE_DATA,
   18382              :                               .createStmt = q->data));
   18383              : 
   18384         1367 :     PQclear(res);
   18385         1367 :     destroyPQExpBuffer(q);
   18386              : }
   18387              : 
   18388              : /*
   18389              :  * dumpAttrDef --- dump an attribute's default-value declaration
   18390              :  */
   18391              : static void
   18392         1047 : dumpAttrDef(Archive *fout, const AttrDefInfo *adinfo)
   18393              : {
   18394         1047 :     DumpOptions *dopt = fout->dopt;
   18395         1047 :     TableInfo  *tbinfo = adinfo->adtable;
   18396         1047 :     int         adnum = adinfo->adnum;
   18397              :     PQExpBuffer q;
   18398              :     PQExpBuffer delq;
   18399              :     char       *qualrelname;
   18400              :     char       *tag;
   18401              :     char       *foreign;
   18402              : 
   18403              :     /* Do nothing if not dumping schema */
   18404         1047 :     if (!dopt->dumpSchema)
   18405            0 :         return;
   18406              : 
   18407              :     /* Skip if not "separate"; it was dumped in the table's definition */
   18408         1047 :     if (!adinfo->separate)
   18409          881 :         return;
   18410              : 
   18411          166 :     q = createPQExpBuffer();
   18412          166 :     delq = createPQExpBuffer();
   18413              : 
   18414          166 :     qualrelname = pg_strdup(fmtQualifiedDumpable(tbinfo));
   18415              : 
   18416          166 :     foreign = tbinfo->relkind == RELKIND_FOREIGN_TABLE ? "FOREIGN " : "";
   18417              : 
   18418          166 :     appendPQExpBuffer(q,
   18419              :                       "ALTER %sTABLE ONLY %s ALTER COLUMN %s SET DEFAULT %s;\n",
   18420          166 :                       foreign, qualrelname, fmtId(tbinfo->attnames[adnum - 1]),
   18421          166 :                       adinfo->adef_expr);
   18422              : 
   18423          166 :     appendPQExpBuffer(delq, "ALTER %sTABLE %s ALTER COLUMN %s DROP DEFAULT;\n",
   18424              :                       foreign, qualrelname,
   18425          166 :                       fmtId(tbinfo->attnames[adnum - 1]));
   18426              : 
   18427          166 :     tag = psprintf("%s %s", tbinfo->dobj.name, tbinfo->attnames[adnum - 1]);
   18428              : 
   18429          166 :     if (adinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   18430          166 :         ArchiveEntry(fout, adinfo->dobj.catId, adinfo->dobj.dumpId,
   18431          166 :                      ARCHIVE_OPTS(.tag = tag,
   18432              :                                   .namespace = tbinfo->dobj.namespace->dobj.name,
   18433              :                                   .owner = tbinfo->rolname,
   18434              :                                   .description = "DEFAULT",
   18435              :                                   .section = SECTION_PRE_DATA,
   18436              :                                   .createStmt = q->data,
   18437              :                                   .dropStmt = delq->data));
   18438              : 
   18439          166 :     free(tag);
   18440          166 :     destroyPQExpBuffer(q);
   18441          166 :     destroyPQExpBuffer(delq);
   18442          166 :     free(qualrelname);
   18443              : }
   18444              : 
   18445              : /*
   18446              :  * getAttrName: extract the correct name for an attribute
   18447              :  *
   18448              :  * The array tblInfo->attnames[] only provides names of user attributes;
   18449              :  * if a system attribute number is supplied, we have to fake it.
   18450              :  * We also do a little bit of bounds checking for safety's sake.
   18451              :  */
   18452              : static const char *
   18453         2235 : getAttrName(int attrnum, const TableInfo *tblInfo)
   18454              : {
   18455         2235 :     if (attrnum > 0 && attrnum <= tblInfo->numatts)
   18456         2235 :         return tblInfo->attnames[attrnum - 1];
   18457            0 :     switch (attrnum)
   18458              :     {
   18459            0 :         case SelfItemPointerAttributeNumber:
   18460            0 :             return "ctid";
   18461            0 :         case MinTransactionIdAttributeNumber:
   18462            0 :             return "xmin";
   18463            0 :         case MinCommandIdAttributeNumber:
   18464            0 :             return "cmin";
   18465            0 :         case MaxTransactionIdAttributeNumber:
   18466            0 :             return "xmax";
   18467            0 :         case MaxCommandIdAttributeNumber:
   18468            0 :             return "cmax";
   18469            0 :         case TableOidAttributeNumber:
   18470            0 :             return "tableoid";
   18471              :     }
   18472            0 :     pg_fatal("invalid column number %d for table \"%s\"",
   18473              :              attrnum, tblInfo->dobj.name);
   18474              :     return NULL;                /* keep compiler quiet */
   18475              : }
   18476              : 
   18477              : /*
   18478              :  * dumpIndex
   18479              :  *    write out to fout a user-defined index
   18480              :  */
   18481              : static void
   18482         2758 : dumpIndex(Archive *fout, const IndxInfo *indxinfo)
   18483              : {
   18484         2758 :     DumpOptions *dopt = fout->dopt;
   18485         2758 :     TableInfo  *tbinfo = indxinfo->indextable;
   18486         2758 :     bool        is_constraint = (indxinfo->indexconstraint != 0);
   18487              :     PQExpBuffer q;
   18488              :     PQExpBuffer delq;
   18489              :     char       *qindxname;
   18490              :     char       *qqindxname;
   18491              : 
   18492              :     /* Do nothing if not dumping schema */
   18493         2758 :     if (!dopt->dumpSchema)
   18494          117 :         return;
   18495              : 
   18496         2641 :     q = createPQExpBuffer();
   18497         2641 :     delq = createPQExpBuffer();
   18498              : 
   18499         2641 :     qindxname = pg_strdup(fmtId(indxinfo->dobj.name));
   18500         2641 :     qqindxname = pg_strdup(fmtQualifiedDumpable(indxinfo));
   18501              : 
   18502              :     /*
   18503              :      * If there's an associated constraint, don't dump the index per se, but
   18504              :      * do dump any comment for it.  (This is safe because dependency ordering
   18505              :      * will have ensured the constraint is emitted first.)  Note that the
   18506              :      * emitted comment has to be shown as depending on the constraint, not the
   18507              :      * index, in such cases.
   18508              :      */
   18509         2641 :     if (!is_constraint)
   18510              :     {
   18511         1048 :         char       *indstatcols = indxinfo->indstatcols;
   18512         1048 :         char       *indstatvals = indxinfo->indstatvals;
   18513         1048 :         char      **indstatcolsarray = NULL;
   18514         1048 :         char      **indstatvalsarray = NULL;
   18515         1048 :         int         nstatcols = 0;
   18516         1048 :         int         nstatvals = 0;
   18517              : 
   18518         1048 :         if (dopt->binary_upgrade)
   18519          158 :             binary_upgrade_set_pg_class_oids(fout, q,
   18520          158 :                                              indxinfo->dobj.catId.oid);
   18521              : 
   18522              :         /* Plain secondary index */
   18523         1048 :         appendPQExpBuffer(q, "%s;\n", indxinfo->indexdef);
   18524              : 
   18525              :         /*
   18526              :          * Append ALTER TABLE commands as needed to set properties that we
   18527              :          * only have ALTER TABLE syntax for.  Keep this in sync with the
   18528              :          * similar code in dumpConstraint!
   18529              :          */
   18530              : 
   18531              :         /* If the index is clustered, we need to record that. */
   18532         1048 :         if (indxinfo->indisclustered)
   18533              :         {
   18534            5 :             appendPQExpBuffer(q, "\nALTER TABLE %s CLUSTER",
   18535            5 :                               fmtQualifiedDumpable(tbinfo));
   18536              :             /* index name is not qualified in this syntax */
   18537            5 :             appendPQExpBuffer(q, " ON %s;\n",
   18538              :                               qindxname);
   18539              :         }
   18540              : 
   18541              :         /*
   18542              :          * If the index has any statistics on some of its columns, generate
   18543              :          * the associated ALTER INDEX queries.
   18544              :          */
   18545         1048 :         if (strlen(indstatcols) != 0 || strlen(indstatvals) != 0)
   18546              :         {
   18547              :             int         j;
   18548              : 
   18549           32 :             if (!parsePGArray(indstatcols, &indstatcolsarray, &nstatcols))
   18550            0 :                 pg_fatal("could not parse index statistic columns");
   18551           32 :             if (!parsePGArray(indstatvals, &indstatvalsarray, &nstatvals))
   18552            0 :                 pg_fatal("could not parse index statistic values");
   18553           32 :             if (nstatcols != nstatvals)
   18554            0 :                 pg_fatal("mismatched number of columns and values for index statistics");
   18555              : 
   18556           96 :             for (j = 0; j < nstatcols; j++)
   18557              :             {
   18558           64 :                 appendPQExpBuffer(q, "ALTER INDEX %s ", qqindxname);
   18559              : 
   18560              :                 /*
   18561              :                  * Note that this is a column number, so no quotes should be
   18562              :                  * used.
   18563              :                  */
   18564           64 :                 appendPQExpBuffer(q, "ALTER COLUMN %s ",
   18565           64 :                                   indstatcolsarray[j]);
   18566           64 :                 appendPQExpBuffer(q, "SET STATISTICS %s;\n",
   18567           64 :                                   indstatvalsarray[j]);
   18568              :             }
   18569              :         }
   18570              : 
   18571              :         /* Indexes can depend on extensions */
   18572         1048 :         append_depends_on_extension(fout, q, &indxinfo->dobj,
   18573              :                                     "pg_catalog.pg_class",
   18574              :                                     "INDEX", qqindxname);
   18575              : 
   18576              :         /* If the index defines identity, we need to record that. */
   18577         1048 :         if (indxinfo->indisreplident)
   18578              :         {
   18579            0 :             appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY USING",
   18580            0 :                               fmtQualifiedDumpable(tbinfo));
   18581              :             /* index name is not qualified in this syntax */
   18582            0 :             appendPQExpBuffer(q, " INDEX %s;\n",
   18583              :                               qindxname);
   18584              :         }
   18585              : 
   18586              :         /*
   18587              :          * If this index is a member of a partitioned index, the backend will
   18588              :          * not allow us to drop it separately, so don't try.  It will go away
   18589              :          * automatically when we drop either the index's table or the
   18590              :          * partitioned index.  (If, in a selective restore with --clean, we
   18591              :          * drop neither of those, then this index will not be dropped either.
   18592              :          * But that's fine, and even if you think it's not, the backend won't
   18593              :          * let us do differently.)
   18594              :          */
   18595         1048 :         if (indxinfo->parentidx == 0)
   18596          866 :             appendPQExpBuffer(delq, "DROP INDEX %s;\n", qqindxname);
   18597              : 
   18598         1048 :         if (indxinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   18599         1048 :             ArchiveEntry(fout, indxinfo->dobj.catId, indxinfo->dobj.dumpId,
   18600         1048 :                          ARCHIVE_OPTS(.tag = indxinfo->dobj.name,
   18601              :                                       .namespace = tbinfo->dobj.namespace->dobj.name,
   18602              :                                       .tablespace = indxinfo->tablespace,
   18603              :                                       .owner = tbinfo->rolname,
   18604              :                                       .description = "INDEX",
   18605              :                                       .section = SECTION_POST_DATA,
   18606              :                                       .createStmt = q->data,
   18607              :                                       .dropStmt = delq->data));
   18608              : 
   18609         1048 :         free(indstatcolsarray);
   18610         1048 :         free(indstatvalsarray);
   18611              :     }
   18612              : 
   18613              :     /* Dump Index Comments */
   18614         2641 :     if (indxinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   18615           15 :         dumpComment(fout, "INDEX", qindxname,
   18616           15 :                     tbinfo->dobj.namespace->dobj.name,
   18617              :                     tbinfo->rolname,
   18618              :                     indxinfo->dobj.catId, 0,
   18619              :                     is_constraint ? indxinfo->indexconstraint :
   18620              :                     indxinfo->dobj.dumpId);
   18621              : 
   18622         2641 :     destroyPQExpBuffer(q);
   18623         2641 :     destroyPQExpBuffer(delq);
   18624         2641 :     free(qindxname);
   18625         2641 :     free(qqindxname);
   18626              : }
   18627              : 
   18628              : /*
   18629              :  * dumpIndexAttach
   18630              :  *    write out to fout a partitioned-index attachment clause
   18631              :  */
   18632              : static void
   18633          594 : dumpIndexAttach(Archive *fout, const IndexAttachInfo *attachinfo)
   18634              : {
   18635              :     /* Do nothing if not dumping schema */
   18636          594 :     if (!fout->dopt->dumpSchema)
   18637           48 :         return;
   18638              : 
   18639          546 :     if (attachinfo->partitionIdx->dobj.dump & DUMP_COMPONENT_DEFINITION)
   18640              :     {
   18641          546 :         PQExpBuffer q = createPQExpBuffer();
   18642              : 
   18643          546 :         appendPQExpBuffer(q, "ALTER INDEX %s ",
   18644          546 :                           fmtQualifiedDumpable(attachinfo->parentIdx));
   18645          546 :         appendPQExpBuffer(q, "ATTACH PARTITION %s;\n",
   18646          546 :                           fmtQualifiedDumpable(attachinfo->partitionIdx));
   18647              : 
   18648              :         /*
   18649              :          * There is no need for a dropStmt since the drop is done implicitly
   18650              :          * when we drop either the index's table or the partitioned index.
   18651              :          * Moreover, since there's no ALTER INDEX DETACH PARTITION command,
   18652              :          * there's no way to do it anyway.  (If you think to change this,
   18653              :          * consider also what to do with --if-exists.)
   18654              :          *
   18655              :          * Although this object doesn't really have ownership as such, set the
   18656              :          * owner field anyway to ensure that the command is run by the correct
   18657              :          * role at restore time.
   18658              :          */
   18659          546 :         ArchiveEntry(fout, attachinfo->dobj.catId, attachinfo->dobj.dumpId,
   18660          546 :                      ARCHIVE_OPTS(.tag = attachinfo->dobj.name,
   18661              :                                   .namespace = attachinfo->dobj.namespace->dobj.name,
   18662              :                                   .owner = attachinfo->parentIdx->indextable->rolname,
   18663              :                                   .description = "INDEX ATTACH",
   18664              :                                   .section = SECTION_POST_DATA,
   18665              :                                   .createStmt = q->data));
   18666              : 
   18667          546 :         destroyPQExpBuffer(q);
   18668              :     }
   18669              : }
   18670              : 
   18671              : /*
   18672              :  * dumpStatisticsExt
   18673              :  *    write out to fout an extended statistics object
   18674              :  */
   18675              : static void
   18676          171 : dumpStatisticsExt(Archive *fout, const StatsExtInfo *statsextinfo)
   18677              : {
   18678          171 :     DumpOptions *dopt = fout->dopt;
   18679              :     PQExpBuffer q;
   18680              :     PQExpBuffer delq;
   18681              :     PQExpBuffer query;
   18682              :     char       *qstatsextname;
   18683              :     PGresult   *res;
   18684              :     char       *stxdef;
   18685              : 
   18686              :     /* Do nothing if not dumping schema */
   18687          171 :     if (!dopt->dumpSchema)
   18688           24 :         return;
   18689              : 
   18690          147 :     q = createPQExpBuffer();
   18691          147 :     delq = createPQExpBuffer();
   18692          147 :     query = createPQExpBuffer();
   18693              : 
   18694          147 :     qstatsextname = pg_strdup(fmtId(statsextinfo->dobj.name));
   18695              : 
   18696          147 :     appendPQExpBuffer(query, "SELECT "
   18697              :                       "pg_catalog.pg_get_statisticsobjdef('%u'::pg_catalog.oid)",
   18698          147 :                       statsextinfo->dobj.catId.oid);
   18699              : 
   18700          147 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   18701              : 
   18702          147 :     stxdef = PQgetvalue(res, 0, 0);
   18703              : 
   18704              :     /* Result of pg_get_statisticsobjdef is complete except for semicolon */
   18705          147 :     appendPQExpBuffer(q, "%s;\n", stxdef);
   18706              : 
   18707              :     /*
   18708              :      * We only issue an ALTER STATISTICS statement if the stxstattarget entry
   18709              :      * for this statistics object is not the default value.
   18710              :      */
   18711          147 :     if (statsextinfo->stattarget >= 0)
   18712              :     {
   18713           32 :         appendPQExpBuffer(q, "ALTER STATISTICS %s ",
   18714           32 :                           fmtQualifiedDumpable(statsextinfo));
   18715           32 :         appendPQExpBuffer(q, "SET STATISTICS %d;\n",
   18716           32 :                           statsextinfo->stattarget);
   18717              :     }
   18718              : 
   18719          147 :     appendPQExpBuffer(delq, "DROP STATISTICS %s;\n",
   18720          147 :                       fmtQualifiedDumpable(statsextinfo));
   18721              : 
   18722          147 :     if (statsextinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   18723          147 :         ArchiveEntry(fout, statsextinfo->dobj.catId,
   18724          147 :                      statsextinfo->dobj.dumpId,
   18725          147 :                      ARCHIVE_OPTS(.tag = statsextinfo->dobj.name,
   18726              :                                   .namespace = statsextinfo->dobj.namespace->dobj.name,
   18727              :                                   .owner = statsextinfo->rolname,
   18728              :                                   .description = "STATISTICS",
   18729              :                                   .section = SECTION_POST_DATA,
   18730              :                                   .createStmt = q->data,
   18731              :                                   .dropStmt = delq->data));
   18732              : 
   18733              :     /* Dump Statistics Comments */
   18734          147 :     if (statsextinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   18735            0 :         dumpComment(fout, "STATISTICS", qstatsextname,
   18736            0 :                     statsextinfo->dobj.namespace->dobj.name,
   18737            0 :                     statsextinfo->rolname,
   18738              :                     statsextinfo->dobj.catId, 0,
   18739            0 :                     statsextinfo->dobj.dumpId);
   18740              : 
   18741          147 :     PQclear(res);
   18742          147 :     destroyPQExpBuffer(q);
   18743          147 :     destroyPQExpBuffer(delq);
   18744          147 :     destroyPQExpBuffer(query);
   18745          147 :     free(qstatsextname);
   18746              : }
   18747              : 
   18748              : /*
   18749              :  * dumpStatisticsExtStats
   18750              :  *    write out to fout the stats for an extended statistics object
   18751              :  */
   18752              : static void
   18753          171 : dumpStatisticsExtStats(Archive *fout, const StatsExtInfo *statsextinfo)
   18754              : {
   18755          171 :     DumpOptions *dopt = fout->dopt;
   18756              :     PQExpBuffer query;
   18757              :     PGresult   *res;
   18758              :     int         nstats;
   18759              : 
   18760              :     /* Do nothing if not dumping statistics */
   18761          171 :     if (!dopt->dumpStatistics)
   18762           40 :         return;
   18763              : 
   18764          131 :     if (!fout->is_prepared[PREPQUERY_DUMPEXTSTATSOBJSTATS])
   18765              :     {
   18766           33 :         PQExpBuffer pq = createPQExpBuffer();
   18767              : 
   18768              :         /*---------
   18769              :          * Set up query for details about extended statistics objects.
   18770              :          *
   18771              :          * The query depends on the backend version:
   18772              :          * - In v19 and newer versions, query directly the pg_stats_ext*
   18773              :          *   catalogs.
   18774              :          * - In v18 and older versions, ndistinct and dependencies have a
   18775              :          *   different format that needs translation.
   18776              :          * - In v14 and older versions, inherited does not exist.
   18777              :          * - In v11 and older versions, there is no pg_stats_ext, hence
   18778              :          *   the logic joins pg_statistic_ext and pg_namespace.
   18779              :          *---------
   18780              :          */
   18781              : 
   18782           33 :         appendPQExpBufferStr(pq,
   18783              :                              "PREPARE getExtStatsStats(pg_catalog.name, pg_catalog.name) AS\n"
   18784              :                              "SELECT ");
   18785              : 
   18786              :         /*
   18787              :          * Versions 15 and newer have inherited stats.
   18788              :          *
   18789              :          * Create this column in all versions because we need to order by it
   18790              :          * later.
   18791              :          */
   18792           33 :         if (fout->remoteVersion >= 150000)
   18793           33 :             appendPQExpBufferStr(pq, "e.inherited, ");
   18794              :         else
   18795            0 :             appendPQExpBufferStr(pq, "false AS inherited, ");
   18796              : 
   18797              :         /*--------
   18798              :          * The ndistinct and dependencies formats changed in v19, so
   18799              :          * everything before that needs to be translated.
   18800              :          *
   18801              :          * The ndistinct translation converts this kind of data:
   18802              :          * {"3, 4": 11, "3, 6": 11, "4, 6": 11, "3, 4, 6": 11}
   18803              :          *
   18804              :          * to this:
   18805              :          * [ {"attributes": [3,4], "ndistinct": 11},
   18806              :          *   {"attributes": [3,6], "ndistinct": 11},
   18807              :          *   {"attributes": [4,6], "ndistinct": 11},
   18808              :          *   {"attributes": [3,4,6], "ndistinct": 11} ]
   18809              :          *
   18810              :          * The dependencies translation converts this kind of data:
   18811              :          * {"3 => 4": 1.000000, "3 => 6": 1.000000,
   18812              :          *  "4 => 6": 1.000000, "3, 4 => 6": 1.000000,
   18813              :          *  "3, 6 => 4": 1.000000}
   18814              :          *
   18815              :          * to this:
   18816              :          * [ {"attributes": [3], "dependency": 4, "degree": 1.000000},
   18817              :          *   {"attributes": [3], "dependency": 6, "degree": 1.000000},
   18818              :          *   {"attributes": [4], "dependency": 6, "degree": 1.000000},
   18819              :          *   {"attributes": [3,4], "dependency": 6, "degree": 1.000000},
   18820              :          *   {"attributes": [3,6], "dependency": 4, "degree": 1.000000} ]
   18821              :          *--------
   18822              :          */
   18823           33 :         if (fout->remoteVersion >= 190000)
   18824           33 :             appendPQExpBufferStr(pq, "e.n_distinct, e.dependencies, ");
   18825              :         else
   18826            0 :             appendPQExpBufferStr(pq,
   18827              :                                  "( "
   18828              :                                  "SELECT json_agg( "
   18829              :                                  "  json_build_object( "
   18830              :                                  "    '" PG_NDISTINCT_KEY_ATTRIBUTES "', "
   18831              :                                  "    string_to_array(kv.key, ', ')::integer[], "
   18832              :                                  "    '" PG_NDISTINCT_KEY_NDISTINCT "', "
   18833              :                                  "    kv.value::bigint )) "
   18834              :                                  "FROM json_each_text(e.n_distinct::text::json) AS kv"
   18835              :                                  ") AS n_distinct, "
   18836              :                                  "( "
   18837              :                                  "SELECT json_agg( "
   18838              :                                  "  json_build_object( "
   18839              :                                  "    '" PG_DEPENDENCIES_KEY_ATTRIBUTES "', "
   18840              :                                  "    string_to_array( "
   18841              :                                  "      split_part(kv.key, ' => ', 1), "
   18842              :                                  "      ', ')::integer[], "
   18843              :                                  "    '" PG_DEPENDENCIES_KEY_DEPENDENCY "', "
   18844              :                                  "    split_part(kv.key, ' => ', 2)::integer, "
   18845              :                                  "    '" PG_DEPENDENCIES_KEY_DEGREE "', "
   18846              :                                  "    kv.value::double precision )) "
   18847              :                                  "FROM json_each_text(e.dependencies::text::json) AS kv "
   18848              :                                  ") AS dependencies, ");
   18849              : 
   18850              :         /* MCV was introduced v13 */
   18851           33 :         if (fout->remoteVersion >= 130000)
   18852           33 :             appendPQExpBufferStr(pq,
   18853              :                                  "e.most_common_vals, e.most_common_freqs, "
   18854              :                                  "e.most_common_base_freqs, ");
   18855              :         else
   18856            0 :             appendPQExpBufferStr(pq,
   18857              :                                  "NULL AS most_common_vals, NULL AS most_common_freqs, "
   18858              :                                  "NULL AS most_common_base_freqs, ");
   18859              : 
   18860              :         /* Expressions were introduced in v14 */
   18861           33 :         if (fout->remoteVersion >= 140000)
   18862              :         {
   18863              :             /*
   18864              :              * There is no ordering column in pg_stats_ext_exprs.  However, we
   18865              :              * can rely on the unnesting of pg_statistic.ext_data.stxdexpr to
   18866              :              * maintain the desired order of expression elements.
   18867              :              */
   18868           33 :             appendPQExpBufferStr(pq,
   18869              :                                  "( "
   18870              :                                  "SELECT jsonb_pretty(jsonb_agg("
   18871              :                                  "nullif(j.obj, '{}'::jsonb))) "
   18872              :                                  "FROM pg_stats_ext_exprs AS ee "
   18873              :                                  "CROSS JOIN LATERAL jsonb_strip_nulls("
   18874              :                                  "    jsonb_build_object( "
   18875              :                                  "       'null_frac', ee.null_frac::text, "
   18876              :                                  "       'avg_width', ee.avg_width::text, "
   18877              :                                  "       'n_distinct', ee.n_distinct::text, "
   18878              :                                  "       'most_common_vals', ee.most_common_vals::text, "
   18879              :                                  "       'most_common_freqs', ee.most_common_freqs::text, "
   18880              :                                  "       'histogram_bounds', ee.histogram_bounds::text, "
   18881              :                                  "       'correlation', ee.correlation::text, "
   18882              :                                  "       'most_common_elems', ee.most_common_elems::text, "
   18883              :                                  "       'most_common_elem_freqs', ee.most_common_elem_freqs::text, "
   18884              :                                  "       'elem_count_histogram', ee.elem_count_histogram::text");
   18885              : 
   18886              :             /* These three have been added to pg_stats_ext_exprs in v19. */
   18887           33 :             if (fout->remoteVersion >= 190000)
   18888           33 :                 appendPQExpBufferStr(pq,
   18889              :                                      ", "
   18890              :                                      "       'range_length_histogram', ee.range_length_histogram::text, "
   18891              :                                      "       'range_empty_frac', ee.range_empty_frac::text, "
   18892              :                                      "       'range_bounds_histogram', ee.range_bounds_histogram::text");
   18893              : 
   18894           33 :             appendPQExpBufferStr(pq,
   18895              :                                  "    )) AS j(obj)"
   18896              :                                  "WHERE ee.statistics_schemaname = $1 "
   18897              :                                  "AND ee.statistics_name = $2 ");
   18898              :             /* Inherited expressions introduced in v15 */
   18899           33 :             if (fout->remoteVersion >= 150000)
   18900           33 :                 appendPQExpBufferStr(pq, "AND ee.inherited = e.inherited");
   18901              : 
   18902           33 :             appendPQExpBufferStr(pq, ") AS exprs ");
   18903              :         }
   18904              :         else
   18905            0 :             appendPQExpBufferStr(pq, "NULL AS exprs ");
   18906              : 
   18907              :         /* pg_stats_ext introduced in v12 */
   18908           33 :         if (fout->remoteVersion >= 120000)
   18909           33 :             appendPQExpBufferStr(pq,
   18910              :                                  "FROM pg_catalog.pg_stats_ext AS e "
   18911              :                                  "WHERE e.statistics_schemaname = $1 "
   18912              :                                  "AND e.statistics_name = $2 ");
   18913              :         else
   18914            0 :             appendPQExpBufferStr(pq,
   18915              :                                  "FROM ( "
   18916              :                                  "SELECT s.stxndistinct AS n_distinct, "
   18917              :                                  "    s.stxdependencies AS dependencies "
   18918              :                                  "FROM pg_catalog.pg_statistic_ext AS s "
   18919              :                                  "JOIN pg_catalog.pg_namespace AS n "
   18920              :                                  "ON n.oid = s.stxnamespace "
   18921              :                                  "WHERE n.nspname = $1 "
   18922              :                                  "AND s.stxname = $2 "
   18923              :                                  ") AS e ");
   18924              : 
   18925              :         /* we always have an inherited column, but it may be a constant */
   18926           33 :         appendPQExpBufferStr(pq, "ORDER BY inherited");
   18927              : 
   18928           33 :         ExecuteSqlStatement(fout, pq->data);
   18929              : 
   18930           33 :         fout->is_prepared[PREPQUERY_DUMPEXTSTATSOBJSTATS] = true;
   18931              : 
   18932           33 :         destroyPQExpBuffer(pq);
   18933              :     }
   18934              : 
   18935          131 :     query = createPQExpBuffer();
   18936              : 
   18937          131 :     appendPQExpBufferStr(query, "EXECUTE getExtStatsStats(");
   18938          131 :     appendStringLiteralAH(query, statsextinfo->dobj.namespace->dobj.name, fout);
   18939          131 :     appendPQExpBufferStr(query, "::pg_catalog.name, ");
   18940          131 :     appendStringLiteralAH(query, statsextinfo->dobj.name, fout);
   18941          131 :     appendPQExpBufferStr(query, "::pg_catalog.name)");
   18942              : 
   18943          131 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   18944              : 
   18945          131 :     destroyPQExpBuffer(query);
   18946              : 
   18947          131 :     nstats = PQntuples(res);
   18948              : 
   18949          131 :     if (nstats > 0)
   18950              :     {
   18951           36 :         PQExpBuffer out = createPQExpBuffer();
   18952              : 
   18953           36 :         int         i_inherited = PQfnumber(res, "inherited");
   18954           36 :         int         i_ndistinct = PQfnumber(res, "n_distinct");
   18955           36 :         int         i_dependencies = PQfnumber(res, "dependencies");
   18956           36 :         int         i_mcv = PQfnumber(res, "most_common_vals");
   18957           36 :         int         i_mcf = PQfnumber(res, "most_common_freqs");
   18958           36 :         int         i_mcbf = PQfnumber(res, "most_common_base_freqs");
   18959           36 :         int         i_exprs = PQfnumber(res, "exprs");
   18960              : 
   18961           72 :         for (int i = 0; i < nstats; i++)
   18962              :         {
   18963           36 :             TableInfo  *tbinfo = statsextinfo->stattable;
   18964              : 
   18965           36 :             if (PQgetisnull(res, i, i_inherited))
   18966            0 :                 pg_fatal("inherited cannot be NULL");
   18967              : 
   18968           36 :             appendPQExpBufferStr(out,
   18969              :                                  "SELECT * FROM pg_catalog.pg_restore_extended_stats(\n");
   18970           36 :             appendPQExpBuffer(out, "\t'version', '%d'::integer,\n",
   18971              :                               fout->remoteVersion);
   18972              : 
   18973              :             /* Relation information */
   18974           36 :             appendPQExpBufferStr(out, "\t'schemaname', ");
   18975           36 :             appendStringLiteralAH(out, tbinfo->dobj.namespace->dobj.name, fout);
   18976           36 :             appendPQExpBufferStr(out, ",\n\t'relname', ");
   18977           36 :             appendStringLiteralAH(out, tbinfo->dobj.name, fout);
   18978              : 
   18979              :             /* Extended statistics information */
   18980           36 :             appendPQExpBufferStr(out, ",\n\t'statistics_schemaname', ");
   18981           36 :             appendStringLiteralAH(out, statsextinfo->dobj.namespace->dobj.name, fout);
   18982           36 :             appendPQExpBufferStr(out, ",\n\t'statistics_name', ");
   18983           36 :             appendStringLiteralAH(out, statsextinfo->dobj.name, fout);
   18984           36 :             appendNamedArgument(out, fout, "inherited", "boolean",
   18985           36 :                                 PQgetvalue(res, i, i_inherited));
   18986              : 
   18987           36 :             if (!PQgetisnull(res, i, i_ndistinct))
   18988           32 :                 appendNamedArgument(out, fout, "n_distinct", "pg_ndistinct",
   18989           32 :                                     PQgetvalue(res, i, i_ndistinct));
   18990              : 
   18991           36 :             if (!PQgetisnull(res, i, i_dependencies))
   18992           33 :                 appendNamedArgument(out, fout, "dependencies", "pg_dependencies",
   18993           33 :                                     PQgetvalue(res, i, i_dependencies));
   18994              : 
   18995           36 :             if (!PQgetisnull(res, i, i_mcv))
   18996           35 :                 appendNamedArgument(out, fout, "most_common_vals", "text[]",
   18997           35 :                                     PQgetvalue(res, i, i_mcv));
   18998              : 
   18999           36 :             if (!PQgetisnull(res, i, i_mcf))
   19000           35 :                 appendNamedArgument(out, fout, "most_common_freqs", "double precision[]",
   19001           35 :                                     PQgetvalue(res, i, i_mcf));
   19002              : 
   19003           36 :             if (!PQgetisnull(res, i, i_mcbf))
   19004           35 :                 appendNamedArgument(out, fout, "most_common_base_freqs", "double precision[]",
   19005           35 :                                     PQgetvalue(res, i, i_mcbf));
   19006              : 
   19007           36 :             if (!PQgetisnull(res, i, i_exprs))
   19008           33 :                 appendNamedArgument(out, fout, "exprs", "jsonb",
   19009           33 :                                     PQgetvalue(res, i, i_exprs));
   19010              : 
   19011           36 :             appendPQExpBufferStr(out, "\n);\n");
   19012              :         }
   19013              : 
   19014           36 :         ArchiveEntry(fout, nilCatalogId, createDumpId(),
   19015           36 :                      ARCHIVE_OPTS(.tag = statsextinfo->dobj.name,
   19016              :                                   .namespace = statsextinfo->dobj.namespace->dobj.name,
   19017              :                                   .owner = statsextinfo->rolname,
   19018              :                                   .description = "EXTENDED STATISTICS DATA",
   19019              :                                   .section = SECTION_POST_DATA,
   19020              :                                   .createStmt = out->data,
   19021              :                                   .deps = &statsextinfo->dobj.dumpId,
   19022              :                                   .nDeps = 1));
   19023           36 :         destroyPQExpBuffer(out);
   19024              :     }
   19025          131 :     PQclear(res);
   19026              : }
   19027              : 
   19028              : /*
   19029              :  * dumpConstraint
   19030              :  *    write out to fout a user-defined constraint
   19031              :  */
   19032              : static void
   19033         2704 : dumpConstraint(Archive *fout, const ConstraintInfo *coninfo)
   19034              : {
   19035         2704 :     DumpOptions *dopt = fout->dopt;
   19036         2704 :     TableInfo  *tbinfo = coninfo->contable;
   19037              :     PQExpBuffer q;
   19038              :     PQExpBuffer delq;
   19039         2704 :     char       *tag = NULL;
   19040              :     char       *foreign;
   19041              : 
   19042              :     /* Do nothing if not dumping schema */
   19043         2704 :     if (!dopt->dumpSchema)
   19044           98 :         return;
   19045              : 
   19046         2606 :     q = createPQExpBuffer();
   19047         2606 :     delq = createPQExpBuffer();
   19048              : 
   19049         5058 :     foreign = tbinfo &&
   19050         2606 :         tbinfo->relkind == RELKIND_FOREIGN_TABLE ? "FOREIGN " : "";
   19051              : 
   19052         2606 :     if (coninfo->contype == 'p' ||
   19053         1267 :         coninfo->contype == 'u' ||
   19054         1023 :         coninfo->contype == 'x')
   19055         1593 :     {
   19056              :         /* Index-related constraint */
   19057              :         IndxInfo   *indxinfo;
   19058              :         int         k;
   19059              : 
   19060         1593 :         indxinfo = (IndxInfo *) findObjectByDumpId(coninfo->conindex);
   19061              : 
   19062         1593 :         if (indxinfo == NULL)
   19063            0 :             pg_fatal("missing index for constraint \"%s\"",
   19064              :                      coninfo->dobj.name);
   19065              : 
   19066         1593 :         if (dopt->binary_upgrade)
   19067          175 :             binary_upgrade_set_pg_class_oids(fout, q,
   19068              :                                              indxinfo->dobj.catId.oid);
   19069              : 
   19070         1593 :         appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s\n", foreign,
   19071         1593 :                           fmtQualifiedDumpable(tbinfo));
   19072         1593 :         appendPQExpBuffer(q, "    ADD CONSTRAINT %s ",
   19073         1593 :                           fmtId(coninfo->dobj.name));
   19074              : 
   19075         1593 :         if (coninfo->condef)
   19076              :         {
   19077              :             /* pg_get_constraintdef should have provided everything */
   19078           10 :             appendPQExpBuffer(q, "%s;\n", coninfo->condef);
   19079              :         }
   19080              :         else
   19081              :         {
   19082         1583 :             appendPQExpBufferStr(q,
   19083         1583 :                                  coninfo->contype == 'p' ? "PRIMARY KEY" : "UNIQUE");
   19084              : 
   19085              :             /*
   19086              :              * PRIMARY KEY constraints should not be using NULLS NOT DISTINCT
   19087              :              * indexes. Being able to create this was fixed, but we need to
   19088              :              * make the index distinct in order to be able to restore the
   19089              :              * dump.
   19090              :              */
   19091         1583 :             if (indxinfo->indnullsnotdistinct && coninfo->contype != 'p')
   19092            0 :                 appendPQExpBufferStr(q, " NULLS NOT DISTINCT");
   19093         1583 :             appendPQExpBufferStr(q, " (");
   19094         3778 :             for (k = 0; k < indxinfo->indnkeyattrs; k++)
   19095              :             {
   19096         2195 :                 int         indkey = (int) indxinfo->indkeys[k];
   19097              :                 const char *attname;
   19098              : 
   19099         2195 :                 if (indkey == InvalidAttrNumber)
   19100            0 :                     break;
   19101         2195 :                 attname = getAttrName(indkey, tbinfo);
   19102              : 
   19103         2195 :                 appendPQExpBuffer(q, "%s%s",
   19104              :                                   (k == 0) ? "" : ", ",
   19105              :                                   fmtId(attname));
   19106              :             }
   19107         1583 :             if (coninfo->conperiod)
   19108          104 :                 appendPQExpBufferStr(q, " WITHOUT OVERLAPS");
   19109              : 
   19110         1583 :             if (indxinfo->indnkeyattrs < indxinfo->indnattrs)
   19111           20 :                 appendPQExpBufferStr(q, ") INCLUDE (");
   19112              : 
   19113         1623 :             for (k = indxinfo->indnkeyattrs; k < indxinfo->indnattrs; k++)
   19114              :             {
   19115           40 :                 int         indkey = (int) indxinfo->indkeys[k];
   19116              :                 const char *attname;
   19117              : 
   19118           40 :                 if (indkey == InvalidAttrNumber)
   19119            0 :                     break;
   19120           40 :                 attname = getAttrName(indkey, tbinfo);
   19121              : 
   19122           80 :                 appendPQExpBuffer(q, "%s%s",
   19123           40 :                                   (k == indxinfo->indnkeyattrs) ? "" : ", ",
   19124              :                                   fmtId(attname));
   19125              :             }
   19126              : 
   19127         1583 :             appendPQExpBufferChar(q, ')');
   19128              : 
   19129         1583 :             if (nonemptyReloptions(indxinfo->indreloptions))
   19130              :             {
   19131            0 :                 appendPQExpBufferStr(q, " WITH (");
   19132            0 :                 appendReloptionsArrayAH(q, indxinfo->indreloptions, "", fout);
   19133            0 :                 appendPQExpBufferChar(q, ')');
   19134              :             }
   19135              : 
   19136         1583 :             if (coninfo->condeferrable)
   19137              :             {
   19138           25 :                 appendPQExpBufferStr(q, " DEFERRABLE");
   19139           25 :                 if (coninfo->condeferred)
   19140           15 :                     appendPQExpBufferStr(q, " INITIALLY DEFERRED");
   19141              :             }
   19142              : 
   19143         1583 :             appendPQExpBufferStr(q, ";\n");
   19144              :         }
   19145              : 
   19146              :         /*
   19147              :          * Append ALTER TABLE commands as needed to set properties that we
   19148              :          * only have ALTER TABLE syntax for.  Keep this in sync with the
   19149              :          * similar code in dumpIndex!
   19150              :          */
   19151              : 
   19152              :         /* If the index is clustered, we need to record that. */
   19153         1593 :         if (indxinfo->indisclustered)
   19154              :         {
   19155           32 :             appendPQExpBuffer(q, "\nALTER TABLE %s CLUSTER",
   19156           32 :                               fmtQualifiedDumpable(tbinfo));
   19157              :             /* index name is not qualified in this syntax */
   19158           32 :             appendPQExpBuffer(q, " ON %s;\n",
   19159           32 :                               fmtId(indxinfo->dobj.name));
   19160              :         }
   19161              : 
   19162              :         /* If the index defines identity, we need to record that. */
   19163         1593 :         if (indxinfo->indisreplident)
   19164              :         {
   19165            0 :             appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY USING",
   19166            0 :                               fmtQualifiedDumpable(tbinfo));
   19167              :             /* index name is not qualified in this syntax */
   19168            0 :             appendPQExpBuffer(q, " INDEX %s;\n",
   19169            0 :                               fmtId(indxinfo->dobj.name));
   19170              :         }
   19171              : 
   19172              :         /* Indexes can depend on extensions */
   19173         1593 :         append_depends_on_extension(fout, q, &indxinfo->dobj,
   19174              :                                     "pg_catalog.pg_class", "INDEX",
   19175         1593 :                                     fmtQualifiedDumpable(indxinfo));
   19176              : 
   19177         1593 :         appendPQExpBuffer(delq, "ALTER %sTABLE ONLY %s ", foreign,
   19178         1593 :                           fmtQualifiedDumpable(tbinfo));
   19179         1593 :         appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
   19180         1593 :                           fmtId(coninfo->dobj.name));
   19181              : 
   19182         1593 :         tag = psprintf("%s %s", tbinfo->dobj.name, coninfo->dobj.name);
   19183              : 
   19184         1593 :         if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   19185         1593 :             ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
   19186         1593 :                          ARCHIVE_OPTS(.tag = tag,
   19187              :                                       .namespace = tbinfo->dobj.namespace->dobj.name,
   19188              :                                       .tablespace = indxinfo->tablespace,
   19189              :                                       .owner = tbinfo->rolname,
   19190              :                                       .description = "CONSTRAINT",
   19191              :                                       .section = SECTION_POST_DATA,
   19192              :                                       .createStmt = q->data,
   19193              :                                       .dropStmt = delq->data));
   19194              :     }
   19195         1013 :     else if (coninfo->contype == 'f')
   19196              :     {
   19197              :         char       *only;
   19198              : 
   19199              :         /*
   19200              :          * Foreign keys on partitioned tables are always declared as
   19201              :          * inheriting to partitions; for all other cases, emit them as
   19202              :          * applying ONLY directly to the named table, because that's how they
   19203              :          * work for regular inherited tables.
   19204              :          */
   19205          219 :         only = tbinfo->relkind == RELKIND_PARTITIONED_TABLE ? "" : "ONLY ";
   19206              : 
   19207              :         /*
   19208              :          * XXX Potentially wrap in a 'SET CONSTRAINTS OFF' block so that the
   19209              :          * current table data is not processed
   19210              :          */
   19211          219 :         appendPQExpBuffer(q, "ALTER %sTABLE %s%s\n", foreign,
   19212          219 :                           only, fmtQualifiedDumpable(tbinfo));
   19213          219 :         appendPQExpBuffer(q, "    ADD CONSTRAINT %s %s;\n",
   19214          219 :                           fmtId(coninfo->dobj.name),
   19215          219 :                           coninfo->condef);
   19216              : 
   19217          219 :         appendPQExpBuffer(delq, "ALTER %sTABLE %s%s ", foreign,
   19218          219 :                           only, fmtQualifiedDumpable(tbinfo));
   19219          219 :         appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
   19220          219 :                           fmtId(coninfo->dobj.name));
   19221              : 
   19222          219 :         tag = psprintf("%s %s", tbinfo->dobj.name, coninfo->dobj.name);
   19223              : 
   19224          219 :         if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   19225          219 :             ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
   19226          219 :                          ARCHIVE_OPTS(.tag = tag,
   19227              :                                       .namespace = tbinfo->dobj.namespace->dobj.name,
   19228              :                                       .owner = tbinfo->rolname,
   19229              :                                       .description = "FK CONSTRAINT",
   19230              :                                       .section = SECTION_POST_DATA,
   19231              :                                       .createStmt = q->data,
   19232              :                                       .dropStmt = delq->data));
   19233              :     }
   19234          794 :     else if ((coninfo->contype == 'c' || coninfo->contype == 'n') && tbinfo)
   19235              :     {
   19236              :         /* CHECK or invalid not-null constraint on a table */
   19237              : 
   19238              :         /* Ignore if not to be dumped separately, or if it was inherited */
   19239          640 :         if (coninfo->separate && coninfo->conislocal)
   19240              :         {
   19241              :             const char *keyword;
   19242              : 
   19243          107 :             if (coninfo->contype == 'c')
   19244           45 :                 keyword = "CHECK CONSTRAINT";
   19245              :             else
   19246           62 :                 keyword = "CONSTRAINT";
   19247              : 
   19248              :             /* not ONLY since we want it to propagate to children */
   19249          107 :             appendPQExpBuffer(q, "ALTER %sTABLE %s\n", foreign,
   19250          107 :                               fmtQualifiedDumpable(tbinfo));
   19251          107 :             appendPQExpBuffer(q, "    ADD CONSTRAINT %s %s;\n",
   19252          107 :                               fmtId(coninfo->dobj.name),
   19253          107 :                               coninfo->condef);
   19254              : 
   19255          107 :             appendPQExpBuffer(delq, "ALTER %sTABLE %s ", foreign,
   19256          107 :                               fmtQualifiedDumpable(tbinfo));
   19257          107 :             appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
   19258          107 :                               fmtId(coninfo->dobj.name));
   19259              : 
   19260          107 :             tag = psprintf("%s %s", tbinfo->dobj.name, coninfo->dobj.name);
   19261              : 
   19262          107 :             if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   19263          107 :                 ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
   19264          107 :                              ARCHIVE_OPTS(.tag = tag,
   19265              :                                           .namespace = tbinfo->dobj.namespace->dobj.name,
   19266              :                                           .owner = tbinfo->rolname,
   19267              :                                           .description = keyword,
   19268              :                                           .section = SECTION_POST_DATA,
   19269              :                                           .createStmt = q->data,
   19270              :                                           .dropStmt = delq->data));
   19271              :         }
   19272              :     }
   19273          154 :     else if (tbinfo == NULL)
   19274              :     {
   19275              :         /* CHECK, NOT NULL constraint on a domain */
   19276          154 :         TypeInfo   *tyinfo = coninfo->condomain;
   19277              : 
   19278              :         Assert(coninfo->contype == 'c' || coninfo->contype == 'n');
   19279              : 
   19280              :         /* Ignore if not to be dumped separately */
   19281          154 :         if (coninfo->separate)
   19282              :         {
   19283              :             const char *keyword;
   19284              : 
   19285            5 :             if (coninfo->contype == 'c')
   19286            5 :                 keyword = "CHECK CONSTRAINT";
   19287              :             else
   19288            0 :                 keyword = "CONSTRAINT";
   19289              : 
   19290            5 :             appendPQExpBuffer(q, "ALTER DOMAIN %s\n",
   19291            5 :                               fmtQualifiedDumpable(tyinfo));
   19292            5 :             appendPQExpBuffer(q, "    ADD CONSTRAINT %s %s;\n",
   19293            5 :                               fmtId(coninfo->dobj.name),
   19294            5 :                               coninfo->condef);
   19295              : 
   19296            5 :             appendPQExpBuffer(delq, "ALTER DOMAIN %s ",
   19297            5 :                               fmtQualifiedDumpable(tyinfo));
   19298            5 :             appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
   19299            5 :                               fmtId(coninfo->dobj.name));
   19300              : 
   19301            5 :             tag = psprintf("%s %s", tyinfo->dobj.name, coninfo->dobj.name);
   19302              : 
   19303            5 :             if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   19304            5 :                 ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
   19305            5 :                              ARCHIVE_OPTS(.tag = tag,
   19306              :                                           .namespace = tyinfo->dobj.namespace->dobj.name,
   19307              :                                           .owner = tyinfo->rolname,
   19308              :                                           .description = keyword,
   19309              :                                           .section = SECTION_POST_DATA,
   19310              :                                           .createStmt = q->data,
   19311              :                                           .dropStmt = delq->data));
   19312              : 
   19313            5 :             if (coninfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   19314              :             {
   19315            5 :                 PQExpBuffer conprefix = createPQExpBuffer();
   19316            5 :                 char       *qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
   19317              : 
   19318            5 :                 appendPQExpBuffer(conprefix, "CONSTRAINT %s ON DOMAIN",
   19319            5 :                                   fmtId(coninfo->dobj.name));
   19320              : 
   19321            5 :                 dumpComment(fout, conprefix->data, qtypname,
   19322            5 :                             tyinfo->dobj.namespace->dobj.name,
   19323              :                             tyinfo->rolname,
   19324            5 :                             coninfo->dobj.catId, 0, coninfo->dobj.dumpId);
   19325            5 :                 destroyPQExpBuffer(conprefix);
   19326            5 :                 free(qtypname);
   19327              :             }
   19328              :         }
   19329              :     }
   19330              :     else
   19331              :     {
   19332            0 :         pg_fatal("unrecognized constraint type: %c",
   19333              :                  coninfo->contype);
   19334              :     }
   19335              : 
   19336              :     /* Dump Constraint Comments --- only works for table constraints */
   19337         2606 :     if (tbinfo && coninfo->separate &&
   19338         1949 :         coninfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   19339           47 :         dumpTableConstraintComment(fout, coninfo);
   19340              : 
   19341         2606 :     free(tag);
   19342         2606 :     destroyPQExpBuffer(q);
   19343         2606 :     destroyPQExpBuffer(delq);
   19344              : }
   19345              : 
   19346              : /*
   19347              :  * dumpTableConstraintComment --- dump a constraint's comment if any
   19348              :  *
   19349              :  * This is split out because we need the function in two different places
   19350              :  * depending on whether the constraint is dumped as part of CREATE TABLE
   19351              :  * or as a separate ALTER command.
   19352              :  */
   19353              : static void
   19354           84 : dumpTableConstraintComment(Archive *fout, const ConstraintInfo *coninfo)
   19355              : {
   19356           84 :     TableInfo  *tbinfo = coninfo->contable;
   19357           84 :     PQExpBuffer conprefix = createPQExpBuffer();
   19358              :     char       *qtabname;
   19359              : 
   19360           84 :     qtabname = pg_strdup(fmtId(tbinfo->dobj.name));
   19361              : 
   19362           84 :     appendPQExpBuffer(conprefix, "CONSTRAINT %s ON",
   19363           84 :                       fmtId(coninfo->dobj.name));
   19364              : 
   19365           84 :     if (coninfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   19366           84 :         dumpComment(fout, conprefix->data, qtabname,
   19367           84 :                     tbinfo->dobj.namespace->dobj.name,
   19368              :                     tbinfo->rolname,
   19369              :                     coninfo->dobj.catId, 0,
   19370           84 :                     coninfo->separate ? coninfo->dobj.dumpId : tbinfo->dobj.dumpId);
   19371              : 
   19372           84 :     destroyPQExpBuffer(conprefix);
   19373           84 :     free(qtabname);
   19374           84 : }
   19375              : 
   19376              : static inline SeqType
   19377          647 : parse_sequence_type(const char *name)
   19378              : {
   19379         1452 :     for (int i = 0; i < lengthof(SeqTypeNames); i++)
   19380              :     {
   19381         1452 :         if (strcmp(SeqTypeNames[i], name) == 0)
   19382          647 :             return (SeqType) i;
   19383              :     }
   19384              : 
   19385            0 :     pg_fatal("unrecognized sequence type: %s", name);
   19386              :     return (SeqType) 0;         /* keep compiler quiet */
   19387              : }
   19388              : 
   19389              : /*
   19390              :  * bsearch() comparator for SequenceItem
   19391              :  */
   19392              : static int
   19393         2974 : SequenceItemCmp(const void *p1, const void *p2)
   19394              : {
   19395         2974 :     SequenceItem v1 = *((const SequenceItem *) p1);
   19396         2974 :     SequenceItem v2 = *((const SequenceItem *) p2);
   19397              : 
   19398         2974 :     return pg_cmp_u32(v1.oid, v2.oid);
   19399              : }
   19400              : 
   19401              : /*
   19402              :  * collectSequences
   19403              :  *
   19404              :  * Construct a table of sequence information.  This table is sorted by OID for
   19405              :  * speed in lookup.
   19406              :  */
   19407              : static void
   19408          259 : collectSequences(Archive *fout)
   19409              : {
   19410              :     PGresult   *res;
   19411              :     const char *query;
   19412              : 
   19413              :     /*
   19414              :      * Before Postgres 10, sequence metadata is in the sequence itself.  With
   19415              :      * some extra effort, we might be able to use the sorted table for those
   19416              :      * versions, but for now it seems unlikely to be worth it.
   19417              :      *
   19418              :      * Since version 18, we can gather the sequence data in this query with
   19419              :      * pg_get_sequence_data(), but we only do so for non-schema-only dumps.
   19420              :      */
   19421          259 :     if (fout->remoteVersion < 100000)
   19422            0 :         return;
   19423          259 :     else if (fout->remoteVersion < 180000 ||
   19424          259 :              (!fout->dopt->dumpData && !fout->dopt->sequence_data))
   19425            8 :         query = "SELECT seqrelid, format_type(seqtypid, NULL), "
   19426              :             "seqstart, seqincrement, "
   19427              :             "seqmax, seqmin, "
   19428              :             "seqcache, seqcycle, "
   19429              :             "NULL, 'f' "
   19430              :             "FROM pg_catalog.pg_sequence "
   19431              :             "ORDER BY seqrelid";
   19432              :     else
   19433          251 :         query = "SELECT seqrelid, format_type(seqtypid, NULL), "
   19434              :             "seqstart, seqincrement, "
   19435              :             "seqmax, seqmin, "
   19436              :             "seqcache, seqcycle, "
   19437              :             "last_value, is_called "
   19438              :             "FROM pg_catalog.pg_sequence, "
   19439              :             "pg_get_sequence_data(seqrelid) "
   19440              :             "ORDER BY seqrelid;";
   19441              : 
   19442          259 :     res = ExecuteSqlQuery(fout, query, PGRES_TUPLES_OK);
   19443              : 
   19444          259 :     nsequences = PQntuples(res);
   19445          259 :     sequences = pg_malloc_array(SequenceItem, nsequences);
   19446              : 
   19447          906 :     for (int i = 0; i < nsequences; i++)
   19448              :     {
   19449          647 :         sequences[i].oid = atooid(PQgetvalue(res, i, 0));
   19450          647 :         sequences[i].seqtype = parse_sequence_type(PQgetvalue(res, i, 1));
   19451          647 :         sequences[i].startv = strtoi64(PQgetvalue(res, i, 2), NULL, 10);
   19452          647 :         sequences[i].incby = strtoi64(PQgetvalue(res, i, 3), NULL, 10);
   19453          647 :         sequences[i].maxv = strtoi64(PQgetvalue(res, i, 4), NULL, 10);
   19454          647 :         sequences[i].minv = strtoi64(PQgetvalue(res, i, 5), NULL, 10);
   19455          647 :         sequences[i].cache = strtoi64(PQgetvalue(res, i, 6), NULL, 10);
   19456          647 :         sequences[i].cycled = (strcmp(PQgetvalue(res, i, 7), "t") == 0);
   19457          647 :         sequences[i].last_value = strtoi64(PQgetvalue(res, i, 8), NULL, 10);
   19458          647 :         sequences[i].is_called = (strcmp(PQgetvalue(res, i, 9), "t") == 0);
   19459          647 :         sequences[i].null_seqtuple = (PQgetisnull(res, i, 8) || PQgetisnull(res, i, 9));
   19460              :     }
   19461              : 
   19462          259 :     PQclear(res);
   19463              : }
   19464              : 
   19465              : /*
   19466              :  * dumpSequence
   19467              :  *    write the declaration (not data) of one user-defined sequence
   19468              :  */
   19469              : static void
   19470          384 : dumpSequence(Archive *fout, const TableInfo *tbinfo)
   19471              : {
   19472          384 :     DumpOptions *dopt = fout->dopt;
   19473              :     SequenceItem *seq;
   19474              :     bool        is_ascending;
   19475              :     int64       default_minv,
   19476              :                 default_maxv;
   19477          384 :     PQExpBuffer query = createPQExpBuffer();
   19478          384 :     PQExpBuffer delqry = createPQExpBuffer();
   19479              :     char       *qseqname;
   19480          384 :     TableInfo  *owning_tab = NULL;
   19481              : 
   19482          384 :     qseqname = pg_strdup(fmtId(tbinfo->dobj.name));
   19483              : 
   19484              :     /*
   19485              :      * For versions >= 10, the sequence information is gathered in a sorted
   19486              :      * table before any calls to dumpSequence().  See collectSequences() for
   19487              :      * more information.
   19488              :      */
   19489          384 :     if (fout->remoteVersion >= 100000)
   19490              :     {
   19491          384 :         SequenceItem key = {0};
   19492              : 
   19493              :         Assert(sequences);
   19494              : 
   19495          384 :         key.oid = tbinfo->dobj.catId.oid;
   19496          384 :         seq = bsearch(&key, sequences, nsequences,
   19497              :                       sizeof(SequenceItem), SequenceItemCmp);
   19498              :     }
   19499              :     else
   19500              :     {
   19501              :         PGresult   *res;
   19502              : 
   19503              :         /*
   19504              :          * Before PostgreSQL 10, sequence metadata is in the sequence itself.
   19505              :          *
   19506              :          * Note: it might seem that 'bigint' potentially needs to be
   19507              :          * schema-qualified, but actually that's a keyword.
   19508              :          */
   19509            0 :         appendPQExpBuffer(query,
   19510              :                           "SELECT 'bigint' AS sequence_type, "
   19511              :                           "start_value, increment_by, max_value, min_value, "
   19512              :                           "cache_value, is_cycled FROM %s",
   19513            0 :                           fmtQualifiedDumpable(tbinfo));
   19514              : 
   19515            0 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   19516              : 
   19517            0 :         if (PQntuples(res) != 1)
   19518            0 :             pg_fatal(ngettext("query to get data of sequence \"%s\" returned %d row (expected 1)",
   19519              :                               "query to get data of sequence \"%s\" returned %d rows (expected 1)",
   19520              :                               PQntuples(res)),
   19521              :                      tbinfo->dobj.name, PQntuples(res));
   19522              : 
   19523            0 :         seq = pg_malloc0_object(SequenceItem);
   19524            0 :         seq->seqtype = parse_sequence_type(PQgetvalue(res, 0, 0));
   19525            0 :         seq->startv = strtoi64(PQgetvalue(res, 0, 1), NULL, 10);
   19526            0 :         seq->incby = strtoi64(PQgetvalue(res, 0, 2), NULL, 10);
   19527            0 :         seq->maxv = strtoi64(PQgetvalue(res, 0, 3), NULL, 10);
   19528            0 :         seq->minv = strtoi64(PQgetvalue(res, 0, 4), NULL, 10);
   19529            0 :         seq->cache = strtoi64(PQgetvalue(res, 0, 5), NULL, 10);
   19530            0 :         seq->cycled = (strcmp(PQgetvalue(res, 0, 6), "t") == 0);
   19531              : 
   19532            0 :         PQclear(res);
   19533              :     }
   19534              : 
   19535              :     /* Calculate default limits for a sequence of this type */
   19536          384 :     is_ascending = (seq->incby >= 0);
   19537          384 :     if (seq->seqtype == SEQTYPE_SMALLINT)
   19538              :     {
   19539           25 :         default_minv = is_ascending ? 1 : PG_INT16_MIN;
   19540           25 :         default_maxv = is_ascending ? PG_INT16_MAX : -1;
   19541              :     }
   19542          359 :     else if (seq->seqtype == SEQTYPE_INTEGER)
   19543              :     {
   19544          284 :         default_minv = is_ascending ? 1 : PG_INT32_MIN;
   19545          284 :         default_maxv = is_ascending ? PG_INT32_MAX : -1;
   19546              :     }
   19547           75 :     else if (seq->seqtype == SEQTYPE_BIGINT)
   19548              :     {
   19549           75 :         default_minv = is_ascending ? 1 : PG_INT64_MIN;
   19550           75 :         default_maxv = is_ascending ? PG_INT64_MAX : -1;
   19551              :     }
   19552              :     else
   19553              :     {
   19554            0 :         pg_fatal("unrecognized sequence type: %d", seq->seqtype);
   19555              :         default_minv = default_maxv = 0;    /* keep compiler quiet */
   19556              :     }
   19557              : 
   19558              :     /*
   19559              :      * Identity sequences are not to be dropped separately.
   19560              :      */
   19561          384 :     if (!tbinfo->is_identity_sequence)
   19562              :     {
   19563          242 :         appendPQExpBuffer(delqry, "DROP SEQUENCE %s;\n",
   19564          242 :                           fmtQualifiedDumpable(tbinfo));
   19565              :     }
   19566              : 
   19567          384 :     resetPQExpBuffer(query);
   19568              : 
   19569          384 :     if (dopt->binary_upgrade)
   19570              :     {
   19571           66 :         binary_upgrade_set_pg_class_oids(fout, query,
   19572           66 :                                          tbinfo->dobj.catId.oid);
   19573              : 
   19574              :         /*
   19575              :          * In older PG versions a sequence will have a pg_type entry, but v14
   19576              :          * and up don't use that, so don't attempt to preserve the type OID.
   19577              :          */
   19578              :     }
   19579              : 
   19580          384 :     if (tbinfo->is_identity_sequence)
   19581              :     {
   19582          142 :         owning_tab = findTableByOid(tbinfo->owning_tab);
   19583              : 
   19584          142 :         appendPQExpBuffer(query,
   19585              :                           "ALTER TABLE %s ",
   19586          142 :                           fmtQualifiedDumpable(owning_tab));
   19587          142 :         appendPQExpBuffer(query,
   19588              :                           "ALTER COLUMN %s ADD GENERATED ",
   19589          142 :                           fmtId(owning_tab->attnames[tbinfo->owning_col - 1]));
   19590          142 :         if (owning_tab->attidentity[tbinfo->owning_col - 1] == ATTRIBUTE_IDENTITY_ALWAYS)
   19591          102 :             appendPQExpBufferStr(query, "ALWAYS");
   19592           40 :         else if (owning_tab->attidentity[tbinfo->owning_col - 1] == ATTRIBUTE_IDENTITY_BY_DEFAULT)
   19593           40 :             appendPQExpBufferStr(query, "BY DEFAULT");
   19594          142 :         appendPQExpBuffer(query, " AS IDENTITY (\n    SEQUENCE NAME %s\n",
   19595          142 :                           fmtQualifiedDumpable(tbinfo));
   19596              : 
   19597              :         /*
   19598              :          * Emit persistence option only if it's different from the owning
   19599              :          * table's.  This avoids using this new syntax unnecessarily.
   19600              :          */
   19601          142 :         if (tbinfo->relpersistence != owning_tab->relpersistence)
   19602           10 :             appendPQExpBuffer(query, "    %s\n",
   19603           10 :                               tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED ?
   19604              :                               "UNLOGGED" : "LOGGED");
   19605              :     }
   19606              :     else
   19607              :     {
   19608          242 :         appendPQExpBuffer(query,
   19609              :                           "CREATE %sSEQUENCE %s\n",
   19610          242 :                           tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED ?
   19611              :                           "UNLOGGED " : "",
   19612          242 :                           fmtQualifiedDumpable(tbinfo));
   19613              : 
   19614          242 :         if (seq->seqtype != SEQTYPE_BIGINT)
   19615          182 :             appendPQExpBuffer(query, "    AS %s\n", SeqTypeNames[seq->seqtype]);
   19616              :     }
   19617              : 
   19618          384 :     appendPQExpBuffer(query, "    START WITH " INT64_FORMAT "\n", seq->startv);
   19619              : 
   19620          384 :     appendPQExpBuffer(query, "    INCREMENT BY " INT64_FORMAT "\n", seq->incby);
   19621              : 
   19622          384 :     if (seq->minv != default_minv)
   19623           15 :         appendPQExpBuffer(query, "    MINVALUE " INT64_FORMAT "\n", seq->minv);
   19624              :     else
   19625          369 :         appendPQExpBufferStr(query, "    NO MINVALUE\n");
   19626              : 
   19627          384 :     if (seq->maxv != default_maxv)
   19628           15 :         appendPQExpBuffer(query, "    MAXVALUE " INT64_FORMAT "\n", seq->maxv);
   19629              :     else
   19630          369 :         appendPQExpBufferStr(query, "    NO MAXVALUE\n");
   19631              : 
   19632          384 :     appendPQExpBuffer(query,
   19633              :                       "    CACHE " INT64_FORMAT "%s",
   19634          384 :                       seq->cache, (seq->cycled ? "\n    CYCLE" : ""));
   19635              : 
   19636          384 :     if (tbinfo->is_identity_sequence)
   19637          142 :         appendPQExpBufferStr(query, "\n);\n");
   19638              :     else
   19639          242 :         appendPQExpBufferStr(query, ";\n");
   19640              : 
   19641              :     /* binary_upgrade:  no need to clear TOAST table oid */
   19642              : 
   19643          384 :     if (dopt->binary_upgrade)
   19644           66 :         binary_upgrade_extension_member(query, &tbinfo->dobj,
   19645              :                                         "SEQUENCE", qseqname,
   19646           66 :                                         tbinfo->dobj.namespace->dobj.name);
   19647              : 
   19648          384 :     if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   19649          384 :         ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
   19650          384 :                      ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
   19651              :                                   .namespace = tbinfo->dobj.namespace->dobj.name,
   19652              :                                   .owner = tbinfo->rolname,
   19653              :                                   .description = "SEQUENCE",
   19654              :                                   .section = SECTION_PRE_DATA,
   19655              :                                   .createStmt = query->data,
   19656              :                                   .dropStmt = delqry->data));
   19657              : 
   19658              :     /*
   19659              :      * If the sequence is owned by a table column, emit the ALTER for it as a
   19660              :      * separate TOC entry immediately following the sequence's own entry. It's
   19661              :      * OK to do this rather than using full sorting logic, because the
   19662              :      * dependency that tells us it's owned will have forced the table to be
   19663              :      * created first.  We can't just include the ALTER in the TOC entry
   19664              :      * because it will fail if we haven't reassigned the sequence owner to
   19665              :      * match the table's owner.
   19666              :      *
   19667              :      * We need not schema-qualify the table reference because both sequence
   19668              :      * and table must be in the same schema.
   19669              :      */
   19670          384 :     if (OidIsValid(tbinfo->owning_tab) && !tbinfo->is_identity_sequence)
   19671              :     {
   19672          137 :         owning_tab = findTableByOid(tbinfo->owning_tab);
   19673              : 
   19674          137 :         if (owning_tab == NULL)
   19675            0 :             pg_fatal("failed sanity check, parent table with OID %u of sequence with OID %u not found",
   19676              :                      tbinfo->owning_tab, tbinfo->dobj.catId.oid);
   19677              : 
   19678          137 :         if (owning_tab->dobj.dump & DUMP_COMPONENT_DEFINITION)
   19679              :         {
   19680          135 :             resetPQExpBuffer(query);
   19681          135 :             appendPQExpBuffer(query, "ALTER SEQUENCE %s",
   19682          135 :                               fmtQualifiedDumpable(tbinfo));
   19683          135 :             appendPQExpBuffer(query, " OWNED BY %s",
   19684          135 :                               fmtQualifiedDumpable(owning_tab));
   19685          135 :             appendPQExpBuffer(query, ".%s;\n",
   19686          135 :                               fmtId(owning_tab->attnames[tbinfo->owning_col - 1]));
   19687              : 
   19688          135 :             if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   19689          135 :                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
   19690          135 :                              ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
   19691              :                                           .namespace = tbinfo->dobj.namespace->dobj.name,
   19692              :                                           .owner = tbinfo->rolname,
   19693              :                                           .description = "SEQUENCE OWNED BY",
   19694              :                                           .section = SECTION_PRE_DATA,
   19695              :                                           .createStmt = query->data,
   19696              :                                           .deps = &(tbinfo->dobj.dumpId),
   19697              :                                           .nDeps = 1));
   19698              :         }
   19699              :     }
   19700              : 
   19701              :     /* Dump Sequence Comments and Security Labels */
   19702          384 :     if (tbinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   19703            0 :         dumpComment(fout, "SEQUENCE", qseqname,
   19704            0 :                     tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
   19705            0 :                     tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
   19706              : 
   19707          384 :     if (tbinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
   19708            0 :         dumpSecLabel(fout, "SEQUENCE", qseqname,
   19709            0 :                      tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
   19710            0 :                      tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
   19711              : 
   19712          384 :     if (fout->remoteVersion < 100000)
   19713            0 :         pg_free(seq);
   19714          384 :     destroyPQExpBuffer(query);
   19715          384 :     destroyPQExpBuffer(delqry);
   19716          384 :     free(qseqname);
   19717          384 : }
   19718              : 
   19719              : /*
   19720              :  * dumpSequenceData
   19721              :  *    write the data of one user-defined sequence
   19722              :  */
   19723              : static void
   19724          402 : dumpSequenceData(Archive *fout, const TableDataInfo *tdinfo)
   19725              : {
   19726          402 :     TableInfo  *tbinfo = tdinfo->tdtable;
   19727              :     int64       last;
   19728              :     bool        called;
   19729              :     PQExpBuffer query;
   19730              : 
   19731              :     /* needn't bother if not dumping sequence data */
   19732          402 :     if (!fout->dopt->dumpData && !fout->dopt->sequence_data)
   19733            1 :         return;
   19734              : 
   19735          401 :     query = createPQExpBuffer();
   19736              : 
   19737              :     /*
   19738              :      * For versions >= 18, the sequence information is gathered in the sorted
   19739              :      * array before any calls to dumpSequenceData().  See collectSequences()
   19740              :      * for more information.
   19741              :      *
   19742              :      * For older versions, we have to query the sequence relations
   19743              :      * individually.
   19744              :      */
   19745          401 :     if (fout->remoteVersion < 180000)
   19746              :     {
   19747              :         PGresult   *res;
   19748              : 
   19749            0 :         appendPQExpBuffer(query,
   19750              :                           "SELECT last_value, is_called FROM %s",
   19751            0 :                           fmtQualifiedDumpable(tbinfo));
   19752              : 
   19753            0 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   19754              : 
   19755            0 :         if (PQntuples(res) != 1)
   19756            0 :             pg_fatal(ngettext("query to get data of sequence \"%s\" returned %d row (expected 1)",
   19757              :                               "query to get data of sequence \"%s\" returned %d rows (expected 1)",
   19758              :                               PQntuples(res)),
   19759              :                      tbinfo->dobj.name, PQntuples(res));
   19760              : 
   19761            0 :         last = strtoi64(PQgetvalue(res, 0, 0), NULL, 10);
   19762            0 :         called = (strcmp(PQgetvalue(res, 0, 1), "t") == 0);
   19763              : 
   19764            0 :         PQclear(res);
   19765              :     }
   19766              :     else
   19767              :     {
   19768          401 :         SequenceItem key = {0};
   19769              :         SequenceItem *entry;
   19770              : 
   19771              :         Assert(sequences);
   19772              :         Assert(tbinfo->dobj.catId.oid);
   19773              : 
   19774          401 :         key.oid = tbinfo->dobj.catId.oid;
   19775          401 :         entry = bsearch(&key, sequences, nsequences,
   19776              :                         sizeof(SequenceItem), SequenceItemCmp);
   19777              : 
   19778          401 :         if (entry->null_seqtuple)
   19779            0 :             pg_fatal("failed to get data for sequence \"%s\"; user may lack "
   19780              :                      "SELECT privilege on the sequence or the sequence may "
   19781              :                      "have been concurrently dropped",
   19782              :                      tbinfo->dobj.name);
   19783              : 
   19784          401 :         last = entry->last_value;
   19785          401 :         called = entry->is_called;
   19786              :     }
   19787              : 
   19788          401 :     resetPQExpBuffer(query);
   19789          401 :     appendPQExpBufferStr(query, "SELECT pg_catalog.setval(");
   19790          401 :     appendStringLiteralAH(query, fmtQualifiedDumpable(tbinfo), fout);
   19791          401 :     appendPQExpBuffer(query, ", " INT64_FORMAT ", %s);\n",
   19792              :                       last, (called ? "true" : "false"));
   19793              : 
   19794          401 :     if (tdinfo->dobj.dump & DUMP_COMPONENT_DATA)
   19795          401 :         ArchiveEntry(fout, nilCatalogId, createDumpId(),
   19796          401 :                      ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
   19797              :                                   .namespace = tbinfo->dobj.namespace->dobj.name,
   19798              :                                   .owner = tbinfo->rolname,
   19799              :                                   .description = "SEQUENCE SET",
   19800              :                                   .section = SECTION_DATA,
   19801              :                                   .createStmt = query->data,
   19802              :                                   .deps = &(tbinfo->dobj.dumpId),
   19803              :                                   .nDeps = 1));
   19804              : 
   19805          401 :     destroyPQExpBuffer(query);
   19806              : }
   19807              : 
   19808              : /*
   19809              :  * dumpTrigger
   19810              :  *    write the declaration of one user-defined table trigger
   19811              :  */
   19812              : static void
   19813          523 : dumpTrigger(Archive *fout, const TriggerInfo *tginfo)
   19814              : {
   19815          523 :     DumpOptions *dopt = fout->dopt;
   19816          523 :     TableInfo  *tbinfo = tginfo->tgtable;
   19817              :     PQExpBuffer query;
   19818              :     PQExpBuffer delqry;
   19819              :     PQExpBuffer trigprefix;
   19820              :     PQExpBuffer trigidentity;
   19821              :     char       *qtabname;
   19822              :     char       *tag;
   19823              : 
   19824              :     /* Do nothing if not dumping schema */
   19825          523 :     if (!dopt->dumpSchema)
   19826           31 :         return;
   19827              : 
   19828          492 :     query = createPQExpBuffer();
   19829          492 :     delqry = createPQExpBuffer();
   19830          492 :     trigprefix = createPQExpBuffer();
   19831          492 :     trigidentity = createPQExpBuffer();
   19832              : 
   19833          492 :     qtabname = pg_strdup(fmtId(tbinfo->dobj.name));
   19834              : 
   19835          492 :     appendPQExpBuffer(trigidentity, "%s ", fmtId(tginfo->dobj.name));
   19836          492 :     appendPQExpBuffer(trigidentity, "ON %s", fmtQualifiedDumpable(tbinfo));
   19837              : 
   19838          492 :     appendPQExpBuffer(query, "%s;\n", tginfo->tgdef);
   19839          492 :     appendPQExpBuffer(delqry, "DROP TRIGGER %s;\n", trigidentity->data);
   19840              : 
   19841              :     /* Triggers can depend on extensions */
   19842          492 :     append_depends_on_extension(fout, query, &tginfo->dobj,
   19843              :                                 "pg_catalog.pg_trigger", "TRIGGER",
   19844          492 :                                 trigidentity->data);
   19845              : 
   19846          492 :     if (tginfo->tgispartition)
   19847              :     {
   19848              :         Assert(tbinfo->ispartition);
   19849              : 
   19850              :         /*
   19851              :          * Partition triggers only appear here because their 'tgenabled' flag
   19852              :          * differs from its parent's.  The trigger is created already, so
   19853              :          * remove the CREATE and replace it with an ALTER.  (Clear out the
   19854              :          * DROP query too, so that pg_dump --create does not cause errors.)
   19855              :          */
   19856          109 :         resetPQExpBuffer(query);
   19857          109 :         resetPQExpBuffer(delqry);
   19858          109 :         appendPQExpBuffer(query, "\nALTER %sTABLE %s ",
   19859          109 :                           tbinfo->relkind == RELKIND_FOREIGN_TABLE ? "FOREIGN " : "",
   19860          109 :                           fmtQualifiedDumpable(tbinfo));
   19861          109 :         switch (tginfo->tgenabled)
   19862              :         {
   19863           38 :             case 'f':
   19864              :             case 'D':
   19865           38 :                 appendPQExpBufferStr(query, "DISABLE");
   19866           38 :                 break;
   19867            0 :             case 't':
   19868              :             case 'O':
   19869            0 :                 appendPQExpBufferStr(query, "ENABLE");
   19870            0 :                 break;
   19871           33 :             case 'R':
   19872           33 :                 appendPQExpBufferStr(query, "ENABLE REPLICA");
   19873           33 :                 break;
   19874           38 :             case 'A':
   19875           38 :                 appendPQExpBufferStr(query, "ENABLE ALWAYS");
   19876           38 :                 break;
   19877              :         }
   19878          109 :         appendPQExpBuffer(query, " TRIGGER %s;\n",
   19879          109 :                           fmtId(tginfo->dobj.name));
   19880              :     }
   19881          383 :     else if (tginfo->tgenabled != 't' && tginfo->tgenabled != 'O')
   19882              :     {
   19883            0 :         appendPQExpBuffer(query, "\nALTER %sTABLE %s ",
   19884            0 :                           tbinfo->relkind == RELKIND_FOREIGN_TABLE ? "FOREIGN " : "",
   19885            0 :                           fmtQualifiedDumpable(tbinfo));
   19886            0 :         switch (tginfo->tgenabled)
   19887              :         {
   19888            0 :             case 'D':
   19889              :             case 'f':
   19890            0 :                 appendPQExpBufferStr(query, "DISABLE");
   19891            0 :                 break;
   19892            0 :             case 'A':
   19893            0 :                 appendPQExpBufferStr(query, "ENABLE ALWAYS");
   19894            0 :                 break;
   19895            0 :             case 'R':
   19896            0 :                 appendPQExpBufferStr(query, "ENABLE REPLICA");
   19897            0 :                 break;
   19898            0 :             default:
   19899            0 :                 appendPQExpBufferStr(query, "ENABLE");
   19900            0 :                 break;
   19901              :         }
   19902            0 :         appendPQExpBuffer(query, " TRIGGER %s;\n",
   19903            0 :                           fmtId(tginfo->dobj.name));
   19904              :     }
   19905              : 
   19906          492 :     appendPQExpBuffer(trigprefix, "TRIGGER %s ON",
   19907          492 :                       fmtId(tginfo->dobj.name));
   19908              : 
   19909          492 :     tag = psprintf("%s %s", tbinfo->dobj.name, tginfo->dobj.name);
   19910              : 
   19911          492 :     if (tginfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   19912          492 :         ArchiveEntry(fout, tginfo->dobj.catId, tginfo->dobj.dumpId,
   19913          492 :                      ARCHIVE_OPTS(.tag = tag,
   19914              :                                   .namespace = tbinfo->dobj.namespace->dobj.name,
   19915              :                                   .owner = tbinfo->rolname,
   19916              :                                   .description = "TRIGGER",
   19917              :                                   .section = SECTION_POST_DATA,
   19918              :                                   .createStmt = query->data,
   19919              :                                   .dropStmt = delqry->data));
   19920              : 
   19921          492 :     if (tginfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   19922            0 :         dumpComment(fout, trigprefix->data, qtabname,
   19923            0 :                     tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
   19924            0 :                     tginfo->dobj.catId, 0, tginfo->dobj.dumpId);
   19925              : 
   19926          492 :     free(tag);
   19927          492 :     destroyPQExpBuffer(query);
   19928          492 :     destroyPQExpBuffer(delqry);
   19929          492 :     destroyPQExpBuffer(trigprefix);
   19930          492 :     destroyPQExpBuffer(trigidentity);
   19931          492 :     free(qtabname);
   19932              : }
   19933              : 
   19934              : /*
   19935              :  * dumpEventTrigger
   19936              :  *    write the declaration of one user-defined event trigger
   19937              :  */
   19938              : static void
   19939           42 : dumpEventTrigger(Archive *fout, const EventTriggerInfo *evtinfo)
   19940              : {
   19941           42 :     DumpOptions *dopt = fout->dopt;
   19942              :     PQExpBuffer query;
   19943              :     PQExpBuffer delqry;
   19944              :     char       *qevtname;
   19945              : 
   19946              :     /* Do nothing if not dumping schema */
   19947           42 :     if (!dopt->dumpSchema)
   19948            6 :         return;
   19949              : 
   19950           36 :     query = createPQExpBuffer();
   19951           36 :     delqry = createPQExpBuffer();
   19952              : 
   19953           36 :     qevtname = pg_strdup(fmtId(evtinfo->dobj.name));
   19954              : 
   19955           36 :     appendPQExpBufferStr(query, "CREATE EVENT TRIGGER ");
   19956           36 :     appendPQExpBufferStr(query, qevtname);
   19957           36 :     appendPQExpBufferStr(query, " ON ");
   19958           36 :     appendPQExpBufferStr(query, fmtId(evtinfo->evtevent));
   19959              : 
   19960           36 :     if (strcmp("", evtinfo->evttags) != 0)
   19961              :     {
   19962            5 :         appendPQExpBufferStr(query, "\n         WHEN TAG IN (");
   19963            5 :         appendPQExpBufferStr(query, evtinfo->evttags);
   19964            5 :         appendPQExpBufferChar(query, ')');
   19965              :     }
   19966              : 
   19967           36 :     appendPQExpBufferStr(query, "\n   EXECUTE FUNCTION ");
   19968           36 :     appendPQExpBufferStr(query, evtinfo->evtfname);
   19969           36 :     appendPQExpBufferStr(query, "();\n");
   19970              : 
   19971           36 :     if (evtinfo->evtenabled != 'O')
   19972              :     {
   19973            0 :         appendPQExpBuffer(query, "\nALTER EVENT TRIGGER %s ",
   19974              :                           qevtname);
   19975            0 :         switch (evtinfo->evtenabled)
   19976              :         {
   19977            0 :             case 'D':
   19978            0 :                 appendPQExpBufferStr(query, "DISABLE");
   19979            0 :                 break;
   19980            0 :             case 'A':
   19981            0 :                 appendPQExpBufferStr(query, "ENABLE ALWAYS");
   19982            0 :                 break;
   19983            0 :             case 'R':
   19984            0 :                 appendPQExpBufferStr(query, "ENABLE REPLICA");
   19985            0 :                 break;
   19986            0 :             default:
   19987            0 :                 appendPQExpBufferStr(query, "ENABLE");
   19988            0 :                 break;
   19989              :         }
   19990            0 :         appendPQExpBufferStr(query, ";\n");
   19991              :     }
   19992              : 
   19993           36 :     appendPQExpBuffer(delqry, "DROP EVENT TRIGGER %s;\n",
   19994              :                       qevtname);
   19995              : 
   19996           36 :     if (dopt->binary_upgrade)
   19997            2 :         binary_upgrade_extension_member(query, &evtinfo->dobj,
   19998              :                                         "EVENT TRIGGER", qevtname, NULL);
   19999              : 
   20000           36 :     if (evtinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   20001           36 :         ArchiveEntry(fout, evtinfo->dobj.catId, evtinfo->dobj.dumpId,
   20002           36 :                      ARCHIVE_OPTS(.tag = evtinfo->dobj.name,
   20003              :                                   .owner = evtinfo->evtowner,
   20004              :                                   .description = "EVENT TRIGGER",
   20005              :                                   .section = SECTION_POST_DATA,
   20006              :                                   .createStmt = query->data,
   20007              :                                   .dropStmt = delqry->data));
   20008              : 
   20009           36 :     if (evtinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   20010            0 :         dumpComment(fout, "EVENT TRIGGER", qevtname,
   20011            0 :                     NULL, evtinfo->evtowner,
   20012            0 :                     evtinfo->dobj.catId, 0, evtinfo->dobj.dumpId);
   20013              : 
   20014           36 :     if (evtinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
   20015            0 :         dumpSecLabel(fout, "EVENT TRIGGER", qevtname,
   20016            0 :                      NULL, evtinfo->evtowner,
   20017            0 :                      evtinfo->dobj.catId, 0, evtinfo->dobj.dumpId);
   20018              : 
   20019           36 :     destroyPQExpBuffer(query);
   20020           36 :     destroyPQExpBuffer(delqry);
   20021           36 :     free(qevtname);
   20022              : }
   20023              : 
   20024              : /*
   20025              :  * dumpRule
   20026              :  *      Dump a rule
   20027              :  */
   20028              : static void
   20029         1150 : dumpRule(Archive *fout, const RuleInfo *rinfo)
   20030              : {
   20031         1150 :     DumpOptions *dopt = fout->dopt;
   20032         1150 :     TableInfo  *tbinfo = rinfo->ruletable;
   20033              :     bool        is_view;
   20034              :     PQExpBuffer query;
   20035              :     PQExpBuffer cmd;
   20036              :     PQExpBuffer delcmd;
   20037              :     PQExpBuffer ruleprefix;
   20038              :     char       *qtabname;
   20039              :     PGresult   *res;
   20040              :     char       *tag;
   20041              : 
   20042              :     /* Do nothing if not dumping schema */
   20043         1150 :     if (!dopt->dumpSchema)
   20044           60 :         return;
   20045              : 
   20046              :     /*
   20047              :      * If it is an ON SELECT rule that is created implicitly by CREATE VIEW,
   20048              :      * we do not want to dump it as a separate object.
   20049              :      */
   20050         1090 :     if (!rinfo->separate)
   20051          879 :         return;
   20052              : 
   20053              :     /*
   20054              :      * If it's an ON SELECT rule, we want to print it as a view definition,
   20055              :      * instead of a rule.
   20056              :      */
   20057          211 :     is_view = (rinfo->ev_type == '1' && rinfo->is_instead);
   20058              : 
   20059          211 :     query = createPQExpBuffer();
   20060          211 :     cmd = createPQExpBuffer();
   20061          211 :     delcmd = createPQExpBuffer();
   20062          211 :     ruleprefix = createPQExpBuffer();
   20063              : 
   20064          211 :     qtabname = pg_strdup(fmtId(tbinfo->dobj.name));
   20065              : 
   20066          211 :     if (is_view)
   20067              :     {
   20068              :         PQExpBuffer result;
   20069              : 
   20070              :         /*
   20071              :          * We need OR REPLACE here because we'll be replacing a dummy view.
   20072              :          * Otherwise this should look largely like the regular view dump code.
   20073              :          */
   20074           10 :         appendPQExpBuffer(cmd, "CREATE OR REPLACE VIEW %s",
   20075           10 :                           fmtQualifiedDumpable(tbinfo));
   20076           10 :         if (nonemptyReloptions(tbinfo->reloptions))
   20077              :         {
   20078            0 :             appendPQExpBufferStr(cmd, " WITH (");
   20079            0 :             appendReloptionsArrayAH(cmd, tbinfo->reloptions, "", fout);
   20080            0 :             appendPQExpBufferChar(cmd, ')');
   20081              :         }
   20082           10 :         result = createViewAsClause(fout, tbinfo);
   20083           10 :         appendPQExpBuffer(cmd, " AS\n%s", result->data);
   20084           10 :         destroyPQExpBuffer(result);
   20085           10 :         if (tbinfo->checkoption != NULL)
   20086            0 :             appendPQExpBuffer(cmd, "\n  WITH %s CHECK OPTION",
   20087              :                               tbinfo->checkoption);
   20088           10 :         appendPQExpBufferStr(cmd, ";\n");
   20089              :     }
   20090              :     else
   20091              :     {
   20092              :         /* In the rule case, just print pg_get_ruledef's result verbatim */
   20093          201 :         appendPQExpBuffer(query,
   20094              :                           "SELECT pg_catalog.pg_get_ruledef('%u'::pg_catalog.oid)",
   20095          201 :                           rinfo->dobj.catId.oid);
   20096              : 
   20097          201 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   20098              : 
   20099          201 :         if (PQntuples(res) != 1)
   20100            0 :             pg_fatal("query to get rule \"%s\" for table \"%s\" failed: wrong number of rows returned",
   20101              :                      rinfo->dobj.name, tbinfo->dobj.name);
   20102              : 
   20103          201 :         printfPQExpBuffer(cmd, "%s\n", PQgetvalue(res, 0, 0));
   20104              : 
   20105          201 :         PQclear(res);
   20106              :     }
   20107              : 
   20108              :     /*
   20109              :      * Add the command to alter the rules replication firing semantics if it
   20110              :      * differs from the default.
   20111              :      */
   20112          211 :     if (rinfo->ev_enabled != 'O')
   20113              :     {
   20114           15 :         appendPQExpBuffer(cmd, "ALTER TABLE %s ", fmtQualifiedDumpable(tbinfo));
   20115           15 :         switch (rinfo->ev_enabled)
   20116              :         {
   20117            0 :             case 'A':
   20118            0 :                 appendPQExpBuffer(cmd, "ENABLE ALWAYS RULE %s;\n",
   20119            0 :                                   fmtId(rinfo->dobj.name));
   20120            0 :                 break;
   20121            0 :             case 'R':
   20122            0 :                 appendPQExpBuffer(cmd, "ENABLE REPLICA RULE %s;\n",
   20123            0 :                                   fmtId(rinfo->dobj.name));
   20124            0 :                 break;
   20125           15 :             case 'D':
   20126           15 :                 appendPQExpBuffer(cmd, "DISABLE RULE %s;\n",
   20127           15 :                                   fmtId(rinfo->dobj.name));
   20128           15 :                 break;
   20129              :         }
   20130              :     }
   20131              : 
   20132          211 :     if (is_view)
   20133              :     {
   20134              :         /*
   20135              :          * We can't DROP a view's ON SELECT rule.  Instead, use CREATE OR
   20136              :          * REPLACE VIEW to replace the rule with something with minimal
   20137              :          * dependencies.
   20138              :          */
   20139              :         PQExpBuffer result;
   20140              : 
   20141           10 :         appendPQExpBuffer(delcmd, "CREATE OR REPLACE VIEW %s",
   20142           10 :                           fmtQualifiedDumpable(tbinfo));
   20143           10 :         result = createDummyViewAsClause(fout, tbinfo);
   20144           10 :         appendPQExpBuffer(delcmd, " AS\n%s;\n", result->data);
   20145           10 :         destroyPQExpBuffer(result);
   20146              :     }
   20147              :     else
   20148              :     {
   20149          201 :         appendPQExpBuffer(delcmd, "DROP RULE %s ",
   20150          201 :                           fmtId(rinfo->dobj.name));
   20151          201 :         appendPQExpBuffer(delcmd, "ON %s;\n",
   20152          201 :                           fmtQualifiedDumpable(tbinfo));
   20153              :     }
   20154              : 
   20155          211 :     appendPQExpBuffer(ruleprefix, "RULE %s ON",
   20156          211 :                       fmtId(rinfo->dobj.name));
   20157              : 
   20158          211 :     tag = psprintf("%s %s", tbinfo->dobj.name, rinfo->dobj.name);
   20159              : 
   20160          211 :     if (rinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   20161          211 :         ArchiveEntry(fout, rinfo->dobj.catId, rinfo->dobj.dumpId,
   20162          211 :                      ARCHIVE_OPTS(.tag = tag,
   20163              :                                   .namespace = tbinfo->dobj.namespace->dobj.name,
   20164              :                                   .owner = tbinfo->rolname,
   20165              :                                   .description = "RULE",
   20166              :                                   .section = SECTION_POST_DATA,
   20167              :                                   .createStmt = cmd->data,
   20168              :                                   .dropStmt = delcmd->data));
   20169              : 
   20170              :     /* Dump rule comments */
   20171          211 :     if (rinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   20172            0 :         dumpComment(fout, ruleprefix->data, qtabname,
   20173            0 :                     tbinfo->dobj.namespace->dobj.name,
   20174              :                     tbinfo->rolname,
   20175            0 :                     rinfo->dobj.catId, 0, rinfo->dobj.dumpId);
   20176              : 
   20177          211 :     free(tag);
   20178          211 :     destroyPQExpBuffer(query);
   20179          211 :     destroyPQExpBuffer(cmd);
   20180          211 :     destroyPQExpBuffer(delcmd);
   20181          211 :     destroyPQExpBuffer(ruleprefix);
   20182          211 :     free(qtabname);
   20183              : }
   20184              : 
   20185              : /*
   20186              :  * getExtensionMembership --- obtain extension membership data
   20187              :  *
   20188              :  * We need to identify objects that are extension members as soon as they're
   20189              :  * loaded, so that we can correctly determine whether they need to be dumped.
   20190              :  * Generally speaking, extension member objects will get marked as *not* to
   20191              :  * be dumped, as they will be recreated by the single CREATE EXTENSION
   20192              :  * command.  However, in binary upgrade mode we still need to dump the members
   20193              :  * individually.
   20194              :  */
   20195              : void
   20196          260 : getExtensionMembership(Archive *fout, ExtensionInfo extinfo[],
   20197              :                        int numExtensions)
   20198              : {
   20199              :     PQExpBuffer query;
   20200              :     PGresult   *res;
   20201              :     int         ntups,
   20202              :                 i;
   20203              :     int         i_classid,
   20204              :                 i_objid,
   20205              :                 i_refobjid;
   20206              :     ExtensionInfo *ext;
   20207              : 
   20208              :     /* Nothing to do if no extensions */
   20209          260 :     if (numExtensions == 0)
   20210            0 :         return;
   20211              : 
   20212          260 :     query = createPQExpBuffer();
   20213              : 
   20214              :     /* refclassid constraint is redundant but may speed the search */
   20215          260 :     appendPQExpBufferStr(query, "SELECT "
   20216              :                          "classid, objid, refobjid "
   20217              :                          "FROM pg_depend "
   20218              :                          "WHERE refclassid = 'pg_extension'::regclass "
   20219              :                          "AND deptype = 'e' "
   20220              :                          "ORDER BY 3");
   20221              : 
   20222          260 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   20223              : 
   20224          260 :     ntups = PQntuples(res);
   20225              : 
   20226          260 :     i_classid = PQfnumber(res, "classid");
   20227          260 :     i_objid = PQfnumber(res, "objid");
   20228          260 :     i_refobjid = PQfnumber(res, "refobjid");
   20229              : 
   20230              :     /*
   20231              :      * Since we ordered the SELECT by referenced ID, we can expect that
   20232              :      * multiple entries for the same extension will appear together; this
   20233              :      * saves on searches.
   20234              :      */
   20235          260 :     ext = NULL;
   20236              : 
   20237         1906 :     for (i = 0; i < ntups; i++)
   20238              :     {
   20239              :         CatalogId   objId;
   20240              :         Oid         extId;
   20241              : 
   20242         1646 :         objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
   20243         1646 :         objId.oid = atooid(PQgetvalue(res, i, i_objid));
   20244         1646 :         extId = atooid(PQgetvalue(res, i, i_refobjid));
   20245              : 
   20246         1646 :         if (ext == NULL ||
   20247         1386 :             ext->dobj.catId.oid != extId)
   20248          291 :             ext = findExtensionByOid(extId);
   20249              : 
   20250         1646 :         if (ext == NULL)
   20251              :         {
   20252              :             /* shouldn't happen */
   20253            0 :             pg_log_warning("could not find referenced extension %u", extId);
   20254            0 :             continue;
   20255              :         }
   20256              : 
   20257         1646 :         recordExtensionMembership(objId, ext);
   20258              :     }
   20259              : 
   20260          260 :     PQclear(res);
   20261              : 
   20262          260 :     destroyPQExpBuffer(query);
   20263              : }
   20264              : 
   20265              : /*
   20266              :  * processExtensionTables --- deal with extension configuration tables
   20267              :  *
   20268              :  * There are two parts to this process:
   20269              :  *
   20270              :  * 1. Identify and create dump records for extension configuration tables.
   20271              :  *
   20272              :  *    Extensions can mark tables as "configuration", which means that the user
   20273              :  *    is able and expected to modify those tables after the extension has been
   20274              :  *    loaded.  For these tables, we dump out only the data- the structure is
   20275              :  *    expected to be handled at CREATE EXTENSION time, including any indexes or
   20276              :  *    foreign keys, which brings us to-
   20277              :  *
   20278              :  * 2. Record FK dependencies between configuration tables.
   20279              :  *
   20280              :  *    Due to the FKs being created at CREATE EXTENSION time and therefore before
   20281              :  *    the data is loaded, we have to work out what the best order for reloading
   20282              :  *    the data is, to avoid FK violations when the tables are restored.  This is
   20283              :  *    not perfect- we can't handle circular dependencies and if any exist they
   20284              :  *    will cause an invalid dump to be produced (though at least all of the data
   20285              :  *    is included for a user to manually restore).  This is currently documented
   20286              :  *    but perhaps we can provide a better solution in the future.
   20287              :  */
   20288              : void
   20289          259 : processExtensionTables(Archive *fout, ExtensionInfo extinfo[],
   20290              :                        int numExtensions)
   20291              : {
   20292          259 :     DumpOptions *dopt = fout->dopt;
   20293              :     PQExpBuffer query;
   20294              :     PGresult   *res;
   20295              :     int         ntups,
   20296              :                 i;
   20297              :     int         i_conrelid,
   20298              :                 i_confrelid;
   20299              : 
   20300              :     /* Nothing to do if no extensions */
   20301          259 :     if (numExtensions == 0)
   20302            0 :         return;
   20303              : 
   20304              :     /*
   20305              :      * Identify extension configuration tables and create TableDataInfo
   20306              :      * objects for them, ensuring their data will be dumped even though the
   20307              :      * tables themselves won't be.
   20308              :      *
   20309              :      * Note that we create TableDataInfo objects even in schema-only mode, ie,
   20310              :      * user data in a configuration table is treated like schema data. This
   20311              :      * seems appropriate since system data in a config table would get
   20312              :      * reloaded by CREATE EXTENSION.  If the extension is not listed in the
   20313              :      * list of extensions to be included, none of its data is dumped.
   20314              :      */
   20315          549 :     for (i = 0; i < numExtensions; i++)
   20316              :     {
   20317          290 :         ExtensionInfo *curext = &(extinfo[i]);
   20318          290 :         char       *extconfig = curext->extconfig;
   20319          290 :         char       *extcondition = curext->extcondition;
   20320          290 :         char      **extconfigarray = NULL;
   20321          290 :         char      **extconditionarray = NULL;
   20322          290 :         int         nconfigitems = 0;
   20323          290 :         int         nconditionitems = 0;
   20324              : 
   20325              :         /*
   20326              :          * Check if this extension is listed as to include in the dump.  If
   20327              :          * not, any table data associated with it is discarded.
   20328              :          */
   20329          290 :         if (extension_include_oids.head != NULL &&
   20330            8 :             !simple_oid_list_member(&extension_include_oids,
   20331              :                                     curext->dobj.catId.oid))
   20332            6 :             continue;
   20333              : 
   20334              :         /*
   20335              :          * Check if this extension is listed as to exclude in the dump.  If
   20336              :          * yes, any table data associated with it is discarded.
   20337              :          */
   20338          290 :         if (extension_exclude_oids.head != NULL &&
   20339            4 :             simple_oid_list_member(&extension_exclude_oids,
   20340              :                                    curext->dobj.catId.oid))
   20341            2 :             continue;
   20342              : 
   20343          284 :         if (strlen(extconfig) != 0 || strlen(extcondition) != 0)
   20344              :         {
   20345              :             int         j;
   20346              : 
   20347           20 :             if (!parsePGArray(extconfig, &extconfigarray, &nconfigitems))
   20348            0 :                 pg_fatal("could not parse %s array", "extconfig");
   20349           20 :             if (!parsePGArray(extcondition, &extconditionarray, &nconditionitems))
   20350            0 :                 pg_fatal("could not parse %s array", "extcondition");
   20351           20 :             if (nconfigitems != nconditionitems)
   20352            0 :                 pg_fatal("mismatched number of configurations and conditions for extension");
   20353              : 
   20354           60 :             for (j = 0; j < nconfigitems; j++)
   20355              :             {
   20356              :                 TableInfo  *configtbl;
   20357           40 :                 Oid         configtbloid = atooid(extconfigarray[j]);
   20358           40 :                 bool        dumpobj =
   20359           40 :                     curext->dobj.dump & DUMP_COMPONENT_DEFINITION;
   20360              : 
   20361           40 :                 configtbl = findTableByOid(configtbloid);
   20362           40 :                 if (configtbl == NULL)
   20363            0 :                     continue;
   20364              : 
   20365              :                 /*
   20366              :                  * Tables of not-to-be-dumped extensions shouldn't be dumped
   20367              :                  * unless the table or its schema is explicitly included
   20368              :                  */
   20369           40 :                 if (!(curext->dobj.dump & DUMP_COMPONENT_DEFINITION))
   20370              :                 {
   20371              :                     /* check table explicitly requested */
   20372            2 :                     if (table_include_oids.head != NULL &&
   20373            0 :                         simple_oid_list_member(&table_include_oids,
   20374              :                                                configtbloid))
   20375            0 :                         dumpobj = true;
   20376              : 
   20377              :                     /* check table's schema explicitly requested */
   20378            2 :                     if (configtbl->dobj.namespace->dobj.dump &
   20379              :                         DUMP_COMPONENT_DATA)
   20380            2 :                         dumpobj = true;
   20381              :                 }
   20382              : 
   20383              :                 /* check table excluded by an exclusion switch */
   20384           44 :                 if (table_exclude_oids.head != NULL &&
   20385            4 :                     simple_oid_list_member(&table_exclude_oids,
   20386              :                                            configtbloid))
   20387            1 :                     dumpobj = false;
   20388              : 
   20389              :                 /* check schema excluded by an exclusion switch */
   20390           40 :                 if (simple_oid_list_member(&schema_exclude_oids,
   20391           40 :                                            configtbl->dobj.namespace->dobj.catId.oid))
   20392            0 :                     dumpobj = false;
   20393              : 
   20394           40 :                 if (dumpobj)
   20395              :                 {
   20396           39 :                     makeTableDataInfo(dopt, configtbl);
   20397           39 :                     if (configtbl->dataObj != NULL)
   20398              :                     {
   20399           39 :                         if (strlen(extconditionarray[j]) > 0)
   20400            0 :                             configtbl->dataObj->filtercond = pg_strdup(extconditionarray[j]);
   20401              :                     }
   20402              :                 }
   20403              :             }
   20404              :         }
   20405          284 :         if (extconfigarray)
   20406           20 :             free(extconfigarray);
   20407          284 :         if (extconditionarray)
   20408           20 :             free(extconditionarray);
   20409              :     }
   20410              : 
   20411              :     /*
   20412              :      * Now that all the TableDataInfo objects have been created for all the
   20413              :      * extensions, check their FK dependencies and register them to try and
   20414              :      * dump the data out in an order that they can be restored in.
   20415              :      *
   20416              :      * Note that this is not a problem for user tables as their FKs are
   20417              :      * recreated after the data has been loaded.
   20418              :      */
   20419              : 
   20420          259 :     query = createPQExpBuffer();
   20421              : 
   20422          259 :     printfPQExpBuffer(query,
   20423              :                       "SELECT conrelid, confrelid "
   20424              :                       "FROM pg_constraint "
   20425              :                       "JOIN pg_depend ON (objid = confrelid) "
   20426              :                       "WHERE contype = 'f' "
   20427              :                       "AND refclassid = 'pg_extension'::regclass "
   20428              :                       "AND classid = 'pg_class'::regclass;");
   20429              : 
   20430          259 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   20431          259 :     ntups = PQntuples(res);
   20432              : 
   20433          259 :     i_conrelid = PQfnumber(res, "conrelid");
   20434          259 :     i_confrelid = PQfnumber(res, "confrelid");
   20435              : 
   20436              :     /* Now get the dependencies and register them */
   20437          259 :     for (i = 0; i < ntups; i++)
   20438              :     {
   20439              :         Oid         conrelid,
   20440              :                     confrelid;
   20441              :         TableInfo  *reftable,
   20442              :                    *contable;
   20443              : 
   20444            0 :         conrelid = atooid(PQgetvalue(res, i, i_conrelid));
   20445            0 :         confrelid = atooid(PQgetvalue(res, i, i_confrelid));
   20446            0 :         contable = findTableByOid(conrelid);
   20447            0 :         reftable = findTableByOid(confrelid);
   20448              : 
   20449            0 :         if (reftable == NULL ||
   20450            0 :             reftable->dataObj == NULL ||
   20451            0 :             contable == NULL ||
   20452            0 :             contable->dataObj == NULL)
   20453            0 :             continue;
   20454              : 
   20455              :         /*
   20456              :          * Make referencing TABLE_DATA object depend on the referenced table's
   20457              :          * TABLE_DATA object.
   20458              :          */
   20459            0 :         addObjectDependency(&contable->dataObj->dobj,
   20460            0 :                             reftable->dataObj->dobj.dumpId);
   20461              :     }
   20462          259 :     PQclear(res);
   20463          259 :     destroyPQExpBuffer(query);
   20464              : }
   20465              : 
   20466              : /*
   20467              :  * getDependencies --- obtain available dependency data
   20468              :  */
   20469              : static void
   20470          259 : getDependencies(Archive *fout)
   20471              : {
   20472              :     PQExpBuffer query;
   20473              :     PGresult   *res;
   20474              :     int         ntups,
   20475              :                 i;
   20476              :     int         i_classid,
   20477              :                 i_objid,
   20478              :                 i_refclassid,
   20479              :                 i_refobjid,
   20480              :                 i_deptype;
   20481              :     DumpableObject *dobj,
   20482              :                *refdobj;
   20483              : 
   20484          259 :     pg_log_info("reading dependency data");
   20485              : 
   20486          259 :     query = createPQExpBuffer();
   20487              : 
   20488              :     /*
   20489              :      * Messy query to collect the dependency data we need.  Note that we
   20490              :      * ignore the sub-object column, so that dependencies of or on a column
   20491              :      * look the same as dependencies of or on a whole table.
   20492              :      *
   20493              :      * PIN dependencies aren't interesting, and EXTENSION dependencies were
   20494              :      * already processed by getExtensionMembership.
   20495              :      */
   20496          259 :     appendPQExpBufferStr(query, "SELECT "
   20497              :                          "classid, objid, refclassid, refobjid, deptype "
   20498              :                          "FROM pg_depend "
   20499              :                          "WHERE deptype != 'p' AND deptype != 'e'\n");
   20500              : 
   20501              :     /*
   20502              :      * Since we don't treat pg_amop entries as separate DumpableObjects, we
   20503              :      * have to translate their dependencies into dependencies of their parent
   20504              :      * opfamily.  Ignore internal dependencies though, as those will point to
   20505              :      * their parent opclass, which we needn't consider here (and if we did,
   20506              :      * it'd just result in circular dependencies).  Also, "loose" opfamily
   20507              :      * entries will have dependencies on their parent opfamily, which we
   20508              :      * should drop since they'd likewise become useless self-dependencies.
   20509              :      * (But be sure to keep deps on *other* opfamilies; see amopsortfamily.)
   20510              :      */
   20511          259 :     appendPQExpBufferStr(query, "UNION ALL\n"
   20512              :                          "SELECT 'pg_opfamily'::regclass AS classid, amopfamily AS objid, refclassid, refobjid, deptype "
   20513              :                          "FROM pg_depend d, pg_amop o "
   20514              :                          "WHERE deptype NOT IN ('p', 'e', 'i') AND "
   20515              :                          "classid = 'pg_amop'::regclass AND objid = o.oid "
   20516              :                          "AND NOT (refclassid = 'pg_opfamily'::regclass AND amopfamily = refobjid)\n");
   20517              : 
   20518              :     /* Likewise for pg_amproc entries */
   20519          259 :     appendPQExpBufferStr(query, "UNION ALL\n"
   20520              :                          "SELECT 'pg_opfamily'::regclass AS classid, amprocfamily AS objid, refclassid, refobjid, deptype "
   20521              :                          "FROM pg_depend d, pg_amproc p "
   20522              :                          "WHERE deptype NOT IN ('p', 'e', 'i') AND "
   20523              :                          "classid = 'pg_amproc'::regclass AND objid = p.oid "
   20524              :                          "AND NOT (refclassid = 'pg_opfamily'::regclass AND amprocfamily = refobjid)\n");
   20525              : 
   20526              :     /*
   20527              :      * Translate dependencies of pg_propgraph_element entries into
   20528              :      * dependencies of their parent pg_class entry.
   20529              :      */
   20530          259 :     if (fout->remoteVersion >= 190000)
   20531          259 :         appendPQExpBufferStr(query, "UNION ALL\n"
   20532              :                              "SELECT 'pg_class'::regclass AS classid, pgepgid AS objid, refclassid, refobjid, deptype "
   20533              :                              "FROM pg_depend d, pg_propgraph_element pge "
   20534              :                              "WHERE deptype NOT IN ('p', 'e', 'i') AND "
   20535              :                              "classid = 'pg_propgraph_element'::regclass AND objid = pge.oid\n");
   20536              : 
   20537              :     /* Sort the output for efficiency below */
   20538          259 :     appendPQExpBufferStr(query, "ORDER BY 1,2");
   20539              : 
   20540          259 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   20541              : 
   20542          259 :     ntups = PQntuples(res);
   20543              : 
   20544          259 :     i_classid = PQfnumber(res, "classid");
   20545          259 :     i_objid = PQfnumber(res, "objid");
   20546          259 :     i_refclassid = PQfnumber(res, "refclassid");
   20547          259 :     i_refobjid = PQfnumber(res, "refobjid");
   20548          259 :     i_deptype = PQfnumber(res, "deptype");
   20549              : 
   20550              :     /*
   20551              :      * Since we ordered the SELECT by referencing ID, we can expect that
   20552              :      * multiple entries for the same object will appear together; this saves
   20553              :      * on searches.
   20554              :      */
   20555          259 :     dobj = NULL;
   20556              : 
   20557       586768 :     for (i = 0; i < ntups; i++)
   20558              :     {
   20559              :         CatalogId   objId;
   20560              :         CatalogId   refobjId;
   20561              :         char        deptype;
   20562              : 
   20563       586509 :         objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
   20564       586509 :         objId.oid = atooid(PQgetvalue(res, i, i_objid));
   20565       586509 :         refobjId.tableoid = atooid(PQgetvalue(res, i, i_refclassid));
   20566       586509 :         refobjId.oid = atooid(PQgetvalue(res, i, i_refobjid));
   20567       586509 :         deptype = *(PQgetvalue(res, i, i_deptype));
   20568              : 
   20569       586509 :         if (dobj == NULL ||
   20570       551103 :             dobj->catId.tableoid != objId.tableoid ||
   20571       548526 :             dobj->catId.oid != objId.oid)
   20572       245931 :             dobj = findObjectByCatalogId(objId);
   20573              : 
   20574              :         /*
   20575              :          * Failure to find objects mentioned in pg_depend is not unexpected,
   20576              :          * since for example we don't collect info about TOAST tables.
   20577              :          */
   20578       586509 :         if (dobj == NULL)
   20579              :         {
   20580              : #ifdef NOT_USED
   20581              :             pg_log_warning("no referencing object %u %u",
   20582              :                            objId.tableoid, objId.oid);
   20583              : #endif
   20584        36711 :             continue;
   20585              :         }
   20586              : 
   20587       551355 :         refdobj = findObjectByCatalogId(refobjId);
   20588              : 
   20589       551355 :         if (refdobj == NULL)
   20590              :         {
   20591              : #ifdef NOT_USED
   20592              :             pg_log_warning("no referenced object %u %u",
   20593              :                            refobjId.tableoid, refobjId.oid);
   20594              : #endif
   20595         1557 :             continue;
   20596              :         }
   20597              : 
   20598              :         /*
   20599              :          * For 'x' dependencies, mark the object for later; we still add the
   20600              :          * normal dependency, for possible ordering purposes.  Currently
   20601              :          * pg_dump_sort.c knows to put extensions ahead of all object types
   20602              :          * that could possibly depend on them, but this is safer.
   20603              :          */
   20604       549798 :         if (deptype == 'x')
   20605           44 :             dobj->depends_on_ext = true;
   20606              : 
   20607              :         /*
   20608              :          * Ordinarily, table rowtypes have implicit dependencies on their
   20609              :          * tables.  However, for a composite type the implicit dependency goes
   20610              :          * the other way in pg_depend; which is the right thing for DROP but
   20611              :          * it doesn't produce the dependency ordering we need. So in that one
   20612              :          * case, we reverse the direction of the dependency.
   20613              :          */
   20614       549798 :         if (deptype == 'i' &&
   20615       150021 :             dobj->objType == DO_TABLE &&
   20616         1279 :             refdobj->objType == DO_TYPE)
   20617          182 :             addObjectDependency(refdobj, dobj->dumpId);
   20618              :         else
   20619              :             /* normal case */
   20620       549616 :             addObjectDependency(dobj, refdobj->dumpId);
   20621              :     }
   20622              : 
   20623          259 :     PQclear(res);
   20624              : 
   20625          259 :     destroyPQExpBuffer(query);
   20626          259 : }
   20627              : 
   20628              : 
   20629              : /*
   20630              :  * createBoundaryObjects - create dummy DumpableObjects to represent
   20631              :  * dump section boundaries.
   20632              :  */
   20633              : static DumpableObject *
   20634          259 : createBoundaryObjects(void)
   20635              : {
   20636              :     DumpableObject *dobjs;
   20637              : 
   20638          259 :     dobjs = pg_malloc_array(DumpableObject, 2);
   20639              : 
   20640          259 :     dobjs[0].objType = DO_PRE_DATA_BOUNDARY;
   20641          259 :     dobjs[0].catId = nilCatalogId;
   20642          259 :     AssignDumpId(dobjs + 0);
   20643          259 :     dobjs[0].name = pg_strdup("PRE-DATA BOUNDARY");
   20644              : 
   20645          259 :     dobjs[1].objType = DO_POST_DATA_BOUNDARY;
   20646          259 :     dobjs[1].catId = nilCatalogId;
   20647          259 :     AssignDumpId(dobjs + 1);
   20648          259 :     dobjs[1].name = pg_strdup("POST-DATA BOUNDARY");
   20649              : 
   20650          259 :     return dobjs;
   20651              : }
   20652              : 
   20653              : /*
   20654              :  * addBoundaryDependencies - add dependencies as needed to enforce the dump
   20655              :  * section boundaries.
   20656              :  */
   20657              : static void
   20658          259 : addBoundaryDependencies(DumpableObject **dobjs, int numObjs,
   20659              :                         DumpableObject *boundaryObjs)
   20660              : {
   20661          259 :     DumpableObject *preDataBound = boundaryObjs + 0;
   20662          259 :     DumpableObject *postDataBound = boundaryObjs + 1;
   20663              :     int         i;
   20664              : 
   20665       980461 :     for (i = 0; i < numObjs; i++)
   20666              :     {
   20667       980202 :         DumpableObject *dobj = dobjs[i];
   20668              : 
   20669              :         /*
   20670              :          * The classification of object types here must match the SECTION_xxx
   20671              :          * values assigned during subsequent ArchiveEntry calls!
   20672              :          */
   20673       980202 :         switch (dobj->objType)
   20674              :         {
   20675       919288 :             case DO_NAMESPACE:
   20676              :             case DO_EXTENSION:
   20677              :             case DO_TYPE:
   20678              :             case DO_SHELL_TYPE:
   20679              :             case DO_FUNC:
   20680              :             case DO_AGG:
   20681              :             case DO_OPERATOR:
   20682              :             case DO_ACCESS_METHOD:
   20683              :             case DO_OPCLASS:
   20684              :             case DO_OPFAMILY:
   20685              :             case DO_COLLATION:
   20686              :             case DO_CONVERSION:
   20687              :             case DO_TABLE:
   20688              :             case DO_TABLE_ATTACH:
   20689              :             case DO_ATTRDEF:
   20690              :             case DO_PROCLANG:
   20691              :             case DO_CAST:
   20692              :             case DO_DUMMY_TYPE:
   20693              :             case DO_TSPARSER:
   20694              :             case DO_TSDICT:
   20695              :             case DO_TSTEMPLATE:
   20696              :             case DO_TSCONFIG:
   20697              :             case DO_FDW:
   20698              :             case DO_FOREIGN_SERVER:
   20699              :             case DO_TRANSFORM:
   20700              :                 /* Pre-data objects: must come before the pre-data boundary */
   20701       919288 :                 addObjectDependency(preDataBound, dobj->dumpId);
   20702       919288 :                 break;
   20703         5206 :             case DO_TABLE_DATA:
   20704              :             case DO_SEQUENCE_SET:
   20705              :             case DO_LARGE_OBJECT:
   20706              :             case DO_LARGE_OBJECT_DATA:
   20707              :                 /* Data objects: must come between the boundaries */
   20708         5206 :                 addObjectDependency(dobj, preDataBound->dumpId);
   20709         5206 :                 addObjectDependency(postDataBound, dobj->dumpId);
   20710         5206 :                 break;
   20711         6111 :             case DO_INDEX:
   20712              :             case DO_INDEX_ATTACH:
   20713              :             case DO_STATSEXT:
   20714              :             case DO_REFRESH_MATVIEW:
   20715              :             case DO_TRIGGER:
   20716              :             case DO_EVENT_TRIGGER:
   20717              :             case DO_DEFAULT_ACL:
   20718              :             case DO_POLICY:
   20719              :             case DO_PUBLICATION:
   20720              :             case DO_PUBLICATION_REL:
   20721              :             case DO_PUBLICATION_TABLE_IN_SCHEMA:
   20722              :             case DO_SUBSCRIPTION:
   20723              :             case DO_SUBSCRIPTION_REL:
   20724              :                 /* Post-data objects: must come after the post-data boundary */
   20725         6111 :                 addObjectDependency(dobj, postDataBound->dumpId);
   20726         6111 :                 break;
   20727        42863 :             case DO_RULE:
   20728              :                 /* Rules are post-data, but only if dumped separately */
   20729        42863 :                 if (((RuleInfo *) dobj)->separate)
   20730          791 :                     addObjectDependency(dobj, postDataBound->dumpId);
   20731        42863 :                 break;
   20732         2748 :             case DO_CONSTRAINT:
   20733              :             case DO_FK_CONSTRAINT:
   20734              :                 /* Constraints are post-data, but only if dumped separately */
   20735         2748 :                 if (((ConstraintInfo *) dobj)->separate)
   20736         2040 :                     addObjectDependency(dobj, postDataBound->dumpId);
   20737         2748 :                 break;
   20738          259 :             case DO_PRE_DATA_BOUNDARY:
   20739              :                 /* nothing to do */
   20740          259 :                 break;
   20741          259 :             case DO_POST_DATA_BOUNDARY:
   20742              :                 /* must come after the pre-data boundary */
   20743          259 :                 addObjectDependency(dobj, preDataBound->dumpId);
   20744          259 :                 break;
   20745         3468 :             case DO_REL_STATS:
   20746              :                 /* stats section varies by parent object type, DATA or POST */
   20747         3468 :                 if (((RelStatsInfo *) dobj)->section == SECTION_DATA)
   20748              :                 {
   20749         2263 :                     addObjectDependency(dobj, preDataBound->dumpId);
   20750         2263 :                     addObjectDependency(postDataBound, dobj->dumpId);
   20751              :                 }
   20752              :                 else
   20753         1205 :                     addObjectDependency(dobj, postDataBound->dumpId);
   20754         3468 :                 break;
   20755              :         }
   20756              :     }
   20757          259 : }
   20758              : 
   20759              : 
   20760              : /*
   20761              :  * BuildArchiveDependencies - create dependency data for archive TOC entries
   20762              :  *
   20763              :  * The raw dependency data obtained by getDependencies() is not terribly
   20764              :  * useful in an archive dump, because in many cases there are dependency
   20765              :  * chains linking through objects that don't appear explicitly in the dump.
   20766              :  * For example, a view will depend on its _RETURN rule while the _RETURN rule
   20767              :  * will depend on other objects --- but the rule will not appear as a separate
   20768              :  * object in the dump.  We need to adjust the view's dependencies to include
   20769              :  * whatever the rule depends on that is included in the dump.
   20770              :  *
   20771              :  * Just to make things more complicated, there are also "special" dependencies
   20772              :  * such as the dependency of a TABLE DATA item on its TABLE, which we must
   20773              :  * not rearrange because pg_restore knows that TABLE DATA only depends on
   20774              :  * its table.  In these cases we must leave the dependencies strictly as-is
   20775              :  * even if they refer to not-to-be-dumped objects.
   20776              :  *
   20777              :  * To handle this, the convention is that "special" dependencies are created
   20778              :  * during ArchiveEntry calls, and an archive TOC item that has any such
   20779              :  * entries will not be touched here.  Otherwise, we recursively search the
   20780              :  * DumpableObject data structures to build the correct dependencies for each
   20781              :  * archive TOC item.
   20782              :  */
   20783              : static void
   20784          131 : BuildArchiveDependencies(Archive *fout)
   20785              : {
   20786          131 :     ArchiveHandle *AH = (ArchiveHandle *) fout;
   20787              :     TocEntry   *te;
   20788              : 
   20789              :     /* Scan all TOC entries in the archive */
   20790         7720 :     for (te = AH->toc->next; te != AH->toc; te = te->next)
   20791              :     {
   20792              :         DumpableObject *dobj;
   20793              :         DumpId     *dependencies;
   20794              :         int         nDeps;
   20795              :         int         allocDeps;
   20796              : 
   20797              :         /* No need to process entries that will not be dumped */
   20798         7589 :         if (te->reqs == 0)
   20799         3885 :             continue;
   20800              :         /* Ignore entries that already have "special" dependencies */
   20801         7582 :         if (te->nDeps > 0)
   20802         3116 :             continue;
   20803              :         /* Otherwise, look up the item's original DumpableObject, if any */
   20804         4466 :         dobj = findObjectByDumpId(te->dumpId);
   20805         4466 :         if (dobj == NULL)
   20806          657 :             continue;
   20807              :         /* No work if it has no dependencies */
   20808         3809 :         if (dobj->nDeps <= 0)
   20809          105 :             continue;
   20810              :         /* Set up work array */
   20811         3704 :         allocDeps = 64;
   20812         3704 :         dependencies = pg_malloc_array(DumpId, allocDeps);
   20813         3704 :         nDeps = 0;
   20814              :         /* Recursively find all dumpable dependencies */
   20815         3704 :         findDumpableDependencies(AH, dobj,
   20816              :                                  &dependencies, &nDeps, &allocDeps);
   20817              :         /* And save 'em ... */
   20818         3704 :         if (nDeps > 0)
   20819              :         {
   20820         2655 :             dependencies = pg_realloc_array(dependencies, DumpId, nDeps);
   20821         2655 :             te->dependencies = dependencies;
   20822         2655 :             te->nDeps = nDeps;
   20823              :         }
   20824              :         else
   20825         1049 :             free(dependencies);
   20826              :     }
   20827          131 : }
   20828              : 
   20829              : /* Recursive search subroutine for BuildArchiveDependencies */
   20830              : static void
   20831         8937 : findDumpableDependencies(ArchiveHandle *AH, const DumpableObject *dobj,
   20832              :                          DumpId **dependencies, int *nDeps, int *allocDeps)
   20833              : {
   20834              :     int         i;
   20835              : 
   20836              :     /*
   20837              :      * Ignore section boundary objects: if we search through them, we'll
   20838              :      * report lots of bogus dependencies.
   20839              :      */
   20840         8937 :     if (dobj->objType == DO_PRE_DATA_BOUNDARY ||
   20841         8920 :         dobj->objType == DO_POST_DATA_BOUNDARY)
   20842         1495 :         return;
   20843              : 
   20844        18383 :     for (i = 0; i < dobj->nDeps; i++)
   20845              :     {
   20846        10941 :         DumpId      depid = dobj->dependencies[i];
   20847              : 
   20848        10941 :         if (TocIDRequired(AH, depid) != 0)
   20849              :         {
   20850              :             /* Object will be dumped, so just reference it as a dependency */
   20851         5708 :             if (*nDeps >= *allocDeps)
   20852              :             {
   20853            0 :                 *allocDeps *= 2;
   20854            0 :                 *dependencies = pg_realloc_array(*dependencies, DumpId, *allocDeps);
   20855              :             }
   20856         5708 :             (*dependencies)[*nDeps] = depid;
   20857         5708 :             (*nDeps)++;
   20858              :         }
   20859              :         else
   20860              :         {
   20861              :             /*
   20862              :              * Object will not be dumped, so recursively consider its deps. We
   20863              :              * rely on the assumption that sortDumpableObjects already broke
   20864              :              * any dependency loops, else we might recurse infinitely.
   20865              :              */
   20866         5233 :             DumpableObject *otherdobj = findObjectByDumpId(depid);
   20867              : 
   20868         5233 :             if (otherdobj)
   20869         5233 :                 findDumpableDependencies(AH, otherdobj,
   20870              :                                          dependencies, nDeps, allocDeps);
   20871              :         }
   20872              :     }
   20873              : }
   20874              : 
   20875              : 
   20876              : /*
   20877              :  * getFormattedTypeName - retrieve a nicely-formatted type name for the
   20878              :  * given type OID.
   20879              :  *
   20880              :  * This does not guarantee to schema-qualify the output, so it should not
   20881              :  * be used to create the target object name for CREATE or ALTER commands.
   20882              :  *
   20883              :  * Note that the result is cached and must not be freed by the caller.
   20884              :  */
   20885              : static const char *
   20886         2335 : getFormattedTypeName(Archive *fout, Oid oid, OidOptions opts)
   20887              : {
   20888              :     TypeInfo   *typeInfo;
   20889              :     char       *result;
   20890              :     PQExpBuffer query;
   20891              :     PGresult   *res;
   20892              : 
   20893         2335 :     if (oid == 0)
   20894              :     {
   20895            0 :         if ((opts & zeroAsStar) != 0)
   20896            0 :             return "*";
   20897            0 :         else if ((opts & zeroAsNone) != 0)
   20898            0 :             return "NONE";
   20899              :     }
   20900              : 
   20901              :     /* see if we have the result cached in the type's TypeInfo record */
   20902         2335 :     typeInfo = findTypeByOid(oid);
   20903         2335 :     if (typeInfo && typeInfo->ftypname)
   20904         1868 :         return typeInfo->ftypname;
   20905              : 
   20906          467 :     query = createPQExpBuffer();
   20907          467 :     appendPQExpBuffer(query, "SELECT pg_catalog.format_type('%u'::pg_catalog.oid, NULL)",
   20908              :                       oid);
   20909              : 
   20910          467 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   20911              : 
   20912              :     /* result of format_type is already quoted */
   20913          467 :     result = pg_strdup(PQgetvalue(res, 0, 0));
   20914              : 
   20915          467 :     PQclear(res);
   20916          467 :     destroyPQExpBuffer(query);
   20917              : 
   20918              :     /*
   20919              :      * Cache the result for re-use in later requests, if possible.  If we
   20920              :      * don't have a TypeInfo for the type, the string will be leaked once the
   20921              :      * caller is done with it ... but that case really should not happen, so
   20922              :      * leaking if it does seems acceptable.
   20923              :      */
   20924          467 :     if (typeInfo)
   20925          467 :         typeInfo->ftypname = result;
   20926              : 
   20927          467 :     return result;
   20928              : }
   20929              : 
   20930              : /*
   20931              :  * Return a column list clause for the given relation.
   20932              :  *
   20933              :  * Special case: if there are no undropped columns in the relation, return
   20934              :  * "", not an invalid "()" column list.
   20935              :  */
   20936              : static const char *
   20937         9012 : fmtCopyColumnList(const TableInfo *ti, PQExpBuffer buffer)
   20938              : {
   20939         9012 :     int         numatts = ti->numatts;
   20940         9012 :     char      **attnames = ti->attnames;
   20941         9012 :     bool       *attisdropped = ti->attisdropped;
   20942         9012 :     char       *attgenerated = ti->attgenerated;
   20943              :     bool        needComma;
   20944              :     int         i;
   20945              : 
   20946         9012 :     appendPQExpBufferChar(buffer, '(');
   20947         9012 :     needComma = false;
   20948        42904 :     for (i = 0; i < numatts; i++)
   20949              :     {
   20950        33892 :         if (attisdropped[i])
   20951          606 :             continue;
   20952        33286 :         if (attgenerated[i])
   20953         1104 :             continue;
   20954        32182 :         if (needComma)
   20955        23394 :             appendPQExpBufferStr(buffer, ", ");
   20956        32182 :         appendPQExpBufferStr(buffer, fmtId(attnames[i]));
   20957        32182 :         needComma = true;
   20958              :     }
   20959              : 
   20960         9012 :     if (!needComma)
   20961          224 :         return "";                /* no undropped columns */
   20962              : 
   20963         8788 :     appendPQExpBufferChar(buffer, ')');
   20964         8788 :     return buffer->data;
   20965              : }
   20966              : 
   20967              : /*
   20968              :  * Check if a reloptions array is nonempty.
   20969              :  */
   20970              : static bool
   20971        14672 : nonemptyReloptions(const char *reloptions)
   20972              : {
   20973              :     /* Don't want to print it if it's just "{}" */
   20974        14672 :     return (reloptions != NULL && strlen(reloptions) > 2);
   20975              : }
   20976              : 
   20977              : /*
   20978              :  * Format a reloptions array and append it to the given buffer.
   20979              :  *
   20980              :  * "prefix" is prepended to the option names; typically it's "" or "toast.".
   20981              :  */
   20982              : static void
   20983          219 : appendReloptionsArrayAH(PQExpBuffer buffer, const char *reloptions,
   20984              :                         const char *prefix, Archive *fout)
   20985              : {
   20986              :     bool        res;
   20987              : 
   20988          219 :     res = appendReloptionsArray(buffer, reloptions, prefix, fout->encoding,
   20989          219 :                                 fout->std_strings);
   20990          219 :     if (!res)
   20991            0 :         pg_log_warning("could not parse %s array", "reloptions");
   20992          219 : }
   20993              : 
   20994              : /*
   20995              :  * read_dump_filters - retrieve object identifier patterns from file
   20996              :  *
   20997              :  * Parse the specified filter file for include and exclude patterns, and add
   20998              :  * them to the relevant lists.  If the filename is "-" then filters will be
   20999              :  * read from STDIN rather than a file.
   21000              :  */
   21001              : static void
   21002           26 : read_dump_filters(const char *filename, DumpOptions *dopt)
   21003              : {
   21004              :     FilterStateData fstate;
   21005              :     char       *objname;
   21006              :     FilterCommandType comtype;
   21007              :     FilterObjectType objtype;
   21008              : 
   21009           26 :     filter_init(&fstate, filename, exit_nicely);
   21010              : 
   21011           84 :     while (filter_read_item(&fstate, &objname, &comtype, &objtype))
   21012              :     {
   21013           33 :         if (comtype == FILTER_COMMAND_TYPE_INCLUDE)
   21014              :         {
   21015           17 :             switch (objtype)
   21016              :             {
   21017            0 :                 case FILTER_OBJECT_TYPE_NONE:
   21018            0 :                     break;
   21019            0 :                 case FILTER_OBJECT_TYPE_DATABASE:
   21020              :                 case FILTER_OBJECT_TYPE_FUNCTION:
   21021              :                 case FILTER_OBJECT_TYPE_INDEX:
   21022              :                 case FILTER_OBJECT_TYPE_TABLE_DATA:
   21023              :                 case FILTER_OBJECT_TYPE_TABLE_DATA_AND_CHILDREN:
   21024              :                 case FILTER_OBJECT_TYPE_TRIGGER:
   21025            0 :                     pg_log_filter_error(&fstate, _("%s filter for \"%s\" is not allowed"),
   21026              :                                         "include",
   21027              :                                         filter_object_type_name(objtype));
   21028            0 :                     exit_nicely(1);
   21029              :                     break;      /* unreachable */
   21030              : 
   21031            1 :                 case FILTER_OBJECT_TYPE_EXTENSION:
   21032            1 :                     simple_string_list_append(&extension_include_patterns, objname);
   21033            1 :                     break;
   21034            1 :                 case FILTER_OBJECT_TYPE_FOREIGN_DATA:
   21035            1 :                     simple_string_list_append(&foreign_servers_include_patterns, objname);
   21036            1 :                     break;
   21037            1 :                 case FILTER_OBJECT_TYPE_SCHEMA:
   21038            1 :                     simple_string_list_append(&schema_include_patterns, objname);
   21039            1 :                     dopt->include_everything = false;
   21040            1 :                     break;
   21041           13 :                 case FILTER_OBJECT_TYPE_TABLE:
   21042           13 :                     simple_string_list_append(&table_include_patterns, objname);
   21043           13 :                     dopt->include_everything = false;
   21044           13 :                     break;
   21045            1 :                 case FILTER_OBJECT_TYPE_TABLE_AND_CHILDREN:
   21046            1 :                     simple_string_list_append(&table_include_patterns_and_children,
   21047              :                                               objname);
   21048            1 :                     dopt->include_everything = false;
   21049            1 :                     break;
   21050              :             }
   21051              :         }
   21052           16 :         else if (comtype == FILTER_COMMAND_TYPE_EXCLUDE)
   21053              :         {
   21054            9 :             switch (objtype)
   21055              :             {
   21056            0 :                 case FILTER_OBJECT_TYPE_NONE:
   21057            0 :                     break;
   21058            1 :                 case FILTER_OBJECT_TYPE_DATABASE:
   21059              :                 case FILTER_OBJECT_TYPE_FUNCTION:
   21060              :                 case FILTER_OBJECT_TYPE_INDEX:
   21061              :                 case FILTER_OBJECT_TYPE_TRIGGER:
   21062              :                 case FILTER_OBJECT_TYPE_FOREIGN_DATA:
   21063            1 :                     pg_log_filter_error(&fstate, _("%s filter for \"%s\" is not allowed"),
   21064              :                                         "exclude",
   21065              :                                         filter_object_type_name(objtype));
   21066            1 :                     exit_nicely(1);
   21067              :                     break;
   21068              : 
   21069            1 :                 case FILTER_OBJECT_TYPE_EXTENSION:
   21070            1 :                     simple_string_list_append(&extension_exclude_patterns, objname);
   21071            1 :                     break;
   21072            1 :                 case FILTER_OBJECT_TYPE_TABLE_DATA:
   21073            1 :                     simple_string_list_append(&tabledata_exclude_patterns,
   21074              :                                               objname);
   21075            1 :                     break;
   21076            1 :                 case FILTER_OBJECT_TYPE_TABLE_DATA_AND_CHILDREN:
   21077            1 :                     simple_string_list_append(&tabledata_exclude_patterns_and_children,
   21078              :                                               objname);
   21079            1 :                     break;
   21080            2 :                 case FILTER_OBJECT_TYPE_SCHEMA:
   21081            2 :                     simple_string_list_append(&schema_exclude_patterns, objname);
   21082            2 :                     break;
   21083            2 :                 case FILTER_OBJECT_TYPE_TABLE:
   21084            2 :                     simple_string_list_append(&table_exclude_patterns, objname);
   21085            2 :                     break;
   21086            1 :                 case FILTER_OBJECT_TYPE_TABLE_AND_CHILDREN:
   21087            1 :                     simple_string_list_append(&table_exclude_patterns_and_children,
   21088              :                                               objname);
   21089            1 :                     break;
   21090              :             }
   21091              :         }
   21092              :         else
   21093              :         {
   21094              :             Assert(comtype == FILTER_COMMAND_TYPE_NONE);
   21095              :             Assert(objtype == FILTER_OBJECT_TYPE_NONE);
   21096              :         }
   21097              : 
   21098           32 :         if (objname)
   21099           25 :             free(objname);
   21100              :     }
   21101              : 
   21102           22 :     filter_free(&fstate);
   21103           22 : }
        

Generated by: LCOV version 2.0-1